|
@@ -1,1144 +0,0 @@
|
|
|
-.. _topics-i18n:
|
|
|
-
|
|
|
-====================
|
|
|
-Internationalization
|
|
|
-====================
|
|
|
-
|
|
|
-Django has full support for internationalization of text in code and
|
|
|
-templates, and format localization of dates and numbers. Here's how it works.
|
|
|
-
|
|
|
-Overview
|
|
|
-========
|
|
|
-
|
|
|
-The goal of internationalization is to allow a single Web application to offer
|
|
|
-its content and functionality in multiple languages and locales.
|
|
|
-
|
|
|
-For text translation, you, the Django developer, can accomplish this goal by
|
|
|
-adding a minimal amount of hooks to your Python code and templates. These hooks
|
|
|
-are called **translation strings**. They tell Django: "This text should be
|
|
|
-translated into the end user's language, if a translation for this text is
|
|
|
-available in that language."
|
|
|
-
|
|
|
-Django takes care of using these hooks to translate Web apps, on the fly,
|
|
|
-according to users' language preferences.
|
|
|
-
|
|
|
-Essentially, Django does two things:
|
|
|
-
|
|
|
- * It lets developers and template authors specify which parts of their apps
|
|
|
- should be translatable.
|
|
|
- * It uses these hooks to translate Web apps for particular users according
|
|
|
- to their language preferences.
|
|
|
-
|
|
|
-For format localization, it's just necessary to set
|
|
|
-:setting:`USE_L10N = True <USE_L10N>` in your settings file. If
|
|
|
-:setting:`USE_L10N` is set to ``True``, Django will display
|
|
|
-numbers and dates in the format of the current locale. That includes field
|
|
|
-representation on templates, and allowed input formats on the admin.
|
|
|
-
|
|
|
-If you don't need internationalization in your app
|
|
|
-==================================================
|
|
|
-
|
|
|
-Django's internationalization hooks are on by default, and that means there's a
|
|
|
-bit of i18n-related overhead in certain places of the framework. If you don't
|
|
|
-use internationalization, you should take the two seconds to set
|
|
|
-:setting:`USE_I18N = False <USE_I18N>` in your settings file. If
|
|
|
-:setting:`USE_I18N` is set to ``False``, then Django will make some
|
|
|
-optimizations so as not to load the internationalization machinery.
|
|
|
-
|
|
|
-You'll probably also want to remove ``'django.core.context_processors.i18n'``
|
|
|
-from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting.
|
|
|
-
|
|
|
-If you do need internationalization: three steps
|
|
|
-================================================
|
|
|
-
|
|
|
- 1. Embed translation strings in your Python code and templates.
|
|
|
- 2. Get translations for those strings, in whichever languages you want to
|
|
|
- support.
|
|
|
- 3. Activate the locale middleware in your Django settings.
|
|
|
-
|
|
|
-.. admonition:: Behind the scenes
|
|
|
-
|
|
|
- Django's translation machinery uses the standard ``gettext`` module that
|
|
|
- comes with Python.
|
|
|
-
|
|
|
-1. How to specify translation strings
|
|
|
-=====================================
|
|
|
-
|
|
|
-Translation strings specify "This text should be translated." These strings can
|
|
|
-appear in your Python code and templates. It's your responsibility to mark
|
|
|
-translatable strings; the system can only translate strings it knows about.
|
|
|
-
|
|
|
-In Python code
|
|
|
---------------
|
|
|
-
|
|
|
-Standard translation
|
|
|
-~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Specify a translation string by using the function ``ugettext()``. It's
|
|
|
-convention to import this as a shorter alias, ``_``, to save typing.
|
|
|
-
|
|
|
-.. note::
|
|
|
- Python's standard library ``gettext`` module installs ``_()`` into the
|
|
|
- global namespace, as an alias for ``gettext()``. In Django, we have chosen
|
|
|
- not to follow this practice, for a couple of reasons:
|
|
|
-
|
|
|
- 1. For international character set (Unicode) support, ``ugettext()`` is
|
|
|
- more useful than ``gettext()``. Sometimes, you should be using
|
|
|
- ``ugettext_lazy()`` as the default translation method for a particular
|
|
|
- file. Without ``_()`` in the global namespace, the developer has to
|
|
|
- think about which is the most appropriate translation function.
|
|
|
-
|
|
|
- 2. The underscore character (``_``) is used to represent "the previous
|
|
|
- result" in Python's interactive shell and doctest tests. Installing a
|
|
|
- global ``_()`` function causes interference. Explicitly importing
|
|
|
- ``ugettext()`` as ``_()`` avoids this problem.
|
|
|
-
|
|
|
-.. highlightlang:: python
|
|
|
-
|
|
|
-In this example, the text ``"Welcome to my site."`` is marked as a translation
|
|
|
-string::
|
|
|
-
|
|
|
- from django.utils.translation import ugettext as _
|
|
|
-
|
|
|
- def my_view(request):
|
|
|
- output = _("Welcome to my site.")
|
|
|
- return HttpResponse(output)
|
|
|
-
|
|
|
-Obviously, you could code this without using the alias. This example is
|
|
|
-identical to the previous one::
|
|
|
-
|
|
|
- from django.utils.translation import ugettext
|
|
|
-
|
|
|
- def my_view(request):
|
|
|
- output = ugettext("Welcome to my site.")
|
|
|
- return HttpResponse(output)
|
|
|
-
|
|
|
-Translation works on computed values. This example is identical to the previous
|
|
|
-two::
|
|
|
-
|
|
|
- def my_view(request):
|
|
|
- words = ['Welcome', 'to', 'my', 'site.']
|
|
|
- output = _(' '.join(words))
|
|
|
- return HttpResponse(output)
|
|
|
-
|
|
|
-Translation works on variables. Again, here's an identical example::
|
|
|
-
|
|
|
- def my_view(request):
|
|
|
- sentence = 'Welcome to my site.'
|
|
|
- output = _(sentence)
|
|
|
- return HttpResponse(output)
|
|
|
-
|
|
|
-(The caveat with using variables or computed values, as in the previous two
|
|
|
-examples, is that Django's translation-string-detecting utility,
|
|
|
-``django-admin.py makemessages``, won't be able to find these strings. More on
|
|
|
-``makemessages`` later.)
|
|
|
-
|
|
|
-The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
|
|
|
-specified with Python's standard named-string interpolation syntax. Example::
|
|
|
-
|
|
|
- def my_view(request, m, d):
|
|
|
- output = _('Today is %(month)s, %(day)s.') % {'month': m, 'day': d}
|
|
|
- return HttpResponse(output)
|
|
|
-
|
|
|
-This technique lets language-specific translations reorder the placeholder
|
|
|
-text. For example, an English translation may be ``"Today is November, 26."``,
|
|
|
-while a Spanish translation may be ``"Hoy es 26 de Noviembre."`` -- with the
|
|
|
-placeholders (the month and the day) with their positions swapped.
|
|
|
-
|
|
|
-For this reason, you should use named-string interpolation (e.g., ``%(day)s``)
|
|
|
-instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
|
|
|
-have more than a single parameter. If you used positional interpolation,
|
|
|
-translations wouldn't be able to reorder placeholder text.
|
|
|
-
|
|
|
-Marking strings as no-op
|
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Use the function ``django.utils.translation.ugettext_noop()`` to mark a string
|
|
|
-as a translation string without translating it. The string is later translated
|
|
|
-from a variable.
|
|
|
-
|
|
|
-Use this if you have constant strings that should be stored in the source
|
|
|
-language because they are exchanged over systems or users -- such as strings in
|
|
|
-a database -- but should be translated at the last possible point in time, such
|
|
|
-as when the string is presented to the user.
|
|
|
-
|
|
|
-.. _lazy-translations:
|
|
|
-
|
|
|
-Lazy translation
|
|
|
-~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Use the function ``django.utils.translation.ugettext_lazy()`` to translate
|
|
|
-strings lazily -- when the value is accessed rather than when the
|
|
|
-``ugettext_lazy()`` function is called.
|
|
|
-
|
|
|
-For example, to translate a model's ``help_text``, do the following::
|
|
|
-
|
|
|
- from django.utils.translation import ugettext_lazy
|
|
|
-
|
|
|
- class MyThing(models.Model):
|
|
|
- name = models.CharField(help_text=ugettext_lazy('This is the help text'))
|
|
|
-
|
|
|
-In this example, ``ugettext_lazy()`` stores a lazy reference to the string --
|
|
|
-not the actual translation. The translation itself will be done when the string
|
|
|
-is used in a string context, such as template rendering on the Django admin
|
|
|
-site.
|
|
|
-
|
|
|
-The result of a ``ugettext_lazy()`` call can be used wherever you would use a
|
|
|
-unicode string (an object with type ``unicode``) in Python. If you try to use
|
|
|
-it where a bytestring (a ``str`` object) is expected, things will not work as
|
|
|
-expected, since a ``ugettext_lazy()`` object doesn't know how to convert
|
|
|
-itself to a bytestring. You can't use a unicode string inside a bytestring,
|
|
|
-either, so this is consistent with normal Python behavior. For example::
|
|
|
-
|
|
|
- # This is fine: putting a unicode proxy into a unicode string.
|
|
|
- u"Hello %s" % ugettext_lazy("people")
|
|
|
-
|
|
|
- # This will not work, since you cannot insert a unicode object
|
|
|
- # into a bytestring (nor can you insert our unicode proxy there)
|
|
|
- "Hello %s" % ugettext_lazy("people")
|
|
|
-
|
|
|
-If you ever see output that looks like ``"hello
|
|
|
-<django.utils.functional...>"``, you have tried to insert the result of
|
|
|
-``ugettext_lazy()`` into a bytestring. That's a bug in your code.
|
|
|
-
|
|
|
-If you don't like the verbose name ``ugettext_lazy``, you can just alias it as
|
|
|
-``_`` (underscore), like so::
|
|
|
-
|
|
|
- from django.utils.translation import ugettext_lazy as _
|
|
|
-
|
|
|
- class MyThing(models.Model):
|
|
|
- name = models.CharField(help_text=_('This is the help text'))
|
|
|
-
|
|
|
-Always use lazy translations in :ref:`Django models <topics-db-models>`.
|
|
|
-Field names and table names should be marked for translation (otherwise, they
|
|
|
-won't be translated in the admin interface). This means writing explicit
|
|
|
-``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class,
|
|
|
-though, rather than relying on Django's default determination of
|
|
|
-``verbose_name`` and ``verbose_name_plural`` by looking at the model's class
|
|
|
-name::
|
|
|
-
|
|
|
- from django.utils.translation import ugettext_lazy as _
|
|
|
-
|
|
|
- class MyThing(models.Model):
|
|
|
- name = models.CharField(_('name'), help_text=_('This is the help text'))
|
|
|
- class Meta:
|
|
|
- verbose_name = _('my thing')
|
|
|
- verbose_name_plural = _('mythings')
|
|
|
-
|
|
|
-Pluralization
|
|
|
-~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Use the function ``django.utils.translation.ungettext()`` to specify pluralized
|
|
|
-messages.
|
|
|
-
|
|
|
-``ungettext`` takes three arguments: the singular translation string, the
|
|
|
-plural translation string and the number of objects.
|
|
|
-
|
|
|
-This function is useful when you need your Django application to be localizable
|
|
|
-to languages where the number and complexity of `plural forms
|
|
|
-<http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is
|
|
|
-greater than the two forms used in English ('object' for the singular and
|
|
|
-'objects' for all the cases where ``count`` is different from zero,
|
|
|
-irrespective of its value).
|
|
|
-
|
|
|
-For example::
|
|
|
-
|
|
|
- from django.utils.translation import ungettext
|
|
|
- def hello_world(request, count):
|
|
|
- page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % {
|
|
|
- 'count': count,
|
|
|
- }
|
|
|
- return HttpResponse(page)
|
|
|
-
|
|
|
-In this example the number of objects is passed to the translation languages as
|
|
|
-the ``count`` variable.
|
|
|
-
|
|
|
-Lets see a slightly more complex usage example::
|
|
|
-
|
|
|
- from django.utils.translation import ungettext
|
|
|
-
|
|
|
- count = Report.objects.count()
|
|
|
- if count == 1:
|
|
|
- name = Report._meta.verbose_name
|
|
|
- else:
|
|
|
- name = Report._meta.verbose_name_plural
|
|
|
-
|
|
|
- text = ungettext(
|
|
|
- 'There is %(count)d %(name)s available.',
|
|
|
- 'There are %(count)d %(name)s available.',
|
|
|
- count
|
|
|
- ) % {
|
|
|
- 'count': count,
|
|
|
- 'name': name
|
|
|
- }
|
|
|
-
|
|
|
-Here we reuse localizable, hopefully already translated literals (contained in
|
|
|
-the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for
|
|
|
-other parts of the sentence so all of it is consistently based on the
|
|
|
-cardinality of the elements at play.
|
|
|
-
|
|
|
-.. _pluralization-var-notes:
|
|
|
-
|
|
|
-.. note::
|
|
|
-
|
|
|
- When using this technique, make sure you use a single name for every
|
|
|
- extrapolated variable included in the literal. In the example above note
|
|
|
- how we used the ``name`` Python variable in both translation strings. This
|
|
|
- example would fail::
|
|
|
-
|
|
|
- from django.utils.translation import ungettext
|
|
|
- from myapp.models import Report
|
|
|
-
|
|
|
- count = Report.objects.count()
|
|
|
- d = {
|
|
|
- 'count': count,
|
|
|
- 'name': Report._meta.verbose_name
|
|
|
- 'plural_name': Report._meta.verbose_name_plural
|
|
|
- }
|
|
|
- text = ungettext(
|
|
|
- 'There is %(count)d %(name)s available.',
|
|
|
- 'There are %(count)d %(plural_name)s available.',
|
|
|
- count
|
|
|
- ) % d
|
|
|
-
|
|
|
- You would get a ``a format specification for argument 'name', as in
|
|
|
- 'msgstr[0]', doesn't exist in 'msgid'`` error when running
|
|
|
- ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at
|
|
|
- runtime.
|
|
|
-
|
|
|
-In template code
|
|
|
-----------------
|
|
|
-
|
|
|
-.. highlightlang:: html+django
|
|
|
-
|
|
|
-Translations in :ref:`Django templates <topics-templates>` uses two template
|
|
|
-tags and a slightly different syntax than in Python code. To give your template
|
|
|
-access to these tags, put ``{% load i18n %}`` toward the top of your template.
|
|
|
-
|
|
|
-The ``{% trans %}`` template tag translates either a constant string
|
|
|
-(enclosed in single or double quotes) or variable content::
|
|
|
-
|
|
|
- <title>{% trans "This is the title." %}</title>
|
|
|
- <title>{% trans myvar %}</title>
|
|
|
-
|
|
|
-If the ``noop`` option is present, variable lookup still takes place, but the
|
|
|
-original text will be returned unchanged. This is useful when "stubbing out"
|
|
|
-content that will require translation in the future::
|
|
|
-
|
|
|
- <title>{% trans "myvar" noop %}</title>
|
|
|
-
|
|
|
-Internally, inline translations use an ``ugettext`` call.
|
|
|
-
|
|
|
-It's not possible to mix a template variable inside a string within ``{% trans
|
|
|
-%}``. If your translations require strings with variables (placeholders), use
|
|
|
-``{% blocktrans %}``::
|
|
|
-
|
|
|
- {% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}
|
|
|
-
|
|
|
-To translate a template expression -- say, using template filters -- you need
|
|
|
-to bind the expression to a local variable for use within the translation
|
|
|
-block::
|
|
|
-
|
|
|
- {% blocktrans with value|filter as myvar %}
|
|
|
- This will have {{ myvar }} inside.
|
|
|
- {% endblocktrans %}
|
|
|
-
|
|
|
-If you need to bind more than one expression inside a ``blocktrans`` tag,
|
|
|
-separate the pieces with ``and``::
|
|
|
-
|
|
|
- {% blocktrans with book|title as book_t and author|title as author_t %}
|
|
|
- This is {{ book_t }} by {{ author_t }}
|
|
|
- {% endblocktrans %}
|
|
|
-
|
|
|
-To pluralize, specify both the singular and plural forms with the
|
|
|
-``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and
|
|
|
-``{% endblocktrans %}``. Example::
|
|
|
-
|
|
|
- {% blocktrans count list|length as counter %}
|
|
|
- There is only one {{ name }} object.
|
|
|
- {% plural %}
|
|
|
- There are {{ counter }} {{ name }} objects.
|
|
|
- {% endblocktrans %}
|
|
|
-
|
|
|
-When you use the pluralization feature and bind additional values to local
|
|
|
-variables apart from the counter value that selects the translated literal to
|
|
|
-be used, have in mind that the ``blocktrans`` construct is internally converted
|
|
|
-to an ``ungettext`` call. This means the same :ref:`notes regarding ungettext
|
|
|
-variables <pluralization-var-notes>` apply.
|
|
|
-
|
|
|
-Each ``RequestContext`` has access to three translation-specific variables:
|
|
|
-
|
|
|
- * ``LANGUAGES`` is a list of tuples in which the first element is the
|
|
|
- language code and the second is the language name (translated into the
|
|
|
- currently active locale).
|
|
|
-
|
|
|
- * ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
|
|
|
- Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`,
|
|
|
- below.)
|
|
|
-
|
|
|
- * ``LANGUAGE_BIDI`` is the current locale's direction. If True, it's a
|
|
|
- right-to-left language, e.g.: Hebrew, Arabic. If False it's a
|
|
|
- left-to-right language, e.g.: English, French, German etc.
|
|
|
-
|
|
|
-
|
|
|
-If you don't use the ``RequestContext`` extension, you can get those values
|
|
|
-with three tags::
|
|
|
-
|
|
|
- {% get_current_language as LANGUAGE_CODE %}
|
|
|
- {% get_available_languages as LANGUAGES %}
|
|
|
- {% get_current_language_bidi as LANGUAGE_BIDI %}
|
|
|
-
|
|
|
-These tags also require a ``{% load i18n %}``.
|
|
|
-
|
|
|
-Translation hooks are also available within any template block tag that accepts
|
|
|
-constant strings. In those cases, just use ``_()`` syntax to specify a
|
|
|
-translation string::
|
|
|
-
|
|
|
- {% some_special_tag _("Page not found") value|yesno:_("yes,no") %}
|
|
|
-
|
|
|
-In this case, both the tag and the filter will see the already-translated
|
|
|
-string, so they don't need to be aware of translations.
|
|
|
-
|
|
|
-.. note::
|
|
|
- In this example, the translation infrastructure will be passed the string
|
|
|
- ``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The
|
|
|
- translated string will need to contain the comma so that the filter
|
|
|
- parsing code knows how to split up the arguments. For example, a German
|
|
|
- translator might translate the string ``"yes,no"`` as ``"ja,nein"``
|
|
|
- (keeping the comma intact).
|
|
|
-
|
|
|
-.. _Django templates: ../templates_python/
|
|
|
-
|
|
|
-Working with lazy translation objects
|
|
|
--------------------------------------
|
|
|
-
|
|
|
-.. highlightlang:: python
|
|
|
-
|
|
|
-Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models
|
|
|
-and utility functions is a common operation. When you're working with these
|
|
|
-objects elsewhere in your code, you should ensure that you don't accidentally
|
|
|
-convert them to strings, because they should be converted as late as possible
|
|
|
-(so that the correct locale is in effect). This necessitates the use of a
|
|
|
-couple of helper functions.
|
|
|
-
|
|
|
-Joining strings: string_concat()
|
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Standard Python string joins (``''.join([...])``) will not work on lists
|
|
|
-containing lazy translation objects. Instead, you can use
|
|
|
-``django.utils.translation.string_concat()``, which creates a lazy object that
|
|
|
-concatenates its contents *and* converts them to strings only when the result
|
|
|
-is included in a string. For example::
|
|
|
-
|
|
|
- from django.utils.translation import string_concat
|
|
|
- ...
|
|
|
- name = ugettext_lazy(u'John Lennon')
|
|
|
- instrument = ugettext_lazy(u'guitar')
|
|
|
- result = string_concat([name, ': ', instrument])
|
|
|
-
|
|
|
-In this case, the lazy translations in ``result`` will only be converted to
|
|
|
-strings when ``result`` itself is used in a string (usually at template
|
|
|
-rendering time).
|
|
|
-
|
|
|
-The allow_lazy() decorator
|
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
-
|
|
|
-Django offers many utility functions (particularly in ``django.utils``) that
|
|
|
-take a string as their first argument and do something to that string. These
|
|
|
-functions are used by template filters as well as directly in other code.
|
|
|
-
|
|
|
-If you write your own similar functions and deal with translations, you'll
|
|
|
-face the problem of what to do when the first argument is a lazy translation
|
|
|
-object. You don't want to convert it to a string immediately, because you might
|
|
|
-be using this function outside of a view (and hence the current thread's locale
|
|
|
-setting will not be correct).
|
|
|
-
|
|
|
-For cases like this, use the ``django.utils.functional.allow_lazy()``
|
|
|
-decorator. It modifies the function so that *if* it's called with a lazy
|
|
|
-translation as the first argument, the function evaluation is delayed until it
|
|
|
-needs to be converted to a string.
|
|
|
-
|
|
|
-For example::
|
|
|
-
|
|
|
- from django.utils.functional import allow_lazy
|
|
|
-
|
|
|
- def fancy_utility_function(s, ...):
|
|
|
- # Do some conversion on string 's'
|
|
|
- ...
|
|
|
- fancy_utility_function = allow_lazy(fancy_utility_function, unicode)
|
|
|
-
|
|
|
-The ``allow_lazy()`` decorator takes, in addition to the function to decorate,
|
|
|
-a number of extra arguments (``*args``) specifying the type(s) that the
|
|
|
-original function can return. Usually, it's enough to include ``unicode`` here
|
|
|
-and ensure that your function returns only Unicode strings.
|
|
|
-
|
|
|
-Using this decorator means you can write your function and assume that the
|
|
|
-input is a proper string, then add support for lazy translation objects at the
|
|
|
-end.
|
|
|
-
|
|
|
-.. _how-to-create-language-files:
|
|
|
-
|
|
|
-2. How to create language files
|
|
|
-===============================
|
|
|
-
|
|
|
-Once you've tagged your strings for later translation, you need to write (or
|
|
|
-obtain) the language translations themselves. Here's how that works.
|
|
|
-
|
|
|
-.. admonition:: Locale restrictions
|
|
|
-
|
|
|
- Django does not support localizing your application into a locale for
|
|
|
- which Django itself has not been translated. In this case, it will ignore
|
|
|
- your translation files. If you were to try this and Django supported it,
|
|
|
- you would inevitably see a mixture of translated strings (from your
|
|
|
- application) and English strings (from Django itself). If you want to
|
|
|
- support a locale for your application that is not already part of
|
|
|
- Django, you'll need to make at least a minimal translation of the Django
|
|
|
- core. See the relevant :ref:`LocaleMiddleware note<locale-middleware-notes>`
|
|
|
- for more details.
|
|
|
-
|
|
|
-Message files
|
|
|
--------------
|
|
|
-
|
|
|
-The first step is to create a **message file** for a new language. A message
|
|
|
-file is a plain-text file, representing a single language, that contains all
|
|
|
-available translation strings and how they should be represented in the given
|
|
|
-language. Message files have a ``.po`` file extension.
|
|
|
-
|
|
|
-Django comes with a tool, ``django-admin.py makemessages``, that automates the
|
|
|
-creation and upkeep of these files.
|
|
|
-
|
|
|
-.. admonition:: A note to Django veterans
|
|
|
-
|
|
|
- The old tool ``bin/make-messages.py`` has been moved to the command
|
|
|
- ``django-admin.py makemessages`` to provide consistency throughout Django.
|
|
|
-
|
|
|
-.. admonition:: Gettext utilities
|
|
|
-
|
|
|
- The ``makemessages`` command (and ``compilemessages`` discussed later) use
|
|
|
- commands from the GNU gettext toolset: ``xgetetxt``, ``msgfmt``,
|
|
|
- ``msgmerge`` and ``msguniq``.
|
|
|
-
|
|
|
- .. versionchanged:: 1.2
|
|
|
-
|
|
|
- The minimum version of the ``gettext`` utilities supported is 0.15.
|
|
|
-
|
|
|
-To create or update a message file, run this command::
|
|
|
-
|
|
|
- django-admin.py makemessages -l de
|
|
|
-
|
|
|
-...where ``de`` is the language code for the message file you want to create.
|
|
|
-The language code, in this case, is in locale format. For example, it's
|
|
|
-``pt_BR`` for Brazilian Portuguese and ``de_AT`` for Austrian German.
|
|
|
-
|
|
|
-The script should be run from one of three places:
|
|
|
-
|
|
|
- * The root directory of your Django project.
|
|
|
- * The root directory of your Django app.
|
|
|
- * The root ``django`` directory (not a Subversion checkout, but the one
|
|
|
- that is linked-to via ``$PYTHONPATH`` or is located somewhere on that
|
|
|
- path). This is only relevant when you are creating a translation for
|
|
|
- Django itself, see :ref:`contributing-translations`.
|
|
|
-
|
|
|
-The script runs over your project source tree or your application source tree
|
|
|
-and pulls out all strings marked for translation. It creates (or updates) a
|
|
|
-message file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de``
|
|
|
-example, the file will be ``locale/de/LC_MESSAGES/django.po``.
|
|
|
-
|
|
|
-By default ``django-admin.py makemessages`` examines every file that has the
|
|
|
-``.html`` file extension. In case you want to override that default, use the
|
|
|
-``--extension`` or ``-e`` option to specify the file extensions to examine::
|
|
|
-
|
|
|
- django-admin.py makemessages -l de -e txt
|
|
|
-
|
|
|
-Separate multiple extensions with commas and/or use ``-e`` or ``--extension``
|
|
|
-multiple times::
|
|
|
-
|
|
|
- django-admin.py makemessages -l=de -e=html,txt -e xml
|
|
|
-
|
|
|
-When `creating JavaScript translation catalogs`_ you need to use the special
|
|
|
-'djangojs' domain, **not** ``-e js``.
|
|
|
-
|
|
|
-.. admonition:: No gettext?
|
|
|
-
|
|
|
- If you don't have the ``gettext`` utilities installed, ``django-admin.py
|
|
|
- makemessages`` will create empty files. If that's the case, either install
|
|
|
- the ``gettext`` utilities or just copy the English message file
|
|
|
- (``locale/en/LC_MESSAGES/django.po``) if available and use it as a starting
|
|
|
- point; it's just an empty translation file.
|
|
|
-
|
|
|
-.. admonition:: Working on Windows?
|
|
|
-
|
|
|
- If you're using Windows and need to install the GNU gettext utilities so
|
|
|
- ``django-admin makemessages`` works see `gettext on Windows`_ for more
|
|
|
- information.
|
|
|
-
|
|
|
-The format of ``.po`` files is straightforward. Each ``.po`` file contains a
|
|
|
-small bit of metadata, such as the translation maintainer's contact
|
|
|
-information, but the bulk of the file is a list of **messages** -- simple
|
|
|
-mappings between translation strings and the actual translated text for the
|
|
|
-particular language.
|
|
|
-
|
|
|
-For example, if your Django app contained a translation string for the text
|
|
|
-``"Welcome to my site."``, like so::
|
|
|
-
|
|
|
- _("Welcome to my site.")
|
|
|
-
|
|
|
-...then ``django-admin.py makemessages`` will have created a ``.po`` file
|
|
|
-containing the following snippet -- a message::
|
|
|
-
|
|
|
- #: path/to/python/module.py:23
|
|
|
- msgid "Welcome to my site."
|
|
|
- msgstr ""
|
|
|
-
|
|
|
-A quick explanation:
|
|
|
-
|
|
|
- * ``msgid`` is the translation string, which appears in the source. Don't
|
|
|
- change it.
|
|
|
- * ``msgstr`` is where you put the language-specific translation. It starts
|
|
|
- out empty, so it's your responsibility to change it. Make sure you keep
|
|
|
- the quotes around your translation.
|
|
|
- * As a convenience, each message includes, in the form of a comment line
|
|
|
- prefixed with ``#`` and located above the ``msgid`` line, the filename
|
|
|
- and line number from which the translation string was gleaned.
|
|
|
-
|
|
|
-Long messages are a special case. There, the first string directly after the
|
|
|
-``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be
|
|
|
-written over the next few lines as one string per line. Those strings are
|
|
|
-directly concatenated. Don't forget trailing spaces within the strings;
|
|
|
-otherwise, they'll be tacked together without whitespace!
|
|
|
-
|
|
|
-.. admonition:: Mind your charset
|
|
|
-
|
|
|
- When creating a PO file with your favorite text editor, first edit
|
|
|
- the charset line (search for ``"CHARSET"``) and set it to the charset
|
|
|
- you'll be using to edit the content. Due to the way the ``gettext`` tools
|
|
|
- work internally and because we want to allow non-ASCII source strings in
|
|
|
- Django's core and your applications, you **must** use UTF-8 as the encoding
|
|
|
- for your PO file. This means that everybody will be using the same
|
|
|
- encoding, which is important when Django processes the PO files.
|
|
|
-
|
|
|
-To reexamine all source code and templates for new translation strings and
|
|
|
-update all message files for **all** languages, run this::
|
|
|
-
|
|
|
- django-admin.py makemessages -a
|
|
|
-
|
|
|
-Compiling message files
|
|
|
------------------------
|
|
|
-
|
|
|
-After you create your message file -- and each time you make changes to it --
|
|
|
-you'll need to compile it into a more efficient form, for use by ``gettext``.
|
|
|
-Do this with the ``django-admin.py compilemessages`` utility.
|
|
|
-
|
|
|
-This tool runs over all available ``.po`` files and creates ``.mo`` files,
|
|
|
-which are binary files optimized for use by ``gettext``. In the same directory
|
|
|
-from which you ran ``django-admin.py makemessages``, run ``django-admin.py
|
|
|
-compilemessages`` like this::
|
|
|
-
|
|
|
- django-admin.py compilemessages
|
|
|
-
|
|
|
-That's it. Your translations are ready for use.
|
|
|
-
|
|
|
-.. admonition:: A note to Django veterans
|
|
|
-
|
|
|
- The old tool ``bin/compile-messages.py`` has been moved to the command
|
|
|
- ``django-admin.py compilemessages`` to provide consistency throughout
|
|
|
- Django.
|
|
|
-
|
|
|
-.. admonition:: Working on Windows?
|
|
|
-
|
|
|
- If you're using Windows and need to install the GNU gettext utilities so
|
|
|
- ``django-admin compilemessages`` works see `gettext on Windows`_ for more
|
|
|
- information.
|
|
|
-
|
|
|
-.. _how-django-discovers-language-preference:
|
|
|
-
|
|
|
-3. How Django discovers language preference
|
|
|
-===========================================
|
|
|
-
|
|
|
-Once you've prepared your translations -- or, if you just want to use the
|
|
|
-translations that come with Django -- you'll just need to activate translation
|
|
|
-for your app.
|
|
|
-
|
|
|
-Behind the scenes, Django has a very flexible model of deciding which language
|
|
|
-should be used -- installation-wide, for a particular user, or both.
|
|
|
-
|
|
|
-To set an installation-wide language preference, set :setting:`LANGUAGE_CODE`.
|
|
|
-Django uses this language as the default translation -- the final attempt if no
|
|
|
-other translator finds a translation.
|
|
|
-
|
|
|
-If all you want to do is run Django with your native language, and a language
|
|
|
-file is available for your language, all you need to do is set
|
|
|
-``LANGUAGE_CODE``.
|
|
|
-
|
|
|
-If you want to let each individual user specify which language he or she
|
|
|
-prefers, use ``LocaleMiddleware``. ``LocaleMiddleware`` enables language
|
|
|
-selection based on data from the request. It customizes content for each user.
|
|
|
-
|
|
|
-To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'``
|
|
|
-to your ``MIDDLEWARE_CLASSES`` setting. Because middleware order matters, you
|
|
|
-should follow these guidelines:
|
|
|
-
|
|
|
- * Make sure it's one of the first middlewares installed.
|
|
|
- * It should come after ``SessionMiddleware``, because ``LocaleMiddleware``
|
|
|
- makes use of session data.
|
|
|
- * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it.
|
|
|
-
|
|
|
-For example, your ``MIDDLEWARE_CLASSES`` might look like this::
|
|
|
-
|
|
|
- MIDDLEWARE_CLASSES = (
|
|
|
- 'django.contrib.sessions.middleware.SessionMiddleware',
|
|
|
- 'django.middleware.locale.LocaleMiddleware',
|
|
|
- 'django.middleware.common.CommonMiddleware',
|
|
|
- )
|
|
|
-
|
|
|
-(For more on middleware, see the :ref:`middleware documentation
|
|
|
-<topics-http-middleware>`.)
|
|
|
-
|
|
|
-``LocaleMiddleware`` tries to determine the user's language preference by
|
|
|
-following this algorithm:
|
|
|
-
|
|
|
- * First, it looks for a ``django_language`` key in the current user's
|
|
|
- session.
|
|
|
-
|
|
|
- * Failing that, it looks for a cookie.
|
|
|
-
|
|
|
- .. versionchanged:: 1.0
|
|
|
-
|
|
|
- In Django version 0.96 and before, the cookie's name is hard-coded to
|
|
|
- ``django_language``. In Django 1,0, The cookie name is set by the
|
|
|
- ``LANGUAGE_COOKIE_NAME`` setting. (The default name is
|
|
|
- ``django_language``.)
|
|
|
-
|
|
|
- * Failing that, it looks at the ``Accept-Language`` HTTP header. This
|
|
|
- header is sent by your browser and tells the server which language(s) you
|
|
|
- prefer, in order by priority. Django tries each language in the header
|
|
|
- until it finds one with available translations.
|
|
|
-
|
|
|
- * Failing that, it uses the global ``LANGUAGE_CODE`` setting.
|
|
|
-
|
|
|
-.. _locale-middleware-notes:
|
|
|
-
|
|
|
-Notes:
|
|
|
-
|
|
|
- * In each of these places, the language preference is expected to be in the
|
|
|
- standard language format, as a string. For example, Brazilian Portuguese
|
|
|
- is ``pt-br``.
|
|
|
-
|
|
|
- * If a base language is available but the sublanguage specified is not,
|
|
|
- Django uses the base language. For example, if a user specifies ``de-at``
|
|
|
- (Austrian German) but Django only has ``de`` available, Django uses
|
|
|
- ``de``.
|
|
|
-
|
|
|
- * Only languages listed in the :setting:`LANGUAGES` setting can be selected.
|
|
|
- If you want to restrict the language selection to a subset of provided
|
|
|
- languages (because your application doesn't provide all those languages),
|
|
|
- set ``LANGUAGES`` to a list of languages. For example::
|
|
|
-
|
|
|
- LANGUAGES = (
|
|
|
- ('de', _('German')),
|
|
|
- ('en', _('English')),
|
|
|
- )
|
|
|
-
|
|
|
- This example restricts languages that are available for automatic
|
|
|
- selection to German and English (and any sublanguage, like de-ch or
|
|
|
- en-us).
|
|
|
-
|
|
|
- .. _LANGUAGES setting: ../settings/#languages
|
|
|
-
|
|
|
- * If you define a custom ``LANGUAGES`` setting, as explained in the
|
|
|
- previous bullet, it's OK to mark the languages as translation strings
|
|
|
- -- but use a "dummy" ``ugettext()`` function, not the one in
|
|
|
- ``django.utils.translation``. You should *never* import
|
|
|
- ``django.utils.translation`` from within your settings file, because that
|
|
|
- module in itself depends on the settings, and that would cause a circular
|
|
|
- import.
|
|
|
-
|
|
|
- The solution is to use a "dummy" ``ugettext()`` function. Here's a sample
|
|
|
- settings file::
|
|
|
-
|
|
|
- ugettext = lambda s: s
|
|
|
-
|
|
|
- LANGUAGES = (
|
|
|
- ('de', ugettext('German')),
|
|
|
- ('en', ugettext('English')),
|
|
|
- )
|
|
|
-
|
|
|
- With this arrangement, ``django-admin.py makemessages`` will still find
|
|
|
- and mark these strings for translation, but the translation won't happen
|
|
|
- at runtime -- so you'll have to remember to wrap the languages in the
|
|
|
- *real* ``ugettext()`` in any code that uses ``LANGUAGES`` at runtime.
|
|
|
-
|
|
|
- * The ``LocaleMiddleware`` can only select languages for which there is a
|
|
|
- Django-provided base translation. If you want to provide translations
|
|
|
- for your application that aren't already in the set of translations
|
|
|
- in Django's source tree, you'll want to provide at least basic
|
|
|
- translations for that language. For example, Django uses technical
|
|
|
- message IDs to translate date formats and time formats -- so you will
|
|
|
- need at least those translations for the system to work correctly.
|
|
|
-
|
|
|
- A good starting point is to copy the English ``.po`` file and to
|
|
|
- translate at least the technical messages -- maybe the validation
|
|
|
- messages, too.
|
|
|
-
|
|
|
- Technical message IDs are easily recognized; they're all upper case. You
|
|
|
- don't translate the message ID as with other messages, you provide the
|
|
|
- correct local variant on the provided English value. For example, with
|
|
|
- ``DATETIME_FORMAT`` (or ``DATE_FORMAT`` or ``TIME_FORMAT``), this would
|
|
|
- be the format string that you want to use in your language. The format
|
|
|
- is identical to the format strings used by the ``now`` template tag.
|
|
|
-
|
|
|
-Once ``LocaleMiddleware`` determines the user's preference, it makes this
|
|
|
-preference available as ``request.LANGUAGE_CODE`` for each
|
|
|
-:class:`~django.http.HttpRequest`. Feel free to read this value in your view
|
|
|
-code. Here's a simple example::
|
|
|
-
|
|
|
- def hello_world(request, count):
|
|
|
- if request.LANGUAGE_CODE == 'de-at':
|
|
|
- return HttpResponse("You prefer to read Austrian German.")
|
|
|
- else:
|
|
|
- return HttpResponse("You prefer to read another language.")
|
|
|
-
|
|
|
-Note that, with static (middleware-less) translation, the language is in
|
|
|
-``settings.LANGUAGE_CODE``, while with dynamic (middleware) translation, it's
|
|
|
-in ``request.LANGUAGE_CODE``.
|
|
|
-
|
|
|
-.. _settings file: ../settings/
|
|
|
-.. _middleware documentation: ../middleware/
|
|
|
-.. _session: ../sessions/
|
|
|
-.. _request object: ../request_response/#httprequest-objects
|
|
|
-
|
|
|
-.. _translations-in-your-own-projects:
|
|
|
-
|
|
|
-Using translations in your own projects
|
|
|
-=======================================
|
|
|
-
|
|
|
-Django looks for translations by following this algorithm:
|
|
|
-
|
|
|
- * First, it looks for a ``locale`` directory in the application directory
|
|
|
- of the view that's being called. If it finds a translation for the
|
|
|
- selected language, the translation will be installed.
|
|
|
- * Next, it looks for a ``locale`` directory in the project directory. If it
|
|
|
- finds a translation, the translation will be installed.
|
|
|
- * Finally, it checks the Django-provided base translation in
|
|
|
- ``django/conf/locale``.
|
|
|
-
|
|
|
-This way, you can write applications that include their own translations, and
|
|
|
-you can override base translations in your project path. Or, you can just build
|
|
|
-a big project out of several apps and put all translations into one big project
|
|
|
-message file. The choice is yours.
|
|
|
-
|
|
|
-.. note::
|
|
|
-
|
|
|
- If you're using manually configured settings, as described
|
|
|
- :ref:`settings-without-django-settings-module`, the ``locale`` directory in
|
|
|
- the project directory will not be examined, since Django loses the ability
|
|
|
- to work out the location of the project directory. (Django normally uses
|
|
|
- the location of the settings file to determine this, and a settings file
|
|
|
- doesn't exist if you're manually configuring your settings.)
|
|
|
-
|
|
|
-All message file repositories are structured the same way. They are:
|
|
|
-
|
|
|
- * ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
- * ``$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
- * All paths listed in ``LOCALE_PATHS`` in your settings file are
|
|
|
- searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
- * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
-
|
|
|
-To create message files, you use the same ``django-admin.py makemessages``
|
|
|
-tool as with the Django message files. You only need to be in the right place
|
|
|
--- in the directory where either the ``conf/locale`` (in case of the source
|
|
|
-tree) or the ``locale/`` (in case of app messages or project messages)
|
|
|
-directory are located. And you use the same ``django-admin.py
|
|
|
-compilemessages`` to produce the binary ``django.mo`` files that are used by
|
|
|
-``gettext``.
|
|
|
-
|
|
|
-You can also run ``django-admin.py compilemessages
|
|
|
---settings=path.to.settings`` to make the compiler process all the directories
|
|
|
-in your ``LOCALE_PATHS`` setting.
|
|
|
-
|
|
|
-Application message files are a bit complicated to discover -- they need the
|
|
|
-``LocaleMiddleware``. If you don't use the middleware, only the Django message
|
|
|
-files and project message files will be processed.
|
|
|
-
|
|
|
-Finally, you should give some thought to the structure of your translation
|
|
|
-files. If your applications need to be delivered to other users and will
|
|
|
-be used in other projects, you might want to use app-specific translations.
|
|
|
-But using app-specific translations and project translations could produce
|
|
|
-weird problems with ``makemessages``: ``makemessages`` will traverse all
|
|
|
-directories below the current path and so might put message IDs into the
|
|
|
-project message file that are already in application message files.
|
|
|
-
|
|
|
-The easiest way out is to store applications that are not part of the project
|
|
|
-(and so carry their own translations) outside the project tree. That way,
|
|
|
-``django-admin.py makemessages`` on the project level will only translate
|
|
|
-strings that are connected to your explicit project and not strings that are
|
|
|
-distributed independently.
|
|
|
-
|
|
|
-The ``set_language`` redirect view
|
|
|
-==================================
|
|
|
-
|
|
|
-As a convenience, Django comes with a view, ``django.views.i18n.set_language``,
|
|
|
-that sets a user's language preference and redirects back to the previous page.
|
|
|
-
|
|
|
-Activate this view by adding the following line to your URLconf::
|
|
|
-
|
|
|
- (r'^i18n/', include('django.conf.urls.i18n')),
|
|
|
-
|
|
|
-(Note that this example makes the view available at ``/i18n/setlang/``.)
|
|
|
-
|
|
|
-The view expects to be called via the ``POST`` method, with a ``language``
|
|
|
-parameter set in request. If session support is enabled, the view
|
|
|
-saves the language choice in the user's session. Otherwise, it saves the
|
|
|
-language choice in a cookie that is by default named ``django_language``.
|
|
|
-(The name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting.)
|
|
|
-
|
|
|
-After setting the language choice, Django redirects the user, following this
|
|
|
-algorithm:
|
|
|
-
|
|
|
- * Django looks for a ``next`` parameter in the ``POST`` data.
|
|
|
- * If that doesn't exist, or is empty, Django tries the URL in the
|
|
|
- ``Referrer`` header.
|
|
|
- * If that's empty -- say, if a user's browser suppresses that header --
|
|
|
- then the user will be redirected to ``/`` (the site root) as a fallback.
|
|
|
-
|
|
|
-Here's example HTML template code:
|
|
|
-
|
|
|
-.. code-block:: html+django
|
|
|
-
|
|
|
- <form action="/i18n/setlang/" method="post">
|
|
|
- <input name="next" type="hidden" value="/next/page/" />
|
|
|
- <select name="language">
|
|
|
- {% for lang in LANGUAGES %}
|
|
|
- <option value="{{ lang.0 }}">{{ lang.1 }}</option>
|
|
|
- {% endfor %}
|
|
|
- </select>
|
|
|
- <input type="submit" value="Go" />
|
|
|
- </form>
|
|
|
-
|
|
|
-Translations and JavaScript
|
|
|
-===========================
|
|
|
-
|
|
|
-Adding translations to JavaScript poses some problems:
|
|
|
-
|
|
|
- * JavaScript code doesn't have access to a ``gettext`` implementation.
|
|
|
-
|
|
|
- * JavaScript code doesn't have access to .po or .mo files; they need to be
|
|
|
- delivered by the server.
|
|
|
-
|
|
|
- * The translation catalogs for JavaScript should be kept as small as
|
|
|
- possible.
|
|
|
-
|
|
|
-Django provides an integrated solution for these problems: It passes the
|
|
|
-translations into JavaScript, so you can call ``gettext``, etc., from within
|
|
|
-JavaScript.
|
|
|
-
|
|
|
-The ``javascript_catalog`` view
|
|
|
--------------------------------
|
|
|
-
|
|
|
-The main solution to these problems is the ``javascript_catalog`` view, which
|
|
|
-sends out a JavaScript code library with functions that mimic the ``gettext``
|
|
|
-interface, plus an array of translation strings. Those translation strings are
|
|
|
-taken from the application, project or Django core, according to what you
|
|
|
-specify in either the info_dict or the URL.
|
|
|
-
|
|
|
-You hook it up like this::
|
|
|
-
|
|
|
- js_info_dict = {
|
|
|
- 'packages': ('your.app.package',),
|
|
|
- }
|
|
|
-
|
|
|
- urlpatterns = patterns('',
|
|
|
- (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
|
|
- )
|
|
|
-
|
|
|
-Each string in ``packages`` should be in Python dotted-package syntax (the
|
|
|
-same format as the strings in ``INSTALLED_APPS``) and should refer to a package
|
|
|
-that contains a ``locale`` directory. If you specify multiple packages, all
|
|
|
-those catalogs are merged into one catalog. This is useful if you have
|
|
|
-JavaScript that uses strings from different applications.
|
|
|
-
|
|
|
-You can make the view dynamic by putting the packages into the URL pattern::
|
|
|
-
|
|
|
- urlpatterns = patterns('',
|
|
|
- (r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
|
|
|
- )
|
|
|
-
|
|
|
-With this, you specify the packages as a list of package names delimited by '+'
|
|
|
-signs in the URL. This is especially useful if your pages use code from
|
|
|
-different apps and this changes often and you don't want to pull in one big
|
|
|
-catalog file. As a security measure, these values can only be either
|
|
|
-``django.conf`` or any package from the ``INSTALLED_APPS`` setting.
|
|
|
-
|
|
|
-Using the JavaScript translation catalog
|
|
|
-----------------------------------------
|
|
|
-
|
|
|
-To use the catalog, just pull in the dynamically generated script like this::
|
|
|
-
|
|
|
- <script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
|
|
|
-
|
|
|
-This uses reverse URL lookup to find the URL of the JavaScript catalog view.
|
|
|
-When the catalog is loaded, your JavaScript code can use the standard
|
|
|
-``gettext`` interface to access it::
|
|
|
-
|
|
|
- document.write(gettext('this is to be translated'));
|
|
|
-
|
|
|
-There is also an ``ngettext`` interface::
|
|
|
-
|
|
|
- var object_cnt = 1 // or 0, or 2, or 3, ...
|
|
|
- s = ngettext('literal for the singular case',
|
|
|
- 'literal for the plural case', object_cnt);
|
|
|
-
|
|
|
-and even a string interpolation function::
|
|
|
-
|
|
|
- function interpolate(fmt, obj, named);
|
|
|
-
|
|
|
-The interpolation syntax is borrowed from Python, so the ``interpolate``
|
|
|
-function supports both positional and named interpolation:
|
|
|
-
|
|
|
- * Positional interpolation: ``obj`` contains a JavaScript Array object
|
|
|
- whose elements values are then sequentially interpolated in their
|
|
|
- corresponding ``fmt`` placeholders in the same order they appear.
|
|
|
- For example::
|
|
|
-
|
|
|
- fmts = ngettext('There is %s object. Remaining: %s',
|
|
|
- 'There are %s objects. Remaining: %s', 11);
|
|
|
- s = interpolate(fmts, [11, 20]);
|
|
|
- // s is 'There are 11 objects. Remaining: 20'
|
|
|
-
|
|
|
- * Named interpolation: This mode is selected by passing the optional
|
|
|
- boolean ``named`` parameter as true. ``obj`` contains a JavaScript
|
|
|
- object or associative array. For example::
|
|
|
-
|
|
|
- d = {
|
|
|
- count: 10
|
|
|
- total: 50
|
|
|
- };
|
|
|
-
|
|
|
- fmts = ngettext('Total: %(total)s, there is %(count)s object',
|
|
|
- 'there are %(count)s of a total of %(total)s objects', d.count);
|
|
|
- s = interpolate(fmts, d, true);
|
|
|
-
|
|
|
-You shouldn't go over the top with string interpolation, though: this is still
|
|
|
-JavaScript, so the code has to make repeated regular-expression substitutions.
|
|
|
-This isn't as fast as string interpolation in Python, so keep it to those
|
|
|
-cases where you really need it (for example, in conjunction with ``ngettext``
|
|
|
-to produce proper pluralizations).
|
|
|
-
|
|
|
-Creating JavaScript translation catalogs
|
|
|
-----------------------------------------
|
|
|
-
|
|
|
-You create and update the translation catalogs the same way as the other
|
|
|
-
|
|
|
-Django translation catalogs -- with the ``django-admin.py makemessages`` tool.
|
|
|
-The only difference is you need to provide a ``-d djangojs`` parameter, like
|
|
|
-this::
|
|
|
-
|
|
|
- django-admin.py makemessages -d djangojs -l de
|
|
|
-
|
|
|
-This would create or update the translation catalog for JavaScript for German.
|
|
|
-After updating translation catalogs, just run ``django-admin.py
|
|
|
-compilemessages`` the same way as you do with normal Django translation
|
|
|
-catalogs.
|
|
|
-
|
|
|
-Specialties of Django translation
|
|
|
-==================================
|
|
|
-
|
|
|
-If you know ``gettext``, you might note these specialties in the way Django
|
|
|
-does translation:
|
|
|
-
|
|
|
- * The string domain is ``django`` or ``djangojs``. This string domain is
|
|
|
- used to differentiate between different programs that store their data
|
|
|
- in a common message-file library (usually ``/usr/share/locale/``). The
|
|
|
- ``django`` domain is used for python and template translation strings
|
|
|
- and is loaded into the global translation catalogs. The ``djangojs``
|
|
|
- domain is only used for JavaScript translation catalogs to make sure
|
|
|
- that those are as small as possible.
|
|
|
- * Django doesn't use ``xgettext`` alone. It uses Python wrappers around
|
|
|
- ``xgettext`` and ``msgfmt``. This is mostly for convenience.
|
|
|
-
|
|
|
-``gettext`` on Windows
|
|
|
-======================
|
|
|
-
|
|
|
-This is only needed for people who either want to extract message IDs or
|
|
|
-compile message files (``.po``). Translation work itself just involves editing
|
|
|
-existing files of this type, but if you want to create your own message files,
|
|
|
-or want to test or compile a changed message file, you will need the
|
|
|
-``gettext`` utilities:
|
|
|
-
|
|
|
- * Download the following zip files from the GNOME servers
|
|
|
- http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
|
|
|
- of its mirrors_
|
|
|
-
|
|
|
- * ``gettext-runtime-X.zip``
|
|
|
- * ``gettext-tools-X.zip``
|
|
|
-
|
|
|
- ``X`` is the version number, we are requiring ``0.15`` or higher.
|
|
|
-
|
|
|
- * Extract the contents of the ``bin\`` directories in both files to the
|
|
|
- same folder on your system (i.e. ``C:\Program Files\gettext-utils``)
|
|
|
-
|
|
|
- * Update the system PATH:
|
|
|
-
|
|
|
- * ``Control Panel > System > Advanced > Environment Variables``
|
|
|
- * In the ``System variables`` list, click ``Path``, click ``Edit``
|
|
|
- * Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
|
|
|
- ``Variable value`` field
|
|
|
-
|
|
|
-.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
|
|
|
-
|
|
|
-You may also use ``gettext`` binaries you have obtained elsewhere, so long as
|
|
|
-the ``xgettext --version`` command works properly. Some version 0.14.4 binaries
|
|
|
-have been found to not support this command. Do not attempt to use Django
|
|
|
-translation utilities with a ``gettext`` package if the command ``xgettext
|
|
|
---version`` entered at a Windows command prompt causes a popup window saying
|
|
|
-"xgettext.exe has generated errors and will be closed by Windows".
|
|
|
-
|
|
|
-.. _format-localization:
|
|
|
-
|
|
|
-Format localization
|
|
|
-===================
|
|
|
-
|
|
|
-Django's formatting system is disabled by default. To enable it, it's necessay
|
|
|
-to set :setting:`USE_L10N = True <USE_L10N>` in your settings file.
|
|
|
-
|
|
|
-When using Django's formatting system, dates and numbers on templates will be
|
|
|
-displayed using the format specified for the current locale. Two users
|
|
|
-accessing the same content, but in different language, will see date and
|
|
|
-number fields formatted in different ways, depending on the format for their
|
|
|
-current locale.
|
|
|
-
|
|
|
-Django will also use localized formats when parsing data in forms. That means
|
|
|
-Django uses different formats for different locales when guessing the format
|
|
|
-used by the user when inputting data on forms. Note that Django uses different
|
|
|
-formats for displaying data, and for parsing it.
|
|
|
-
|
|
|
-Creating custom format files
|
|
|
-----------------------------
|
|
|
-
|
|
|
-Django provides format definitions for many locales, but sometimes you might
|
|
|
-want to create your own, because a format files doesn't exist for your locale,
|
|
|
-or because you want to overwrite some of the values.
|
|
|
-
|
|
|
-To use custom formats, first thing to do, is to specify the path where you'll
|
|
|
-place format files. To do that, just set your :setting:`FORMAT_MODULE_PATH`
|
|
|
-setting to the the path (in the format ``'foo.bar.baz``) where format files
|
|
|
-will exists.
|
|
|
-
|
|
|
-Files are not placed directly in this directory, but in a directory named as
|
|
|
-the locale, and must be named ``formats.py``.
|
|
|
-
|
|
|
-To customize the English formats, a structure like this would be needed::
|
|
|
-
|
|
|
- mysite/
|
|
|
- formats/
|
|
|
- __init__.py
|
|
|
- en/
|
|
|
- __init__.py
|
|
|
- formats.py
|
|
|
-
|
|
|
-where :file:`formats.py` contains custom format definitions. For example::
|
|
|
-
|
|
|
- THOUSAND_SEPARATOR = ' '
|
|
|
-
|
|
|
-to use a space as a thousand separator, instead of the default for English,
|
|
|
-a comma.
|