using System.Collections; using TMPro; using UnityEngine; using UnityEngine.Localization.Components; using UnityEngine.SceneManagement; using UnityEngine.UI; using System.Collections.Generic; public class LocalizationRuntimeBootstrap : MonoBehaviour { private static LocalizationRuntimeBootstrap _instance; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void Bootstrap() { LocalizationService.EnsureInitialized(); if (_instance != null) { return; } GameObject go = new GameObject("LocalizationRuntimeBootstrap"); DontDestroyOnLoad(go); _instance = go.AddComponent(); } private void Awake() { if (_instance != null && _instance != this) { Destroy(gameObject); return; } _instance = this; SceneManager.sceneLoaded += OnSceneLoaded; LocalizationService.LanguageChanged += OnLanguageChanged; } private void Start() { StartCoroutine(ApplyLocalizationDeferred()); } private void OnDestroy() { if (_instance == this) { SceneManager.sceneLoaded -= OnSceneLoaded; LocalizationService.LanguageChanged -= OnLanguageChanged; _instance = null; } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { StartCoroutine(ApplyLocalizationDeferred()); } private void OnLanguageChanged(string languageCode) { StartCoroutine(ApplyLocalizationDeferred()); } private IEnumerator ApplyLocalizationDeferred() { // Some UI updates its text in Start/OnEnable one or two frames after scene load. // Re-apply for a few frames so late-bound labels are still captured. for (int i = 0; i < 4; i++) { yield return null; ApplyLocalizationToLoadedTexts(); } } private static void ApplyLocalizationToLoadedTexts() { foreach (Text text in EnumerateSceneTexts()) { if (!IsLocalizable(text)) { continue; } LocalizedLiteralText binding = text.GetComponent(); if (binding == null) { binding = text.gameObject.AddComponent(); } binding.CaptureIfNeeded(text.text, false); binding.Refresh(); } foreach (TMP_Text tmp in EnumerateSceneTmpTexts()) { if (!IsLocalizable(tmp)) { continue; } LocalizedLiteralText binding = tmp.GetComponent(); if (binding == null) { binding = tmp.gameObject.AddComponent(); } binding.CaptureIfNeeded(tmp.text, true); binding.Refresh(); } } private static IEnumerable EnumerateSceneTexts() { int sceneCount = SceneManager.sceneCount; for (int i = 0; i < sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (!scene.IsValid() || !scene.isLoaded) { continue; } GameObject[] roots = scene.GetRootGameObjects(); for (int rootIndex = 0; rootIndex < roots.Length; rootIndex++) { Text[] texts = roots[rootIndex].GetComponentsInChildren(true); for (int textIndex = 0; textIndex < texts.Length; textIndex++) { yield return texts[textIndex]; } } } } private static IEnumerable EnumerateSceneTmpTexts() { int sceneCount = SceneManager.sceneCount; for (int i = 0; i < sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (!scene.IsValid() || !scene.isLoaded) { continue; } GameObject[] roots = scene.GetRootGameObjects(); for (int rootIndex = 0; rootIndex < roots.Length; rootIndex++) { TMP_Text[] texts = roots[rootIndex].GetComponentsInChildren(true); for (int textIndex = 0; textIndex < texts.Length; textIndex++) { yield return texts[textIndex]; } } } } private static bool IsLocalizable(Component component) { if (component == null || component.gameObject == null) { return false; } GameObject gameObject = component.gameObject; if (!gameObject.scene.IsValid() || !gameObject.scene.isLoaded || string.IsNullOrEmpty(gameObject.scene.name)) { return false; } if (gameObject.GetComponent() != null || gameObject.GetComponent() != null || gameObject.GetComponent() != null) { return false; } return true; } }