=================================
Using Translation System in elisa 
=================================


Since the release 0.3.2 Elisa is using the Flumotion translations
system which is using gettext to manage translation. This is a How-To
for the plugin developers, who want to use this system to get their
plugins localized.


To understand this document, you should already have a plugin and
components inside it. That also means that you have a minimum
knowlegde of python.  Once you will have understood this document, you
can use the system directly during the development, you don't have to
do it after finishing the plugin ;).

Anyway this document describes how to integrate the translation system in an
existing plugin and their components in this steps:


.. contents::


Other Things:


- Updating the Translation
- Different Domains per plugin
- Compile all translations for svn
- Test a translation

If you are interested to add a translation to a plugin that has already
translations you may take a look at `Making a pot/po file`_ and `Compiling to mo`_


Create the 'domain'
===================

A directory with translation is always for one certain domain. A domain is one
plugin name. Make a new directory in your main plugin directory for example
called i18n. Now open your plugin.conf file and add a subsection called i18n
to your section 'general' and there you can specify your domain (for more
domains see `Different Domains per plugin`_) pointing to the directory. That
could look like this:

::

    [general]
    name='myplugin'
    version='0.0.1'
    plugin_dependencies=[]
    external_dependencies=[]
    description="This is my first plugin"

    [[i18n]]
    elisa-myplugin="i18n"

The domain, as you can see, should be elisa-[name_of_the_plugin]. That makes
it easier to seperate the plugins and to find the correct domain for it.

This domain-name is pointing to the directory, or a directory path (like
"translation/i18n/thisplugin") using the plugin.conf as the root. It should
**not** start or end with a "/" and should not go higher than the root it
self.

In this directory, we put the translation files as three-letter-mo-files. More
about this later.



Set up the components
=====================

This step has to be done in _every_ component of your plugin, that has
translateable strings. That is not for names, but for all things, that
the end user reads on the Elisa window. Logging messages are not
translated.

Import
------

At first, you have to import the translation stuff. Do this at the
top:

::

    from elisa.extern.translator import gettexter, N_

If you have strings, that might be plural or singular and you have different
translation for it, you may also import ngettexter:

::

    from elisa.extern.translator import gettexter, ngettexter, N_

Making T
--------

Now you should do (before the first definition of a class), define a method
for making a Translateable for this domain. Renember the domain for this
example was 'elisa-myplugin'. The domain _has_ to be the same as the domain
you've specified in the plugin.conf.

::

  T_ = gettexter('elisa-myplugin')

If you have also Singular/Plural-Things you may also do:

::

  P_ = ngettexter('elisa-myplugin')

Now you have one (or two) method(s) that can create a Translateable
from a String for this domain. What a Translateable is, is not
important for you, but Elisa needs it to translate stuff.


Marking Strings
---------------

Now you have this function ``T_`` and can you use it, to make Translateables. But
to be able to handle the translation easiely, it is also necessary that the
translateable strings are marked. For this, we have imported the wrapper
function ``N_``. Now look for the strings in the component you want to have
translated and add the calls to ``T_`` and ``N_`` functions:

::

    T_(N_("String that should be translated"))

If you have some arguments, that you want to ship with, you can do it like
this:

::

    T_(N_("The arguments are '%s', '%s' and '%s'."), arg1, arg2, arg3)


For the singular/plural strings, we are using the ``P_`` function instead. Here the
first argument is a tuple, containing the singular string, the plural string
and the number used to decide which one to use. That could for e.g. looke like
this:

::

    P_( (N_("Found %s result"),
         N_("Found %s results"),
          results_count), results_count )


If you have done this for all your Strings in your components, you can go on
with the next step.


Making a pot/po file
====================

You can now simply make a pot-file (the template for translation), by doing
this in the directory where all python source files are:

::

    $ xgettext --language=python --keyword=N_ *.py -o messages.pot

That will create a file called messages.pot.

Attention: most Project are using the 2-letter language code. Elisa is using
the 3-letter code which is specified in ISO-639-3, and has a list of nearly
7.000 languages. Before you start a new translation file, you should look up
what the code is for your language. For German it would be 'deu', so let's make
the po-file by doing this in the directory where the python files are:

::

    msginit --input messages.pot --locale deu

That should create a file called 'deu.po'. You can now edit this file and make
the translation. I would suggest you to create a new directory for these
translation sources. Call it for e.g. po/ or put them in the same directory as
the compiled ones and let your archive software take care of it.

While editing this file, don't forget to change the Charset, if neccessary.
Change it to UTF-8, if you have any special characters.


Compiling to mo
===============

Gettext is expecting the translation files to be compiled as mo-files in a very
strange hierachy. But you don't have to care about it, Elisa will
on-the-fly compile po files that haven't already been compiled or
modified since last translation file update.

If your plugin has a setup.py, you can list your translations in a
file (by default data/translations.lst). That file has the following
format:

::

      #
      # domain path/to/input /path/to/output
      # other-domain path/to/input/only
      #
      #
      # Don't forget the empty line at the end!

      # example:
      elisa-myplugin po i18n

Then, running the following command will compile po files that need to
be compiled and include them in the package data, so that your egg
plugin is correctly shipping the translation:

::

  $ python setup.py build_po

The build_po command is automatically executed when you "build" and
run the "bdist_egg" setup.py commands.


Update translations
===================

If you have more than one file or you updated one of the python-source files,
you might want to update the translation files as well. To do this, you can
use xgettext again:

::

    $ xgettext --language=python --join-existing --output esp.po --keyword=N_ *.py

This should have added the new strings to the end of the esp.po.

Different domains per plugin
============================

Elisa allows more than one directory-path per domain. To make this as useful
as possible, we also allow multiple domains per plugin. That enables the
possibility of shipping translation-only plugins. That is very useful for the
many languages we are going to support. Let's make one plugin, called
prg-good, that has prussia tranlation files for the plugins Arthur, Ford and
Marvin (with their corresponding domains elisa-arthur, elisa-ford and
elisa-marvin).

We use prg, because it is the code by ISO-639-3 for the prussian language.

The plugin-config would look like this:

::

    [general]
    name='prg-good'
    version='0.0.1'
    plugin_dependencies=[]
    external_dependencies=[]
    description="This is a language plugin for prussia (prg)"

    [[i18n]]
    elisa-arthur="i18n"
    elisa-ford="i18n"
    elis-marvin="i18n"


Of course, the place for the languages could vary for each domain, but
for this example it is easier and more useful to have the same.

Okay. This example expects that we already have existing messages.pot for the
different plugins. If not, you can make them (as seen above). Now we are
making a prg.po file for each of them (see above). But they are not important
for the package. We need the compiled ones. Okay, let's make everything ready
for compiling (sorry, no script yet...).

::

    $ mkdir -p i18n/prg/LC_MESSAGES/

(For other translations, you've to replace 'prg' ;) )

Now you can compile the files, doing this:

::

    $ msgfmt --output i18n/prg/LC_MESSAGES/[domain].mo input_file.po

That would for e.g. be for the elisa-arthur.po file, which is for the
elisa-arthur domain:

::

    $ msgfmt --output i18n/prg/LC_MESSAGES/elisa-arthur.mo elisa-arthur.po

Do this, with every domain/po-file you have and you've finished the
translation-only plugin for the prussian language. Easy right?


Test the translation/Set the translations
=========================================

I expect that you are using a frontend/view system that has i18n support, like
the poblenou one.

The cool thing about this i18n system is, that you can set a list of
languages for each frontend. Simply put a languages list option into your
configuration file for elisa in the section for the frontend on which you want
to test. Here is an example for the languages german (deu) and english (eng)
(in this order) for the frontend 'frontend1':

::

  [frontend1]
  languages = ['deu', 'eng']

Now start elisa and test your translation. If you get unicode-errors, you
might have forgotten to set the charset to 'UTF-8' before compiling ;).

-----------------------------------------------------------------------------

If you have anything to add, update or comment please don't hessitate to mail
me: Benjamin Kampmann < benjamin [at] fluendo dot com >
