docs.unity3d.com
    Show / Hide Table of Contents

    Scripting

    This documentation describes the most common ways to interact with the Localization System via C# scripts, further examples can be found in the Scripting API documentation.

    You can download additional scripting examples from the package manager window, in the Localization package’s Samples section.

    LocalizedString

    A LocalizedString accesses specific entries from within a String Table.

    You can use the LocalizedString in a user script. It serializes and displays its own editor, which you can use to select the table and table entry, and edit the localized values inline, without opening the Tables window.

    The LocalizedString editor in Unity.

    The LocalizedString provides a UnityEngine.Localization.LocalizedString.StringChanged event. The script calls the event whenever the selected Locale changes. This makes your code simpler and more efficient, because the script only calls it when it needs to update the LocalizedString.

    
    public class LocalizedStringWithEvents : MonoBehaviour
    {
        public LocalizedString myString;
    
        string localizedText;
    
        /// <summary>
        /// Register a ChangeHandler. This is called whenever the string needs to be updated.
        /// </summary>
        void OnEnable()
        {
            myString.StringChanged += UpdateString;
        }
    
        void OnDisable()
        {
            myString.StringChanged -= UpdateString;
        }
    
        void UpdateString(string s)
        {
            localizedText = s;
        }
    
        void OnGUI()
        {
            EditorGUILayout.LabelField(localizedText);
        }
    }
    

    Dynamic Strings

    Sometimes you might need to update a localized string, such as when using Smart Strings or String.Format with arguments that have since changed. Calling GetLocalizedString with the arguments always updates the string. When you use the StringChanged event, you can use the RefreshString function to request an update, and the Arguments property to configure the arguments that format the string.

    
    /// <summary>
    /// This example expects a Smart String with a named placeholder of `TimeNow`, such as "The time now is {TimeNow}".
    /// </summary>
    public class LocalizedStringSmart : MonoBehaviour
    {
        public LocalizedString myString;
    
        string localizedText;
    
        public float TimeNow => Time.time;
    
        /// <summary>
        /// Register a ChangeHandler. This is called whenever we need to update our string.
        /// </summary>
        void OnEnable()
        {
            myString.Arguments = new[] { this };
            myString.StringChanged += UpdateString;
        }
    
        void OnDisable()
        {
            myString.StringChanged -= UpdateString;
        }
    
        void UpdateString(string s)
        {
            localizedText = s;
        }
    
        void OnGUI()
        {
            // This calls UpdateString immediately (if the table is loaded) or when the table is available.
            myString.RefreshString();
            GUILayout.Label(localizedText);
        }
    }
    

    LocalizedAsset

    LocalizedAsset is a generic class that accesses localized versions of Unity assets from within an Asset Table.

    You can use the LocalizedAsset in a user script. It serializes and displays its own editor, which you can use to select the table and table entry, and edit the localized values inline, without opening the Tables window.

    The LocalizedAsset editor in Unity.

    The LocalizedAsset provides an AssetChanged event. The script calls the event whenever a new localized asset is available, such as when the game language changes. This makes your code simpler and more efficient, because the script only calls it when it needs to update the LocalizedAsset.

    To use a LocalizedAsset, you need to create a concrete version of the class and mark it as Serializable.

    For example, to support localizing font assets, you could define the following class:

    using System;
    using UnityEngine;
    using UnityEngine.Localization;
    
    [Serializable]
    public class LocalizedFont : LocalizedAsset<Font> {}
    

    In this example, you can now add LocalizedFont to a script, and LocalizedAsset will call the AssetChanged event when a localized Font asset is available.

    The following Unity assets are already supported:

    Type Class
    AudioClip LocalizedAudioClip
    Font LocalizedFont
    GameObject/Prefab LocalizedGameObject
    Material LocalizedMaterial
    UnityEngine.Object LocalizedObject
    Sprite LocalizedSprite
    Texture LocalizedTexture
    TMP Font LocalizedTmpFont

    TableReference

    Use the TableReference struct to reference an Asset Table or String Table. To reference a table, you can use either the table's name or its unique GUID. It is usually safer to use the GUID, because you might decide to change the table name in future, which would require you to manually update your references, but the GUID always stays the same.

    TableEntryReference

    Use the TableEntryReference struct to reference an entry in an Asset Table or String Table. To reference a table, you can use either the table entry's name or its unique Key ID, an unsigned long integer. It is usually safer to use the Key ID, because you might decide to change the table entry name in future, which would require you to manually update your references, but the Key ID always stays the same.

    Using AsyncOperationHandle

    Unity does not hold all localized assets in memory ready for use. Instead, it loads them on demand when it needs them, and unloads them when it no longer needs them. Because of this, localized Assets might not be immediately available, and Unity might need to load them from disk or fetch them from a server. To facilitate this, Unity uses the AsyncOperationHandle as an interface to all requests. When an Asset is not immediately available, the localization system returns an AsyncOperationHandle. When the operation has finished, the AsyncOperationHandle provides a Completed event to notify Unity. It calls this during LateUpdate. If the request has already completed (for example, when the requested data is already loaded from a previous request, or during preloading), you can check the IsDone property for immediate access via the Result property. Alternatively, the Completed event still occurs in LateUpdate, allowing for all code to follow the same path. You can also yield on an AsyncOperationHandle inside a coroutine.

    To force an operation to complete on the main thread, call WaitForCompletion. See Synchronous Workflow for further details.

    Make a basic Locale selection menu

    This example demonstrates how to create a way for the person playing a game to select the language (defined in the Localization system by Locale) they want to use in the game. To add a UI dropdown menu to the Scene, go to GameObject > UI > Dropdown, and attach the following script:

    
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Localization.Settings;
    using UnityEngine.UI;
    
    public class LocaleDropdown : MonoBehaviour
    {
        public Dropdown dropdown;
    
        IEnumerator Start()
        {
            // Wait for the localization system to initialize
            yield return LocalizationSettings.InitializationOperation;
    
            // Generate list of available Locales
            var options = new List<Dropdown.OptionData>();
            int selected = 0;
            for (int i = 0; i < LocalizationSettings.AvailableLocales.Locales.Count; ++i)
            {
                var locale = LocalizationSettings.AvailableLocales.Locales[i];
                if (LocalizationSettings.SelectedLocale == locale)
                    selected = i;
                options.Add(new Dropdown.OptionData(locale.name));
            }
            dropdown.options = options;
    
            dropdown.value = selected;
            dropdown.onValueChanged.AddListener(LocaleSelected);
        }
    
        static void LocaleSelected(int index)
        {
            LocalizationSettings.SelectedLocale = LocalizationSettings.AvailableLocales.Locales[index];
        }
    }
    
    

    You can see a more advanced version of this script in the Localization package samples.

    Custom Table loading

    This example demonstrates how the ITableProvider can be used to provide a custom String Table without using the Addressables system. This approach is particularly useful when you want to allow users to add third party content, such as modding. The localization data could be loaded from an external file and then converted into a table at runtime.

    
    [Serializable]
    public class CustomTableProvider : ITableProvider
    {
        public string customTableCollectionName = "My Custom Table";
    
        public AsyncOperationHandle<TTable> ProvideTableAsync<TTable>(string tableCollectionName, Locale locale) where TTable : LocalizationTable
        {
            Debug.Log($"Requested {locale.LocaleName} {typeof(TTable).Name} with the name `{tableCollectionName}`.");
    
            // Provide a custom string table only with the name "My Custom Table".
            if (typeof(TTable) == typeof(StringTable) && tableCollectionName == customTableCollectionName)
            {
                // Create the table and its shared table data.
                var table = ScriptableObject.CreateInstance<StringTable>();
                table.SharedData = ScriptableObject.CreateInstance<SharedTableData>();
                table.SharedData.TableCollectionName = customTableCollectionName;
                table.LocaleIdentifier = locale.Identifier;
    
                // Add some values
                table.AddEntry("My Entry 1", "My localized value 1");
                table.AddEntry("My Entry 2", "My localized value 2");
    
                return Addressables.ResourceManager.CreateCompletedOperation(table as TTable, null);
            }
    
            // Fallback to default table loading.
            return default;
        }
    }
    
    

    The CustomTableProvider can be applied to handle String Tables or Asset Tables:

    
    public static class AssignCustomTableProviderExample
    {
        [MenuItem("Localization Samples/Assign Custom table provider")]
        public static void AssignTableProvider()
        {
            // Create an instance of the table provider.
            var provider = new CustomTableProvider();
    
            // A provider can be assigned to each database or the same provider can be shared between both.
            var settings = LocalizationEditorSettings.ActiveLocalizationSettings;
            settings.GetStringDatabase().TableProvider = provider;
            settings.GetAssetDatabase().TableProvider = provider;
    
            // Set dirty so the changes are saved.
            EditorUtility.SetDirty(settings);
        }
    }
    
    

    Applying changes to a table after the game is built

    This example demonstrates how the ITablePostprocessor can be used to apply changes to a table after it has loaded but before it has been used. This can be beneficial when you wish to modify or add additional entries to a table, such as when supporting third party content (modding).

    
    [Serializable]
    public class CustomTablePatcher : ITablePostprocessor
    {
        public void PostprocessTable(LocalizationTable table)
        {
            Debug.Log($"Postprocess {table}");
    
            if (table is StringTable stringTable)
            {
                // Add a new value
                stringTable.AddEntry("some new entry", "localized value");
    
                // Update an old value
                var entry = stringTable.GetEntry("some existing value");
                if (entry != null)
                {
                    entry.Value = "updated localized value";
                }
            }
            else if (table is AssetTable assetTable)
            {
                // Add a new value
                var entry = assetTable.AddEntry("my texture asset", null);
                entry.SetAssetOverride(Texture2D.whiteTexture);
    
                // Override an existing value
                var overrideEntry = assetTable.GetEntry("existing entry");
                if (overrideEntry != null)
                {
                    var texture = new Texture2D(10, 10);
                    overrideEntry.SetAssetOverride(texture);
                }
            }
        }
    }
    
    

    The CustomTablePatcher can be applied to handle String Tables or Asset Tables:

    
    public static class AssignCustomTablePatcherExample
    {
        [MenuItem("Localization Samples/Assign Custom table postprocessor")]
        public static void AssignTablePostprocessor()
        {
            // Create an instance of the table provider.
            var provider = new CustomTablePatcher();
    
            // A table postprocessor can be assigned to each database or the same can be shared between both.
            var settings = LocalizationEditorSettings.ActiveLocalizationSettings;
            settings.GetStringDatabase().TablePostprocessor = provider;
            settings.GetAssetDatabase().TablePostprocessor = provider;
    
            // Set dirty so the changes are saved.
            EditorUtility.SetDirty(settings);
        }
    }
    
    

    Editor

    Use the Editor scripting class LocalizationEditorSettings to make changes to Localization assets.

    The following example shows how to update a collection by adding support for a new Locale.

    
    // Create the new Locale
    var locale = Locale.CreateLocale(SystemLanguage.Spanish);
    AssetDatabase.CreateAsset(locale, "Assets/Spanish.asset");
    LocalizationEditorSettings.AddLocale(locale);
    
    // Get the collection
    var collection = LocalizationEditorSettings.GetStringTableCollection("My String Table");
    
    // Add a new table
    var newTable = collection.AddNewTable(locale.Identifier) as StringTable;
    
    // Add a new entry to the table
    var entry = newTable.AddEntry("Hello", "Hola");
    
    // Add some metadata
    entry.AddMetadata(new Comment { CommentText = "This is a comment"});
    
    // We need to mark the table and shared table data entry as we have made changes
    EditorUtility.SetDirty(newTable);
    EditorUtility.SetDirty(newTable.SharedData);
    
    
    Back to top
    Copyright © 2023 Unity Technologies — Terms of use
    • Legal
    • Privacy Policy
    • Cookies
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)
    "Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
    Generated by DocFX on 18 October 2023