Localization: a Winning Solution
Thanks to digital distribution, we now live in a global market and a lot of our potential customers simply don’t speak English. Having your applications localized will increase their global reach and will open new opportunities for your business. You’ll be more likely to find local partners and distributors interested in your products. Supporting more than one language isn’t a complex task once you’ve setup everything and streamlined your development process. Most of Ovogame’s applications are localized in many languages (English, French, German, Spanish, Italian, Russian, Japanese, etc.). It’s well worth it for us as we generate about 45% of our income from non-English-speaking territories. In this article, we’ll give you directions and tips about the technical side of localization. At Ovogame, we are using our own multiplatform engine (Android, iOS, Windows, OSX, BB10). As it is possible to use these techniques on all systems, we’ll stay as platform-neutral as possible.
No Text in Your Code
The best way to handle localization is to think about it from the start of your project. You shouldn’t treat your primary language (English) differently than the other languages supported by your apps. English may be set by default, but that should be the only difference with the other languages.
The golden rule is to NEVER have any text hard-coded inside your source code. Instead, it should all be stored in an external file (like any other data). Supporting different languages means creating different files per language and loading the correct one.
As you can’t have any actual text in your code, the best way is to handle them with keywords. For example, if you want to display a greeting message like, “Hello world,” you could use the keyword GREETING instead. Your code could look like this:
String message = Translate("GREETING"); DisplayText(message);
The function Translate returns the correct sentence to display. If the application language is set to English, it will return, “Hello world,” but if it’s in French, “Salut monde.” The function Translate needs a simple list of keywords linked to their localized sentence. It will scan this list and once the right keyword is reached, it returns the corresponding text. In practice, it’s wise to cache this string; there is no point to call Translate every frame.
Using keywords is very nice because you can still understand their meaning when reading your code. As they are proper strings, you can build some of them dynamically (mainly when they’re indexed: RATING_0, RATING_1 …) to simplify your code.
Using Excel or Open Office
We like to use Excel’s files to store all our localizations and there are many good reasons for this choice. Everyone can view and edit these files, so the persons localizing or proofreading your text will be comfortable with this format. You can add more information (extra columns and lines) and use different colors to help them. It’s also easy to provide links to images (often better than a long speech). Basically, Excel is a very practical tool for creating and managing all your localization.
The other great advantage is that your database is automatically created. The relationship between your keywords and their localizations is obvious: each line contains a keyword and its corresponding translation (stored in two consecutive cells). We need a way to extract this information so you can use it in your application. Excel’s files are complex and coding a function to read such a file format would be a lot of work. Thankfully, we don’t have to do this because it’s easy to convert them into a basic ASCII text file. If you are serious about localization, you should handle text files supporting two bytes per character. If you want to localize in Japanese or Chinese, you must support this anyway. It isn’t mandatory, but it would be a shame to not support it. Simply store your characters in 16 bits instead of 8 bits.
Before converting your Excel file, you might want to do a bit of cleaning first. You should remove all unwanted information and just keep the first two columns (keywords and localizations).
If you are using Microsoft Excel to convert your file, simply save it as a Unicode text (*.txt) file. This new file contains only ASCII characters stored on 16 bits. As the following picture shows, it’s a very simple format. You can use it directly in your application.
Remember that every ASCII character in that file is stored using two bytes (16 bits). The file starts with a magic number (one character: ASCII value 65279) that you can skip. A TAB character (ASCII value 9) is used to separate the keywords from their localization. A carriage return (ASCII value 13 and 10) is used to separate the different lines. As you can see, it isn’t difficult to code a little function to load this file into memory and create a linked list or lookup table of these keyword/localization pairs.
If you are using Open Office instead of Microsoft Excel, you can save your files as Text CSV (.csv) (*.csv) using UNICODE for the ‘character set’ option. The file format isn’t the same as the previous one, but you won’t have difficulties figuring out the differences by yourself.
Selecting the Correct Language
At this stage, you have a specific text file for each of your supported languages. You just need to load the correct one. A nice little feature is to automatically select the language used by the device. So, if the device is set to French, your application could automatically start in French. With most platforms, it’s very simple to find out the language set on your device. For example, with Android, you can simply call a function from your Activity class:
Configuration config=getApplicationContext().getResources().getConfiguration(); String lang = config.locale.getLanguage();
The function getLanguage returns strings like en (English), fr (French), de (German). You should check the value of lang and if you don’t support that language, set it back to your default one (en in our case as we want English to be default). This string will be used to identify the current language during your application life cycle, so keep it safe. You can use these abbreviations (en, fr, de…) to setup a simple naming convention for your files.
With this convention, it’s simple to know which file to load. Also, you can find out dynamically if a language is supported by your application: simply check if the corresponding language file exists. This way, you can add new languages without changing a line of your code. It’s always a good idea to make your code as generic as possible and let the assets handle themselves (data-driven instead of code-driven).
If you are developing your applications for different platforms (iOS, OS X, Windows, etc.), you’ll find similar functions as getLanguage on all systems.
Localizing Other Assets
Sometimes, you need to localize more than just text. You might have textures containing some writing. You should use the same naming convention as before.
To simplify your code, you can dynamically create the names of your localized textures using a simple function:
String name = LocalizeName("gameover", "png");
The function LocalizeName concatenates the current language and the extension (.png in this example). So, if the language is Spanish (es), the name returned will be gameover_es.png.
You might have some assets that need to be localized in some languages but not for all of them. For example, in France, we are comfortable using the Anglicism ‘Game Over’ (translating it would actually sound weird). It would be a shame to duplicate the default asset just to create a fake localized one (gameover_fr.png). Instead, the function LocalizeName could test if the file exists (it’ll need the complete path for that). If the file doesn’t exist, the function should return the name of the default file. For our example, in French, LocalizeName would return gameover_en.png.
Finding the Right People
You should work with native speakers for all your localization. Don’t ever use automatic translation tools (online software) like Babel Fish or Google Translate. The result is so bad that you are better keeping your application in English.
We did find an alternative way to get very motivated translators. We ask our fans if they can do it. These people enjoy our apps and know them almost as well as we do. We develop a much closer relationship with these users than we would ever get from hiring someone via an online service. They are very keen on making the best localization. We send them beta builds so they can test if their localization is perfect. It really feels like they are part of the team.
Give your translators as much detail about your application as possible. If they can test a proper version (like our fans do), it is even better. The more they know about your application, the better they’ll localize it.
Be careful with the size of your UI (buttons, message box, etc.). Most English words are small compared to other languages. Usually, German words are very long and it might be wise to check if they fit in your UI as early as possible. It’s also useful to have a way to auto-scale your text, so you can be certain it will always fit inside a specific area (like a button).
Don’t hesitate to add formatting information inside your text. For example, “Chapter [NUM]” contains the tag [NUM]. We will substitute the proper index in code (Chapter 1, Chapter 2…). It’s very useful because for some languages, the formatting is completely different (in Chinese, it’s in the middle 第[NUM]章). Using this solution will remove most of the formatting problems.
There are many other aspects to be considered when localizing (fonts, testing, etc.), but that would be too long for this article. Hopefully, this quick overview has convinced you that the technical side of localization is accessible to anyone. It’s a simple way to increase the visibility of your application; you should do it.