Files
LanMountainDesktop/LanMountainDesktop.PluginSdk/PluginLocalizer.cs

115 lines
3.7 KiB
C#
Raw Normal View History

2026-03-10 00:04:33 +08:00
using System.Globalization;
using System.Text.Json;
namespace LanMountainDesktop.PluginSdk;
public sealed class PluginLocalizer
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
private readonly Dictionary<string, Dictionary<string, string>> _cache =
new(StringComparer.OrdinalIgnoreCase);
public PluginLocalizer(string pluginDirectory, string? languageCode)
{
ArgumentException.ThrowIfNullOrWhiteSpace(pluginDirectory);
PluginDirectory = pluginDirectory;
LanguageCode = NormalizeLanguageCode(languageCode);
}
public string PluginDirectory { get; }
public string LanguageCode { get; }
public static PluginLocalizer Create(IPluginContext context)
{
ArgumentNullException.ThrowIfNull(context);
return new PluginLocalizer(context.PluginDirectory, ResolveLanguageCode(context.Properties));
}
public static PluginLocalizer Create(PluginDesktopComponentContext context)
{
ArgumentNullException.ThrowIfNull(context);
return new PluginLocalizer(context.PluginDirectory, ResolveLanguageCode(context.Properties));
}
public string GetString(string key, string fallback)
{
ArgumentException.ThrowIfNullOrWhiteSpace(key);
var primaryTable = LoadLanguageTable(LanguageCode);
if (primaryTable.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value))
{
return value;
}
if (!string.Equals(LanguageCode, "en-US", StringComparison.OrdinalIgnoreCase))
{
var fallbackTable = LoadLanguageTable("en-US");
if (fallbackTable.TryGetValue(key, out value) && !string.IsNullOrWhiteSpace(value))
{
return value;
}
}
return fallback;
}
public string Format(string key, string fallback, params object[] args)
{
return string.Format(CultureInfo.CurrentCulture, GetString(key, fallback), args);
}
public static string NormalizeLanguageCode(string? languageCode)
{
return string.Equals(languageCode, "en-US", StringComparison.OrdinalIgnoreCase)
? "en-US"
: "zh-CN";
}
public static string ResolveLanguageCode(IReadOnlyDictionary<string, object?> properties)
{
ArgumentNullException.ThrowIfNull(properties);
return properties.TryGetValue(PluginHostPropertyKeys.HostLanguageCode, out var rawValue) &&
rawValue is string languageCode
? NormalizeLanguageCode(languageCode)
: NormalizeLanguageCode(CultureInfo.CurrentUICulture.Name);
}
private Dictionary<string, string> LoadLanguageTable(string languageCode)
{
if (_cache.TryGetValue(languageCode, out var table))
{
return table;
}
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
try
{
var filePath = Path.Combine(PluginDirectory, "Localization", $"{languageCode}.json");
if (File.Exists(filePath))
{
var json = File.ReadAllText(filePath).TrimStart('\uFEFF');
var data = JsonSerializer.Deserialize<Dictionary<string, string>>(json, JsonOptions);
if (data is not null)
{
result = new Dictionary<string, string>(data, StringComparer.OrdinalIgnoreCase);
}
}
}
catch
{
// Keep empty localization table for plugin resilience.
}
_cache[languageCode] = result;
return result;
}
}