Localizing custom asset (Fonts) doesnt work in build

Hello,

I was building a Localization system, and followed this thread to localize the fonts in our texts.

I’ve created texts prefabs with this configuration that I’m using throughout the game:

While it works perfectly in Editor, I’m finding some erratic behaviour in Build.

One thing I have not yet traced is that in some instances, upon starting the game, EVERY SINGLE TEXT appears blank (or default null character). Since I know the menus, I can blindly navigate through to the language settings, and when I change the languages (thus creating a LocalizationEvent call), the text appears again.

This happens sometimes, I couldn’t find why yet. But having this issue or not in a playsession, I have traced another issue when navigating the language settings: I have to navigate through the menu twice for the fonts to be changed accordingly.

SIMPLIFIED EXAMPLE:

  • Imagine I have this horizontal scroll to navigate through all my different languages seen in the previous image.
  • If my current language is English, I can navigate the menu normally and see languages change.
  • When I get to change from Italian to Polish (first lang with a different font) I will not see nor text or fonts change.
  • If I go back to Italian and then Polish again, I will see fonts and texts updated correctly.
  • This will happen again each time I’m navigating to languages with fonts I have not visited yet.

The stack trace for this error reads the following:

AssertionException: Assertion failure. Value was Null
Expected: Value was not Null
at UnityEngine.Assertions.Assert.Fail (System.String message, System.String userMessage) [0x00043] in <34494dee0a8743c49ad9dc4c9c1f32e6>:0
at UnityEngine.Assertions.Assert.IsNotNull (UnityEngine.Object value, System.String message) [0x00013] in <34494dee0a8743c49ad9dc4c9c1f32e6>:0
at UnityEngine.Assertions.Assert.IsNotNull[T] (T value, System.String message) [0x0001f] in <34494dee0a8743c49ad9dc4c9c1f32e6>:0
at UnityEngine.Assertions.Assert.IsNotNull[T] (T value) [0x00001] in <34494dee0a8743c49ad9dc4c9c1f32e6>:0
at UnityEngine.Localization.Tables.TableEntry.get_SharedEntry () [0x0000f] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Tables\DetailedLocalizationTable.cs:35
at UnityEngine.Localization.GetTableEntryOperation`2[TTable,TEntry].HandleEntryOverride (UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[TObject] asyncOperation, TEntry entry) [0x0006f] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Operations\GetTableEntryOperation.cs:87
at UnityEngine.Localization.GetTableEntryOperation`2[TTable,TEntry].ExtractEntryFromTable (UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[TObject] asyncOperation) [0x0005e] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Operations\GetTableEntryOperation.cs:64
at UnityEngine.Localization.GetTableEntryOperation`2[TTable,TEntry].Execute () [0x00080] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Operations\GetTableEntryOperation.cs:50
at UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1[TObject].InvokeExecute () [0x00001] in C:\...\Library\PackageCache\com.unity.addressables@1.19.18\Runtime\ResourceManager\AsyncOperations\AsyncOperationBase.cs:474
at UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1[TObject].Start (UnityEngine.ResourceManagement.ResourceManager rm, UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle dependency, DelegateList`1[T] updateCallbacks) [0x000a1] in C:\...\Library\PackageCache\com.unity.addressables@1.19.18\Runtime\ResourceManager\AsyncOperations\AsyncOperationBase.cs:469
at UnityEngine.ResourceManagement.ResourceManager.StartOperation[TObject] (UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1[TObject] operation, UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle dependency) [0x00001] in C:\...\Library\PackageCache\com.unity.addressables@1.19.18\Runtime\ResourceManager\ResourceManager.cs:460
at UnityEngine.Localization.Settings.LocalizedDatabase`2[TTable,TEntry].GetTableEntryAsync (UnityEngine.Localization.Tables.TableReference tableReference, UnityEngine.Localization.Tables.TableEntryReference tableEntryReference, UnityEngine.Localization.Locale locale, UnityEngine.Localization.Settings.FallbackBehavior fallbackBehavior) [0x00041] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Settings\Database\LocalizedDatabase.cs:461
at UnityEngine.Localization.Settings.LocalizedAssetDatabase.GetLocalizedAssetAsyncInternal[TObject] (UnityEngine.Localization.Tables.TableReference tableReference, UnityEngine.Localization.Tables.TableEntryReference tableEntryReference, UnityEngine.Localization.Locale locale, UnityEngine.Localization.Settings.FallbackBehavior fallbackBehavior) [0x00001] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Settings\Database\LocalizedAssetDatabase.cs:96
at UnityEngine.Localization.Settings.LocalizedAssetDatabase.GetLocalizedAssetAsync[TObject] (UnityEngine.Localization.Tables.TableReference tableReference, UnityEngine.Localization.Tables.TableEntryReference tableEntryReference, UnityEngine.Localization.Locale locale, UnityEngine.Localization.Settings.FallbackBehavior fallbackBehavior) [0x00001] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Settings\Database\LocalizedAssetDatabase.cs:69
at UnityEngine.Localization.LocalizedAsset`1[TObject].LoadAssetAsync () [0x0000c] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Localized Reference\LocalizedAsset.cs:197
at UnityEngine.Localization.LocalizedAsset`1[TObject].HandleLocaleChange (UnityEngine.Localization.Locale _) [0x00018] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Localized Reference\LocalizedAsset.cs:286
at (wrapper delegate-invoke) System.Action`1[UnityEngine.Localization.Locale].invoke_void_T(UnityEngine.Localization.Locale)
at UnityEngine.Localization.Settings.LocalizationSettings+<InitializeAndCallSelectedLocaleChangedCoroutine>d__72.MoveNext () [0x0004b] in C:\...\Library\PackageCache\com.unity.localization@1.0.5\Runtime\Settings\LocalizationSettings.cs:406
at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00026] in <34494dee0a8743c49ad9dc4c9c1f32e6>:0 ```

From which I read that when the system tries to load the locale, it returns null, so the Localization Update Corroutine fails.
But next time, the same locale is not null? How?

I have tried to go through this [solution](https://discussions.unity.com/t/838665) .
Although I'm not familiar with Adressables, it seems that everything is correct in our projects, and rebuilding didn't seem to change anything.

What can I do?

Unity 2021.2.14f1
Localization 1.0.5
Addressables 1.19.18

Hi,

Could you share the code you are using?

This is the LocEvent class:

using TMPro;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;

    [System.Serializable]
    public class LocalizedFont : LocalizedAsset<TMP_FontAsset> { }

    [System.Serializable]
    public class UpdateFontEvent : UnityEvent<TMP_FontAsset> { }

    public class LocalizedFontEvent : LocalizedAssetEvent<TMP_FontAsset, LocalizedFont, UpdateFontEvent>
    {
}

Upon changing the option from the settings menu, we have this function callback

public class SettingsMenu : UIScreen
{
    [SerializeField] private OptionHorizontalSelector languageSelector;

      public void SetLanguage()
        {
            GameController.Instance.Persistance.SettingsData.Language = languageSelector.GetCurrentSelected();
        }
}

That goes through the Settings class

public class SettingsDataHandler
{
       // ----- SettingsData -----
        [System.Serializable]
        public class SettingsData
        {
            // Everything here is an index referencing the selected option on the menus!
            // Audio
            public int masterVolume = 10;
            public int musicVolume = 8;
            public int sfxVolume = 8;
            // Gameplay
            public int languageID = -1;
           ...
        }

        // ----- SettingsDataHandler -----
        private SettingsData settingsData;

        public int Language
        {
            get { return settingsData.languageID; }
            set
            {
                settingsData.languageID = value;
                LoadLanguage(value);
            }
        }

        //This is the function that gets called in the end. It also gets called upon game start, when loading the stored/default language:
        private void LoadLanguage(int id)
        {
            LocalizationSettings.InitializationOperation.WaitForCompletion();
            LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.Locales[id];
        }
}

Edits: Sorry so much editing, tring to convey the info as best as possible!

Could you try updating to the latest package version 1.4.3? if it’s not visible in the package manager you can edit the manifest.json file in the packages folder and set it manually.

YES! That does fix the issue!

Tried to update from Package Manager but the Update button did not appear, so updated manifest.json. I guess you are aware of that.

HOWEVER, a new error has appeared, related to the first untracked issue. Again, the text is not appearing, now showing this log:

OperationException : Expected to have a current operation to wait on. Can not complete.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[ ])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:LogError (object)
UnityEngine.AddressableAssets.AddressablesImpl:LogException (UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle,System.Exception) (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/AddressablesImpl.cs:219)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:set_OperationException (System.Exception) (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs:348)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:Complete (UnityEngine.Localization.Settings.LocalizationSettings,bool,System.Exception,bool) (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs:488)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:Complete (UnityEngine.Localization.Settings.LocalizationSettings,bool,string,bool) (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs:451)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:Complete (UnityEngine.Localization.Settings.LocalizationSettings,bool,string) (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs:435)
UnityEngine.Localization.Operations.WaitForCurrentOperationAsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:InvokeWaitForCompletion () (at C:/.../Library/PackageCache/com.unity.localization@1.4.3/Runtime/Operations/WaitForCurrentOperationAsyncOperationBase.cs:40)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1<UnityEngine.Localization.Settings.LocalizationSettings>:WaitForCompletion () (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs:172)
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1<UnityEngine.Localization.Settings.LocalizationSettings>:WaitForCompletion () (at C:/.../Library/PackageCache/com.unity.addressables@1.20.5/Runtime/ResourceManager/AsyncOperations/AsyncOperationHandle.cs:199)
Ugly.SettingsDataHandler:LoadLanguage (int) (at C:/.../Assets/Scripts/Game/GameStorage/SettingsDataHandler.cs:201)
Ugly.SettingsDataHandler:LoadSettingsData (string) (at C:/.../Assets/Scripts/Game/GameStorage/SettingsDataHandler.cs:160)
Ugly.Persistance:ResetPersistentSettingsData () (at C:/.../Assets/Scripts/Game/Persistance.cs:47)
Ugly.GameController:OnFirstAwake () (at C:/.../Assets/Scripts/Game/GameController.cs:124)
Ugly.GameController:Awake () (at C:/.../Assets/Scripts/Game/GameController.cs:84)

This is triggered by the WaitForCompletion when loading the default language (pasting again the code). Happens when starting the game, trying to load the saved settings:

private void LoadLanguage(int id)
        {
            LocalizationSettings.InitializationOperation.WaitForCompletion();
            LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.Locales[id];
        }

Is that function deprecated somehow in this new patch? Or should I try to catch an exception I dont know about here?

Btw, thanks for the quick responses, you are even faster than me! Seeing your answers in other posts too, seems like you are doing a great job around here. Really appreciated!

Nothing is deprecated. I’m not sure what would cause this. Try enabling initialize synchronously in the localization settings. Then remove the call to WaitForCompletion. See if that fixes the issues

I’m also seeing these artifacts for just a frame or two when changing language.
I will take a look into that tomorrow, lets see if I can find something causing it…

(magenta should be letters)

That did fix both issues. Thank you.
Curious about what am I doing wrong with the async load…

I’m not sure but I suspect you were calling wait for completion on an operation that has been released. The initialize synchronously flag will call it for you at the start.

Ok karl, I’m sorry I’m getting back to you.

After doing all this, I was able to have a correct build yesterday, that is behaving as expected.
However, now that I’m working again on the Editor, I have this issue where Reloading Script Assemblies takes forever (more than 30min last time I tried).

In the Localizations Settings, I had this Preload option:
9007090--1241455--upload_2023-5-11_15-56-30.png

I have found out that disabling Domain Reloading, fixed the wait time, but I dont want to do that just because I updated a package…
The other thing I tried is to select “No Preloading”. That seems to fix it too.

Is this an expected behaviour?

This sounds like its preloading all the tables during the assembly reload. It could be a bug although it could also be by design if you have a project locale selected in the editor as this will trigger the preloading. Could you please file a bug report so we can look into it?

Ok. Will try to do it when crunch time finishes x)
No time now to reproduce the issue in a test project.

1 Like