Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Loca breaks with no internet?

Discussion in 'Localization Tools' started by Nilokilo, Nov 23, 2023.

  1. Nilokilo

    Nilokilo

    Joined:
    Oct 21, 2020
    Posts:
    13
    I have set preload behavior to "no preload" in the settings but as soon as I start the game without anything downloaded previously with Internet turned off the log gets spammed with errors that it can not load loca bundles and that the locale is null. The scene does not even have any loca or text at all and still it wants to load it by force.

    It gets even worse once the error with the null locale appeared the game remains broken even if the Internet returns. Only a restart with internet turned on fixes it.

    I tried setting the addressables group schema retry count to -1 as suggested in the tooltip to prevent downloading but it does not allow me to do it, it resets to 0. Also there seems to be no function to reinitialize localization.

    What I want to achieve is: don't load anything by default and only if there is text in the scene or I call get loca myself it should download. Is there a way to do this?
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,147
    The system will need to load the locales at the start In order to know what languages are supported and to pick the initial language.
    Are your addressables being hosted remotely?
    Can you have a local version of the locales bundle?
     
  3. Nilokilo

    Nilokilo

    Joined:
    Oct 21, 2020
    Posts:
    13
    Yes they are purely remote, no local bundles. Besides we don't want local bundles I also don't know how to have 2 versions in parallel. The loca bundle has always the entire loca in it so putting this to local + updatable is no option.

    Is there no way to prevent the loca system to permanently crash without Internet in startup? It could be so easy if it works like normal addressables which can be either downloaded manually on demand or get pulled automatically when a component requests it.
    My suggestion would be if preload is set to No preload it does nothing, then add a function to manually initialize loca which returns a handle which contains errors when for example the connection is dead so the client can retry by recalling that function. Or is there another trick I can try?
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,147
    There are a few things you could try.

    1)
    You could ignore the initial errors and reset the system when you want to retry by releasing the initialization operation.

    Code (csharp):
    1. Addressables.Release(Localization.InitializationOperation);
    2. // Restart initialization
    3. Localization.InitializationOperation;
    2) You could provide a custom locale provider. Create a new class that inherits from ILocalesProvider. In the Editor, assign it to LocalizationSettings.AvailableLocales and set the settings dirty so it saves.
    EditorUtility.SetDirty(LocalizationSettings.Instance)
    . You will then need to return the locales, they could be loaded from addressables or just created locally in memory.

    3)
    You could provide a local copy of the remote assets to fall back to. This can be done by adding them to a directory which you add to the cache with Caching.AddCache
    You need to make sure the files have the correct naming and manifest, I can walk you through it if it's something you want to try.
     
  5. Nilokilo

    Nilokilo

    Joined:
    Oct 21, 2020
    Posts:
    13
    I tried the first suggestion and it did not work. First of all Localization namespace did not contain the handle so i used LocalizationSettings.InitializationOperation instead. Then awaiting the operation task always returns with status succeeded and no operationException but the errors are logged. Anyway i cought them with the ResourceManager.ExceptionHandler to set a flag that something went wrong. And then i called Addressables.Release(LocalizationSettings.InitializationOperation) and awaited the InitializationOperation again but no more errors are thrown as if nothing gets executed anymore so this approach failed.

    The second suggestion i don't really know how to achieve what you described but since it still has to return locales from addressables it will fail as well and a locale created in memory - how does that work and how would i assign the class inheriting from ILocalProvider in the settings?

    Option 3 sounds a bit too complex for now.

    But regarding a sulution (if any works) with local or memory locales, how would i still get the download error flow when trying to load a real locale from addressable without internet? I prefer option 1 though if it just would return an operationException in the handle which it doesn't and had a retry function as you posted but also it does not work.

    If you think option 1 should work i would like to see a working code snippet.
     
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,147
    Sorry, yes it should be LocalizationSettings, not Localization.
    There was 1 step I forgot, you also need to reset the LocalesProvider, however, there is a simpler way to handle this.
    LocalizationSettings implements IDisposable which resets the entire system. We mainly use this for testing but it should be exactly what you need.

    So do this instead:

    Code (csharp):
    1. ((IDisposable)LocalizationSettings.Instance).Dispose();
    2.  
    3. // Restart initialization
    4. Localization.InitializationOperation;
     
    Nilokilo likes this.
  7. Nilokilo

    Nilokilo

    Joined:
    Oct 21, 2020
    Posts:
    13
    Thanks, the disposable way worked! But the way to detect the errors is not very nice. Would it be possibble in a future update that the InitializationOperation does not return success and propagates the exception? I did not find a better way to handle the error case at the moment than this:


    Code (CSharp):
    1. private bool _initializingSuccessful = true;      
    2.        
    3. private async void Start()
    4. {
    5.     ResourceManager.ExceptionHandler = CustomExceptionHandler;
    6.     do
    7.     {
    8.        await InitializeLoca();
    9.     }
    10.     while (!_initializingSuccessful);
    11.  
    12.     Debug.Log("Success!");
    13. }
    14. private async UniTask InitializeLoca()
    15. {
    16.     _initializingSuccessful = true;
    17.     var op = LocalizationSettings.InitializationOperation;
    18.     await op.Task;
    19.     //always returns success no matter what :(
    20.     Debug.LogWarning($"status: {op.Status}");
    21.     //always null :(
    22.     Debug.LogWarning($"Exception: {op.OperationException}");
    23.  
    24.     //retry after 2s if failed
    25.     if (!_initializingSuccessful)
    26.     {
    27.         ((IDisposable)LocalizationSettings.Instance).Dispose();
    28.         await UniTask.Delay(TimeSpan.FromSeconds(2));
    29.     }
    30. }
    31. void CustomExceptionHandler(AsyncOperationHandle handle, Exception exception)
    32. {
    33.     if (exception != null)
    34.     {
    35.         Debug.LogError(exception.Message);
    36.         _initializingSuccessful = false;
    37.     }
    38. }
     
    karl_jones likes this.
  8. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,147
    I have created a bug so we can fix it in the future. https://issuetracker.unity3d.com/product/unity/issues/guid/LOC-1038
     
    Nilokilo likes this.