1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

Preliminary clean-up of docs/translation.txt in i18n branch

git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@1057 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2005-11-03 06:52:53 +00:00
parent 1c4a48134a
commit e2b7527f79

View File

@ -3,388 +3,421 @@ How to do translations
====================== ======================
Django has support for internationalization of program strings and template Django has support for internationalization of program strings and template
content. Translations use the gettext library to produce strings in several content. Translations use the ``gettext`` library to produce strings in several
languages. Here is an overview how translation works with django. languages. Here's an overview of how translation works with Django.
The goal of this howto is to give programmers the needed informations on how The goal of this document is to explain how to use translations in projects,
to use translations in their own projects, on how to add translations to how to add translations to Django patches and how to update and create
django patches and on how to update and create translation files. translation files.
Using Translations in Python Using translations in Python
============================ ============================
The translation machinery in django uses the standard gettext module that The translation machinery in Django uses the standard ``gettext`` module that
comes as part of your Python installation. It does wrap it in it's own comes with Python. Django uses in its own functions and classes, but it uses
functions and classes to accomplish all of it's goals, but essentially it's standard ``gettext`` machinery under the hood.
just standard gettext machinery.
So to translate strings in your source you have to make use of one of the To translate strings in your code, use one of the ``gettext`` helper functions.
gettext helper functions. There are essentially two ways to make use of them: There are essentially two ways to use them:
- you can use the _() function that is available globally. This function will * Use the ``_()`` function, which is available globally. This function
translate any string value it get's as parameter. translates any string value.
- you can use django.utils.translation and import gettext or gettext_noop * Use ``django.utils.translation`` and import ``gettext`` or
from there. gettext is identical to _() ``gettext_noop`` from there. ``gettext`` is identical to ``_()``.
There is one important thing to know about translations: the system can only Note one important thing about translations: The system can only translate
translate strings it knows about. So to know about those strings you have to strings it knows about. That means you have to mark strings for translation.
mark them for translation. That is done by either calling _(), gettext() or This is done either by calling ``_()``, ``gettext()`` or ``gettext_noop()`` on
gettext_noop() on those string constants. You can translate variable values string constants. You can translate variable values or computed values, but the
or computed values, but the system needs to know those strings beforehand. system needs to know those strings beforehand.
The usual way is to build your strings by standard string interpolation and The usual method is to build your strings using string interpolation and using
to use the gettext functions to do the actual translation of the string the ``gettext`` functions to do the actual translation. Example::
itself, like so::
def hello_world(request, name, site): def hello_world(request, name, site):
page = _('Hello %(name)s, welcome to %(site)s!') % { page = _('Hello %(name)s, welcome to %(site)s!') % {
'name': name, 'name': name,
'site': site, 'site': site,
} }
return page return HttpResponse(page)
This short snippet shows one important thing: you shouldn't use the positional This short snippet shows one important thing: You shouldn't use positional
string interpolation (the one that uses %s and %d) but use the named string string interpolation (e.g., ``%s`` or ``%d``). Use the named string
interpolation (the one that uses %(name)s), instead. The reason is that other interpolation (e.g., ``%(name)s``), instead. Do this because other languages
languages might require a reordering of text. might require reordering of text.
The other two helper functions are similar in use:: The other two helper functions are similar::
def hello_world(request, name, site): from django.utils.translation import gettext
from django.utils.translation import gettext def hello_world(request, name, site):
page = gettext('Hello %(name)s, welcome to %(site)s!') % { page = gettext('Hello %(name)s, welcome to %(site)s!') % {
'name': name, 'name': name,
'site': site, 'site': site,
} }
return page return HttpResponse(page)
The difference is, you explicitly import them. There are two important The difference here is that ``gettext`` is explicitly imported.
helpers: gettext and gettext_noop. gettext is just like _() - it will
translate it's argument. gettext_noop is different in that it does only
mark a string for inclusion into the message file but doesn't do translation.
Instead the string is later translated from a variable. This comes up if you
have constant strings that should be stored in the source language because
they are exchanged over systems or users - like strings in a database - but
should be translated at the last possible point in time, when the string
is presented to the user.
One special case that isn't available in other gettext usages are lazily Two important helper functions are available: ``gettext`` and ``gettext_noop``.
translated strings. This is needed for stuff that you set up in your django
model files - those messages are stored internally and translated on access, but * ``gettext`` is just like ``_()`` -- it translates its argument.
not translated on storage (as that would only take the default language into account). * ``gettext_noop`` is different. It marks a string for inclusion into the
To translate a model helptext, do the following:: message file but doesn't do translation. Instead, 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.
One function, ``django.utils.translation.gettext_lazy()``, isn't available in
the standard ``gettext`` module. Use it for lazily translated strings, such as
messages in Django models that are stored internally and translated on access
-- but not translated on storage, as that would only take the default language
into account.
For example, to translate a model's ``help_text``, do the following::
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
class Mything(meta.Model): class MyThing(meta.Model):
name = meta.CharField(help_text=gettext_lazy('This is the help text'))
name = meta.CharField('Name', help_text=gettext_lazy('This is the help text')) In this example, ``gettext_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.
This way only a lazy reference is stored for the string, not the actual translation. If you don't like the verbose name ``gettext_lazy``, you can just alias it as
The translation itself will be done when the string is used in a string context, like ``_``, like so::
template rendering in the admin.
If you don't like the verbose name gettext_lazy, you can just alias it as _ - in the model
file you will allways use lazy translations anyway. And it's a good idea to add translations
for the field names and table names, too. This means writing explicit verbose_name and
verbose_names options in the META subclass, though::
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class Mything(meta.Model): class MyThing(meta.Model):
name = meta.CharField(help_text=_('This is the help text'))
name = meta.CharField(_('Name'), help_text=_('This is the help text')) Always use lazy translations in Django models. And it's a good idea to add
translations for the field names and table names, too. This means writing
explicit verbose_name and verbose_names options in the ``META`` class,
though::
from django.utils.translation import gettext_lazy as _
class MyThing(meta.Model):
name = meta.CharField(_('name'), help_text=_('This is the help text'))
class META: class META:
verbose_name = _('my thing')
verbose_name_plural = _('mythings')
verbose_name = _('Mything') A standard problem with translations is pluralization of strings. Use
verbose_name_plural = _('Mythings') ``ngettext`` to solve this problem. Example::
There is another standard problem with translations, that is pluralization of
strings. This is done by the standard helper ngettext like so::
def hello_world(request, count): def hello_world(request, count):
from django.utils.translation import ngettext from django.utils.translation import ngettext
page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % { page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % {
'count': count, 'count': count,
} }
return page return HttpResponse(page)
Using Translations in Templates Using translations in templates
=============================== ===============================
Using translations in the templates is much like in python code. There is Using translations in Django templates works much like translations in Python
just a template tag that will allow you to use the same _() helper function code. The ``{% i18n %}`` template tag lets you use the same ``_()`` helper
as with your source:: function as in your Python code::
<html> <html>
<title>{% i18n _('This is the title.') %}</title> <title>{% i18n _('This is the title.') %}</title>
<body> <body>
<p>{% i18n _('Hello %(name)s, welcome at %(site)s!') %}</p> <p>{% i18n _('Hello %(name)s, welcome at %(site)s!') %}</p>
<p>{% i18n ngettext('There is %(count)d file', 'There are %(count)d files', files|count) %}</p> <p>{% i18n ngettext('There is %(count)d file', 'There are %(count)d files', files|count) %}</p>
</body> </body>
</html> </html>
This short snippet shows you how to do translations. You can just translate It's not only possible to translate hard-coded strings, but the strings can
strings, but there is one speciality: the strings can contain interpolation contain interpolated parts, e.g. ``%(name)s``. Those parts are automatically
parts. Those parts are automatically resolved from the template context, just resolved from the template context, just as they would be if you had used them
as they would be if you had used them in {{ ... }}. But this can only resolve in ``{{ ... }}``. But this can only resolve variables, not more complex
variables, not more complex expressions. expressions.
To translate a variable value, you can just do {% i18n _(variable) %}. This To translate a variable value, do this::
can even include filters like {% i18n _(variable|lower} %}.
There is additional support for i18n string constants for other situations {% i18n _(variable) %}
as well. All template tags that do variable resolving (with or without filters)
will accept string constants, too. Those string constants can now be i18n
strings like this::
<html> Filters are allowed, too::
<title>{{ _('This is the title') }}</title>
<body>
<p>{{ _('Hello World!') }}</p>
</body>
</html>
This is much shorter, but won't allow you to use gettext_noop or ngettext. {% i18n _(variable|lower) %}
Sometimes you might want to give the user a selection of languages. This Any template tag that resolves variables accepts i18n-string constants, too.
can be done by accessing the LANGUAGES variable of a DjangoContext. This
is a list of tuples where the first element is the language code and the Also, note you can use ``_()`` around variable names, like so::
second element is the language name (in that language). The code might
look like this:: <html>
<title>{{ _('This is the title') }}</title>
<body>
<p>{{ _('Hello, world!') }}</p>
</body>
</html>
This syntax is much shorter, but it doesn't allow you to use ``gettext_noop``
or ``ngettext``.
Each ``DjangoContext`` has access to two 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 (in that language).
* ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
Example: ``en-us``. (See "How language preference is discovered", below.)
The ``setlang`` redirect view
-----------------------------
Django comes with a view, ``django.views.i18n.set_language`` that sets a user's
language preference and redirects back to the previous page. For example, put
this HTML code in your template::
<form action="/i18n/setlang/" method="POST"> <form action="/i18n/setlang/" method="POST">
<input name="next" type="hidden" value="http://server.doma.in/path/to/go/to/after/switch/"/> <input name="next" type="hidden" value="/next/page/" />
<select name="language"> <select name="language">
{% for lang in LANGUAGES %} {% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option> <option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %} {% endfor %}
</select> </select>
<input type="submit" value="Go" />
</form> </form>
This would jump to a language switcher and then be redirected back to the When a user submits the form, his chosen language will be saved in a cookie,
page it came from. The switcher page will just store the language in either and he'll be redirected either to the URL specified in the ``next`` field, or,
the users session or a special cookie for use in the language discovery. if ``next`` is empty, to the URL in the ``Referer`` header. If the ``Referer``
is blank -- say, if a user's browser suppresses that header -- then the user
will be redirected to ``/`` (the site root) as a fallback.
You can leave out the "next" field. In that case the /i18n/setlang/ view Activate the ``setlang`` redirect view by adding the following line to your
will redirect to the URL that is in the "Referer" header. Please keep in mind URLconf::
that people might suppress that header, so in those cases there won't be a
URL to redirect to - in those cases the view function will redirect to "/"
as a fallback.
The /i18n/setlang/ url can be set up by including the following in your (r'^i18n/', include('django.conf.urls.i18n'),
ROOT_URLCONF::
urlpatterns = patterns('', Note that this example makes the view available at ``/i18n/setlang/``.
(r'^i18n/', include('django.conf.urls.i18n'),
)
This adds the setlang handler to your urlspace and hooks up a standard view How language preference is discovered
function to it. =====================================
How the Language is Discovered Django has a very flexible model of deciding which language should be used --
============================== installation-wide, for a particular user, or both.
Django has a very flexible model of deciding what language is to be used. To set an installation-wide language preference, set ``LANGUAGE_CODE`` in your
The first line in choice is the LANGUAGE_CODE setting in your config file. settings file. Django uses this language as the default translation -- the
This is used as the default translation - the last try if none of the other final attempt if no other translator finds a translation.
translattors find a translation. Actually if youre requirement is just to
run django with your native language, you only need to set LANGUAGE_CODE
and that's it - if there is a language file for django for your language.
But with web applications, users come from all over the world. So you don't If all you want to do is run Django with your native language, and a language
want to have a single translation active, you want to decide what language to file is available for your language, all you need to do is set
present to each and every user. This is where the LocaleMiddleware comes ``LANGUAGE_CODE``.
into the picture. You need to add it to your middleware setting. It should
be one of the first middlewares installed, but it should come after the
session middleware - that's because it makes uses of the session data. And
it must be installed before the AdminUserRequired middleware, as that will
do redirects based on not-logged-in state and so the LocaleMiddleware won't
ever see the login page (and so not initialize the language correctly).
So your middleware settings might look like this:: 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 lets each user have his or her own
setting.
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.
For example, your ``MIDDLEWARE_CLASSES`` might look like this::
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.middleware.sessions.SessionMiddleware', 'django.middleware.sessions.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', 'django.middleware.locale.LocaleMiddleware',
'django.middleware.admin.AdminUserRequired',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
) )
This activates the LocalMiddlware in your server (in this case it was taken ``LocaleMiddleware`` tries to determine the user's language preference by
from the admin.py settings file). following this algorithm:
The LocaleMiddleware allows a selection of the language based on data from * First, it looks for a ``django_language`` key in the the current user's
the request - every user can have her own settings. session.
* Failing that, it looks for a cookie called ``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.
The first thing the LocaleMiddleware does, it looks at the session data for the Notes:
user. If that carries a key django_language, it's contents will be used as the
language code. If the session doesn't contain a language setting, the
middleware will look at the cookies for a django_language cookie. If that is
found, it gives the language code.
The format for the explicit django_language parameters is allways the * In each of these places, the language preference is expected to be in the
language to use - for example it's pt-br for Brazilian. If a base language standard language format, as a string. For example, Brazilian is
is available, but the sublanguage specified is not, the base language is used. ``pt-br``.
For example if you specify de-at (Austrian German), but there is only a * If a base language is available but the sublanguage specified is not,
language de available, that language is used. Django uses the base language. For example, if a user specifies ``de-at``
(Austrian German) but Django only has ``de`` available, Django uses
``de``.
If neither the session nor the cookie carry a language code, the middleware Once ``LocaleMiddleware`` determines the user's preference, it makes this
will look at the HTTP header Accept-Language. This header is sent by your preference available as ``request.LANGUAGE_CODE`` for each `request object`_.
browser and tells the server what languages you prefer. Languages are ordered Feel free to read this value in your view code. Here's a simple example::
by some choice value - the higher, the more you prefer the language.
So the middleware will iterate over that header, ordered by the preference def hello_world(request, count):
value. The language with the highest preference that is in the django base if request.LANGUAGE_CODE == 'de-at':
message file directory will be used as the language to present to the user. return HttpResponse("You prefer to read Austrian German.")
else:
return HttpResponse("You prefer to read another language.")
Since the middlware discovers the language based on the request, your app Note that, with static (middleware-less) translation, the language is in
might need to know what language is selected (if only to show the flag of ``settings.LANGUAGE_CODE``, while with dynamic (middleware) translation, it's
that language). The selected language is stored by the middleware in the in ``request.LANGUAGE_CODE``.
request as the LANGUAGE_CODE attribute. So with static translation (when
you don't use the middlware) the language is in settings.LANGUAGE_CODE, while
with dynamic translations (when you do use the middleware) it's in
request.LANGUAGE_CODE. And if your application builds on DjangoContext
instances for template rendering, it will be automatically be available
as LANGUAGE_CODE in your template (with automatic determination where to
pull it from).
Creating Language Files .. _request object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects
Creating language files
======================= =======================
So now you have tagged all your strings for later translation. But you need So, you've tagged all of your strings for later translation. But you need to
to write the translations themselves. They need to be in a format grokable write the translations themselves.
by gettext. You need to update them. You may need to create new ones for new
languages. This will show you how to do it.
The first step is to create a message file for a new language. This can They need to be in a format grokable by ``gettext``. You need to update them.
be created with a tool delivered with django. To run it on the django You may need to create new ones for new languages. This section shows you how
source tree (best from a subversion checkout), just go to the django-Directory to do it.
itself. Not the one you checked out, but the one you linked to your
$PYTHONPATH or the one that's localted somewhere on that path.
That directory includes a subdirectory conf, and that a directory locale. The Creating message files
tools to do translations are in the django/bin directory. The first tool ----------------------
to use is make-messages.py - this tool will run over the whole source tree
and pull out all strings marked for translation.
To run it, just do the following:: The first step is to create a message file for a new language. Django comes
with a tool, ``make-messages.py``, that automates this.
bin/make-messages.py -l de To run it on the Django source tree, navigate to the ``django`` directory
itself -- not a Subversion check out, but the one linked to via ``$PYTHONPATH``
or located somewhere on that path.
This will create or update the german message file. This file is located Then run this command::
at conf/locale/de/LC_MESSAGES/django.po - this file can be directly edited
with your favorite editor. You need to first edit the charset line - search
for CHARSET and set it to the charset you will use to edit the content. It
might be that it is utf-8 - if you prefer another encoding, you can use some
tools like recode or iconv to change the charset of the file and then change
the charset definition in the file (it's in the Content-Type: line).
The language code for storage is in locale format - so it is pt_BR for bin/make-messages.py -l de
Brazilian or de_AT for Austrian German.
If you don't have the gettext utilities installed, make-messages.py will create ...where ``de`` is the language code for the message file you want to create.
empty files. If that is the case, either install the gettext utilities, or
just copy the conf/locale/en/LC_MESSAGES/django.po and start with that - it's just
an empty translation file.
Every message in the message file is of the same format. One line is the msgid. This script runs over the entire Django source tree and pulls out all strings
This is the actual string in the source - you don't change it. The other line marked for translation, creating or updating the language's message file.
is msgstr - this is the translation. It starts out empty. You change it.
There is one speciality for long messages: there the first string directly When it's done, it will have created (or updated) a message file under the
after the msgstr (or msgid) is an emtpy string. Then the content itself will directory ``conf/locale``. In this example, the file will be
be written over the next few lines as one string per line. Those strings ``conf/locale/de/LC_MESSAGES/django.po``.
are directly concatenated - don't forget trailing spaces within the strings,
otherwise they will be tacked together without whitespace!
After you created your message file you need to transform it into some more If you don't have the ``gettext`` utilities installed, ``make-messages.py``
efficient form to read by gettext. This is done with the second tool, that's will create empty files. If that's the case, either install the ``gettext``
compile-messages.py. This tool just runs over all available .po files and utilities or just copy the English message file
turns them into .mo files. Run it as follows:: (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a starting point; it's
just an empty translation file.
Once you've created the ``.po`` file, edit the 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. Then, proceed to write your
translations.
The language code for storage is in locale format -- so it's ``pt_BR`` for
Brazilian and ``de_AT`` for Austrian German.
Every message in the message file is in the same format:
* One line is the msgid. This is the actual string in the source. Don't
change it.
* The other line is msgstr. This is the translation. It starts out empty.
You change it.
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!
Compiling message files
-----------------------
After you create your message file, you'll need to transform it into a more
efficient form to be read by ``gettext``. Do this with the
``compile-messages.py`` utility. This tool runs over all available ``.po``
files and creates ``.mo`` files. Run it like this::
bin/compile-messages.py bin/compile-messages.py
That's it. You made your first translation. If you now configure your browser That's it. You made your first translation. Now, if you configure your browser
to request your language, it show up in the admin for example. to request your language, Django apps will use your language preference.
Another thing: please give us the name of your newly created language in that Another thing: Please submit the name of your newly-created language in that
native language - so we can add it to the global list of available languages native language, so we can add it to the global list of available languages
that is mirrored in settings.LANGUAGES (and the DjangoContext variable that is mirrored in ``settings.LANGUAGES`` (and the ``LANGUAGES`` template
LANGUAGES in templates). variable).
Using Translations in Your Own Projects Using translations in your own projects
======================================= =======================================
Of course you want to make use of the translations in your own projects, too. Of course, your own projects should make use of translations. Django makes this
This is very simple with django, as django looks in several locations for simple, because it looks for message files in several locations.
message files. The base path in your django distribution is only the last
place to look for translations. Before that, django looks first into your
application directory (actually in the application directory of the view
function that is about to be called!) for message files. If there is one for
the selected language, it will be installed. After that django looks into the
project directory for message files. If there is one for the selected language,
it will be installed after the app-specific one. And only then comes the
base translation.
That way you can write applications that bring their own translations with Django looks for translations by following this algorithm:
them and you can override base translations in your project path if you
want to do that. 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. All message file repositories are structured the same. They are:
- $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo) * First, it looks for a ``locale`` directory in the application directory
- $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo) of the view that's being called. If it finds a translation for the
- all paths listed in LOCALE_PATHS in your settings file are selected language, the translation will be installed.
searched in that order for <language>/LC_MESSAGES/django.(po|mo) * Next, it looks for a ``locale`` directory in the project directory. If it
- $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo) finds a translation, the translation will be installed.
* Finally, it checks the base translation in ``django/conf/locale``.
Actually the appliaction doesn't need to be stored below the project path - This way, you can write applications that include their own translations, and
django uses module introspection to find the right place where your application you can override base translations in your project path if you want to do that.
is stored. It only needs to be listed in your INSTALLED_APPS setting. 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.
To create message files, you use the same make-messages.py tool as with the All message file repositories are structured the same way. They are:
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/ * ``$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 ``make-messages.py`` 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 (in case of app messages or project messages) directory are located. And you
use the same compile-messages.py to produce the binary django.mo files that use the same ``compile-messages.py`` to produce the binary ``django.mo`` files that
are used by gettext. are used by ``gettext``.
Application message files are a bit complicated to discover - they need the Application message files are a bit complicated to discover -- they need the
i18n middleware to be found. If you don't use the middleware, only the ``LocaleMiddleware``. If you don't use the middleware, only the Django message
django message files and project message files will be processed. files and project message files will be processed.
Additionally you should think about how to structure your translation Finally, you should give some thought to the structure of your translation
files. If your applications should be delivered to other users and should 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. be used in other projects, you might want to use app-specific translations.
But using app-specific translations and project translations could produce But using app-specific translations and project translations could produce
weird problems with make-messages: make-messages will traverse all directories weird problems with ``make-messages``: ``make-messages`` will traverse all directories
below the current path and so might put message IDs into the project below the current path and so might put message IDs into the project
message file that are already in application message files. Easiest way message file that are already in application message files.
out is to store applications that are not part of the project (and so carry
their own translations) outside the project tree. That way make-messages
on the project level will only translate stuff that is connected to your
explicit project and not stuff that is distributed independently.
Specialities of Django Translation 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,
``make-messages`` on the project level will only translate strings that are
connected to your explicit project and not strings that are distributed
independently.
Specialities of Django translation
================================== ==================================
If you know gettext, you might see some specialities with the way django does If you know ``gettext``, you might note these specialities in the way Django
translations. For one, the string domain is allways django. The string domain does translation:
is used to differentiate between different programs that store their stuff
in a common messagefile library (usually /usr/share/locale/). In our case there
are django-specific locale libraries and so the domain itself isn't used. We
could store app message files with different names and put them for example
in the project library, but decided against this: with message files in the
application tree, they can more easily be distributed.
Another speciality is that we only use gettext and gettext_noop - that's
because django uses allways DEFAULT_CHARSET strings internally. There isn't
much use in using ugettext or something like that, as you allways will need to
produce utf-8 anyway.
And last we don't use xgettext alone and some makefiles but use python
wrappers around xgettext and msgfmt. That's mostly for convenience.
* The string domain is always ``django``. The string domain is used to
differentiate between different programs that store their data in a
common messagefile library (usually ``/usr/share/locale/``). In Django's
case, there are Django-specific locale libraries, so the domain itself
isn't used. We could store app message files with different names and put
them, say, in the project library, but we decided against this. With
message files in the application tree, apps can be distributed more
easily.
* Django only uses ``gettext`` and ``gettext_noop``. That's because Django
always uses ``DEFAULT_CHARSET`` strings internally. There isn't much use
in using ``ugettext``, because you'll always need to produce utf-8
anyway.
* Django doesn't use ``xgettext`` alone. It uses Python wrappers around
``xgettext`` and ``msgfmt``. That's mostly for convenience.