Unity: Localization Made Easy

Pudding Entertainment
5 min readFeb 12, 2020

For video tutorial click here

If you are an indie developer or a small studio, localization is something that the most probably you are not going to implement in the initial release of your game. Nevertheless, in order to grow your audience and attract new players having multi-language support is an essential element you will consider doing in the subsequent versions. In this tutorial, I will show a very easy way to do localization for your game without any 3rd party assets.

Prerequisites

I’m going to use Unity 2019.3 but earlier versions will do as well. I’ve used these mechanics in one of my games — Zen Jigsaw — you can see it in action there.

As always, source code is available at GitHub, please, find the link at the end of this article.

The approach described in this tutorial works best for small to medium size games. There are two components required: properties files which hold all in-game texts and language resolver to fill in the required text.

In this tutorial two languages will be used — English and Russian — but the approach is handily extensible to all other supported languages.

Scene setup

Before Unity, I had an experience with another popular game development framework called Libgdx. If you ever worked with it you might find certain similarities in the technique described here. Localization in Libgdx is supported out-of-the-box and implemented in an extremely straightforward manner. I was a bit surprised that Unity is still lacking this must-have feature. Yes, there is 0.4 package available, but it is still in early development stages.

Part 1. Creating properties files

To access properties files from the code we will store them in the Resources folder.

Properties files setup

I call those files “properties” because of the structure, for example English.txt file has the following content:

welcome=Welcome!
long_text=This is a\nvery long\ntext

Each property file will fulfill the contract:

  • Single line consists of two parts — key on the left side of separator and value on the right side
  • Lines are separated by a newline
  • File name corresponds to Unity SystemLanguageenum
  • All properties files have the same keys but different localized values
  • Separator between key and value is ‘=’, you can use any other symbol as well

Part 2. Reading properties files

In order to make use of files prepared earlier let’s create a script that will be responsible for reading the files line by line, collecting all key-value pairs and filling them into Text components:

public class LangResolver : MonoBehaviour
{
private const char Separator = '=';
private readonly Dictionary<string, string> _lang = new Dictionary<string, string>();
private SystemLanguage _language;
private void Awake()
{
DontDestroyOnLoad(gameObject);
ReadProperties();
Debug.Log(_lang.Count);
Debug.Log(_lang.Keys.First());
Debug.Log(_lang.Values.First());
}
private void ReadProperties()
{
_language = Application.systemLanguage;
var file = Resources.Load<TextAsset>(_language.ToString());
if (file == null)
{
file = Resources.Load<TextAsset>(SystemLanguage.English.ToString());
_language = SystemLanguage.English;
}
foreach (var line in file.text.Split('\n'))
{
var prop = line.Split(Separator);
_lang[prop[0]] = prop[1];
}
}
}

Let’s create a new Empty Game Object and attach LangResolver to it.

If you hit the Play button now you will see the following output:

This is the size of the _lang dictionary as well as the first key and value from the English properties file!

It is important to have a default value in case someone runs your game with unsupported language. Usually, English is used but it might vary.

Note! This script is meant to be initialized only once, ideally in the very first scene (usually Splash scene). If you don’t have a scene like that a check for duplicates should be added.

At this point, you might be wondering: where is the language selector on the scene? I left this part of UX out of the tutorial scope deliberately. In modern games language change option is no longer a necessity, relying on System language is perfectly fine. But I have it cover in Advanced Localization tutorial, make sure to check it out!

Part 3. Localization

The next step is to bind keys from properties to Text components. For this purpose let’s create the following helper class:

public class LangText : MonoBehaviour
{
public string Identifier;
}

This script will be attached to every Text component we want to fill in with the text from files. Identifier field is a key from properties.

The last step is to have all texts filled. Let’s add the following public method in LangResolver:

public void ResolveTexts()
{
var allTexts = Resources.FindObjectsOfTypeAll<LangText>();
foreach (var langText in allTexts)
{
var text = langText.GetComponent<Text>();
text.text = Regex.Unescape(_lang[langText.Identifier]);
}
}

Note! Regex.Unescape method is used to properly parse new lines and other possible formatting chars from the properties files.

While you can call this method from within the script itself (from Awake, for example) I prefer to have a dedicated UIResolver class:

public class UIResolver : MonoBehaviour
{
private void Start()
{
FindObjectOfType<LangResolver>().ResolveTexts();
}
}

Part 4. Testing

The tricky part now is to test it with different languages since you would need to adjust your OS system language. I believe you don’t want to do that, so let’s just “simulate” this behavior by changing the first line in the ReadProperties method to _language = SystemLanguage.Russian

If you hit the Play button you will see:

Russian

Don’t worry if you can’t read Cyrillic, the text is a direct translation.

With English by default the result will be:

English

In general, you don’t need to keep any text in the Text component itself, since its text will be replaced anyway. However it might be helpful to understand how the text will look like from a UX point of view, so I would suggest keeping some text in Unity editor, while using properties files as an ultimate source of truth.

Afterwards

Well done finishing the tutorial! Should you have any questions please leave them in the comments section below.

The project source files can be found at this GitHub repository

The game I was referring to can be downloaded here Zen Jigsaw.

Support

If you like the content you read and want to support the author — thank you very much!
Here is my Ethereum wallet for tips:
0xB34C2BcE674104a7ca1ECEbF76d21fE1099132F0

--

--

Pudding Entertainment

Serious software engineer with everlasting passion for GameDev. Dreaming of next big project. https://pudding.pro