Hi, this will be the first of my tutorial section where I will address a number of topics around the development of games in Unity3D. First off the bat though, let me just say that I am a self-taught indie dev, I havent worked in a big game studio, so this is just me sharing the ways that I have found to get around certain things that have come up in my development of my own games. It may not necessarily be the correct or best practise method, but it works for me, and if it works for you too, then that’s awesome! So, today’s topic is localisation. This is something that seems to be often overlooked in games either entirely, or thrown in at the last minute and then requires a lot of rework to integrate. I wanted to make sure that I could localise Xenomorph right off the bat, so this is the approach that I took to it.
Ok, so there were a few considerations that I wanted make sure that I fully covered in my approach.
- It had to be simple to implement and easy to expand upon
- It must be able to automatically change all the text in the game (interface, dialog, menus etc)
- It must be easy to add new languages
- It must support changing of art assets (signposts, directions, any written text etc)
- It must be in a format easy to have translated
So with that in mind, this is how I decided to approach it.
I figured the easiest way to achieve the above is to store the actual text in a simple text file, that way I can just send the text file to a translator and they can send me back the translated file, simples. This approach does however have one very serious limitation. It relies on you referencing the text you want from a specific line number. For example, Line 10 in your text file might be “Quit Game”. If someone changes the line numbering by inserting a line somewhere in the file or a simple carriage return, then this will throw out your whole system. As its only me developing my games, I have good attention to detail and discipline, so I am not worried about that 😉 I am however concerned that a translator may muck up the lines, so that is something for me to bear in mind, or adapt the system to be able to cope with that in the future. So my text and art assets will be developed in the following way: Text: Have a number of text files that relate to whatever text is needed in game. I went with individual text files for Dialog, Menu’s and UI (interface). That way when developing the game I can just append new lines to the text file in a logical way, rather than it all dumped as a mess in one file. You can use as many or as little files as you want, that is up to you. Art: My game is a 2D game that use a sprite atlas for each level. This means that I can create seperate Atlases for each language. I actually maintain a photoshop layered file that has the base texture atlas, and I add each language as a seperate layer that can be switched on and off.
Ok, now we have the approach and decided what to make, here is how I actually developed it. Firstly, we need a language manager script, and this should be persistent across the whole game ideally. This script is going to let the game know which language we are currently using. This is nice and simple, and I use an enum to create the languages I want.
Ok, there you can see that we just set a simple enum up and then make a public reference to it, so that we can set the language in the inspector within Unity. So lets look at setting up text first, we will come back to graphics later on. In order to setup a system for reading text, we need to do the following:
- Create our default text files, these will be in English for me.
- Create a TextAsset to load these files into Unity from our Resources folder. Important, the text assets will be stored in the Resources folders, I went with /Resources/Languages/
- Check which language we are currently using, and load the corresponding file
- Create a public method to read from that file wherever we need text in our game.
Lets setup what we need: First we need a string that tells us the name of the file for each language we have:
In the inspector, you can now simply give the name of your text file (without the .txt extension, it doesnt need it in Unity). So for example, if your filename was called “English_Dialog.txt” then you would enter English_Dialog into the inspector in Unity. You get the idea… Then we need to setup a way of reading those files into Unity, and for that I am using a StreamReader which you need to use a scecific namespace for
This allows you to read the text from the files in your resources folder. Now we need to create something to load them into, and for that we will use Unity TextAssets. Again, we need to create a reference to them and then load the text into them.
Ok, that loads our text from file into the Asset, but now we need to read it into a string array so that we can read the text anywhere from our game. I went with an array, because then you can split the text file out line by line into an array, then simply call the line number of the file from the array and it returns the text you want.
As you can see, this basically takes the text file, splits it line by line and then saves it into our final text array dialogLines. No whenever you want to ready localised text into your game, simply use a nice simple method like this:
You have to minus 1 from the line you want to read becuase arrays start from 0, the text file will start from line 1. So in order to put this all together now as a coherent script, here is my Language manager that caters for 4 different files I want, Dialog, Menus, Messages and Interface. It also allows me to use English, French, German, Spanish, Russian and Italian. All I have to do is create the following text files:
I place those in my Resources/Language folder and then I can just send those files for translation, and rename them as needed for each language. Here is my completed script that gives me public methods to read from each file individually:
There you go, so in closing if my Messages_Engligh.txt looks like this:
And I ran this code anywhere in my game :
It would return “Access Granted” I hope that makes sense! So now lets move on to the next part.
Ok, localising artwork is also relatively simple when you have things setup in a simple way. My levels use a single tileset for the floors (its a top down game) and therefore, any text is likely to be written there. Here is a screenshot as an example. What I needed to do, was create seperate PNG files for each language, and load them in seperately as I load the level, based on the language chosen. First off, I create a LevelManager script and set the following variables.
Once done, simply give the name of the PNG tilesets in the inspector on the LevelManager. One again, you do not need to give the extension, so for example it might be… Level1_Tileset_English Now, we just need to first get the language we are currently using, then get a reference to the material used for the floor tiles and swap out the tileset based on the language. For this, I call the following method during the Awake() function when loading a level.
Simplifying the code
Ok, we have our code but its a little too wet, and could certainly be simplified. Rather than using an if statement for each different language, lets just setup a simple set of strings to use as the file prefix, and then pull the language in from the enum instead. Lets say for example that our dialog file is called English_Dialog, French_Dialog, Spanish_Dialog… instead of using if statements, lets just use one line of code to read the file based on the language.
Now you can see that we simply create a standard prefix string, pass in the underscore and then the language as a string. We can now simplify our final code to this:
And the same with the tileset script:
And thats it really, simply call that function when loading the level and there you have it, localised text and images. I hope this has been useful to someone, like I said, its a very simple approach that problably only suits an indie dev, but it certainly does work. Thanks for reading 🙂