112 lines
3.7 KiB
C#
112 lines
3.7 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 本地化
|
||
/// </summary>
|
||
public interface ILocalizationService
|
||
{
|
||
public string Prefix { get; }
|
||
/// <summary>
|
||
/// 当前语言
|
||
/// </summary>
|
||
public string CurrentLanguage { get; }
|
||
/// <summary>
|
||
/// 更改回调,通常在此检查并下载语言包
|
||
/// </summary>
|
||
public event Func<string,string,UniTask> OnLanguageChangeAsync;
|
||
/// <summary>
|
||
/// 语言更改完成回调,UI和World执行更新
|
||
/// </summary>
|
||
public event Action<string,string> OnLanguageChanged;
|
||
/// <summary>
|
||
/// 获取翻译文本,返回无复制的引用
|
||
/// </summary>
|
||
/// <param name="key"></param>
|
||
/// <param name="language">语言,默认为当前CultureInfo.Name</param>
|
||
/// <returns></returns>
|
||
public string GetLocalizedString(string key,string language=null);
|
||
public UniTask ChangeLanguageAsync(string newLanguage);
|
||
public IDictionary<string, IDictionary<string, string>> 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<string, string, UniTask> OnLanguageChangeAsync;
|
||
public event Action<string, string> OnLanguageChanged;
|
||
|
||
private readonly ILogger<LocalizationService> _logger;
|
||
|
||
public IDictionary<string, IDictionary<string, string>> LocalizedStrings { get; } =
|
||
new Dictionary<string, IDictionary<string, string>>();
|
||
|
||
private readonly ValidHandle _isBusy = new();
|
||
|
||
private readonly HashSet<string> _untranslatedKeys = new();
|
||
|
||
public LocalizationService(ILogger<LocalizationService> 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();
|
||
}
|
||
}
|
||
|
||
}
|