fix: ajustes de idioma e pipelina
Some checks failed
Deploy ASP.NET MVC to OCI / build-and-deploy (push) Has been cancelled
Some checks failed
Deploy ASP.NET MVC to OCI / build-and-deploy (push) Has been cancelled
This commit is contained in:
parent
c76a4ea5ab
commit
be3a93f90d
127
.gitea/workflows/deploy.yml
Normal file
127
.gitea/workflows/deploy.yml
Normal file
@ -0,0 +1,127 @@
|
||||
name: Deploy ASP.NET MVC to OCI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: localACDC
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Debug - List files
|
||||
run: |
|
||||
echo "=== Arquivos na raiz ==="
|
||||
ls -la
|
||||
echo "=== Procurando Dockerfile ==="
|
||||
find . -name "Dockerfile" -o -name "dockerfile" -type f
|
||||
echo "=== Estrutura do projeto ==="
|
||||
tree -L 3 || find . -type d -name "convertit"
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
registry.redecarneir.us/convertit:latest
|
||||
registry.redecarneir.us/convertit:${{ github.sha }}
|
||||
cache-from: |
|
||||
type=local,src=/tmp/.buildx-cache
|
||||
type=registry,ref=registry.redecarneir.us/convertit:cache
|
||||
cache-to: |
|
||||
type=local,dest=/tmp/.buildx-cache-new,mode=max
|
||||
type=registry,ref=registry.redecarneir.us/convertit:cache,mode=max
|
||||
build-args: |
|
||||
BUILDKIT_INLINE_CACHE=1
|
||||
|
||||
- name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||
|
||||
- name: Deploy to OCI Server
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: 129.146.116.218
|
||||
username: ${{ secrets.SSH_USERNAME }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
port: 22
|
||||
timeout: 60s
|
||||
script: |
|
||||
# Para o container anterior da aplicação (se existir)
|
||||
docker stop convertit || true
|
||||
docker rm convertit || true
|
||||
|
||||
# Remove imagem antiga
|
||||
docker rmi registry.redecarneir.us/convertit:latest || true
|
||||
|
||||
# Puxa nova imagem
|
||||
docker pull registry.redecarneir.us/convertit:latest
|
||||
|
||||
# Executa o novo container na porta 80
|
||||
docker run -d \
|
||||
--name convertit \
|
||||
--restart unless-stopped \
|
||||
--add-host="k3ss1:172.17.0.1" \
|
||||
--add-host="k3sw2:172.17.0.1" \
|
||||
-p 80:8080 \
|
||||
--memory=2g \
|
||||
--cpus=1.5 \
|
||||
--health-cmd="curl -f http://localhost:8080/health || exit 1" \
|
||||
--health-interval=30s \
|
||||
--health-timeout=10s \
|
||||
--health-retries=3 \
|
||||
--health-start-period=60s \
|
||||
-e ASPNETCORE_ENVIRONMENT=Production \
|
||||
-e ASPNETCORE_URLS="http://+:8080" \
|
||||
-e DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \
|
||||
-e DOTNET_USE_POLLING_FILE_WATCHER=true \
|
||||
-e DOTNET_EnableDiagnostics=0 \
|
||||
-e DOTNET_RUNNING_IN_CONTAINER=true \
|
||||
registry.redecarneir.us/convertit:latest
|
||||
|
||||
# Limpa imagens não utilizadas
|
||||
docker image prune -f
|
||||
|
||||
# Verifica se o container está rodando
|
||||
docker ps | grep convertit
|
||||
|
||||
# Testa se a aplicação está respondendo na porta 80
|
||||
sleep 10
|
||||
curl -f http://localhost:80 || echo "Aplicação pode estar inicializando..."
|
||||
|
||||
- name: Verify deployment
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: 129.146.116.218
|
||||
username: ${{ secrets.SSH_USERNAME }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
port: 22
|
||||
script: |
|
||||
echo "=== Status dos containers ==="
|
||||
docker ps -a | grep convertit
|
||||
|
||||
echo "=== Logs da aplicação (últimas 20 linhas) ==="
|
||||
docker logs convertit --tail 20
|
||||
|
||||
echo "=== Teste de conectividade ==="
|
||||
curl -I http://localhost:80 || echo "Aplicação ainda não está acessível"
|
||||
89
CLAUDE.md
Normal file
89
CLAUDE.md
Normal file
@ -0,0 +1,89 @@
|
||||
# Claude Context - Convert-It Online
|
||||
|
||||
## Projeto Overview
|
||||
Convert-It Online é uma aplicação web ASP.NET Core que oferece ferramentas gratuitas de conversão de arquivos com suporte a múltiplos idiomas.
|
||||
|
||||
## URLs Amigáveis ao SEO - SISTEMA IMPLEMENTADO
|
||||
|
||||
### Estrutura de URLs Traduzidas
|
||||
**IMPORTANTE**: O projeto agora possui URLs totalmente traduzidas para melhor SEO.
|
||||
|
||||
#### URLs por Idioma:
|
||||
|
||||
**Português (pt-BR):**
|
||||
- Ferramentas de Texto: `/pt-BR/ferramentas-de-texto/conversor-de-maiusculas-minusculas`
|
||||
- Conversores de Imagem: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
||||
|
||||
**Espanhol (es-MX, es-CL, es-PY):**
|
||||
- Herramientas de Texto: `/es-MX/herramientas-de-texto/conversor-de-mayusculas-minusculas`
|
||||
- Convertidores de Imagen: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
||||
|
||||
### Arquitetura do Sistema de URLs
|
||||
|
||||
1. **UrlTranslationService**: Mapeia URLs traduzidas para controllers originais
|
||||
2. **RouteConstraints personalizados**:
|
||||
- `LocalizedAreaRouteConstraint`
|
||||
- `LocalizedControllerRouteConstraint`
|
||||
3. **Resources (.resx)**: Contêm as traduções das URLs em `UrlTextTools`, `UrlImageConverters`, etc.
|
||||
|
||||
## Estrutura de Localização
|
||||
|
||||
### Idiomas Suportados
|
||||
- `pt-BR` (Português Brasil) - idioma padrão
|
||||
- `es-MX` (Espanhol México)
|
||||
- `es-CL` (Espanhol Chile)
|
||||
- `es-PY` (Espanhol Paraguai)
|
||||
|
||||
### Arquivos de Resources
|
||||
- `SharedResource.{culture}.resx` - Resources compartilhados incluindo traduções de URL
|
||||
- `Areas/*/Views/*/Index.{culture}.resx` - Resources específicos de views
|
||||
- `Views/Home/*.{culture}.resx` - Resources das páginas principais
|
||||
|
||||
## Areas e Controllers
|
||||
|
||||
### TextTools
|
||||
- **Controller**: `CaseConverterController`
|
||||
- **Funcionalidade**: Conversão de texto (maiúsculas, minúsculas, primeira maiúscula)
|
||||
- **URL PT**: `/pt-BR/ferramentas-de-texto/conversor-de-maiusculas-minusculas`
|
||||
- **URL ES**: `/es-MX/herramientas-de-texto/conversor-de-mayusculas-minusculas`
|
||||
|
||||
### ImageConverters
|
||||
- **Controller**: `JpgToWebpController`
|
||||
- **Funcionalidade**: Conversão de JPG para WebP
|
||||
- **URL PT**: `/pt-BR/conversores-de-imagem/jpg-para-webp`
|
||||
- **URL ES**: `/es-MX/convertidores-de-imagen/jpg-a-webp`
|
||||
|
||||
## Desenvolvimento Guidelines
|
||||
|
||||
### Adicionando Novos Conversores
|
||||
1. **Controller**: Criar em `Areas/{AreaName}/Controllers/`
|
||||
2. **URL Translation**: Adicionar mapeamento em `UrlTranslationService`
|
||||
3. **Resources**: Adicionar traduções em todos os arquivos `.resx` relevantes
|
||||
4. **Testing**: Verificar URLs traduzidas em todos os idiomas
|
||||
|
||||
### Manutenção URLs SEO
|
||||
- ✅ SEMPRE verificar se novas funcionalidades seguem padrão de URL traduzida
|
||||
- ✅ Manter compatibilidade com URLs antigas (fallback implementado)
|
||||
- ✅ Validar traduções em todos os idiomas suportados
|
||||
- ✅ Usar nomes descritivos e friendly nas URLs traduzidas
|
||||
|
||||
### Padrões de Nomenclatura
|
||||
- URLs sempre em minúsculas
|
||||
- Usar hífens (-) para separar palavras
|
||||
- Manter consistência entre idiomas
|
||||
- Refletir a funcionalidade real da ferramenta
|
||||
|
||||
## Comandos Úteis
|
||||
- Build: `dotnet build`
|
||||
- Run: `dotnet run`
|
||||
- Test local: navegar para `https://localhost:59345/pt-BR/ferramentas-de-texto/conversor-de-maiusculas-minusculas`
|
||||
|
||||
## Status Atual
|
||||
✅ Sistema de URLs traduzidas implementado e funcionando
|
||||
✅ Suporte completo para 4 idiomas
|
||||
✅ RouteConstraints personalizados implementados
|
||||
✅ Fallback para URLs antigas mantido
|
||||
🔄 Aguardando testes finais
|
||||
|
||||
---
|
||||
*Mantenha este arquivo atualizado quando adicionar novos conversores ou idiomas.*
|
||||
@ -1,10 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36414.22 d17.14
|
||||
VisualStudioVersion = 17.14.36414.22
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Convert-It", "Convert-It.csproj", "{D8E3BC66-82F6-0019-7082-DF2342D15CEC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deploy", "deploy", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitea\workflows\deploy.yml = .gitea\workflows\deploy.yml
|
||||
Dockerfile = Dockerfile
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
58
Dockerfile
Normal file
58
Dockerfile
Normal file
@ -0,0 +1,58 @@
|
||||
# Dockerfile self-contained para m<>xima performance
|
||||
FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
USER app
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
|
||||
# Copiar apenas arquivos de projeto primeiro (melhor cache)
|
||||
COPY ["Convert-It.csproj", "./"]
|
||||
|
||||
# Restore com configura<72><61>es otimizadas para ARM64
|
||||
RUN dotnet restore "./Convert-It.csproj" \
|
||||
--runtime linux-arm64 \
|
||||
--no-cache
|
||||
|
||||
# Copiar c<>digo fonte
|
||||
COPY . .
|
||||
WORKDIR "/src"
|
||||
|
||||
# Build otimizado
|
||||
RUN dotnet build "./Convert-It.csproj" \
|
||||
-c $BUILD_CONFIGURATION \
|
||||
-o /app/build \
|
||||
--runtime linux-arm64 \
|
||||
--no-restore
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
|
||||
# Publish self-contained para eliminar cold start
|
||||
RUN dotnet publish "./Convert-It.csproj" \
|
||||
-c $BUILD_CONFIGURATION \
|
||||
-o /app/publish \
|
||||
--runtime linux-arm64 \
|
||||
--no-restore \
|
||||
--self-contained true \
|
||||
/p:PublishTrimmed=true \
|
||||
/p:PublishSingleFile=false
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0 AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
|
||||
# Vari<72>veis de ambiente otimizadas para produ<64><75>o
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
|
||||
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
|
||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
||||
ENV DOTNET_EnableDiagnostics=0
|
||||
|
||||
# Healthcheck simples
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
|
||||
ENTRYPOINT ["./Convert-It"]
|
||||
41
Extensions/HtmlHelperExtensions.cs
Normal file
41
Extensions/HtmlHelperExtensions.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Convert_It_Online.Services;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Convert_It_Online.Extensions
|
||||
{
|
||||
public static class HtmlHelperExtensions
|
||||
{
|
||||
public static string LocalizedUrl(this IHtmlHelper htmlHelper, string area, string controller, string action = "Index")
|
||||
{
|
||||
var context = htmlHelper.ViewContext.HttpContext;
|
||||
var urlTranslationService = context.RequestServices.GetRequiredService<IUrlTranslationService>();
|
||||
|
||||
// Get current culture
|
||||
var cultureFeature = context.Features.Get<Microsoft.AspNetCore.Localization.IRequestCultureFeature>();
|
||||
var culture = cultureFeature?.RequestCulture.UICulture ?? new CultureInfo("pt-BR");
|
||||
|
||||
// Get localized URL
|
||||
var localizedUrl = urlTranslationService.GetLocalizedUrl(area, controller, action, culture);
|
||||
|
||||
return localizedUrl;
|
||||
}
|
||||
|
||||
public static IHtmlContent LocalizedLink(this IHtmlHelper htmlHelper, string linkText, string area, string controller, string action = "Index", object? htmlAttributes = null)
|
||||
{
|
||||
var url = htmlHelper.LocalizedUrl(area, controller, action);
|
||||
|
||||
var attributes = "";
|
||||
if (htmlAttributes != null)
|
||||
{
|
||||
var props = htmlAttributes.GetType().GetProperties();
|
||||
var attrList = props.Select(p => $"{p.Name.Replace('_', '-')}=\"{p.GetValue(htmlAttributes)}\"");
|
||||
attributes = " " + string.Join(" ", attrList);
|
||||
}
|
||||
|
||||
var html = $"<a href=\"{url}\"{attributes}>{linkText}</a>";
|
||||
return new HtmlString(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Middleware/UrlTranslationMiddleware.cs
Normal file
72
Middleware/UrlTranslationMiddleware.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using Convert_It_Online.Services;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Convert_It_Online.Middleware
|
||||
{
|
||||
public class UrlTranslationMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IUrlTranslationService _urlTranslationService;
|
||||
private readonly ILogger<UrlTranslationMiddleware> _logger;
|
||||
|
||||
public UrlTranslationMiddleware(RequestDelegate next, IUrlTranslationService urlTranslationService, ILogger<UrlTranslationMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_urlTranslationService = urlTranslationService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var path = context.Request.Path.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
_logger.LogInformation($"Processing path: {path}");
|
||||
|
||||
// Pattern: /{culture}/{translatedArea}/{translatedController}[/{action}]
|
||||
var match = Regex.Match(path, @"^/([a-z]{2}-[A-Z]{2})/([^/]+)/([^/]+)(?:/([^/]+))?");
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var cultureName = match.Groups[1].Value;
|
||||
var translatedArea = match.Groups[2].Value;
|
||||
var translatedController = match.Groups[3].Value;
|
||||
var action = match.Groups[4].Success ? match.Groups[4].Value : "Index";
|
||||
|
||||
_logger.LogInformation($"Matched: culture={cultureName}, area={translatedArea}, controller={translatedController}, action={action}");
|
||||
|
||||
try
|
||||
{
|
||||
var culture = new CultureInfo(cultureName);
|
||||
var originalArea = _urlTranslationService.GetOriginalArea(translatedArea, culture);
|
||||
var originalController = _urlTranslationService.GetOriginalController(translatedController, culture);
|
||||
|
||||
_logger.LogInformation($"Translations: originalArea={originalArea}, originalController={originalController}");
|
||||
|
||||
if (originalArea != null && originalController != null)
|
||||
{
|
||||
// Rewrite the path to use original controller names
|
||||
var newPath = $"/{cultureName}/{originalArea}/{originalController}";
|
||||
if (!string.IsNullOrEmpty(action) && action != "Index")
|
||||
{
|
||||
newPath += $"/{action}";
|
||||
}
|
||||
|
||||
_logger.LogInformation($"Rewriting path from {path} to {newPath}");
|
||||
context.Request.Path = newPath;
|
||||
}
|
||||
}
|
||||
catch (CultureNotFoundException)
|
||||
{
|
||||
_logger.LogWarning($"Culture {cultureName} not found");
|
||||
// Continue with original path if culture is not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Program.cs
37
Program.cs
@ -1,53 +1,53 @@
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Localization.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Convert_It_Online.Services;
|
||||
using Convert_It_Online.Middleware;
|
||||
|
||||
// 1. Builder e Serviços
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddLocalization();
|
||||
|
||||
builder.Services.AddSingleton<IUrlTranslationService, UrlTranslationService>();
|
||||
|
||||
var supportedCultures = new[] { "pt-BR", "es-MX", "es-CL", "es-PY" };
|
||||
builder.Services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
options.DefaultRequestCulture = new RequestCulture("pt-BR");
|
||||
options.SupportedCultures = supportedCultures.Select(c => new CultureInfo(c)).ToList();
|
||||
options.SupportedUICultures = supportedCultures.Select(c => new CultureInfo(c)).ToList();
|
||||
});
|
||||
|
||||
builder.Services.AddControllersWithViews()
|
||||
.AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix);
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// 2. Configuração de Localização (RequestLocalizationOptions)
|
||||
var supportedCultures = new[] { "pt-BR", "es-MX", "es-CL", "es-PY" };
|
||||
|
||||
var localizationOptions = new RequestLocalizationOptions
|
||||
{
|
||||
DefaultRequestCulture = new RequestCulture("pt-BR"),
|
||||
SupportedCultures = supportedCultures.Select(c => new CultureInfo(c)).ToList(),
|
||||
SupportedUICultures = supportedCultures.Select(c => new CultureInfo(c)).ToList()
|
||||
};
|
||||
var localizationOptions = app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value;
|
||||
|
||||
localizationOptions.RequestCultureProviders.Clear();
|
||||
localizationOptions.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
|
||||
localizationOptions.RequestCultureProviders.Insert(1, new QueryStringRequestCultureProvider());
|
||||
localizationOptions.RequestCultureProviders.Insert(2, new AcceptLanguageHeaderRequestCultureProvider());
|
||||
localizationOptions.RequestCultureProviders.Insert(1, new AcceptLanguageHeaderRequestCultureProvider());
|
||||
localizationOptions.RequestCultureProviders.Insert(2, new QueryStringRequestCultureProvider());
|
||||
|
||||
// 3. Pipeline de Middlewares (na ordem correta)
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
app.UseExceptionHandler("/Home/Error");
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseMiddleware<UrlTranslationMiddleware>();
|
||||
app.UseRouting();
|
||||
|
||||
app.UseRequestLocalization(localizationOptions);
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
// 4. Mapeamento de Rotas (com cultura)
|
||||
app.MapControllerRoute(
|
||||
name: "areaRoute",
|
||||
pattern: "{culture:length(2,5)}/{area:exists}/{controller=Home}/{action=Index}/{id?}");
|
||||
@ -61,5 +61,4 @@ app.MapControllerRoute(
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}",
|
||||
defaults: new { culture = "pt-BR" });
|
||||
|
||||
// 5. Execução
|
||||
app.Run();
|
||||
|
||||
37
Routing/LocalizedAreaRouteConstraint.cs
Normal file
37
Routing/LocalizedAreaRouteConstraint.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Convert_It_Online.Services;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Convert_It_Online.Routing
|
||||
{
|
||||
public class LocalizedAreaRouteConstraint : IRouteConstraint
|
||||
{
|
||||
private readonly IUrlTranslationService _urlTranslationService;
|
||||
|
||||
public LocalizedAreaRouteConstraint(IUrlTranslationService urlTranslationService)
|
||||
{
|
||||
_urlTranslationService = urlTranslationService;
|
||||
}
|
||||
|
||||
public bool Match(HttpContext? httpContext, IRouter? route, string routeKey,
|
||||
RouteValueDictionary values, RouteDirection routeDirection)
|
||||
{
|
||||
if (values.TryGetValue("translatedArea", out var value) && value is string areaName)
|
||||
{
|
||||
if (values.TryGetValue("culture", out var cultureValue) && cultureValue is string cultureName)
|
||||
{
|
||||
var culture = new CultureInfo(cultureName);
|
||||
var originalArea = _urlTranslationService.GetOriginalArea(areaName, culture);
|
||||
|
||||
if (originalArea != null)
|
||||
{
|
||||
values["area"] = originalArea;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Routing/LocalizedControllerRouteConstraint.cs
Normal file
37
Routing/LocalizedControllerRouteConstraint.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Convert_It_Online.Services;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Convert_It_Online.Routing
|
||||
{
|
||||
public class LocalizedControllerRouteConstraint : IRouteConstraint
|
||||
{
|
||||
private readonly IUrlTranslationService _urlTranslationService;
|
||||
|
||||
public LocalizedControllerRouteConstraint(IUrlTranslationService urlTranslationService)
|
||||
{
|
||||
_urlTranslationService = urlTranslationService;
|
||||
}
|
||||
|
||||
public bool Match(HttpContext? httpContext, IRouter? route, string routeKey,
|
||||
RouteValueDictionary values, RouteDirection routeDirection)
|
||||
{
|
||||
if (values.TryGetValue("translatedController", out var value) && value is string controllerName)
|
||||
{
|
||||
if (values.TryGetValue("culture", out var cultureValue) && cultureValue is string cultureName)
|
||||
{
|
||||
var culture = new CultureInfo(cultureName);
|
||||
var originalController = _urlTranslationService.GetOriginalController(controllerName, culture);
|
||||
|
||||
if (originalController != null)
|
||||
{
|
||||
values["controller"] = originalController;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Services/IUrlTranslationService.cs
Normal file
13
Services/IUrlTranslationService.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Convert_It_Online.Services
|
||||
{
|
||||
public interface IUrlTranslationService
|
||||
{
|
||||
string TranslateArea(string area, CultureInfo culture);
|
||||
string TranslateController(string controller, CultureInfo culture);
|
||||
string? GetOriginalArea(string translatedArea, CultureInfo culture);
|
||||
string? GetOriginalController(string translatedController, CultureInfo culture);
|
||||
string GetLocalizedUrl(string area, string controller, string action, CultureInfo culture);
|
||||
}
|
||||
}
|
||||
144
Services/UrlTranslationService.cs
Normal file
144
Services/UrlTranslationService.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Convert_It_Online.Services
|
||||
{
|
||||
public class UrlTranslationService : IUrlTranslationService
|
||||
{
|
||||
private readonly Dictionary<string, Dictionary<string, string>> _areaTranslations;
|
||||
private readonly Dictionary<string, Dictionary<string, string>> _controllerTranslations;
|
||||
private readonly Dictionary<string, Dictionary<string, string>> _reverseAreaTranslations;
|
||||
private readonly Dictionary<string, Dictionary<string, string>> _reverseControllerTranslations;
|
||||
|
||||
public UrlTranslationService()
|
||||
{
|
||||
_areaTranslations = new Dictionary<string, Dictionary<string, string>>
|
||||
{
|
||||
["pt-BR"] = new Dictionary<string, string>
|
||||
{
|
||||
["TextTools"] = "ferramentas-de-texto",
|
||||
["ImageConverters"] = "conversores-de-imagem"
|
||||
},
|
||||
["es-MX"] = new Dictionary<string, string>
|
||||
{
|
||||
["TextTools"] = "herramientas-de-texto",
|
||||
["ImageConverters"] = "convertidores-de-imagen"
|
||||
},
|
||||
["es-CL"] = new Dictionary<string, string>
|
||||
{
|
||||
["TextTools"] = "herramientas-de-texto",
|
||||
["ImageConverters"] = "convertidores-de-imagen"
|
||||
},
|
||||
["es-PY"] = new Dictionary<string, string>
|
||||
{
|
||||
["TextTools"] = "herramientas-de-texto",
|
||||
["ImageConverters"] = "convertidores-de-imagen"
|
||||
}
|
||||
};
|
||||
|
||||
_controllerTranslations = new Dictionary<string, Dictionary<string, string>>
|
||||
{
|
||||
["pt-BR"] = new Dictionary<string, string>
|
||||
{
|
||||
["CaseConverter"] = "conversor-de-maiusculas-minusculas",
|
||||
["JpgToWebp"] = "jpg-para-webp"
|
||||
},
|
||||
["es-MX"] = new Dictionary<string, string>
|
||||
{
|
||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||
["JpgToWebp"] = "jpg-a-webp"
|
||||
},
|
||||
["es-CL"] = new Dictionary<string, string>
|
||||
{
|
||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||
["JpgToWebp"] = "jpg-a-webp"
|
||||
},
|
||||
["es-PY"] = new Dictionary<string, string>
|
||||
{
|
||||
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
|
||||
["JpgToWebp"] = "jpg-a-webp"
|
||||
}
|
||||
};
|
||||
|
||||
// Create reverse mappings for lookup
|
||||
_reverseAreaTranslations = CreateReverseMappings(_areaTranslations);
|
||||
_reverseControllerTranslations = CreateReverseMappings(_controllerTranslations);
|
||||
}
|
||||
|
||||
private Dictionary<string, Dictionary<string, string>> CreateReverseMappings(
|
||||
Dictionary<string, Dictionary<string, string>> original)
|
||||
{
|
||||
var reverse = new Dictionary<string, Dictionary<string, string>>();
|
||||
|
||||
foreach (var culture in original.Keys)
|
||||
{
|
||||
reverse[culture] = new Dictionary<string, string>();
|
||||
foreach (var kvp in original[culture])
|
||||
{
|
||||
reverse[culture][kvp.Value] = kvp.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return reverse;
|
||||
}
|
||||
|
||||
public string TranslateArea(string area, CultureInfo culture)
|
||||
{
|
||||
var cultureName = culture.Name;
|
||||
|
||||
if (_areaTranslations.TryGetValue(cultureName, out var areaDict) &&
|
||||
areaDict.TryGetValue(area, out var translatedArea))
|
||||
{
|
||||
return translatedArea;
|
||||
}
|
||||
|
||||
return area.ToLowerInvariant();
|
||||
}
|
||||
|
||||
public string TranslateController(string controller, CultureInfo culture)
|
||||
{
|
||||
var cultureName = culture.Name;
|
||||
|
||||
if (_controllerTranslations.TryGetValue(cultureName, out var controllerDict) &&
|
||||
controllerDict.TryGetValue(controller, out var translatedController))
|
||||
{
|
||||
return translatedController;
|
||||
}
|
||||
|
||||
return controller.ToLowerInvariant();
|
||||
}
|
||||
|
||||
public string? GetOriginalArea(string translatedArea, CultureInfo culture)
|
||||
{
|
||||
var cultureName = culture.Name;
|
||||
|
||||
if (_reverseAreaTranslations.TryGetValue(cultureName, out var areaDict) &&
|
||||
areaDict.TryGetValue(translatedArea, out var originalArea))
|
||||
{
|
||||
return originalArea;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string? GetOriginalController(string translatedController, CultureInfo culture)
|
||||
{
|
||||
var cultureName = culture.Name;
|
||||
|
||||
if (_reverseControllerTranslations.TryGetValue(cultureName, out var controllerDict) &&
|
||||
controllerDict.TryGetValue(translatedController, out var originalController))
|
||||
{
|
||||
return originalController;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetLocalizedUrl(string area, string controller, string action, CultureInfo culture)
|
||||
{
|
||||
var translatedArea = TranslateArea(area, culture);
|
||||
var translatedController = TranslateController(controller, culture);
|
||||
|
||||
return $"/{culture.Name}/{translatedArea}/{translatedController}";
|
||||
}
|
||||
}
|
||||
}
|
||||
122
SharedResource.es-CL.resx
Normal file
122
SharedResource.es-CL.resx
Normal file
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!-- Main Page Content - Chilean Spanish -->
|
||||
<data name="PageTitle" xml:space="preserve">
|
||||
<value>Convertidores Gratuitos Online</value>
|
||||
</data>
|
||||
<data name="Subtitle" xml:space="preserve">
|
||||
<value>Convierte textos, imágenes y documentos gratis. Herramientas online bacanes y seguras, sin necesidad de instalar nada.</value>
|
||||
</data>
|
||||
<data name="ChooseConverter" xml:space="preserve">
|
||||
<value>Elige tu Conversor</value>
|
||||
</data>
|
||||
<data name="TextToolsTitle" xml:space="preserve">
|
||||
<value>Herramientas de Texto</value>
|
||||
</data>
|
||||
<data name="TextToolsDescription" xml:space="preserve">
|
||||
<value>Convierte, formatea y manipula textos súper fácil.</value>
|
||||
</data>
|
||||
<data name="ImageToolsTitle" xml:space="preserve">
|
||||
<value>Conversores de Imagen</value>
|
||||
</data>
|
||||
<data name="ImageToolsDescription" xml:space="preserve">
|
||||
<value>Optimiza y convierte imágenes a cualquier formato al tiro.</value>
|
||||
</data>
|
||||
<data name="AboutSiteTitle" xml:space="preserve">
|
||||
<value>Sobre Convert-It Online</value>
|
||||
</data>
|
||||
<data name="AboutSiteContent" xml:space="preserve">
|
||||
<value>Convert-It Online es una plataforma gratuita que ofrece varias herramientas de conversión para que puedas hacer tu pega más fácil. Todas las conversiones son súper seguras, no guardamos tus archivos en nuestros servidores.</value>
|
||||
</data>
|
||||
<data name="WhyFreeTitle" xml:space="preserve">
|
||||
<value>¿Por qué es gratis?</value>
|
||||
</data>
|
||||
<data name="WhyFreeContent" xml:space="preserve">
|
||||
<value>Creemos que las herramientas útiles deberían estar al alcance de todos. Nuestro sitio se mantiene con publicidad no molesta, así puedes usar todos los conversores sin pagar ni una luca.</value>
|
||||
</data>
|
||||
<data name="SecurityTitle" xml:space="preserve">
|
||||
<value>Seguridad y privacidad</value>
|
||||
</data>
|
||||
<data name="SecurityContent" xml:space="preserve">
|
||||
<value>Tus archivos se procesan en tu navegador cuando se puede. Para conversiones que necesitan procesamiento en el servidor, los archivos se borran automáticamente después de la conversión.</value>
|
||||
</data>
|
||||
|
||||
<!-- Navigation Menu - Chilean Terms -->
|
||||
<data name="HomeLink" xml:space="preserve">
|
||||
<value>Inicio</value>
|
||||
</data>
|
||||
<data name="TextMenuTitle" xml:space="preserve">
|
||||
<value>Texto</value>
|
||||
</data>
|
||||
<data name="ImageMenuTitle" xml:space="preserve">
|
||||
<value>Imagen</value>
|
||||
</data>
|
||||
<data name="CaseConverterTitle" xml:space="preserve">
|
||||
<value>Conversor de Mayúsculas/Minúsculas</value>
|
||||
</data>
|
||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||
<value>JPG a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- Footer -->
|
||||
<data name="FooterText" xml:space="preserve">
|
||||
<value>© 2025 Convert-It Online. Herramientas gratis de conversión.</value>
|
||||
</data>
|
||||
<data name="About" xml:space="preserve">
|
||||
<value>Sobre nosotros</value>
|
||||
</data>
|
||||
<data name="Contact" xml:space="preserve">
|
||||
<value>Contacto</value>
|
||||
</data>
|
||||
<data name="Terms" xml:space="preserve">
|
||||
<value>Términos</value>
|
||||
</data>
|
||||
|
||||
<!-- TextTools Page - Chilean -->
|
||||
<data name="TextToolsPageTitle" xml:space="preserve">
|
||||
<value>Conversor de Texto</value>
|
||||
</data>
|
||||
<data name="TextAreaLabel" xml:space="preserve">
|
||||
<value>Pega tu texto acá</value>
|
||||
</data>
|
||||
<data name="ToUpperButton" xml:space="preserve">
|
||||
<value>MAYÚSCULAS</value>
|
||||
</data>
|
||||
<data name="ToLowerButton" xml:space="preserve">
|
||||
<value>minúsculas</value>
|
||||
</data>
|
||||
<data name="ToSentenceCaseButton" xml:space="preserve">
|
||||
<value>Primera mayúscula</value>
|
||||
</data>
|
||||
<data name="ResultTitle" xml:space="preserve">
|
||||
<value>Resultado</value>
|
||||
</data>
|
||||
|
||||
<!-- Image Converter -->
|
||||
<data name="ImageConverterPageTitle" xml:space="preserve">
|
||||
<value>Conversor JPG a WebP</value>
|
||||
</data>
|
||||
<data name="ImageConverterPageDescription" xml:space="preserve">
|
||||
<value>Convierte tus imágenes JPG al formato WebP al tiro y eficiente. WebP te da mejor compresión manteniendo la calidad de la imagen.</value>
|
||||
</data>
|
||||
<data name="FileInputLabel" xml:space="preserve">
|
||||
<value>Selecciona un archivo JPG</value>
|
||||
</data>
|
||||
<data name="ConvertButton" xml:space="preserve">
|
||||
<value>Convertir a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- URL Translations -->
|
||||
<data name="UrlTextTools" xml:space="preserve">
|
||||
<value>herramientas-de-texto</value>
|
||||
</data>
|
||||
<data name="UrlImageConverters" xml:space="preserve">
|
||||
<value>convertidores-de-imagen</value>
|
||||
</data>
|
||||
<data name="UrlCaseConverter" xml:space="preserve">
|
||||
<value>conversor-de-mayusculas-minusculas</value>
|
||||
</data>
|
||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||
<value>jpg-a-webp</value>
|
||||
</data>
|
||||
</root>
|
||||
122
SharedResource.es-MX.resx
Normal file
122
SharedResource.es-MX.resx
Normal file
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!-- Main Page Content - Mexican Spanish -->
|
||||
<data name="PageTitle" xml:space="preserve">
|
||||
<value>Convertidores Gratuitos en Línea</value>
|
||||
</data>
|
||||
<data name="Subtitle" xml:space="preserve">
|
||||
<value>Convierte textos, imágenes y documentos gratis. Herramientas en línea rápidas y seguras, sin necesidad de instalar nada.</value>
|
||||
</data>
|
||||
<data name="ChooseConverter" xml:space="preserve">
|
||||
<value>Elige tu Convertidor</value>
|
||||
</data>
|
||||
<data name="TextToolsTitle" xml:space="preserve">
|
||||
<value>Herramientas de Texto</value>
|
||||
</data>
|
||||
<data name="TextToolsDescription" xml:space="preserve">
|
||||
<value>Convierte, formatea y manipula textos fácilmente.</value>
|
||||
</data>
|
||||
<data name="ImageToolsTitle" xml:space="preserve">
|
||||
<value>Convertidores de Imagen</value>
|
||||
</data>
|
||||
<data name="ImageToolsDescription" xml:space="preserve">
|
||||
<value>Optimiza y convierte imágenes a cualquier formato.</value>
|
||||
</data>
|
||||
<data name="AboutSiteTitle" xml:space="preserve">
|
||||
<value>Acerca de Convert-It Online</value>
|
||||
</data>
|
||||
<data name="AboutSiteContent" xml:space="preserve">
|
||||
<value>Convert-It Online es una plataforma gratuita que ofrece diversas herramientas de conversión para facilitar tu trabajo diario. Todas las conversiones se realizan de forma segura, sin almacenar tus archivos en nuestros servidores.</value>
|
||||
</data>
|
||||
<data name="WhyFreeTitle" xml:space="preserve">
|
||||
<value>¿Por qué es gratis?</value>
|
||||
</data>
|
||||
<data name="WhyFreeContent" xml:space="preserve">
|
||||
<value>Creemos que las herramientas útiles deben ser accesibles para todos. Nuestro sitio se mantiene a través de anuncios no intrusivos, permitiendo que uses todos los convertidores sin costo alguno.</value>
|
||||
</data>
|
||||
<data name="SecurityTitle" xml:space="preserve">
|
||||
<value>Seguridad y privacidad</value>
|
||||
</data>
|
||||
<data name="SecurityContent" xml:space="preserve">
|
||||
<value>Tus archivos se procesan localmente en tu navegador siempre que sea posible. Para conversiones que requieren procesamiento en el servidor, los archivos se eliminan automáticamente después de la conversión.</value>
|
||||
</data>
|
||||
|
||||
<!-- Navigation Menu - Mexican Terms -->
|
||||
<data name="HomeLink" xml:space="preserve">
|
||||
<value>Inicio</value>
|
||||
</data>
|
||||
<data name="TextMenuTitle" xml:space="preserve">
|
||||
<value>Texto</value>
|
||||
</data>
|
||||
<data name="ImageMenuTitle" xml:space="preserve">
|
||||
<value>Imagen</value>
|
||||
</data>
|
||||
<data name="CaseConverterTitle" xml:space="preserve">
|
||||
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
||||
</data>
|
||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||
<value>JPG a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- Footer -->
|
||||
<data name="FooterText" xml:space="preserve">
|
||||
<value>© 2025 Convert-It Online. Herramientas gratuitas de conversión.</value>
|
||||
</data>
|
||||
<data name="About" xml:space="preserve">
|
||||
<value>Acerca de</value>
|
||||
</data>
|
||||
<data name="Contact" xml:space="preserve">
|
||||
<value>Contacto</value>
|
||||
</data>
|
||||
<data name="Terms" xml:space="preserve">
|
||||
<value>Términos</value>
|
||||
</data>
|
||||
|
||||
<!-- TextTools Page - Mexican -->
|
||||
<data name="TextToolsPageTitle" xml:space="preserve">
|
||||
<value>Convertidor de Texto</value>
|
||||
</data>
|
||||
<data name="TextAreaLabel" xml:space="preserve">
|
||||
<value>Escribe tu texto aquí</value>
|
||||
</data>
|
||||
<data name="ToUpperButton" xml:space="preserve">
|
||||
<value>MAYÚSCULAS</value>
|
||||
</data>
|
||||
<data name="ToLowerButton" xml:space="preserve">
|
||||
<value>minúsculas</value>
|
||||
</data>
|
||||
<data name="ToSentenceCaseButton" xml:space="preserve">
|
||||
<value>Primera mayúscula</value>
|
||||
</data>
|
||||
<data name="ResultTitle" xml:space="preserve">
|
||||
<value>Resultado</value>
|
||||
</data>
|
||||
|
||||
<!-- Image Converter -->
|
||||
<data name="ImageConverterPageTitle" xml:space="preserve">
|
||||
<value>Convertidor JPG a WebP</value>
|
||||
</data>
|
||||
<data name="ImageConverterPageDescription" xml:space="preserve">
|
||||
<value>Convierte tus imágenes JPG al formato WebP de forma rápida y eficiente. WebP ofrece mejor compresión manteniendo la calidad de la imagen.</value>
|
||||
</data>
|
||||
<data name="FileInputLabel" xml:space="preserve">
|
||||
<value>Selecciona un archivo JPG</value>
|
||||
</data>
|
||||
<data name="ConvertButton" xml:space="preserve">
|
||||
<value>Convertir a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- URL Translations -->
|
||||
<data name="UrlTextTools" xml:space="preserve">
|
||||
<value>herramientas-de-texto</value>
|
||||
</data>
|
||||
<data name="UrlImageConverters" xml:space="preserve">
|
||||
<value>convertidores-de-imagen</value>
|
||||
</data>
|
||||
<data name="UrlCaseConverter" xml:space="preserve">
|
||||
<value>conversor-de-mayusculas-minusculas</value>
|
||||
</data>
|
||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||
<value>jpg-a-webp</value>
|
||||
</data>
|
||||
</root>
|
||||
122
SharedResource.es-PY.resx
Normal file
122
SharedResource.es-PY.resx
Normal file
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!-- Main Page Content - Paraguayan Spanish with Guaraní influences -->
|
||||
<data name="PageTitle" xml:space="preserve">
|
||||
<value>Convertidores Gratuitos en Línea</value>
|
||||
</data>
|
||||
<data name="Subtitle" xml:space="preserve">
|
||||
<value>Convierte textos, imágenes y documentos gratis. Herramientas en línea rápidas y seguras, sin necesidad de instalar nada che.</value>
|
||||
</data>
|
||||
<data name="ChooseConverter" xml:space="preserve">
|
||||
<value>Elige tu Convertidor</value>
|
||||
</data>
|
||||
<data name="TextToolsTitle" xml:space="preserve">
|
||||
<value>Herramientas de Texto</value>
|
||||
</data>
|
||||
<data name="TextToolsDescription" xml:space="preserve">
|
||||
<value>Convierte, formatea y manipula textos facilito.</value>
|
||||
</data>
|
||||
<data name="ImageToolsTitle" xml:space="preserve">
|
||||
<value>Convertidores de Imagen</value>
|
||||
</data>
|
||||
<data name="ImageToolsDescription" xml:space="preserve">
|
||||
<value>Optimiza y convierte imágenes a cualquier formato al toque.</value>
|
||||
</data>
|
||||
<data name="AboutSiteTitle" xml:space="preserve">
|
||||
<value>Acerca de Convert-It Online</value>
|
||||
</data>
|
||||
<data name="AboutSiteContent" xml:space="preserve">
|
||||
<value>Convert-It Online es una plataforma gratuita que ofrece diversas herramientas de conversión para facilitar tu trabajo diario che. Todas las conversiones se realizan de forma segura, sin guardar tus archivos en nuestros servidores.</value>
|
||||
</data>
|
||||
<data name="WhyFreeTitle" xml:space="preserve">
|
||||
<value>¿Por qué es gratis?</value>
|
||||
</data>
|
||||
<data name="WhyFreeContent" xml:space="preserve">
|
||||
<value>Creemos que las herramientas útiles deben estar al alcance de todos. Nuestro sitio se mantiene a través de publicidad no molesta, así podés usar todos los convertidores sin pagar nada che.</value>
|
||||
</data>
|
||||
<data name="SecurityTitle" xml:space="preserve">
|
||||
<value>Seguridad y privacidad</value>
|
||||
</data>
|
||||
<data name="SecurityContent" xml:space="preserve">
|
||||
<value>Tus archivos se procesan localmente en tu navegador cuando es posible. Para conversiones que necesitan procesamiento en el servidor, los archivos se borran automáticamente después de la conversión.</value>
|
||||
</data>
|
||||
|
||||
<!-- Navigation Menu - Paraguayan Terms -->
|
||||
<data name="HomeLink" xml:space="preserve">
|
||||
<value>Inicio</value>
|
||||
</data>
|
||||
<data name="TextMenuTitle" xml:space="preserve">
|
||||
<value>Texto</value>
|
||||
</data>
|
||||
<data name="ImageMenuTitle" xml:space="preserve">
|
||||
<value>Imagen</value>
|
||||
</data>
|
||||
<data name="CaseConverterTitle" xml:space="preserve">
|
||||
<value>Convertidor de Mayúsculas/Minúsculas</value>
|
||||
</data>
|
||||
<data name="JpgToWebpTitle" xml:space="preserve">
|
||||
<value>JPG a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- Footer -->
|
||||
<data name="FooterText" xml:space="preserve">
|
||||
<value>© 2025 Convert-It Online. Herramientas gratuitas de conversión.</value>
|
||||
</data>
|
||||
<data name="About" xml:space="preserve">
|
||||
<value>Acerca de</value>
|
||||
</data>
|
||||
<data name="Contact" xml:space="preserve">
|
||||
<value>Contacto</value>
|
||||
</data>
|
||||
<data name="Terms" xml:space="preserve">
|
||||
<value>Términos</value>
|
||||
</data>
|
||||
|
||||
<!-- TextTools Page - Paraguayan -->
|
||||
<data name="TextToolsPageTitle" xml:space="preserve">
|
||||
<value>Convertidor de Texto</value>
|
||||
</data>
|
||||
<data name="TextAreaLabel" xml:space="preserve">
|
||||
<value>Escribí tu texto acá</value>
|
||||
</data>
|
||||
<data name="ToUpperButton" xml:space="preserve">
|
||||
<value>MAYÚSCULAS</value>
|
||||
</data>
|
||||
<data name="ToLowerButton" xml:space="preserve">
|
||||
<value>minúsculas</value>
|
||||
</data>
|
||||
<data name="ToSentenceCaseButton" xml:space="preserve">
|
||||
<value>Primera mayúscula</value>
|
||||
</data>
|
||||
<data name="ResultTitle" xml:space="preserve">
|
||||
<value>Resultado</value>
|
||||
</data>
|
||||
|
||||
<!-- Image Converter -->
|
||||
<data name="ImageConverterPageTitle" xml:space="preserve">
|
||||
<value>Convertidor JPG a WebP</value>
|
||||
</data>
|
||||
<data name="ImageConverterPageDescription" xml:space="preserve">
|
||||
<value>Convertí tus imágenes JPG al formato WebP de forma rápida y eficiente che. WebP ofrece mejor compresión manteniendo la calidad de la imagen.</value>
|
||||
</data>
|
||||
<data name="FileInputLabel" xml:space="preserve">
|
||||
<value>Seleccioná un archivo JPG</value>
|
||||
</data>
|
||||
<data name="ConvertButton" xml:space="preserve">
|
||||
<value>Convertir a WebP</value>
|
||||
</data>
|
||||
|
||||
<!-- URL Translations -->
|
||||
<data name="UrlTextTools" xml:space="preserve">
|
||||
<value>herramientas-de-texto</value>
|
||||
</data>
|
||||
<data name="UrlImageConverters" xml:space="preserve">
|
||||
<value>convertidores-de-imagen</value>
|
||||
</data>
|
||||
<data name="UrlCaseConverter" xml:space="preserve">
|
||||
<value>conversor-de-mayusculas-minusculas</value>
|
||||
</data>
|
||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||
<value>jpg-a-webp</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -204,6 +204,20 @@
|
||||
<value>Termos</value>
|
||||
</data>
|
||||
|
||||
<!-- URL Translations -->
|
||||
<data name="UrlTextTools" xml:space="preserve">
|
||||
<value>ferramentas-de-texto</value>
|
||||
</data>
|
||||
<data name="UrlImageConverters" xml:space="preserve">
|
||||
<value>conversores-de-imagem</value>
|
||||
</data>
|
||||
<data name="UrlCaseConverter" xml:space="preserve">
|
||||
<value>conversor-de-maiusculas-minusculas</value>
|
||||
</data>
|
||||
<data name="UrlJpgToWebp" xml:space="preserve">
|
||||
<value>jpg-para-webp</value>
|
||||
</data>
|
||||
|
||||
<!-- FAQ Resources for Contact Page -->
|
||||
<data name="Faq1Question" xml:space="preserve">
|
||||
<value>Como posso converter meus arquivos de forma segura?</value>
|
||||
|
||||
@ -17,10 +17,7 @@
|
||||
<div class="converter-menu">
|
||||
@foreach (var tool in Model)
|
||||
{
|
||||
<a asp-area="@tool.Area"
|
||||
asp-controller="@tool.Controller"
|
||||
asp-action="@tool.Action"
|
||||
asp-route-culture="@ViewContext.RouteData.Values["culture"]"
|
||||
<a href="@Html.LocalizedUrl(tool.Area, tool.Controller, tool.Action)"
|
||||
class="converter-item">
|
||||
<div class="converter-icon">
|
||||
<i class="@tool.IconClass"></i>
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
<i class="bi bi-fonts me-1"></i>@ViewBag.TextMenuTitle
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="textToolsDropdown">
|
||||
<li><a class="dropdown-item" asp-area="TextTools" asp-controller="CaseConverter" asp-action="Index" asp-route-culture="@requestCulture?.RequestCulture.UICulture.Name">
|
||||
<li><a class="dropdown-item" href="@Html.LocalizedUrl("TextTools", "CaseConverter")">
|
||||
<i class="bi bi-type me-2"></i>@ViewBag.CaseConverterTitle
|
||||
</a></li>
|
||||
</ul>
|
||||
@ -47,7 +47,7 @@
|
||||
<i class="bi bi-image-alt me-1"></i>@ViewBag.ImageMenuTitle
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="imageToolsDropdown">
|
||||
<li><a class="dropdown-item" asp-area="ImageConverters" asp-controller="JpgToWebp" asp-action="Index" asp-route-culture="@requestCulture?.RequestCulture.UICulture.Name">
|
||||
<li><a class="dropdown-item" href="@Html.LocalizedUrl("ImageConverters", "JpgToWebp")">
|
||||
<i class="bi bi-arrow-left-right me-2"></i>@ViewBag.JpgToWebpTitle
|
||||
</a></li>
|
||||
</ul>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@using Convert_It_Online
|
||||
@using Convert_It_Online.Extensions
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
Loading…
Reference in New Issue
Block a user