From 33a1681f3d29d74330abf1383cf3cc8baac62e4d Mon Sep 17 00:00:00 2001 From: ayuan9957 <107920784+ayuan9957@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:27:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20VR=E6=89=8B=E6=9F=84=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E7=BF=BB=E8=AF=91=20-=20=E6=96=B0=E5=A2=9EVR?= =?UTF-8?q?ControllerTooltipLocalizer=E7=BB=84=E4=BB=B6=EF=BC=8C=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E5=88=87=E6=8D=A2=E6=97=B6=E8=87=AA=E5=8A=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0VRTK=E6=89=8B=E6=9F=84tooltip=E6=96=87=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/LocalizationManager.cs | 11 ++ .../Managers/VRControllerTooltipLocalizer.cs | 141 ++++++++++++++++++ .../VRControllerTooltipLocalizer.cs.meta | 11 ++ Assets/Scripts/Managers/VRManager.cs | 1 + 4 files changed, 164 insertions(+) create mode 100644 Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs create mode 100644 Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs.meta diff --git a/Assets/Scripts/Localization/LocalizationManager.cs b/Assets/Scripts/Localization/LocalizationManager.cs index 3fb13bb..0c4118e 100644 --- a/Assets/Scripts/Localization/LocalizationManager.cs +++ b/Assets/Scripts/Localization/LocalizationManager.cs @@ -487,6 +487,17 @@ public class LocalizationManager : MonoBehaviour { "{0}与{1}边界间距为{2}M,小于200M", new[] { "{0}与{1}边界间距为{2}M,小于200M", "Distance between {0} and {1} boundary is {2}M, less than 200M", "Distance entre {0} et {1} : {2}M, inférieure à 200M", "Расстояние между {0} и {1}: {2}м, менее 200м" } }, { "{0}与{1}边界间距为{2}M,小于100M", new[] { "{0}与{1}边界间距为{2}M,小于100M", "Distance between {0} and {1} boundary is {2}M, less than 100M", "Distance entre {0} et {1} : {2}M, inférieure à 100M", "Расстояние между {0} и {1}: {2}м, менее 100м" } }, { "{0}距离水源距离为{1}M,超出100M", new[] { "{0}距离水源距离为{1}M,超出100M", "{0} distance to water source is {1}M, exceeds 100M", "Distance de {0} à la source d'eau : {1}M, supérieure à 100M", "Расстояние от {0} до источника воды {1}м, более 100м" } }, + + // VR controller tooltips (VRTK_ControllerTooltips) + { "展/收", new[] { "展/收", "Deploy/Stow", "Déployer/Ranger", "Развернуть/Свернуть" } }, + { "选中车辆", new[] { "选中车辆", "Select Vehicle", "Sélectionner le véhicule", "Выбрать машину" } }, + { "移动", new[] { "移动", "Move", "Déplacer", "Движение" } }, + { "射线", new[] { "射线", "Ray", "Rayon", "Луч" } }, + { "移动车辆", new[] { "移动车辆", "Move Vehicle", "Déplacer le véhicule", "Переместить машину" } }, + { "选择车辆", new[] { "选择车辆", "Select Vehicle", "Sélectionner le véhicule", "Выбрать машину" } }, + { "触发物体", new[] { "触发物体", "Trigger Object", "Activer l'objet", "Активировать объект" } }, + { "抓取物体", new[] { "抓取物体", "Grab Object", "Saisir l'objet", "Захватить объект" } }, + { "传送", new[] { "传送", "Teleport", "Téléportation", "Телепорт" } }, }; [SerializeField] private int language; diff --git a/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs b/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs new file mode 100644 index 0000000..4907bda --- /dev/null +++ b/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs @@ -0,0 +1,141 @@ +using UnityEngine; +using UnityEngine.UI; +using VRTK; + +/// +/// Localizes VRTK controller tooltip text at runtime. +/// Caches original Chinese texts from prefab fields, then updates +/// via ResetTooltip() when the language changes. +/// +public class VRControllerTooltipLocalizer : MonoBehaviour +{ + private class TooltipCache + { + public VRTK_ControllerTooltips component; + public string triggerText; + public string gripText; + public string touchpadText; + public string buttonOneText; + public string buttonTwoText; + public string startMenuText; + } + + private TooltipCache[] caches; + private bool initialized; + + void Start() + { + CacheTooltips(); + if (initialized) ApplyLocalization(); + LocalizationManager.LanguageChanged += OnLanguageChanged; + } + + void OnDestroy() + { + LocalizationManager.LanguageChanged -= OnLanguageChanged; + } + + private void OnLanguageChanged() + { + if (initialized) ApplyLocalization(); + } + + private void CacheTooltips() + { + VRTK_ControllerTooltips[] tooltips = GetComponentsInChildren(true); + if (tooltips == null || tooltips.Length == 0) + { + tooltips = FindObjectsOfType(); + } + + if (tooltips == null || tooltips.Length == 0) return; + + caches = new TooltipCache[tooltips.Length]; + for (int i = 0; i < tooltips.Length; i++) + { + caches[i] = new TooltipCache + { + component = tooltips[i], + triggerText = tooltips[i].triggerText, + gripText = tooltips[i].gripText, + touchpadText = tooltips[i].touchpadText, + buttonOneText = tooltips[i].buttonOneText, + buttonTwoText = tooltips[i].buttonTwoText, + startMenuText = tooltips[i].startMenuText + }; + } + initialized = true; + } + + private void ApplyLocalization() + { + Font font = LocalizationManager.UIFont; + + foreach (var cache in caches) + { + if (cache.component == null) continue; + + // Set all fields with localized text, then reset once + cache.component.triggerText = LocalizeTooltipText(cache.triggerText); + cache.component.gripText = LocalizeTooltipText(cache.gripText); + cache.component.touchpadText = LocalizeTooltipText(cache.touchpadText); + cache.component.buttonOneText = LocalizeTooltipText(cache.buttonOneText); + cache.component.buttonTwoText = LocalizeTooltipText(cache.buttonTwoText); + cache.component.startMenuText = LocalizeTooltipText(cache.startMenuText); + cache.component.ResetTooltip(); + + // Apply localized font to tooltip Text components after ResetTooltip + // so SetText() has already run (it doesn't touch font, only material) + if (font != null) + { + VRTK_ObjectTooltip[] objTooltips = cache.component.GetComponentsInChildren(true); + foreach (var ot in objTooltips) + { + ApplyFontRecursive(ot.transform, font); + } + } + } + } + + private void ApplyFontRecursive(Transform parent, Font font) + { + Text[] texts = parent.GetComponentsInChildren(true); + foreach (var t in texts) + { + Color savedColor = t.color; + t.font = font; + t.color = savedColor; + t.verticalOverflow = VerticalWrapMode.Overflow; + } + } + + /// + /// Translate tooltip text that may contain \\n (literal backslash-n) + /// or \n (actual newline) as multi-line separators. + /// Each line is translated independently. + /// + private static string LocalizeTooltipText(string original) + { + if (string.IsNullOrEmpty(original)) return original; + + // VRTK uses literal \\n in prefab fields; SetText() converts to \n + if (original.Contains("\\n")) + { + string[] parts = original.Split(new[] { "\\n" }, System.StringSplitOptions.None); + for (int i = 0; i < parts.Length; i++) + parts[i] = LocalizationManager.Get(parts[i].Trim()); + return string.Join("\\n", parts); + } + + // Handle actual newlines (in case text was already converted) + if (original.Contains("\n")) + { + string[] parts = original.Split(new[] { "\n" }, System.StringSplitOptions.None); + for (int i = 0; i < parts.Length; i++) + parts[i] = LocalizationManager.Get(parts[i].Trim()); + return string.Join("\n", parts); + } + + return LocalizationManager.Get(original); + } +} diff --git a/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs.meta b/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs.meta new file mode 100644 index 0000000..986dc8e --- /dev/null +++ b/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6e286fc5954c4045bb66e03d68ba7bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Managers/VRManager.cs b/Assets/Scripts/Managers/VRManager.cs index 8a2f04c..f0a0ddf 100644 --- a/Assets/Scripts/Managers/VRManager.cs +++ b/Assets/Scripts/Managers/VRManager.cs @@ -22,6 +22,7 @@ public class VRManager : IVRInput { SDKManager = GameObject.Instantiate(Resources.Load(ResourcesManager.GetPath(vrtkPrefabName))).GetComponent(); SDKManager.transform.position = postion; + SDKManager.gameObject.AddComponent(); SDKManager.LoadedSetupChanged += SDKManager_LoadedSetupChanged; VRTK_Logger.instance.throwExceptions = false; //leftInput = SDKManager.scriptAliasLeftController.GetComponent();