mirror of
https://github.com/django/django.git
synced 2025-07-03 17:29: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:
parent
1c4a48134a
commit
e2b7527f79
@ -3,388 +3,421 @@ How to do translations
|
||||
======================
|
||||
|
||||
Django has support for internationalization of program strings and template
|
||||
content. Translations use the gettext library to produce strings in several
|
||||
languages. Here is an overview how translation works with django.
|
||||
content. Translations use the ``gettext`` library to produce strings in several
|
||||
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
|
||||
to use translations in their own projects, on how to add translations to
|
||||
django patches and on how to update and create translation files.
|
||||
The goal of this document is to explain how to use translations in projects,
|
||||
how to add translations to Django patches and how to update and create
|
||||
translation files.
|
||||
|
||||
Using Translations in Python
|
||||
Using translations in Python
|
||||
============================
|
||||
|
||||
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
|
||||
functions and classes to accomplish all of it's goals, but essentially it's
|
||||
just standard gettext machinery.
|
||||
The translation machinery in Django uses the standard ``gettext`` module that
|
||||
comes with Python. Django uses in its own functions and classes, but it uses
|
||||
standard ``gettext`` machinery under the hood.
|
||||
|
||||
So to translate strings in your source you have to make use of one of the
|
||||
gettext helper functions. There are essentially two ways to make use of them:
|
||||
To translate strings in your code, use one of the ``gettext`` helper functions.
|
||||
There are essentially two ways to use them:
|
||||
|
||||
- you can use the _() function that is available globally. This function will
|
||||
translate any string value it get's as parameter.
|
||||
- you can use django.utils.translation and import gettext or gettext_noop
|
||||
from there. gettext is identical to _()
|
||||
* Use the ``_()`` function, which is available globally. This function
|
||||
translates any string value.
|
||||
* Use ``django.utils.translation`` and import ``gettext`` or
|
||||
``gettext_noop`` from there. ``gettext`` is identical to ``_()``.
|
||||
|
||||
There is one important thing to know about translations: the system can only
|
||||
translate strings it knows about. So to know about those strings you have to
|
||||
mark them for translation. That is done by either calling _(), gettext() or
|
||||
gettext_noop() on those string constants. You can translate variable values
|
||||
or computed values, but the system needs to know those strings beforehand.
|
||||
Note one important thing about translations: The system can only translate
|
||||
strings it knows about. That means you have to mark strings for translation.
|
||||
This is done either by calling ``_()``, ``gettext()`` or ``gettext_noop()`` on
|
||||
string constants. You can translate variable values or computed values, but the
|
||||
system needs to know those strings beforehand.
|
||||
|
||||
The usual way is to build your strings by standard string interpolation and
|
||||
to use the gettext functions to do the actual translation of the string
|
||||
itself, like so::
|
||||
The usual method is to build your strings using string interpolation and using
|
||||
the ``gettext`` functions to do the actual translation. Example::
|
||||
|
||||
def hello_world(request, name, site):
|
||||
page = _('Hello %(name)s, welcome to %(site)s!') % {
|
||||
'name': name,
|
||||
'site': site,
|
||||
}
|
||||
return page
|
||||
def hello_world(request, name, site):
|
||||
page = _('Hello %(name)s, welcome to %(site)s!') % {
|
||||
'name': name,
|
||||
'site': site,
|
||||
}
|
||||
return HttpResponse(page)
|
||||
|
||||
This short snippet shows one important thing: you shouldn't use the positional
|
||||
string interpolation (the one that uses %s and %d) but use the named string
|
||||
interpolation (the one that uses %(name)s), instead. The reason is that other
|
||||
languages might require a reordering of text.
|
||||
This short snippet shows one important thing: You shouldn't use positional
|
||||
string interpolation (e.g., ``%s`` or ``%d``). Use the named string
|
||||
interpolation (e.g., ``%(name)s``), instead. Do this because other languages
|
||||
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
|
||||
page = gettext('Hello %(name)s, welcome to %(site)s!') % {
|
||||
'name': name,
|
||||
'site': site,
|
||||
}
|
||||
return page
|
||||
from django.utils.translation import gettext
|
||||
def hello_world(request, name, site):
|
||||
page = gettext('Hello %(name)s, welcome to %(site)s!') % {
|
||||
'name': name,
|
||||
'site': site,
|
||||
}
|
||||
return HttpResponse(page)
|
||||
|
||||
The difference is, you explicitly import them. There are two important
|
||||
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.
|
||||
The difference here is that ``gettext`` is explicitly imported.
|
||||
|
||||
One special case that isn't available in other gettext usages are lazily
|
||||
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
|
||||
not translated on storage (as that would only take the default language into account).
|
||||
To translate a model helptext, do the following::
|
||||
Two important helper functions are available: ``gettext`` and ``gettext_noop``.
|
||||
|
||||
* ``gettext`` is just like ``_()`` -- it translates its argument.
|
||||
* ``gettext_noop`` is different. It marks a string for inclusion into the
|
||||
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
|
||||
|
||||
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.
|
||||
The translation itself will be done when the string is used in a string context, like
|
||||
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::
|
||||
If you don't like the verbose name ``gettext_lazy``, you can just alias it as
|
||||
``_``, like so::
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
class Mything(meta.Model):
|
||||
|
||||
name = meta.CharField(_('Name'), help_text=_('This is the help text'))
|
||||
class MyThing(meta.Model):
|
||||
name = meta.CharField(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:
|
||||
verbose_name = _('my thing')
|
||||
verbose_name_plural = _('mythings')
|
||||
|
||||
verbose_name = _('Mything')
|
||||
verbose_name_plural = _('Mythings')
|
||||
|
||||
There is another standard problem with translations, that is pluralization of
|
||||
strings. This is done by the standard helper ngettext like so::
|
||||
A standard problem with translations is pluralization of strings. Use
|
||||
``ngettext`` to solve this problem. Example::
|
||||
|
||||
def hello_world(request, count):
|
||||
from django.utils.translation import ngettext
|
||||
page = ngettext('there is %(count)d object', 'there are %(count)d objects', 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
|
||||
just a template tag that will allow you to use the same _() helper function
|
||||
as with your source::
|
||||
Using translations in Django templates works much like translations in Python
|
||||
code. The ``{% i18n %}`` template tag lets you use the same ``_()`` helper
|
||||
function as in your Python code::
|
||||
|
||||
<html>
|
||||
<title>{% i18n _('This is the title.') %}</title>
|
||||
<body>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<title>{% i18n _('This is the title.') %}</title>
|
||||
<body>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
This short snippet shows you how to do translations. You can just translate
|
||||
strings, but there is one speciality: the strings can contain interpolation
|
||||
parts. Those parts are automatically resolved from the template context, just
|
||||
as they would be if you had used them in {{ ... }}. But this can only resolve
|
||||
variables, not more complex expressions.
|
||||
It's not only possible to translate hard-coded strings, but the strings can
|
||||
contain interpolated parts, e.g. ``%(name)s``. Those parts are automatically
|
||||
resolved from the template context, just as they would be if you had used them
|
||||
in ``{{ ... }}``. But this can only resolve variables, not more complex
|
||||
expressions.
|
||||
|
||||
To translate a variable value, you can just do {% i18n _(variable) %}. This
|
||||
can even include filters like {% i18n _(variable|lower} %}.
|
||||
To translate a variable value, do this::
|
||||
|
||||
There is additional support for i18n string constants for other situations
|
||||
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::
|
||||
{% i18n _(variable) %}
|
||||
|
||||
<html>
|
||||
<title>{{ _('This is the title') }}</title>
|
||||
<body>
|
||||
<p>{{ _('Hello World!') }}</p>
|
||||
</body>
|
||||
</html>
|
||||
Filters are allowed, too::
|
||||
|
||||
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
|
||||
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
|
||||
second element is the language name (in that language). The code might
|
||||
look like this::
|
||||
Any template tag that resolves variables accepts i18n-string constants, too.
|
||||
|
||||
Also, note you can use ``_()`` around variable names, like so::
|
||||
|
||||
<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">
|
||||
<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">
|
||||
{% for lang in LANGUAGES %}
|
||||
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
|
||||
This would jump to a language switcher and then be redirected back to the
|
||||
page it came from. The switcher page will just store the language in either
|
||||
the users session or a special cookie for use in the language discovery.
|
||||
When a user submits the form, his chosen language will be saved in a cookie,
|
||||
and he'll be redirected either to the URL specified in the ``next`` field, or,
|
||||
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
|
||||
will redirect to the URL that is in the "Referer" header. Please keep in mind
|
||||
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.
|
||||
Activate the ``setlang`` redirect view by adding the following line to your
|
||||
URLconf::
|
||||
|
||||
The /i18n/setlang/ url can be set up by including the following in your
|
||||
ROOT_URLCONF::
|
||||
(r'^i18n/', include('django.conf.urls.i18n'),
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^i18n/', include('django.conf.urls.i18n'),
|
||||
)
|
||||
Note that this example makes the view available at ``/i18n/setlang/``.
|
||||
|
||||
This adds the setlang handler to your urlspace and hooks up a standard view
|
||||
function to it.
|
||||
How language preference is discovered
|
||||
=====================================
|
||||
|
||||
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.
|
||||
The first line in choice is the LANGUAGE_CODE setting in your config file.
|
||||
This is used as the default translation - the last try if none of the other
|
||||
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.
|
||||
To set an installation-wide language preference, set ``LANGUAGE_CODE`` in your
|
||||
settings file. Django uses this language as the default translation -- the
|
||||
final attempt if no other translator finds a translation.
|
||||
|
||||
But with web applications, users come from all over the world. So you don't
|
||||
want to have a single translation active, you want to decide what language to
|
||||
present to each and every user. This is where the LocaleMiddleware comes
|
||||
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).
|
||||
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``.
|
||||
|
||||
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 = (
|
||||
'django.middleware.sessions.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.admin.AdminUserRequired',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
)
|
||||
|
||||
This activates the LocalMiddlware in your server (in this case it was taken
|
||||
from the admin.py settings file).
|
||||
``LocaleMiddleware`` tries to determine the user's language preference by
|
||||
following this algorithm:
|
||||
|
||||
The LocaleMiddleware allows a selection of the language based on data from
|
||||
the request - every user can have her own settings.
|
||||
* First, it looks for a ``django_language`` key in the the current user's
|
||||
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
|
||||
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.
|
||||
Notes:
|
||||
|
||||
The format for the explicit django_language parameters is allways the
|
||||
language to use - for example it's pt-br for Brazilian. If a base language
|
||||
is available, but the sublanguage specified is not, the base language is used.
|
||||
For example if you specify de-at (Austrian German), but there is only a
|
||||
language de available, that language is used.
|
||||
* In each of these places, the language preference is expected to be in the
|
||||
standard language format, as a string. For example, Brazilian 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``.
|
||||
|
||||
If neither the session nor the cookie carry a language code, the middleware
|
||||
will look at the HTTP header Accept-Language. This header is sent by your
|
||||
browser and tells the server what languages you prefer. Languages are ordered
|
||||
by some choice value - the higher, the more you prefer the language.
|
||||
Once ``LocaleMiddleware`` determines the user's preference, it makes this
|
||||
preference available as ``request.LANGUAGE_CODE`` for each `request object`_.
|
||||
Feel free to read this value in your view code. Here's a simple example::
|
||||
|
||||
So the middleware will iterate over that header, ordered by the preference
|
||||
value. The language with the highest preference that is in the django base
|
||||
message file directory will be used as the language to present to the user.
|
||||
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.")
|
||||
|
||||
Since the middlware discovers the language based on the request, your app
|
||||
might need to know what language is selected (if only to show the flag of
|
||||
that language). The selected language is stored by the middleware in the
|
||||
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).
|
||||
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``.
|
||||
|
||||
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
|
||||
to write the translations themselves. They need to be in a format grokable
|
||||
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.
|
||||
So, you've tagged all of your strings for later translation. But you need to
|
||||
write the translations themselves.
|
||||
|
||||
The first step is to create a message file for a new language. This can
|
||||
be created with a tool delivered with django. To run it on the django
|
||||
source tree (best from a subversion checkout), just go to the django-Directory
|
||||
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.
|
||||
They need to be in a format grokable by ``gettext``. You need to update them.
|
||||
You may need to create new ones for new languages. This section shows you how
|
||||
to do it.
|
||||
|
||||
That directory includes a subdirectory conf, and that a directory locale. The
|
||||
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.
|
||||
Creating message files
|
||||
----------------------
|
||||
|
||||
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
|
||||
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).
|
||||
Then run this command::
|
||||
|
||||
The language code for storage is in locale format - so it is pt_BR for
|
||||
Brazilian or de_AT for Austrian German.
|
||||
bin/make-messages.py -l de
|
||||
|
||||
If you don't have the gettext utilities installed, make-messages.py will 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.
|
||||
...where ``de`` is the language code for the message file you want to create.
|
||||
|
||||
Every message in the message file is of the same format. One line is the msgid.
|
||||
This is the actual string in the source - you don't change it. The other line
|
||||
is msgstr - this is the translation. It starts out empty. You change it.
|
||||
This script runs over the entire Django source tree and pulls out all strings
|
||||
marked for translation, creating or updating the language's message file.
|
||||
|
||||
There is one speciality for long messages: there the first string directly
|
||||
after the msgstr (or msgid) is an emtpy 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 will be tacked together without whitespace!
|
||||
When it's done, it will have created (or updated) a message file under the
|
||||
directory ``conf/locale``. In this example, the file will be
|
||||
``conf/locale/de/LC_MESSAGES/django.po``.
|
||||
|
||||
After you created your message file you need to transform it into some more
|
||||
efficient form to read by gettext. This is done with the second tool, that's
|
||||
compile-messages.py. This tool just runs over all available .po files and
|
||||
turns them into .mo files. Run it as follows::
|
||||
If you don't have the ``gettext`` utilities installed, ``make-messages.py``
|
||||
will create empty files. If that's the case, either install the ``gettext``
|
||||
utilities or just copy the English message file
|
||||
(``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
|
||||
|
||||
That's it. You made your first translation. If you now configure your browser
|
||||
to request your language, it show up in the admin for example.
|
||||
That's it. You made your first translation. Now, if you configure your browser
|
||||
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
|
||||
native language - so we can add it to the global list of available languages
|
||||
that is mirrored in settings.LANGUAGES (and the DjangoContext variable
|
||||
LANGUAGES in templates).
|
||||
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
|
||||
that is mirrored in ``settings.LANGUAGES`` (and the ``LANGUAGES`` template
|
||||
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.
|
||||
This is very simple with django, as django looks in several locations for
|
||||
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.
|
||||
Of course, your own projects should make use of translations. Django makes this
|
||||
simple, because it looks for message files in several locations.
|
||||
|
||||
That way you can write applications that bring their own translations with
|
||||
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:
|
||||
Django looks for translations by following this algorithm:
|
||||
|
||||
- $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)
|
||||
* 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 base translation in ``django/conf/locale``.
|
||||
|
||||
Actually the appliaction doesn't need to be stored below the project path -
|
||||
django uses module introspection to find the right place where your application
|
||||
is stored. It only needs to be listed in your INSTALLED_APPS setting.
|
||||
This way, you can write applications that include their own translations, 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.
|
||||
|
||||
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/
|
||||
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 ``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
|
||||
use the same compile-messages.py to produce the binary django.mo files that
|
||||
are used by gettext.
|
||||
use the same ``compile-messages.py`` to produce the binary ``django.mo`` files that
|
||||
are used by ``gettext``.
|
||||
|
||||
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
|
||||
django message files and project message files will be processed.
|
||||
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.
|
||||
|
||||
Additionally you should think about how to structure your translation
|
||||
files. If your applications should be delivered to other users and should
|
||||
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 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
|
||||
message file that are already in application message files. 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 stuff that is connected to your
|
||||
explicit project and not stuff that is distributed independently.
|
||||
message file that are already in application message files.
|
||||
|
||||
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
|
||||
translations. For one, the string domain is allways django. The string domain
|
||||
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.
|
||||
If you know ``gettext``, you might note these specialities in the way Django
|
||||
does translation:
|
||||
|
||||
* 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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user