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:
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.xgettext
alone. It uses Python wrappers around xgettext
and msgfmt
. This is mostly for convenience.Once you've prepared your translations-or, if you just want to use the translations that come with Django-you'll 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 LANGUAGE_CODE
. Django uses this language as the default translation-the final attempt if no better matching translation is found through one of the methods employed by the locale middleware (see below).
If all you want is to run Django with your native language all you need to do is set LANGUAGE_CODE
and make sure the corresponding message files and their compiled versions (.mo
) exist.
If you want to let each individual user specify which language they prefer, then you also need to use the 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:
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.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 Chapter 17, Django Middleware.
LocaleMiddleware
tries to determine the user's language preference by following this algorithm:
i18n_patterns
function in your root URLconf. See internationalization for more information about the language prefix and how to internationalize URL patterns.LANGUAGE_SESSION_KEY
key in the current user's session.LANGUAGE_COOKIE_NAME
setting. (The default name is django_language
.)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.LANGUAGE_CODE
setting.Notes:
pt-br
.de-at
(Austrian German) but Django only has de
available, Django uses de
.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, as explained in the previous bullet, you can mark the language names as translation strings-but use ugettext_lazy()
instead of ugettext()
to avoid a circular import.Here's a sample settings file:
from django.utils.translation import ugettext_lazy as _ LANGUAGES = [ ('de', _('German')), ('en', _('English')), ]
Once LocaleMiddleware
determines the user's preference, it makes this preference available as request.LANGUAGE_CODE
for each HttpRequest
. Feel free to read this value in your view code. Here's a simple example:
from django.http import HttpResponse 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
.
At runtime, Django builds an in-memory unified catalog of literal 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 message files (.mo
) and the precedence of multiple translations for the same literal:
LOCALE_PATHS
have the highest precedence, with the ones appearing first having higher precedence than the ones appearing later.locale
directory in each of the installed apps listed in INSTALLED_APPS
. The ones appearing first have higher precedence than the ones appearing later.django/conf/locale
is used as a fallback.In all cases, the name of the directory containing the translation is expected to be named using locale name notation. For example, de
, pt_BR
, es_AR
, and so on.
This way, you can write applications that include their own translations, and you can override base translations in your project. 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.
All message file repositories are structured the same way. They are:
LOCALE_PATHS
in your settings file are searched for <language>/LC_MESSAGES/django.(po|mo)
$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 django-admin makemessages
tool. And you use django-admin compilemessages
to produce the binary .mo
files that are used by gettext
.
You can also run django-admin compilemessages
to make the compiler process all the directories in your LOCALE_PATHS
setting.