Search Unity

Question Loading Localized Anything Fails the First Time

Discussion in 'Localization Tools' started by CharlieDaLoon, Jul 6, 2020.

  1. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Using 0.7 of the Unity Localization Preview

    I should not that I have preloading turned on for all of my tables - though it doesn't seem to make a difference.

    During my initial loading screen, I've added

    Code (CSharp):
    1.  
    2.         var test = LocalizationSettings.Instance.GetInitializationOperation();
    3.         while(!test.IsDone)
    4.         {
    5.             yield return null;
    6.         }
    7.  
    I wanted to make sure that the preload would be finished before continuing on.

    Then later, when loading a specific UI panel, it accesses a localized string thusly

    Code (CSharp):
    1. nameText.text = currentSelected.info.LocalizedName();
    Code (CSharp):
    1.  
    2. [SerializeField]
    3. private LocalizedString localizedname;
    4. public string LocalizedName()
    5.     {
    6.         var resolvedName = localizedName.GetLocalizedString();
    7.         if(resolvedName .IsDone)
    8.         {
    9.             // This line will NEVER be hit the first time a particular name is accessed
    10.             return resolvedName .Result;
    11.         }
    12.         Debug.Log($"Unable to localize card name for ID {cardNumber}");
    13.         //Return the result anyway because no matter what I return here, this is what's going to be displayed
    14.         return resolvedName .Result;
    15.     }
    16.  
    So for the purposes of an easy example, let's say I have a text field, and when you click on it, it cycles through a list of objects that have localized names. When the scene loads, Object1's name loads in, and it's an empty string because "IsDone" is false, so nothing is displayed. Then you click, Object2's name loads in, and it's an empty string because IsDone is false. Etc, etc, etc, etc until it cycles back around the Object1, and now the .IsDone is finished and the correct name displays.

    This happens for all of my string tables, and all of my asset tables. Which is particularly frustrating because I'm supposed to be playing localized dialogue on top of localized text, but the LocalizedAudioClip will never play the first time it's accessed.

    I understand why this is happening - GetLocalizedString is an async function, and my code is immediately moving onto the IsDone line before the async function has time to finish running. I just thought that preloading the tables was supposed to solve this problem.

    Is there a way of doing this that will solve this problem? This is the first time I've bothered with localizing anything.
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    Hi,
    I actually fixed a bug today that I think is the problem. Localized strings that use table name Guid don't return immediately even after preloading. I have a fix for this in the next version.
    With the fix it should work as you expect.

    Code (csharp):
    1. while(!test.IsDone)      
    2.   {            
    3. yield return null;      
    4.    }
    You can yield on the actual operation so you don't need to check isDone
     
    Last edited: Jul 6, 2020
    CharlieDaLoon likes this.
  3. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Any chance this affects preloaded assets also?

    When can we expect the next version?
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    Yes it's any tables including preloaded. Next release is scheduled for next month. I may be able to do an early release with a few big fixes.
     
    CharlieDaLoon likes this.
  5. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Amazing, glad to hear it! I sincerely hope this is the issue I'm having... Now I just need to figure out how to work around it until then so my team can move forward for the next month.

    Thanks for your help!
     
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    How many string tables do you have? It's actually not that hard to work around.
     
    CharlieDaLoon likes this.
  7. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    At the moment we have 6 string tables and 1 asset table of audio clips. The workaround I've been using so far is to hide localized strings off-screen during loading screens that pre-load the strings I want a second time.
     
  8. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    So the bug is that loading a table using a guid takes an extra frame because preloading does not update the guid reference cache. So you could load the string tables during initialization with their guid. Then it should be fine.

    E.g LocalizationSettings.StringDatabase.GetTablrAsync(new Guid(....

    Use the guid of the shared table data asset.

    Alternatively use the table name instead of a guid. we use the guid when editing through the Inspector.
     
    CharlieDaLoon likes this.
  9. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Aaahhh, got it! Thanks for the explanation, I appreciate it! I'm relying heavily on ScriptableObjects whose LocalizedStrings are set in the editor, so now I understand where the problem is coming from. I can devise a good way that we can still rely on the editor but also work around this issue for now. Thanks again!
     
    karl_jones likes this.
  10. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    So I saw you pushed an update to Localization a few days after I opened this, and I saw in the changelog that the fix for the inspector stuff was included.

    So inspector stuff is working now - but nothing I'm using programmatically is working, and I've found the reason why.

    In the localization tutorials here, the way it's suggested to load in a localized string is as such:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Localization;
    3.  
    4. public class LocalizedStringExample : MonoBehaviour
    5. {
    6.     public LocalizedString myString;
    7.  
    8.     void OnGUI()
    9.     {
    10.         var localizedText = myString.GetLocalizedString();
    11.         if (localizedText.IsDone)
    12.         {
    13.             GUILayout.Label(localizedText.Result);
    14.         }
    15.     }
    16. }
    This is.... wrong. By definition this will never work the first time you access a localized asset.
    OnGUI
    is a synchronous function and
    GetLocalizedString()
    appears to be asynchronous. So
    OnGUI
    is firing off the call to
    GetLocalizedString()
    and doesn't bother to await the asynchronous function to be finished. So for me, what's happening is that
    IsDone
    is always false the first time a localized string is accessed, Unity pitches a fit, and then the second time I access the localized string, it works fine because IsDone is now set to true from the last time I called
    GetLocalizedString()
    .

    Now the concerning thing is that, as mentioned, I'm preloading all of my tables, so I would expect this not to happen. I would expect every string in my table to be loadable on demand in the way the code implies it is.

    I'm not really doing anything special with these tables, the localized strings, or with my project. It's a relatively small project, so I don't really know why this wouldn't work for me if it does work for you, for example.
     
  11. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    Yes this was a bug. It's to do with how we load a table by guid. We have a fix in 0.8.0 which is scheduled for the 17th
     
    nicolasgramlich likes this.
  12. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Excellent! Thanks for the quick reply, looking forward to it!
     
    karl_jones likes this.
  13. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Yesterday's update fixed my issue! Just wanted to come back and thank you for your hard work and communication!
     
    karl_jones likes this.
  14. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    I don't suppose this bug might also exist with LocalizedAudioClips?

    Accessing it in much the same way:
    Code (CSharp):
    1. public AudioClip LocalizedAudioClip()
    2.     {
    3.         if(loadedLocalizedAudioClip != null)
    4.         {
    5.             return loadedLocalizedAudioClip;
    6.         }
    7.         if(!localizedAudioClip.IsEmpty)
    8.         {
    9.             var result = localizedAudioClip.LoadAssetAsync();
    10.             if (result.IsDone)
    11.             {
    12.                 loadedLocalizedAudioClip = result.Result;
    13.             }
    14.         }
    15.         return loadedLocalizedAudioClip;
    16.     }
    The first time the code passes over this, much like with the strings last time, the asset can't be accessed so it's just returning null. The second time it passes over it, it works as it should every time.
     
  15. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    It won't work the first time unless the asset has already been loaded somewhere else. Addressables needs to load the asset asynchronously and it won't return until the late update method at the earliest.
    Have you marked the table as preloaded? It's in the meta data editor part.
     
  16. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Yes, I meant to include that in my previous post - all of my tables are marked as preload (because they're small enough at this point that I don't mind doing it). Does this change your answer at all?
     
  17. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    Yes, it should be working the first time if preloading has completed.
    Has LocalizationSettings.InitializationOperation finished?
    Is LocalizationSettings.InitializationOperation.isDone true the first time you try and get the audio clip?
     
  18. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    I added a Debug.Log, see here at line 3
    Code (CSharp):
    1. if(!localizedAudioClip.IsEmpty)
    2.     {
    3.         Debug.Log(LocalizationSettings.InitializationOperation.IsDone);
    4.         var result = localizedAudioClip.LoadAssetAsync();
    5.         if (result.IsDone)
    6.         {
    7.             loadedLocalizedAudioClip = result.Result;
    8.         }
    9. }
    On the first run through this code, that outputs true.

    I suspected that this would be the case because I have a load screen before the main title screen that waits for

    GetInitializationOperation()
    to be finished before it allows the user to progress.
     
  19. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,282
    Looks like it could be a bug. Could you please file a bug report.
     
  20. CharlieDaLoon

    CharlieDaLoon

    Joined:
    Mar 3, 2020
    Posts:
    22
    Bug submitted, thanks for your input!
     
    karl_jones likes this.