.. -*- coding: utf-8 -*-
.. _internationalization:
Internationalization
---------------------
Cubicweb fully supports the internalization of its content and interface.
Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
.. _`GNU gettext`: http://www.gnu.org/software/gettext/
Cubicweb' internalization involves two steps:
* in your Python code and cubicweb-tal templates : mark translatable strings
* in your instance : handle the translation catalog, edit translations
String internationalization
~~~~~~~~~~~~~~~~~~~~~~~~~~~
User defined string
```````````````````
In the Python code and cubicweb-tal templates translatable strings can be
marked in one of the following ways :
* by using the *built-in* function `_` ::
class PrimaryView(EntityView):
"""the full view of an non final entity"""
__regid__ = 'primary'
title = _('primary')
OR
* by using the equivalent request's method ::
class NoResultView(View):
"""default view when no result has been found"""
__regid__ = 'noresult'
def call(self, **kwargs):
self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
% self._cw._('No result matching query'))
The goal of the *built-in* function `_` is only **to mark the
translatable strings**, it will only return the string to translate
itself, but not its translation (it's actually another name for the
`unicode` builtin).
In the other hand the request's method `self._cw._` is also meant to
retrieve the proper translation of translation strings in the
requested language.
Finally you can also use the `__` attribute of request object to get a
translation for a string *which should not itself added to the catalog*,
usually in case where the actual msgid is created by string interpolation ::
self._cw.__('This %s' % etype)
In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
messages catalogs.
Translations in cubicweb-tal template can also be done with TAL tags
`i18n:content` and `i18n:replace`.
If you need to add messages on top of those that can be found in the source,
you can create a file named `i18n/static-messages.pot`.
You could put there messages not found in the python sources or
overrides for some messages of used cubes.
Generated string
````````````````
We do not need to mark the translation strings of entities/relations used by a
particular instance's schema as they are generated automatically. String for
various actions are also generated.
For exemple the following schema ::
Class EntityA(EntityType):
relation_a2b = SubjectRelation('EntityB')
class EntityB(EntityType):
pass
May generate the following message ::
add EntityA relation_a2b EntityB subject
This message will be used in views of ``EntityA`` for creation of a new
``EntityB`` with a preset relation ``relation_a2b`` between the current
``EntityA`` and the new ``EntityB``. The opposite message ::
add EntityA relation_a2b EntityB object
Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
title of they respective creation form will be ::
creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
In the translated string you can use ``%(linkto)s`` for reference to the source
``entity``.
Handling the translation catalog
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once the internationalization is done in your code, you need to populate and
update the translation catalog. Cubicweb provides the following commands for this
purpose:
* `i18ncubicweb` updates Cubicweb framework's translation
catalogs. Unless you actually work on the framework itself, you
don't need to use this command.
* `i18ncube` updates the translation catalogs of *one particular cube*
(or of all cubes). After this command is executed you must update
the translation files *.po* in the "i18n" directory of your
cube. This command will of course not remove existing translations
still in use. It will mark unused translation but not remove them.
* `i18ninstance` recompiles the translation catalogs of *one particular
instance* (or of all instances) after the translation catalogs of
its cubes have been updated. This command is automatically
called every time you create or update your instance. The compiled
catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
instance where `lang` is the language identifier ('en' or 'fr'
for exemple).
Example
```````
You have added and/or modified some translation strings in your cube
(after creating a new view or modifying the cube's schema for exemple).
To update the translation catalogs you need to do:
1. `cubicweb-ctl i18ncube <cube>`
2. Edit the <cube>/i18n/xxx.po files and add missing translations (empty `msgstr`)
3. `hg ci -m "updated i18n catalogs"`
4. `cubicweb-ctl i18ninstance <myinstance>`
Editing po files
~~~~~~~~~~~~~~~~
Using a PO aware editor
````````````````````````
Many tools exist to help maintain .po (PO) files. Common editors or
development environment provides modes for these. One can also find
dedicated PO files editor, such as `poedit`_.
.. _`poedit`: http://www.poedit.net/
While usage of such a tool is commendable, PO files are perfectly
editable with a (unicode aware) plain text editor. It is also useful
to know their structure for troubleshooting purposes.
Structure of a PO file
``````````````````````
In this section, we selectively quote passages of the `GNU gettext`_
manual chapter on PO files, available there::
http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
One PO file entry has the following schematic structure::
white-space
# translator-comments
#. extracted-comments
#: reference...
#, flag...
#| msgid previous-untranslated-string
msgid untranslated-string
msgstr translated-string
A simple entry can look like this::
#: lib/error.c:116
msgid "Unknown system error"
msgstr "Error desconegut del sistema"
It is also possible to have entries with a context specifier. They
look like this::
white-space
# translator-comments
#. extracted-comments
#: reference...
#, flag...
#| msgctxt previous-context
#| msgid previous-untranslated-string
msgctxt context
msgid untranslated-string
msgstr translated-string
The context serves to disambiguate messages with the same
untranslated-string. It is possible to have several entries with the
same untranslated-string in a PO file, provided that they each have a
different context. Note that an empty context string and an absent
msgctxt line do not mean the same thing.
Contexts and CubicWeb
`````````````````````
CubicWeb PO files have both non-contextual and contextual msgids.
Contextual entries are automatically used in some cases. For instance,
entity.dc_type(), eschema.display_name(req) or display_name(etype,
req, form, context) methods/function calls will use them.
It is also possible to explicitly use the with _cw.pgettext(context,
msgid).