| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- using System;
- using System.Collections.Generic;
- using Newtonsoft.Json;
- using TMPro;
- using UnityEngine;
- using UnityEngine.UI;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- namespace AppUI.Localization
- {
- /// <summary>
- /// AppUI 独立多语言表。查词时优先读本表,缺失则回退 <see cref="TextAutoLanguage2"/>。
- /// 旧 BowArrow 资源与逻辑不做任何修改。
- /// </summary>
- public static class AppUILocalization
- {
- const string ResourcesPrefix = "AppUILocalization/";
- static LanguageEnum currentLanguageEnum = LanguageEnum.Chinese;
- static Dictionary<string, string> languageDictionary;
- static bool inited;
- public static event Action<LanguageEnum> OnLanguageChanged;
- public static void Init()
- {
- if (inited && languageDictionary != null)
- return;
- int id = PlayerPrefs.GetInt("Language", 0);
- LoadLanguage((LanguageEnum)id, notifyListeners: false);
- }
- /// <summary>强制按 PlayerPrefs 当前语言重载 json(Editor 预览改 json 后点刷新用)。</summary>
- public static void Reload()
- {
- inited = false;
- languageDictionary = null;
- int id = PlayerPrefs.GetInt("Language", 0);
- LoadLanguage((LanguageEnum)id, notifyListeners: false);
- }
- /// <summary>
- /// 与旧系统同步切换语言。应在设置页等入口调用,保证 TextAutoLanguage / TextAutoLanguage2 / ImageAutoLanguage 一并更新。
- /// </summary>
- public static void ChangeAllLanguages(LanguageEnum languageEnum)
- {
- TextAutoLanguage.ChangeLanguage(languageEnum);
- TextAutoLanguage2.ChangeLanguage(languageEnum);
- ImageAutoLanguage.ChangeLanguage(languageEnum);
- ChangeLanguage(languageEnum);
- }
- /// <summary>仅加载 AppUI 表并刷新 <see cref="AppUITextAutoLanguage"/> 组件。</summary>
- public static void ChangeLanguage(LanguageEnum languageEnum)
- {
- LoadLanguage(languageEnum, notifyListeners: true);
- }
- static void LoadLanguage(LanguageEnum languageEnum, bool notifyListeners)
- {
- string fileName = ResolveFileName(languageEnum);
- languageDictionary = LoadDictionary(fileName);
- currentLanguageEnum = languageEnum;
- inited = true;
- if (!notifyListeners)
- return;
- foreach (var item in AppUITextAutoLanguage.RegisteredComponents)
- {
- try
- {
- item.ApplyToText();
- }
- catch (Exception e)
- {
- Debug.LogError(e.Message);
- }
- }
- OnLanguageChanged?.Invoke(languageEnum);
- }
- public static LanguageEnum GetLanguage()
- {
- Init();
- return currentLanguageEnum;
- }
- public static string GetTextByKey(string textKey)
- {
- return ResolveText(textKey);
- }
- /// <summary>
- /// 查词后按 <see cref="TMP_Text"/> 可用宽度插入 <c>\u200B</c>,便于窄容器内逐字/逐字母换行。
- /// <paramref name="maxWidth"/> / <paramref name="maxHeight"/> 为 0 时使用 <paramref name="tmpText"/> 的 RectTransform 尺寸。
- /// </summary>
- public static string GetTextByKey(string textKey, TMP_Text tmpText, float maxWidth = 0f, float maxHeight = 0f, params object[] formatArgs)
- {
- return GetTextWithWidthBreak(ResolveText(textKey), tmpText, null, maxWidth, maxHeight, formatArgs);
- }
- /// <summary>Legacy <see cref="Text"/> 版本。</summary>
- public static string GetTextByKey(string textKey, Text legacyText, float maxWidth = 0f, float maxHeight = 0f, params object[] formatArgs)
- {
- return GetTextWithWidthBreak(ResolveText(textKey), null, legacyText, maxWidth, maxHeight, formatArgs);
- }
- /// <summary>显式指定布局矩形与 TMP 组件。</summary>
- public static string GetTextByKey(string textKey, RectTransform rect, TMP_Text tmpText, float maxWidth = 0f, float maxHeight = 0f, params object[] formatArgs)
- {
- string text = FormatResolvedText(ResolveText(textKey), formatArgs);
- if (tmpText == null || string.IsNullOrEmpty(text))
- return text;
- maxWidth = AppUILocalizationTextBreak.ResolveMaxWidth(rect != null ? rect : tmpText.rectTransform, maxWidth);
- maxHeight = AppUILocalizationTextBreak.ResolveMaxHeight(rect != null ? rect : tmpText.rectTransform, maxHeight);
- return AppUILocalizationTextBreak.InsertWidthBreaks(text, tmpText, maxWidth, maxHeight);
- }
- /// <summary>对已解析文案按宽度插入 <c>\u200B</c>。</summary>
- public static string InsertWidthBreaks(string text, TMP_Text tmpText, float maxWidth = 0f, float maxHeight = 0f)
- {
- return AppUILocalizationTextBreak.InsertWidthBreaks(text, tmpText, maxWidth, maxHeight);
- }
- /// <summary>Legacy <see cref="Text"/> 版本。</summary>
- public static string InsertWidthBreaks(string text, Text legacyText, float maxWidth = 0f, float maxHeight = 0f)
- {
- return AppUILocalizationTextBreak.InsertWidthBreaks(text, legacyText, maxWidth, maxHeight);
- }
- static string GetTextWithWidthBreak(string text, TMP_Text tmpText, Text legacyText, float maxWidth, float maxHeight, object[] formatArgs)
- {
- text = FormatResolvedText(text, formatArgs);
- if (string.IsNullOrEmpty(text))
- return text;
- if (tmpText != null)
- return AppUILocalizationTextBreak.InsertWidthBreaks(text, tmpText, maxWidth, maxHeight);
- if (legacyText != null)
- return AppUILocalizationTextBreak.InsertWidthBreaks(text, legacyText, maxWidth, maxHeight);
- return text;
- }
- static string FormatResolvedText(string text, object[] formatArgs)
- {
- if (string.IsNullOrEmpty(text))
- return text;
- if (formatArgs != null && formatArgs.Length > 0)
- return string.Format(text, formatArgs);
- return text;
- }
- public static string GetTextByCNKey(string textKey)
- {
- Init();
- if (currentLanguageEnum == LanguageEnum.Chinese)
- return textKey;
- if (TryGetLocal(textKey, out string localText))
- return localText;
- return TextAutoLanguage2.GetTextByCNKey(textKey);
- }
- /// <summary>新表优先,旧表回退;两边都没有时返回 key 并打 Warning。</summary>
- public static string ResolveText(string textKey)
- {
- Init();
- if (TryGetLocal(textKey, out string localText))
- return localText;
- try
- {
- return TextAutoLanguage2.GetTextByKey(textKey);
- }
- catch (KeyNotFoundException)
- {
- Debug.LogWarning($"[AppUILocalization] Missing key: {textKey}");
- return textKey;
- }
- }
- static bool TryGetLocal(string textKey, out string text)
- {
- text = null;
- if (languageDictionary == null || string.IsNullOrEmpty(textKey))
- return false;
- return languageDictionary.TryGetValue(textKey, out text) && text != null;
- }
- static string ResolveFileName(LanguageEnum languageEnum)
- {
- if (languageEnum == LanguageEnum.English)
- return "en";
- if (languageEnum == LanguageEnum.Japan)
- return "Japan";
- return "cn";
- }
- static Dictionary<string, string> LoadDictionary(string fileName)
- {
- TextAsset asset = null;
- #if UNITY_EDITOR
- if (!Application.isPlaying)
- {
- asset = AssetDatabase.LoadAssetAtPath<TextAsset>(
- $"Assets/AppUI/Resources/AppUILocalization/{fileName}.json");
- }
- #endif
- if (asset == null)
- asset = Resources.Load<TextAsset>(ResourcesPrefix + fileName);
- if (asset == null)
- {
- Debug.LogError($"[AppUILocalization] Missing Resources/{ResourcesPrefix}{fileName}.json");
- return new Dictionary<string, string>();
- }
- return JsonConvert.DeserializeObject<Dictionary<string, string>>(asset.text)
- ?? new Dictionary<string, string>();
- }
- }
- }
|