# Working with multiple language text files in multilingual games

What kind of tools and practices are used for maintaining text for multilingual games? By "text" I mean literally any piece of text you see in the game: dialog, menu options, tutorials, etc.

I want to keep it as modular as possible and make it very easy to add new language options by simply providing a new set of files.

Are there publicly available tools that I can use to maintain these text files and, preferably, pass it to others that can perform the translation process and allow them to put together all of the input data without me having to hardcode anything into the game?

• Mozilla addons have a language folder with subfolders like en-US and de-DE with all the text files in it. It's easy to provide a manager that will manage from which folder it reads the strings. – Appleshell Jan 3 '14 at 1:30
• How about i18n (internationalization)? Do you need to account for different word forms used with numerals? Cos some languages might have 3-4 word forms for words next to numbers 1..12 – Kromster Mar 4 '14 at 4:38

As always, there are lots of ways to achieve what you want. However, unlike other applications, games have very specific requirements, so what works best for other programs may not be best for a specific game.

Remember that localization is a very complicated matter. It's not just about translating words and meanings. There are lots of subtle meanings in whatever texts you have, cultural issues to remember, and even technical matters such as textbox size (a text may fit on the screen when written in English, but can overflow when written in Finnish).

Most European languages (English being a notable exception) use diacritics, accent marks and glyphs unique to them. Other languages use other scripts (like Greek or Russian). Others use different writing systems (Arabic and Hebrew read from right to left, and Japanese can be written from top to bottom). Do you have all the fonts required to support all those languages? Specifically logo like texts are very susceptible to text length problems, so be careful, and optimally plan for localization from the beginning.

Because of this, in my opinion, simple is best. I prefer to use the simplest solution that works for my interests. Here are some ways to localize a game.

### Hardcoding

If your game has very few (less than 100) strings, and you're not considering on updating it, or if you just have very few languages, it is very possible to just say

if language is french then
display("bonjour")
else
display("hello")
end


Doing stuff like this just works, and if it works for you, you probably don't need anything fancier. Also, you can do more sophisticated things, like reducing or increasing the amount of texts depending on the language. If possible, try to consider localizing like this.

### Parameter hardcoding

This is pretty much the same, but I've seen it more in the scripts a game uses, instead of the main program. The idea is that every function you make that can be localized, you take each possible language as an argument, like so:

function print(text_en, text_fr)
if language is french then
display(text_fr)
else
display(text_en)
end
end


and then

print("hello", "bonjour")


This is very common in the scripts a game uses, and the best thing about it is that it maintains the context of each string, which allows for higher quality translations than just isolated strings, and if possible should be considered.

### Automatic replacement

Especially when making translations after an initial game has been shipped, it is possible to add a very thin translation layer in every text related function, that takes the original text, looks it up in a translation table, and replaces it if a match is found.

function translate(text)
if language is french then
if text == "hello" then
return "bonjour" -- replace with a hashtable for faster lookups
end
else
return text
end
end

function print(text)
text = translate(text)
display(text)
end


This allows you to add translations to an already finished game with minimal impact on the original already functioning code. I rarely see it used before a game is finished, because if the original text changes, you also need to change the lookup key. But it works, and if you have good lookup tables, it can be quite fast.

### String resources

This is very common in application development. The idea is that you have a resource file which defines a bunch of constants like:

...
strings["en"][1044] = "hello"
strings["fr"][1044] = "bonjour"
...


and whenever you want to print the localized text, you go like

function print(id)
if language is french then
display(strings["fr"][id])
else
display(strings["en"][id])
end
end


There are thousands of variations of this. You can have a file for each language, a file for each module; you can store them in source files, xml files, json files, csv files, binary files; you can import them from excel, word, a proprietary tool, etc.

The obvious advantage of this is that programmers love it. Keeping program and data separate is the dream of every programmer, and it pretty much works. However, keep in mind that as the amount of strings increases, the amount of ID vastly increases, and a string ID has no semantic information attached to it, so it is very easy to make mistakes.

Also, it is very common for developers to try to avoid string duplication by encoding common strings like "yes" and "no" only once. However, in some languages, the words used for those common words are different depending on the context. For example, if you're asked "don't you want coffee?", and you answer "no", in Japanese it means "yes, I want coffee" (a double negative), while in Spanish it means "no, I don't want coffee". Because of this, it is very common for developers to encode each string in a different ID, even if that means you end up with hundreds of "yes"es in your string file.

Since moving strings to a separate file and attaching meaningless IDs to them loses the context of the phrases, you may need to have a much more thorough language testing effort. Be careful with this technique.

### Language agnosticism

This is not location related, but many games give up on this, and make the game understandable with drawings and other gimmicks that don't require written words. It definitely makes interesting games, and doesn't require any kind of translations. Remember cultural differences though (some colors have different meanings on some cultures, and some hand gestures may be okay in one culture, while offensive in another)/

Just one last thing you might find useful. This is a very comprehensive list of languages (actually "cultures"), with predefined codes for each of them that you may use in your program.

I'm not sure if there is a game-specific translation framework but I've used gettext system for handling translations in WordPress. Here's the WP page describing their translation process along with a list of tools. The gist is that you create a template file that you in turn use to create translations. The final step is producing a binary, machine optimized file that is used in the actual application.

I've used Poedit (runs on Windows, Mac and Linux) to edit translations for WP and found the experience to be fairly nice.

It looks like Python supports gettext out of the box so it should be relatively simple to get gettext up and running in your game.

This is how I usually add multi-language support to my applications.

Presume u have a list of words/expressions u are using in your game, list them in file(in english). Then add the translation of the required language and make such a file for every language.

Default/English language file the only weird file because the key(left word )and translation value(right word) are an exact match.

• new game = new game
• settings = settings
• won = won
• lost = lost ...

Dutch language file

• new game = nieuw spel
• settings = instellingen
• won = gewonnen
• lost = verloren ...

When your game is starting, you just read all the language files and store them into a global defined string matrix. In this matrix the first dimension of the matrix is the language the second dimension is the string u need.

English is first dimension 0

• String[0][1] = new game
• String[0][2] = settings

Dutch is first dimension 1

• matrix[1][1] = nieuw spel
• matrix[1][2] = instellingen

Now u need to declare a global variable that keeps an integer named LANGUAGE. In your code u can now refer to this variable to get the language u need.

• matrix[LANGUAGE][1] will give 'new game' if LANGUAGE = 0(english)
• matrix[LANGUAGE][1] will give 'nieuw spel' if LANGUAGE = 1(dutch)

If you use this language matrix all over your code, u can simply change the language of your game by changing the LANGUAGE global variable.

If u want to add a language u simply add another file that contains all the translations for that language. Because your game will load all these language files into the language matrix, the new language will become available when u restart the game.

p.s. sorry if the layout is not that good =P

What are you coding in?

.NET has satellite assemblies which can be loaded automatically by setting the UiCulture on the current thread. An easy cross-language way of doing it would be XML files with a key-value pair for each element of text you need.

• I'm using the Pygame framework, and it seems that I can arbitrarily change text anytime I want, so I could just flip a switch from one language to another and just pull data from a separate set of localization files. I'm not sure if I should look at how the problem is solved "in general" before I look at platform-specific solutions. – Hime Dec 3 '13 at 21:17

Could store your strings in an excel spreadsheet like so and export as .csv for easy reading\parsing. Easy to edit and update and where you currently hard code your string you look up the string using the string id instead to find the corresponding string for that language. Could load them all in memory if its a small amount of text or feasible for your app/platform. You will need to write some code to manage this but should be straight forward, if you need some more help feel free to post. Ill happily post more specifics.

StringID English French

Title_screen English_Foo1 French_foo1

Java also has a nice infrastructure for handling this with property files : http://docs.oracle.com/javase/tutorial/i18n/intro/steps.html