SHA256
147 lines
6.0 KiB
C#
147 lines
6.0 KiB
C#
using System;
|
|
using ADOFAIRenderer.Localization;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
|
|
namespace ADOFAIRenderer.UI;
|
|
|
|
/// <summary>
|
|
/// Component that binds a TextMeshProUGUI component to a localization key or dynamic string provider,
|
|
/// automatically updating the displayed text whenever the active language changes.
|
|
/// <para>
|
|
/// The text is set when the binding is made (<see cref="Bind(TextMeshProUGUI, string)"/>), when the component is enabled,
|
|
/// and on every <see cref="LocalizationManager.OnLanguageChanged"/> event. A key and a dynamic provider are mutually
|
|
/// exclusive: setting one clears the other. With neither set, <see cref="Refresh"/> leaves the text unchanged.
|
|
/// Runs on the main Unity thread.
|
|
/// </para>
|
|
/// </summary>
|
|
internal class LocalizedText : MonoBehaviour
|
|
{
|
|
/// <summary>Text component that receives the string; looked up on the same GameObject if not assigned by Bind.</summary>
|
|
private TextMeshProUGUI? _textComponent;
|
|
/// <summary>Localization key resolved through <see cref="LocalizationManager.Get(string)"/>; <c>null</c> when a provider is used.</summary>
|
|
private string? _key;
|
|
/// <summary>Function that returns the full text (already localized/formatted); <c>null</c> when a key is used.</summary>
|
|
private Func<string>? _dynamicProvider;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public string? Key
|
|
{
|
|
get => _key;
|
|
set
|
|
{
|
|
_key = value;
|
|
_dynamicProvider = null;
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="provider">Function returning the text to display; called on the main Unity thread.</param>
|
|
public void SetDynamic(Func<string> provider)
|
|
{
|
|
_dynamicProvider = provider;
|
|
_key = null;
|
|
Refresh();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the text component and subscribes to language changes. The subscription lasts until <see cref="OnDestroy"/>,
|
|
/// also while the component is disabled (a refresh of a disabled object only changes its text).
|
|
/// </summary>
|
|
private void Awake()
|
|
{
|
|
EnsureComponent();
|
|
LocalizationManager.OnLanguageChanged += HandleLanguageChanged;
|
|
}
|
|
|
|
/// <summary>Refreshes the text each time the component is enabled.</summary>
|
|
private void OnEnable()
|
|
{
|
|
Refresh();
|
|
}
|
|
|
|
/// <summary>Unsubscribes from <see cref="LocalizationManager.OnLanguageChanged"/>.</summary>
|
|
private void OnDestroy()
|
|
{
|
|
LocalizationManager.OnLanguageChanged -= HandleLanguageChanged;
|
|
}
|
|
|
|
/// <summary>Language change handler; the new language is read by <see cref="LocalizationManager.Get(string)"/>.</summary>
|
|
private void HandleLanguageChanged(SystemLanguage language)
|
|
{
|
|
Refresh();
|
|
}
|
|
|
|
/// <summary>Assigns <see cref="_textComponent"/> from the same GameObject if it is not set yet.</summary>
|
|
private void EnsureComponent()
|
|
{
|
|
if (_textComponent == null)
|
|
{
|
|
_textComponent = GetComponent<TextMeshProUGUI>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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 <see cref="LocalizationManager.Get(string)"/>).
|
|
/// </summary>
|
|
public void Refresh()
|
|
{
|
|
EnsureComponent();
|
|
if (_textComponent == null) return;
|
|
|
|
if (_dynamicProvider != null)
|
|
{
|
|
_textComponent.text = _dynamicProvider();
|
|
}
|
|
else if (!string.IsNullOrEmpty(_key))
|
|
{
|
|
_textComponent.text = LocalizationManager.Get(_key);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Binds a TextMeshProUGUI component to a localization key.
|
|
/// Reuses the <see cref="LocalizedText"/> already on the target's GameObject or adds one, then sets the key,
|
|
/// which replaces any earlier binding and updates the text immediately.
|
|
/// </summary>
|
|
/// <param name="target">Text to localize.</param>
|
|
/// <param name="key">Localization key, e.g. <c>"ui.render_config.codec"</c>.</param>
|
|
/// <returns>The binding component.</returns>
|
|
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
|
public static LocalizedText Bind(TextMeshProUGUI target, string key)
|
|
{
|
|
if (target == null) throw new ArgumentNullException(nameof(target));
|
|
var component = target.GetComponent<LocalizedText>() ?? target.gameObject.AddComponent<LocalizedText>();
|
|
component._textComponent = target;
|
|
component.Key = key;
|
|
return component;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Binds a TextMeshProUGUI component to a dynamic string provider function.
|
|
/// Reuses or adds the component like <see cref="Bind(TextMeshProUGUI, string)"/> and updates the text immediately.
|
|
/// </summary>
|
|
/// <param name="target">Text to localize.</param>
|
|
/// <param name="provider">Function returning the text; called on every refresh.</param>
|
|
/// <returns>The binding component.</returns>
|
|
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
|
public static LocalizedText Bind(TextMeshProUGUI target, Func<string> provider)
|
|
{
|
|
if (target == null) throw new ArgumentNullException(nameof(target));
|
|
var component = target.GetComponent<LocalizedText>() ?? target.gameObject.AddComponent<LocalizedText>();
|
|
component._textComponent = target;
|
|
component.SetDynamic(provider);
|
|
return component;
|
|
}
|
|
}
|