实现多语言切换

This commit is contained in:
2025-12-09 03:31:07 +08:00
parent 9631e00a12
commit 429fb39140
18 changed files with 1173 additions and 41 deletions

View File

@@ -4,8 +4,11 @@
@layout EmptyLayout
@inject ILogger<Login> Logger
@inject IJSRuntime JS
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<Login> L
@inject Atomx.Admin.Client.Services.ILocalizationProvider LocalizationProvider
<PageTitle>登录</PageTitle>
<PageTitle>@L["login.title"]</PageTitle>
@if (!dataLoaded)
{
@@ -20,29 +23,29 @@ else
<Form @ref="form" Model="@login" OnFinish="LoginAsync">
<FluentValidationValidator />
<FormItem>
<AntDesign.Input Placeholder="登录账号" Size="InputSize.Large" @bind-Value="@login.Account">
<AntDesign.Input Placeholder="@L["login.account.placeholder"]" Size="InputSize.Large" @bind-Value="@login.Account">
<Prefix><Icon Type="user" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<AntDesign.Input Placeholder="登录密码" Size="InputSize.Large" @bind-Value="@login.Password" Type="InputType.Password">
<AntDesign.Input Placeholder="@L["login.password.placeholder"]" Size="InputSize.Large" @bind-Value="@login.Password" Type="InputType.Password">
<Prefix><Icon Type="lock" /></Prefix>
</AntDesign.Input>
</FormItem>
<FormItem>
<a style="float: left;">
忘记密码
@L["login.forgot"]
</a>
<a style="float: right;">
<NavLink href="/register">马上注册</NavLink>
<NavLink href="/register">@L["login.register"]</NavLink>
</a>
</FormItem>
<FormItem>
<Button Type="ButtonType.Primary" HtmlType="submit" Class="submit" Size="ButtonSize.Large" Block>登录</Button>
<Button Type="ButtonType.Primary" HtmlType="submit" Class="submit" Size="ButtonSize.Large" Block>@L["login.submit"]</Button>
</FormItem>
<FormItem>
<a @onclick="setAccount">
设置开发帐号
@L["login.setdev"]
</a>
</FormItem>
</Form>
@@ -50,9 +53,31 @@ else
</GridCol>
</GridRow>
<GridRow Style="padding-top:40px">
<span style="font-size:12px;padding-right:3px;">Copyright © 2025-@DateTime.Now.Year Atomlust.com All rights reserved.</span>
<span style="font-size:12px;padding-right:3px;">@L["copyright"]</span>
<span style="font-size:12px">runing as @handler</span>
</GridRow>
<GridRow>
<Atomx.Admin.Client.Components.LangSelector />
</GridRow>
<GridRow Style="padding-top:10px">
<div>
<strong>Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/weather">Weather</NavLink></span>
</div>
<div>
<strong>zh Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/zh/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/zh/weather">Weather</NavLink></span>
</div>
<div>
<strong>en Quick links:</strong>
<span style="padding-left:10px;"><NavLink href="/en/counter">Counter</NavLink></span>
<span style="padding-left:10px;"><NavLink href="/en/weather">Weather</NavLink></span>
</div>
</GridRow>
</Flex>
}
@@ -86,6 +111,11 @@ else
{
handler = "Server";
}
if (LocalizationProvider != null)
{
LocalizationProvider.LanguageChanged += OnLanguageChanged;
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
@@ -103,6 +133,25 @@ else
dataLoaded = true;
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()
@@ -200,6 +249,15 @@ else
login.Account = "admin";
login.Password = "admin888";
}
private string GetShortCulture(string current)
{
if (string.IsNullOrEmpty(current)) return current;
if (current.StartsWith("zh", StringComparison.OrdinalIgnoreCase)) return "zh";
if (current.StartsWith("en", StringComparison.OrdinalIgnoreCase)) return "en";
var prefix = current.Split('-', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
return prefix ?? current;
}
}
@* 页面内 JS 辅助:用于在 Server 模式下从浏览器发起 POST 并携带凭证,使浏览器接收 Set-Cookie *@