Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Localization not working in build

Discussion in 'Localization Tools' started by the_humble, Jun 9, 2023.

  1. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    I got localization to work in my project, but it doesn't seem to be working whenever I build. I have rebuilt the addressables in multiple ocassions, but in my build everything appears to be resorting to fallback fonts or fallback text. I am currently using this custom class to handle localization in TMPRO components.


    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using TMPro;
    5. using UnityEngine;
    6. using UnityEngine.Localization;
    7. using UnityEngine.Localization.Components;
    8. using UnityEngine.Localization.Settings;
    9. using UnityEngine.ResourceManagement.AsyncOperations;
    10.  
    11.     public class LocalizeTMProComponent : MonoBehaviour
    12.     {
    13.         [SerializeField]
    14.         LocalizedString stringReference = new LocalizedString();
    15.  
    16.         public LocalizedString StringReference { get => stringReference; }
    17.  
    18.         [SerializeField]
    19.         LocalizedTMProFont fontAssetReference = new LocalizedTMProFont();
    20.  
    21.         private TextMeshProUGUI textMeshProUGUI;
    22.  
    23.         private void Awake()
    24.         {
    25.             LocalizationSettings.SelectedLocaleChanged += LocaleChanged;
    26.             textMeshProUGUI = GetComponent<TextMeshProUGUI>();
    27.         }
    28.  
    29.         IEnumerator Start()
    30.         {
    31.             // Wait for the Locales to load.
    32.             yield return LocalizationSettings.InitializationOperation;
    33.         }
    34.  
    35.         private void OnEnable()
    36.         {
    37.             LoadString();
    38.             LoadFont();
    39.         }
    40.  
    41.         private void LocaleChanged(Locale locale)
    42.         {
    43.             LoadString();
    44.             LoadFont();
    45.         }
    46.  
    47.         private void LoadString()
    48.         {
    49.             if (!ValidateStringReference()) return;
    50.             var operation = stringReference.GetLocalizedStringAsync();
    51.             UpdateString(operation);
    52.  
    53.             textMeshProUGUI.ForceMeshUpdate();
    54.         }
    55.  
    56.         private void LoadFont()
    57.         {
    58.             if (!ValidateFontAssetReference()) return;
    59.             var operation = fontAssetReference.LoadAssetAsync();
    60.             UpdateFont(operation);
    61.  
    62.             textMeshProUGUI.ForceMeshUpdate();
    63.         }
    64.  
    65.         private void UpdateString(AsyncOperationHandle<string> value)
    66.         {
    67.             if(!value.IsDone)
    68.             {
    69.                 value.Completed += UpdateString;
    70.                 return;
    71.             }
    72.  
    73.             textMeshProUGUI.text = value.Result;
    74.         }
    75.  
    76.         private void UpdateFont(AsyncOperationHandle<TMP_FontAsset> value)
    77.         {
    78.             if (!value.IsDone)
    79.             {
    80.                 value.Completed += UpdateFont;
    81.                 return;
    82.             }
    83.  
    84.             textMeshProUGUI.font = value.Result;
    85.         }
    86.  
    87.         private bool ValidateStringReference()
    88.         {
    89.             if (stringReference == null) return false;
    90.             return true;
    91.         }
    92.  
    93.         private bool ValidateFontAssetReference()
    94.         {
    95.             if (fontAssetReference == null) return false;
    96.             return true;
    97.         }
    98.  
    99.  
    100.     }
    101.  
    102.  
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,820
    Try swapping the order so you apply the font before you apply the string.

    Code (csharp):
    1.  
    2.         private void LocaleChanged(Locale locale)
    3.         {
    4.             LoadFont();
    5.             LoadString();
    6.         }
    7.  
     
    the_humble likes this.
  3. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    It worked! But now I'm having an issue were if I try to start my game in a different language it shows invalid characters (as if it was translating) and then jumps back to English without changing the font. Do you know why something like this would happen?
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,820
    Did you change OnEnable and LocaleChanged?
     
  5. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    Both of them, yes
     
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,820
    It sounds like it may still be loading the asset. Try waiting for both the font and the string to be loaded before you switch.
    Maybe try a coroutine to do it all:

    Code (csharp):
    1. IEnumerator ChangeText()
    2. {
    3.     var fontOperation = fontAssetReference.LoadAssetAsync();
    4.     var stringOperation = stringReference.GetLocalizedStringAsync();
    5.  
    6.     if (!fontOperation.IsDone)
    7.         yield return fontOperation;
    8.  
    9.     if (!stringOperation.IsDone)
    10.         yield return stringOperation;
    11.  
    12.     textMeshProUGUI.font = fontOperation.Result;
    13.     textMeshProUGUI.text = stringOperation.Result;
    14.     textMeshProUGUI.ForceMeshUpdate();
    15. }
    If its switching from the language back to English then it sounds like you may be changing the language in code somewhere.
     
  7. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    Is giving this error
    Code (CSharp):
    1. Exception: Attempting to use an invalid operation handle
    2. UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[TObject].get_InternalOp () (at Library/PackageCache/com.unity.addressables@1.19.19/Runtime/ResourceManager/AsyncOperations/AsyncOperationHandle.cs:213)
    3. UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[TObject].get_Result () (at Library/PackageCache/com.unity.addressables@1.19.19/Runtime/ResourceManager/AsyncOperations/AsyncOperationHandle.cs:277)
    4. Fiero.Localization.LocalizeTMProComponent+<ChangeText>d__9.MoveNext () (at Assets/Scripts/System/Localization/LocalizeTMProComponent.cs:61)
    5. UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <40205bb2cb25478a9cb0f5e54cf11441>:0)
    6.  
     
    Last edited: Jun 9, 2023
  8. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,820
    We do have a bug with initialization running before Addressables.
    Try yielding/waiting for
    Addressables.InitializeAsync();
    before you do anything localization. We have a fix in the next release.

    E.G

    Code (csharp):
    1. IEnumerator ChangeText()
    2. {
    3.     yield return Addressables.InitializeAsync()
    4.  
    5.     var fontOperation = fontAssetReference.LoadAssetAsync();
    6.     var stringOperation = stringReference.GetLocalizedStringAsync();
    7.  
    8.     if (!fontOperation.IsDone)
    9.         yield return fontOperation;
    10.  
    11.     if (!stringOperation.IsDone)
    12.         yield return stringOperation;
    13.  
    14.     textMeshProUGUI.font = fontOperation.Result;
    15.     textMeshProUGUI.text = stringOperation.Result;
    16.     textMeshProUGUI.ForceMeshUpdate();
    17. }
     
    Last edited: Jun 9, 2023
  9. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    Is still giving errors even when yielding for the Addressables initialization but if I use the previous LoadFont and LoadText methods it works. The only other detail I have now is that the user is able to see when the language change happens, so I will probably need to add a loading screen or a buffer before the player encounters the first scene
     
  10. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,820
    It's probably called Localization Initialization somewhere before your code.
    Yes, you will need somewhere to hide the loading. We have an example loading screen in the package samples.
     
  11. the_humble

    the_humble

    Joined:
    Oct 14, 2019
    Posts:
    12
    I will keep looking into it.
    Thanks a lot Karl! Your answers have made my life easier with localization multiple times already and I can't thank you enough
     
    karl_jones likes this.