160 lines
5.4 KiB
C#
160 lines
5.4 KiB
C#
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
namespace QRRapidoApp.Middleware
|
|
{
|
|
public class LanguageRedirectionMiddleware
|
|
{
|
|
private readonly RequestDelegate _next;
|
|
private readonly ILogger<LanguageRedirectionMiddleware> _logger;
|
|
private readonly string[] _supportedCultures = { "pt-BR", "es-PY" };
|
|
private readonly Dictionary<string, string> _cultureAliases = new(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
{ "pt", "pt-BR" },
|
|
{ "pt-br", "pt-BR" },
|
|
{ "es", "es-PY" }
|
|
};
|
|
private const string DefaultCulture = "pt-BR";
|
|
|
|
public LanguageRedirectionMiddleware(RequestDelegate next, ILogger<LanguageRedirectionMiddleware> logger)
|
|
{
|
|
_next = next;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
var path = context.Request.Path.Value?.TrimStart('/') ?? "";
|
|
|
|
if (TryHandleCultureAlias(context, path))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (HasCultureInPath(path) || IsSpecialRoute(path))
|
|
{
|
|
await _next(context);
|
|
return;
|
|
}
|
|
|
|
var detectedCulture = DetectBrowserLanguage(context);
|
|
|
|
// If the detected culture is the default, do not redirect.
|
|
if (detectedCulture == DefaultCulture)
|
|
{
|
|
await _next(context);
|
|
return;
|
|
}
|
|
|
|
var redirectUrl = $"/{detectedCulture}";
|
|
if (!string.IsNullOrEmpty(path))
|
|
{
|
|
redirectUrl += $"/{path}";
|
|
}
|
|
|
|
if (context.Request.QueryString.HasValue)
|
|
{
|
|
redirectUrl += context.Request.QueryString.Value;
|
|
}
|
|
|
|
_logger.LogInformation("Redirecting to localized URL: {RedirectUrl} (detected culture: {Culture})",
|
|
redirectUrl, detectedCulture);
|
|
|
|
context.Response.Redirect(redirectUrl, permanent: false);
|
|
}
|
|
|
|
private bool HasCultureInPath(string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path))
|
|
return false;
|
|
|
|
var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
|
if (segments.Length == 0)
|
|
return false;
|
|
|
|
return _supportedCultures.Contains(segments[0]);
|
|
}
|
|
|
|
private bool TryHandleCultureAlias(HttpContext context, string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
|
if (segments.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var firstSegment = segments[0];
|
|
if (_cultureAliases.TryGetValue(firstSegment, out var mappedCulture))
|
|
{
|
|
var remainingSegments = segments.Length > 1
|
|
? "/" + string.Join('/', segments.Skip(1))
|
|
: string.Empty;
|
|
|
|
var redirectUrl = $"/{mappedCulture}{remainingSegments}";
|
|
if (context.Request.QueryString.HasValue)
|
|
{
|
|
redirectUrl += context.Request.QueryString.Value;
|
|
}
|
|
|
|
_logger.LogInformation("Redirecting alias '{Alias}' to canonical culture URL: {RedirectUrl}", firstSegment, redirectUrl);
|
|
context.Response.Redirect(redirectUrl, permanent: true);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool IsSpecialRoute(string path)
|
|
{
|
|
var specialRoutes = new[]
|
|
{
|
|
"api/", "health", "_framework/", "lib/", "css/", "js/", "images/",
|
|
"favicon.ico", "robots.txt", "sitemap.xml",
|
|
"signin-microsoft", "signin-google", "signout-callback-oidc",
|
|
"Account/ExternalLoginCallback", "Account/Logout", "Pagamento/CreateCheckout",
|
|
"Pagamento/StripeWebhook", "api/QR", "Home/Error", "ads.txt"
|
|
};
|
|
|
|
return specialRoutes.Any(route => path.StartsWith(route, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private string DetectBrowserLanguage(HttpContext context)
|
|
{
|
|
var acceptLanguage = context.Request.GetTypedHeaders().AcceptLanguage;
|
|
|
|
if (acceptLanguage != null && acceptLanguage.Any())
|
|
{
|
|
foreach (var lang in acceptLanguage.OrderByDescending(x => x.Quality ?? 1.0))
|
|
{
|
|
var langCode = lang.Value.Value;
|
|
|
|
// Exact match for es-PY
|
|
if (string.Equals(langCode, "es-PY", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return "es-PY";
|
|
}
|
|
|
|
// Generic 'es' maps to 'es-PY'
|
|
if (langCode.StartsWith("es-", StringComparison.OrdinalIgnoreCase) || string.Equals(langCode, "es", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return "es-PY";
|
|
}
|
|
|
|
// Check for pt-BR
|
|
if (langCode.StartsWith("pt-", StringComparison.OrdinalIgnoreCase) || string.Equals(langCode, "pt", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return "pt-BR";
|
|
}
|
|
}
|
|
}
|
|
|
|
return DefaultCulture;
|
|
}
|
|
}
|
|
}
|