|
1 ==================== |
|
2 Internationalization |
|
3 ==================== |
|
4 |
|
5 Django has full support for internationalization of text in code and templates. |
|
6 Here's how it works. |
|
7 |
|
8 Overview |
|
9 ======== |
|
10 |
|
11 The goal of internationalization is to allow a single Web application to offer |
|
12 its content and functionality in multiple languages. |
|
13 |
|
14 You, the Django developer, can accomplish this goal by adding a minimal amount |
|
15 of hooks to your Python code and templates. These hooks are called |
|
16 **translation strings**. They tell Django: "This text should be translated into |
|
17 the end user's language, if a translation for this text is available in that |
|
18 language." |
|
19 |
|
20 Django takes care of using these hooks to translate Web apps, on the fly, |
|
21 according to users' language preferences. |
|
22 |
|
23 Essentially, Django does two things: |
|
24 |
|
25 * It lets developers and template authors specify which parts of their apps |
|
26 should be translatable. |
|
27 * It uses these hooks to translate Web apps for particular users according |
|
28 to their language preferences. |
|
29 |
|
30 How to internationalize your app: in three steps |
|
31 ------------------------------------------------ |
|
32 |
|
33 1. Embed translation strings in your Python code and templates. |
|
34 2. Get translations for those strings, in whichever languages you want to |
|
35 support. |
|
36 3. Activate the locale middleware in your Django settings. |
|
37 |
|
38 .. admonition:: Behind the scenes |
|
39 |
|
40 Django's translation machinery uses the standard ``gettext`` module that |
|
41 comes with Python. |
|
42 |
|
43 If you don't need internationalization |
|
44 ====================================== |
|
45 |
|
46 Django's internationalization hooks are on by default, and that means there's a |
|
47 bit of i18n-related overhead in certain places of the framework. If you don't |
|
48 use internationalization, you should take the two seconds to set |
|
49 ``USE_I18N = False`` in your settings file. If ``USE_I18N`` is set to |
|
50 ``False``, then Django will make some optimizations so as not to load the |
|
51 internationalization machinery. See the `documentation for USE_I18N`_. |
|
52 |
|
53 You'll probably also want to remove ``'django.core.context_processors.i18n'`` |
|
54 from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. |
|
55 |
|
56 .. _documentation for USE_I18N: ../settings/#use-i18n |
|
57 |
|
58 How to specify translation strings |
|
59 ================================== |
|
60 |
|
61 Translation strings specify "This text should be translated." These strings can |
|
62 appear in your Python code and templates. It's your responsibility to mark |
|
63 translatable strings; the system can only translate strings it knows about. |
|
64 |
|
65 In Python code |
|
66 -------------- |
|
67 |
|
68 Standard translation |
|
69 ~~~~~~~~~~~~~~~~~~~~ |
|
70 |
|
71 Specify a translation string by using the function ``_()``. (Yes, the name of |
|
72 the function is the "underscore" character.) This function is available |
|
73 globally in any Python module; you don't have to import it. |
|
74 |
|
75 In this example, the text ``"Welcome to my site."`` is marked as a translation |
|
76 string:: |
|
77 |
|
78 def my_view(request): |
|
79 output = _("Welcome to my site.") |
|
80 return HttpResponse(output) |
|
81 |
|
82 The function ``django.utils.translation.gettext()`` is identical to ``_()``. |
|
83 This example is identical to the previous one:: |
|
84 |
|
85 from django.utils.translation import gettext |
|
86 def my_view(request): |
|
87 output = gettext("Welcome to my site.") |
|
88 return HttpResponse(output) |
|
89 |
|
90 Translation works on computed values. This example is identical to the previous |
|
91 two:: |
|
92 |
|
93 def my_view(request): |
|
94 words = ['Welcome', 'to', 'my', 'site.'] |
|
95 output = _(' '.join(words)) |
|
96 return HttpResponse(output) |
|
97 |
|
98 Translation works on variables. Again, here's an identical example:: |
|
99 |
|
100 def my_view(request): |
|
101 sentence = 'Welcome to my site.' |
|
102 output = _(sentence) |
|
103 return HttpResponse(output) |
|
104 |
|
105 (The caveat with using variables or computed values, as in the previous two |
|
106 examples, is that Django's translation-string-detecting utility, |
|
107 ``make-messages.py``, won't be able to find these strings. More on |
|
108 ``make-messages`` later.) |
|
109 |
|
110 The strings you pass to ``_()`` or ``gettext()`` can take placeholders, |
|
111 specified with Python's standard named-string interpolation syntax. Example:: |
|
112 |
|
113 def my_view(request, n): |
|
114 output = _('%(name)s is my name.') % {'name': n} |
|
115 return HttpResponse(output) |
|
116 |
|
117 This technique lets language-specific translations reorder the placeholder |
|
118 text. For example, an English translation may be ``"Adrian is my name."``, |
|
119 while a Spanish translation may be ``"Me llamo Adrian."`` -- with the |
|
120 placeholder (the name) placed after the translated text instead of before it. |
|
121 |
|
122 For this reason, you should use named-string interpolation (e.g., ``%(name)s``) |
|
123 instead of positional interpolation (e.g., ``%s`` or ``%d``). If you used |
|
124 positional interpolation, translations wouldn't be able to reorder placeholder |
|
125 text. |
|
126 |
|
127 Marking strings as no-op |
|
128 ~~~~~~~~~~~~~~~~~~~~~~~~ |
|
129 |
|
130 Use the function ``django.utils.translation.gettext_noop()`` to mark a string |
|
131 as a translation string without translating it. The string is later translated |
|
132 from a variable. |
|
133 |
|
134 Use this if you have constant strings that should be stored in the source |
|
135 language because they are exchanged over systems or users -- such as strings in |
|
136 a database -- but should be translated at the last possible point in time, such |
|
137 as when the string is presented to the user. |
|
138 |
|
139 Lazy translation |
|
140 ~~~~~~~~~~~~~~~~ |
|
141 |
|
142 Use the function ``django.utils.translation.gettext_lazy()`` to translate |
|
143 strings lazily -- when the value is accessed rather than when the |
|
144 ``gettext_lazy()`` function is called. |
|
145 |
|
146 For example, to translate a model's ``help_text``, do the following:: |
|
147 |
|
148 from django.utils.translation import gettext_lazy |
|
149 |
|
150 class MyThing(models.Model): |
|
151 name = models.CharField(help_text=gettext_lazy('This is the help text')) |
|
152 |
|
153 In this example, ``gettext_lazy()`` stores a lazy reference to the string -- |
|
154 not the actual translation. The translation itself will be done when the string |
|
155 is used in a string context, such as template rendering on the Django admin site. |
|
156 |
|
157 If you don't like the verbose name ``gettext_lazy``, you can just alias it as |
|
158 ``_`` (underscore), like so:: |
|
159 |
|
160 from django.utils.translation import gettext_lazy as _ |
|
161 |
|
162 class MyThing(models.Model): |
|
163 name = models.CharField(help_text=_('This is the help text')) |
|
164 |
|
165 Always use lazy translations in `Django models`_. And it's a good idea to add |
|
166 translations for the field names and table names, too. This means writing |
|
167 explicit ``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` |
|
168 class, though:: |
|
169 |
|
170 from django.utils.translation import gettext_lazy as _ |
|
171 |
|
172 class MyThing(models.Model): |
|
173 name = models.CharField(_('name'), help_text=_('This is the help text')) |
|
174 class Meta: |
|
175 verbose_name = _('my thing') |
|
176 verbose_name_plural = _('mythings') |
|
177 |
|
178 .. _Django models: ../model_api/ |
|
179 |
|
180 Pluralization |
|
181 ~~~~~~~~~~~~~ |
|
182 |
|
183 Use the function ``django.utils.translation.ngettext()`` to specify pluralized |
|
184 messages. Example:: |
|
185 |
|
186 from django.utils.translation import ngettext |
|
187 def hello_world(request, count): |
|
188 page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % { |
|
189 'count': count, |
|
190 } |
|
191 return HttpResponse(page) |
|
192 |
|
193 ``ngettext`` takes three arguments: the singular translation string, the plural |
|
194 translation string and the number of objects (which is passed to the |
|
195 translation languages as the ``count`` variable). |
|
196 |
|
197 In template code |
|
198 ---------------- |
|
199 |
|
200 Using translations in `Django templates`_ uses two template tags and a slightly |
|
201 different syntax than in Python code. To give your template access to these |
|
202 tags, put ``{% load i18n %}`` toward the top of your template. |
|
203 |
|
204 The ``{% trans %}`` template tag translates a constant string or a variable |
|
205 content:: |
|
206 |
|
207 <title>{% trans "This is the title." %}</title> |
|
208 |
|
209 If you only want to mark a value for translation, but translate it later from a |
|
210 variable, use the ``noop`` option:: |
|
211 |
|
212 <title>{% trans "value" noop %}</title> |
|
213 |
|
214 It's not possible to use template variables in ``{% trans %}`` -- only constant |
|
215 strings, in single or double quotes, are allowed. If your translations require |
|
216 variables (placeholders), use ``{% blocktrans %}``. Example:: |
|
217 |
|
218 {% blocktrans %}This will have {{ value }} inside.{% endblocktrans %} |
|
219 |
|
220 To translate a template expression -- say, using template filters -- you need |
|
221 to bind the expression to a local variable for use within the translation |
|
222 block:: |
|
223 |
|
224 {% blocktrans with value|filter as myvar %} |
|
225 This will have {{ myvar }} inside. |
|
226 {% endblocktrans %} |
|
227 |
|
228 If you need to bind more than one expression inside a ``blocktrans`` tag, |
|
229 separate the pieces with ``and``:: |
|
230 |
|
231 {% blocktrans with book|title as book_t and author|title as author_t %} |
|
232 This is {{ book_t }} by {{ author_t }} |
|
233 {% endblocktrans %} |
|
234 |
|
235 To pluralize, specify both the singular and plural forms with the |
|
236 ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and |
|
237 ``{% endblocktrans %}``. Example:: |
|
238 |
|
239 {% blocktrans count list|count as counter %} |
|
240 There is only one {{ name }} object. |
|
241 {% plural %} |
|
242 There are {{ counter }} {{ name }} objects. |
|
243 {% endblocktrans %} |
|
244 |
|
245 Internally, all block and inline translations use the appropriate |
|
246 ``gettext`` / ``ngettext`` call. |
|
247 |
|
248 Each ``RequestContext`` has access to two translation-specific variables: |
|
249 |
|
250 * ``LANGUAGES`` is a list of tuples in which the first element is the |
|
251 language code and the second is the language name (in that language). |
|
252 * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. |
|
253 Example: ``en-us``. (See "How language preference is discovered", below.) |
|
254 * ``LANGUAGE_BIDI`` is the current language's direction. If True, it's a |
|
255 right-to-left language, e.g: Hebrew, Arabic. If False it's a |
|
256 left-to-right language, e.g: English, French, German etc. |
|
257 |
|
258 |
|
259 If you don't use the ``RequestContext`` extension, you can get those values with |
|
260 three tags:: |
|
261 |
|
262 {% get_current_language as LANGUAGE_CODE %} |
|
263 {% get_available_languages as LANGUAGES %} |
|
264 {% get_current_language_bidi as LANGUAGE_BIDI %} |
|
265 |
|
266 These tags also require a ``{% load i18n %}``. |
|
267 |
|
268 Translation hooks are also available within any template block tag that accepts |
|
269 constant strings. In those cases, just use ``_()`` syntax to specify a |
|
270 translation string. Example:: |
|
271 |
|
272 {% some_special_tag _("Page not found") value|yesno:_("yes,no") %} |
|
273 |
|
274 In this case, both the tag and the filter will see the already-translated |
|
275 string, so they don't need to be aware of translations. |
|
276 |
|
277 .. _Django templates: ../templates_python/ |
|
278 |
|
279 How to create language files |
|
280 ============================ |
|
281 |
|
282 Once you've tagged your strings for later translation, you need to write (or |
|
283 obtain) the language translations themselves. Here's how that works. |
|
284 |
|
285 .. admonition:: Locale restrictions |
|
286 |
|
287 Django does not support localizing your application into a locale for |
|
288 which Django itself has not been translated. In this case, it will ignore |
|
289 your translation files. If you were to try this and Django supported it, |
|
290 you would inevitably see a mixture of translated strings (from your |
|
291 application) and English strings (from Django itself). If you want to |
|
292 support a locale for your application that is not already part of |
|
293 Django, you'll need to make at least a minimal translation of the Django |
|
294 core. |
|
295 |
|
296 Message files |
|
297 ------------- |
|
298 |
|
299 The first step is to create a **message file** for a new language. A message |
|
300 file is a plain-text file, representing a single language, that contains all |
|
301 available translation strings and how they should be represented in the given |
|
302 language. Message files have a ``.po`` file extension. |
|
303 |
|
304 Django comes with a tool, ``bin/make-messages.py``, that automates the creation |
|
305 and upkeep of these files. |
|
306 |
|
307 To create or update a message file, run this command:: |
|
308 |
|
309 bin/make-messages.py -l de |
|
310 |
|
311 ...where ``de`` is the language code for the message file you want to create. |
|
312 The language code, in this case, is in locale format. For example, it's |
|
313 ``pt_BR`` for Brazilian and ``de_AT`` for Austrian German. |
|
314 |
|
315 The script should be run from one of three places: |
|
316 |
|
317 * The root ``django`` directory (not a Subversion checkout, but the one |
|
318 that is linked-to via ``$PYTHONPATH`` or is located somewhere on that |
|
319 path). |
|
320 * The root directory of your Django project. |
|
321 * The root directory of your Django app. |
|
322 |
|
323 The script runs over the entire Django source tree and pulls out all strings |
|
324 marked for translation. It creates (or updates) a message file in the directory |
|
325 ``conf/locale``. In the ``de`` example, the file will be |
|
326 ``conf/locale/de/LC_MESSAGES/django.po``. |
|
327 |
|
328 If run over your project source tree or your application source tree, it will |
|
329 do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES`` |
|
330 (note the missing ``conf`` prefix). |
|
331 |
|
332 .. admonition:: No gettext? |
|
333 |
|
334 If you don't have the ``gettext`` utilities installed, ``make-messages.py`` |
|
335 will create empty files. If that's the case, either install the ``gettext`` |
|
336 utilities or just copy the English message file |
|
337 (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a starting point; |
|
338 it's just an empty translation file. |
|
339 |
|
340 The format of ``.po`` files is straightforward. Each ``.po`` file contains a |
|
341 small bit of metadata, such as the translation maintainer's contact |
|
342 information, but the bulk of the file is a list of **messages** -- simple |
|
343 mappings between translation strings and the actual translated text for the |
|
344 particular language. |
|
345 |
|
346 For example, if your Django app contained a translation string for the text |
|
347 ``"Welcome to my site."``, like so:: |
|
348 |
|
349 _("Welcome to my site.") |
|
350 |
|
351 ...then ``make-messages.py`` will have created a ``.po`` file containing the |
|
352 following snippet -- a message:: |
|
353 |
|
354 #: path/to/python/module.py:23 |
|
355 msgid "Welcome to my site." |
|
356 msgstr "" |
|
357 |
|
358 A quick explanation: |
|
359 |
|
360 * ``msgid`` is the translation string, which appears in the source. Don't |
|
361 change it. |
|
362 * ``msgstr`` is where you put the language-specific translation. It starts |
|
363 out empty, so it's your responsibility to change it. Make sure you keep |
|
364 the quotes around your translation. |
|
365 * As a convenience, each message includes the filename and line number |
|
366 from which the translation string was gleaned. |
|
367 |
|
368 Long messages are a special case. There, the first string directly after the |
|
369 ``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be |
|
370 written over the next few lines as one string per line. Those strings are |
|
371 directly concatenated. Don't forget trailing spaces within the strings; |
|
372 otherwise, they'll be tacked together without whitespace! |
|
373 |
|
374 .. admonition:: Mind your charset |
|
375 |
|
376 When creating a ``.po`` file with your favorite text editor, first edit |
|
377 the charset line (search for ``"CHARSET"``) and set it to the charset |
|
378 you'll be using to edit the content. Generally, utf-8 should work for most |
|
379 languages, but ``gettext`` should handle any charset you throw at it. |
|
380 |
|
381 To reexamine all source code and templates for new translation strings and |
|
382 update all message files for **all** languages, run this:: |
|
383 |
|
384 make-messages.py -a |
|
385 |
|
386 Compiling message files |
|
387 ----------------------- |
|
388 |
|
389 After you create your message file -- and each time you make changes to it -- |
|
390 you'll need to compile it into a more efficient form, for use by ``gettext``. |
|
391 Do this with the ``bin/compile-messages.py`` utility. |
|
392 |
|
393 This tool runs over all available ``.po`` files and creates ``.mo`` files, |
|
394 which are binary files optimized for use by ``gettext``. In the same directory |
|
395 from which you ran ``make-messages.py``, run ``compile-messages.py`` like |
|
396 this:: |
|
397 |
|
398 bin/compile-messages.py |
|
399 |
|
400 That's it. Your translations are ready for use. |
|
401 |
|
402 .. admonition:: A note to translators |
|
403 |
|
404 If you've created a translation in a language Django doesn't yet support, |
|
405 please let us know! See `Submitting and maintaining translations`_ for |
|
406 the steps to take. |
|
407 |
|
408 .. _Submitting and maintaining translations: ../contributing/ |
|
409 |
|
410 How Django discovers language preference |
|
411 ======================================== |
|
412 |
|
413 Once you've prepared your translations -- or, if you just want to use the |
|
414 translations that come with Django -- you'll just need to activate translation |
|
415 for your app. |
|
416 |
|
417 Behind the scenes, Django has a very flexible model of deciding which language |
|
418 should be used -- installation-wide, for a particular user, or both. |
|
419 |
|
420 To set an installation-wide language preference, set ``LANGUAGE_CODE`` in your |
|
421 `settings file`_. Django uses this language as the default translation -- the |
|
422 final attempt if no other translator finds a translation. |
|
423 |
|
424 If all you want to do is run Django with your native language, and a language |
|
425 file is available for your language, all you need to do is set |
|
426 ``LANGUAGE_CODE``. |
|
427 |
|
428 If you want to let each individual user specify which language he or she |
|
429 prefers, use ``LocaleMiddleware``. ``LocaleMiddleware`` enables language |
|
430 selection based on data from the request. It customizes content for each user. |
|
431 |
|
432 To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` |
|
433 to your ``MIDDLEWARE_CLASSES`` setting. Because middleware order matters, you |
|
434 should follow these guidelines: |
|
435 |
|
436 * Make sure it's one of the first middlewares installed. |
|
437 * It should come after ``SessionMiddleware``, because ``LocaleMiddleware`` |
|
438 makes use of session data. |
|
439 * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it. |
|
440 |
|
441 For example, your ``MIDDLEWARE_CLASSES`` might look like this:: |
|
442 |
|
443 MIDDLEWARE_CLASSES = ( |
|
444 'django.contrib.sessions.middleware.SessionMiddleware', |
|
445 'django.middleware.locale.LocaleMiddleware', |
|
446 'django.middleware.common.CommonMiddleware', |
|
447 ) |
|
448 |
|
449 (For more on middleware, see the `middleware documentation`_.) |
|
450 |
|
451 ``LocaleMiddleware`` tries to determine the user's language preference by |
|
452 following this algorithm: |
|
453 |
|
454 * First, it looks for a ``django_language`` key in the the current user's |
|
455 `session`_. |
|
456 * Failing that, it looks for a cookie called ``django_language``. |
|
457 * Failing that, it looks at the ``Accept-Language`` HTTP header. This |
|
458 header is sent by your browser and tells the server which language(s) you |
|
459 prefer, in order by priority. Django tries each language in the header |
|
460 until it finds one with available translations. |
|
461 * Failing that, it uses the global ``LANGUAGE_CODE`` setting. |
|
462 |
|
463 Notes: |
|
464 |
|
465 * In each of these places, the language preference is expected to be in the |
|
466 standard language format, as a string. For example, Brazilian is |
|
467 ``pt-br``. |
|
468 * If a base language is available but the sublanguage specified is not, |
|
469 Django uses the base language. For example, if a user specifies ``de-at`` |
|
470 (Austrian German) but Django only has ``de`` available, Django uses |
|
471 ``de``. |
|
472 * Only languages listed in the `LANGUAGES setting`_ can be selected. If |
|
473 you want to restrict the language selection to a subset of provided |
|
474 languages (because your application doesn't provide all those languages), |
|
475 set ``LANGUAGES`` to a list of languages. For example:: |
|
476 |
|
477 LANGUAGES = ( |
|
478 ('de', _('German')), |
|
479 ('en', _('English')), |
|
480 ) |
|
481 |
|
482 This example restricts languages that are available for automatic |
|
483 selection to German and English (and any sublanguage, like de-ch or |
|
484 en-us). |
|
485 |
|
486 .. _LANGUAGES setting: ../settings/#languages |
|
487 |
|
488 * If you define a custom ``LANGUAGES`` setting, as explained in the |
|
489 previous bullet, it's OK to mark the languages as translation strings |
|
490 -- but use a "dummy" ``gettext()`` function, not the one in |
|
491 ``django.utils.translation``. You should *never* import |
|
492 ``django.utils.translation`` from within your settings file, because that |
|
493 module in itself depends on the settings, and that would cause a circular |
|
494 import. |
|
495 |
|
496 The solution is to use a "dummy" ``gettext()`` function. Here's a sample |
|
497 settings file:: |
|
498 |
|
499 gettext = lambda s: s |
|
500 |
|
501 LANGUAGES = ( |
|
502 ('de', gettext('German')), |
|
503 ('en', gettext('English')), |
|
504 ) |
|
505 |
|
506 With this arrangement, ``make-messages.py`` will still find and mark |
|
507 these strings for translation, but the translation won't happen at |
|
508 runtime -- so you'll have to remember to wrap the languages in the *real* |
|
509 ``gettext()`` in any code that uses ``LANGUAGES`` at runtime. |
|
510 |
|
511 * The ``LocaleMiddleware`` can only select languages for which there is a |
|
512 Django-provided base translation. If you want to provide translations |
|
513 for your application that aren't already in the set of translations |
|
514 in Django's source tree, you'll want to provide at least basic |
|
515 translations for that language. For example, Django uses technical |
|
516 message IDs to translate date formats and time formats -- so you will |
|
517 need at least those translations for the system to work correctly. |
|
518 |
|
519 A good starting point is to copy the English ``.po`` file and to |
|
520 translate at least the technical messages -- maybe the validator |
|
521 messages, too. |
|
522 |
|
523 Technical message IDs are easily recognized; they're all upper case. You |
|
524 don't translate the message ID as with other messages, you provide the |
|
525 correct local variant on the provided English value. For example, with |
|
526 ``DATETIME_FORMAT`` (or ``DATE_FORMAT`` or ``TIME_FORMAT``), this would |
|
527 be the format string that you want to use in your language. The format |
|
528 is identical to the format strings used by the ``now`` template tag. |
|
529 |
|
530 Once ``LocaleMiddleware`` determines the user's preference, it makes this |
|
531 preference available as ``request.LANGUAGE_CODE`` for each `request object`_. |
|
532 Feel free to read this value in your view code. Here's a simple example:: |
|
533 |
|
534 def hello_world(request, count): |
|
535 if request.LANGUAGE_CODE == 'de-at': |
|
536 return HttpResponse("You prefer to read Austrian German.") |
|
537 else: |
|
538 return HttpResponse("You prefer to read another language.") |
|
539 |
|
540 Note that, with static (middleware-less) translation, the language is in |
|
541 ``settings.LANGUAGE_CODE``, while with dynamic (middleware) translation, it's |
|
542 in ``request.LANGUAGE_CODE``. |
|
543 |
|
544 .. _settings file: ../settings/ |
|
545 .. _middleware documentation: ../middleware/ |
|
546 .. _session: ../sessions/ |
|
547 .. _request object: ../request_response/#httprequest-objects |
|
548 |
|
549 The ``set_language`` redirect view |
|
550 ================================== |
|
551 |
|
552 As a convenience, Django comes with a view, ``django.views.i18n.set_language``, |
|
553 that sets a user's language preference and redirects back to the previous page. |
|
554 |
|
555 Activate this view by adding the following line to your URLconf:: |
|
556 |
|
557 (r'^i18n/', include('django.conf.urls.i18n')), |
|
558 |
|
559 (Note that this example makes the view available at ``/i18n/setlang/``.) |
|
560 |
|
561 The view expects to be called via the ``GET`` method, with a ``language`` |
|
562 parameter set in the query string. If session support is enabled, the view |
|
563 saves the language choice in the user's session. Otherwise, it saves the |
|
564 language choice in a ``django_language`` cookie. |
|
565 |
|
566 After setting the language choice, Django redirects the user, following this |
|
567 algorithm: |
|
568 |
|
569 * Django looks for a ``next`` parameter in the query string. |
|
570 * If that doesn't exist, or is empty, Django tries the URL in the |
|
571 ``Referer`` header. |
|
572 * If that's empty -- say, if a user's browser suppresses that header -- |
|
573 then the user will be redirected to ``/`` (the site root) as a fallback. |
|
574 |
|
575 Here's example HTML template code:: |
|
576 |
|
577 <form action="/i18n/setlang/" method="get"> |
|
578 <input name="next" type="hidden" value="/next/page/" /> |
|
579 <select name="language"> |
|
580 {% for lang in LANGUAGES %} |
|
581 <option value="{{ lang.0 }}">{{ lang.1 }}</option> |
|
582 {% endfor %} |
|
583 </select> |
|
584 <input type="submit" value="Go" /> |
|
585 </form> |
|
586 |
|
587 Using translations in your own projects |
|
588 ======================================= |
|
589 |
|
590 Django looks for translations by following this algorithm: |
|
591 |
|
592 * First, it looks for a ``locale`` directory in the application directory |
|
593 of the view that's being called. If it finds a translation for the |
|
594 selected language, the translation will be installed. |
|
595 * Next, it looks for a ``locale`` directory in the project directory. If it |
|
596 finds a translation, the translation will be installed. |
|
597 * Finally, it checks the base translation in ``django/conf/locale``. |
|
598 |
|
599 This way, you can write applications that include their own translations, and |
|
600 you can override base translations in your project path. Or, you can just build |
|
601 a big project out of several apps and put all translations into one big project |
|
602 message file. The choice is yours. |
|
603 |
|
604 .. note:: |
|
605 |
|
606 If you're using manually configured settings, as described in the |
|
607 `settings documentation`_, the ``locale`` directory in the project |
|
608 directory will not be examined, since Django loses the ability to work out |
|
609 the location of the project directory. (Django normally uses the location |
|
610 of the settings file to determine this, and a settings file doesn't exist |
|
611 if you're manually configuring your settings.) |
|
612 |
|
613 .. _settings documentation: ../settings/#using-settings-without-the-django-settings-module-environment-variable |
|
614 |
|
615 All message file repositories are structured the same way. They are: |
|
616 |
|
617 * ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|
618 * ``$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|
619 * All paths listed in ``LOCALE_PATHS`` in your settings file are |
|
620 searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)`` |
|
621 * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|
622 |
|
623 To create message files, you use the same ``make-messages.py`` tool as with the |
|
624 Django message files. You only need to be in the right place -- in the directory |
|
625 where either the ``conf/locale`` (in case of the source tree) or the ``locale/`` |
|
626 (in case of app messages or project messages) directory are located. And you |
|
627 use the same ``compile-messages.py`` to produce the binary ``django.mo`` files that |
|
628 are used by ``gettext``. |
|
629 |
|
630 Application message files are a bit complicated to discover -- they need the |
|
631 ``LocaleMiddleware``. If you don't use the middleware, only the Django message |
|
632 files and project message files will be processed. |
|
633 |
|
634 Finally, you should give some thought to the structure of your translation |
|
635 files. If your applications need to be delivered to other users and will |
|
636 be used in other projects, you might want to use app-specific translations. |
|
637 But using app-specific translations and project translations could produce |
|
638 weird problems with ``make-messages``: ``make-messages`` will traverse all |
|
639 directories below the current path and so might put message IDs into the |
|
640 project message file that are already in application message files. |
|
641 |
|
642 The easiest way out is to store applications that are not part of the project |
|
643 (and so carry their own translations) outside the project tree. That way, |
|
644 ``make-messages`` on the project level will only translate strings that are |
|
645 connected to your explicit project and not strings that are distributed |
|
646 independently. |
|
647 |
|
648 Translations and JavaScript |
|
649 =========================== |
|
650 |
|
651 Adding translations to JavaScript poses some problems: |
|
652 |
|
653 * JavaScript code doesn't have access to a ``gettext`` implementation. |
|
654 |
|
655 * JavaScript code doesn't have access to .po or .mo files; they need to be |
|
656 delivered by the server. |
|
657 |
|
658 * The translation catalogs for JavaScript should be kept as small as |
|
659 possible. |
|
660 |
|
661 Django provides an integrated solution for these problems: It passes the |
|
662 translations into JavaScript, so you can call ``gettext``, etc., from within |
|
663 JavaScript. |
|
664 |
|
665 The ``javascript_catalog`` view |
|
666 ------------------------------- |
|
667 |
|
668 The main solution to these problems is the ``javascript_catalog`` view, which |
|
669 sends out a JavaScript code library with functions that mimic the ``gettext`` |
|
670 interface, plus an array of translation strings. Those translation strings are |
|
671 taken from the application, project or Django core, according to what you |
|
672 specify in either the {{{info_dict}}} or the URL. |
|
673 |
|
674 You hook it up like this:: |
|
675 |
|
676 js_info_dict = { |
|
677 'packages': ('your.app.package',), |
|
678 } |
|
679 |
|
680 urlpatterns = patterns('', |
|
681 (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), |
|
682 ) |
|
683 |
|
684 Each string in ``packages`` should be in Python dotted-package syntax (the |
|
685 same format as the strings in ``INSTALLED_APPS``) and should refer to a package |
|
686 that contains a ``locale`` directory. If you specify multiple packages, all |
|
687 those catalogs are merged into one catalog. This is useful if you have |
|
688 JavaScript that uses strings from different applications. |
|
689 |
|
690 You can make the view dynamic by putting the packages into the URL pattern:: |
|
691 |
|
692 urlpatterns = patterns('', |
|
693 (r'^jsi18n/(?P<packages>\S+?)/$, 'django.views.i18n.javascript_catalog'), |
|
694 ) |
|
695 |
|
696 With this, you specify the packages as a list of package names delimited by '+' |
|
697 signs in the URL. This is especially useful if your pages use code from |
|
698 different apps and this changes often and you don't want to pull in one big |
|
699 catalog file. As a security measure, these values can only be either |
|
700 ``django.conf`` or any package from the ``INSTALLED_APPS`` setting. |
|
701 |
|
702 Using the JavaScript translation catalog |
|
703 ---------------------------------------- |
|
704 |
|
705 To use the catalog, just pull in the dynamically generated script like this:: |
|
706 |
|
707 <script type="text/javascript" src="/path/to/jsi18n/"></script> |
|
708 |
|
709 This is how the admin fetches the translation catalog from the server. When the |
|
710 catalog is loaded, your JavaScript code can use the standard ``gettext`` |
|
711 interface to access it:: |
|
712 |
|
713 document.write(gettext('this is to be translated')); |
|
714 |
|
715 There even is a ``ngettext`` interface and a string interpolation function:: |
|
716 |
|
717 d = { |
|
718 count: 10 |
|
719 }; |
|
720 s = interpolate(ngettext('this is %(count)s object', 'this are %(count)s objects', d.count), d); |
|
721 |
|
722 The ``interpolate`` function supports both positional interpolation and named |
|
723 interpolation. So the above could have been written as:: |
|
724 |
|
725 s = interpolate(ngettext('this is %s object', 'this are %s objects', 11), [11]); |
|
726 |
|
727 The interpolation syntax is borrowed from Python. You shouldn't go over the top |
|
728 with string interpolation, though: this is still JavaScript, so the code will |
|
729 have to do repeated regular-expression substitutions. This isn't as fast as |
|
730 string interpolation in Python, so keep it to those cases where you really |
|
731 need it (for example, in conjunction with ``ngettext`` to produce proper |
|
732 pluralizations). |
|
733 |
|
734 Creating JavaScript translation catalogs |
|
735 ---------------------------------------- |
|
736 |
|
737 You create and update the translation catalogs the same way as the other Django |
|
738 translation catalogs -- with the {{{make-messages.py}}} tool. The only |
|
739 difference is you need to provide a ``-d djangojs`` parameter, like this:: |
|
740 |
|
741 make-messages.py -d djangojs -l de |
|
742 |
|
743 This would create or update the translation catalog for JavaScript for German. |
|
744 After updating translation catalogs, just run ``compile-messages.py`` the same |
|
745 way as you do with normal Django translation catalogs. |
|
746 |
|
747 Specialities of Django translation |
|
748 ================================== |
|
749 |
|
750 If you know ``gettext``, you might note these specialities in the way Django |
|
751 does translation: |
|
752 |
|
753 * The string domain is ``django`` or ``djangojs``. The string domain is used to |
|
754 differentiate between different programs that store their data in a |
|
755 common message-file library (usually ``/usr/share/locale/``). The ``django`` |
|
756 domain is used for python and template translation strings and is loaded into |
|
757 the global translation catalogs. The ``djangojs`` domain is only used for |
|
758 JavaScript translation catalogs to make sure that those are as small as |
|
759 possible. |
|
760 * Django only uses ``gettext`` and ``gettext_noop``. That's because Django |
|
761 always uses ``DEFAULT_CHARSET`` strings internally. There isn't much use |
|
762 in using ``ugettext``, because you'll always need to produce utf-8 |
|
763 anyway. |
|
764 * Django doesn't use ``xgettext`` alone. It uses Python wrappers around |
|
765 ``xgettext`` and ``msgfmt``. That's mostly for convenience. |