aboutsummaryrefslogtreecommitdiff
path: root/plugins/i18n_subsites/localizing_using_jinja2.rst
blob: a28beddf8b1d925d490955bb2e4bc58e45a641ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
-----------------------------
Localizing themes with Jinja2
-----------------------------

1. Localize templates
---------------------

To enable the |ext| extension in your templates, you must add it to
``JINJA_ENVIRONMENT`` in your Pelican configuration

.. code-block:: python

  JINJA_ENVIRONMENT = {
    'extensions': ['jinja2.ext.i18n', ...]
  }

Then follow the `Jinja2 templating documentation for the I18N plugin
<http://jinja.pocoo.org/docs/templates/#i18n>`_ to make your templates
localizable. This usually means surrounding strings with the ``{%
trans %}`` directive or using ``gettext()`` in expressions

.. code-block:: jinja

    {% trans %}translatable content{% endtrans %}
    {{ gettext('a translatable string') }}

For pluralization support, etc. consult the documentation.

To enable `newstyle gettext calls
<http://jinja.pocoo.org/docs/extensions/#newstyle-gettext>`_ the
``I18N_GETTEXT_NEWSTYLE`` config variable must be set to ``True``
(default).

.. |ext| replace:: ``jinja2.ext.i18n``

2. Specify translations location
--------------------------------

The |ext| extension uses the `Python gettext library
<http://docs.python.org/library/gettext.html>`_ for translating
strings.

In your Pelican config you can give the path in which to look for
translations in the ``I18N_GETTEXT_LOCALEDIR`` variable. If not given,
it is assumed to be the ``translations`` subfolder in the top folder
of the theme specified by ``THEME``.

The domain of the translations (the name of each translation file is
``domain.mo``) is controlled by the ``I18N_GETTEXT_DOMAIN`` config
variable (defaults to ``messages``).

Example
.......

With the following in your Pelican settings file

.. code-block:: python

  I18N_GETTEXT_LOCALEDIR = 'some/path/'
  I18N_GETTEXT_DOMAIN = 'my_domain'

the translation for language 'cz' will be expected to be in
``some/path/cz/LC_MESSAGES/my_domain.mo``


3. Extract translatable strings and translate them
--------------------------------------------------

There are many ways to extract translatable strings and create
``gettext`` compatible translations. You can create the ``*.po`` and
``*.mo`` message catalog files yourself, or you can use some helper
tool as described in `the Python gettext library tutorial
<http://docs.python.org/library/gettext.html#internationalizing-your-programs-and-modules>`_.

You of course don't need to provide a translation for the language in
which the templates are written which is assumed to be the original
``DEFAULT_LANG``. This can be overridden in the
``I18N_TEMPLATES_LANG`` variable.

Recommended tool: babel
.......................

`Babel <http://babel.pocoo.org/>`_ makes it easy to extract
translatable strings from the localized Jinja2 templates and assists
with creating translations as documented in this `Jinja2-Babel
tutorial
<http://pythonhosted.org/Flask-Babel/#translating-applications>`_
[#flask]_ on which the following is based.

1. Add babel mapping
~~~~~~~~~~~~~~~~~~~~

Let's assume that you are localizing a theme in ``themes/my_theme/``
and that you use the default settings, i.e. the default domain
``messages`` and will put the translations in the ``translations``
subdirectory of the theme directory as
``themes/my_theme/translations/``.

It is up to you where to store babel mappings and translation files
templates (``*.pot``), but a convenient place is to put them in
``themes/my_theme/`` and work in that directory. From now on let's
assume that it will be our current working directory (CWD).

To tell babel to extract translatable strings from the templates
create a mapping file ``babel.cfg`` with the following line

.. code-block:: cfg

    [jinja2: templates/**.html]


2. Extract translatable strings from templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Run the following command to create a ``messages.pot`` message catalog
template file from extracted translatable strings

.. code-block:: bash

    pybabel extract --mapping babel.cfg --output messages.pot ./


3. Initialize message catalogs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you want to translate the template to language ``lang``, run the
following command to create a message catalog
``translations/lang/LC_MESSAGES/messages.po`` using the template
``messages.pot``

.. code-block:: bash

    pybabel init --input-file messages.pot --output-dir translations/ --locale lang --domain messages

babel expects ``lang`` to be a valid locale identifier, so if e.g. you
are translating for language ``cz`` but the corresponding locale is
``cs``, you have to use the locale identifier. Nevertheless, the
gettext infrastructure should later correctly find the locale for a
given language.

4. Fill the message catalogs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The message catalog files format is quite intuitive, it is fully
documented in the `GNU gettext manual
<http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files>`_. Essentially,
you fill in the ``msgstr`` strings


.. code-block:: po

    msgid "just a simple string"
    msgstr "jenom jednoduchý řetězec"

    msgid ""
    "some multiline string"
    "looks like this"
    msgstr ""
    "nějaký více řádkový řetězec"
    "vypadá takto"

You might also want to remove ``#,fuzzy`` flags once the translation
is complete and reviewed to show that it can be compiled.

5. Compile the message catalogs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The message catalogs must be compiled into binary format using this
command

.. code-block:: bash

    pybabel compile --directory translations/ --domain messages

This command might complain about "fuzzy" translations, which means
you should review the translations and once done, remove the fuzzy
flag line.

(6.) Update the catalogs when templates change
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you add any translatable patterns into your templates, you have to
update your message catalogs too.  First you extract a new message
catalog template as described in the 2. step. Then you run the
following command [#pybabel_error]_

.. code-block:: bash

   pybabel update --input-file messages.pot --output-dir translations/ --domain messages

This will merge the new patterns with the old ones. Once you review
and fill them, you have to recompile them as described in the 5. step.

.. [#flask] Although the tutorial is focused on Flask-based web
            applications, the linked translation tutorial is not
            Flask-specific.
.. [#pybabel_error] If you get an error ``TypeError: must be str, not
                    bytes`` with Python 3.3, it is likely you are
                    suffering from this `bug
                    <https://github.com/mitsuhiko/flask-babel/issues/43>`_.
                    Until the fix is released, you can use babel with
                    Python 2.7.