using System; using ADOFAIRenderer.Localization; using TMPro; using UnityEngine; namespace ADOFAIRenderer.UI; /// /// Component that binds a TextMeshProUGUI component to a localization key or dynamic string provider, /// automatically updating the displayed text whenever the active language changes. /// /// The text is set when the binding is made (), when the component is enabled, /// and on every event. A key and a dynamic provider are mutually /// exclusive: setting one clears the other. With neither set, leaves the text unchanged. /// Runs on the main Unity thread. /// /// internal class LocalizedText : MonoBehaviour { /// Text component that receives the string; looked up on the same GameObject if not assigned by Bind. private TextMeshProUGUI? _textComponent; /// Localization key resolved through ; null when a provider is used. private string? _key; /// Function that returns the full text (already localized/formatted); null when a key is used. private Func? _dynamicProvider; /// /// Gets or sets the localization key. Setting this will clear any dynamic provider and refresh the text immediately. /// A null or empty key leaves the current text as it is. /// public string? Key { get => _key; set { _key = value; _dynamicProvider = null; Refresh(); } } /// /// Sets a dynamic string provider function, clears the key and refreshes the text immediately. /// The provider is called on every refresh (enable and language change), so it can combine several keys or /// runtime values, e.g. a label that depends on UI state. /// /// Function returning the text to display; called on the main Unity thread. public void SetDynamic(Func provider) { _dynamicProvider = provider; _key = null; Refresh(); } /// /// Finds the text component and subscribes to language changes. The subscription lasts until , /// also while the component is disabled (a refresh of a disabled object only changes its text). /// private void Awake() { EnsureComponent(); LocalizationManager.OnLanguageChanged += HandleLanguageChanged; } /// Refreshes the text each time the component is enabled. private void OnEnable() { Refresh(); } /// Unsubscribes from . private void OnDestroy() { LocalizationManager.OnLanguageChanged -= HandleLanguageChanged; } /// Language change handler; the new language is read by . private void HandleLanguageChanged(SystemLanguage language) { Refresh(); } /// Assigns from the same GameObject if it is not set yet. private void EnsureComponent() { if (_textComponent == null) { _textComponent = GetComponent(); } } /// /// Refreshes the text using either the dynamic provider or the static localization key. /// The provider takes precedence; with neither set, or without a text component, nothing changes. /// A key that is missing in every locale is displayed as the key itself (see ). /// public void Refresh() { EnsureComponent(); if (_textComponent == null) return; if (_dynamicProvider != null) { _textComponent.text = _dynamicProvider(); } else if (!string.IsNullOrEmpty(_key)) { _textComponent.text = LocalizationManager.Get(_key); } } /// /// Binds a TextMeshProUGUI component to a localization key. /// Reuses the already on the target's GameObject or adds one, then sets the key, /// which replaces any earlier binding and updates the text immediately. /// /// Text to localize. /// Localization key, e.g. "ui.render_config.codec". /// The binding component. /// is null. public static LocalizedText Bind(TextMeshProUGUI target, string key) { if (target == null) throw new ArgumentNullException(nameof(target)); var component = target.GetComponent() ?? target.gameObject.AddComponent(); component._textComponent = target; component.Key = key; return component; } /// /// Binds a TextMeshProUGUI component to a dynamic string provider function. /// Reuses or adds the component like and updates the text immediately. /// /// Text to localize. /// Function returning the text; called on every refresh. /// The binding component. /// is null. public static LocalizedText Bind(TextMeshProUGUI target, Func provider) { if (target == null) throw new ArgumentNullException(nameof(target)); var component = target.GetComponent() ?? target.gameObject.AddComponent(); component._textComponent = target; component.SetDynamic(provider); return component; } }