Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
July 28, 2014
arrowPress Releases
July 28, 2014
PR Newswire
View All
View All     Submit Event





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Localization: a Winning Solution
by Jean-Claude Cottier on 03/10/14 05:52:00 am   Expert Blogs   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

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.

There are many online services where you can hire translators, like dystranslations.com and tethras.com. We haven’t used them, but they were recommended by fellow game developers.

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.

Final Tips

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.


Related Jobs

Integrated Military
Integrated Military — Remote Work Possible, Florida, United States
[07.27.14]

Software Engineer
Cloud Imperium Games
Cloud Imperium Games — Austin, Texas, United States
[07.25.14]

DevOps Engineer
Cloud Imperium Games
Cloud Imperium Games — Austin, Texas, United States
[07.25.14]

Animation Programmer
Cloud Imperium Games
Cloud Imperium Games — Austin, Texas, United States
[07.25.14]

Server/Backend Programmer






Comments


Roger Haagensen
profile image
Could you fill out or mention how the following is handled?:

How do you handle translations where the text is longer, are the buttons tall enough to handle wrapped text in the button?

In fields that has a width does the text wrap?

Does scroll bars appear where text goes out of bounds?

How do you handle Right to Left text?

Do you handle/support mirrored interfaces? (Right to Left languages tend to do this)

How do you handle Top to Bottom languages?


If none of this is handled then you are basically just enforcing English/International language formatting and word length restrictions, and you will end up with clipped text.



Also a note for designer to keep in mind is that one may not need to translate everything.
Fields with text that wraps and has scrollbars can easily handle any word lengths so.

So translating description area or information areas make sense, Unicode supports Right to Left markers so you could have the text almost automatically reverse itself.

Tooltips and similar can also be easily translated.

What one should think twice about when translating are buttons. If buttons have text like ON or OFF then those may not need translation (just their tooltip/description the manual/documentation, and so on), this allows users to search the net and always find results and tips from others on usage.

In some cases you may not need text in the buttons but can use symbols instead.

Myself I'm working on a few projects and there the interface language is English, but some of the projects will have the tooltip/description/documentation/manual fully translatable.
This ensures a consistent and clean and easy to use "International" interface (with no chance of text getting clipped/cut off or forcing the user to scroll bars around to see all the text.

Now if you interface is basically HTML5 with CSS then that is designed for flowing and dynamic text and most if not all the issues of wrapping text and varying lengths of words is no longer an issue.

Jean-Claude Cottier
profile image
So many questions :)

>How do you handle translations where the text is longer, are the buttons tall enough to handle wrapped text in the button?
Basically, my default way to display text is by specifying an area. If the text is too long it will scale down. 99.5% of the time this is fine, we don't notice the difference in scale. For the 0.5% were it is too obvious (read ugly), I have two choices: either I ask the translator if it can reword it to make it shorter or I am updating my UI to make room for the text (widening the button or displaying it with 2 lines like you suggested). In practice, this doesn't happen very often.

>In fields that has a width does the text wrap?
>Does scroll bars appear where text goes out of bounds?
I am using something similar to the button. I try to display a text inside a fix area. I have a function that can cut a text into different segment (at a specified width). I can also give an optional parameter to make sure the maximum amount of line doesn't goes beyond a threshold. Obviously, the function might have to scale down my text. In that case, it does return also the maximum scaling factor that I will apply to each line. This is enough for my need. If I really need to display a big amount of text, I usually prefer to split it in few "talk bubble". If you reference these talk bubbles with an indexed KEYWORD then you can have a different number of bubbles per languages. You just need a way to know if the keyword exist in your database so you can adjust and have different amount of bubble per languages (managed dynamically).

>How do you handle Right to Left text?
>Do you handle/support mirrored interfaces? (Right to Left languages tend to do this)
I don't and to be honest I don't think there are good incentive to support such market. It might be just too much work for not enough ROI.

>How do you handle Top to Bottom languages?
Like 99.99% of western games: I display the text left to right. I guess, those players are used to this.

To resume, I always try to fit my text inside a fix area and for this I have functions that allow me to do it on the fly.

JC

Gary LaRochelle
profile image
Having had to design an interface for a multi-language game, design for German and you'll always have enough room.

Katy Smith
profile image
I learned this lesson the hard way :)

Ron Dippold
profile image
FYI, you left a working URL in one screenshot, and the directory is open... I'm sure I'm not the only one curious enough to try it.

Jean-Claude Cottier
profile image
I've done some cleaning thanks. Not that I mind people checking what was inside :)

Ron Dippold
profile image
Okay, just making sure one of those wasn't 'our entire next game.zip'

Robert Basler
profile image
Localization is tough, here are some other issues to consider if you're making a localization system for your game:

There is the problem where Spain's Spanish is not the same as Mexico's Spanish. I use a country/language system like ESes ESmx ENus or FRca. ISO 3166-1 is a country list. ISO 639-1 is a language list.

If you use replacement strings in your strings like "Weapon: %s %s %u" for "Weapon: Superior Sword 2" you might consider providing parameter indices so they can be rearranged "Weapon: {0} {2} {1}" (Concatenating strings like this is also fraught with peril, so bad example.)

Date, numeric and currency formats are a whole can of fish on their own so be careful there.

Be very careful getting fans to do translation work. Other than the myriad legal issues with volunteer work, make sure you get someone else to check it. There have been many cases of volunteer translators playing jokes.

I wrote a bit about one of my localization experiences here: http://onemanmmo.com/index.php?cmd=newsitem&comment=news.1.63.0

Jean-Claude Cottier
profile image
You are right, there are other issues to consider, and I said it at the end of the post: "There are many other aspects to be considered when localizing". Obviously, the more experience you have with localization, the better you'll be at fixing these problems for your next project.

You also have the same language difference with English (UK-US), colour / color for example. But people will still be able to understand the game. If you can support multiple version (I do time to time) for English, Portuguese, Spanish... then that's great. But the point of the article was to get people starting localizing their apps, 1 Spanish version is better than none obviously.

For formatting, if you check the article, I am using things like: Chapter [NUM] and sometime I have more than 1 keyword to replace but I keep that to a minimum as it might not work in all languages. Sometimes, I have to add more keywords to have different version as some languages like French have genders (but English doesn't). So, I end up with 2 identical sentences in English but in French they are different.

Thomas Happ
profile image
Thanks for the article. I wonder if there are metrics for what happens if you release in English in, say, Europe, where a lot of folks will understand English anyway? Does it hurt your sales? What if you wait until a later patch to localize?

Jean-Claude Cottier
profile image
I don't have such metrics. I don't think it is a problem to localize your app at a later stage. I do that all the time. My apps are all released with English and French on release (I'm French) then I add some languages depending on the success or not of the game. I create apps for the long term, and they do have a very long tail. I don't mind starting marketing an app in a specific country months after release if that game just had been localized recently.

Junxue Li
profile image
Thanks for sharing! There are two things to consider and how you do it:
1. If you are not familiar with all the languages, how do you ensure the quality of each translation, make sure them accurate and flow?
2. Will you check the text on every button, dialog box, etc to make sure they fit in? I've seen enough examples of texts protruding out of the dialog box.

Jean-Claude Cottier
profile image
Yes, I check every sentences for all languages inside the games (button or not). Most of the time, the hidden cheats in my games are only used during those test, so I don't have to spend ages testing all languages.

Peter Lowe
profile image
Great article, a simpler solution to the game over graphic might be to include the entry "game_over_en" in the French asset file and let translate function be unaware of the single resource with two or more entries, and would enable you to have multiple defaults for different language families.


none
 
Comment: