Table of Contents

Translation Process

Thank you for taking an interest in open source development! Translating singapore is a matter of editing a single file and then running a script on it. What could be simpler?

Language strings are stored in standard GNU Gettext PO (portable object) files which means you can (at least in theory) use all currently available PO editors such as poEdit to make your translations.

For added convenience strings for each language are split into two sections: one for normal gallery operation and another for strings that are only used in admin mode. This means that admin strings are not needlessly loaded for every page and also that translators have the choice of only translating the standard strings or going the whole way and translating the admin strings too.

It is a good idea for all translators and potential translators to join the development mailing list. Use this, the internationalisation forum and the translations tracker to interact with other translators and developers.

The reason for the “in theory” is that many PO editors do not support the plural forms that singapore makes use of - even though they are defined and supported by GNU Gettext. poEdit does support plural forms since v1.3 and is highly recommended. Alternatively it is just as easy to use a standard text editor to make your translations.

Requirements

No further software is required for using the multilanguage capabilities of singapore. However the extract and merge tools use xgettext and msgmerge respectively. Both these programs are part of GNU Gettext which is already installed on most Linux distributions. A package of the relevant gettext binaries for Windows is available here: http://singapore.sourceforge.net/binaries/singapore-gettext-Win32.zip. The path to xgettext is stored in tools/extract.php and the path to msgmerge is stored in tools/merge.php. However if the gettext programs are in your PATH or in the tools/ directory itself then you do not need to edit anything.

Updating a translation

Each singapore release requires the language files to be updated slightly. First make sure you have the latest available translation (the translations tracker is a good place to check for this). Now you need to merge in the new untranslated strings and remove the obsolete ones (this may have already been done but there's no harm in doing it again). Place the old PO file in the locale directory of an installation of the latest version of singapore and use the merge script provided in the tools directory.

Now proceed translating the strings as described below. Finally, attach the updated PO file to the appropriate tracker item making sure to state which version of singapore it is for.

Starting a new translation

The very first thing to do is submit a tracker item on the translations tracker to inform people of your intentions so that two or more people do not needlessly spend time translating the same files for the same language. Once you have completed your translations you can attach the files to the tracker item.

All language files are kept in a single directory (locale/ by default). They are named as follows:

where LANG represents the ISO639 language code of the chosen language (e.g. de for German, en for English, en-gb for English (United Kingdom)). A more comprehensive list of language codes may be found here: http://www.rickbull.co.uk/tutorials/HTML/Useful%20Information/language_codes.php

Start by copying a PO template file (singapore.pot if you are translating the standard strings or singapore.admin.pot if you are translating the admin strings) and naming it appropriately for your language as described above. Now open the file in your chosen PO editor or a plain text editor and set about translating the strings.

You also need to fill in certain parts of the PO file header. You may do this at any stage of the translation.

NOTES:

  1. Strings in the form “crumb line|You are here:“
    In these cases the text up to and including the vertical bar, |, should NOT be included in the translation. They are simply hints for the translator.
  2. Strings in the form “Showing %s-%s of %s”
    In these cases each %s will be replaced at runtime by a number or string in order from left to right according to the rules of printf(). Essentially each %s is a placeholder and so needs to be present at the appropriate place in the translated string.
    However some languages may require the order of the arguments to be changed. For example if instead of “Showing 1-10 of 15” you want to say “Out of 15 objects 1-10 are shown” then you must use the argument swapping syntax of printf(). More details on this may be found here: http://www.php.net/sprintf
  3. Strings with plurals
    You must correctly specify the Plural-forms header field in order to make use of plural forms. Put each plural in its own msgstr[x] where x is a number between 0 (inclusive) and the nplurals number you specified in the header (see examples below).
  4. Using a text-editor
    When translating an entry you must leave the English language strings (those on lines starting msgid) untouched and insert the translated strings between the double-quotes on the following lines (those starting msgstr or msgstr[x] in the case of plurals).
  5. Obsolete entries
    When updating a PO file, obsolete entries (i.e. those strings which appeared in the previous version but do not in the current version) are placed at the end of the PO file and prepended by #~. There is no need to translate these entries as they are ignored by the compiler.

Once you have translated all the strings and filled in the header, you need to compile the PO file into a PHP serialized object file for use with singapore. Do this using the compile script provided in the tools/ directory of the singapore distribution.

And that's it!

Now go and attach your translated PO file(s) to the tracker item you created before starting the translation so that everyone else can make use of it.

Examples

The following string

# File: ../includes/singapore.class.php, line: 247
#, c-format
msgid “Page created in %s seconds”
msgstr ””

when translated into French becomes

# File: ../includes/singapore.class.php, line: 247
#, c-format
msgid “Page created in %s seconds”
msgstr “Page créée en %s secondes”

and the following string

# File: ../includes/admin.class.php, line: 173
msgid “admin bar|Edit image”
msgstr “”

when translated into Italian becomes

# File: ../includes/admin.class.php, line: 173
msgid “admin bar|Edit image”
msgstr “Modifica l'immagine”

and the following string

# File: ../includes/singapore.class.php, line: 530
#, c-format
msgid “%s gallery”
msgid_plural “%s galleries”
msgstr[0] “”

when translated into Spanish becomes

# File: ../includes/singapore.class.php, line: 530
#, c-format
msgid “%s gallery”
msgid_plural “%s galleries”
msgstr[0] “%s galería”
msgstr[1] “%s galerías”

Filling in the header section

NOTE: This section is mainly copied from the section 5.2 of the GNU Gettext manual.

The initial comments “SOME DESCRIPTIVE TITLE”, “YEAR” and “FIRST AUTHOR <EMAIL@ADDRESS>, YEAR” ought to be replaced by sensible information.

The following fields must be filled in correctly:

Content-Type

Replace ISO-8859-1 with the character encoding used for your language, in your locale, or UTF-8. This field is needed for correct operation of the msgmerge program, as well as for users whose locale's character encoding differs from yours.

The following encodings are frequently used for the corresponding languages.

The character encoding name can be written in either upper or lower case. Usually upper case is preferred.

Plural-Forms

See the plural forms section.

The following fields should be filled in:

Project-Id-Version

This is the name and version of the package.

Last-Translator

Fill in your name and email address (without double quotes).

Language-Team

Fill in the English name of the language followed by the native name of the language in brackets. E.g. “Language-Team: German (Deutsch)\n”
Note this is different from the GNU specification but is required in order for the language flipper function to work.

The following fields may be left alone:

POT-Creation-Date

This has already been filled in by xgettext.

PO-Revision-Date

You don't need to fill this in. It should be filled by the editor when you save the file.

Content-Transfer-Encoding

Set this to 8bit.

Plural forms

NOTE: This section is mainly copied from the section 10.2.5 of the GNU Gettext manual.

The Plural-forms field in the PO header is used to calculate which plural form of a word to use. In English there are only two plural forms but other languages have only one or as many as four.

Please check the list below to see if your language is listed. If it is then use the corresponding string. If not then you can either write it yourself (details below and in the gettext manual) or email a member of the team describing how your langauge works (e.g. (not real) 0 car, 1-2 cars, 3 caren, 5+ carii) and we will write one for you.

Only one form:

Some languages only require one single form. There is no distinction between the singular and plural form. An appropriate header entry would look like this:

Plural-Forms: nplurals=1; plural=0;

Languages with this property include:

Finno-Ugric family

Hungarian

Asian family

Japanese, Korean

Turkic/Altaic family

Turkish

Two forms, singular used for one only

This is the form used in most existing programs since it is what English is using. A header entry would look like this:

Plural-Forms: nplurals=2; plural=n==1 ? 0 : 1;

Languages with this property include:

Germanic family

Danish, Dutch, English, German, Norwegian, Swedish

Finno-Ugric family

Estonian, Finnish

Latin/Greek family

Greek

Semitic family

Hebrew

Romanic family

Italian, Portuguese, Spanish

Artificial

Esperanto

Two forms, singular used for zero and one

Exceptional case in the language family. The header entry would be:

Plural-Forms: nplurals=2; plural=n>1;

Languages with this property include:

Romanic family

French, Brazilian Portuguese

Three forms, special case for zero

The header entry would be:

Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;

Languages with this property include:

Baltic family

Latvian

Three forms, special cases for one and two

The header entry would be:

Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;

Languages with this property include:

Celtic

Gaeilge (Irish)

Three forms, special case for numbers ending in 1[2-9]

The header entry would look like this:

Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;

Languages with this property include:

Baltic family

Lithuanian

Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]

The header entry would look like this:

Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;

Languages with this property include:

Slavic family

Croatian, Czech, Russian, Slovak, Ukrainian

Three forms, special case for one and some numbers ending in 2, 3, or 4

The header entry would look like this:

Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;

Languages with this property include:

Slavic family

Polish

Four forms, special case for one and all numbers ending in 02, 03, or 04

The header entry would look like this:

Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;

Languages with this property include:

Slavic family

Slovenian

How the Plural-forms header works:

The nplurals value must be a decimal number which specifies how many different plural forms exist for this language. The string following plural is an expression which is using the C language syntax. Exceptions are that no negative numbers are allowed, numbers must be decimal, and the only variable allowed is n. This expression will be evaluated whenever one of the plural functions is called. The numeric value passed to these functions is then substituted for all uses of the variable n in the expression. The resulting value then must be greater or equal to zero and smaller than the value given as the value of nplurals.