GlobalLocalizationManager.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Newtonsoft.Json;
  6. namespace TeamAAS.Localization
  7. {
  8. /// <summary>
  9. /// 全局多语言管理器 - 支持使用原文(中文/英文等)作为查找 key
  10. /// </summary>
  11. public class GlobalLocalizationManager
  12. {
  13. private static readonly Lazy<GlobalLocalizationManager> _instance = new Lazy<GlobalLocalizationManager>(() => new GlobalLocalizationManager());
  14. public static GlobalLocalizationManager Instance => _instance.Value;
  15. private readonly Dictionary<string, LanguageResourcePack> _languagePacks = new Dictionary<string, LanguageResourcePack>();
  16. private string _currentLanguage = "zh-CN"; // 默认中文
  17. private string _fallbackLanguage = "zh-CN"; // 回退语言(用于查找 key)
  18. /// <summary>
  19. /// 当前语言(如 "zh-CN", "en-US", "ja-JP")
  20. /// </summary>
  21. public string CurrentLanguage
  22. {
  23. get => _currentLanguage;
  24. set
  25. {
  26. if (_currentLanguage != value)
  27. {
  28. _currentLanguage = value;
  29. LanguageChanged?.Invoke(this, EventArgs.Empty);
  30. }
  31. }
  32. }
  33. /// <summary>
  34. /// 回退语言(用于反向查找原文对应的 key)- 通常是中文
  35. /// </summary>
  36. public string FallbackLanguage
  37. {
  38. get => _fallbackLanguage;
  39. set => _fallbackLanguage = value;
  40. }
  41. /// <summary>
  42. /// 语言切换事件
  43. /// </summary>
  44. public event EventHandler LanguageChanged;
  45. /// <summary>
  46. /// 已加载的语言列表
  47. /// </summary>
  48. public IReadOnlyList<string> AvailableLanguages => _languagePacks.Keys.ToList();
  49. private GlobalLocalizationManager()
  50. {
  51. }
  52. public string GetLanguageName(string languageCode)
  53. {
  54. if (_languagePacks.TryGetValue(languageCode, out var pack))
  55. {
  56. return pack.LanguageName;
  57. }
  58. return languageCode; // 如果没有找到,返回语言代码
  59. }
  60. /// <summary>
  61. /// 从指定目录加载所有语言包(.json 人类可读格式)
  62. /// </summary>
  63. /// <param name="localizationDirectory">多语言资源目录,如 "Localization"</param>
  64. public void LoadLanguagePacks(string localizationDirectory)
  65. {
  66. if (!Directory.Exists(localizationDirectory))
  67. {
  68. Directory.CreateDirectory(localizationDirectory);
  69. return;
  70. }
  71. _languagePacks.Clear();
  72. var jsonFiles = Directory.GetFiles(localizationDirectory, "*.json", SearchOption.AllDirectories);
  73. foreach (var file in jsonFiles)
  74. {
  75. try
  76. {
  77. var json = File.ReadAllText(file);
  78. var pack = JsonConvert.DeserializeObject<LanguageResourcePack>(json);
  79. if (pack != null && !string.IsNullOrWhiteSpace(pack.LanguageCode))
  80. {
  81. _languagePacks[pack.LanguageCode] = pack;
  82. AppLogger.Info($"[Localization] 已加载 JSON 语言包: {pack.LanguageName} ({pack.LanguageCode}) - {file}");
  83. }
  84. }
  85. catch (Exception ex)
  86. {
  87. AppLogger.Error($"[Localization] 加载 JSON 语言包失败: {file} - {ex.Message}");
  88. }
  89. }
  90. }
  91. /// <summary>
  92. /// 添加单个语言包(支持运行时动态添加)
  93. /// </summary>
  94. public void AddLanguagePack(LanguageResourcePack pack)
  95. {
  96. if (pack == null || string.IsNullOrWhiteSpace(pack.LanguageCode))
  97. return;
  98. _languagePacks[pack.LanguageCode] = pack;
  99. }
  100. /// <summary>
  101. /// 翻译文本 - 使用原文作为 key 查找翻译
  102. /// </summary>
  103. /// <param name="originalText">原文(如"相机设备")</param>
  104. /// <param name="context">可选的上下文信息(如类型名、属性名等)</param>
  105. /// <returns>翻译后的文本,如果没有找到则返回原文</returns>
  106. public string Translate(string originalText, string context = null)
  107. {
  108. if (string.IsNullOrWhiteSpace(originalText))
  109. return originalText;
  110. // 如果当前语言就是回退语言(中文),直接返回原文
  111. if (_currentLanguage == _fallbackLanguage)
  112. return originalText;
  113. // 从当前语言包查找翻译
  114. if (_languagePacks.TryGetValue(_currentLanguage, out var pack))
  115. {
  116. var translation = pack.GetTranslationByOriginalText(originalText, context);
  117. if (!string.IsNullOrWhiteSpace(translation))
  118. return translation;
  119. }
  120. // 找不到翻译,返回原文
  121. return originalText;
  122. }
  123. /// <summary>
  124. /// 获取属性的显示名称翻译
  125. /// </summary>
  126. /// <param name="typeName">类型名称</param>
  127. /// <param name="propertyName">属性名称</param>
  128. /// <param name="originalDisplayName">原始显示名称(来自 [DisplayName] 特性)</param>
  129. public string GetPropertyDisplayName(string typeName, string propertyName, string originalDisplayName)
  130. {
  131. return Translate(originalDisplayName, $"{typeName}.{propertyName}.DisplayName");
  132. }
  133. /// <summary>
  134. /// 获取属性的描述翻译
  135. /// </summary>
  136. public string GetPropertyDescription(string typeName, string propertyName, string originalDescription)
  137. {
  138. return Translate(originalDescription, $"{typeName}.{propertyName}.Description");
  139. }
  140. /// <summary>
  141. /// 获取属性的分类翻译
  142. /// </summary>
  143. public string GetPropertyCategory(string typeName, string propertyName, string originalCategory)
  144. {
  145. return Translate(originalCategory, $"{typeName}.{propertyName}.Category");
  146. }
  147. /// <summary>
  148. /// 获取插件的显示名称翻译
  149. /// </summary>
  150. public string GetPluginDisplayName(string pluginId, string originalDisplayName)
  151. {
  152. return Translate(originalDisplayName, $"Plugin.{pluginId}.DisplayName");
  153. }
  154. /// <summary>
  155. /// 获取插件的描述翻译
  156. /// </summary>
  157. public string GetPluginDescription(string pluginId, string originalDescription)
  158. {
  159. return Translate(originalDescription, $"Plugin.{pluginId}.Description");
  160. }
  161. /// <summary>
  162. /// 获取插件类别的翻译
  163. /// </summary>
  164. public string GetPluginCategoryName(string originalCategory)
  165. {
  166. return Translate(originalCategory, "PluginCategory");
  167. }
  168. /// <summary>
  169. /// 获取枚举值的翻译
  170. /// </summary>
  171. public string GetEnumDisplayName(string enumTypeName, string originalEnumValue)
  172. {
  173. return Translate(originalEnumValue, $"Enum.{enumTypeName}");
  174. }
  175. /// <summary>
  176. /// 获取通用UI文本翻译
  177. /// </summary>
  178. public string GetUIText(string originalText)
  179. {
  180. return Translate(originalText, "UI");
  181. }
  182. }
  183. }