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 Unity main 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 Unity main 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;
}
}