localizing_using_jinja2.rst 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. -----------------------------
  2. Localizing themes with Jinja2
  3. -----------------------------
  4. 1. Localize templates
  5. ---------------------
  6. To enable the |ext| extension in your templates, you must add it to
  7. ``JINJA_EXTENSIONS`` in your Pelican configuration
  8. .. code-block:: python
  9. JINJA_EXTENSIONS = ['jinja2.ext.i18n', ...]
  10. Then follow the `Jinja2 templating documentation for the I18N plugin
  11. <http://jinja.pocoo.org/docs/templates/#i18n>`_ to make your templates
  12. localizable. This usually means surrounding strings with the ``{%
  13. trans %}`` directive or using ``gettext()`` in expressions
  14. .. code-block:: jinja
  15. {% trans %}translatable content{% endtrans %}
  16. {{ gettext('a translatable string') }}
  17. For pluralization support, etc. consult the documentation.
  18. To enable `newstyle gettext calls
  19. <http://jinja.pocoo.org/docs/extensions/#newstyle-gettext>`_ the
  20. ``I18N_GETTEXT_NEWSTYLE`` config variable must be set to ``True``
  21. (default).
  22. .. |ext| replace:: ``jinja2.ext.i18n``
  23. 2. Specify translations location
  24. --------------------------------
  25. The |ext| extension uses the `Python gettext library
  26. <http://docs.python.org/library/gettext.html>`_ for translating
  27. strings.
  28. In your Pelican config you can give the path in which to look for
  29. translations in the ``I18N_GETTEXT_LOCALEDIR`` variable. If not given,
  30. it is assumed to be the ``translations`` subfolder in the top folder
  31. of the theme specified by ``THEME``.
  32. The domain of the translations (the name of each translation file is
  33. ``domain.mo``) is controlled by the ``I18N_GETTEXT_DOMAIN`` config
  34. variable (defaults to ``messages``).
  35. Example
  36. .......
  37. With the following in your Pelican settings file
  38. .. code-block:: python
  39. I18N_GETTEXT_LOCALEDIR = 'some/path/'
  40. I18N_GETTEXT_DOMAIN = 'my_domain'
  41. the translation for language 'cz' will be expected to be in
  42. ``some/path/cz/LC_MESSAGES/my_domain.mo``
  43. 3. Extract translatable strings and translate them
  44. --------------------------------------------------
  45. There are many ways to extract translatable strings and create
  46. ``gettext`` compatible translations. You can create the ``*.po`` and
  47. ``*.mo`` message catalog files yourself, or you can use some helper
  48. tool as described in `the Python gettext library tutorial
  49. <http://docs.python.org/library/gettext.html#internationalizing-your-programs-and-modules>`_.
  50. You of course don't need to provide a translation for the language in
  51. which the templates are written which is assumed to be the original
  52. ``DEFAULT_LANG``. This can be overridden in the
  53. ``I18N_TEMPLATES_LANG`` variable.
  54. Recommended tool: babel
  55. .......................
  56. `Babel <http://babel.pocoo.org/>`_ makes it easy to extract
  57. translatable strings from the localized Jinja2 templates and assists
  58. with creating translations as documented in this `Jinja2-Babel
  59. tutorial
  60. <http://pythonhosted.org/Flask-Babel/#translating-applications>`_
  61. [#flask]_ on which the following is based.
  62. 1. Add babel mapping
  63. ~~~~~~~~~~~~~~~~~~~~
  64. Let's assume that you are localizing a theme in ``themes/my_theme/``
  65. and that you use the default settings, i.e. the default domain
  66. ``messages`` and will put the translations in the ``translations``
  67. subdirectory of the theme directory as
  68. ``themes/my_theme/translations/``.
  69. It is up to you where to store babel mappings and translation files
  70. templates (``*.pot``), but a convenient place is to put them in
  71. ``themes/my_theme/`` and work in that directory. From now on let's
  72. assume that it will be our current working directory (CWD).
  73. To tell babel to extract translatable strings from the templates
  74. create a mapping file ``babel.cfg`` with the following line
  75. .. code-block:: cfg
  76. [jinja2: templates/**.html]
  77. 2. Extract translatable strings from templates
  78. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  79. Run the following command to create a ``messages.pot`` message catalog
  80. template file from extracted translatable strings
  81. .. code-block:: bash
  82. pybabel extract --mapping babel.cfg --output messages.pot ./
  83. 3. Initialize message catalogs
  84. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  85. If you want to translate the template to language ``lang``, run the
  86. following command to create a message catalog
  87. ``translations/lang/LC_MESSAGES/messages.po`` using the template
  88. ``messages.pot``
  89. .. code-block:: bash
  90. pybabel init --input-file messages.pot --output-dir translations/ --locale lang --domain messages
  91. babel expects ``lang`` to be a valid locale identifier, so if e.g. you
  92. are translating for language ``cz`` but the corresponding locale is
  93. ``cs``, you have to use the locale identifier. Nevertheless, the
  94. gettext infrastructure should later correctly find the locale for a
  95. given language.
  96. 4. Fill the message catalogs
  97. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  98. The message catalog files format is quite intuitive, it is fully
  99. documented in the `GNU gettext manual
  100. <http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files>`_. Essentially,
  101. you fill in the ``msgstr`` strings
  102. .. code-block:: po
  103. msgid "just a simple string"
  104. msgstr "jenom jednoduchý řetězec"
  105. msgid ""
  106. "some multiline string"
  107. "looks like this"
  108. msgstr ""
  109. "nějaký více řádkový řetězec"
  110. "vypadá takto"
  111. You might also want to remove ``#,fuzzy`` flags once the translation
  112. is complete and reviewed to show that it can be compiled.
  113. 5. Compile the message catalogs
  114. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  115. The message catalogs must be compiled into binary format using this
  116. command
  117. .. code-block:: bash
  118. pybabel compile --directory translations/ --domain messages
  119. This command might complain about "fuzzy" translations, which means
  120. you should review the translations and once done, remove the fuzzy
  121. flag line.
  122. (6.) Update the catalogs when templates change
  123. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  124. If you add any translatable patterns into your templates, you have to
  125. update your message catalogs too. First you extract a new message
  126. catalog template as described in the 2. step. Then you run the
  127. following command [#pybabel_error]_
  128. .. code-block:: bash
  129. pybabel update --input-file messages.pot --output-dir translations/ --domain messages
  130. This will merge the new patterns with the old ones. Once you review
  131. and fill them, you have to recompile them as described in the 5. step.
  132. .. [#flask] Although the tutorial is focused on Flask-based web
  133. applications, the linked translation tutorial is not
  134. Flask-specific.
  135. .. [#pybabel_error] If you get an error ``TypeError: must be str, not
  136. bytes`` with Python 3.3, it is likely you are
  137. suffering from this `bug
  138. <https://github.com/mitsuhiko/flask-babel/issues/43>`_.
  139. Until the fix is released, you can use babel with
  140. Python 2.7.