|
@@ -1,27 +1,44 @@
|
|
|
-====================
|
|
|
-Internationalization
|
|
|
-====================
|
|
|
+===========
|
|
|
+Translation
|
|
|
+===========
|
|
|
|
|
|
.. module:: django.utils.translation
|
|
|
|
|
|
Overview
|
|
|
========
|
|
|
|
|
|
-The goal of internationalization is to allow a single Web application to offer
|
|
|
-its content and functionality in multiple languages and locales.
|
|
|
+In order to make a Django project translatable, you have to add a minimal amount
|
|
|
+of hooks to your Python code and templates. These hooks are called
|
|
|
+:term:`translation strings <translation string>`. 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." It's your responsibility to mark
|
|
|
+translatable strings; the system can only translate strings it knows about.
|
|
|
+
|
|
|
+Django then provides utilities to extract the translation strings into a
|
|
|
+:term:`message file`. This file is a convenient way for translators to provide
|
|
|
+the equivalent of the translation strings in the target language. Once the
|
|
|
+translators have filled in the message file, it must be compiled. This process
|
|
|
+relies on the GNU gettext toolset.
|
|
|
+
|
|
|
+Once this is done, Django takes care of translating Web apps on the fly in each
|
|
|
+available language, according to users' language preferences.
|
|
|
+
|
|
|
+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. 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 :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
|
|
|
|
|
|
-For text translations, you, the Django developer, can accomplish this goal by
|
|
|
-adding a minimal amount of hooks to your Python 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." It's your responsibility to mark translatable
|
|
|
-strings; the system can only translate strings it knows about.
|
|
|
+.. note::
|
|
|
|
|
|
-Django takes care of using these hooks to translate Web apps, on the fly,
|
|
|
-according to users' language preferences.
|
|
|
+ There is also an independent but related :setting:`USE_L10N` setting that
|
|
|
+ controls if Django should implement format localization. See
|
|
|
+ :doc:`/topics/i18n/formatting` for more details.
|
|
|
|
|
|
-Specifying translation strings: In Python code
|
|
|
-==============================================
|
|
|
+Internationalization: in Python code
|
|
|
+====================================
|
|
|
|
|
|
Standard translation
|
|
|
--------------------
|
|
@@ -85,8 +102,8 @@ Translation works on variables. Again, here's an identical example::
|
|
|
|
|
|
(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.)
|
|
|
+:djadmin:`django-admin.py makemessages <makemessages>`, won't be able to find
|
|
|
+these strings. More on :djadmin:`makemessages` later.)
|
|
|
|
|
|
The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
|
|
|
specified with Python's standard named-string interpolation syntax. Example::
|
|
@@ -126,7 +143,7 @@ This also works in templates with the :ttag:`comment` tag:
|
|
|
|
|
|
{% comment %}Translators: This is a text of the base template {% endcomment %}
|
|
|
|
|
|
-The comment will then appear in the resulting .po file and should also be
|
|
|
+The comment will then appear in the resulting ``.po`` file and should also be
|
|
|
displayed by most translation tools.
|
|
|
|
|
|
Marking strings as no-op
|
|
@@ -221,9 +238,10 @@ cardinality of the elements at play.
|
|
|
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``.
|
|
|
+ You would get an error when running :djadmin:`django-admin.py
|
|
|
+ compilemessages <compilemessages>`::
|
|
|
+
|
|
|
+ a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'
|
|
|
|
|
|
.. _contextual-markers:
|
|
|
|
|
@@ -239,10 +257,10 @@ these words correctly in different contexts, you can use the
|
|
|
:func:`django.utils.translation.npgettext()` function if the string needs
|
|
|
pluralization. Both take a context string as the first variable.
|
|
|
|
|
|
-In the resulting .po file, the string will then appear as often as there are
|
|
|
-different contextual markers for the same string (the context will appear on
|
|
|
-the ``msgctxt`` line), allowing the translator to give a different translation
|
|
|
-for each of them.
|
|
|
+In the resulting ``.po`` file, the string will then appear as often as there are
|
|
|
+different contextual markers for the same string (the context will appear on the
|
|
|
+``msgctxt`` line), allowing the translator to give a different translation for
|
|
|
+each of them.
|
|
|
|
|
|
For example::
|
|
|
|
|
@@ -258,7 +276,7 @@ or::
|
|
|
name = models.CharField(help_text=pgettext_lazy(
|
|
|
'help text for MyThing model', 'This is the help text'))
|
|
|
|
|
|
-will appear in the .po file as:
|
|
|
+will appear in the ``.po`` file as:
|
|
|
|
|
|
.. code-block:: po
|
|
|
|
|
@@ -333,7 +351,7 @@ name::
|
|
|
|
|
|
class Meta:
|
|
|
verbose_name = _('my thing')
|
|
|
- verbose_name_plural = _('mythings')
|
|
|
+ verbose_name_plural = _('my things')
|
|
|
|
|
|
Notes on model classes translation
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -398,7 +416,7 @@ strings when ``result`` itself is used in a string (usually at template
|
|
|
rendering time).
|
|
|
|
|
|
Localized names of languages
|
|
|
-============================
|
|
|
+----------------------------
|
|
|
|
|
|
.. function:: get_language_info
|
|
|
|
|
@@ -421,8 +439,8 @@ Similar access to this information is available for template code. See below.
|
|
|
|
|
|
.. _specifying-translation-strings-in-template-code:
|
|
|
|
|
|
-Specifying translation strings: In template code
|
|
|
-================================================
|
|
|
+Internationalization: in template code
|
|
|
+======================================
|
|
|
|
|
|
.. highlightlang:: html+django
|
|
|
|
|
@@ -672,8 +690,8 @@ There are also simple filters available for convenience:
|
|
|
|
|
|
.. _Django templates: ../templates_python/
|
|
|
|
|
|
-Specifying translation strings: In JavaScript code
|
|
|
-==================================================
|
|
|
+Internationalization: in JavaScript code
|
|
|
+========================================
|
|
|
|
|
|
.. highlightlang:: python
|
|
|
|
|
@@ -681,8 +699,8 @@ 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.
|
|
|
+* 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.
|
|
@@ -700,12 +718,12 @@ The ``javascript_catalog`` view
|
|
|
|
|
|
.. function:: javascript_catalog(request, domain='djangojs', packages=None)
|
|
|
|
|
|
-The main solution to these problems is the :meth:`django.views.i18n.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 applications or Django core, according to what you
|
|
|
-specify in either the info_dict or the URL. Paths listed in
|
|
|
-:setting:`LOCALE_PATHS` are also included.
|
|
|
+The main solution to these problems is the
|
|
|
+:meth:`django.views.i18n.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 applications or
|
|
|
+Django core, according to what you specify in either the ``info_dict`` or the
|
|
|
+URL. Paths listed in :setting:`LOCALE_PATHS` are also included.
|
|
|
|
|
|
You hook it up like this::
|
|
|
|
|
@@ -815,8 +833,8 @@ to produce proper pluralizations).
|
|
|
|
|
|
.. _url-internationalization:
|
|
|
|
|
|
-Specifying translation strings: In URL patterns
|
|
|
-===============================================
|
|
|
+Internationalization: in URL patterns
|
|
|
+=====================================
|
|
|
|
|
|
.. versionadded:: 1.4
|
|
|
|
|
@@ -922,9 +940,9 @@ URL patterns can also be marked translatable using the
|
|
|
)
|
|
|
|
|
|
|
|
|
-After you've created the translations (see :doc:`localization` for more
|
|
|
-information), the :func:`~django.core.urlresolvers.reverse` function will
|
|
|
-return the URL in the active language. Example::
|
|
|
+After you've created the translations, the
|
|
|
+:func:`~django.core.urlresolvers.reverse` function will return the URL in the
|
|
|
+active language. Example::
|
|
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
from django.utils.translation import activate
|
|
@@ -971,10 +989,242 @@ template tag. It enables the given language in the enclosed template section:
|
|
|
|
|
|
The :ttag:`language` tag expects the language code as the only argument.
|
|
|
|
|
|
+.. _how-to-create-language-files:
|
|
|
+
|
|
|
+Localization: how to create language files
|
|
|
+==========================================
|
|
|
+
|
|
|
+Once the string literals of an application have been tagged for later
|
|
|
+translation, the translation themselves need to be written (or obtained). Here's
|
|
|
+how that works.
|
|
|
+
|
|
|
+.. _locale-restrictions:
|
|
|
+
|
|
|
+.. 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.
|
|
|
+
|
|
|
+ A good starting point is to copy the Django English ``.po`` file and to
|
|
|
+ translate at least some :term:`translation strings <translation string>`.
|
|
|
+
|
|
|
+Message files
|
|
|
+-------------
|
|
|
+
|
|
|
+The first step is to create a :term:`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, :djadmin:`django-admin.py makemessages
|
|
|
+<makemessages>`, that automates the creation and upkeep of these files.
|
|
|
+
|
|
|
+.. admonition:: Gettext utilities
|
|
|
+
|
|
|
+ The ``makemessages`` command (and ``compilemessages`` discussed later) use
|
|
|
+ commands from the GNU gettext toolset: ``xgettext``, ``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 :term:`locale format<locale name>`. For
|
|
|
+example, it's ``pt_BR`` for Brazilian Portuguese and ``de_AT`` for Austrian
|
|
|
+German.
|
|
|
+
|
|
|
+The script should be run from one of two places:
|
|
|
+
|
|
|
+* The root directory of your Django project.
|
|
|
+* The root directory of your Django app.
|
|
|
+
|
|
|
+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 :djadmin:`django-admin.py makemessages <makemessages>` examines every
|
|
|
+file that has the ``.html`` or ``.txt`` 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
|
|
|
+
|
|
|
+.. warning::
|
|
|
+
|
|
|
+ When :ref:`creating message files from JavaScript source code
|
|
|
+ <creating-message-files-from-js-code>` you need to use the special
|
|
|
+ 'djangojs' domain, **not** ``-e js``.
|
|
|
+
|
|
|
+.. admonition:: No gettext?
|
|
|
+
|
|
|
+ If you don't have the ``gettext`` utilities installed,
|
|
|
+ :djadmin:`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
|
|
|
+ :djadmin:`makemessages` works, see :ref:`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 :djadmin:`django-admin.py makemessages <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 :djadmin:`django-admin.py compilemessages <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 :djadmin:`django-admin.py makemessages <makemessages>`, run :djadmin:`django-admin.py compilemessages <compilemessages>` like this::
|
|
|
+
|
|
|
+ django-admin.py compilemessages
|
|
|
+
|
|
|
+That's it. Your translations are ready for use.
|
|
|
+
|
|
|
+.. admonition:: Working on Windows?
|
|
|
+
|
|
|
+ If you're using Windows and need to install the GNU gettext utilities so
|
|
|
+ :djadmin:`django-admin.py compilemessages <compilemessages>` works see
|
|
|
+ :ref:`gettext_on_windows` for more information.
|
|
|
+
|
|
|
+.. admonition:: .po files: Encoding and BOM usage.
|
|
|
+
|
|
|
+ Django only supports ``.po`` files encoded in UTF-8 and without any BOM
|
|
|
+ (Byte Order Mark) so if your text editor adds such marks to the beginning of
|
|
|
+ files by default then you will need to reconfigure it.
|
|
|
+
|
|
|
+.. _creating-message-files-from-js-code:
|
|
|
+
|
|
|
+Creating message files from JavaScript source code
|
|
|
+--------------------------------------------------
|
|
|
+
|
|
|
+You create and update the message files the same way as the other Django message
|
|
|
+files -- with the :djadmin:`django-admin.py makemessages <makemessages>` tool.
|
|
|
+The only difference is you need to explicitly specify what in gettext parlance
|
|
|
+is known as a domain in this case the ``djangojs`` domain, by providing a ``-d
|
|
|
+djangojs`` parameter, like this::
|
|
|
+
|
|
|
+ django-admin.py makemessages -d djangojs -l de
|
|
|
+
|
|
|
+This would create or update the message file for JavaScript for German. After
|
|
|
+updating message files, just run :djadmin:`django-admin.py compilemessages
|
|
|
+<compilemessages>` the same way as you do with normal Django message files.
|
|
|
+
|
|
|
+.. _gettext_on_windows:
|
|
|
+
|
|
|
+``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. 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".
|
|
|
+
|
|
|
+
|
|
|
+Miscellaneous
|
|
|
+=============
|
|
|
+
|
|
|
.. _set_language-redirect-view:
|
|
|
|
|
|
The ``set_language`` redirect view
|
|
|
-==================================
|
|
|
+----------------------------------
|
|
|
|
|
|
.. highlightlang:: python
|
|
|
|
|
@@ -1019,3 +1269,293 @@ Here's example HTML template code:
|
|
|
</select>
|
|
|
<input type="submit" value="Go" />
|
|
|
</form>
|
|
|
+
|
|
|
+Using translations outside views and templates
|
|
|
+----------------------------------------------
|
|
|
+
|
|
|
+While Django provides a rich set of i18n tools for use in views and templates,
|
|
|
+it does not restrict the usage to Django-specific code. The Django translation
|
|
|
+mechanisms can be used to translate arbitrary texts to any language that is
|
|
|
+supported by Django (as long as an appropriate translation catalog exists, of
|
|
|
+course). You can load a translation catalog, activate it and translate text to
|
|
|
+language of your choice, but remember to switch back to original language, as
|
|
|
+activating a translation catalog is done on per-thread basis and such change
|
|
|
+will affect code running in the same thread.
|
|
|
+
|
|
|
+For example::
|
|
|
+
|
|
|
+ from django.utils import translation
|
|
|
+ def welcome_translated(language):
|
|
|
+ cur_language = translation.get_language()
|
|
|
+ try:
|
|
|
+ translation.activate(language)
|
|
|
+ text = translation.ugettext('welcome')
|
|
|
+ finally:
|
|
|
+ translation.activate(cur_language)
|
|
|
+ return text
|
|
|
+
|
|
|
+Calling this function with the value 'de' will give you ``"Willkommen"``,
|
|
|
+regardless of :setting:`LANGUAGE_CODE` and language set by middleware.
|
|
|
+
|
|
|
+Functions of particular interest are ``django.utils.translation.get_language()``
|
|
|
+which returns the language used in the current thread,
|
|
|
+``django.utils.translation.activate()`` which activates a translation catalog
|
|
|
+for the current thread, and ``django.utils.translation.check_for_language()``
|
|
|
+which checks if the given language is supported by Django.
|
|
|
+
|
|
|
+Implementation notes
|
|
|
+====================
|
|
|
+
|
|
|
+.. _specialties-of-django-i18n:
|
|
|
+
|
|
|
+Specialties of Django translation
|
|
|
+---------------------------------
|
|
|
+
|
|
|
+Django's translation machinery uses the standard ``gettext`` module that comes
|
|
|
+with Python. 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.
|
|
|
+
|
|
|
+.. _how-django-discovers-language-preference:
|
|
|
+
|
|
|
+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 it, all you need to do is set :setting:`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 :setting:`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. And it should come before ``CommonMiddleware``
|
|
|
+ because ``CommonMiddleware`` needs an activated language in order
|
|
|
+ to resolve the requested URL.
|
|
|
+* If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it.
|
|
|
+
|
|
|
+For example, your :setting:`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 :doc:`middleware documentation
|
|
|
+</topics/http/middleware>`.)
|
|
|
+
|
|
|
+``LocaleMiddleware`` tries to determine the user's language preference by
|
|
|
+following this algorithm:
|
|
|
+
|
|
|
+.. versionchanged:: 1.4
|
|
|
+
|
|
|
+* First, it looks for the language prefix in the requested URL. This is
|
|
|
+ only performed when you are using the ``i18n_patterns`` function in your
|
|
|
+ root URLconf. See :ref:`url-internationalization` for more information
|
|
|
+ about the language prefix and how to internationalize URL patterns.
|
|
|
+
|
|
|
+* Failing that, it looks for a ``django_language`` key in the current
|
|
|
+ user's session.
|
|
|
+
|
|
|
+* Failing that, it looks for a cookie.
|
|
|
+
|
|
|
+ The name of the cookie used is set by the :setting:`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 :setting:`LANGUAGE_CODE` setting.
|
|
|
+
|
|
|
+.. _locale-middleware-notes:
|
|
|
+
|
|
|
+Notes:
|
|
|
+
|
|
|
+* In each of these places, the language preference is expected to be in the
|
|
|
+ standard :term:`language format<language code>`, 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 :setting:`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).
|
|
|
+
|
|
|
+* If you define a custom :setting:`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, :djadmin:`django-admin.py makemessages <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 :setting:`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 a basic
|
|
|
+ one as described in the :ref:`Locale restrictions<locale-restrictions>`
|
|
|
+ note.
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+.. _how-django-discovers-translations:
|
|
|
+
|
|
|
+How Django discovers translations
|
|
|
+---------------------------------
|
|
|
+
|
|
|
+At runtime, Django builds an in-memory unified catalog of literals-translations.
|
|
|
+To achieve this it looks for translations by following this algorithm regarding
|
|
|
+the order in which it examines the different file paths to load the compiled
|
|
|
+:term:`message files <message file>` (``.mo``) and the precedence of multiple
|
|
|
+translations for the same literal:
|
|
|
+
|
|
|
+1. The directories listed in :setting:`LOCALE_PATHS` have the highest
|
|
|
+ precedence, with the ones appearing first having higher precedence than
|
|
|
+ the ones appearing later.
|
|
|
+2. Then, it looks for and uses if it exists a ``locale`` directory in each
|
|
|
+ of the installed apps listed in :setting:`INSTALLED_APPS`. The ones
|
|
|
+ appearing first have higher precedence than the ones appearing later.
|
|
|
+3. Then, it looks for a ``locale`` directory in the project directory, or
|
|
|
+ more accurately, in the directory containing your settings file.
|
|
|
+4. Finally, the Django-provided base translation in ``django/conf/locale``
|
|
|
+ is used as a fallback.
|
|
|
+
|
|
|
+.. deprecated:: 1.3
|
|
|
+
|
|
|
+ Lookup in the ``locale`` subdirectory of the directory containing your
|
|
|
+ settings file (item 3 above) is deprecated since the 1.3 release and will be
|
|
|
+ removed in Django 1.5. You can use the :setting:`LOCALE_PATHS` setting
|
|
|
+ instead, by listing the absolute filesystem path of such ``locale``
|
|
|
+ directory in the setting value.
|
|
|
+
|
|
|
+.. seealso::
|
|
|
+
|
|
|
+ The translations for literals included in JavaScript assets are looked up
|
|
|
+ following a similar but not identical algorithm. See the
|
|
|
+ :ref:`javascript_catalog view documentation <javascript_catalog-view>` for
|
|
|
+ more details.
|
|
|
+
|
|
|
+In all cases the name of the directory containing the translation is expected to
|
|
|
+be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``,
|
|
|
+etc.
|
|
|
+
|
|
|
+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 common
|
|
|
+message file specific to the project you are composing. The choice is yours.
|
|
|
+
|
|
|
+.. note::
|
|
|
+
|
|
|
+ If you're using manually configured settings, as described in
|
|
|
+ :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:
|
|
|
+
|
|
|
+* All paths listed in :setting:`LOCALE_PATHS` in your settings file are
|
|
|
+ searched for ``<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
+* ``$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` --
|
|
|
+ deprecated, see above.
|
|
|
+* ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
+* ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)``
|
|
|
+
|
|
|
+To create message files, you use the :djadmin:`django-admin.py makemessages <makemessages>`
|
|
|
+tool. You only need to be in the same directory where the ``locale/`` directory
|
|
|
+is located. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
|
|
|
+to produce the binary ``.mo`` files that are used by ``gettext``.
|
|
|
+
|
|
|
+You can also run :djadmin:`django-admin.py compilemessages
|
|
|
+--settings=path.to.settings <compilemessages>` to make the compiler process all
|
|
|
+the directories in your :setting:`LOCALE_PATHS` setting.
|
|
|
+
|
|
|
+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-specific translations could produce weird
|
|
|
+problems with :djadmin:`makemessages`: it will traverse all directories below
|
|
|
+the current path and so might put message IDs into a unified, common message
|
|
|
+file for the current project 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,
|
|
|
+:djadmin:`django-admin.py makemessages <makemessages>`, when ran on a project
|
|
|
+level will only extract strings that are connected to your explicit project and
|
|
|
+not strings that are distributed independently.
|