unityzgy/Assets/Scripts/Managers/VRControllerTooltipLocalizer.cs

142 lines
4.7 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using VRTK;
/// <summary>
/// Localizes VRTK controller tooltip text at runtime.
/// Caches original Chinese texts from prefab fields, then updates
/// via ResetTooltip() when the language changes.
/// </summary>
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<VRTK_ControllerTooltips>(true);
if (tooltips == null || tooltips.Length == 0)
{
tooltips = FindObjectsOfType<VRTK_ControllerTooltips>();
}
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<VRTK_ObjectTooltip>(true);
foreach (var ot in objTooltips)
{
ApplyFontRecursive(ot.transform, font);
}
}
}
}
private void ApplyFontRecursive(Transform parent, Font font)
{
Text[] texts = parent.GetComponentsInChildren<Text>(true);
foreach (var t in texts)
{
Color savedColor = t.color;
t.font = font;
t.color = savedColor;
t.verticalOverflow = VerticalWrapMode.Overflow;
}
}
/// <summary>
/// Translate tooltip text that may contain \\n (literal backslash-n)
/// or \n (actual newline) as multi-line separators.
/// Each line is translated independently.
/// </summary>
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);
}
}