How to support multiple languages in Unity


Together with our Publisher Noodlecake we have decided to translate Shooting Stars in order to boost the reach of the game.  For the initial release we have decided to go with the 7 most common (AppStore) languages English, German, Italian, French, Spanish, Portuguese and Russian.

To implement more than one language without a lot of fuzz, we wanted to find a solution that perfectly fits our workflow.  After a couple of experiments we have decided to create a custom Text component that allows our designer to easily build localized interfaces without the need to write a single line of code. To keep things simple, we are using simple .txt files to store our internationalized strings as key-value pairs. 

For example:

key=This is a test text

So there is a .txt file for every language we support, with same keys and translated values. To prevent lags during gameplay I load the right language file in a static Dictionary on app start. As a fallback I also load the english version in a separate Dictionary in case of a missing key.

Next step was the actual display of the translated text. Therefore I have overridden the built in Text component and added a key field to my new component.

This is how I load the strings from the file into a Dictionary:

private void LoadLanguage(string lang){
    fields.Clear();
    TextAsset textAsset=Resources.Load("I18N/"+lang);
    string allTexts="";
    if(textAsset==null){
        textAsset=Resources.Load("I18N/en");
    }
    allTexts=textAsset.text;
    string[] lines=allTexts.Split(new string[] { "\r\n", "\n" },
        StringSplitOptions.None);
    string key, value;
    for(int i=0;i < lines.Length;i++){
        if(lines[i].IndexOf("=") >= 0 && !lines[i].StartsWith("#")){
            key=lines[i].Substring(0, lines[i].IndexOf("="));
            value=lines[i].Substring(lines[i].IndexOf("=")+1,
                    lines[i].Length-lines[i].IndexOf("=")-1).Replace("\\n", Environment.NewLine);
            fields.Add(key, value);
        }
    }
}
    

The custom Text component:

public class TextI18N : Text {

    public string i18NKey;

    void Awake(){
        Refresh();
    }

    public void Refresh(){
        text=I18N.Instance.Get(i18NKey, false);
    }
}

UPDATE

After posting this tutorial on reddit, the user justaghostofanother wrote a super detailed do's and don'ts about localization which can be found in the /r/unity3d thread.

4 Comments

Alexander Haider

Even though Alex may be the quiet one but his godlike development skills will render you speechless for quite a while. Some people say: Wherever there's a problem there's an Alex to fix it.