commit | author | age
|
7534ba
|
1 |
.. index:: |
CM |
2 |
single: i18n |
|
3 |
single: l10n |
|
4 |
single: internationalization |
|
5 |
single: localization |
|
6 |
|
|
7 |
.. _i18n_chapter: |
|
8 |
|
|
9 |
Internationalization and Localization |
|
10 |
===================================== |
|
11 |
|
d2b365
|
12 |
:term:`Internationalization` (i18n) is the act of creating software with a user |
SP |
13 |
interface that can potentially be displayed in more than one language or |
|
14 |
cultural context. :term:`Localization` (l10n) is the process of displaying the |
|
15 |
user interface of an internationalized application in a *particular* language |
|
16 |
or cultural context. |
df3beb
|
17 |
|
d2b365
|
18 |
:app:`Pyramid` offers internationalization and localization subsystems that can |
SP |
19 |
be used to translate the text of buttons, error messages, and other software- |
|
20 |
and template-defined values into the native language of a user of your |
|
21 |
application. |
7534ba
|
22 |
|
CM |
23 |
.. index:: |
|
24 |
single: translation string |
|
25 |
pair: domain; translation |
|
26 |
pair: msgid; translation |
|
27 |
single: message identifier |
|
28 |
|
|
29 |
Creating a Translation String |
|
30 |
----------------------------- |
|
31 |
|
d2b365
|
32 |
While you write your software, you can insert specialized markup into your |
SP |
33 |
Python code that makes it possible for the system to translate text values into |
|
34 |
the languages used by your application's users. This markup creates a |
|
35 |
:term:`translation string`. A translation string is an object that behaves |
|
36 |
mostly like a normal Unicode object, except that it also carries around extra |
|
37 |
information related to its job as part of the :app:`Pyramid` translation |
|
38 |
machinery. |
7534ba
|
39 |
|
d2b365
|
40 |
Using the ``TranslationString`` Class |
7534ba
|
41 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
CM |
42 |
|
|
43 |
The most primitive way to create a translation string is to use the |
fec0f0
|
44 |
:class:`pyramid.i18n.TranslationString` callable: |
7534ba
|
45 |
|
CM |
46 |
.. code-block:: python |
|
47 |
:linenos: |
|
48 |
|
fec0f0
|
49 |
from pyramid.i18n import TranslationString |
7534ba
|
50 |
ts = TranslationString('Add') |
CM |
51 |
|
|
52 |
This creates a Unicode-like object that is a TranslationString. |
|
53 |
|
|
54 |
.. note:: |
|
55 |
|
d2b365
|
56 |
For people more familiar with :term:`Zope` i18n, a TranslationString is a |
SP |
57 |
lot like a ``zope.i18nmessageid.Message`` object. It is not a subclass, |
|
58 |
however. For people more familiar with :term:`Pylons` or :term:`Django` |
|
59 |
i18n, using a TranslationString is a lot like using "lazy" versions of |
|
60 |
related gettext APIs. |
7534ba
|
61 |
|
d2b365
|
62 |
The first argument to :class:`~pyramid.i18n.TranslationString` is the |
SP |
63 |
``msgid``; it is required. It represents the key into the translation mappings |
|
64 |
provided by a particular localization. The ``msgid`` argument must be a Unicode |
|
65 |
object or an ASCII string. The msgid may optionally contain *replacement |
|
66 |
markers*. For instance: |
7534ba
|
67 |
|
CM |
68 |
.. code-block:: python |
|
69 |
:linenos: |
|
70 |
|
fec0f0
|
71 |
from pyramid.i18n import TranslationString |
7534ba
|
72 |
ts = TranslationString('Add ${number}') |
CM |
73 |
|
d2b365
|
74 |
Within the string above, ``${number}`` is a replacement marker. It will be |
SP |
75 |
replaced by whatever is in the *mapping* for a translation string. The mapping |
|
76 |
may be supplied at the same time as the replacement marker itself: |
7534ba
|
77 |
|
CM |
78 |
.. code-block:: python |
|
79 |
:linenos: |
|
80 |
|
fec0f0
|
81 |
from pyramid.i18n import TranslationString |
7534ba
|
82 |
ts = TranslationString('Add ${number}', mapping={'number':1}) |
CM |
83 |
|
d2b365
|
84 |
Any number of replacement markers can be present in the msgid value, any number |
SP |
85 |
of times. Only markers which can be replaced by the values in the *mapping* |
|
86 |
will be replaced at translation time. The others will not be interpolated and |
|
87 |
will be output literally. |
7534ba
|
88 |
|
CM |
89 |
A translation string should also usually carry a *domain*. The domain |
d2b365
|
90 |
represents a translation category to disambiguate it from other translations of |
SP |
91 |
the same msgid, in case they conflict. |
7534ba
|
92 |
|
CM |
93 |
.. code-block:: python |
|
94 |
:linenos: |
|
95 |
|
fec0f0
|
96 |
from pyramid.i18n import TranslationString |
879bb5
|
97 |
ts = TranslationString('Add ${number}', mapping={'number':1}, |
7534ba
|
98 |
domain='form') |
CM |
99 |
|
d2b365
|
100 |
The above translation string named a domain of ``form``. A :term:`translator` |
SP |
101 |
function will often use the domain to locate the right translator file on the |
|
102 |
filesystem which contains translations for a given domain. In this case, if it |
|
103 |
were trying to translate our msgid to German, it might try to find a |
|
104 |
translation from a :term:`gettext` file within a :term:`translation directory` |
|
105 |
like this one: |
23bfce
|
106 |
|
BL |
107 |
.. code-block:: text |
7534ba
|
108 |
|
CM |
109 |
locale/de/LC_MESSAGES/form.mo |
|
110 |
|
|
111 |
In other words, it would want to take translations from the ``form.mo`` |
|
112 |
translation file in the German language. |
|
113 |
|
d2b365
|
114 |
Finally, the TranslationString constructor accepts a ``default`` argument. If |
SP |
115 |
a ``default`` argument is supplied, it replaces usages of the ``msgid`` as the |
|
116 |
*default value* for the translation string. When ``default`` is ``None``, the |
|
117 |
``msgid`` value passed to a TranslationString is used as an implicit message |
|
118 |
identifier. Message identifiers are matched with translations in translation |
|
119 |
files, so it is often useful to create translation strings with "opaque" |
|
120 |
message identifiers unrelated to their default text: |
7534ba
|
121 |
|
CM |
122 |
.. code-block:: python |
|
123 |
:linenos: |
|
124 |
|
fec0f0
|
125 |
from pyramid.i18n import TranslationString |
7534ba
|
126 |
ts = TranslationString('add-number', default='Add ${number}', |
CM |
127 |
domain='form', mapping={'number':1}) |
|
128 |
|
d2b365
|
129 |
When default text is used, Default text objects may contain replacement values. |
7534ba
|
130 |
|
CM |
131 |
.. index:: |
|
132 |
single: translation string factory |
|
133 |
|
|
134 |
Using the ``TranslationStringFactory`` Class |
|
135 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
136 |
|
|
137 |
Another way to generate a translation string is to use the |
d2b365
|
138 |
:attr:`~pyramid.i18n.TranslationStringFactory` object. This object is a |
SP |
139 |
*translation string factory*. Basically a translation string factory presets |
|
140 |
the ``domain`` value of any :term:`translation string` generated by using it. |
|
141 |
For example: |
7534ba
|
142 |
|
CM |
143 |
.. code-block:: python |
|
144 |
:linenos: |
|
145 |
|
fec0f0
|
146 |
from pyramid.i18n import TranslationStringFactory |
CM |
147 |
_ = TranslationStringFactory('pyramid') |
c12653
|
148 |
ts = _('add-number', default='Add ${number}', mapping={'number':1}) |
7534ba
|
149 |
|
d2b365
|
150 |
.. note:: We assigned the translation string factory to the name ``_``. This |
SP |
151 |
is a convention which will be supported by translation file generation |
|
152 |
tools. |
7534ba
|
153 |
|
CM |
154 |
After assigning ``_`` to the result of a |
d2b365
|
155 |
:func:`~pyramid.i18n.TranslationStringFactory`, the subsequent result of |
SP |
156 |
calling ``_`` will be a :class:`~pyramid.i18n.TranslationString` instance. |
|
157 |
Even though a ``domain`` value was not passed to ``_`` (as would have been |
|
158 |
necessary if the :class:`~pyramid.i18n.TranslationString` constructor were used |
|
159 |
instead of a translation string factory), the ``domain`` attribute of the |
|
160 |
resulting translation string will be ``pyramid``. As a result, the previous |
|
161 |
code example is completely equivalent (except for spelling) to: |
7534ba
|
162 |
|
CM |
163 |
.. code-block:: python |
|
164 |
:linenos: |
|
165 |
|
fec0f0
|
166 |
from pyramid.i18n import TranslationString as _ |
c12653
|
167 |
ts = _('add-number', default='Add ${number}', mapping={'number':1}, |
fec0f0
|
168 |
domain='pyramid') |
7534ba
|
169 |
|
d2b365
|
170 |
You can set up your own translation string factory much like the one provided |
SP |
171 |
above by using the :class:`~pyramid.i18n.TranslationStringFactory` class. For |
|
172 |
example, if you'd like to create a translation string factory which presets the |
|
173 |
``domain`` value of generated translation strings to ``form``, you'd do |
|
174 |
something like this: |
7534ba
|
175 |
|
CM |
176 |
.. code-block:: python |
|
177 |
:linenos: |
|
178 |
|
fec0f0
|
179 |
from pyramid.i18n import TranslationStringFactory |
7534ba
|
180 |
_ = TranslationStringFactory('form') |
c12653
|
181 |
ts = _('add-number', default='Add ${number}', mapping={'number':1}) |
7534ba
|
182 |
|
d2b365
|
183 |
Creating a unique domain for your application via a translation string factory |
SP |
184 |
is best practice. Using your own unique translation domain allows another |
|
185 |
person to reuse your application without needing to merge your translation |
|
186 |
files with their own. Instead they can just include your package's |
|
187 |
:term:`translation directory` via the |
|
188 |
:meth:`pyramid.config.Configurator.add_translation_dirs` method. |
7534ba
|
189 |
|
CM |
190 |
.. note:: |
|
191 |
|
|
192 |
For people familiar with Zope internationalization, a |
|
193 |
TranslationStringFactory is a lot like a |
d2b365
|
194 |
``zope.i18nmessageid.MessageFactory`` object. It is not a subclass, |
SP |
195 |
however. |
7534ba
|
196 |
|
CM |
197 |
.. index:: |
|
198 |
single: gettext |
|
199 |
single: translation directories |
|
200 |
|
d2b365
|
201 |
Working with ``gettext`` Translation Files |
7534ba
|
202 |
------------------------------------------ |
CM |
203 |
|
d2b365
|
204 |
The basis of :app:`Pyramid` translation services is GNU :term:`gettext`. Once |
SP |
205 |
your application source code files and templates are marked up with translation |
|
206 |
markers, you can work on translations by creating various kinds of gettext |
|
207 |
files. |
7534ba
|
208 |
|
CM |
209 |
.. note:: |
|
210 |
|
d2b365
|
211 |
The steps a developer must take to work with :term:`gettext` :term:`message |
SP |
212 |
catalog` files within a :app:`Pyramid` application are very similar to the |
|
213 |
steps a :term:`Pylons` developer must take to do the same. See the |
|
214 |
:ref:`Pylons Internationalization and Localization documentation |
82862b
|
215 |
<pylonswebframework:i18n>` for more information. |
b5dc7f
|
216 |
|
d2b365
|
217 |
GNU gettext uses three types of files in the translation framework, ``.pot`` |
SP |
218 |
files, ``.po`` files, and ``.mo`` files. |
b5dc7f
|
219 |
|
CM |
220 |
``.pot`` (Portable Object Template) files |
|
221 |
|
d2b365
|
222 |
A ``.pot`` file is created by a program which searches through your project's |
SP |
223 |
source code and which picks out every :term:`message identifier` passed to |
|
224 |
one of the ``_()`` functions (e.g., :term:`translation string` |
|
225 |
constructions). The list of all message identifiers is placed into a ``.pot`` |
|
226 |
file, which serves as a template for creating ``.po`` files. |
b5dc7f
|
227 |
|
CM |
228 |
``.po`` (Portable Object) files |
|
229 |
|
d2b365
|
230 |
The list of messages in a ``.pot`` file are translated by a human to a |
SP |
231 |
particular language; the result is saved as a ``.po`` file. |
b5dc7f
|
232 |
|
CM |
233 |
``.mo`` (Machine Object) files |
|
234 |
|
d2b365
|
235 |
A ``.po`` file is turned into a machine-readable binary file, which is the |
SP |
236 |
``.mo`` file. Compiling the translations to machine code makes the |
|
237 |
localized program start faster. |
b5dc7f
|
238 |
|
5119ae
|
239 |
The tools for working with :term:`gettext` translation files related to a |
d2b365
|
240 |
:app:`Pyramid` application are :term:`Lingua` and :term:`Gettext`. Lingua can |
SP |
241 |
scrape i18n references out of Python and Chameleon files and create the |
|
242 |
``.pot`` file. Gettext includes ``msgmerge`` tool to update a ``.po`` file from |
|
243 |
an updated ``.pot`` file and ``msgfmt`` to compile ``.po`` files to ``.mo`` |
|
244 |
files. |
7534ba
|
245 |
|
CM |
246 |
.. index:: |
e4dc74
|
247 |
single: Gettext |
5119ae
|
248 |
single: Lingua |
7534ba
|
249 |
|
CM |
250 |
.. _installing_babel: |
|
251 |
|
e4dc74
|
252 |
Installing Lingua and Gettext |
WA |
253 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7534ba
|
254 |
|
d2b365
|
255 |
In order for the commands related to working with ``gettext`` translation files |
SP |
256 |
to work properly, you will need to have :term:`Lingua` and :term:`Gettext` |
|
257 |
installed into the same environment in which :app:`Pyramid` is installed. |
7534ba
|
258 |
|
CM |
259 |
Installation on UNIX |
|
260 |
++++++++++++++++++++ |
|
261 |
|
e4dc74
|
262 |
Gettext is often already installed on UNIX systems. You can check if it is |
WA |
263 |
installed by testing if the ``msgfmt`` command is available. If it is not |
d2b365
|
264 |
available you can install it through the packaging system from your OS; the |
SP |
265 |
package name is almost always ``gettext``. For example on a Debian or Ubuntu |
|
266 |
system run this command: |
e4dc74
|
267 |
|
c843d6
|
268 |
.. code-block:: bash |
e4dc74
|
269 |
|
WA |
270 |
$ sudo apt-get install gettext |
|
271 |
|
|
272 |
Installing Lingua is done with the Python packaging tools. If the |
d67566
|
273 |
:term:`virtual environment` into which you've installed your :app:`Pyramid` |
c843d6
|
274 |
application lives at the environment variable ``$VENV``, you can install Lingua |
SP |
275 |
like so: |
7534ba
|
276 |
|
c843d6
|
277 |
.. code-block:: bash |
7534ba
|
278 |
|
c843d6
|
279 |
$ $VENV/bin/pip install lingua |
7534ba
|
280 |
|
CM |
281 |
Installation on Windows |
|
282 |
+++++++++++++++++++++++ |
|
283 |
|
e4dc74
|
284 |
There are several ways to install Gettext on Windows: it is included in the |
WA |
285 |
`Cygwin <http://www.cygwin.com/>`_ collection, or you can use the `installer |
d2b365
|
286 |
from the GnuWin32 <http://gnuwin32.sourceforge.net/packages/gettext.htm>`_, or |
SP |
287 |
compile it yourself. Make sure the installation path is added to your |
e4dc74
|
288 |
``$PATH``. |
WA |
289 |
|
|
290 |
Installing Lingua is done with the Python packaging tools. If the |
d67566
|
291 |
:term:`virtual environment` into which you've installed your :app:`Pyramid` |
c843d6
|
292 |
application lives at the environment variable ``%VENV%``, you can install |
SP |
293 |
Lingua like so: |
7534ba
|
294 |
|
a651b3
|
295 |
.. code-block:: doscon |
7534ba
|
296 |
|
108121
|
297 |
c:\> %VENV%\Scripts\pip install lingua |
7534ba
|
298 |
|
5c5f7a
|
299 |
|
CM |
300 |
.. index:: |
7534ba
|
301 |
pair: extracting; messages |
b5dc7f
|
302 |
|
CM |
303 |
.. _extracting_messages: |
7534ba
|
304 |
|
CM |
305 |
Extracting Messages from Code and Templates |
|
306 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
307 |
|
d2b365
|
308 |
Once Lingua is installed, you may extract a message catalog template from the |
e4dc74
|
309 |
code and :term:`Chameleon` templates which reside in your :app:`Pyramid` |
WA |
310 |
application. You run a ``pot-create`` command to extract the messages: |
5c5f7a
|
311 |
|
c843d6
|
312 |
.. code-block:: bash |
7534ba
|
313 |
|
c843d6
|
314 |
$ cd /file/path/to/myapplication_setup.py |
7534ba
|
315 |
$ mkdir -p myapplication/locale |
5e6160
|
316 |
$ $VENV/bin/pot-create -o myapplication/locale/myapplication.pot src |
7534ba
|
317 |
|
d2b365
|
318 |
The message catalog ``.pot`` template will end up in |
7534ba
|
319 |
``myapplication/locale/myapplication.pot``. |
b5dc7f
|
320 |
|
7534ba
|
321 |
|
CM |
322 |
.. index:: |
8e3b34
|
323 |
pair: initializing; message catalog |
7534ba
|
324 |
|
8e3b34
|
325 |
Initializing a Message Catalog File |
CM |
326 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7534ba
|
327 |
|
b5dc7f
|
328 |
Once you've extracted messages into a ``.pot`` file (see |
d2b365
|
329 |
:ref:`extracting_messages`), to begin localizing the messages present in the |
SP |
330 |
``.pot`` file, you need to generate at least one ``.po`` file. A ``.po`` file |
|
331 |
represents translations of a particular set of messages to a particular locale. |
|
332 |
Initialize a ``.po`` file for a specific locale from a pre-generated ``.pot`` |
|
333 |
template by using the ``msginit`` command from Gettext: |
23bfce
|
334 |
|
c843d6
|
335 |
.. code-block:: bash |
7534ba
|
336 |
|
c843d6
|
337 |
$ cd /file/path/to/myapplication_setup.py |
e4dc74
|
338 |
$ cd myapplication/locale |
WA |
339 |
$ mkdir -p es/LC_MESSAGES |
b4245a
|
340 |
$ msginit -l es -o es/LC_MESSAGES/myapplication.po |
7534ba
|
341 |
|
d2b365
|
342 |
This will create a new message catalog ``.po`` file in |
7534ba
|
343 |
``myapplication/locale/es/LC_MESSAGES/myapplication.po``. |
CM |
344 |
|
d2b365
|
345 |
Once the file is there, it can be worked on by a human translator. One tool |
1cb30e
|
346 |
which may help with this is `Poedit <https://poedit.net/>`_. |
b5dc7f
|
347 |
|
d2b365
|
348 |
Note that :app:`Pyramid` itself ignores the existence of all ``.po`` files. |
SP |
349 |
For a running application to have translations available, a ``.mo`` file must |
|
350 |
exist. See :ref:`compiling_message_catalog`. |
7534ba
|
351 |
|
CM |
352 |
.. index:: |
|
353 |
pair: updating; message catalog |
|
354 |
|
|
355 |
Updating a Catalog File |
|
356 |
~~~~~~~~~~~~~~~~~~~~~~~ |
|
357 |
|
d2b365
|
358 |
If more translation strings are added to your application, or translation |
SP |
359 |
strings change, you will need to update existing ``.po`` files based on changes |
|
360 |
to the ``.pot`` file, so that the new and changed messages can also be |
|
361 |
translated or re-translated. |
b5dc7f
|
362 |
|
d2b365
|
363 |
First, regenerate the ``.pot`` file as per :ref:`extracting_messages`. Then use |
SP |
364 |
the ``msgmerge`` command from Gettext. |
b5dc7f
|
365 |
|
c843d6
|
366 |
.. code-block:: bash |
7534ba
|
367 |
|
c843d6
|
368 |
$ cd /file/path/to/myapplication_setup.py |
e4dc74
|
369 |
$ cd myapplication/locale |
WA |
370 |
$ msgmerge --update es/LC_MESSAGES/myapplication.po myapplication.pot |
7534ba
|
371 |
|
CM |
372 |
.. index:: |
|
373 |
pair: compiling; message catalog |
b5dc7f
|
374 |
|
CM |
375 |
.. _compiling_message_catalog: |
7534ba
|
376 |
|
CM |
377 |
Compiling a Message Catalog File |
|
378 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
379 |
|
d2b365
|
380 |
Finally, to prepare an application for performing actual runtime translations, |
SP |
381 |
compile ``.po`` files to ``.mo`` files using the ``msgfmt`` command from |
|
382 |
Gettext: |
23bfce
|
383 |
|
c843d6
|
384 |
.. code-block:: bash |
7534ba
|
385 |
|
c843d6
|
386 |
$ cd /file/path/to/myapplication_setup.py |
d2b365
|
387 |
$ msgfmt -o myapplication/locale/es/LC_MESSAGES/myapplication.mo \ |
SP |
388 |
myapplication/locale/es/LC_MESSAGES/myapplication.po |
7534ba
|
389 |
|
02801e
|
390 |
This will create a ``.mo`` file for each ``.po`` file in your application. As |
SP |
391 |
long as the :term:`translation directory` in which the ``.mo`` file ends up in |
|
392 |
is configured into your application (see |
d2b365
|
393 |
:ref:`adding_a_translation_directory`), these translations will be available to |
SP |
394 |
:app:`Pyramid`. |
7534ba
|
395 |
|
CM |
396 |
.. index:: |
|
397 |
single: localizer |
6ce1e0
|
398 |
single: translation |
CM |
399 |
single: pluralization |
7534ba
|
400 |
|
CM |
401 |
Using a Localizer |
|
402 |
----------------- |
|
403 |
|
70acd2
|
404 |
A :term:`localizer` is an object that allows you to perform translation or |
d2b365
|
405 |
pluralization "by hand" in an application. You may use the |
SP |
406 |
:attr:`pyramid.request.Request.localizer` attribute to obtain a |
|
407 |
:term:`localizer`. The localizer object will be configured to produce |
|
408 |
translations implied by the active :term:`locale negotiator`, or a default |
330164
|
409 |
localizer object if no explicit locale negotiator is registered. |
7534ba
|
410 |
|
CM |
411 |
.. code-block:: python |
|
412 |
:linenos: |
|
413 |
|
|
414 |
def aview(request): |
330164
|
415 |
localizer = request.localizer |
7534ba
|
416 |
|
012b97
|
417 |
.. note:: |
M |
418 |
|
d2b365
|
419 |
If you need to create a localizer for a locale, use the |
86bbe8
|
420 |
:func:`pyramid.i18n.make_localizer` function. |
CL |
421 |
|
7534ba
|
422 |
.. index:: |
CM |
423 |
single: translating (i18n) |
|
424 |
|
|
425 |
.. _performing_a_translation: |
|
426 |
|
|
427 |
Performing a Translation |
|
428 |
~~~~~~~~~~~~~~~~~~~~~~~~ |
|
429 |
|
|
430 |
A :term:`localizer` has a ``translate`` method which accepts either a |
d2b365
|
431 |
:term:`translation string` or a Unicode string and which returns a Unicode |
SP |
432 |
object representing the translation. Generating a translation in a view |
|
433 |
component of an application might look like so: |
7534ba
|
434 |
|
CM |
435 |
.. code-block:: python |
|
436 |
:linenos: |
|
437 |
|
fec0f0
|
438 |
from pyramid.i18n import TranslationString |
7534ba
|
439 |
|
879bb5
|
440 |
ts = TranslationString('Add ${number}', mapping={'number':1}, |
fec0f0
|
441 |
domain='pyramid') |
7534ba
|
442 |
|
CM |
443 |
def aview(request): |
330164
|
444 |
localizer = request.localizer |
7534ba
|
445 |
translated = localizer.translate(ts) # translation string |
CM |
446 |
# ... use translated ... |
|
447 |
|
330164
|
448 |
The ``request.localizer`` attribute will be a :class:`pyramid.i18n.Localizer` |
CM |
449 |
object bound to the locale name represented by the request. The translation |
|
450 |
returned from its :meth:`pyramid.i18n.Localizer.translate` method will depend |
|
451 |
on the ``domain`` attribute of the provided translation string as well as the |
7534ba
|
452 |
locale of the localizer. |
CM |
453 |
|
012b97
|
454 |
.. note:: |
M |
455 |
|
d2b365
|
456 |
If you're using :term:`Chameleon` templates, you don't need to pre-translate |
SP |
457 |
translation strings this way. See :ref:`chameleon_translation_strings`. |
7534ba
|
458 |
|
CM |
459 |
.. index:: |
|
460 |
single: pluralizing (i18n) |
|
461 |
|
|
462 |
.. _performing_a_pluralization: |
|
463 |
|
|
464 |
Performing a Pluralization |
|
465 |
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
466 |
|
d2b365
|
467 |
A :term:`localizer` has a ``pluralize`` method with the following signature: |
7534ba
|
468 |
|
CM |
469 |
.. code-block:: python |
|
470 |
:linenos: |
|
471 |
|
|
472 |
def pluralize(singular, plural, n, domain=None, mapping=None): |
|
473 |
... |
|
474 |
|
221fff
|
475 |
The simplest case is the ``singular`` and ``plural`` arguments being passed as |
d2b365
|
476 |
Unicode literals. This returns the appropriate literal according to the locale |
221fff
|
477 |
pluralization rules for the number ``n``, and interpolates ``mapping``. |
7534ba
|
478 |
|
CM |
479 |
.. code-block:: python |
|
480 |
:linenos: |
|
481 |
|
|
482 |
def aview(request): |
330164
|
483 |
localizer = request.localizer |
7534ba
|
484 |
translated = localizer.pluralize('Item', 'Items', 1, 'mydomain') |
CM |
485 |
# ... use translated ... |
|
486 |
|
d2b365
|
487 |
However, for support of other languages, the ``singular`` argument should be a |
SP |
488 |
Unicode value representing a :term:`message identifier`. In this case the |
|
489 |
``plural`` value is ignored. ``domain`` should be a :term:`translation domain`, |
|
490 |
and ``mapping`` should be a dictionary that is used for *replacement value* |
|
491 |
interpolation of the translated string. |
221fff
|
492 |
|
MW |
493 |
The value of ``n`` will be used to find the appropriate plural form for the |
d2b365
|
494 |
current language, and ``pluralize`` will return a Unicode translation for the |
221fff
|
495 |
message id ``singular``. The message file must have defined ``singular`` as a |
MW |
496 |
translation with plural forms. |
|
497 |
|
|
498 |
The argument provided as ``singular`` may be a :term:`translation string` |
|
499 |
object, but the domain and mapping information attached is ignored. |
|
500 |
|
|
501 |
.. code-block:: python |
|
502 |
:linenos: |
|
503 |
|
|
504 |
def aview(request): |
330164
|
505 |
localizer = request.localizer |
221fff
|
506 |
num = 1 |
543113
|
507 |
translated = localizer.pluralize('item_plural', '${number} items', |
MW |
508 |
num, 'mydomain', mapping={'number':num}) |
221fff
|
509 |
|
MW |
510 |
The corresponding message catalog must have language plural definitions and |
|
511 |
plural alternatives set. |
|
512 |
|
|
513 |
.. code-block:: text |
|
514 |
:linenos: |
|
515 |
|
|
516 |
"Plural-Forms: nplurals=3; plural=n==0 ? 0 : n==1 ? 1 : 2;" |
|
517 |
|
|
518 |
msgid "item_plural" |
|
519 |
msgid_plural "" |
|
520 |
msgstr[0] "No items" |
|
521 |
msgstr[1] "${number} item" |
|
522 |
msgstr[2] "${number} items" |
|
523 |
|
|
524 |
More information on complex plurals can be found in the `gettext documentation |
|
525 |
<https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/Plural-forms.html>`_. |
|
526 |
|
7534ba
|
527 |
.. index:: |
CM |
528 |
single: locale name |
|
529 |
single: negotiate_locale_name |
|
530 |
|
|
531 |
.. _obtaining_the_locale_name: |
|
532 |
|
|
533 |
Obtaining the Locale Name for a Request |
|
534 |
--------------------------------------- |
|
535 |
|
|
536 |
You can obtain the locale name related to a request by using the |
330164
|
537 |
:func:`pyramid.request.Request.locale_name` attribute of the request. |
7534ba
|
538 |
|
CM |
539 |
.. code-block:: python |
|
540 |
:linenos: |
|
541 |
|
|
542 |
def aview(request): |
330164
|
543 |
locale_name = request.locale_name |
7534ba
|
544 |
|
d2b365
|
545 |
The locale name of a request is dynamically computed; it will be the locale |
SP |
546 |
name negotiated by the currently active :term:`locale negotiator`, or the |
|
547 |
:term:`default locale name` if the locale negotiator returns ``None``. You can |
|
548 |
change the default locale name by changing the ``pyramid.default_locale_name`` |
|
549 |
setting. See :ref:`default_locale_name_setting`. |
7534ba
|
550 |
|
d2b365
|
551 |
Once :func:`~pyramid.request.Request.locale_name` is first run, the locale name |
SP |
552 |
is stored on the request object. Subsequent calls to |
|
553 |
:func:`~pyramid.request.Request.locale_name` will return the stored locale name |
|
554 |
without invoking the :term:`locale negotiator`. To avoid this caching, you can |
|
555 |
use the :func:`pyramid.i18n.negotiate_locale_name` function: |
7534ba
|
556 |
|
CM |
557 |
.. code-block:: python |
|
558 |
:linenos: |
|
559 |
|
fec0f0
|
560 |
from pyramid.i18n import negotiate_locale_name |
7534ba
|
561 |
|
CM |
562 |
def aview(request): |
|
563 |
locale_name = negotiate_locale_name(request) |
|
564 |
|
|
565 |
You can also obtain the locale name related to a request using the |
|
566 |
``locale_name`` attribute of a :term:`localizer`. |
|
567 |
|
533849
|
568 |
.. code-block:: python |
CM |
569 |
:linenos: |
|
570 |
|
7534ba
|
571 |
def aview(request): |
330164
|
572 |
localizer = request.localizer |
7534ba
|
573 |
locale_name = localizer.locale_name |
CM |
574 |
|
d2b365
|
575 |
Obtaining the locale name as an attribute of a localizer is equivalent to |
SP |
576 |
obtaining a locale name by asking for the |
330164
|
577 |
:func:`~pyramid.request.Request.locale_name` attribute. |
7534ba
|
578 |
|
CM |
579 |
.. index:: |
|
580 |
single: date and currency formatting (i18n) |
|
581 |
single: Babel |
|
582 |
|
|
583 |
Performing Date Formatting and Currency Formatting |
|
584 |
-------------------------------------------------- |
|
585 |
|
d2b365
|
586 |
:app:`Pyramid` does not itself perform date and currency formatting for |
SP |
587 |
different locales. However, :term:`Babel` can help you do this via the |
|
588 |
:class:`babel.core.Locale` class. The `Babel documentation for this class |
8d212a
|
589 |
<http://babel.pocoo.org/en/latest/api/core.html#basic-interface>`_ provides |
SP |
590 |
minimal information about how to perform date and currency related locale |
|
591 |
operations. See :ref:`installing_babel` for information about how to install |
|
592 |
Babel. |
7534ba
|
593 |
|
d2b365
|
594 |
The :class:`babel.core.Locale` class requires a :term:`locale name` as an |
SP |
595 |
argument to its constructor. You can use :app:`Pyramid` APIs to obtain the |
|
596 |
locale name for a request to pass to the :class:`babel.core.Locale` |
|
597 |
constructor. See :ref:`obtaining_the_locale_name`. For example: |
7534ba
|
598 |
|
CM |
599 |
.. code-block:: python |
|
600 |
:linenos: |
|
601 |
|
|
602 |
from babel.core import Locale |
|
603 |
|
|
604 |
def aview(request): |
330164
|
605 |
locale_name = request.locale_name |
7534ba
|
606 |
locale = Locale(locale_name) |
CM |
607 |
|
|
608 |
.. index:: |
|
609 |
pair: translation strings; Chameleon |
|
610 |
|
|
611 |
.. _chameleon_translation_strings: |
|
612 |
|
|
613 |
Chameleon Template Support for Translation Strings |
|
614 |
-------------------------------------------------- |
|
615 |
|
d2b365
|
616 |
When a :term:`translation string` is used as the subject of textual rendering |
SP |
617 |
by a :term:`Chameleon` template renderer, it will automatically be translated |
|
618 |
to the requesting user's language if a suitable translation exists. This is |
|
619 |
true of both the ZPT and text variants of the Chameleon template renderers. |
7534ba
|
620 |
|
d2b365
|
621 |
For example, in a Chameleon ZPT template, the translation string represented by |
SP |
622 |
"some_translation_string" in each example below will go through translation |
|
623 |
before being rendered: |
7534ba
|
624 |
|
CM |
625 |
.. code-block:: xml |
|
626 |
:linenos: |
|
627 |
|
|
628 |
<span tal:content="some_translation_string"/> |
|
629 |
|
|
630 |
.. code-block:: xml |
|
631 |
:linenos: |
|
632 |
|
|
633 |
<span tal:replace="some_translation_string"/> |
|
634 |
|
|
635 |
.. code-block:: xml |
|
636 |
:linenos: |
|
637 |
|
|
638 |
<span>${some_translation_string}</span> |
|
639 |
|
|
640 |
.. code-block:: xml |
|
641 |
:linenos: |
|
642 |
|
|
643 |
<a tal:attributes="href some_translation_string">Click here</a> |
05d032
|
644 |
|
CM |
645 |
.. XXX the last example above appears to not yet work as of Chameleon |
|
646 |
.. 1.2.3 |
7534ba
|
647 |
|
d2b365
|
648 |
The features represented by attributes of the ``i18n`` namespace of Chameleon |
SP |
649 |
will also consult the :app:`Pyramid` translations. See |
1cb30e
|
650 |
http://chameleon.readthedocs.org/en/latest/reference.html#translation-i18n. |
7534ba
|
651 |
|
CM |
652 |
.. note:: |
|
653 |
|
d2b365
|
654 |
Unlike when Chameleon is used outside of :app:`Pyramid`, when it is used |
SP |
655 |
*within* :app:`Pyramid`, it does not support use of the ``zope.i18n`` |
|
656 |
translation framework. Applications which use :app:`Pyramid` should use the |
|
657 |
features documented in this chapter rather than ``zope.i18n``. |
7534ba
|
658 |
|
d2b365
|
659 |
Third party :app:`Pyramid` template renderers might not provide this support |
SP |
660 |
out of the box and may need special code to do an equivalent. For those, you |
|
661 |
can always use the more manual translation facility described in |
|
662 |
:ref:`performing_a_translation`. |
7534ba
|
663 |
|
6ce1e0
|
664 |
.. index:: |
CM |
665 |
single: Mako i18n |
|
666 |
|
d2b365
|
667 |
Mako Pyramid i18n Support |
ddf07e
|
668 |
------------------------- |
CM |
669 |
|
34515f
|
670 |
There exists a recipe within the :term:`Pyramid Community Cookbook` named |
SP |
671 |
:ref:`Mako Internationalization <cookbook:mako_i18n>` which explains how to add |
|
672 |
idiomatic i18n support to :term:`Mako` templates. |
ddf07e
|
673 |
|
88c92b
|
674 |
|
SP |
675 |
.. index:: |
|
676 |
single: Jinja2 i18n |
|
677 |
|
|
678 |
Jinja2 Pyramid i18n Support |
|
679 |
--------------------------- |
|
680 |
|
|
681 |
The add-on `pyramid_jinja2 <https://github.com/Pylons/pyramid_jinja2>`_ |
|
682 |
provides a scaffold with an example of how to use internationalization with |
|
683 |
Jinja2 in Pyramid. See the documentation sections `Internalization (i18n) |
19d341
|
684 |
<https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#internalization-i18n>`_ |
88c92b
|
685 |
and `Paster Template I18N |
19d341
|
686 |
<https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#paster-template-i18n>`_. |
88c92b
|
687 |
|
SP |
688 |
|
7534ba
|
689 |
.. index:: |
CM |
690 |
single: localization deployment settings |
|
691 |
single: default_locale_name |
|
692 |
|
|
693 |
.. _localization_deployment_settings: |
|
694 |
|
|
695 |
Localization-Related Deployment Settings |
|
696 |
---------------------------------------- |
|
697 |
|
875ded
|
698 |
A :app:`Pyramid` application will have a ``pyramid.default_locale_name`` |
d2b365
|
699 |
setting. This value represents the :term:`default locale name` used when the |
SP |
700 |
:term:`locale negotiator` returns ``None``. Pass it to the |
|
701 |
:mod:`~pyramid.config.Configurator` constructor at startup time: |
7534ba
|
702 |
|
CM |
703 |
.. code-block:: python |
|
704 |
:linenos: |
|
705 |
|
d7f259
|
706 |
from pyramid.config import Configurator |
875ded
|
707 |
config = Configurator(settings={'pyramid.default_locale_name':'de'}) |
7534ba
|
708 |
|
875ded
|
709 |
You may alternately supply a ``pyramid.default_locale_name`` via an |
f8869c
|
710 |
application's ``.ini`` file: |
7534ba
|
711 |
|
CM |
712 |
.. code-block:: ini |
|
713 |
:linenos: |
|
714 |
|
|
715 |
[app:main] |
3d338e
|
716 |
use = egg:MyProject |
875ded
|
717 |
pyramid.reload_templates = true |
MM |
718 |
pyramid.debug_authorization = false |
|
719 |
pyramid.debug_notfound = false |
|
720 |
pyramid.default_locale_name = de |
7534ba
|
721 |
|
d2b365
|
722 |
If this value is not supplied via the Configurator constructor or via a config |
SP |
723 |
file, it will default to ``en``. |
7534ba
|
724 |
|
d2b365
|
725 |
If this setting is supplied within the :app:`Pyramid` application ``.ini`` |
SP |
726 |
file, it will be available as a settings key: |
7534ba
|
727 |
|
CM |
728 |
.. code-block:: python |
|
729 |
:linenos: |
|
730 |
|
b68aad
|
731 |
from pyramid.threadlocal import get_current_registry |
CM |
732 |
settings = get_current_registry().settings |
875ded
|
733 |
default_locale_name = settings['pyramid.default_locale_name'] |
6ce1e0
|
734 |
|
CM |
735 |
.. index:: |
00f9fe
|
736 |
single: detecting languages |
7534ba
|
737 |
|
2f935c
|
738 |
"Detecting" Available Languages |
CM |
739 |
------------------------------- |
|
740 |
|
d2b365
|
741 |
Other systems provide an API that returns the set of "available languages" as |
SP |
742 |
indicated by the union of all languages in all translation directories on disk |
|
743 |
at the time of the call to the API. |
2f935c
|
744 |
|
d2b365
|
745 |
It is by design that :app:`Pyramid` doesn't supply such an API. Instead the |
SP |
746 |
application itself is responsible for knowing the "available languages". The |
|
747 |
rationale is this: any particular application deployment must always know which |
|
748 |
languages it should be translatable to anyway, regardless of which translation |
|
749 |
files are on disk. |
2f935c
|
750 |
|
d2b365
|
751 |
Here's why: it's not a given that because translations exist in a particular |
SP |
752 |
language within the registered set of translation directories that this |
|
753 |
particular deployment wants to allow translation to that language. For |
|
754 |
example, some translations may exist but they may be incomplete or incorrect. |
|
755 |
Or there may be translations to a language but not for all translation domains. |
2f935c
|
756 |
|
CM |
757 |
Any nontrivial application deployment will always need to be able to |
d2b365
|
758 |
selectively choose to allow only some languages even if that set of languages |
SP |
759 |
is smaller than all those detected within registered translation directories. |
|
760 |
The easiest way to allow for this is to make the application entirely |
|
761 |
responsible for knowing which languages are allowed to be translated to instead |
|
762 |
of relying on the framework to divine this information from translation |
|
763 |
directory file info. |
2f935c
|
764 |
|
d2b365
|
765 |
You can set up a system to allow a deployer to select available languages based |
SP |
766 |
on convention by using the :mod:`pyramid.settings` mechanism. |
2f935c
|
767 |
|
f8869c
|
768 |
Allow a deployer to modify your application's ``.ini`` file: |
2f935c
|
769 |
|
CM |
770 |
.. code-block:: ini |
23bfce
|
771 |
:linenos: |
2f935c
|
772 |
|
CM |
773 |
[app:main] |
3d338e
|
774 |
use = egg:MyProject |
23bfce
|
775 |
# ... |
2f935c
|
776 |
available_languages = fr de en ru |
CM |
777 |
|
|
778 |
Then as a part of the code of a custom :term:`locale negotiator`: |
|
779 |
|
23bfce
|
780 |
.. code-block:: python |
BL |
781 |
:linenos: |
879bb5
|
782 |
|
ddc745
|
783 |
from pyramid.settings import aslist |
TT |
784 |
|
|
785 |
def my_locale_negotiator(request): |
|
786 |
languages = aslist(request.registry.settings['available_languages']) |
|
787 |
# ... |
2f935c
|
788 |
|
d2b365
|
789 |
This is only a suggestion. You can create your own "available languages" |
SP |
790 |
configuration scheme as necessary. |
2f935c
|
791 |
|
7534ba
|
792 |
.. index:: |
CM |
793 |
pair: translation; activating |
|
794 |
pair: locale; negotiator |
|
795 |
single: translation directory |
|
796 |
|
6ce1e0
|
797 |
.. index:: |
CM |
798 |
pair: activating; translation |
|
799 |
|
7534ba
|
800 |
.. _activating_translation: |
CM |
801 |
|
|
802 |
Activating Translation |
|
803 |
---------------------- |
|
804 |
|
d2b365
|
805 |
By default, a :app:`Pyramid` application performs no translation. To turn |
SP |
806 |
translation on you must: |
7534ba
|
807 |
|
12cb6d
|
808 |
- add at least one :term:`translation directory` to your application. |
7534ba
|
809 |
|
b5dc7f
|
810 |
- ensure that your application sets the :term:`locale name` correctly. |
6ce1e0
|
811 |
|
CM |
812 |
.. index:: |
|
813 |
pair: translation directory; adding |
12cb6d
|
814 |
|
f8ed00
|
815 |
.. _adding_a_translation_directory: |
CM |
816 |
|
12cb6d
|
817 |
Adding a Translation Directory |
CM |
818 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
7534ba
|
819 |
|
d2b365
|
820 |
:term:`gettext` is the underlying machinery behind the :app:`Pyramid` |
SP |
821 |
translation machinery. A translation directory is a directory organized to be |
|
822 |
useful to :term:`gettext`. A translation directory usually includes a listing |
|
823 |
of language directories, each of which itself includes an ``LC_MESSAGES`` |
|
824 |
directory. Each ``LC_MESSAGES`` directory should contain one or more ``.mo`` |
|
825 |
files. Each ``.mo`` file represents a :term:`message catalog`, which is used to |
|
826 |
provide translations to your application. |
7534ba
|
827 |
|
4d4173
|
828 |
Adding a :term:`translation directory` registers all of its constituent |
d2b365
|
829 |
:term:`message catalog` files within your :app:`Pyramid` application to be |
SP |
830 |
available to use for translation services. This includes all of the ``.mo`` |
|
831 |
files found within all ``LC_MESSAGES`` directories within each locale directory |
|
832 |
in the translation directory. |
7534ba
|
833 |
|
f8ed00
|
834 |
You can add a translation directory imperatively by using the |
d2b365
|
835 |
:meth:`pyramid.config.Configurator.add_translation_dirs` during application |
SP |
836 |
startup. For example: |
7534ba
|
837 |
|
f8ed00
|
838 |
.. code-block:: python |
CM |
839 |
:linenos: |
7534ba
|
840 |
|
d7f259
|
841 |
from pyramid.config import Configurator |
879bb5
|
842 |
config.add_translation_dirs('my.application:locale/', |
f8ed00
|
843 |
'another.application:locale/') |
7534ba
|
844 |
|
f8ed00
|
845 |
A message catalog in a translation directory added via |
d2b365
|
846 |
:meth:`~pyramid.config.Configurator.add_translation_dirs` will be merged into |
SP |
847 |
translations from a message catalog added earlier if both translation |
|
848 |
directories contain translations for the same locale and :term:`translation |
|
849 |
domain`. |
7534ba
|
850 |
|
6ce1e0
|
851 |
.. index:: |
CM |
852 |
pair: setting; locale |
|
853 |
|
12cb6d
|
854 |
Setting the Locale |
CM |
855 |
~~~~~~~~~~~~~~~~~~ |
7534ba
|
856 |
|
d2b365
|
857 |
When the *default locale negotiator* (see :ref:`default_locale_negotiator`) is |
SP |
858 |
in use, you can inform :app:`Pyramid` of the current locale name by doing any |
|
859 |
of these things before any translations need to be performed: |
12cb6d
|
860 |
|
d2b365
|
861 |
- Set the ``_LOCALE_`` attribute of the request to a valid locale name (usually |
SP |
862 |
directly within view code), e.g., ``request._LOCALE_ = 'de'``. |
12cb6d
|
863 |
|
d2b365
|
864 |
- Ensure that a valid locale name value is in the ``request.params`` dictionary |
SP |
865 |
under the key named ``_LOCALE_``. This is usually the result of passing a |
|
866 |
``_LOCALE_`` value in the query string or in the body of a form post |
|
867 |
associated with a request. For example, visiting |
|
868 |
``http://my.application?_LOCALE_=de``. |
12cb6d
|
869 |
|
CM |
870 |
- Ensure that a valid locale name value is in the ``request.cookies`` |
d2b365
|
871 |
dictionary under the key named ``_LOCALE_``. This is usually the result of |
SP |
872 |
setting a ``_LOCALE_`` cookie in a prior response, e.g., |
|
873 |
``response.set_cookie('_LOCALE_', 'de')``. |
12cb6d
|
874 |
|
CM |
875 |
.. note:: |
|
876 |
|
|
877 |
If this locale negotiation scheme is inappropriate for a particular |
d2b365
|
878 |
application, you can configure a custom :term:`locale negotiator` function |
SP |
879 |
into that application as required. See :ref:`custom_locale_negotiator`. |
12cb6d
|
880 |
|
6ce1e0
|
881 |
.. index:: |
CM |
882 |
single: locale negotiator |
|
883 |
|
12cb6d
|
884 |
.. _locale_negotiators: |
CM |
885 |
|
|
886 |
Locale Negotiators |
|
887 |
------------------ |
7534ba
|
888 |
|
d2b365
|
889 |
A :term:`locale negotiator` informs the operation of a :term:`localizer` by |
SP |
890 |
telling it what :term:`locale name` is related to a particular request. A |
|
891 |
locale negotiator is a bit of code which accepts a request and which returns a |
|
892 |
:term:`locale name`. It is consulted when |
|
893 |
:meth:`pyramid.i18n.Localizer.translate` or |
|
894 |
:meth:`pyramid.i18n.Localizer.pluralize` is invoked. It is also consulted when |
|
895 |
:func:`~pyramid.request.Request.locale_name` is accessed or when |
|
896 |
:func:`~pyramid.i18n.negotiate_locale_name` is invoked. |
7534ba
|
897 |
|
12cb6d
|
898 |
.. _default_locale_negotiator: |
CM |
899 |
|
|
900 |
The Default Locale Negotiator |
|
901 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
902 |
|
d2b365
|
903 |
Most applications can make use of the default locale negotiator, which requires |
SP |
904 |
no additional coding or configuration. |
12cb6d
|
905 |
|
CM |
906 |
The default locale negotiator implementation named |
d2b365
|
907 |
:class:`~pyramid.i18n.default_locale_negotiator` uses the following set of |
SP |
908 |
steps to determine the locale name. |
12cb6d
|
909 |
|
d2b365
|
910 |
- First the negotiator looks for the ``_LOCALE_`` attribute of the request |
SP |
911 |
object (possibly set directly by view code or by a listener for an |
|
912 |
:term:`event`). |
12cb6d
|
913 |
|
CM |
914 |
- Then it looks for the ``request.params['_LOCALE_']`` value. |
|
915 |
|
|
916 |
- Then it looks for the ``request.cookies['_LOCALE_']`` value. |
|
917 |
|
d2b365
|
918 |
- If no locale can be found via the request, it falls back to using the |
SP |
919 |
:term:`default locale name` (see :ref:`localization_deployment_settings`). |
12cb6d
|
920 |
|
d2b365
|
921 |
- Finally if the default locale name is not explicitly set, it uses the locale |
SP |
922 |
name ``en``. |
12cb6d
|
923 |
|
CM |
924 |
.. _custom_locale_negotiator: |
|
925 |
|
|
926 |
Using a Custom Locale Negotiator |
|
927 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
928 |
|
d2b365
|
929 |
Locale negotiation is sometimes policy-laden and complex. If the (simple) |
SP |
930 |
default locale negotiation scheme described in :ref:`activating_translation` is |
|
931 |
inappropriate for your application, you may create a special :term:`locale |
|
932 |
negotiator`. Subsequently you may override the default locale negotiator by |
|
933 |
adding your newly created locale negotiator to your application's |
|
934 |
configuration. |
12cb6d
|
935 |
|
d2b365
|
936 |
A locale negotiator is simply a callable which accepts a request and returns a |
SP |
937 |
single :term:`locale name` or ``None`` if no locale can be determined. |
12cb6d
|
938 |
|
CM |
939 |
Here's an implementation of a simple locale negotiator: |
|
940 |
|
|
941 |
.. code-block:: python |
392a6c
|
942 |
:linenos: |
12cb6d
|
943 |
|
CM |
944 |
def my_locale_negotiator(request): |
|
945 |
locale_name = request.params.get('my_locale') |
|
946 |
return locale_name |
|
947 |
|
d2b365
|
948 |
If a locale negotiator returns ``None``, it signifies to :app:`Pyramid` that |
SP |
949 |
the default application locale name should be used. |
12cb6d
|
950 |
|
CM |
951 |
You may add your newly created locale negotiator to your application's |
f8ed00
|
952 |
configuration by passing an object which can act as the negotiator (or a |
CM |
953 |
:term:`dotted Python name` referring to the object) as the |
d2b365
|
954 |
``locale_negotiator`` argument of the :class:`~pyramid.config.Configurator` |
SP |
955 |
instance during application startup. For example: |
7534ba
|
956 |
|
f8ed00
|
957 |
.. code-block:: python |
CM |
958 |
:linenos: |
7534ba
|
959 |
|
d7f259
|
960 |
from pyramid.config import Configurator |
f8ed00
|
961 |
config = Configurator(locale_negotiator=my_locale_negotiator) |
7534ba
|
962 |
|
d2b365
|
963 |
Alternatively, use the |
SP |
964 |
:meth:`pyramid.config.Configurator.set_locale_negotiator` method. |
7534ba
|
965 |
|
f8ed00
|
966 |
For example: |
7534ba
|
967 |
|
f8ed00
|
968 |
.. code-block:: python |
CM |
969 |
:linenos: |
7534ba
|
970 |
|
d7f259
|
971 |
from pyramid.config import Configurator |
f8ed00
|
972 |
config = Configurator() |
CM |
973 |
config.set_locale_negotiator(my_locale_negotiator) |