This page explains everything on how to translate Allacrost to another language. There is a section for translators, and a section for developers. Neither one has to read the other.
Localization is the act of making programs behave in a region-specific way. When a program formats numbers or dates in a way specific to your part of the world or prints messages (or accepts input) in your native language, the program is said to be localized. This page explains how to localize Allacrost. Doing so will be done with a GNU tool called gettext.
- 1 Gettext Overview
- 2 Translators
- 3 Developers
This section gives a brief overview of how gettext works, and describes three important files needed for gettext to work correctly. Both translators and developers should read this section.
GNU gettext translates strings in a program to a given language automatically, without the user having to do anything. The given language is usually set with environment variables in the user's operating system. Every string in a program that should be translatable must be wrapped in a call to gettext. gettext requires certain files in order to accomplish the translations, and these files are described below.
A PO file is the main file a translator will edit. It contains all the strings in the game needing translation, and their respective translation. PO files have a .po extension and are named with the first two letters of the language's native name. For example, a French language file would be called fr.po and a German file de.po.
A POT file is a PO template file. It is typically named after the package/application it is used in, and ends with the extension .pot. It contains all of the strings extracted from the program that need to be translated, as well as any comments from the developers to the translators about how to translate specific strings. Initial PO files are created from the POT file, and then the PO files are modified further for each language. There is typically only one POT file per package, and it is generated with the xgettext program.
A MO file is a compiled binary form of its corresponding PO file. For example, compiling fr.po will generate fr.mo. It is these MO files that Allacrost will read during execution. As such, they must be located in a specific spot for Allacrost to find them, which will vary depending on the operating system.
|Note: This section is intended for translators only.|
This section describes how to create an initial PO file for your desired language, and what you as a translator need to do to see your new translations in the game.
Commonly Asked Questions
Here are some questions that may be on your mind.
- What do I have to do to make my translations?
- In a nutshell, you have to create and edit a gettext text file and then send it to a developer for inclusion in the project.
- Which tools will I need to have?
- You will need a simple text editor. Or, if you want to get fancy, there are PO file editing tools out there (you will be editing a .po file). PoEdit is an example of such a tool.
- Which files will I need to create or edit?
- You have to create your language's PO file and then edit it. You create it from the allacrost.pot file. Every English string listed in your .po file will have and need a corresponding string in your language.
- Do I need to look at any code files to do my translations?
- No, you do not need to look at any code.
- Will my translation work only if I've translated every single string?
- No, you do not need to translate every string for your translation to work. Any untranslated string will be displayed in English.
- If the original (English) text is updated, is there any way for me to find out so I can update my own translations?
- The easiest way is to just run an hg pull command to update the allacrost.pot file. PoEdit will then merge the updates with your existing translation (or you can do it yourself from the command-line). See this page for more information about Mercurial.
The easiest way to get started on a translation for your desired language is to simply copy the project's POT file (allacrost.pot) to your desired language's PO file (for example, fr.po). The allacrost.pot file is located in Allacrost's Mercurial repository, so if you don't already have it, follow the instructions here. Once you've created your language's PO file, start editing it, either with a simple text editor, or with PoEdit.
Seeing Translations In-Game
This is completely optional, but if you like, you can see your translations in the game as you work on them. There is no need to have a finished translation first. Any untranslated strings in your language's PO file will just show up in the game in English.
In order for the game to know about your new translations, two things have to happen:
- The game needs to be able to find a compiled, binary MO file of your language's PO file.
- Fortunately, PoEdit will automatically create this binary MO file every time you save the PO file. All you have to do is move it to the correct location so the game can find it. This varies per OS:
- Location on Linux: txt/$lang/LC_MESSAGES/allacrost.mo
- Location on OS X: Allacrost.app/Contents/Resources/translations/$lang/LC_MESSAGES/allacrost.mo
- Location on Windows: txt/$lang/LC_MESSAGES/allacrost.mo
- where $lang is the name of the PO file minus the .po extension.
- The startup menu in game that allows you to select a language needs to be modified to list your new language.
- Fortunately, this involves editing only one file: languages.lua located in dat/config/. Just follow the instructions in that file to add your language to it.
You should now be able to see your translations in the game.
Getting Text Updates
Sometimes, the in-game English text gets changed around. These updates can be merged with your existing translation, and you can continue translating quite seamlessly. Of course, some strings you've already translated may need to be updated. gettext will mark these as fuzzy after merging them into your PO file. When you're ready to get the new changes, grab them from the mercurial repository. For more information, go here. Then, with PoEdit, go to the Catalog menu and select Update from POT file. The changes are then merged into your existing PO file.
Once you are ready to have your translation officially included in the project, just send (preferably via email) your language's PO file to any developer, and he or she will commit it into the Mercurial repository.
|Note: This section is intended for developers only.|
This section will describe how to wrap strings in calls to gettext, as well as how to generate the POT file and keep it up-to-date between releases. And for the curious it also explains things going on behind the scenes.
Preparing the code
The source code must be modified to use the GNU gettext calls. Source code here refers to both the C++ code of the game and all Lua scripts. In Allacrost this is done by wrapping strings that the user will see in the Translate function for the C++ code or the hoa_system::Translate function for the Lua scripts. The Translate function is just a wrapper for gettext. For example, if the following string needed to be translated:
cout << "My name is Claudius." << endl;
it would become
cout << Translate("My name is Claudius.") << endl;
Strings as Keys
gettext uses the supplied strings as keys for looking up alternative translations, and will return the original string when no translation is available.
gettext caches previous translation results. When the same translation is requested twice, gettext will, the second time, find the result through a single cache lookup.
It is entirely possible to have the same string in different locations in a source code file. If the string is meant to be translated exactly the same way in both locations, nothing special need be done. The only indication to the translator will be comments above the string they will be translating indicating on what line or lines in the source code file the string is located. The same translation will be returned for both strings, and the translator only has to translate the string once.
It is also possible that those two strings in the code need to be translated differently. This is where gettext contexts come into play. Basically, each string would be passed to gettext with a different context, which differentiates the two strings so gettext treats them as two completely different strings. And that is enough to know for now until the need arises for this capability.
Comments to Translators
It is also useful to note that comments placed directly before strings marked for translation can be made available as hints to translators by helper programs. This is done with a comment symbol immediately followed by the word "TRANSLATORS:". For example,
//TRANSLATORS: Please do not translate Claudius, as it is a proper noun. cout << Translate("My name is Claudius.") << endl;
There is no space between the comment symbol and the word "TRANSLATORS:". This comment will then show up in the POT file just above the string needing translation, so the translator will know what to do with it. Only those strings with special translation needs should have these comments.
|Note: Currently comments only work in the C++ files. xgettext is not able to detect comments in Lua files yet. I suspect it's because it doesn't officially support Lua files, and there doesn't seem to be an argument to it to tell it about a new language.|
Updating the code
During development portions of a source code file will move around, be added to or deleted entirely. This may or may not affect translations, depending of course on how much or little is done to a file.
When strings needing translation are added to the POT and PO files, they are preceded by comments indicating the line number in the file from whence they come. So if a line containing a string needing translating is moved to elsewhere in the file, the POT and PO files will be out-of-date, but only slightly, as the comment indicating the line number will be off. Most translators aren't going to be poking around in the source code looking at these line numbers; if they need additional instructions on how to translate a string then the developer should give them a comment. It doesn't matter much that the line numbers are off, so long as the actual string did not change.
As mentioned earlier, gettext uses the supplied strings as keys for looking up translations. Since the string itself acts as a key, as long as the string doesn't change, gettext will still be able to look up the correct translation, even if the string is now on a different line.
But this is all quite fixable, as explained below in updating the POT file. Now, if the string was modified, or even deleted, or new strings were added to the source code file, then the only remedy is updating the POT file.
Creating and updating the POT file
Once the code has been prepared for gettext, a POT file needs to be created. Initially, no POT file will exist. After it has been created, it will need to be updated periodically to add in new strings and remove obsolete ones. This is done by running the program xgettext, and the instructions for doing so will vary for each operating system.
|Note: Most of the time you will only have to update the POT file, since one has already been created and committed to the Mercurial repository.|
There are two ways to create and update the POT file on Linux. One involves using the GNU Automake system, and one involves using a tool called PoEdit. The GNU Automake method will be explained here for two reasons: one, it is very simple to use, and two, the instructions for using PoEdit are explained below in the Mac OS X section, since it runs on any operating system.
Firstly, one must run configure to generate the appropriate Makefiles. After running configure, go to the directory where all the language files are stored (for Allacrost this is the txt/ directory). There should be a Makefile there.
To initially create the POT file, just run the following command:
|Note: When adding comments to the Lua map files, do not use the apostrophe character or a single double-quote character. xgettext has a bug: in this case it will no longer match the extracted text with the correct line number, causing no translations to occur.|
One may be tempted to think that running the above command could also handle updating the POT file, but this is not the case. If new translatable strings have been added to the game, or old ones deleted, the following command must be run to update the POT file:
|Note: This is the one and only command any developer should ever need to run.|
After running this command, the POT file (in Allacrost's case, allacrost.pot) is updated and ready for the translators. Any existing PO files are also updated with the changes pushed to the translators. This is done via the LINGUAS file. All currently supported languages must be included in this file. Any ambiguous strings are marked as fuzzy, needing special attention from the translators. For the curious, the GNU Automake system is actually invoking xgettext when the make command is run. You can take a look at the Makevars file to see some of the options that are passed to xgettext.
xgettext needs to be told which files to scan for translatable strings so it can add them to the POT file. This is the purpose of the POTFILES.in file. All files containing translatable strings must be listed in this file by their relative path name starting at the project's root directory. (Don't forget to rerun configure if you update this file, as its contents are used by the Makefile.)
Mac OS X
PoEdit is used to create and update the POT file on Mac OS X.
PoEdit is used to create and update the POT file on Windows. The instructions for using it should be similar to those on Mac OS X.
Viewing Translations in-Game
In order to actually use the translations in the game, gettext needs to be able to load the binary MO file generated from the chosen language's PO file. This binary file needs to be in a location where gettext will expect it, and it varies on each operating system. This section explains how to view the translations without actually installing the game.
On Linux, gettext looks for the binary MO files under txt/$lang/LC_MESSAGES/allacrost.mo. If actually installing the game, a simple:
should be enough to generate the binary MO files and put them in the right place.
If you are not yet installing the game, here is the current process to do all this, from within the txt/ directory:
make $lang.mo mkdir $lang mkdir $lang/LC_MESSAGES mv $lang.mo $lang/LC_MESSAGES/allacrost.mo
where $lang is the name of the PO file minus the .po extension.
|Note: There should be a way to get the Makefile to do this for you, but I don't know what it is yet.|
Then all you have to do is select the desired language from the boot mode menu!
Mac OS X
Since only developers should be reading this section, it implies you are using the Allacrost XCode project file. This will handle everything for you already, so you just need to select the specific language from the boot mode menu!
However, for the curious, gettext looks for the binary MO files on the Mac inside the application's Resources folder, Allacrost.app/Contents/Resources/translations/$lang/LC_MESSAGES/allacrost.mo, where $lang is the name of the PO file minus the .po extension.