Apply locale selectively to all UI elements within a canvas?

Unity noob here, just got the Localization package running today. Using Localization package v1.0.5 within Unity 2021.2.14f1.

In my case I am hoping to be able to selectively apply locale to different parts of my application. Instead of always applying locale globally, it possible to have one canvas with all child UI in “English (en)” locale and a separate canvas with all child UI “Spanish (es)” locale simultaneously? And within those canvases provide separate controls to change locale on user input?

For context, my case is a split screen application where both sides of the screen are running separate instances of essentially the same application, but it is not a multiplayer game.

Yes you can do this. First I would upgrade to 1.3.1 to make sure you have the latest version. It should be visible in the package manager if you enable the show all versions option in the package manager. Alternatively you can just edit the manifest JSON file in the packages file.

A LocalizedString can have a LocaleOverride applied to change the language from the selected one. Class LocalizedReference | Localization | 1.3.2

So you would need to apply this override to all the localized strings you want to be different from the selected locale.

@karl_jones Thanks for your help! I’ll look into this at some point this week and update the thread when I’ve tried it.

I may come up with some questions about best practices for implementing the LocaleOverride. Seems like I’ll just need to connect all LocalizedStrings on my secondary canvas to its UI toggle (a button for switching between English and Spanish) via LocaleOverride.

1 Like

Okay, so after looking into it I think this is the workflow that I will have to apply to each of my UI components to use LocaleOverride.

        TextMeshProUGUI ExampleTextMeshProUGUI = ExampleGameObject.GetComponent<TextMeshProUGUI>();
        LocalizeStringEvent ExampleLocalizeStringEvent = ExampleTextMeshProUGUI.GetComponent<LocalizeStringEvent>();
     ExampleLocalizeStringEvent.StringReference.LocaleOverride = LocalizationSettings.AvailableLocales.GetLocale(SystemLanguage.English); // or SystemLanguage.Spanish
        ExampleTextMeshProUGUI.text = ExampleLocalizeStringEvent.StringReference.GetLocalizedString();

This seems to work for me. @karl_jones , anything that I am missing? or any better way to do it?

Thanks!

Assuming you have 2 Canvases, 1 for selected locale and 1 for the override locale:

Call this on the locale override canvas.

void ApplyLocaleOverride(Locale locale, GameObject canvasRoot)
{
    foreach(var ls in canvasRoot.GetComponentsInChildren<LocalizeStringEvent>())
    {
        ls.StringReference.LocaleOverride = locale;
    }
}

You should not need to call GetLocalizedString, the text should automatically update when LocaleOverride is changed, as long as you are using the StringChanged event.

Excellent, appreciate your help a lot!

My mistake with using GetLocalizedString(), I must have misinterpreted one of my early tests with assigning LocalizeStringEvent.StringReference.LocaleOverride to think I needed that.

Below is my final script solving this problem for anyone that might be searching in the future. This is meant to provide language toggling on two identical canvases, each with their own button to switch between English and Spanish, via the onClick listener. I have a CanvasManager component class attached to the root canvas for each UI, which holds public references to the child UI objects - just my current choice for managing each UI. Both of my language buttons use this one script.

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

public class LangButton : MonoBehaviour
{
    [SerializeField] CanvasManager CanvasManager;

    // To be used as reference to check locale override status within ApplyLocaleOverride
    LocalizeStringEvent LocalizeStringEventRef;

    UnityEngine.Localization.Locale EnLocale;
    UnityEngine.Localization.Locale EsLocale;

    // Start is called before the first frame update
    IEnumerator Start()
    {
        // Wait for the localization system to initialize
        yield return LocalizationSettings.InitializationOperation;

        // Establish available locales
        //
        // These could also be accessed with
        // LocalizationSettings.AvailableLocales.GetLocale(SystemLanguage.English);
        // LocalizationSettings.AvailableLocales.GetLocale(SystemLanguage.Spanish);
        for (int i = 0; i < LocalizationSettings.AvailableLocales.Locales.Count; ++i)
        {
            var Locale = LocalizationSettings.AvailableLocales.Locales[i];
            switch (Locale.name)
            {
                case "English (en)":
                    EnLocale = LocalizationSettings.AvailableLocales.Locales[i];
                    break;

                case "Spanish (es)":
                    EsLocale = LocalizationSettings.AvailableLocales.Locales[i];
                    break;
            }
        }

        // Initialize reference to check locale override status within ApplyLocaleOverride
        LocalizeStringEventRef = CanvasManager.GetComponentInChildren<LocalizeStringEvent>();

        // Set initial locale override to English
        ApplyLocaleOverride(EnLocale, CanvasManager.gameObject);

        // Add listener to button
        CanvasManager.LangBtn.GetComponent<Button>().onClick.AddListener(ChangeLang);
    }

    void ChangeLang()
    {
        if (LocalizeStringEventRef.StringReference.LocaleOverride == EnLocale)
        {
            ApplyLocaleOverride(EsLocale, CanvasManager.gameObject);
        }
        else if (LocalizeStringEventRef.StringReference.LocaleOverride == EsLocale)
        {
            ApplyLocaleOverride(EnLocale, CanvasManager.gameObject);
        }
    }

    // Override locale per canvas by looping through each LocalizeStringEvent component within a canvas
    void ApplyLocaleOverride(Locale locale, GameObject canvasRoot)
    {
        foreach(var LocalizeStringEvent in canvasRoot.GetComponentsInChildren<LocalizeStringEvent>(true)) // Pass includeInactive param as true to get inactive UI strings too
        {
            LocalizeStringEvent.StringReference.LocaleOverride = locale;
        }
    }

}

Thanks again, @karl_jones !