OneConversorTemplate/OnlyOneAccessTemplate/Services/LanguageService.cs
Ricardo Carneiro b1d75213ab first commit
2025-05-30 23:48:28 -03:00

262 lines
8.8 KiB
C#

using Microsoft.Extensions.Caching.Memory;
using System.Globalization;
namespace OnlyOneAccessTemplate.Services
{
public class LanguageService : ILanguageService
{
private readonly IMemoryCache _cache;
private readonly ILogger<LanguageService> _logger;
private static readonly Dictionary<string, string> SupportedLanguages = new()
{
{ "pt", "Português" },
{ "en", "English" },
{ "es", "Español" }
};
private static readonly Dictionary<string, string> LanguageCultures = new()
{
{ "pt", "pt-BR" },
{ "en", "en-US" },
{ "es", "es-ES" }
};
public LanguageService(IMemoryCache cache, ILogger<LanguageService> logger)
{
_cache = cache;
_logger = logger;
}
public string GetCurrentLanguage(HttpContext context)
{
try
{
// 1. Verificar na URL
var pathLanguage = GetLanguageFromPath(context.Request.Path);
if (!string.IsNullOrEmpty(pathLanguage))
{
return pathLanguage;
}
// 2. Verificar cookie de preferência
if (context.Request.Cookies.TryGetValue("preferred_language", out var cookieLanguage) &&
SupportedLanguages.ContainsKey(cookieLanguage))
{
return cookieLanguage;
}
// 3. Verificar Accept-Language header
var browserLanguage = GetLanguageFromBrowser(context);
if (!string.IsNullOrEmpty(browserLanguage))
{
return browserLanguage;
}
// 4. Retornar idioma padrão
return GetDefaultLanguage();
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao determinar idioma atual");
return GetDefaultLanguage();
}
}
public string GetLanguageFromPath(string path)
{
if (string.IsNullOrEmpty(path) || path == "/")
return string.Empty;
var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (segments.Length == 0)
return string.Empty;
var firstSegment = segments[0].ToLowerInvariant();
return SupportedLanguages.ContainsKey(firstSegment) ? firstSegment : string.Empty;
}
public List<string> GetSupportedLanguages()
{
return SupportedLanguages.Keys.ToList();
}
public string GetDefaultLanguage()
{
return "pt";
}
public string GetLanguageDisplayName(string languageCode)
{
return SupportedLanguages.TryGetValue(languageCode, out var displayName)
? displayName
: languageCode;
}
public Dictionary<string, string> GetHreflangUrls(string currentUrl, string currentLanguage)
{
var cacheKey = $"hreflang_{currentUrl}_{currentLanguage}";
if (_cache.TryGetValue(cacheKey, out Dictionary<string, string>? cachedUrls) && cachedUrls != null)
{
return cachedUrls;
}
var hreflangUrls = new Dictionary<string, string>();
try
{
var baseUrl = RemoveLanguageFromUrl(currentUrl, currentLanguage);
foreach (var language in SupportedLanguages.Keys)
{
var url = language == GetDefaultLanguage()
? baseUrl
: $"{baseUrl.TrimEnd('/')}/{language}";
hreflangUrls[language] = url;
}
// Adicionar x-default para o idioma padrão
hreflangUrls["x-default"] = hreflangUrls[GetDefaultLanguage()];
_cache.Set(cacheKey, hreflangUrls, TimeSpan.FromMinutes(15));
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao gerar URLs hreflang para {CurrentUrl}", currentUrl);
}
return hreflangUrls;
}
public string GetCultureInfo(string languageCode)
{
return LanguageCultures.TryGetValue(languageCode, out var culture) ? culture : "pt-BR";
}
public void SetLanguageCookie(HttpContext context, string languageCode)
{
if (!SupportedLanguages.ContainsKey(languageCode))
return;
var cookieOptions = new CookieOptions
{
Expires = DateTimeOffset.UtcNow.AddYears(1),
HttpOnly = false,
Secure = context.Request.IsHttps,
SameSite = SameSiteMode.Lax
};
context.Response.Cookies.Append("preferred_language", languageCode, cookieOptions);
}
public string GenerateLanguageSwitcher(HttpContext context, string currentLanguage)
{
var currentUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}";
var hreflangUrls = GetHreflangUrls(currentUrl, currentLanguage);
var switcher = new List<string>();
foreach (var language in SupportedLanguages)
{
var isActive = language.Key == currentLanguage;
var cssClass = isActive ? "active" : "";
var url = hreflangUrls.TryGetValue(language.Key, out var langUrl) ? langUrl : "/";
switcher.Add($"<a href=\"{url}\" class=\"language-link {cssClass}\" hreflang=\"{language.Key}\">{language.Value}</a>");
}
return string.Join("", switcher);
}
public bool IsRtlLanguage(string languageCode)
{
// Lista de idiomas RTL (Right-to-Left)
var rtlLanguages = new[] { "ar", "he", "fa", "ur" };
return rtlLanguages.Contains(languageCode);
}
public string GetLanguageDirection(string languageCode)
{
return IsRtlLanguage(languageCode) ? "rtl" : "ltr";
}
public bool IsValidLanguage(string languageCode)
{
return !string.IsNullOrEmpty(languageCode) && SupportedLanguages.ContainsKey(languageCode.ToLowerInvariant());
}
public string NormalizeLanguageCode(string languageCode)
{
if (string.IsNullOrEmpty(languageCode))
return GetDefaultLanguage();
var normalized = languageCode.ToLowerInvariant().Trim();
// Handle common variations
normalized = normalized switch
{
"pt-br" or "pt_br" or "portuguese" => "pt",
"en-us" or "en_us" or "english" => "en",
"es-es" or "es_es" or "spanish" or "español" => "es",
_ => normalized
};
return IsValidLanguage(normalized) ? normalized : GetDefaultLanguage();
}
private string GetLanguageFromBrowser(HttpContext context)
{
try
{
var acceptLanguage = context.Request.Headers.AcceptLanguage.ToString();
if (string.IsNullOrEmpty(acceptLanguage))
return string.Empty;
// Parse Accept-Language header
var languages = acceptLanguage
.Split(',')
.Select(lang => lang.Split(';')[0].Trim())
.Select(lang => lang.Length >= 2 ? lang.Substring(0, 2).ToLowerInvariant() : lang)
.Where(lang => SupportedLanguages.ContainsKey(lang));
return languages.FirstOrDefault() ?? string.Empty;
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao analisar Accept-Language header");
return string.Empty;
}
}
private string RemoveLanguageFromUrl(string url, string currentLanguage)
{
try
{
var uri = new Uri(url);
var path = uri.AbsolutePath;
if (currentLanguage != GetDefaultLanguage())
{
var languagePrefix = $"/{currentLanguage}";
if (path.StartsWith(languagePrefix))
{
path = path.Substring(languagePrefix.Length);
if (string.IsNullOrEmpty(path))
path = "/";
}
}
return $"{uri.Scheme}://{uri.Host}{(uri.Port != 80 && uri.Port != 443 ? $":{uri.Port}" : "")}{path}";
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro ao remover idioma da URL {Url}", url);
return url;
}
}
}
}