fix locale
This commit is contained in:
@@ -20,19 +20,16 @@
|
|||||||
<span style="padding-left:10px;"><NavLink href="/account/login">Login</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/account/login">Login</NavLink></span>
|
||||||
<span style="padding-left:10px;"><NavLink href="/weather">Weather</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/weather">Weather</NavLink></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:16px;">
|
<div style="margin-top:16px;">
|
||||||
<strong>zh Quick links:</strong>
|
<strong>zh Quick links:</strong>
|
||||||
<span style="padding-left:10px;"><NavLink href="/zh/account/login">Login</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/zh/account/login">Login</NavLink></span>
|
||||||
<span style="padding-left:10px;"><NavLink href="/zh/weather">Weather</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/zh/weather">Weather</NavLink></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:16px;">
|
<div style="margin-top:16px;">
|
||||||
<strong>en Quick links:</strong>
|
<strong>en Quick links:</strong>
|
||||||
<span style="padding-left:10px;"><NavLink href="/en/account/login">Login</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/en/account/login">Login</NavLink></span>
|
||||||
<span style="padding-left:10px;"><NavLink href="/en/weather">Weather</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/en/weather">Weather</NavLink></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@@ -40,35 +37,20 @@
|
|||||||
|
|
||||||
private int currentCount = 0;
|
private int currentCount = 0;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (LocalizationProvider != null)
|
// localization handled globally in Routes. No per-page initialization needed.
|
||||||
{
|
return Task.CompletedTask;
|
||||||
LocalizationProvider.LanguageChanged += OnLanguageChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If running in browser, ensure current culture loaded (WASM loads asynchronously)
|
|
||||||
if (OperatingSystem.IsBrowser() && LocalizationProvider != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await LocalizationProvider.LoadCultureAsync(LocalizationProvider.CurrentCulture);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLanguageChanged(object? sender, string culture)
|
private void OnLanguageChanged(object? sender, string culture)
|
||||||
{
|
{
|
||||||
_ = InvokeAsync(StateHasChanged);
|
// no-op; global router remount will update page translations
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (LocalizationProvider != null)
|
// no per-page unsubscribe required
|
||||||
{
|
|
||||||
LocalizationProvider.LanguageChanged -= OnLanguageChanged;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IncrementCount()
|
private void IncrementCount()
|
||||||
|
|||||||
@@ -111,11 +111,6 @@ else
|
|||||||
{
|
{
|
||||||
handler = "Server";
|
handler = "Server";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LocalizationProvider != null)
|
|
||||||
{
|
|
||||||
LocalizationProvider.LanguageChanged += OnLanguageChanged;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
@@ -133,25 +128,6 @@ else
|
|||||||
dataLoaded = true;
|
dataLoaded = true;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure culture loaded on client so translations are available
|
|
||||||
if (firstRender && OperatingSystem.IsBrowser() && LocalizationProvider != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await LocalizationProvider.LoadCultureAsync(LocalizationProvider.CurrentCulture);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnLanguageChanged(object? sender, string culture)
|
|
||||||
{
|
|
||||||
// ensure UI updates on Blazor sync context
|
|
||||||
await InvokeAsync(() => {
|
|
||||||
dataLoaded = true; // ensure UI is rendered
|
|
||||||
StateHasChanged();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoginAsync()
|
private async Task LoginAsync()
|
||||||
|
|||||||
@@ -17,6 +17,18 @@
|
|||||||
<span style="padding-left:10px;"><NavLink href="/counter">Counter</NavLink></span>
|
<span style="padding-left:10px;"><NavLink href="/counter">Counter</NavLink></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:12px; margin-bottom:12px;">
|
||||||
|
<strong>zh Quick links:</strong>
|
||||||
|
<span style="padding-left:10px;"><NavLink href="/zh/account/login">Login</NavLink></span>
|
||||||
|
<span style="padding-left:10px;"><NavLink href="/zh/counter">Counter</NavLink></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:12px; margin-bottom:12px;">
|
||||||
|
<strong>en Quick links:</strong>
|
||||||
|
<span style="padding-left:10px;"><NavLink href="/en/account/login">Login</NavLink></span>
|
||||||
|
<span style="padding-left:10px;"><NavLink href="/en/counter">Counter</NavLink></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
@if (forecasts == null)
|
@if (forecasts == null)
|
||||||
{
|
{
|
||||||
<p><em>Loading...</em></p>
|
<p><em>Loading...</em></p>
|
||||||
@@ -51,34 +63,13 @@ else
|
|||||||
public string Locale { get; set; } = string.Empty;
|
public string Locale { get; set; } = string.Empty;
|
||||||
private WeatherForecast[]? forecasts;
|
private WeatherForecast[]? forecasts;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (LocalizationProvider != null)
|
// localization handled globally in Routes. No per-page initialization needed.
|
||||||
{
|
return Task.CompletedTask;
|
||||||
LocalizationProvider.LanguageChanged += OnLanguageChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OperatingSystem.IsBrowser() && LocalizationProvider != null)
|
public void Dispose() { }
|
||||||
{
|
|
||||||
try { await LocalizationProvider.LoadCultureAsync(LocalizationProvider.CurrentCulture); } catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate asynchronous loading to demonstrate a loading indicator
|
|
||||||
await Task.Delay(500);
|
|
||||||
|
|
||||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
|
||||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
|
||||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
|
||||||
{
|
|
||||||
Date = startDate.AddDays(index),
|
|
||||||
TemperatureC = Random.Shared.Next(-20, 55),
|
|
||||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
|
||||||
}).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLanguageChanged(object? s, string c) => _ = InvokeAsync(StateHasChanged);
|
|
||||||
|
|
||||||
public void Dispose() { if (LocalizationProvider != null) LocalizationProvider.LanguageChanged -= OnLanguageChanged; }
|
|
||||||
|
|
||||||
private class WeatherForecast
|
private class WeatherForecast
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
@inject Atomx.Admin.Client.Services.ILocalizationProvider LocalizationProvider
|
@inject Atomx.Admin.Client.Services.ILocalizationProvider LocalizationProvider
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
<div @key="LocalizationProvider.CurrentCulture">
|
||||||
<Router AppAssembly="typeof(Program).Assembly">
|
<Router AppAssembly="typeof(Program).Assembly">
|
||||||
<Found Context="routeData">
|
<Found Context="routeData">
|
||||||
<CascadingValue Value="routeData">
|
<CascadingValue Value="routeData">
|
||||||
@@ -13,11 +15,87 @@
|
|||||||
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||||
</Found>
|
</Found>
|
||||||
</Router>
|
</Router>
|
||||||
|
</div>
|
||||||
<AntContainer />
|
<AntContainer />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
// Subscribe to language changes to remount router when needed
|
||||||
|
if (LocalizationProvider != null)
|
||||||
|
{
|
||||||
|
LocalizationProvider.LanguageChanged += OnLanguageChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to navigation events so client-side nav to /zh/... or /en/... triggers culture change
|
||||||
|
Navigation.LocationChanged += OnLocationChanged;
|
||||||
|
|
||||||
|
// Try detect first URL segment as short culture (e.g. /zh/ or /en/) and set culture before first render
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var relative = Navigation.ToBaseRelativePath(Navigation.Uri).Trim('/');
|
||||||
|
var segments = string.IsNullOrEmpty(relative) ? Array.Empty<string>() : relative.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var first = segments.FirstOrDefault();
|
||||||
|
var mapping = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "zh", "zh-Hans" },
|
||||||
|
{ "en", "en-US" }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(first) && mapping.TryGetValue(first, out var mapped))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsBrowser())
|
||||||
|
{
|
||||||
|
await LocalizationProvider.SetCultureAsync(mapped);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (LocalizationProvider is Atomx.Admin.Client.Services.LocalizationProvider concrete)
|
||||||
|
{
|
||||||
|
concrete.SetCultureForServer(mapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnLocationChanged(object? sender, LocationChangedEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var relative = Navigation.ToBaseRelativePath(args.Location).Trim('/');
|
||||||
|
var segments = string.IsNullOrEmpty(relative) ? Array.Empty<string>() : relative.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var first = segments.FirstOrDefault();
|
||||||
|
if (string.IsNullOrEmpty(first)) return;
|
||||||
|
|
||||||
|
var mapping = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
{ "zh", "zh-Hans" },
|
||||||
|
{ "en", "en-US" }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mapping.TryGetValue(first, out var mapped))
|
||||||
|
{
|
||||||
|
// if culture already set to same, skip
|
||||||
|
if (string.Equals(LocalizationProvider.CurrentCulture, mapped, StringComparison.OrdinalIgnoreCase)) return;
|
||||||
|
|
||||||
|
// Call async set; ignore errors
|
||||||
|
await LocalizationProvider.SetCultureAsync(mapped);
|
||||||
|
|
||||||
|
// Trigger router remount via StateHasChanged
|
||||||
|
_ = InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender && !_initialized)
|
if (firstRender && !_initialized)
|
||||||
@@ -33,4 +111,19 @@
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnLanguageChanged(object? s, string culture)
|
||||||
|
{
|
||||||
|
// Remount router via @key by triggering StateHasChanged
|
||||||
|
_ = InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (LocalizationProvider != null)
|
||||||
|
{
|
||||||
|
LocalizationProvider.LanguageChanged -= OnLanguageChanged;
|
||||||
|
}
|
||||||
|
Navigation.LocationChanged -= OnLocationChanged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
@@ -33,7 +34,9 @@ namespace Atomx.Admin.Client.Services
|
|||||||
private readonly ILocalizationService _localizationService;
|
private readonly ILocalizationService _localizationService;
|
||||||
|
|
||||||
// <20><><EFBFBD>棺culture -> translations
|
// <20><><EFBFBD>棺culture -> translations
|
||||||
private readonly Dictionary<string, Dictionary<string, string>> _cache = new();
|
// Use a static concurrent dictionary so files loaded during middleware/server prerender
|
||||||
|
// are visible to provider instances created later in the same request pipeline.
|
||||||
|
private static readonly ConcurrentDictionary<string, Dictionary<string, string>> _cache = new();
|
||||||
|
|
||||||
// <20><><EFBFBD>뵽<EFBFBD><EBB5BD><EFBFBD><EFBFBD> culture <20><>ӳ<EFBFBD><D3B3>
|
// <20><><EFBFBD>뵽<EFBFBD><EBB5BD><EFBFBD><EFBFBD> culture <20><>ӳ<EFBFBD><D3B3>
|
||||||
private static readonly Dictionary<string, string> ShortToCulture = new(StringComparer.OrdinalIgnoreCase)
|
private static readonly Dictionary<string, string> ShortToCulture = new(StringComparer.OrdinalIgnoreCase)
|
||||||
@@ -231,6 +234,70 @@ namespace Atomx.Admin.Client.Services
|
|||||||
|
|
||||||
public Task LoadCultureAsync(string culture) => EnsureCultureLoadedAsync(MapToFullCulture(culture));
|
public Task LoadCultureAsync(string culture) => EnsureCultureLoadedAsync(MapToFullCulture(culture));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Server-side synchronous culture set used during prerender to ensure translations
|
||||||
|
/// are available immediately. This method will attempt to load localization
|
||||||
|
/// JSON from the server's webroot synchronously and set thread cultures.
|
||||||
|
/// </summary>
|
||||||
|
public void SetCultureForServer(string cultureShortOrFull)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cultureFull = MapToFullCulture(cultureShortOrFull);
|
||||||
|
if (string.IsNullOrEmpty(cultureFull)) return;
|
||||||
|
|
||||||
|
// set thread culture
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ci = new CultureInfo(cultureFull);
|
||||||
|
CultureInfo.DefaultThreadCurrentCulture = ci;
|
||||||
|
CultureInfo.DefaultThreadCurrentUICulture = ci;
|
||||||
|
_currentCulture = cultureFull;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
// try load from webroot synchronously via IWebHostEnvironment if available
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var envType = Type.GetType("Microsoft.AspNetCore.Hosting.IWebHostEnvironment, Microsoft.AspNetCore.Hosting.Abstractions")
|
||||||
|
?? Type.GetType("Microsoft.AspNetCore.Hosting.IWebHostEnvironment");
|
||||||
|
if (envType != null)
|
||||||
|
{
|
||||||
|
var env = _sp.GetService(envType);
|
||||||
|
if (env != null)
|
||||||
|
{
|
||||||
|
var webRootProp = envType.GetProperty("WebRootPath");
|
||||||
|
var contentRootProp = envType.GetProperty("ContentRootPath");
|
||||||
|
var webRoot = webRootProp?.GetValue(env) as string ?? Path.Combine(contentRootProp?.GetValue(env) as string ?? ".", "wwwroot");
|
||||||
|
var path = Path.Combine(webRoot ?? ".", "localization", cultureFull + ".json");
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(path);
|
||||||
|
var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
|
||||||
|
_cache[cultureFull] = dict;
|
||||||
|
_logger?.LogInformation("(Server sync) Loaded localization file for {Culture} from path {Path}, entries: {Count}", cultureFull, path, dict.Count);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.LogWarning(ex, "(Server sync) Failed to read localization file synchronously: {Path}", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.LogDebug(ex, "SetCultureForServer failed to load file for {Culture}", cultureFull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.LogDebug(ex, "SetCultureForServer encountered error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SetCultureInternalAsync(string cultureFull, bool persistCookie)
|
private async Task SetCultureInternalAsync(string cultureFull, bool persistCookie)
|
||||||
{
|
{
|
||||||
_logger?.LogDebug("SetCultureInternalAsync start: {Culture}, persist={Persist}", cultureFull, persistCookie);
|
_logger?.LogDebug("SetCultureInternalAsync start: {Culture}, persist={Persist}", cultureFull, persistCookie);
|
||||||
|
|||||||
@@ -26,24 +26,55 @@ namespace Atomx.Admin.Middlewares
|
|||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context)
|
public async Task InvokeAsync(HttpContext context)
|
||||||
{
|
{
|
||||||
|
var logger = context.RequestServices.GetService(typeof(ILogger<RequestCultureMiddleware>)) as ILogger<RequestCultureMiddleware>;
|
||||||
|
|
||||||
var path = context.Request.Path.Value ?? "/";
|
var path = context.Request.Path.Value ?? "/";
|
||||||
|
logger?.LogDebug("RequestCultureMiddleware start for path {Path}", path);
|
||||||
var trimmed = path.Trim('/');
|
var trimmed = path.Trim('/');
|
||||||
if (!string.IsNullOrEmpty(trimmed))
|
if (!string.IsNullOrEmpty(trimmed))
|
||||||
{
|
{
|
||||||
var segments = trimmed.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
var segments = trimmed.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
var first = segments.FirstOrDefault();
|
var first = segments.FirstOrDefault();
|
||||||
|
logger?.LogDebug("RequestCultureMiddleware firstSegment='{Seg}'", first);
|
||||||
if (!string.IsNullOrEmpty(first) && ShortToCulture.TryGetValue(first, out var cultureName))
|
if (!string.IsNullOrEmpty(first) && ShortToCulture.TryGetValue(first, out var cultureName))
|
||||||
{
|
{
|
||||||
|
logger?.LogInformation("RequestCultureMiddleware detected locale prefix '{Prefix}' -> {Culture}", first, cultureName);
|
||||||
|
|
||||||
// 设置线程 Culture(影响后续处理中 IStringLocalizer / 日期格式等)
|
// 设置线程 Culture(影响后续处理中 IStringLocalizer / 日期格式等)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ci = new CultureInfo(cultureName);
|
var ci = new CultureInfo(cultureName);
|
||||||
CultureInfo.DefaultThreadCurrentCulture = ci;
|
CultureInfo.DefaultThreadCurrentCulture = ci;
|
||||||
CultureInfo.DefaultThreadCurrentUICulture = ci;
|
CultureInfo.DefaultThreadCurrentUICulture = ci;
|
||||||
|
logger?.LogDebug("Thread culture set to {Culture}", cultureName);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 忽略非法 culture
|
logger?.LogWarning(ex, "Failed to set thread culture to {Culture}", cultureName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to synchronously load localization for server-side rendering
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var providerObj = context.RequestServices.GetService(typeof(Atomx.Admin.Client.Services.ILocalizationProvider));
|
||||||
|
if (providerObj == null)
|
||||||
|
{
|
||||||
|
logger?.LogDebug("ILocalizationProvider not registered in RequestServices");
|
||||||
|
}
|
||||||
|
else if (providerObj is Atomx.Admin.Client.Services.LocalizationProvider provider)
|
||||||
|
{
|
||||||
|
logger?.LogDebug("Calling SetCultureForServer on LocalizationProvider with {Culture}", cultureName);
|
||||||
|
provider.SetCultureForServer(cultureName);
|
||||||
|
logger?.LogInformation("LocalizationProvider.CurrentCulture after SetCultureForServer: {Culture}", provider.CurrentCulture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger?.LogDebug("ILocalizationProvider resolved but not the concrete LocalizationProvider type: {Type}", providerObj.GetType().FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger?.LogWarning(ex, "Error while invoking SetCultureForServer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将请求路径去掉首段语言前缀,便于后续路由匹配(例如 /zh/account -> /account)
|
// 将请求路径去掉首段语言前缀,便于后续路由匹配(例如 /zh/account -> /account)
|
||||||
@@ -66,6 +97,7 @@ namespace Atomx.Admin.Middlewares
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger?.LogDebug("RequestCultureMiddleware found no locale prefix for path {Path}", path);
|
||||||
await _next(context);
|
await _next(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,8 +207,8 @@ app.UseResponseCompression();
|
|||||||
// ʹ<><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> CORS <20><><EFBFBD><EFBFBD>
|
// ʹ<><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> CORS <20><><EFBFBD><EFBFBD>
|
||||||
app.UseCors("DefaultCors");
|
app.UseCors("DefaultCors");
|
||||||
|
|
||||||
//// ע<><D7A2> RequestCultureMiddleware<72><65>ʹ<EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Culture <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ
|
// ע<><D7A2> RequestCultureMiddleware<72><65>ʹ<EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Culture <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ
|
||||||
//app.UseMiddleware<RequestCultureMiddleware>();
|
app.UseMiddleware<RequestCultureMiddleware>();
|
||||||
|
|
||||||
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
app.UseStaticFiles(new StaticFileOptions
|
||||||
|
|||||||
Reference in New Issue
Block a user