Translation file format (.po)
Translations are stored in ".po"
files (Portable Object), named with a language code
specific to each language and country. So for example the translations for the Spanish spoken in
Spain would be found in es_ES.po
and for Spanish spoken in Mexico would be found in es_MX.po
.
It is a plain-text filetype, so you can edit it however you choose, but translators often prefer to use purpose-built translation editors (such as Poedit), or web-based translation tools (such as https://translations.launchpad.net).
The format of ".po"
files is a list of entries, with the english phrase to be translated, followed
by the local translation. The english phrase is on the line or lines beginning with msgid
, and the
translated phrase goes on the line or lines beginning with msgstr
.
Before the msgid
line there will be a comment line indicating where in the source code the word or
phrase came from. This can often help when the meaning of the english is not obvious. There may also
be comments left by the developers to make translation easier.
Most entries will look something like this:
#: action.cpp:421
msgid "Construct Terrain"
msgstr "niarreT tcurtsnoC"
The english phrase here is “Construct Terrain”, and it comes from line 421 of the file “action.cpp”. The example translation is just a reversal of the english letters. With this, in stead of “Construct Terrain”, the game will display “niarreT tcurtsnoC”.
Another exmple is:
#: action.cpp:425 defense.cpp:635 defense.cpp:701 npcmove.cpp:2049
msgid "Sleep"
msgstr "pleeS"
This is similar to the last example, except it is a more common phrase. It is used in the files action.cpp, defense.cpp (twice) and npcmove.cpp. The translation will replace every usage.
File Header
The header at the top of the ".po"
file is the only part that differs from the
comment/msgid/msgstr format.
If you are working on an already established translation you will not have to modify it.
For a new translation, it should be mostly set up for you, either by the editor you are using or by
the msginit
program which is the recommended way of initializing a translation (see
TRANSLATING.md).
If you are starting from another translation file however, you might need to change a few things. Just fill it in as best you are able.
The header will look something like:
# French translations for Cataclysm-DDA package.
# Copyright (C) 2013 CleverRaven and Cataclysm-DDA contributors.
# This file is distributed under the same license as the Cataclysm-DDA package.
# Administrator <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: 0.7-git\n"
"Report-Msgid-Bugs-To: http://github.com/CleverRaven/Cataclysm-DDA\n"
"POT-Creation-Date: 2013-08-01 13:44+0800\n"
"PO-Revision-Date: 2013-08-01 14:02+0800\n"
"Last-Translator: YOUR NAME <[email protected]>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
If you are starting a new translation, or you are in charge of the existing translation, it is helpful if you include your name and e-mail address so that you can be contacted with any questions or issues regarding the translation.
The only important part that cannot be easily filled out manually is the Plural-Forms
section. It
determines how different numbers of things are handled in your language. More on that later.
Format strings and newlines
Some strings will have special terms such as %s
, %2$d
and \n
.
\n
represents a linebreak. Mostly these are unnecessary as the code wraps lines where it can, but
sometimes these are used for placing things on different lines. Just use \n
in your translation
wherever a new line should go.
%s
and other similar terms are replaced with something else when the game is running. You might
need to move them around, depending on the translation. It is important that every term beginning
with %
is kept in the translation.
Here is an example which replaces a %d
with a number:
#: addiction.cpp:224
#, c-format
msgid ""
"Strength - %d; Perception - 1; Dexterity - 1;\n"
"Depression and physical pain to some degree. Frequent cravings. Vomiting."
msgstr ""
";1 - ytiretxeD ;1 - noitpecreP ;%d - htgnertS\n"
".gnitimoV .sgnivarc tneuqerF .eerged emos ot niap lacisyhp dna noisserpeD"
Here it is important that the %d
was not reversed, and that the \n
remained at the end of the
line. In this case, %d
will be replaced with the character’s strength modifier when the message is
displayed.
In some cases it might be necessary to change the order of terms. This can confuse the game. If the
order of the %
terms changes, you must add numbers to all of them, so that the game knows which
was which. Some strings will already have these numbers, but some might not.
As an example, if there is a string with %s shoots %s!
, it might change in translation. Perhaps it
will become something like %s is shot by %s!
. But now it is the wrong way around, the shooter has
swapped with the shootee.
In this case, each %s
should be numbered with a digit (1-9) then a dollar sign ($) between the %
and the s
. For example %1$s shoots %2$s!
would be equivalent to %s shoots %s!
. So the example
translation above could be %2$s is shot by %1$s!
, and this would work correctly.
The game can figure out these %1$s
%2$s
parameters automatically, but you must make sure that
(A): all of the %
terms in the translation are numbered; and (B): the numbers are correct in terms
of the original ordering in the english text.
For example:
#: map.cpp:680
#, c-format
msgid "%s loses control of the %s."
msgstr "%2$s eht fo lortnoc sesol %1$s"
would be displayed in-game as kcurt eht fo lortnoc sesol liagibA
, assuming Abigail
was driving a
truck
.
Special tags in strings
Some strings in the translation may have special tags in front of or inside them. These tags should be left as-is, and only the rest of the string translated.
For example, the NPC and city names from “data/raw/names.json” are prefixed with <name>
so as to
avoid conflicts with words (such as Wood
the material, and Wood
the last name). For these, the
<name>
part should be left in.
For example:
#. ~ proper name; gender=female; usage=given
#: lang/json/json_names.py:6
msgid "<name>Abigail"
msgstr "<name>liagibA"
Names also have a comment above them, indicating what the name is used for in-game. In this case,
Abigail
is a possible first name for a female NPC.
Plural forms
Many languages use different terms for things depending on how many of them there are. These are
supported using plural forms, defined by the Plural-Form
line in the ".po"
file header.
For these, there will be multiple msgstr
lines, intended for the different forms depending on
number. The game will automatically choose the correct form depending on the number of things.
For example:
#: melee.cpp:913
#, c-format
msgid "%d enemy hit!"
msgid_plural "%d enemies hit!"
msgstr[0] "!tih ymene %d"
msgstr[1] "!tih seimene %d"
Here the first entry is for when there is only one enemy
, the second is for when there are more
than one enemies
. The rules differ wildly between languages.