From ed2e3ecd24eec3db66612ccb1c5da9dbe6079aa8 Mon Sep 17 00:00:00 2001
From: yxw <17074267@qq.com>
Date: Tue, 9 Dec 2025 19:10:10 +0800
Subject: [PATCH] fix localization
---
.../Atomx.Admin.Client.csproj | 11 ++-
.../Atomx.Admin.Client/Pages/Login.razor | 69 +++--------------
Atomx.Admin/Atomx.Admin.Client/Program.cs | 8 +-
.../Services/LocalizationProvider.cs | 2 +-
Atomx.Admin/Atomx.Admin.Client/_Imports.razor | 6 +-
.../Atomx.Admin.Client/wwwroot/js/common.js | 74 ++++++++++++-------
Atomx.Admin/Atomx.Admin/Atomx.Admin.csproj | 8 +-
Atomx.Admin/Atomx.Admin/Program.cs | 32 --------
Atomx.Admin/Atomx.Admin/appsettings.json | 2 +-
9 files changed, 81 insertions(+), 131 deletions(-)
diff --git a/Atomx.Admin/Atomx.Admin.Client/Atomx.Admin.Client.csproj b/Atomx.Admin/Atomx.Admin.Client/Atomx.Admin.Client.csproj
index d442b1b..9a1ffb5 100644
--- a/Atomx.Admin/Atomx.Admin.Client/Atomx.Admin.Client.csproj
+++ b/Atomx.Admin/Atomx.Admin.Client/Atomx.Admin.Client.csproj
@@ -8,6 +8,13 @@
Default
+
+
+
+
+
+
+
@@ -26,8 +33,4 @@
-
-
-
-
diff --git a/Atomx.Admin/Atomx.Admin.Client/Pages/Login.razor b/Atomx.Admin/Atomx.Admin.Client/Pages/Login.razor
index f45f7dc..f7ce2dc 100644
--- a/Atomx.Admin/Atomx.Admin.Client/Pages/Login.razor
+++ b/Atomx.Admin/Atomx.Admin.Client/Pages/Login.razor
@@ -1,12 +1,9 @@
@page "/account/login"
@page "/{locale}/account/login"
-@using System.Text.Json
@layout EmptyLayout
@inject ILogger Logger
-@inject IJSRuntime JS
-@using Microsoft.Extensions.Localization
@inject IStringLocalizer L
-@inject Atomx.Admin.Client.Services.ILocalizationProvider LocalizationProvider
+
@L["login.title"]
@@ -144,41 +141,30 @@ else
if (!OperatingSystem.IsBrowser())
{
// Server 模式:使用浏览器发起的 fetch(通过 JS)并携带 credentials: 'include'
- Logger.LogInformation("Server 模式,使用浏览器 fetch 登录");
- var jsResult = await JS.InvokeAsync("__atomx_post_json", api, login);
-
- var success = jsResult.TryGetProperty("success", out var sprop) && sprop.GetBoolean();
- if (success && jsResult.TryGetProperty("data", out var dprop) && dprop.ValueKind == JsonValueKind.Object)
+ var jsResult = await JS.InvokeAsync("ajax.Post", api, login);
+ var result = jsResult.ToJson().FromJson>();
+ if (result != null && result.Success)
{
- var token = dprop.TryGetProperty("token", out var t) ? t.GetString() ?? string.Empty : string.Empty;
- var refresh = dprop.TryGetProperty("refreshToken", out var r) ? r.GetString() ?? string.Empty : string.Empty;
+ var auth = result.Data;
+ await localStorage.SetItemAsync(StorageKeys.AccessToken, auth.Token);
+ await localStorage.SetItemAsync(StorageKeys.RefreshToken, auth.RefreshToken);
- // WASM 的 localStorage 在 Server Circuit 中无意义,兼容auto模式写入 localStorage。
- try
+ if (AuthStateProvider is PersistentAuthenticationStateProvider provider)
{
- await localStorage.SetItemAsync(StorageKeys.AccessToken, token);
- await localStorage.SetItemAsync(StorageKeys.RefreshToken, refresh);
-
- if (AuthStateProvider is PersistentAuthenticationStateProvider provider)
- {
- provider.UpdateAuthenticationState(token);
- }
+ provider.UpdateAuthenticationState(auth.Token);
}
- catch { }
- // 浏览器已通过 fetch 收到 Set-Cookie;强制重载使 Circuit 使用新 Cookie。
Logger.LogInformation($"登录成功,server 跳转: {ReturnUrl}");
Navigation.NavigateTo(ReturnUrl ?? "/", forceLoad: true);
}
else
{
- var msg = jsResult.TryGetProperty("message", out var m) ? m.GetString() ?? "登录失败" : "登录失败";
- ModalService.Error(new ConfirmOptions() { Title = "提示", Content = msg });
+ ModalService.Error(new ConfirmOptions() { Title = "提示", Content = result.Message });
}
}
else
{
- // Wasm 模式:继续使用 HttpService(之前逻辑),保存 localStorage 并更新 AuthStateProvider
+ // Wasm 模式:保存 localStorage 并更新 AuthStateProvider
var result = await HttpService.Post>(api, login);
if (result.Success && result.Data != null)
{
@@ -225,35 +211,4 @@ 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 *@
-
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/Atomx.Admin/Atomx.Admin.Client/Program.cs b/Atomx.Admin/Atomx.Admin.Client/Program.cs
index f83dfb8..bd2d48d 100644
--- a/Atomx.Admin/Atomx.Admin.Client/Program.cs
+++ b/Atomx.Admin/Atomx.Admin.Client/Program.cs
@@ -1,14 +1,12 @@
using Atomx.Admin.Client.Services;
using Atomx.Admin.Client.Utils;
+using Atomx.Admin.Client.Validators;
using Blazored.LocalStorage;
+using FluentValidation;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Localization;
-using System.Net.Http;
-using FluentValidation;
-using System.Linq;
-using System.Reflection;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
@@ -70,7 +68,7 @@ builder.Services.AddScoped(sp =>
return new HttpService(httpClient, httpContextAccessor);
});
-builder.Services.AddValidatorsFromAssembly(typeof(Atomx.Admin.Client.Validators.LoginModelValidator).Assembly);
+builder.Services.AddValidatorsFromAssembly(typeof(LoginModelValidator).Assembly);
builder.Services.AddAntDesign();
diff --git a/Atomx.Admin/Atomx.Admin.Client/Services/LocalizationProvider.cs b/Atomx.Admin/Atomx.Admin.Client/Services/LocalizationProvider.cs
index f3938d8..8a8b9f3 100644
--- a/Atomx.Admin/Atomx.Admin.Client/Services/LocalizationProvider.cs
+++ b/Atomx.Admin/Atomx.Admin.Client/Services/LocalizationProvider.cs
@@ -300,7 +300,7 @@ namespace Atomx.Admin.Client.Services
private async Task SetCultureInternalAsync(string cultureFull, bool persistCookie)
{
- _logger?.LogDebug("SetCultureInternalAsync start: {Culture}, persist={Persist}", cultureFull, persistCookie);
+ //_logger?.LogDebug("ڲĻ첽ʼ: {Culture}, ־û={Persist}", cultureFull, persistCookie);
await EnsureCultureLoadedAsync(cultureFull);
try
diff --git a/Atomx.Admin/Atomx.Admin.Client/_Imports.razor b/Atomx.Admin/Atomx.Admin.Client/_Imports.razor
index 91cc495..98a7ad9 100644
--- a/Atomx.Admin/Atomx.Admin.Client/_Imports.razor
+++ b/Atomx.Admin/Atomx.Admin.Client/_Imports.razor
@@ -1,5 +1,6 @@
@using System.Net.Http
@using System.Net.Http.Json
+@using System.Text.Json
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@@ -32,10 +33,11 @@
@using Blazored.FluentValidation
-
+@inject IJSRuntime JS
@inject ILocalStorageService localStorage
+@inject ILocalizationProvider LocalizationProvider
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager Navigation
@inject HttpService HttpService
@inject MessageService MessageService
-@inject ModalService ModalService
\ No newline at end of file
+@inject ModalService ModalService
diff --git a/Atomx.Admin/Atomx.Admin.Client/wwwroot/js/common.js b/Atomx.Admin/Atomx.Admin.Client/wwwroot/js/common.js
index 42e4be5..bf2ede7 100644
--- a/Atomx.Admin/Atomx.Admin.Client/wwwroot/js/common.js
+++ b/Atomx.Admin/Atomx.Admin.Client/wwwroot/js/common.js
@@ -1,34 +1,58 @@
window.cookies = {
- Read: function (name) {
- try {
- const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
- if (match) return decodeURIComponent(match[2]);
- return '';
- } catch (e) {
- return '';
+ Read: function (name) {
+ try {
+ const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
+ if (match) return decodeURIComponent(match[2]);
+ return '';
+ } catch (e) {
+ return '';
+ }
+ },
+ Write: function (name, value, expiresIso) {
+ try {
+ var expires = '';
+ if (expiresIso) {
+ expires = '; expires=' + new Date(expiresIso).toUTCString();
+ }
+ document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/';
+ } catch (e) { }
+ },
+ Delete: function (cookie_name) {
+ document.cookie = cookie_name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+ }
+};
+
+window.ajax = {
+ Post: async function (url, data) {
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ credentials: 'include',
+ body: JSON.stringify(data)
+ });
+ const text = await res.text();
+ try {
+ return JSON.parse(text);
+ } catch {
+ return { success: res.ok, message: text };
+ }
+ } catch (err) {
+ return { success: false, message: err?.toString() ?? 'network error' };
+ }
}
- },
- Write: function (name, value, expiresIso) {
- try {
- var expires = '';
- if (expiresIso) {
- expires = '; expires=' + new Date(expiresIso).toUTCString();
- }
- document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/';
- } catch (e) { }
- }
};
window.getBrowserLanguage = function () {
- try {
- return (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage || '';
- } catch (e) {
- return '';
- }
+ try {
+ return (navigator.languages && navigator.languages[0]) || navigator.language || navigator.userLanguage || '';
+ } catch (e) {
+ return '';
+ }
};
window.setHtmlLang = function (lang) {
- try {
- if (document && document.documentElement) document.documentElement.lang = lang || '';
- } catch (e) { }
+ try {
+ if (document && document.documentElement) document.documentElement.lang = lang || '';
+ } catch (e) { }
};
diff --git a/Atomx.Admin/Atomx.Admin/Atomx.Admin.csproj b/Atomx.Admin/Atomx.Admin/Atomx.Admin.csproj
index b6ede15..367211d 100644
--- a/Atomx.Admin/Atomx.Admin/Atomx.Admin.csproj
+++ b/Atomx.Admin/Atomx.Admin/Atomx.Admin.csproj
@@ -8,9 +8,13 @@
+
+
+
+
@@ -43,8 +47,4 @@
-
-
-
-
diff --git a/Atomx.Admin/Atomx.Admin/Program.cs b/Atomx.Admin/Atomx.Admin/Program.cs
index 9b77014..d021fee 100644
--- a/Atomx.Admin/Atomx.Admin/Program.cs
+++ b/Atomx.Admin/Atomx.Admin/Program.cs
@@ -155,38 +155,6 @@ builder.Services.AddValidatorsFromAssembly(typeof(Atomx.Admin.Client.Validators.
var app = builder.Build();
-// Preload localization files on startup to ensure server-side rendering finds translations
-try
-{
- using var scope = app.Services.CreateScope();
- var logger = scope.ServiceProvider.GetService()?.CreateLogger("LocalizationStartup");
- var provider = scope.ServiceProvider.GetService();
- if (provider != null)
- {
- logger?.LogInformation("Preloading localization files for server startup");
- // preload supported cultures
- var supported = new[] { "zh-Hans", "en-US" };
- foreach (var c in supported)
- {
- try
- {
- provider.LoadCultureAsync(c).GetAwaiter().GetResult();
- logger?.LogInformation("Preloaded localization for {Culture}", c);
- }
- catch (Exception ex)
- {
- logger?.LogWarning(ex, "Failed to preload localization for {Culture}", c);
- }
- }
- }
-}
-catch (Exception ex)
-{
- // don't block startup
- var l = app.Services.GetService()?.CreateLogger("LocalizationStartup");
- l?.LogWarning(ex, "Failed to run localization preload");
-}
-
app.AddDataMigrate();
// Forwarded headers
diff --git a/Atomx.Admin/Atomx.Admin/appsettings.json b/Atomx.Admin/Atomx.Admin/appsettings.json
index 7c1b3d1..96bb03d 100644
--- a/Atomx.Admin/Atomx.Admin/appsettings.json
+++ b/Atomx.Admin/Atomx.Admin/appsettings.json
@@ -68,7 +68,7 @@
},
"Seq": {
- "ServerUrl": "http://log.firestones.cn/",
+ "ServerUrl": "http://log.atomlust.com/",
"ApiKey": "bBWmvSE2LJh4KsMeidvF",
"MinimumLevel": "Warning",
"LevelOverride": {