using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using BITKit; using Cysharp.Threading.Tasks; using Microsoft.Extensions.Logging; namespace Net.BITKit.Localization { /// /// 本地化 /// public interface ILocalizationService { public string Prefix { get; } /// /// 当前语言 /// public string CurrentLanguage { get; } /// /// 更改回调,通常在此检查并下载语言包 /// public event Func OnLanguageChangeAsync; /// /// 语言更改完成回调,UI和World执行更新 /// public event Action OnLanguageChanged; /// /// 获取翻译文本,返回无复制的引用 /// /// /// 语言,默认为当前CultureInfo.Name /// public string GetLocalizedString(string key,string language=null); public UniTask ChangeLanguageAsync(string newLanguage); public IDictionary> LocalizedStrings { get; } } public class LocalizationService : ILocalizationService,IDisposable { private static LocalizationService _singleton; public string Prefix => "#"; private char _prefix = '#'; public string CurrentLanguage { get; private set; } public event Func OnLanguageChangeAsync; public event Action OnLanguageChanged; private readonly ILogger _logger; public IDictionary> LocalizedStrings { get; } = new Dictionary>(); private readonly ValidHandle _isBusy = new(); private readonly HashSet _untranslatedKeys = new(); public LocalizationService(ILogger logger) { if (_singleton is not null) { logger.LogError("LocalizationService can only be one singleton"); return; } _logger = logger; } public string GetLocalizedString(string key, string language = null) { language ??= CurrentLanguage; // 默认使用当前语言 if (key[0] != _prefix) { key = _prefix + key; } if (LocalizedStrings.TryGetValue(language, out var langDict) && langDict.TryGetValue(key, out var value)) { return value; } _untranslatedKeys.Add(key); return key.Replace(Prefix,string.Empty).Replace("_"," "); // 如果找不到翻译,就返回 key 本身(常见策略) } public async UniTask ChangeLanguageAsync(string newLanguage) { if (CurrentLanguage == newLanguage) return; var oldLanguage = CurrentLanguage; CurrentLanguage = newLanguage; await _isBusy; using var _ = _isBusy.GetHandle(); await UniTask.SwitchToMainThread(); await OnLanguageChangeAsync.UniTaskFunc(oldLanguage, newLanguage); // 触发同步事件(例如更新 UI) OnLanguageChanged?.Invoke(oldLanguage, newLanguage); } public void Dispose() { _isBusy?.Dispose(); _singleton = null; _logger.LogInformation("Untranslated keys:\n"+string.Join("\n", _untranslatedKeys)); _untranslatedKeys.Clear(); } } }