diff options
author | Adrian Holovaty <adrian@holovaty.com> | 2005-11-03 06:52:53 +0000 |
---|---|---|
committer | Adrian Holovaty <adrian@holovaty.com> | 2005-11-03 06:52:53 +0000 |
commit | e2b7527f79e7106b7d5910072b8e4500a658000d (patch) | |
tree | 58c4190f4a04f5b88709ea0c878f21da3618c829 | |
parent | 1c4a48134afcf7e49685b97cd7b65af5c058db75 (diff) | |
download | django-e2b7527f79e7106b7d5910072b8e4500a658000d.tar.gz |
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
-rw-r--r-- | docs/translation.txt | 671 |
1 files changed, 352 insertions, 319 deletions
diff --git a/docs/translation.txt b/docs/translation.txt index 54c5a4b512..dfb989d2ab 100644 --- a/docs/translation.txt +++ b/docs/translation.txt @@ -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. - -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: - -- 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 _() - -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. - -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:: - - def hello_world(request, name, site): - page = _('Hello %(name)s, welcome to %(site)s!') % { - 'name': name, - 'site': site, - } - return 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. - -The other two helper functions are similar in use:: - - 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 - -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. - -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:: +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. - from django.utils.translation import gettext_lazy +To translate strings in your code, use one of the ``gettext`` helper functions. +There are essentially two ways to use them: + + * 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 ``_()``. + +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 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 HttpResponse(page) + +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:: + + 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) - class Mything(meta.Model): +The difference here is that ``gettext`` is explicitly imported. - name = meta.CharField('Name', help_text=gettext_lazy('This is the help text')) - ... +Two important helper functions are available: ``gettext`` and ``gettext_noop``. -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. + * ``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. -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:: +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): + name = meta.CharField(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. + +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')) - class META: +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:: - verbose_name = _('Mything') - verbose_name_plural = _('Mythings') + from django.utils.translation import gettext_lazy as _ -There is another standard problem with translations, that is pluralization of -strings. This is done by the standard helper ngettext like so:: + 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') + +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:: - - <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. - -To translate a variable value, you can just do {% i18n _(variable) %}. This -can even include filters like {% i18n _(variable|lower} %}. - -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:: - - <html> - <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. - -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:: +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> + +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, do this:: + + {% i18n _(variable) %} + +Filters are allowed, too:: + + {% i18n _(variable|lower) %} + +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/``. + +How language preference is discovered +===================================== + +Django has a very flexible model of deciding which language should be used -- +installation-wide, for a particular user, or both. -This adds the setlang handler to your urlspace and hooks up a standard view -function to it. +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. -How the Language is Discovered -============================== +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``. -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. +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. -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). +To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` +to your ``MIDDLEWARE_CLASSES`` setting. Because middleware order matters, you +should follow these guidelines: -So your middleware settings might look like this:: + * 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). - -The LocaleMiddleware allows a selection of the language based on data from -the request - every user can have her own settings. - -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. - -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. - -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. - -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. - -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). - -Creating Language Files +``LocaleMiddleware`` tries to determine the user's language preference by +following this algorithm: + + * 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. + +Notes: + + * 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``. + +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:: + + 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``. + +.. _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. - -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. - -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. - -To run it, just do the following:: - - bin/make-messages.py -l de - -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). - -The language code for storage is in locale format - so it is pt_BR for -Brazilian or de_AT for Austrian German. - -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. - -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. - -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! - -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:: +So, you've tagged all of 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 section shows you how +to do it. + +Creating message files +---------------------- + +The first step is to create a message file for a new language. Django comes +with a tool, ``make-messages.py``, that automates this. + +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. + +Then run this command:: + + bin/make-messages.py -l de + +...where ``de`` is the language code for the message file you want to create. + +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. + +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``. + +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. - -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: - -- $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) - -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. - -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/ +Of course, your own projects should make use of translations. Django makes this +simple, because it looks for message files in several locations. + +Django looks for translations by following this algorithm: + + * First, it looks for a ``locale`` directory in the application directory + of the view that's being called. If it finds a translation for the + selected language, the translation will be installed. + * Next, it looks for a ``locale`` directory in the project directory. If it + finds a translation, the translation will be installed. + * Finally, it checks the base translation in ``django/conf/locale``. + +This way, you can write applications that include their own translations, and +you can override base translations in your project path 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 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 -================================== - -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. +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. -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. +Specialities of Django translation +================================== +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. |