Search Unity

Official Package UI Localization is available in 2020.2

Discussion in 'Editor Workflows' started by yuji_unity3d, Aug 24, 2020.

  1. yuji_unity3d

    yuji_unity3d

    Unity Technologies

    Joined:
    Oct 30, 2015
    Posts:
    2
    UI of your Package can be localized in 2020.2. This thread introduces how to do that.

    First of all, now we can have 4 languages for this feature, Japanese, Korean, Simplified Chinese and Traditional Chinese. You will need to install language module in the Editor via the Unity Hub beforehand.

    Step 1: Create a PO file as a dictionary.
    PO files are dictionary files defined in GNU gettext. The file names need to be as follows:
    • ja.po for Japanese
    • ko.po for Korean
    • zh_hans.po for Simplified Chinese
    • zh_hant.po for Traditional Chinese
    See GNU gettext for the file format. We'll prepare a sample ja.po file with the following contents.

    msgid ""
    msgstr ""
    "Language: ja\n"

    msgid "Yes"
    msgstr "TranslatedYes"

    Note that the first entry is an empty character. All you need to set the property is the language. The second entry contains a sample "Yes" translation. The file format must be saved in UTF-8.
    When a po file exists under Assets folder, the registration strings can be observed by the inspector.

    Step 2: Create an Assembly Definition File.
    The dictionaries need to be separated so that they don't interfere with other packages or with Unity's own dictionaries. Create an assembly definition file at the location that contains the po file. Typically you make Assembly Definition File for Runtime and Editor each. The po file should be placed at Editor one.

    Step 3: Set LocalizationAsset attribute to the assembly.
    Assets/Editor/Localization/Localization.cs for example would be good, whose content is:
    Code (CSharp):
    1. #if UNITY_2020_2_OR_NEWER
    2. [assembly: UnityEditor.Localization]
    3. #endif
    Step 4: Call L10n.Tr for the translation.

    L10n.Tr("Yes") returns "TranslatedYes" now if users change Language to Japanese at Preference Window. Please use it for the UI. This is the example:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class MyWindow : EditorWindow
    5. {
    6.     private static readonly string YesString = L10n.Tr("Yes");
    7.     [MenuItem("Window/My Custom Editor Window")]
    8.     static void Init()
    9.     {
    10.         var window = (MyWindow)EditorWindow.GetWindow(typeof(MyWindow));
    11.         window.Show();
    12.     }
    13.  
    14.     void OnGUI()
    15.     {
    16.         GUILayout.Label(YesString);
    17.     }
    18. }
    MyWindow.png

    Note:
    • L10n.Tr looks up a dictionary. You should call it outside of your update function like OnGUI.
    • Currently texts in UI Toolkit cannot be localized automatically.
     
    Deleted User, SugoiDev, Mauri and 4 others like this.
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    Are there built-in texts that we can use?
     
  3. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    398
    After loading a VisualElement hierarchy, you can use UQuery to go through all TextElements and apply the translation:
    Code (CSharp):
    1. rootVisualElement.Query<TextElement>().ForEach((e) => e.text = L10n.Tr(e.text));
     
    yuji_unity3d and JoNax97 like this.
  4. yuji_unity3d

    yuji_unity3d

    Unity Technologies

    Joined:
    Oct 30, 2015
    Posts:
    2
    If you don't define
    [assembly: UnityEditor.Localization]
    then the dictionary for the Unity Editor will be used. So you can expect simple expressions like "Yes" or "Open" to be translated. But we don't recommend it because you can't control the content of the dictionary. When you want to see the content, Localization/ja.po in the Unity installed folder is the one.
     
    Peter77 likes this.
  5. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    First, thank you for investing in localization!

    I do have a question though: what is the reasoning behind this design L10n.Tr("Yes") to retrieve "TranslatedYes"? In all localization system that I've personally used, I would input a key e.g. L10n.Tr("GENERIC_POPUP_CONFIRM") and either get "YES" or some other translated text back depending on the language. In the current design, what happens if I change my original text and only fix a typo in my source language? For example Tr("Are You sure?") -> Tr("Are you sure?"), wouldn't this change break the lookup table? Also, if the English translation is used as a key, doesn't that mean I have to maintain this string in two places? Once in my source code (which I wouldn't want to anyway, so I'd rather load this from another file), but also in the lookup table?
     
    Peter77 likes this.
  6. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    This simple dictionary lookup does not work for plurals. There is a whole explanation of plural forms in the gettext manual: https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html

    po files support plurals like this:

    Code (CSharp):
    1.  
    2. #, c-format
    3. msgid "One file removed"
    4. msgid_plural "%d files removed"
    5. msgstr[0] "Un archivo borrado"
    6. msgstr[1] "%d archivos borrados"
    7.  
    For plurals, gettext has the special ngettext function, you could overload the Tr function (or add another method) for plurals like this:

    Code (CSharp):
    1.  
    2. int filesRemoved = 3;
    3. String translated = L10n.Tr("One file removed", "%d files removed",  filesRemoved);
    4.  
    5. // translated ==  "%d archivos borrados"
    6.