feat: Implement URL-based culture detection, localization cache busting, and enable full Blazor WASM globalization data.

This commit is contained in:
Ho Ngoc Hai
2026-01-19 12:19:15 +07:00
parent 4c4aab4883
commit 8de0a7e7c0
4 changed files with 36 additions and 8 deletions

View File

@@ -5,7 +5,7 @@
<ActivatorContent>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Class="mr-2 cursor-pointer">
<MudText Typo="Typo.button" Style="font-family: var(--font-heading);">
@(CultureInfo.CurrentCulture.Name.StartsWith("vi") ? "VI" : "EN")
@GetCurrentLabel()
</MudText>
<MudIcon Icon="@Icons.Material.Rounded.Language" Size="Size.Small" />
</MudStack>
@@ -27,13 +27,24 @@
</MudMenu>
@code {
private string GetCurrentLabel()
{
var uri = new Uri(Navigation.Uri);
var path = uri.PathAndQuery;
// Simple heuristic: if path starts with /vi-VN or /vi, show VI. Default EN.
if (path.StartsWith("/vi", StringComparison.OrdinalIgnoreCase))
{
return "VI";
}
return "EN";
}
private void SwitchLanguage(string targetCulture)
{
var uri = new Uri(Navigation.Uri);
var path = uri.PathAndQuery;
// Simple logic to replace or prepend culture segment
// Check if path starts with a supported culture
var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
string newPath;
@@ -42,13 +53,11 @@
segments[0].Equals("vi", StringComparison.OrdinalIgnoreCase) ||
segments[0].Equals("en", StringComparison.OrdinalIgnoreCase)))
{
// Replace first segment
segments[0] = targetCulture;
newPath = "/" + string.Join('/', segments);
}
else
{
// Prepend
if (path == "/") path = "";
newPath = $"/{targetCulture}{path}";
}

View File

@@ -35,7 +35,7 @@ public class LocalizationCache
if (cultureName == "vi") cultureName = "vi-VN";
if (cultureName == "en") cultureName = "en-US";
var loaded = await _httpClient.GetFromJsonAsync<Dictionary<string, string>>($"/locales/{cultureName}.json");
var loaded = await _httpClient.GetFromJsonAsync<Dictionary<string, string>>($"/locales/{cultureName}.json?v={DateTime.Now.Ticks}");
if (loaded != null)
{
_strings = loaded;

View File

@@ -27,8 +27,26 @@ builder.Services.AddSingleton<IStringLocalizerFactory, JsonStringLocalizerFactor
// Build the host
var host = builder.Build();
// Initialize Localization Cache
// Initialize Localization Cache
var cache = host.Services.GetRequiredService<LocalizationCache>();
await cache.LoadAsync(CultureInfo.CurrentCulture);
// Detect culture from BaseAddress (which is set by <base href> from Server)
var baseAddress = builder.HostEnvironment.BaseAddress;
var culture = new CultureInfo("en-US"); // Default
if (baseAddress.Contains("/vi-VN/", StringComparison.OrdinalIgnoreCase))
{
culture = new CultureInfo("vi-VN");
}
else if (baseAddress.Contains("/vi/", StringComparison.OrdinalIgnoreCase))
{
culture = new CultureInfo("vi-VN");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await cache.LoadAsync(culture);
await host.RunAsync();

View File

@@ -5,6 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
<ItemGroup>