Horde Documentation

Translation Guide

Date: 2009-01-31
Revision: 1.29.4.7
Authors: Jan Schneider
Contact: i18n@lists.horde.org

1   Translation Tool

translation.php is a small PHP script that should help translators doing their work.

Any feedback, bug reports and feature requests should be send to the i18n mailing list. This is also the right place for new translations and general discussions of i18n and l10n questions and problems.

translation.php is located in horde/po, so you will have to make horde/po your working directory in order to run the commands quoted below. But you can run the script from any directory, just adapt the directory to the script. See _Prerequisites if your PHP binary is not located in /usr/bin/php.

For a list of available commands run:

./translation.php help

For detailed help on a certain command run:

./translation.php help command

Additional information about creating translations and fixing problems can be found in the file horde/docs/TRANSLATION.

1.1   Prerequisites

To run this script you'll need a PHP command line executable with gettext support compiled in, and the basic PEAR libraries. The script expects your PHP executable to be at /usr/bin/php. If your executable is at another place, either edit the first line of translation.php to reflect your location or call the script like:

/usr/local/bin/php translation.php.

You'll need the gettext package version 0.12 or greater.

You'll need the PEAR packages Console_Getopt 0.11 or greater, Console_Table and File_Find. To install all needed packages, run:

pear upgrade PEAR Console_Getopt
pear install Console_Table File_Find

or download the newest package from the PEAR server and install them manually in your PEAR directory.

1.2   Creating a new translation

To create a new translation you first have to extract all gettext messages from the PHP sources. There are already template files with the .pot suffix in the po directories that you can use if you have troubles extracting the messages, though these templates might be slightly outdated. Run:

./translation.php extract

You now have to create a new PO file for your locale. A locale has the form ll_CC where ll is the two letter ISO 639 code of the language and CC the two letter ISO 3166 code of the country, e.g. de_DE, en_US or pt_BR. translation.php is able to guess the locale from the LANG environment variable but it is safer to specify the locale with the -l parameter. To create the PO file run:

./translation.php init -l ll_CC

Now you can start the translation by editing the created ll_CC.po files. It is important to set the correct charset for the locale in the Content-Type: header. You should fill out the the complete header of the created ll_CC.po file, e.g.:

# Dutch translation for Horde.
# Copyright 2004-2009 The Horde Project (http://www.horde.org/)
# This file is distributed under the same license as the Horde package.
# Joris Braakman <jbraakman@yahoo.com>, 2004.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde 2.3\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2004-04-14 10:30+0200\n"
"PO-Revision-Date: 2004-04-14 17:17+02:00\n"
"Last-Translator: Joris Braakman <jbraakman@yahoo.com>\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8-bit\n"

To compile the translations to a binary format run:

./translation.php make -l ll_CC

After you created the new translation you have to add entries for this locale in the configuration file horde/config/nls.php.

If you create a new translation for a certain module but there are already translations for the same language for other modules, then you should use a compendium. This will save you a lot of time and it will make translations much more consistent.

1.3   Compendiums

This tool utilizes a nice feature of gettext: compendium files. A compendium is a special PO file containing a set of translations recurring in many different packages. These compendiums will be used in the background without much intervention required. But you have to create and edit a compendium before you can use it.

To create a compendium of all existing translations for a certain locale run:

./translation.php compendium -l ll_CC

The compendium.po being created will contain all modules' translations of this locale merged into a single file. You should take a closer look at this file because you may find a lot of special marked lines where you translated certain strings differently in the various modules. It's a good idea to fix the modules' translations now so that all modules use the same translations for the same strings. You can always recreate your compendium with the above command.

If you're maintaining translations for different branches and assumed that you have all modules of the HEAD branches in one directory and all of the FRAMEWORK_3 branches in another, you probably want to share a compendium between these directories.

To do this, you should first create a compendium in the FRAMEWORK_3 branch, review it and fix all translations until you're happy with the results. Then create a second compendium in the HEAD branch and include your first one with the --add option. Now fix the translations in this branch. If you're ready you can remove the first compendium and for now on use the compendium in the HEAD branch for both branches. To do so, use the -c or --compendium option to specify a path to your compendium.

1.4   Updating translations

The process of updating translations is a cycle where you extract new gettext strings from the sources, translate those new strings or update the already translated strings and compile them after.

To update the translation for a module, run:

./translation.php update -m modulename -l ll_CC

This extracts the new strings from the sources and tries to update them from already existing translations in the compendium. You just have to translate all untranslated strings in the ll_CC.po file in the po directory of the module you updated.

If extracting new strings fails for some reason, you can use the provided .pot file to update your translation:

./translation.php merge -m modulename -l ll_CC

If your compendium is in a different directory than the translation.php script, you can specify the path to the compendium:

./translation.php update -m modulename -l ll_CC -c /path/to/compendium

Once this is done, you can compile the translation by calling:

./translation.php make -m modulename -l ll_CC

1.5   Extending existent translations

To have your own string (e.g. that you added to config files) displayed in several languages, you have to

  1. specify your texts as gettext arguments, in English,
  2. edit the translation files for the required national languages,
  3. compile those translation files.

Be sure to keep records of your extensions, as you will probably have to repeat steps 2 and 3 after the next update.

E.g., you plan to offer two IMAP servers to select from in the Webmail login screen:

  1. In horde/imp/config/servers.php, you specify:

    $servers['Central'] = array(
       'name' => _("Central Mail Service"),
    ...
    $servers['CompSci'] = array(
       'name' => _("Mail Service of Computer Science Dpt.")
    ...
    
  2. In horde/imp/po/de_DE.po you add two entries:

    msgid "Central Mail Service"
    msgstr "Zentraler Mailserver"
    
    msgid "Mail Service of Computer Science Dpt."
    msgstr "Mailserver Informatik"
    

    Likewise, you amend the translation files for other languages, as needed.

  3. You compile the translations using the commands:

    ./po/translation.php make --module imp --no-compendium
    

2   Access Keys

Access keys, also known as shortcut keys, allow easy access to important functions, normally by hitting the Alt/Meta key in combination with another key. This key is marked in most user interfaces by being underlined.

As the access key is part of the word representing the action being executed, it is in the translators responsibility to select an access key when he translates these words. The action is always a link in Horde. The access key of a link is selected by prefixing it with an underscore.

The help link in the menu for example is always "_Help". This means that the "H" of the link will be underlined and the help can be opened by hitting Alt+H. In the PO file this string will appear as:

#: templates/menu/menu.inc:53
msgid "_Help"
msgstr ""

A Spanish translator might want to translate this to:

#: templates/menu/menu.inc:53
msgid "_Help"
msgstr "_Ayuda"

Translators of multibyte languages need to do this a bit differently as only ASCII characters are allowed for access keys. A Traditional Chinese translator might want to use:

#: templates/menu/menu.inc:53
msgid "_Help"
msgstr "_H說明"

This renders to "說明(H)" in the interface and you can access this link with "H" as the access key.

3   Right-to-Left Languages

Translations for languages that are written from right to left might cause unexpected behavior if parenthesis or similar characters appear inside a translated string. To fix this broken string rendering you have to insert special Unicode codepoints into the translated string.

Before such a string in parenthesis, add the U+202D codepoint. If there is more right-to-left text to come after the closing parenthesis, add the U+202E codepoint after it. If using the PO mode of the Emacs editor you can add codepoints with the "ucs-insert" command.

4   Help Texts

4.1   Organization of the help files

The help texts are available in the horde/locale/, and horde/APP/locale/, directories, where APP is any Horde application. Every available translation is kept in a file called help.xml, in a subdirectory named according to RFC 3066. Examples:

  • Horde's original help texts are in the horde/locale/en_US/help.xml file.
  • IMP's Brazilian help texts are in the horde/imp/locale/pt_BR/help.xml file.

When, for any desired application and locale, there is no help.xml file available, Horde's help system will use the application's locale/en_US/help.xml file, instead.

The help files must be encoded in the language's preferred character set.

There is no compilation step involved: Every modification to, or addition of, a help.xml file takes immediate effect.

4.2   Syntax of the help files

Each help file must consist of syntactically valid XML code.

There are no predefined entities beyond the XML standard entities:

  • &lt; (less than)
  • &gt; (greater than)
  • &amp; (ampersand)
  • &apos; (ASCII apostrophe)
  • &quot; (ASCII quotation mark)

Any character available in the language's preferred character set can be entered as a numerical character reference (based on its Unicode scalar value), such as &#160; for the No-Break Space character.

The general structure can be learned from the existing examples; of course, the XML tags must be syntactically valid, and properly nested.

Note

A PHP error message like Undefined index: url in /opt/test-webmail/horde/lib/Horde/Help.php means that you have mis-spelled, or omitted, an attribute (url, in this example).

The following tags are available:

XML-Tag Parent Attributes Purpose
help List of help texts
entry help id Help text
title entry Entry in the help index
heading entry Level 2 heading
para entry Paragraph
ref para module, entry Link into the help system
eref para url External link
href para app, url Link into a Horde application
b para Bold text
i para Italic text on new line
pre entry Example box
tip entry Tip/hint box
warn entry Warning box

The elements marked para, in the Parent column, may also be used within pre, tip, and warn elements.

The following attributes are available:

XML-Tag Attribute Purpose/Syntax
entry id Anchor
ref module Index of Horde application, see horde/config/registry.php
entry Id of help file entry, see above
eref url arbitrary URL
href app Index of Horde application, see horde/config/registry.php
url URL within Horde application

Examples:

<ref module="imp" entry="compose-attachments">selecting attachments</ref>
<eref url="http://wiki.horde.org/FAQ/User/IMP?referer=FAQ/User#toc17">
      UW-IMAP quirk</eref>
<href app="turba" url="search.php">Address search</href>

The Translation Tool will introduce additional attributes:

XML-Tag Attribute Purpose/Syntax
entry state See Finishing a translation
md5 Used internally

4.3   Reference from the Horde applications

The typical incantation, e.g.:

<?php echo Help::link('imp', 'compose-buttons') ?>

will yield a link, adorned with the help.png icon, to the entry marked id="compose-buttons" in the IMP help file pertaining to the user's current locale. Usually, these links are placed in the template files, next to the item to be explained by the pertinent help entry.

The Horde menu will usually contain a general help item, which is generated in lib/Horde/Menu.php.

4.4   Creating a new translation

If necessary, define a suitable locale id ll_CC, complying with RFC 3066. E.g., if you plan to add an Austrian translation, you would use de_AT as your locale id.

For Horde, and for all relevant applications, copy the help.xml files from the locale/en_US/ subdirectories to the locale/ll_CC/ subdirectories, creating them if necessary.

Translate each new locale/ll_CC/help.xml file, leaving all tags and attributes unchanged. Just translate the text between the tags.

Important

The id attributes must be kept unchanged, under any circumstances.

If the application is already translated and only the help files are missing, then be sure to use the same terminology as the existing translation. In any case, try to use a lucid, coherent terminology.

4.5   Finishing a translation

If you want to submit a translation to be included in the Horde code base, make sure that you have completed all translations. Then run:

./translation.php make-help

This will mark all entries as being up-to-date so that you or other translators can later see which entries have been changed since then.

4.6   Updating an existing translation

Run:

./translation.php update-help

This will merge your existing help file with all changes from the original, English help file since your last translation. Changed entries are marked with the attribute state="changed", new entries with state="new". The original entry from the English help file is added in a comment below a changed entry, so that you can easily compare them.

Translate the remaining English phrases, like discussed above. When your finished, remove any English entries and follow the steps at Finishing a translation.

4.7   Extending existent translations

If you feel that some feature should be better explained to the end user, then proceed as following:

  1. Determine, whether you will have to extend an existing entry, or add a new one.
  2. In the latter case, choose a suitable id for your new help entry.
  3. Edit the existing entry in, or add a new entry to, the application's en_US/help.xml file. Change all translations needed in your site in the same way. Be sure to use the same id everywhere.
  4. If you have added a new entry, you might want to add a link to it from a template, as explained above in Reference from the Horde applications.
  5. If you feel that your enhancement may be useful to other users, file an enhancement request at http://bugs.horde.org/ with a patch including your changes to the template and the help.xml files.
  6. In any case, keep notes of your changes, so you can apply them to later versions if necessary.