quot;HUD label for '{entry}' not found"); return new IntVariable(); } var variable = new IntVariable { Value = initial }; var text = new LocalizedString(Table, entry); text.Add("value", variable); // name must match {value} in the table label.SetBinding("text", text); // updates on locale change and on variable change return variable; } // Gameplay calls these. Setting Value triggers the label to re-format. public void SetHealth(int v) => health.Value = v; public void AddScore(int v) => score.Value += v; public void SetAmmo(int v) => ammo.Value = v; } ``` **Explanation** - `IntVariable` implements value-changed notification; the bound `LocalizedString` re-formats when `Value` changes. No `Update()` polling, no string concatenation in C#. - Never build sentences in code (`"Score: " + n`): word order differs per language. Put the whole sentence in the table and pass values in. - Bindings on elements created in `OnEnable` are fine; if you rebuild the UI tree, re-run `Bind`. - HUD values change often. If you profile allocations, consider updating very hot values (a timer at 60 Hz) with a cached format string fetched once per locale change instead (`LocalizedString.StringChanged`). ## 2.3 uGUI and TextMeshPro: Localize String Event For uGUI/TMP text (still common in VR world-space canvases): 1. Select the TMP text > **Localize** from the component context menu (or add **Localize String Event**). 2. Set **String Reference** to table/entry. Add local variables if needed. 3. **Update String** event > target the TMP component's `text` setter (Unity usually wires this for you when you use the Localize context menu). From code, change the entry or force refresh: ```csharp // Assets/Scripts/UI/PromptText.cs using UnityEngine; using UnityEngine.Localization.Components; [RequireComponent(typeof(LocalizeStringEvent))] public class PromptText : MonoBehaviour { LocalizeStringEvent localize; void Awake() => localize = GetComponent<LocalizeStringEvent>(); /// e.g. ShowPrompt("prompt.open_door") / ShowPrompt("prompt.pick_up") public void ShowPrompt(string entryKey) { localize.SetEntry(entryKey); // triggers OnUpdateString with the new text } public void Refresh() => localize.RefreshString(); // after changing argument values } ``` ## 2.4 Script: minimal label for anything else When the target isn't UI Toolkit or uGUI (a `TextMesh`, a 3D sign, a log), subscribe to `StringChanged` - and always unsubscribe. ```csharp // Assets/Scripts/UI/LocalizedTextMesh.cs using UnityEngine; using UnityEngine.Localization; [RequireComponent(typeof(TextMesh))] public class LocalizedTextMesh : MonoBehaviour { public LocalizedString text = new LocalizedString("UI", "sign.welcome"); TextMesh mesh; void Awake() => mesh = GetComponent<TextMesh>(); void OnEnable() => text.StringChanged += OnChanged; // fires immediately once loaded void OnDisable() => text.StringChanged -= OnChanged; // avoid the lapsed listener void OnChanged(string value) => mesh.text = value; } ``` The first subscription starts loading and delivers the current value; later locale changes call `OnChanged` again. Forgetting `OnDisable` is the **lapsed listener** bug from the Observer chapter ([[Game Programming Patterns (Review)]]). ## 2.5 Exercise Localize the entire HUD from [[3.HUD and Inventory Example]] without a single `+` on a string. Then switch to German at runtime and look for clipped labels - fix them in USS with flexible widths, not by shortening the German. ## Sources - UI Toolkit (Unity 6+) bindings: https://docs.unity3d.com/Packages/[email protected]/manual/UIToolkit.html - `LocalizedString` API (examples incl. SetBinding and IntVariable): https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Localization.LocalizedString.html - `LocalizeStringEvent` API: https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Localization.Components.LocalizeStringEvent.html