doc/book/en/devweb/internationalization.rst
changeset 10491 c67bcee93248
parent 10490 76ab3c71aff2
child 10492 68c13e0c0fc5
equal deleted inserted replaced
10490:76ab3c71aff2 10491:c67bcee93248
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 .. _internationalization:
       
     4 
       
     5 Internationalization
       
     6 ---------------------
       
     7 
       
     8 Cubicweb fully supports the internalization of its content and interface.
       
     9 
       
    10 Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
       
    11 
       
    12 .. _`GNU gettext`: http://www.gnu.org/software/gettext/
       
    13 
       
    14 Cubicweb' internalization involves two steps:
       
    15 
       
    16 * in your Python code and cubicweb-tal templates : mark translatable strings
       
    17 
       
    18 * in your instance : handle the translation catalog, edit translations
       
    19 
       
    20 String internationalization
       
    21 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
    22 
       
    23 User defined string
       
    24 ```````````````````
       
    25 
       
    26 In the Python code and cubicweb-tal templates translatable strings can be
       
    27 marked in one of the following ways :
       
    28 
       
    29  * by using the *built-in* function `_`:
       
    30 
       
    31    .. sourcecode:: python
       
    32 
       
    33      class PrimaryView(EntityView):
       
    34          """the full view of an non final entity"""
       
    35          __regid__ = 'primary'
       
    36          title = _('primary')
       
    37 
       
    38   OR
       
    39 
       
    40  * by using the equivalent request's method:
       
    41 
       
    42    .. sourcecode:: python
       
    43 
       
    44      class NoResultView(View):
       
    45          """default view when no result has been found"""
       
    46          __regid__ = 'noresult'
       
    47 
       
    48          def call(self, **kwargs):
       
    49              self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
       
    50                  % self._cw._('No result matching query'))
       
    51 
       
    52 The goal of the *built-in* function `_` is only **to mark the
       
    53 translatable strings**, it will only return the string to translate
       
    54 itself, but not its translation (it's actually another name for the
       
    55 `unicode` builtin).
       
    56 
       
    57 In the other hand the request's method `self._cw._` is also meant to
       
    58 retrieve the proper translation of translation strings in the
       
    59 requested language.
       
    60 
       
    61 Finally you can also use the `__` attribute of request object to get a
       
    62 translation for a string *which should not itself added to the catalog*,
       
    63 usually in case where the actual msgid is created by string interpolation ::
       
    64 
       
    65   self._cw.__('This %s' % etype)
       
    66 
       
    67 In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
       
    68 messages catalogs.
       
    69 
       
    70 Translations in cubicweb-tal template can also be done with TAL tags
       
    71 `i18n:content` and `i18n:replace`.
       
    72 
       
    73 If you need to add messages on top of those that can be found in the source,
       
    74 you can create a file named `i18n/static-messages.pot`.
       
    75 
       
    76 You could put there messages not found in the python sources or
       
    77 overrides for some messages of used cubes.
       
    78 
       
    79 Generated string
       
    80 ````````````````
       
    81 
       
    82 We do not need to mark the translation strings of entities/relations used by a
       
    83 particular instance's schema as they are generated automatically. String for
       
    84 various actions are also generated.
       
    85 
       
    86 For exemple the following schema:
       
    87 
       
    88 .. sourcecode:: python
       
    89 
       
    90 
       
    91   class EntityA(EntityType):
       
    92       relation_a2b = SubjectRelation('EntityB')
       
    93 
       
    94   class EntityB(EntityType):
       
    95       pass
       
    96 
       
    97 May generate the following message ::
       
    98 
       
    99   add EntityA relation_a2b EntityB subject
       
   100 
       
   101 This message will be used in views of ``EntityA`` for creation of a new
       
   102 ``EntityB`` with a preset relation ``relation_a2b`` between the current
       
   103 ``EntityA`` and the new ``EntityB``. The opposite message ::
       
   104 
       
   105   add EntityA relation_a2b EntityB object
       
   106 
       
   107 Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
       
   108 title of they respective creation form will be ::
       
   109 
       
   110   creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
       
   111 
       
   112   creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
       
   113 
       
   114 In the translated string you can use ``%(linkto)s`` for reference to the source
       
   115 ``entity``.
       
   116 
       
   117 Handling the translation catalog
       
   118 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   119 
       
   120 Once the internationalization is done in your code, you need to populate and
       
   121 update the translation catalog. Cubicweb provides the following commands for this
       
   122 purpose:
       
   123 
       
   124 
       
   125 * `i18ncubicweb` updates Cubicweb framework's translation
       
   126   catalogs. Unless you actually work on the framework itself, you
       
   127   don't need to use this command.
       
   128 
       
   129 * `i18ncube` updates the translation catalogs of *one particular cube*
       
   130   (or of all cubes). After this command is executed you must update
       
   131   the translation files *.po* in the "i18n" directory of your
       
   132   cube. This command will of course not remove existing translations
       
   133   still in use. It will mark unused translation but not remove them.
       
   134 
       
   135 * `i18ninstance` recompiles the translation catalogs of *one particular
       
   136   instance* (or of all instances) after the translation catalogs of
       
   137   its cubes have been updated. This command is automatically
       
   138   called every time you create or update your instance. The compiled
       
   139   catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
       
   140   instance where `lang` is the language identifier ('en' or 'fr'
       
   141   for exemple).
       
   142 
       
   143 
       
   144 Example
       
   145 ```````
       
   146 
       
   147 You have added and/or modified some translation strings in your cube
       
   148 (after creating a new view or modifying the cube's schema for exemple).
       
   149 To update the translation catalogs you need to do:
       
   150 
       
   151 1. `cubicweb-ctl i18ncube <cube>`
       
   152 2. Edit the <cube>/i18n/xxx.po  files and add missing translations (empty `msgstr`)
       
   153 3. `hg ci -m "updated i18n catalogs"`
       
   154 4. `cubicweb-ctl i18ninstance <myinstance>`
       
   155 
       
   156 Editing po files
       
   157 ~~~~~~~~~~~~~~~~
       
   158 
       
   159 Using a PO aware editor
       
   160 ````````````````````````
       
   161 
       
   162 Many tools exist to help maintain .po (PO) files. Common editors or
       
   163 development environment provides modes for these. One can also find
       
   164 dedicated PO files editor, such as `poedit`_.
       
   165 
       
   166 .. _`poedit`:  http://www.poedit.net/
       
   167 
       
   168 While usage of such a tool is commendable, PO files are perfectly
       
   169 editable with a (unicode aware) plain text editor. It is also useful
       
   170 to know their structure for troubleshooting purposes.
       
   171 
       
   172 Structure of a PO file
       
   173 ``````````````````````
       
   174 
       
   175 In this section, we selectively quote passages of the `GNU gettext`_
       
   176 manual chapter on PO files, available there::
       
   177 
       
   178  http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
       
   179 
       
   180 One PO file entry has the following schematic structure::
       
   181 
       
   182      white-space
       
   183      #  translator-comments
       
   184      #. extracted-comments
       
   185      #: reference...
       
   186      #, flag...
       
   187      #| msgid previous-untranslated-string
       
   188      msgid untranslated-string
       
   189      msgstr translated-string
       
   190 
       
   191 
       
   192 A simple entry can look like this::
       
   193 
       
   194      #: lib/error.c:116
       
   195      msgid "Unknown system error"
       
   196      msgstr "Error desconegut del sistema"
       
   197 
       
   198 It is also possible to have entries with a context specifier. They
       
   199 look like this::
       
   200 
       
   201      white-space
       
   202      #  translator-comments
       
   203      #. extracted-comments
       
   204      #: reference...
       
   205      #, flag...
       
   206      #| msgctxt previous-context
       
   207      #| msgid previous-untranslated-string
       
   208      msgctxt context
       
   209      msgid untranslated-string
       
   210      msgstr translated-string
       
   211 
       
   212 
       
   213 The context serves to disambiguate messages with the same
       
   214 untranslated-string. It is possible to have several entries with the
       
   215 same untranslated-string in a PO file, provided that they each have a
       
   216 different context. Note that an empty context string and an absent
       
   217 msgctxt line do not mean the same thing.
       
   218 
       
   219 Contexts and CubicWeb
       
   220 `````````````````````
       
   221 
       
   222 CubicWeb PO files have both non-contextual and contextual msgids.
       
   223 
       
   224 Contextual entries are automatically used in some cases. For instance,
       
   225 entity.dc_type(), eschema.display_name(req) or display_name(etype,
       
   226 req, form, context) methods/function calls will use them.
       
   227 
       
   228 It is also possible to explicitly use the with _cw.pgettext(context,
       
   229 msgid).