Files
Atomx/Atomx.Admin/Atomx.Admin.Client/Services/JsonStringLocalizer.cs
2025-12-06 13:30:17 +08:00

141 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Localization;
using System.Globalization;
using System.Net.Http;
using System.Text.Json;
namespace Atomx.Admin.Client.Services
{
public class JsonStringLocalizer : IStringLocalizer
{
private readonly string _resourcesPath;
private readonly Dictionary<string, Dictionary<string, string>> _resourcesCache = new();
private readonly object _lock = new();
private readonly HttpClient? _httpClient;
// resourcesPath 应为相对于站点根的“目录”名称,例如 "Localization"
// 在 Blazor WebAssembly 场景下,会使用注入的 HttpClient 从 wwwroot/Localization/{culture}.json 获取资源
public JsonStringLocalizer(string resourcesPath, HttpClient? httpClient = null)
{
_resourcesPath = (resourcesPath ?? "Localization").Trim('/'); // 规范化
_httpClient = httpClient;
}
public LocalizedString this[string name]
{
get
{
var value = GetString(name);
return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
}
}
public LocalizedString this[string name, params object[] arguments]
{
get
{
var format = GetString(name);
var value = string.Format(format ?? name, arguments);
return new LocalizedString(name, value, resourceNotFound: format == null);
}
}
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
{
var culture = CultureInfo.CurrentUICulture.Name;
var resources = LoadResources(culture);
return resources.Select(r => new LocalizedString(r.Key, r.Value, false));
}
private string? GetString(string name)
{
var culture = CultureInfo.CurrentUICulture.Name;
var resources = LoadResources(culture);
// 尝试当前文化
if (resources.TryGetValue(name, out var value))
return value;
// 如果还找不到,尝试英文作为后备
if (culture != "en-US")
{
var enResources = LoadResources("en-US");
if (enResources.TryGetValue(name, out var enValue))
return enValue;
}
return null;
}
private Dictionary<string, string> LoadResources(string culture)
{
lock (_lock)
{
if (_resourcesCache.TryGetValue(culture, out var cachedResources))
return cachedResources;
var resources = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var fileName = $"{culture}.json";
// 在浏览器WASM环境下通过 HttpClient 从静态资源目录获取
if (OperatingSystem.IsBrowser() && _httpClient != null)
{
try
{
// 构造相对 URL例如 "Localization/zh-Hans.json"
var relativeUrl = $"{_resourcesPath}/{fileName}";
var json = _httpClient.GetStringAsync(relativeUrl).ConfigureAwait(false).GetAwaiter().GetResult();
var jsonResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
if (jsonResources != null)
{
foreach (var item in jsonResources)
{
resources[item.Key] = item.Value;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading localization file {fileName} via HttpClient: {ex.Message}");
}
_resourcesCache[culture] = resources;
return resources;
}
// 非浏览器(例如 Server 或在 prerender 阶段)尝试从文件系统读取。
// 尝试几种可能的路径:基路径为 AppContext.BaseDirectory 或当前工作目录,或直接使用传入的路径。
try
{
var candidates = new[]
{
Path.Combine(AppContext.BaseDirectory, _resourcesPath, fileName),
Path.Combine(Directory.GetCurrentDirectory(), _resourcesPath, fileName),
Path.Combine(_resourcesPath, fileName),
};
var filePath = candidates.FirstOrDefault(File.Exists);
if (!string.IsNullOrEmpty(filePath))
{
var json = File.ReadAllText(filePath);
var jsonResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
if (jsonResources != null)
{
foreach (var item in jsonResources)
{
resources[item.Key] = item.Value;
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading localization file {fileName} from disk: {ex.Message}");
}
_resourcesCache[culture] = resources;
return resources;
}
}
}
}