using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using UnityEngine.Localization.Tables; using UnityEngine.ResourceManagement.AsyncOperations; namespace Ichni.Localization { /// /// 项目运行时代码读取 Unity Localization 文本的统一入口。 /// 静态 Prefab 文本仍应使用 LocalizeStringEvent;只有运行时生成、Yarn 命令、Story 数据等无法直接挂组件的文本才调用本服务。 /// 同步接口绝不强制 Addressables 完成加载:Localization 尚未就绪时直接返回 fallback,避免在场景切换或 UI 点击中制造卡顿。 /// public static class LocalizationTextService { private static readonly HashSet ReportedFallbacks = new HashSet(); /// /// 在 Unity Localization 已初始化时立即解析文本;无法解析时返回调用方提供的 fallback。 /// fallback 传入 null 时回退显示 Key,适合开发阶段快速定位缺失条目;传入空字符串时会保留空字符串。 /// public static string Resolve( TableReference tableReference, string entryKey, string fallback = null, params object[] arguments) { string resolvedFallback = GetFallback(entryKey, fallback); if (string.IsNullOrEmpty(entryKey)) { return resolvedFallback; } AsyncOperationHandle initializationOperation = LocalizationSettings.InitializationOperation; if (!initializationOperation.IsDone || initializationOperation.Status != AsyncOperationStatus.Succeeded) { ReportFallbackOnce(tableReference, entryKey, "Unity Localization 尚未完成初始化"); return resolvedFallback; } try { string localizedText = LocalizationSettings.StringDatabase.GetLocalizedString( tableReference, entryKey, null, FallbackBehavior.UseProjectSettings, arguments); if (!string.IsNullOrEmpty(localizedText)) { return localizedText; } ReportFallbackOnce(tableReference, entryKey, "String Table 未返回有效文本"); } catch (Exception exception) { ReportFallbackOnce(tableReference, entryKey, exception.Message); } return resolvedFallback; } /// /// 异步解析文本。该接口只等待 Unity 官方 和字符串加载操作, /// 不创建额外 Bootstrap,也不使用 WaitForCompletion 阻塞主线程。 /// public static async Task ResolveAsync( TableReference tableReference, string entryKey, string fallback = null, params object[] arguments) { string resolvedFallback = GetFallback(entryKey, fallback); if (string.IsNullOrEmpty(entryKey)) { return resolvedFallback; } try { AsyncOperationHandle initializationOperation = LocalizationSettings.InitializationOperation; await initializationOperation.Task; if (initializationOperation.Status != AsyncOperationStatus.Succeeded) { ReportFallbackOnce(tableReference, entryKey, "Unity Localization 初始化失败"); return resolvedFallback; } AsyncOperationHandle textOperation = LocalizationSettings.StringDatabase.GetLocalizedStringAsync( tableReference, entryKey, null, FallbackBehavior.UseProjectSettings, arguments); await textOperation.Task; if (textOperation.Status == AsyncOperationStatus.Succeeded && !string.IsNullOrEmpty(textOperation.Result)) { return textOperation.Result; } ReportFallbackOnce(tableReference, entryKey, "String Table 异步加载失败或未返回有效文本"); } catch (Exception exception) { ReportFallbackOnce(tableReference, entryKey, exception.Message); } return resolvedFallback; } private static string GetFallback(string entryKey, string fallback) { return fallback ?? entryKey ?? string.Empty; } /// /// 同一 Table/Key 的回退原因只输出一次,避免 Helper、Timeline 等重复刷新 UI 时刷屏。 /// private static void ReportFallbackOnce(TableReference tableReference, string entryKey, string reason) { string diagnosticKey = $"{tableReference}:{entryKey}"; if (!ReportedFallbacks.Add(diagnosticKey)) { return; } Debug.LogWarning($"[LocalizationTextService] 无法解析 '{diagnosticKey}',将显示 fallback。原因:{reason}"); } } }