|
1 ==================== |
|
2 Internationalization |
|
3 ==================== |
|
4 |
|
5 Overview |
|
6 ======== |
|
7 |
|
8 The goal of internationalization is to allow a single Web application to offer |
|
9 its content and functionality in multiple languages and locales. |
|
10 |
|
11 For text translations, you, the Django developer, can accomplish this goal by |
|
12 adding a minimal amount of hooks to your Python and templates. These hooks |
|
13 are called **translation strings**. They tell Django: "This text should be |
|
14 translated into the end user's language, if a translation for this text is |
|
15 available in that language." It's your responsibility to mark translatable |
|
16 strings; the system can only translate strings it knows about. |
|
17 |
|
18 Django takes care of using these hooks to translate Web apps, on the fly, |
|
19 according to users' language preferences. |
|
20 |
|
21 Specifying translation strings: In Python code |
|
22 ============================================== |
|
23 |
|
24 Standard translation |
|
25 -------------------- |
|
26 |
|
27 Specify a translation string by using the function ``ugettext()``. It's |
|
28 convention to import this as a shorter alias, ``_``, to save typing. |
|
29 |
|
30 .. note:: |
|
31 Python's standard library ``gettext`` module installs ``_()`` into the |
|
32 global namespace, as an alias for ``gettext()``. In Django, we have chosen |
|
33 not to follow this practice, for a couple of reasons: |
|
34 |
|
35 1. For international character set (Unicode) support, ``ugettext()`` is |
|
36 more useful than ``gettext()``. Sometimes, you should be using |
|
37 ``ugettext_lazy()`` as the default translation method for a particular |
|
38 file. Without ``_()`` in the global namespace, the developer has to |
|
39 think about which is the most appropriate translation function. |
|
40 |
|
41 2. The underscore character (``_``) is used to represent "the previous |
|
42 result" in Python's interactive shell and doctest tests. Installing a |
|
43 global ``_()`` function causes interference. Explicitly importing |
|
44 ``ugettext()`` as ``_()`` avoids this problem. |
|
45 |
|
46 .. highlightlang:: python |
|
47 |
|
48 In this example, the text ``"Welcome to my site."`` is marked as a translation |
|
49 string:: |
|
50 |
|
51 from django.utils.translation import ugettext as _ |
|
52 |
|
53 def my_view(request): |
|
54 output = _("Welcome to my site.") |
|
55 return HttpResponse(output) |
|
56 |
|
57 Obviously, you could code this without using the alias. This example is |
|
58 identical to the previous one:: |
|
59 |
|
60 from django.utils.translation import ugettext |
|
61 |
|
62 def my_view(request): |
|
63 output = ugettext("Welcome to my site.") |
|
64 return HttpResponse(output) |
|
65 |
|
66 Translation works on computed values. This example is identical to the previous |
|
67 two:: |
|
68 |
|
69 def my_view(request): |
|
70 words = ['Welcome', 'to', 'my', 'site.'] |
|
71 output = _(' '.join(words)) |
|
72 return HttpResponse(output) |
|
73 |
|
74 Translation works on variables. Again, here's an identical example:: |
|
75 |
|
76 def my_view(request): |
|
77 sentence = 'Welcome to my site.' |
|
78 output = _(sentence) |
|
79 return HttpResponse(output) |
|
80 |
|
81 (The caveat with using variables or computed values, as in the previous two |
|
82 examples, is that Django's translation-string-detecting utility, |
|
83 ``django-admin.py makemessages``, won't be able to find these strings. More on |
|
84 ``makemessages`` later.) |
|
85 |
|
86 The strings you pass to ``_()`` or ``ugettext()`` can take placeholders, |
|
87 specified with Python's standard named-string interpolation syntax. Example:: |
|
88 |
|
89 def my_view(request, m, d): |
|
90 output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d} |
|
91 return HttpResponse(output) |
|
92 |
|
93 This technique lets language-specific translations reorder the placeholder |
|
94 text. For example, an English translation may be ``"Today is November 26."``, |
|
95 while a Spanish translation may be ``"Hoy es 26 de Noviembre."`` -- with the |
|
96 the month and the day placeholders swapped. |
|
97 |
|
98 For this reason, you should use named-string interpolation (e.g., ``%(day)s``) |
|
99 instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you |
|
100 have more than a single parameter. If you used positional interpolation, |
|
101 translations wouldn't be able to reorder placeholder text. |
|
102 |
|
103 Marking strings as no-op |
|
104 ------------------------ |
|
105 |
|
106 Use the function ``django.utils.translation.ugettext_noop()`` to mark a string |
|
107 as a translation string without translating it. The string is later translated |
|
108 from a variable. |
|
109 |
|
110 Use this if you have constant strings that should be stored in the source |
|
111 language because they are exchanged over systems or users -- such as strings in |
|
112 a database -- but should be translated at the last possible point in time, such |
|
113 as when the string is presented to the user. |
|
114 |
|
115 Pluralization |
|
116 ------------- |
|
117 |
|
118 Use the function ``django.utils.translation.ungettext()`` to specify pluralized |
|
119 messages. |
|
120 |
|
121 ``ungettext`` takes three arguments: the singular translation string, the plural |
|
122 translation string and the number of objects. |
|
123 |
|
124 This function is useful when you need your Django application to be localizable |
|
125 to languages where the number and complexity of `plural forms |
|
126 <http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is |
|
127 greater than the two forms used in English ('object' for the singular and |
|
128 'objects' for all the cases where ``count`` is different from zero, irrespective |
|
129 of its value.) |
|
130 |
|
131 For example:: |
|
132 |
|
133 from django.utils.translation import ungettext |
|
134 def hello_world(request, count): |
|
135 page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % { |
|
136 'count': count, |
|
137 } |
|
138 return HttpResponse(page) |
|
139 |
|
140 In this example the number of objects is passed to the translation languages as |
|
141 the ``count`` variable. |
|
142 |
|
143 Lets see a slightly more complex usage example:: |
|
144 |
|
145 from django.utils.translation import ungettext |
|
146 |
|
147 count = Report.objects.count() |
|
148 if count == 1: |
|
149 name = Report._meta.verbose_name |
|
150 else: |
|
151 name = Report._meta.verbose_name_plural |
|
152 |
|
153 text = ungettext( |
|
154 'There is %(count)d %(name)s available.', |
|
155 'There are %(count)d %(name)s available.', |
|
156 count |
|
157 ) % { |
|
158 'count': count, |
|
159 'name': name |
|
160 } |
|
161 |
|
162 Here we reuse localizable, hopefully already translated literals (contained in |
|
163 the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for |
|
164 other parts of the sentence so all of it is consistently based on the |
|
165 cardinality of the elements at play. |
|
166 |
|
167 .. _pluralization-var-notes: |
|
168 |
|
169 .. note:: |
|
170 |
|
171 When using this technique, make sure you use a single name for every |
|
172 extrapolated variable included in the literal. In the example above note how |
|
173 we used the ``name`` Python variable in both translation strings. This |
|
174 example would fail:: |
|
175 |
|
176 from django.utils.translation import ungettext |
|
177 from myapp.models import Report |
|
178 |
|
179 count = Report.objects.count() |
|
180 d = { |
|
181 'count': count, |
|
182 'name': Report._meta.verbose_name, |
|
183 'plural_name': Report._meta.verbose_name_plural |
|
184 } |
|
185 text = ungettext( |
|
186 'There is %(count)d %(name)s available.', |
|
187 'There are %(count)d %(plural_name)s available.', |
|
188 count |
|
189 ) % d |
|
190 |
|
191 You would get a ``a format specification for argument 'name', as in |
|
192 'msgstr[0]', doesn't exist in 'msgid'`` error when running |
|
193 ``django-admin.py compilemessages``. |
|
194 |
|
195 .. _lazy-translations: |
|
196 |
|
197 Lazy translation |
|
198 ---------------- |
|
199 |
|
200 Use the function ``django.utils.translation.ugettext_lazy()`` to translate |
|
201 strings lazily -- when the value is accessed rather than when the |
|
202 ``ugettext_lazy()`` function is called. |
|
203 |
|
204 For example, to translate a model's ``help_text``, do the following:: |
|
205 |
|
206 from django.utils.translation import ugettext_lazy |
|
207 |
|
208 class MyThing(models.Model): |
|
209 name = models.CharField(help_text=ugettext_lazy('This is the help text')) |
|
210 |
|
211 In this example, ``ugettext_lazy()`` stores a lazy reference to the string -- |
|
212 not the actual translation. The translation itself will be done when the string |
|
213 is used in a string context, such as template rendering on the Django admin |
|
214 site. |
|
215 |
|
216 The result of a ``ugettext_lazy()`` call can be used wherever you would use a |
|
217 unicode string (an object with type ``unicode``) in Python. If you try to use |
|
218 it where a bytestring (a ``str`` object) is expected, things will not work as |
|
219 expected, since a ``ugettext_lazy()`` object doesn't know how to convert |
|
220 itself to a bytestring. You can't use a unicode string inside a bytestring, |
|
221 either, so this is consistent with normal Python behavior. For example:: |
|
222 |
|
223 # This is fine: putting a unicode proxy into a unicode string. |
|
224 u"Hello %s" % ugettext_lazy("people") |
|
225 |
|
226 # This will not work, since you cannot insert a unicode object |
|
227 # into a bytestring (nor can you insert our unicode proxy there) |
|
228 "Hello %s" % ugettext_lazy("people") |
|
229 |
|
230 If you ever see output that looks like ``"hello |
|
231 <django.utils.functional...>"``, you have tried to insert the result of |
|
232 ``ugettext_lazy()`` into a bytestring. That's a bug in your code. |
|
233 |
|
234 If you don't like the verbose name ``ugettext_lazy``, you can just alias it as |
|
235 ``_`` (underscore), like so:: |
|
236 |
|
237 from django.utils.translation import ugettext_lazy as _ |
|
238 |
|
239 class MyThing(models.Model): |
|
240 name = models.CharField(help_text=_('This is the help text')) |
|
241 |
|
242 Always use lazy translations in :doc:`Django models </topics/db/models>`. |
|
243 Field names and table names should be marked for translation (otherwise, they |
|
244 won't be translated in the admin interface). This means writing explicit |
|
245 ``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class, |
|
246 though, rather than relying on Django's default determination of |
|
247 ``verbose_name`` and ``verbose_name_plural`` by looking at the model's class |
|
248 name:: |
|
249 |
|
250 from django.utils.translation import ugettext_lazy as _ |
|
251 |
|
252 class MyThing(models.Model): |
|
253 name = models.CharField(_('name'), help_text=_('This is the help text')) |
|
254 class Meta: |
|
255 verbose_name = _('my thing') |
|
256 verbose_name_plural = _('mythings') |
|
257 |
|
258 Working with lazy translation objects |
|
259 ------------------------------------- |
|
260 |
|
261 .. highlightlang:: python |
|
262 |
|
263 Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models |
|
264 and utility functions is a common operation. When you're working with these |
|
265 objects elsewhere in your code, you should ensure that you don't accidentally |
|
266 convert them to strings, because they should be converted as late as possible |
|
267 (so that the correct locale is in effect). This necessitates the use of a |
|
268 couple of helper functions. |
|
269 |
|
270 Joining strings: string_concat() |
|
271 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
272 |
|
273 Standard Python string joins (``''.join([...])``) will not work on lists |
|
274 containing lazy translation objects. Instead, you can use |
|
275 ``django.utils.translation.string_concat()``, which creates a lazy object that |
|
276 concatenates its contents *and* converts them to strings only when the result |
|
277 is included in a string. For example:: |
|
278 |
|
279 from django.utils.translation import string_concat |
|
280 ... |
|
281 name = ugettext_lazy(u'John Lennon') |
|
282 instrument = ugettext_lazy(u'guitar') |
|
283 result = string_concat(name, ': ', instrument) |
|
284 |
|
285 In this case, the lazy translations in ``result`` will only be converted to |
|
286 strings when ``result`` itself is used in a string (usually at template |
|
287 rendering time). |
|
288 |
|
289 The allow_lazy() decorator |
|
290 ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
291 |
|
292 Django offers many utility functions (particularly in ``django.utils``) that |
|
293 take a string as their first argument and do something to that string. These |
|
294 functions are used by template filters as well as directly in other code. |
|
295 |
|
296 If you write your own similar functions and deal with translations, you'll |
|
297 face the problem of what to do when the first argument is a lazy translation |
|
298 object. You don't want to convert it to a string immediately, because you might |
|
299 be using this function outside of a view (and hence the current thread's locale |
|
300 setting will not be correct). |
|
301 |
|
302 For cases like this, use the ``django.utils.functional.allow_lazy()`` |
|
303 decorator. It modifies the function so that *if* it's called with a lazy |
|
304 translation as the first argument, the function evaluation is delayed until it |
|
305 needs to be converted to a string. |
|
306 |
|
307 For example:: |
|
308 |
|
309 from django.utils.functional import allow_lazy |
|
310 |
|
311 def fancy_utility_function(s, ...): |
|
312 # Do some conversion on string 's' |
|
313 ... |
|
314 fancy_utility_function = allow_lazy(fancy_utility_function, unicode) |
|
315 |
|
316 The ``allow_lazy()`` decorator takes, in addition to the function to decorate, |
|
317 a number of extra arguments (``*args``) specifying the type(s) that the |
|
318 original function can return. Usually, it's enough to include ``unicode`` here |
|
319 and ensure that your function returns only Unicode strings. |
|
320 |
|
321 Using this decorator means you can write your function and assume that the |
|
322 input is a proper string, then add support for lazy translation objects at the |
|
323 end. |
|
324 |
|
325 .. _specifying-translation-strings-in-template-code: |
|
326 |
|
327 Specifying translation strings: In template code |
|
328 ================================================ |
|
329 |
|
330 .. highlightlang:: html+django |
|
331 |
|
332 Translations in :doc:`Django templates </topics/templates>` uses two template |
|
333 tags and a slightly different syntax than in Python code. To give your template |
|
334 access to these tags, put ``{% load i18n %}`` toward the top of your template. |
|
335 |
|
336 ``trans`` template tag |
|
337 ---------------------- |
|
338 |
|
339 The ``{% trans %}`` template tag translates either a constant string |
|
340 (enclosed in single or double quotes) or variable content:: |
|
341 |
|
342 <title>{% trans "This is the title." %}</title> |
|
343 <title>{% trans myvar %}</title> |
|
344 |
|
345 If the ``noop`` option is present, variable lookup still takes place but the |
|
346 translation is skipped. This is useful when "stubbing out" content that will |
|
347 require translation in the future:: |
|
348 |
|
349 <title>{% trans "myvar" noop %}</title> |
|
350 |
|
351 Internally, inline translations use an ``ugettext`` call. |
|
352 |
|
353 In case a template var (``myvar`` above) is passed to the tag, the tag will |
|
354 first resolve such variable to a string at run-time and then look up that |
|
355 string in the message catalogs. |
|
356 |
|
357 It's not possible to mix a template variable inside a string within ``{% trans |
|
358 %}``. If your translations require strings with variables (placeholders), use |
|
359 ``{% blocktrans %}`` instead. |
|
360 |
|
361 ``blocktrans`` template tag |
|
362 --------------------------- |
|
363 |
|
364 Contrarily to the ``trans`` tag, the ``blocktrans`` tag allows you to mark |
|
365 complex sentences consisting of literals and variable content for translation |
|
366 by making use of placeholders:: |
|
367 |
|
368 {% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %} |
|
369 |
|
370 To translate a template expression -- say, accessing object attributes or |
|
371 using template filters -- you need to bind the expression to a local variable |
|
372 for use within the translation block. Examples:: |
|
373 |
|
374 {% blocktrans with article.price as amount %} |
|
375 That will cost $ {{ amount }}. |
|
376 {% endblocktrans %} |
|
377 |
|
378 {% blocktrans with value|filter as myvar %} |
|
379 This will have {{ myvar }} inside. |
|
380 {% endblocktrans %} |
|
381 |
|
382 If you need to bind more than one expression inside a ``blocktrans`` tag, |
|
383 separate the pieces with ``and``:: |
|
384 |
|
385 {% blocktrans with book|title as book_t and author|title as author_t %} |
|
386 This is {{ book_t }} by {{ author_t }} |
|
387 {% endblocktrans %} |
|
388 |
|
389 This tag also provides for pluralization. To use it: |
|
390 |
|
391 * Designate and bind a counter value with the name ``count``. This value will |
|
392 be the one used to select the right plural form. |
|
393 |
|
394 * Specify both the singular and plural forms separating them with the |
|
395 ``{% plural %}`` tag within the ``{% blocktrans %}`` and |
|
396 ``{% endblocktrans %}`` tags. |
|
397 |
|
398 An example:: |
|
399 |
|
400 {% blocktrans count list|length as counter %} |
|
401 There is only one {{ name }} object. |
|
402 {% plural %} |
|
403 There are {{ counter }} {{ name }} objects. |
|
404 {% endblocktrans %} |
|
405 |
|
406 A more complex example:: |
|
407 |
|
408 {% blocktrans with article.price as amount count i.length as years %} |
|
409 That will cost $ {{ amount }} per year. |
|
410 {% plural %} |
|
411 That will cost $ {{ amount }} per {{ years }} years. |
|
412 {% endblocktrans %} |
|
413 |
|
414 When you use both the pluralization feature and bind values to local variables |
|
415 in addition to the counter value, keep in mind that the ``blocktrans`` |
|
416 construct is internally converted to an ``ungettext`` call. This means the |
|
417 same :ref:`notes regarding ungettext variables <pluralization-var-notes>` |
|
418 apply. |
|
419 |
|
420 .. _template-translation-vars: |
|
421 |
|
422 Other tags |
|
423 ---------- |
|
424 |
|
425 Each ``RequestContext`` has access to three translation-specific variables: |
|
426 |
|
427 * ``LANGUAGES`` is a list of tuples in which the first element is the |
|
428 :term:`language code` and the second is the language name (translated into |
|
429 the currently active locale). |
|
430 |
|
431 * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. |
|
432 Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`.) |
|
433 |
|
434 * ``LANGUAGE_BIDI`` is the current locale's direction. If True, it's a |
|
435 right-to-left language, e.g.: Hebrew, Arabic. If False it's a |
|
436 left-to-right language, e.g.: English, French, German etc. |
|
437 |
|
438 If you don't use the ``RequestContext`` extension, you can get those values with |
|
439 three tags:: |
|
440 |
|
441 {% get_current_language as LANGUAGE_CODE %} |
|
442 {% get_available_languages as LANGUAGES %} |
|
443 {% get_current_language_bidi as LANGUAGE_BIDI %} |
|
444 |
|
445 These tags also require a ``{% load i18n %}``. |
|
446 |
|
447 Translation hooks are also available within any template block tag that accepts |
|
448 constant strings. In those cases, just use ``_()`` syntax to specify a |
|
449 translation string:: |
|
450 |
|
451 {% some_special_tag _("Page not found") value|yesno:_("yes,no") %} |
|
452 |
|
453 In this case, both the tag and the filter will see the already-translated |
|
454 string, so they don't need to be aware of translations. |
|
455 |
|
456 .. note:: |
|
457 In this example, the translation infrastructure will be passed the string |
|
458 ``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The |
|
459 translated string will need to contain the comma so that the filter |
|
460 parsing code knows how to split up the arguments. For example, a German |
|
461 translator might translate the string ``"yes,no"`` as ``"ja,nein"`` |
|
462 (keeping the comma intact). |
|
463 |
|
464 .. _Django templates: ../templates_python/ |
|
465 |
|
466 Specifying translation strings: In JavaScript code |
|
467 ================================================== |
|
468 |
|
469 Adding translations to JavaScript poses some problems: |
|
470 |
|
471 * JavaScript code doesn't have access to a ``gettext`` implementation. |
|
472 |
|
473 * JavaScript code doesn't have access to .po or .mo files; they need to be |
|
474 delivered by the server. |
|
475 |
|
476 * The translation catalogs for JavaScript should be kept as small as |
|
477 possible. |
|
478 |
|
479 Django provides an integrated solution for these problems: It passes the |
|
480 translations into JavaScript, so you can call ``gettext``, etc., from within |
|
481 JavaScript. |
|
482 |
|
483 The ``javascript_catalog`` view |
|
484 ------------------------------- |
|
485 |
|
486 .. module:: django.views.i18n |
|
487 |
|
488 .. function:: javascript_catalog(request, domain='djangojs', packages=None) |
|
489 |
|
490 The main solution to these problems is the :meth:`django.views.i18n.javascript_catalog` |
|
491 view, which sends out a JavaScript code library with functions that mimic the |
|
492 ``gettext`` interface, plus an array of translation strings. Those translation |
|
493 strings are taken from the application, project or Django core, according to what |
|
494 you specify in either the info_dict or the URL. |
|
495 |
|
496 You hook it up like this:: |
|
497 |
|
498 js_info_dict = { |
|
499 'packages': ('your.app.package',), |
|
500 } |
|
501 |
|
502 urlpatterns = patterns('', |
|
503 (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), |
|
504 ) |
|
505 |
|
506 Each string in ``packages`` should be in Python dotted-package syntax (the |
|
507 same format as the strings in ``INSTALLED_APPS``) and should refer to a package |
|
508 that contains a ``locale`` directory. If you specify multiple packages, all |
|
509 those catalogs are merged into one catalog. This is useful if you have |
|
510 JavaScript that uses strings from different applications. |
|
511 |
|
512 By default, the view uses the ``djangojs`` gettext domain. This can be |
|
513 changed by altering the ``domain`` argument. |
|
514 |
|
515 You can make the view dynamic by putting the packages into the URL pattern:: |
|
516 |
|
517 urlpatterns = patterns('', |
|
518 (r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'), |
|
519 ) |
|
520 |
|
521 With this, you specify the packages as a list of package names delimited by '+' |
|
522 signs in the URL. This is especially useful if your pages use code from |
|
523 different apps and this changes often and you don't want to pull in one big |
|
524 catalog file. As a security measure, these values can only be either |
|
525 ``django.conf`` or any package from the ``INSTALLED_APPS`` setting. |
|
526 |
|
527 Using the JavaScript translation catalog |
|
528 ---------------------------------------- |
|
529 |
|
530 To use the catalog, just pull in the dynamically generated script like this:: |
|
531 |
|
532 <script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script> |
|
533 |
|
534 This uses reverse URL lookup to find the URL of the JavaScript catalog view. |
|
535 When the catalog is loaded, your JavaScript code can use the standard |
|
536 ``gettext`` interface to access it:: |
|
537 |
|
538 document.write(gettext('this is to be translated')); |
|
539 |
|
540 There is also an ``ngettext`` interface:: |
|
541 |
|
542 var object_cnt = 1 // or 0, or 2, or 3, ... |
|
543 s = ngettext('literal for the singular case', |
|
544 'literal for the plural case', object_cnt); |
|
545 |
|
546 and even a string interpolation function:: |
|
547 |
|
548 function interpolate(fmt, obj, named); |
|
549 |
|
550 The interpolation syntax is borrowed from Python, so the ``interpolate`` |
|
551 function supports both positional and named interpolation: |
|
552 |
|
553 * Positional interpolation: ``obj`` contains a JavaScript Array object |
|
554 whose elements values are then sequentially interpolated in their |
|
555 corresponding ``fmt`` placeholders in the same order they appear. |
|
556 For example:: |
|
557 |
|
558 fmts = ngettext('There is %s object. Remaining: %s', |
|
559 'There are %s objects. Remaining: %s', 11); |
|
560 s = interpolate(fmts, [11, 20]); |
|
561 // s is 'There are 11 objects. Remaining: 20' |
|
562 |
|
563 * Named interpolation: This mode is selected by passing the optional |
|
564 boolean ``named`` parameter as true. ``obj`` contains a JavaScript |
|
565 object or associative array. For example:: |
|
566 |
|
567 d = { |
|
568 count: 10, |
|
569 total: 50 |
|
570 }; |
|
571 |
|
572 fmts = ngettext('Total: %(total)s, there is %(count)s object', |
|
573 'there are %(count)s of a total of %(total)s objects', d.count); |
|
574 s = interpolate(fmts, d, true); |
|
575 |
|
576 You shouldn't go over the top with string interpolation, though: this is still |
|
577 JavaScript, so the code has to make repeated regular-expression substitutions. |
|
578 This isn't as fast as string interpolation in Python, so keep it to those |
|
579 cases where you really need it (for example, in conjunction with ``ngettext`` |
|
580 to produce proper pluralizations). |
|
581 |
|
582 The ``set_language`` redirect view |
|
583 ================================== |
|
584 |
|
585 .. function:: set_language(request) |
|
586 |
|
587 As a convenience, Django comes with a view, :meth:`django.views.i18n.set_language`, |
|
588 that sets a user's language preference and redirects back to the previous page. |
|
589 |
|
590 Activate this view by adding the following line to your URLconf:: |
|
591 |
|
592 (r'^i18n/', include('django.conf.urls.i18n')), |
|
593 |
|
594 (Note that this example makes the view available at ``/i18n/setlang/``.) |
|
595 |
|
596 The view expects to be called via the ``POST`` method, with a ``language`` |
|
597 parameter set in request. If session support is enabled, the view |
|
598 saves the language choice in the user's session. Otherwise, it saves the |
|
599 language choice in a cookie that is by default named ``django_language``. |
|
600 (The name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting.) |
|
601 |
|
602 After setting the language choice, Django redirects the user, following this |
|
603 algorithm: |
|
604 |
|
605 * Django looks for a ``next`` parameter in the ``POST`` data. |
|
606 * If that doesn't exist, or is empty, Django tries the URL in the |
|
607 ``Referrer`` header. |
|
608 * If that's empty -- say, if a user's browser suppresses that header -- |
|
609 then the user will be redirected to ``/`` (the site root) as a fallback. |
|
610 |
|
611 Here's example HTML template code: |
|
612 |
|
613 .. code-block:: html+django |
|
614 |
|
615 <form action="/i18n/setlang/" method="post"> |
|
616 {% csrf_token %} |
|
617 <input name="next" type="hidden" value="/next/page/" /> |
|
618 <select name="language"> |
|
619 {% for lang in LANGUAGES %} |
|
620 <option value="{{ lang.0 }}">{{ lang.1 }}</option> |
|
621 {% endfor %} |
|
622 </select> |
|
623 <input type="submit" value="Go" /> |
|
624 </form> |