WebGL asynchronous or synchronous issues with Localization

Hi, I am getting this error in my browser when playing my webgl build:

Exception: WebGLPlayer does not support synchronous Addressable loading. Please do not use WaitForCompletion on the WebGLPlayer platform.
at UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1[TObject].WaitForCompletion () [0x00000] in <00000000000000000000000000000000>:0

This is the code that handles the localization from the Unity side:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using TMPro;
using UnityEngine.UI;
using UnityEngine.Localization.Metadata;
using System.Collections;

public class DropdownLanguageSelector : MonoBehaviour
{
    [Header("References")]
    public Button toggleButton;
    public RectTransform dropdownContent;
    public GameObject buttonPrefab;

    [Header("Toggle Button Display")]
    public Image toggleFlagImage;
    public TMP_Text toggleLanguageText;

    private bool isDropdownOpen = true;
    private List<GameObject> spawnedButtons = new List<GameObject>();
    private Locale currentLocale;

    private void OnDisable()
    {
        toggleButton.onClick.RemoveListener(ToggleDropdown);
        LocalizationSettings.SelectedLocaleChanged -= UpdateToggleDisplay;
    }

    private IEnumerator Start()
    {
        // Wait for the localization system to initialize
        yield return LocalizationSettings.InitializationOperation;

        // Now it's safe to use the localization system
        Debug.Log("Localization system initialized. Current Locale: " + LocalizationSettings.SelectedLocale);

        toggleButton.onClick.AddListener(ToggleDropdown);

        PopulateDropdown();
        ToggleDropdown();

        UpdateToggleDisplay(LocalizationSettings.SelectedLocale);

        LocalizationSettings.SelectedLocaleChanged += UpdateToggleDisplay;
    }

    void ToggleDropdown()
    {
        isDropdownOpen = !isDropdownOpen;
        dropdownContent.gameObject.SetActive(isDropdownOpen);

        // Update button styles to highlight the current locale
        UpdateButtonStyles();
    }

    void PopulateDropdown()
    {
        var locales = LocalizationSettings.AvailableLocales.Locales;

        foreach (var locale in locales)
        {
            var buttonInstance = Instantiate(buttonPrefab, dropdownContent);
            var buttonScript = buttonInstance.GetComponent<LanguageButton>();

            if (buttonScript != null)
            {
                buttonScript.SetLocale(locale, OnLanguageSelected);
            }

            spawnedButtons.Add(buttonInstance);
        }
    }

    void UpdateToggleDisplay(Locale selectedLocale)
    {
        if (selectedLocale == null) return;

        currentLocale = selectedLocale;

        var metadata = selectedLocale.Metadata.GetMetadata<LocaleMetadata>();
        if (metadata != null)
        {
            toggleFlagImage.sprite = metadata.Flag; // Custom metadata for flags
        }

        toggleLanguageText.text = FormatLocaleCode(selectedLocale.Identifier.Code);
    }

    void UpdateButtonStyles()
    {
        foreach (var button in spawnedButtons)
        {
            var buttonScript = button.GetComponent<LanguageButton>();
            if (buttonScript != null)
            {
                // Check if the button's locale matches the current selected locale
                bool isCurrentLocale = buttonScript.GetLocale() == currentLocale;

                // Change button appearance
                var buttonImage = button.GetComponent<Image>();
                if (buttonImage != null)
                {
                    buttonImage.color = isCurrentLocale ? Color.red : Color.white;
                }
            }
        }
    }

    void OnLanguageSelected(Locale selectedLocale)
    {
        // Change the active locale and close the dropdown
        LocalizationSettings.SelectedLocale = selectedLocale;
        ToggleDropdown();
    }

    string FormatLocaleCode(string code)
    {
        // Force Chinese locale code to be "ZH"
        if (code.ToLower().StartsWith("zh"))
        {
            return "ZH";
        }

        return code.ToUpper();
    }
}

What must I do to allow the WebGL to work with the locales?

Nothing stands out in your script. Do you have a full callstack with the error?

That error is the only thing it gives there rest of the errors under it are just a result of that error as that it can not find the locales.

 IEnumerator Start()
    {
        yield return WaitForLoc();

        toggleButton.onClick.AddListener(ToggleDropdown);

        PopulateDropdown();
        ToggleDropdown();

        UpdateToggleDisplay(LocalizationSettings.SelectedLocale);

        LocalizationSettings.SelectedLocaleChanged += UpdateToggleDisplay;
    }

    IEnumerator WaitForLoc()
    {
        yield return LocalizationSettings.InitializationOperation;
        //while (LocalizationSettings.InitializationOperation.IsDone != true)
        //{
        //    yield return null;
        //}
    }

I am currently trying this to see if I can avoid any async stuff as it just breaks everything localization related.

#edit this also does not work → 777d631d-a4ad-40f7-b245-4163eaeb7c28:14 Exception: WebGLPlayer does not support synchronous Addressable loading. Please do not use WaitForCompletion on the WebGLPlayer platform.
at UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1[TObject].WaitForCompletion () [0x00000] in <00000000000000000000000000000000>:0

Do you have any other scripts calling into localization before this?

No, this is the only script used to handle localization / changing the active language.
If you want I can give you access to download my repo of this project. It is just my portfolio: Nathan Steendam | Portfolio Website

Sharing the link so you can check the error :muscle:

1 Like

Yes, can you share the project? The webgl errors dont provide enough information.

With the amazing help of @karl_jones I was able to solve the problem. I was using.GetLocalizedString() in my code on start which caused the error. Karl recommended using GetLocalizedStringAsync instead.

1 Like