diff -r 261778de26ff -r 620f9b141567 thirdparty/google_appengine/lib/django/docs/i18n.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thirdparty/google_appengine/lib/django/docs/i18n.txt Tue Aug 26 21:49:54 2008 +0000 @@ -0,0 +1,765 @@ +==================== +Internationalization +==================== + +Django has full support for internationalization of text in code and templates. +Here's how it works. + +Overview +======== + +The goal of internationalization is to allow a single Web application to offer +its content and functionality in multiple languages. + +You, the Django developer, can accomplish this goal by adding a minimal amount +of hooks to your Python code and templates. These hooks are called +**translation strings**. They tell Django: "This text should be translated into +the end user's language, if a translation for this text is available in that +language." + +Django takes care of using these hooks to translate Web apps, on the fly, +according to users' language preferences. + +Essentially, Django does two things: + + * It lets developers and template authors specify which parts of their apps + should be translatable. + * It uses these hooks to translate Web apps for particular users according + to their language preferences. + +How to internationalize your app: in three steps +------------------------------------------------ + + 1. Embed translation strings in your Python code and templates. + 2. Get translations for those strings, in whichever languages you want to + support. + 3. Activate the locale middleware in your Django settings. + +.. admonition:: Behind the scenes + + Django's translation machinery uses the standard ``gettext`` module that + comes with Python. + +If you don't need internationalization +====================================== + +Django's internationalization hooks are on by default, and that means there's a +bit of i18n-related overhead in certain places of the framework. If you don't +use internationalization, you should take the two seconds to set +``USE_I18N = False`` in your settings file. If ``USE_I18N`` is set to +``False``, then Django will make some optimizations so as not to load the +internationalization machinery. See the `documentation for USE_I18N`_. + +You'll probably also want to remove ``'django.core.context_processors.i18n'`` +from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. + +.. _documentation for USE_I18N: ../settings/#use-i18n + +How to specify translation strings +================================== + +Translation strings specify "This text should be translated." These strings can +appear in your Python code and templates. It's your responsibility to mark +translatable strings; the system can only translate strings it knows about. + +In Python code +-------------- + +Standard translation +~~~~~~~~~~~~~~~~~~~~ + +Specify a translation string by using the function ``_()``. (Yes, the name of +the function is the "underscore" character.) This function is available +globally in any Python module; you don't have to import it. + +In this example, the text ``"Welcome to my site."`` is marked as a translation +string:: + + def my_view(request): + output = _("Welcome to my site.") + return HttpResponse(output) + +The function ``django.utils.translation.gettext()`` is identical to ``_()``. +This example is identical to the previous one:: + + from django.utils.translation import gettext + def my_view(request): + output = gettext("Welcome to my site.") + return HttpResponse(output) + +Translation works on computed values. This example is identical to the previous +two:: + + def my_view(request): + words = ['Welcome', 'to', 'my', 'site.'] + output = _(' '.join(words)) + return HttpResponse(output) + +Translation works on variables. Again, here's an identical example:: + + def my_view(request): + sentence = 'Welcome to my site.' + output = _(sentence) + return HttpResponse(output) + +(The caveat with using variables or computed values, as in the previous two +examples, is that Django's translation-string-detecting utility, +``make-messages.py``, won't be able to find these strings. More on +``make-messages`` later.) + +The strings you pass to ``_()`` or ``gettext()`` can take placeholders, +specified with Python's standard named-string interpolation syntax. Example:: + + def my_view(request, n): + output = _('%(name)s is my name.') % {'name': n} + return HttpResponse(output) + +This technique lets language-specific translations reorder the placeholder +text. For example, an English translation may be ``"Adrian is my name."``, +while a Spanish translation may be ``"Me llamo Adrian."`` -- with the +placeholder (the name) placed after the translated text instead of before it. + +For this reason, you should use named-string interpolation (e.g., ``%(name)s``) +instead of positional interpolation (e.g., ``%s`` or ``%d``). If you used +positional interpolation, translations wouldn't be able to reorder placeholder +text. + +Marking strings as no-op +~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the function ``django.utils.translation.gettext_noop()`` to mark a string +as a translation string without translating it. 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. + +Lazy translation +~~~~~~~~~~~~~~~~ + +Use the function ``django.utils.translation.gettext_lazy()`` to translate +strings lazily -- when the value is accessed rather than when the +``gettext_lazy()`` function is called. + +For example, to translate a model's ``help_text``, do the following:: + + from django.utils.translation import gettext_lazy + + class MyThing(models.Model): + name = models.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 +``_`` (underscore), like so:: + + from django.utils.translation import gettext_lazy as _ + + class MyThing(models.Model): + name = models.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_name_plural`` options in the ``Meta`` +class, though:: + + from django.utils.translation import gettext_lazy as _ + + class MyThing(models.Model): + name = models.CharField(_('name'), help_text=_('This is the help text')) + class Meta: + verbose_name = _('my thing') + verbose_name_plural = _('mythings') + +.. _Django models: ../model_api/ + +Pluralization +~~~~~~~~~~~~~ + +Use the function ``django.utils.translation.ngettext()`` to specify pluralized +messages. Example:: + + from django.utils.translation import ngettext + def hello_world(request, count): + page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % { + 'count': count, + } + return HttpResponse(page) + +``ngettext`` takes three arguments: the singular translation string, the plural +translation string and the number of objects (which is passed to the +translation languages as the ``count`` variable). + +In template code +---------------- + +Using translations in `Django templates`_ uses two template tags and a slightly +different syntax than in Python code. To give your template access to these +tags, put ``{% load i18n %}`` toward the top of your template. + +The ``{% trans %}`` template tag translates a constant string or a variable +content:: + + {% trans "This is the title." %} + +If you only want to mark a value for translation, but translate it later from a +variable, use the ``noop`` option:: + + {% trans "value" noop %} + +It's not possible to use template variables in ``{% trans %}`` -- only constant +strings, in single or double quotes, are allowed. If your translations require +variables (placeholders), use ``{% blocktrans %}``. Example:: + + {% blocktrans %}This will have {{ value }} inside.{% endblocktrans %} + +To translate a template expression -- say, using template filters -- you need +to bind the expression to a local variable for use within the translation +block:: + + {% blocktrans with value|filter as myvar %} + This will have {{ myvar }} inside. + {% endblocktrans %} + +If you need to bind more than one expression inside a ``blocktrans`` tag, +separate the pieces with ``and``:: + + {% blocktrans with book|title as book_t and author|title as author_t %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +To pluralize, specify both the singular and plural forms with the +``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and +``{% endblocktrans %}``. Example:: + + {% blocktrans count list|count as counter %} + There is only one {{ name }} object. + {% plural %} + There are {{ counter }} {{ name }} objects. + {% endblocktrans %} + +Internally, all block and inline translations use the appropriate +``gettext`` / ``ngettext`` call. + +Each ``RequestContext`` 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.) + * ``LANGUAGE_BIDI`` is the current language's direction. If True, it's a + right-to-left language, e.g: Hebrew, Arabic. If False it's a + left-to-right language, e.g: English, French, German etc. + + +If you don't use the ``RequestContext`` extension, you can get those values with +three tags:: + + {% get_current_language as LANGUAGE_CODE %} + {% get_available_languages as LANGUAGES %} + {% get_current_language_bidi as LANGUAGE_BIDI %} + +These tags also require a ``{% load i18n %}``. + +Translation hooks are also available within any template block tag that accepts +constant strings. In those cases, just use ``_()`` syntax to specify a +translation string. Example:: + + {% some_special_tag _("Page not found") value|yesno:_("yes,no") %} + +In this case, both the tag and the filter will see the already-translated +string, so they don't need to be aware of translations. + +.. _Django templates: ../templates_python/ + +How to create language files +============================ + +Once you've tagged your strings for later translation, you need to write (or +obtain) the language translations themselves. Here's how that works. + +.. admonition:: Locale restrictions + + Django does not support localizing your application into a locale for + which Django itself has not been translated. In this case, it will ignore + your translation files. If you were to try this and Django supported it, + you would inevitably see a mixture of translated strings (from your + application) and English strings (from Django itself). If you want to + support a locale for your application that is not already part of + Django, you'll need to make at least a minimal translation of the Django + core. + +Message files +------------- + +The first step is to create a **message file** for a new language. A message +file is a plain-text file, representing a single language, that contains all +available translation strings and how they should be represented in the given +language. Message files have a ``.po`` file extension. + +Django comes with a tool, ``bin/make-messages.py``, that automates the creation +and upkeep of these files. + +To create or update a message file, run this command:: + + bin/make-messages.py -l de + +...where ``de`` is the language code for the message file you want to create. +The language code, in this case, is in locale format. For example, it's +``pt_BR`` for Brazilian and ``de_AT`` for Austrian German. + +The script should be run from one of three places: + + * The root ``django`` directory (not a Subversion checkout, but the one + that is linked-to via ``$PYTHONPATH`` or is located somewhere on that + path). + * The root directory of your Django project. + * The root directory of your Django app. + +The script runs over the entire Django source tree and pulls out all strings +marked for translation. It creates (or updates) a message file in the directory +``conf/locale``. In the ``de`` example, the file will be +``conf/locale/de/LC_MESSAGES/django.po``. + +If run over your project source tree or your application source tree, it will +do the same, but the location of the locale directory is ``locale/LANG/LC_MESSAGES`` +(note the missing ``conf`` prefix). + +.. admonition:: No gettext? + + 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. + +The format of ``.po`` files is straightforward. Each ``.po`` file contains a +small bit of metadata, such as the translation maintainer's contact +information, but the bulk of the file is a list of **messages** -- simple +mappings between translation strings and the actual translated text for the +particular language. + +For example, if your Django app contained a translation string for the text +``"Welcome to my site."``, like so:: + + _("Welcome to my site.") + +...then ``make-messages.py`` will have created a ``.po`` file containing the +following snippet -- a message:: + + #: path/to/python/module.py:23 + msgid "Welcome to my site." + msgstr "" + +A quick explanation: + + * ``msgid`` is the translation string, which appears in the source. Don't + change it. + * ``msgstr`` is where you put the language-specific translation. It starts + out empty, so it's your responsibility to change it. Make sure you keep + the quotes around your translation. + * As a convenience, each message includes the filename and line number + from which the translation string was gleaned. + +Long messages are a special case. There, the first string directly after the +``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be +written over the next few lines as one string per line. Those strings are +directly concatenated. Don't forget trailing spaces within the strings; +otherwise, they'll be tacked together without whitespace! + +.. admonition:: Mind your charset + + When creating a ``.po`` file with your favorite text editor, first edit + the charset line (search for ``"CHARSET"``) and set it to the charset + you'll be using to edit the content. Generally, utf-8 should work for most + languages, but ``gettext`` should handle any charset you throw at it. + +To reexamine all source code and templates for new translation strings and +update all message files for **all** languages, run this:: + + make-messages.py -a + +Compiling message files +----------------------- + +After you create your message file -- and each time you make changes to it -- +you'll need to compile it into a more efficient form, for use by ``gettext``. +Do this with the ``bin/compile-messages.py`` utility. + +This tool runs over all available ``.po`` files and creates ``.mo`` files, +which are binary files optimized for use by ``gettext``. In the same directory +from which you ran ``make-messages.py``, run ``compile-messages.py`` like +this:: + + bin/compile-messages.py + +That's it. Your translations are ready for use. + +.. admonition:: A note to translators + + If you've created a translation in a language Django doesn't yet support, + please let us know! See `Submitting and maintaining translations`_ for + the steps to take. + + .. _Submitting and maintaining translations: ../contributing/ + +How Django discovers language preference +======================================== + +Once you've prepared your translations -- or, if you just want to use the +translations that come with Django -- you'll just need to activate translation +for your app. + +Behind the scenes, Django has a very flexible model of deciding which language +should be used -- installation-wide, for a particular user, or both. + +To set an installation-wide language preference, set ``LANGUAGE_CODE`` in your +`settings file`_. Django uses this language as the default translation -- the +final attempt if no other translator finds a translation. + +If all you want to do is run Django with your native language, and a language +file is available for your language, all you need to do is set +``LANGUAGE_CODE``. + +If you want to let each individual user specify which language he or she +prefers, use ``LocaleMiddleware``. ``LocaleMiddleware`` enables language +selection based on data from the request. It customizes content for each user. + +To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` +to your ``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. + * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it. + +For example, your ``MIDDLEWARE_CLASSES`` might look like this:: + + MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + ) + +(For more on middleware, see the `middleware documentation`_.) + +``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``. + * Only languages listed in the `LANGUAGES setting`_ can be selected. If + you want to restrict the language selection to a subset of provided + languages (because your application doesn't provide all those languages), + set ``LANGUAGES`` to a list of languages. For example:: + + LANGUAGES = ( + ('de', _('German')), + ('en', _('English')), + ) + + This example restricts languages that are available for automatic + selection to German and English (and any sublanguage, like de-ch or + en-us). + + .. _LANGUAGES setting: ../settings/#languages + + * If you define a custom ``LANGUAGES`` setting, as explained in the + previous bullet, it's OK to mark the languages as translation strings + -- but use a "dummy" ``gettext()`` function, not the one in + ``django.utils.translation``. You should *never* import + ``django.utils.translation`` from within your settings file, because that + module in itself depends on the settings, and that would cause a circular + import. + + The solution is to use a "dummy" ``gettext()`` function. Here's a sample + settings file:: + + gettext = lambda s: s + + LANGUAGES = ( + ('de', gettext('German')), + ('en', gettext('English')), + ) + + With this arrangement, ``make-messages.py`` will still find and mark + these strings for translation, but the translation won't happen at + runtime -- so you'll have to remember to wrap the languages in the *real* + ``gettext()`` in any code that uses ``LANGUAGES`` at runtime. + + * The ``LocaleMiddleware`` can only select languages for which there is a + Django-provided base translation. If you want to provide translations + for your application that aren't already in the set of translations + in Django's source tree, you'll want to provide at least basic + translations for that language. For example, Django uses technical + message IDs to translate date formats and time formats -- so you will + need at least those translations for the system to work correctly. + + A good starting point is to copy the English ``.po`` file and to + translate at least the technical messages -- maybe the validator + messages, too. + + Technical message IDs are easily recognized; they're all upper case. You + don't translate the message ID as with other messages, you provide the + correct local variant on the provided English value. For example, with + ``DATETIME_FORMAT`` (or ``DATE_FORMAT`` or ``TIME_FORMAT``), this would + be the format string that you want to use in your language. The format + is identical to the format strings used by the ``now`` template tag. + +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``. + +.. _settings file: ../settings/ +.. _middleware documentation: ../middleware/ +.. _session: ../sessions/ +.. _request object: ../request_response/#httprequest-objects + +The ``set_language`` redirect view +================================== + +As a convenience, Django comes with a view, ``django.views.i18n.set_language``, +that sets a user's language preference and redirects back to the previous page. + +Activate this view by adding the following line to your URLconf:: + + (r'^i18n/', include('django.conf.urls.i18n')), + +(Note that this example makes the view available at ``/i18n/setlang/``.) + +The view expects to be called via the ``GET`` method, with a ``language`` +parameter set in the query string. If session support is enabled, the view +saves the language choice in the user's session. Otherwise, it saves the +language choice in a ``django_language`` cookie. + +After setting the language choice, Django redirects the user, following this +algorithm: + + * Django looks for a ``next`` parameter in the query string. + * If that doesn't exist, or is empty, Django tries the URL in the + ``Referer`` header. + * If that's empty -- say, if a user's browser suppresses that header -- + then the user will be redirected to ``/`` (the site root) as a fallback. + +Here's example HTML template code:: + +
+ + + +
+ +Using translations in your own projects +======================================= + +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. 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. + +.. note:: + + If you're using manually configured settings, as described in the + `settings documentation`_, the ``locale`` directory in the project + directory will not be examined, since Django loses the ability to work out + the location of the project directory. (Django normally uses the location + of the settings file to determine this, and a settings file doesn't exist + if you're manually configuring your settings.) + +.. _settings documentation: ../settings/#using-settings-without-the-django-settings-module-environment-variable + +All message file repositories are structured the same way. They are: + + * ``$APPPATH/locale//LC_MESSAGES/django.(po|mo)`` + * ``$PROJECTPATH/locale//LC_MESSAGES/django.(po|mo)`` + * All paths listed in ``LOCALE_PATHS`` in your settings file are + searched in that order for ``/LC_MESSAGES/django.(po|mo)`` + * ``$PYTHONPATH/django/conf/locale//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``. + +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. + +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 below the current path and so might put message IDs into the +project message file that are already in application message files. + +The easiest way out is to store applications that are not part of the project +(and so carry their own translations) outside the project tree. That way, +``make-messages`` on the project level will only translate strings that are +connected to your explicit project and not strings that are distributed +independently. + +Translations and JavaScript +=========================== + +Adding translations to JavaScript poses some problems: + + * JavaScript code doesn't have access to a ``gettext`` implementation. + + * JavaScript code doesn't have access to .po or .mo files; they need to be + delivered by the server. + + * The translation catalogs for JavaScript should be kept as small as + possible. + +Django provides an integrated solution for these problems: It passes the +translations into JavaScript, so you can call ``gettext``, etc., from within +JavaScript. + +The ``javascript_catalog`` view +------------------------------- + +The main solution to these problems is the ``javascript_catalog`` view, which +sends out a JavaScript code library with functions that mimic the ``gettext`` +interface, plus an array of translation strings. Those translation strings are +taken from the application, project or Django core, according to what you +specify in either the {{{info_dict}}} or the URL. + +You hook it up like this:: + + js_info_dict = { + 'packages': ('your.app.package',), + } + + urlpatterns = patterns('', + (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), + ) + +Each string in ``packages`` should be in Python dotted-package syntax (the +same format as the strings in ``INSTALLED_APPS``) and should refer to a package +that contains a ``locale`` directory. If you specify multiple packages, all +those catalogs are merged into one catalog. This is useful if you have +JavaScript that uses strings from different applications. + +You can make the view dynamic by putting the packages into the URL pattern:: + + urlpatterns = patterns('', + (r'^jsi18n/(?P\S+?)/$, 'django.views.i18n.javascript_catalog'), + ) + +With this, you specify the packages as a list of package names delimited by '+' +signs in the URL. This is especially useful if your pages use code from +different apps and this changes often and you don't want to pull in one big +catalog file. As a security measure, these values can only be either +``django.conf`` or any package from the ``INSTALLED_APPS`` setting. + +Using the JavaScript translation catalog +---------------------------------------- + +To use the catalog, just pull in the dynamically generated script like this:: + + + +This is how the admin fetches the translation catalog from the server. When the +catalog is loaded, your JavaScript code can use the standard ``gettext`` +interface to access it:: + + document.write(gettext('this is to be translated')); + +There even is a ``ngettext`` interface and a string interpolation function:: + + d = { + count: 10 + }; + s = interpolate(ngettext('this is %(count)s object', 'this are %(count)s objects', d.count), d); + +The ``interpolate`` function supports both positional interpolation and named +interpolation. So the above could have been written as:: + + s = interpolate(ngettext('this is %s object', 'this are %s objects', 11), [11]); + +The interpolation syntax is borrowed from Python. You shouldn't go over the top +with string interpolation, though: this is still JavaScript, so the code will +have to do repeated regular-expression substitutions. This isn't as fast as +string interpolation in Python, so keep it to those cases where you really +need it (for example, in conjunction with ``ngettext`` to produce proper +pluralizations). + +Creating JavaScript translation catalogs +---------------------------------------- + +You create and update the translation catalogs the same way as the other Django +translation catalogs -- with the {{{make-messages.py}}} tool. The only +difference is you need to provide a ``-d djangojs`` parameter, like this:: + + make-messages.py -d djangojs -l de + +This would create or update the translation catalog for JavaScript for German. +After updating translation catalogs, just run ``compile-messages.py`` the same +way as you do with normal Django translation catalogs. + +Specialities of Django translation +================================== + +If you know ``gettext``, you might note these specialities in the way Django +does translation: + + * The string domain is ``django`` or ``djangojs``. The string domain is used to + differentiate between different programs that store their data in a + common message-file library (usually ``/usr/share/locale/``). The ``django`` + domain is used for python and template translation strings and is loaded into + the global translation catalogs. The ``djangojs`` domain is only used for + JavaScript translation catalogs to make sure that those are as small as + possible. + * Django 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.