From 6c7f9867d06518a5e004c016ee2e9efaf9f3a9d3 Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Tue, 23 Jun 2026 08:22:25 +0800 Subject: [PATCH] refactor(UXAssist): clean up I18N internals without changing public API --- UXAssist/Common/I18N.cs | 103 +++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/UXAssist/Common/I18N.cs b/UXAssist/Common/I18N.cs index c53e5d1..a237470 100644 --- a/UXAssist/Common/I18N.cs +++ b/UXAssist/Common/I18N.cs @@ -4,34 +4,60 @@ using HarmonyLib; namespace UXAssist.Common; +/// +/// Provides bilingual localization helpers that integrate with the game's system. +/// public static class I18N { private static bool _initialized; private static bool _dirty; + /// + /// Invoked after the game has finished loading the active language and all registered strings have been applied. + /// public static Action OnInitialized; + /// + /// Registers the localization hooks with Harmony. + /// public static void Init() { Harmony.CreateAndPatchAll(typeof(I18N)); } + /// + /// Returns whether the localization system has finished its initial load. + /// + /// true if localization is initialized; otherwise false. public static bool Initialized() => _initialized; - private static readonly List> Keys = []; - private static readonly Dictionary> Strings = []; - public static void Add(string key, string enus, string zhcn = null) + /// + /// Holds the English and Simplified Chinese localized values for a single entry. + /// + private sealed class LocalizedString { - if (zhcn == null && key == enus) return; - Keys.Add(Tuple.Create(key, enus, -1)); - if (Strings.TryGetValue(2052, out var zhcnList)) + public string En { get; } + public string Zh { get; } + + public LocalizedString(string en, string zh) { - zhcnList.Add(string.IsNullOrEmpty(zhcn) ? enus : zhcn); - } - else - { - Strings.Add(2052, [string.IsNullOrEmpty(zhcn) ? enus : zhcn]); + En = en; + Zh = zh; } + } + + private static readonly Dictionary Entries = new(); + + /// + /// Registers a localized string pair. + /// + /// The lookup key. + /// The English text. + /// The Simplified Chinese text. + public static void Add(string key, string en, string zh) + { + if (zh is null && key == en) return; + Entries[key] = new LocalizedString(en, string.IsNullOrEmpty(zh) ? en : zh); _dirty = true; } @@ -39,25 +65,17 @@ public static class I18N { var indexer = Localization.namesIndexer; var index = indexer.Count; - var len = Keys.Count; - for (var i = 0; i < len; i++) + foreach (var key in Entries.Keys) { - var (key, def, value) = Keys[i]; - if (value >= 0) continue; - if (indexer.TryGetValue(key, out var idx)) - { - Keys[i] = Tuple.Create(key, def, idx); - continue; - } + if (indexer.TryGetValue(key, out _)) continue; indexer[key] = index; - Keys[i] = Tuple.Create(key, def, index); index++; } _dirty = false; var strings = Localization.strings; if (strings == null) return; - var len2 = strings.Length; - for (var i = 0; i < len2; i++) + var len = strings.Length; + for (var i = 0; i < len; i++) { ApplyLanguage(i); if (i != Localization.currentLanguageIndex) continue; @@ -90,31 +108,40 @@ public static class I18N } } - var keyLength = Keys.Count; - if (Strings.TryGetValue(Localization.Languages[index].lcId, out var list)) + var isChinese = Localization.Languages[index].lcId == 2052; + foreach (var entry in Entries) { - for (var j = 0; j < keyLength; j++) - { - strs[Keys[j].Item3] = list[j]; - } - } - else - { - for (var j = 0; j < keyLength; j++) - { - strs[Keys[j].Item3] = Keys[j].Item2; - } + if (!Localization.namesIndexer.TryGetValue(entry.Key, out var idx)) continue; + strs[idx] = isChinese ? entry.Value.Zh : entry.Value.En; } } + /// + /// Applies any pending localization changes to the game's localization tables. + /// public static void Apply() { if (!_initialized) return; - if (Keys.Count == 0) return; + if (Entries.Count == 0) return; if (!_dirty) return; ApplyIndexers(); } + /// + /// Returns the localized text for the given key in the currently active language, + /// falling back to the key itself when no entry is registered. + /// + /// The lookup key. + /// The localized text, or if no entry exists. + public static string Translate(string key) + { + if (!Entries.TryGetValue(key, out var loc)) return key; + var languageIndex = Localization.currentLanguageIndex; + if (languageIndex >= 0 && languageIndex < Localization.Languages.Length && Localization.Languages[languageIndex].lcId == 2052) + return loc.Zh; + return loc.En; + } + [HarmonyPostfix, HarmonyPriority(Priority.Last), HarmonyPatch(typeof(Localization), nameof(Localization.LoadSettings))] private static void Localization_LoadSettings_Postfix() { @@ -136,4 +163,4 @@ public static class I18N if (!_initialized) return; OnInitialized?.Invoke(); } -} \ No newline at end of file +}