WebApp: Translating a plugin

November 14, 2012 by Simon Koster   Comments (0)

, , , ,

With the recent release of WebApp 1.2, we have been a bit slow in publishing blog posts in this series. From the community of WebApp developers, we have received feedback (big thanks to Christof!) about the fuzziness of the available information on translating plugins. In one of our previous blog posts we already talked about how to use gettext in your code to allow your plugin to be availabe in different languages. But now we are going to talk about how to actually translate the sentences and supply the plugin with the translations.


A short recap

The GNU gettext functionality makes use of the binary translations files (or .MO-file). This file is converted from a readable .PO-file by the use of the msgfmt command. For each language there is a separate .MO or .PO-file placed in a separate directory in the WebApp. Each file contains the translations for all the strings used in the code on the client and the server-side. For more details on this you can read the first blog post about translations in the WebApp.


Step 1: Marking strings as translatable in your plugin

When you have created a plugin and used _('Example') to translate your sentences you have to add the proper domain to the gettext functions. In our previous blog posts we talked about this domain argument in gettext functions. 

If you add translations for your 'googlemapsdirections' plugin and use the _('Example') function, you will have to change it to the following line:

  • dgettext("plugin_googlemapsdirections", "Example");

The Zarafa WebApp will automatically bind the language files defined in your manifest.xml file, to the correct domain in gettext. It will prepend "plugin_" in front of the domain name as you can see in the above example. There the plugin "googlemapsdirections" uses the "plugin_googlemapsdirections" as domain.

There are also other functions that will specify from which domain the translations need to be retrieved. "msgid" in these examples is the string that you want to translate.

  • dgettext(domain, msgid)
  • dngettext(domain, msgid, msgid_plural, count)
  • dpgettext(domain, msgctxt, msgid)
  • dnpgettext(domain, msgctxt, msgid, msgid_plural, count)

Step 2: Extracting the translated strings

We start out with a plugin that has all translatable strings passed through the appropiate gettext functions. The first step to take is to extract all these strings from the code and put them in a .POT-file, or template. 

For this gettext has a nice utility called: xgettext. The xgettext utility is able to search to a number of different languages and detect what translatable sentences are used. PHP is one of them, allthough it does not by default include all the functions we implemented besides the basic gettext functionalities. There is a solution for that however: you can add the functions it needs to look in the command you give to xgettext. For JavaScript the xgettext utility does not even have an option, but we can make it work if you set the language to Python and supply the correct set of keywords it needs to look for. 

  • xgettext --keyword=_ --keyword=_W --keyword=_TT -j -L Python --keyword=dgettext:2 --keyword=ngettext:1,2 --keyword=dngettext:2,3 --keyword=pgettext:1c,2 --keyword=dpgettext:2c,3 --keyword=npgettext:1c,2,3 --keyword=dnpgettext:2c,3,4 --add-comments=TRANSLATORS --from-code utf-8 -o OUTPUT.POT INPUTFILES

This line retrieves all the translations from the JavaScript "INPUTFILES" and puts them into OUTPUT.POT. For PHP we only change the "-L Python" to "-L PHP" and the input files.

If you run this command twice and supply the same output file it will append the previously created one.

When the .POT-file is created you need to make sure that the header at the start of the file has the correct charset filled in. This needs to be changed to "UTF-8".


Step 3: Translating

This .POT-file now holds all the translated strings. In order to be able to translate these sentences you can use an translation management tool like Pootle. This online application will take the .POT-file and allow multiple translators to translate the strings into different languages.

Zarafa's translator interface translating to Dutch


Step 4: Your plugin translated

Pootle will generate a .PO-file for each language. You have to place these files in the appropiate language directory and convert them to .MO-files as described in the previous blog post about translations (using msgfmt). 

With this information, you should now be able to not only make your plugin translatable, but also translate your plugin.

We hope to have cleared up some of the confusion surrounding this topic. Feel free to ask further questions in the comments or on the forum; we also value feedback on the documentation materials - if any topic needs clarification, please let us know!