Browse Source

Fixed #10260 - Refactored internationalization documentation. Thanks, Ramiro Morales.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12440 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Jannis Leidel 15 years ago
parent
commit
f93f056c32

+ 1 - 1
django/conf/global_settings.py

@@ -306,7 +306,7 @@ YEAR_MONTH_FORMAT = 'F Y'
 # http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
 MONTH_DAY_FORMAT = 'F j'
 
-# Default shortformatting for date objects. See all available format strings here:
+# Default short formatting for date objects. See all available format strings here:
 # http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now
 SHORT_DATE_FORMAT = 'm/d/Y'
 

+ 72 - 0
docs/howto/i18n.txt

@@ -0,0 +1,72 @@
+.. _howto-i18n:
+
+.. _using-translations-in-your-own-projects:
+
+===============================================
+Using internationalization in your own projects
+===============================================
+
+At runtime, 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 Django-provided base translation in
+      ``django/conf/locale``.
+
+In all cases the name of the directory containing the translation is expected to
+be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``,
+etc.
+
+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
+    :ref:`settings-without-django-settings-module`, 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.)
+
+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 :djadmin:`django-admin.py makemessages <makemessages>`
+tool. You only need to be in the same directory where the ``locale/`` directory
+is located. And you use :djadmin:`django-admin.py compilemessages <compilemessages>`
+to produce the binary ``.mo`` files that are used by ``gettext``. Read the
+:ref:`topics-i18n-localization` document for more details.
+
+You can also run ``django-admin.py compilemessages --settings=path.to.settings``
+to make the compiler process all the directories in your :setting:`LOCALE_PATHS`
+setting.
+
+Application message files are a bit complicated to discover -- they need the
+:class:`~django.middleware.locale.LocaleMiddleware`. If you don't use the
+middleware, only the Django message files and project message files will be
+installed and available at runtime.
+
+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 ``makemessages``: It 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,
+``django-admin.py makemessages`` on the project level will only translate
+strings that are connected to your explicit project and not strings that are
+distributed independently.

+ 1 - 0
docs/howto/index.txt

@@ -20,6 +20,7 @@ you quickly accomplish common tasks.
    deployment/index
    error-reporting
    initial-data
+   i18n
    jython
    legacy-databases
    outputting-csv

+ 13 - 6
docs/internals/contributing.txt

@@ -402,15 +402,18 @@ translated, here's what to do:
 
     * Join the `Django i18n mailing list`_ and introduce yourself.
 
+    * Make sure you read the notes about :ref:`specialties-of-django-i18n`.
+
     * Create translations using the methods described in the
-      :ref:`i18n documentation <topics-i18n>`. For this you will use the
-      ``django-admin.py makemessages`` tool. In this particular case it should
-      be run from the top-level ``django`` directory of the Django source tree.
+      :ref:`localization documentation <topics-i18n-localization>`. For this
+      you will use the ``django-admin.py makemessages`` tool. In this
+      particular case it should be run from the top-level ``django`` directory
+      of the Django source tree.
 
       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`` (for example for ``pt-BR``, the file will be
-      ``conf/locale/pt-br/LC_MESSAGES/django.po``).
+      the directory ``conf/locale`` (for example for ``pt_BR``, the file will be
+      ``conf/locale/pt_BR/LC_MESSAGES/django.po``).
 
     * Make sure that ``django-admin.py compilemessages -l <lang>`` runs without
       producing any warnings.
@@ -419,7 +422,11 @@ translated, here's what to do:
       ``-d djangojs`` command line option to the ``django-admin.py``
       invocations).
 
-    * Create a diff of the ``.po`` file(s) against the current Subversion trunk.
+    * Optionally, review and update the ``conf/locale/<locale>/formats.py``
+      file to describe the date, time and numbers formatting particularities of
+      your locale. See :ref:`format-localization` for details.
+
+    * Create a diff against the current Subversion trunk.
 
     * Open a ticket in Django's ticket system, set its ``Component`` field to
       ``Translations``, and attach the patch to it.

+ 8 - 6
docs/ref/settings.txt

@@ -883,8 +883,8 @@ LANGUAGE_CODE
 Default: ``'en-us'``
 
 A string representing the language code for this installation. This should be in
-standard language format. For example, U.S. English is ``"en-us"``. See
-:ref:`topics-i18n`.
+standard :term:`language format<language code>`. For example, U.S. English is
+``"en-us"``. See :ref:`topics-i18n`.
 
 .. setting:: LANGUAGE_COOKIE_NAME
 
@@ -911,9 +911,11 @@ see the current list of translated languages by looking in
 
 .. _online source: http://code.djangoproject.com/browser/django/trunk/django/conf/global_settings.py
 
-The list is a tuple of two-tuples in the format (language code, language
-name) -- for example, ``('ja', 'Japanese')``. This specifies which languages
-are available for language selection. See :ref:`topics-i18n`.
+The list is a tuple of two-tuples in the format ``(language code, language
+name)``, the ``language code`` part should be a
+:term:`language name<language code>` -- for example, ``('ja', 'Japanese')``.
+This specifies which languages are available for language selection. See
+:ref:`topics-i18n`.
 
 Generally, the default value should suffice. Only set this setting if you want
 to restrict language selection to a subset of the Django-provided languages.
@@ -948,7 +950,7 @@ LOCALE_PATHS
 Default: ``()`` (Empty tuple)
 
 A tuple of directories where Django looks for translation files.
-See :ref:`translations-in-your-own-projects`.
+See :ref:`using-translations-in-your-own-projects`.
 
 .. setting:: LOGIN_REDIRECT_URL
 

+ 15 - 2
docs/releases/1.2.txt

@@ -516,6 +516,19 @@ documentation <ref-contrib-syndication>`.
 
 .. _RSS best practices: http://www.rssboard.org/rss-profile
 
+Technical message IDs
+---------------------
+
+Up to version 1.1 Django used :ref:`technical message IDs<technical-messages>`
+to provide localizers the possibility to translate date and time formats. They
+were translatable :term:`translation strings <translation string>` that could
+be recognized because they were all upper case (for example
+``DATETIME_FORMAT``, ``DATE_FORMAT``, ``TIME_FORMAT``). They have been
+deprecated in favor of the new :ref:`Format localization
+<format-localization>` infrastructure that allows localizers to specify that
+information in a ``formats.py`` file in the corresponding
+``django/conf/locale/<locale name>/`` directory.
+
 What's new in Django 1.2
 ========================
 
@@ -577,7 +590,7 @@ added support for comparison operators. No longer will you have to type:
 .. code-block:: html+django
 
     {% ifnotequal a b %}
-    ...
+     ...
     {% endifnotequal %}
 
 You can now do this:
@@ -585,7 +598,7 @@ You can now do this:
 .. code-block:: html+django
 
     {% if a != b %}
-    ...
+     ...
     {% endif %}
 
 There's really no reason to use ``{% ifequal %}`` or ``{% ifnotequal %}``

+ 0 - 1144
docs/topics/i18n.txt

@@ -1,1144 +0,0 @@
-.. _topics-i18n:
-
-====================
-Internationalization
-====================
-
-Django has full support for internationalization of text in code and
-templates, and format localization of dates and numbers. 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 and locales.
-
-For text translation, 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.
-
-For format localization, it's just necessary to set
-:setting:`USE_L10N = True <USE_L10N>` in your settings file. If
-:setting:`USE_L10N` is set to ``True``, Django will display
-numbers and dates in the format of the current locale. That includes field
-representation on templates, and allowed input formats on the admin.
-
-If you don't need internationalization in your app
-==================================================
-
-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
-:setting:`USE_I18N = False <USE_I18N>` in your settings file. If
-:setting:`USE_I18N` is set to ``False``, then Django will make some
-optimizations so as not to load the internationalization machinery.
-
-You'll probably also want to remove ``'django.core.context_processors.i18n'``
-from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting.
-
-If you do need internationalization: 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.
-
-1. 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 ``ugettext()``. It's
-convention to import this as a shorter alias, ``_``, to save typing.
-
-.. note::
-    Python's standard library ``gettext`` module installs ``_()`` into the
-    global namespace, as an alias for ``gettext()``. In Django, we have chosen
-    not to follow this practice, for a couple of reasons:
-
-      1. For international character set (Unicode) support, ``ugettext()`` is
-         more useful than ``gettext()``. Sometimes, you should be using
-         ``ugettext_lazy()`` as the default translation method for a particular
-         file. Without ``_()`` in the global namespace, the developer has to
-         think about which is the most appropriate translation function.
-
-      2. The underscore character (``_``) is used to represent "the previous
-         result" in Python's interactive shell and doctest tests. Installing a
-         global ``_()`` function causes interference. Explicitly importing
-         ``ugettext()`` as ``_()`` avoids this problem.
-
-.. highlightlang:: python
-
-In this example, the text ``"Welcome to my site."`` is marked as a translation
-string::
-
-    from django.utils.translation import ugettext as _
-
-    def my_view(request):
-        output = _("Welcome to my site.")
-        return HttpResponse(output)
-
-Obviously, you could code this without using the alias. This example is
-identical to the previous one::
-
-    from django.utils.translation import ugettext
-
-    def my_view(request):
-        output = ugettext("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,
-``django-admin.py makemessages``, won't be able to find these strings. More on
-``makemessages`` later.)
-
-The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
-specified with Python's standard named-string interpolation syntax. Example::
-
-    def my_view(request, m, d):
-        output = _('Today is %(month)s, %(day)s.') % {'month': m, 'day': d}
-        return HttpResponse(output)
-
-This technique lets language-specific translations reorder the placeholder
-text. For example, an English translation may be ``"Today is November, 26."``,
-while a Spanish translation may be ``"Hoy es 26 de Noviembre."`` -- with the
-placeholders (the month and the day) with their positions swapped.
-
-For this reason, you should use named-string interpolation (e.g., ``%(day)s``)
-instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
-have more than a single parameter. 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.ugettext_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-translations:
-
-Lazy translation
-~~~~~~~~~~~~~~~~
-
-Use the function ``django.utils.translation.ugettext_lazy()`` to translate
-strings lazily -- when the value is accessed rather than when the
-``ugettext_lazy()`` function is called.
-
-For example, to translate a model's ``help_text``, do the following::
-
-    from django.utils.translation import ugettext_lazy
-
-    class MyThing(models.Model):
-        name = models.CharField(help_text=ugettext_lazy('This is the help text'))
-
-In this example, ``ugettext_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.
-
-The result of a ``ugettext_lazy()`` call can be used wherever you would use a
-unicode string (an object with type ``unicode``) in Python. If you try to use
-it where a bytestring (a ``str`` object) is expected, things will not work as
-expected, since a ``ugettext_lazy()`` object doesn't know how to convert
-itself to a bytestring.  You can't use a unicode string inside a bytestring,
-either, so this is consistent with normal Python behavior. For example::
-
-    # This is fine: putting a unicode proxy into a unicode string.
-    u"Hello %s" % ugettext_lazy("people")
-
-    # This will not work, since you cannot insert a unicode object
-    # into a bytestring (nor can you insert our unicode proxy there)
-    "Hello %s" % ugettext_lazy("people")
-
-If you ever see output that looks like ``"hello
-<django.utils.functional...>"``, you have tried to insert the result of
-``ugettext_lazy()`` into a bytestring. That's a bug in your code.
-
-If you don't like the verbose name ``ugettext_lazy``, you can just alias it as
-``_`` (underscore), like so::
-
-    from django.utils.translation import ugettext_lazy as _
-
-    class MyThing(models.Model):
-        name = models.CharField(help_text=_('This is the help text'))
-
-Always use lazy translations in :ref:`Django models <topics-db-models>`.
-Field names and table names should be marked for translation (otherwise, they
-won't be translated in the admin interface). This means writing explicit
-``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class,
-though, rather than relying on Django's default determination of
-``verbose_name`` and ``verbose_name_plural`` by looking at the model's class
-name::
-
-    from django.utils.translation import ugettext_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')
-
-Pluralization
-~~~~~~~~~~~~~
-
-Use the function ``django.utils.translation.ungettext()`` to specify pluralized
-messages.
-
-``ungettext`` takes three arguments: the singular translation string, the
-plural translation string and the number of objects.
-
-This function is useful when you need your Django application to be localizable
-to languages where the number and complexity of `plural forms
-<http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is
-greater than the two forms used in English ('object' for the singular and
-'objects' for all the cases where ``count`` is different from zero,
-irrespective of its value).
-
-For example::
-
-    from django.utils.translation import ungettext
-    def hello_world(request, count):
-        page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % {
-            'count': count,
-        }
-        return HttpResponse(page)
-
-In this example the number of objects is passed to the translation languages as
-the ``count`` variable.
-
-Lets see a slightly more complex usage example::
-
-    from django.utils.translation import ungettext
-
-    count = Report.objects.count()
-    if count == 1:
-        name = Report._meta.verbose_name
-    else:
-        name = Report._meta.verbose_name_plural
-
-    text = ungettext(
-            'There is %(count)d %(name)s available.',
-            'There are %(count)d %(name)s available.',
-            count
-    ) % {
-        'count': count,
-        'name': name
-    }
-
-Here we reuse localizable, hopefully already translated literals (contained in
-the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for
-other parts of the sentence so all of it is consistently based on the
-cardinality of the elements at play.
-
-.. _pluralization-var-notes:
-
-.. note::
-
-    When using this technique, make sure you use a single name for every
-    extrapolated variable included in the literal. In the example above note
-    how we used the ``name`` Python variable in both translation strings. This
-    example would fail::
-
-        from django.utils.translation import ungettext
-        from myapp.models import Report
-
-        count = Report.objects.count()
-        d = {
-            'count': count,
-            'name': Report._meta.verbose_name
-            'plural_name': Report._meta.verbose_name_plural
-        }
-        text = ungettext(
-                'There is %(count)d %(name)s available.',
-                'There are %(count)d %(plural_name)s available.',
-                count
-        ) % d
-
-    You would get a ``a format specification for argument 'name', as in
-    'msgstr[0]', doesn't exist in 'msgid'`` error when running
-    ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at
-    runtime.
-
-In template code
-----------------
-
-.. highlightlang:: html+django
-
-Translations in :ref:`Django templates <topics-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 either a constant string
-(enclosed in single or double quotes) or variable content::
-
-    <title>{% trans "This is the title." %}</title>
-    <title>{% trans myvar %}</title>
-
-If the ``noop`` option is present, variable lookup still takes place, but the
-original text will be returned unchanged. This is useful when "stubbing out"
-content that will require translation in the future::
-
-    <title>{% trans "myvar" noop %}</title>
-
-Internally, inline translations use an ``ugettext`` call.
-
-It's not possible to mix a template variable inside a string within ``{% trans
-%}``. If your translations require strings with variables (placeholders), use
-``{% blocktrans %}``::
-
-    {% blocktrans %}This string 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|length as counter %}
-    There is only one {{ name }} object.
-    {% plural %}
-    There are {{ counter }} {{ name }} objects.
-    {% endblocktrans %}
-
-When you use the pluralization feature and bind additional values to local
-variables apart from the counter value that selects the translated literal to
-be used, have in mind that the ``blocktrans`` construct is internally converted
-to an ``ungettext`` call. This means the same :ref:`notes regarding ungettext
-variables <pluralization-var-notes>` apply.
-
-Each ``RequestContext`` has access to three 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 (translated into the
-      currently active locale).
-
-    * ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
-      Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`,
-      below.)
-
-    * ``LANGUAGE_BIDI`` is the current locale'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::
-
-    {% 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.
-
-.. note::
-    In this example, the translation infrastructure will be passed the string
-    ``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The
-    translated string will need to contain the comma so that the filter
-    parsing code knows how to split up the arguments. For example, a German
-    translator might translate the string ``"yes,no"`` as ``"ja,nein"``
-    (keeping the comma intact).
-
-.. _Django templates: ../templates_python/
-
-Working with lazy translation objects
--------------------------------------
-
-.. highlightlang:: python
-
-Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models
-and utility functions is a common operation. When you're working with these
-objects elsewhere in your code, you should ensure that you don't accidentally
-convert them to strings, because they should be converted as late as possible
-(so that the correct locale is in effect). This necessitates the use of a
-couple of helper functions.
-
-Joining strings: string_concat()
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Standard Python string joins (``''.join([...])``) will not work on lists
-containing lazy translation objects. Instead, you can use
-``django.utils.translation.string_concat()``, which creates a lazy object that
-concatenates its contents *and* converts them to strings only when the result
-is included in a string. For example::
-
-    from django.utils.translation import string_concat
-    ...
-    name = ugettext_lazy(u'John Lennon')
-    instrument = ugettext_lazy(u'guitar')
-    result = string_concat([name, ': ', instrument])
-
-In this case, the lazy translations in ``result`` will only be converted to
-strings when ``result`` itself is used in a string (usually at template
-rendering time).
-
-The allow_lazy() decorator
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Django offers many utility functions (particularly in ``django.utils``) that
-take a string as their first argument and do something to that string. These
-functions are used by template filters as well as directly in other code.
-
-If you write your own similar functions and deal with translations, you'll
-face the problem of what to do when the first argument is a lazy translation
-object. You don't want to convert it to a string immediately, because you might
-be using this function outside of a view (and hence the current thread's locale
-setting will not be correct).
-
-For cases like this, use the ``django.utils.functional.allow_lazy()``
-decorator. It modifies the function so that *if* it's called with a lazy
-translation as the first argument, the function evaluation is delayed until it
-needs to be converted to a string.
-
-For example::
-
-    from django.utils.functional import allow_lazy
-
-    def fancy_utility_function(s, ...):
-        # Do some conversion on string 's'
-        ...
-    fancy_utility_function = allow_lazy(fancy_utility_function, unicode)
-
-The ``allow_lazy()`` decorator takes, in addition to the function to decorate,
-a number of extra arguments (``*args``) specifying the type(s) that the
-original function can return. Usually, it's enough to include ``unicode`` here
-and ensure that your function returns only Unicode strings.
-
-Using this decorator means you can write your function and assume that the
-input is a proper string, then add support for lazy translation objects at the
-end.
-
-.. _how-to-create-language-files:
-
-2. 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. See the relevant :ref:`LocaleMiddleware note<locale-middleware-notes>`
-    for more details.
-
-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, ``django-admin.py makemessages``, that automates the
-creation and upkeep of these files.
-
-.. admonition:: A note to Django veterans
-
-    The old tool ``bin/make-messages.py`` has been moved to the command
-    ``django-admin.py makemessages`` to provide consistency throughout Django.
-
-.. admonition:: Gettext utilities
-
-    The ``makemessages`` command (and ``compilemessages`` discussed later) use
-    commands from the GNU gettext toolset: ``xgetetxt``, ``msgfmt``,
-    ``msgmerge`` and ``msguniq``.
-
-    .. versionchanged:: 1.2
-
-    The minimum version of the ``gettext`` utilities supported is 0.15.
-
-To create or update a message file, run this command::
-
-    django-admin.py makemessages -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 Portuguese and ``de_AT`` for Austrian German.
-
-The script should be run from one of three places:
-
-    * The root directory of your Django project.
-    * The root directory of your Django app.
-    * The root ``django`` directory (not a Subversion checkout, but the one
-      that is linked-to via ``$PYTHONPATH`` or is located somewhere on that
-      path). This is only relevant when you are creating a translation for
-      Django itself, see :ref:`contributing-translations`.
-
-The script runs over your project source tree or your application source tree
-and pulls out all strings marked for translation. It creates (or updates) a
-message file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de``
-example, the file will be ``locale/de/LC_MESSAGES/django.po``.
-
-By default ``django-admin.py makemessages`` examines every file that has the
-``.html`` file extension. In case you want to override that default, use the
-``--extension`` or ``-e`` option to specify the file extensions to examine::
-
-    django-admin.py makemessages -l de -e txt
-
-Separate multiple extensions with commas and/or use ``-e`` or ``--extension``
-multiple times::
-
-    django-admin.py makemessages -l=de -e=html,txt -e xml
-
-When `creating JavaScript translation catalogs`_ you need to use the special
-'djangojs' domain, **not** ``-e js``.
-
-.. admonition:: No gettext?
-
-    If you don't have the ``gettext`` utilities installed, ``django-admin.py
-    makemessages`` will create empty files. If that's the case, either install
-    the ``gettext`` utilities or just copy the English message file
-    (``locale/en/LC_MESSAGES/django.po``) if available and use it as a starting
-    point; it's just an empty translation file.
-
-.. admonition:: Working on Windows?
-
-   If you're using Windows and need to install the GNU gettext utilities so
-   ``django-admin makemessages`` works see `gettext on Windows`_ for more
-   information.
-
-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 ``django-admin.py makemessages`` 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, in the form of a comment line
-      prefixed with ``#`` and located above the ``msgid`` line, 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. Due to the way the ``gettext`` tools
-    work internally and because we want to allow non-ASCII source strings in
-    Django's core and your applications, you **must** use UTF-8 as the encoding
-    for your PO file. This means that everybody will be using the same
-    encoding, which is important when Django processes the PO files.
-
-To reexamine all source code and templates for new translation strings and
-update all message files for **all** languages, run this::
-
-    django-admin.py makemessages -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 ``django-admin.py compilemessages`` 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 ``django-admin.py makemessages``, run ``django-admin.py
-compilemessages`` like this::
-
-   django-admin.py compilemessages
-
-That's it. Your translations are ready for use.
-
-.. admonition:: A note to Django veterans
-
-    The old tool ``bin/compile-messages.py`` has been moved to the command
-    ``django-admin.py compilemessages`` to provide consistency throughout
-    Django.
-
-.. admonition:: Working on Windows?
-
-   If you're using Windows and need to install the GNU gettext utilities so
-   ``django-admin compilemessages`` works see `gettext on Windows`_ for more
-   information.
-
-.. _how-django-discovers-language-preference:
-
-3. 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 :setting:`LANGUAGE_CODE`.
-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 :ref:`middleware documentation
-<topics-http-middleware>`.)
-
-``LocaleMiddleware`` tries to determine the user's language preference by
-following this algorithm:
-
-    * First, it looks for a ``django_language`` key in the current user's
-      session.
-
-    * Failing that, it looks for a cookie.
-
-      .. versionchanged:: 1.0
-
-      In Django version 0.96 and before, the cookie's name is hard-coded to
-      ``django_language``. In Django 1,0, The cookie name is set by the
-      ``LANGUAGE_COOKIE_NAME`` setting. (The default name is
-      ``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.
-
-.. _locale-middleware-notes:
-
-Notes:
-
-    * In each of these places, the language preference is expected to be in the
-      standard language format, as a string. For example, Brazilian Portuguese
-      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 :setting:`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" ``ugettext()`` 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" ``ugettext()`` function. Here's a sample
-      settings file::
-
-          ugettext = lambda s: s
-
-          LANGUAGES = (
-              ('de', ugettext('German')),
-              ('en', ugettext('English')),
-          )
-
-      With this arrangement, ``django-admin.py makemessages`` 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* ``ugettext()`` 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 validation
-      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
-:class:`~django.http.HttpRequest`. 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
-
-.. _translations-in-your-own-projects:
-
-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 Django-provided 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
-    :ref:`settings-without-django-settings-module`, 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.)
-
-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 ``django-admin.py makemessages``
-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 ``django-admin.py
-compilemessages`` to produce the binary ``django.mo`` files that are used by
-``gettext``.
-
-You can also run ``django-admin.py compilemessages
---settings=path.to.settings`` to make the compiler process all the directories
-in your ``LOCALE_PATHS`` setting.
-
-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 ``makemessages``: ``makemessages`` 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,
-``django-admin.py makemessages`` on the project level will only translate
-strings that are connected to your explicit project and not strings that are
-distributed independently.
-
-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 ``POST`` method, with a ``language``
-parameter set in request. If session support is enabled, the view
-saves the language choice in the user's session. Otherwise, it saves the
-language choice in a cookie that is by default named ``django_language``.
-(The name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting.)
-
-After setting the language choice, Django redirects the user, following this
-algorithm:
-
-    * Django looks for a ``next`` parameter in the ``POST`` data.
-    * If that doesn't exist, or is empty, Django tries the URL in the
-      ``Referrer`` 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:
-
-.. code-block:: html+django
-
-    <form action="/i18n/setlang/" method="post">
-    <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>
-
-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<packages>\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::
-
-    <script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
-
-This uses reverse URL lookup to find the URL of the JavaScript catalog view.
-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 is also an ``ngettext`` interface::
-
-    var object_cnt = 1 // or 0, or 2, or 3, ...
-    s = ngettext('literal for the singular case',
-            'literal for the plural case', object_cnt);
-
-and even a string interpolation function::
-
-    function interpolate(fmt, obj, named);
-
-The interpolation syntax is borrowed from Python, so the ``interpolate``
-function supports both positional and named interpolation:
-
-    * Positional interpolation: ``obj`` contains a JavaScript Array object
-      whose elements values are then sequentially interpolated in their
-      corresponding ``fmt`` placeholders in the same order they appear.
-      For example::
-
-        fmts = ngettext('There is %s object. Remaining: %s',
-                'There are %s objects. Remaining: %s', 11);
-        s = interpolate(fmts, [11, 20]);
-        // s is 'There are 11 objects. Remaining: 20'
-
-    * Named interpolation: This mode is selected by passing the optional
-      boolean ``named`` parameter as true. ``obj`` contains a JavaScript
-      object or associative array. For example::
-
-        d = {
-            count: 10
-            total: 50
-        };
-
-        fmts = ngettext('Total: %(total)s, there is %(count)s object',
-        'there are %(count)s of a total of %(total)s objects', d.count);
-        s = interpolate(fmts, d, true);
-
-You shouldn't go over the top with string interpolation, though: this is still
-JavaScript, so the code has to make 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 ``django-admin.py makemessages`` tool.
-The only difference is you need to provide a ``-d djangojs`` parameter, like
-this::
-
-    django-admin.py makemessages -d djangojs -l de
-
-This would create or update the translation catalog for JavaScript for German.
-After updating translation catalogs, just run ``django-admin.py
-compilemessages`` the same way as you do with normal Django translation
-catalogs.
-
-Specialties of Django translation
-==================================
-
-If you know ``gettext``, you might note these specialties in the way Django
-does translation:
-
-    * The string domain is ``django`` or ``djangojs``. This string domain is
-      used to differentiate between different programs that store their data
-      in a common message-file library (usually ``/usr/share/locale/``). The
-      ``django`` domain is used for python and template translation strings
-      and is loaded into the global translation catalogs. The ``djangojs``
-      domain is only used for JavaScript translation catalogs to make sure
-      that those are as small as possible.
-    * Django doesn't use ``xgettext`` alone. It uses Python wrappers around
-      ``xgettext`` and ``msgfmt``. This is mostly for convenience.
-
-``gettext`` on Windows
-======================
-
-This is only needed for people who either want to extract message IDs or
-compile message files (``.po``). Translation work itself just involves editing
-existing files of this type, but if you want to create your own message files,
-or want to test or compile a changed message file, you will need the
-``gettext`` utilities:
-
-    * Download the following zip files from the GNOME servers
-      http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
-      of its mirrors_
-
-      * ``gettext-runtime-X.zip``
-      * ``gettext-tools-X.zip``
-
-      ``X`` is the version number, we are requiring ``0.15`` or higher.
-
-    * Extract the contents of the ``bin\`` directories in both files to the
-      same folder on your system (i.e. ``C:\Program Files\gettext-utils``)
-
-    * Update the system PATH:
-
-      * ``Control Panel > System > Advanced > Environment Variables``
-      * In the ``System variables`` list, click ``Path``, click ``Edit``
-      * Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
-        ``Variable value`` field
-
-.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
-
-You may also use ``gettext`` binaries you have obtained elsewhere, so long as
-the ``xgettext --version`` command works properly. Some version 0.14.4 binaries
-have been found to not support this command. Do not attempt to use Django
-translation utilities with a ``gettext`` package if the command ``xgettext
---version`` entered at a Windows command prompt causes a popup window saying
-"xgettext.exe has generated errors and will be closed by Windows".
-
-.. _format-localization:
-
-Format localization
-===================
-
-Django's formatting system is disabled by default. To enable it, it's necessay
-to set :setting:`USE_L10N = True <USE_L10N>` in your settings file.
-
-When using Django's formatting system, dates and numbers on templates will be
-displayed using the format specified for the current locale. Two users
-accessing the same content, but in different language, will see date and
-number fields formatted in different ways, depending on the format for their
-current locale.
-
-Django will also use localized formats when parsing data in forms. That means
-Django uses different formats for different locales when guessing the format
-used by the user when inputting data on forms. Note that Django uses different
-formats for displaying data, and for parsing it.
-
-Creating custom format files
-----------------------------
-
-Django provides format definitions for many locales, but sometimes you might
-want to create your own, because a format files doesn't exist for your locale,
-or because you want to overwrite some of the values.
-
-To use custom formats, first thing to do, is to specify the path where you'll
-place format files. To do that, just set your :setting:`FORMAT_MODULE_PATH`
-setting to the the path (in the format ``'foo.bar.baz``) where format files
-will exists.
-
-Files are not placed directly in this directory, but in a directory named as
-the locale, and must be named ``formats.py``.
-
-To customize the English formats, a structure like this would be needed::
-
-    mysite/
-        formats/
-            __init__.py
-            en/
-                __init__.py
-                formats.py
-
-where :file:`formats.py` contains custom format definitions. For example::
-
-    THOUSAND_SEPARATOR = ' '
-
-to use a space as a thousand separator, instead of the default for English,
-a comma.

+ 195 - 0
docs/topics/i18n/deployment.txt

@@ -0,0 +1,195 @@
+.. _topics-i18n-deployment:
+
+==========================
+Deployment of translations
+==========================
+
+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
+:setting:`USE_I18N = False <USE_I18N>` in your settings file. If
+:setting:`USE_I18N` is set to ``False``, then Django will make some
+optimizations so as not to load the internationalization machinery.
+
+You'll probably also want to remove ``'django.core.context_processors.i18n'``
+from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting.
+
+.. note::
+
+    There is also an independent but related :setting:`USE_L10N` setting that
+    controls if Django should implement format localization.
+
+    If :setting:`USE_L10N` is set to ``True``, Django will handle numbers times,
+    and dates in the format of the current locale. That includes representation
+    of these field types on templates and allowed input formats for dates,
+    times on model forms.
+
+    See :ref:`format-localization` for more details.
+
+If you do need internationalization
+===================================
+
+.. _how-django-discovers-language-preference:
+
+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 :setting:`LANGUAGE_CODE`.
+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 it, 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 :ref:`middleware documentation
+<topics-http-middleware>`.)
+
+``LocaleMiddleware`` tries to determine the user's language preference by
+following this algorithm:
+
+    * First, it looks for a ``django_language`` key in the current user's
+      session.
+
+    * Failing that, it looks for a cookie.
+
+      .. versionchanged:: 1.0
+
+      In Django version 0.96 and before, the cookie's name is hard-coded to
+      ``django_language``. In Django 1,0, The cookie name is set by the
+      ``LANGUAGE_COOKIE_NAME`` setting. (The default name is
+      ``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.
+
+.. _locale-middleware-notes:
+
+Notes:
+
+    * In each of these places, the language preference is expected to be in the
+      standard :term:`language format<language code>`, as a string. For example,
+      Brazilian Portuguese 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 :setting:`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" ``ugettext()`` 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" ``ugettext()`` function. Here's a sample
+      settings file::
+
+          ugettext = lambda s: s
+
+          LANGUAGES = (
+              ('de', ugettext('German')),
+              ('en', ugettext('English')),
+          )
+
+      With this arrangement, ``django-admin.py makemessages`` 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* ``ugettext()`` 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 a basic
+      one as described in the :ref:`Locale restrictions<locale-restrictions>`
+      note.
+
+Once ``LocaleMiddleware`` determines the user's preference, it makes this
+preference available as ``request.LANGUAGE_CODE`` for each
+:class:`~django.http.HttpRequest`. 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
+
+How Django discovers translations
+---------------------------------
+
+As described in :ref:`using-translations-in-your-own-projects`,
+at runtime, 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 Django-provided base translation in
+      ``django/conf/locale``.
+
+In all cases the name of the directory containing the translation is expected to
+be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``,
+etc.

+ 115 - 0
docs/topics/i18n/index.txt

@@ -0,0 +1,115 @@
+.. _topics-i18n:
+
+=====================================
+Internationalization and localization
+=====================================
+
+Overview
+========
+
+Django has full support for internationalization of text in code and
+templates, and format localization of dates and numbers. Here's how it works.
+
+Essentially, Django does two things:
+
+    * It allows developers and template authors to 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.
+
+The complete process can be seen as divided in three stages. It is also possible
+to identify an identical number of roles with very well defined responsabilities
+associated with each of these tasks (although it's perfectly normal if you
+find yourself performing more than one of these roles):
+
+    * For applicacion authors wishing to make sure their Django apps can be
+      used in different locales: :ref:`topics-i18n-internationalization`.
+    * For translators wanting to translate Django apps: :ref:`topics-i18n-localization`.
+    * For system administrators/final users setting up internationalized apps or
+      developers integrating third party apps: :ref:`topics-i18n-deployment`.
+
+.. toctree::
+   :hidden:
+   :maxdepth: 1
+
+   internationalization
+   localization
+   deployment
+
+.. _ seealso::
+
+For more general information about the topic, see the `GNU gettext documentation`_
+and the `Wikipedia article`_.
+
+.. _GNU gettext documentation: http://www.gnu.org/software/gettext/manual/gettext.html#Concepts
+.. _Wikipedia article: http://en.wikipedia.org/wiki/Internationalization_and_localization
+
+Glossary
+========
+
+First lets define some terms that will help us to handle a common language:
+
+.. glossary::
+
+    locale name
+      A locale name, either a language specification of the form ``ll`` or a
+      combined language and country specification of the form ``ll_CC``.
+      Examples: ``it``, ``de_AT``, ``es``, ``pt_BR``. Note the underscore in
+      some of them and the case of the part located to its right.
+
+    language code
+      Represents the name of a language. Browsers send the names of the
+      languages they accept in the ``Accept-Language`` HTTP header using this
+      format. Examples: ``it``, ``de-at``, ``es``, ``pt-br``. Note the ``-``
+      separator.
+
+    message file
+      A message file is a plain-text file, representing a single language,
+      that contains all available :term:`translation strings
+      <translation string>` and how they should be represented in the given
+      language. Message files have a ``.po`` file extension.
+
+    translation string
+      A literal that can be translated.
+
+.. _specialties-of-django-i18n:
+
+Specialties of Django translation
+=================================
+
+Django's translation machinery uses the standard ``gettext`` module that comes
+with Python. If you know ``gettext``, you might note these specialties in the
+way Django does translation:
+
+    * The string domain is ``django`` or ``djangojs``. This string domain is
+      used to differentiate between different programs that store their data
+      in a common message-file library (usually ``/usr/share/locale/``). The
+      ``django`` domain is used for python and template translation strings
+      and is loaded into the global translation catalogs. The ``djangojs``
+      domain is only used for JavaScript translation catalogs to make sure
+      that those are as small as possible.
+    * Django doesn't use ``xgettext`` alone. It uses Python wrappers around
+      ``xgettext`` and ``msgfmt``. This is mostly for convenience.
+
+.. _technical-messages:
+
+Django technical message IDs
+----------------------------
+
+.. versionchanged:: 1.2
+    Starting with Django 1.2, technical message IDs are being replaced by :ref:`format-localization`
+
+Django uses technical message IDs to translate date formats and time formats.
+Technical message IDs are :term:`translation strings <translation string>` and
+can be easily recognized; they're all upper case. You don't translate the
+message ID as with other translation strings, you provide the correct local
+variant on the provided English value. The format is identical to the format
+strings used by the ``now`` template tag.
+
+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. A Django
+contributor localizing it to Spanish probably would provide a ``"j N Y P"``
+"translation" for it in the relevant ``django.po`` file::
+
+    msgid "DATETIME_FORMAT"
+    msgstr "j N Y P"

+ 578 - 0
docs/topics/i18n/internationalization.txt

@@ -0,0 +1,578 @@
+.. _topics-i18n-internationalization:
+
+====================
+Internationalization
+====================
+
+Overview
+========
+
+The goal of internationalization is to allow a single Web application to offer
+its content and functionality in multiple languages and locales.
+
+For text translations, you, the Django developer, can accomplish this goal by
+adding a minimal amount of hooks to your Python 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." It's your responsibility to mark translatable
+strings; the system can only translate strings it knows about.
+
+Django takes care of using these hooks to translate Web apps, on the fly,
+according to users' language preferences.
+
+Specifying translation strings: In Python code
+==============================================
+
+Standard translation
+--------------------
+
+Specify a translation string by using the function ``ugettext()``. It's
+convention to import this as a shorter alias, ``_``, to save typing.
+
+.. note::
+    Python's standard library ``gettext`` module installs ``_()`` into the
+    global namespace, as an alias for ``gettext()``. In Django, we have chosen
+    not to follow this practice, for a couple of reasons:
+
+      1. For international character set (Unicode) support, ``ugettext()`` is
+         more useful than ``gettext()``. Sometimes, you should be using
+         ``ugettext_lazy()`` as the default translation method for a particular
+         file. Without ``_()`` in the global namespace, the developer has to
+         think about which is the most appropriate translation function.
+
+      2. The underscore character (``_``) is used to represent "the previous
+         result" in Python's interactive shell and doctest tests. Installing a
+         global ``_()`` function causes interference. Explicitly importing
+         ``ugettext()`` as ``_()`` avoids this problem.
+
+.. highlightlang:: python
+
+In this example, the text ``"Welcome to my site."`` is marked as a translation
+string::
+
+    from django.utils.translation import ugettext as _
+
+    def my_view(request):
+        output = _("Welcome to my site.")
+        return HttpResponse(output)
+
+Obviously, you could code this without using the alias. This example is
+identical to the previous one::
+
+    from django.utils.translation import ugettext
+
+    def my_view(request):
+        output = ugettext("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,
+``django-admin.py makemessages``, won't be able to find these strings. More on
+``makemessages`` later.)
+
+The strings you pass to ``_()`` or ``ugettext()`` can take placeholders,
+specified with Python's standard named-string interpolation syntax. Example::
+
+    def my_view(request, m, d):
+        output = _('Today is %(month)s, %(day)s.') % {'month': m, 'day': d}
+        return HttpResponse(output)
+
+This technique lets language-specific translations reorder the placeholder
+text. For example, an English translation may be ``"Today is November, 26."``,
+while a Spanish translation may be ``"Hoy es 26 de Noviembre."`` -- with the
+placeholders (the month and the day) with their positions swapped.
+
+For this reason, you should use named-string interpolation (e.g., ``%(day)s``)
+instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you
+have more than a single parameter. 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.ugettext_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.
+
+Pluralization
+-------------
+
+Use the function ``django.utils.translation.ungettext()`` to specify pluralized
+messages.
+
+``ungettext`` takes three arguments: the singular translation string, the plural
+translation string and the number of objects.
+
+This function is useful when you need your Django application to be localizable
+to languages where the number and complexity of `plural forms
+<http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is
+greater than the two forms used in English ('object' for the singular and
+'objects' for all the cases where ``count`` is different from zero, irrespective
+of its value.)
+
+For example::
+
+    from django.utils.translation import ungettext
+    def hello_world(request, count):
+        page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % {
+            'count': count,
+        }
+        return HttpResponse(page)
+
+In this example the number of objects is passed to the translation languages as
+the ``count`` variable.
+
+Lets see a slightly more complex usage example::
+
+    from django.utils.translation import ungettext
+
+    count = Report.objects.count()
+    if count == 1:
+        name = Report._meta.verbose_name
+    else:
+        name = Report._meta.verbose_name_plural
+
+    text = ungettext(
+            'There is %(count)d %(name)s available.',
+            'There are %(count)d %(name)s available.',
+            count
+    ) % {
+        'count': count,
+        'name': name
+    }
+
+Here we reuse localizable, hopefully already translated literals (contained in
+the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for
+other parts of the sentence so all of it is consistently based on the
+cardinality of the elements at play.
+
+.. _pluralization-var-notes:
+
+.. note::
+
+    When using this technique, make sure you use a single name for every
+    extrapolated variable included in the literal. In the example above note how
+    we used the ``name`` Python variable in both translation strings. This
+    example would fail::
+
+        from django.utils.translation import ungettext
+        from myapp.models import Report
+
+        count = Report.objects.count()
+        d = {
+            'count': count,
+            'name': Report._meta.verbose_name
+            'plural_name': Report._meta.verbose_name_plural
+        }
+        text = ungettext(
+                'There is %(count)d %(name)s available.',
+                'There are %(count)d %(plural_name)s available.',
+                count
+        ) % d
+
+    You would get a ``a format specification for argument 'name', as in
+    'msgstr[0]', doesn't exist in 'msgid'`` error when running
+    ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at
+    runtime.
+
+.. _lazy-translations:
+
+Lazy translation
+----------------
+
+Use the function ``django.utils.translation.ugettext_lazy()`` to translate
+strings lazily -- when the value is accessed rather than when the
+``ugettext_lazy()`` function is called.
+
+For example, to translate a model's ``help_text``, do the following::
+
+    from django.utils.translation import ugettext_lazy
+
+    class MyThing(models.Model):
+        name = models.CharField(help_text=ugettext_lazy('This is the help text'))
+
+In this example, ``ugettext_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.
+
+The result of a ``ugettext_lazy()`` call can be used wherever you would use a
+unicode string (an object with type ``unicode``) in Python. If you try to use
+it where a bytestring (a ``str`` object) is expected, things will not work as
+expected, since a ``ugettext_lazy()`` object doesn't know how to convert
+itself to a bytestring.  You can't use a unicode string inside a bytestring,
+either, so this is consistent with normal Python behavior. For example::
+
+    # This is fine: putting a unicode proxy into a unicode string.
+    u"Hello %s" % ugettext_lazy("people")
+
+    # This will not work, since you cannot insert a unicode object
+    # into a bytestring (nor can you insert our unicode proxy there)
+    "Hello %s" % ugettext_lazy("people")
+
+If you ever see output that looks like ``"hello
+<django.utils.functional...>"``, you have tried to insert the result of
+``ugettext_lazy()`` into a bytestring. That's a bug in your code.
+
+If you don't like the verbose name ``ugettext_lazy``, you can just alias it as
+``_`` (underscore), like so::
+
+    from django.utils.translation import ugettext_lazy as _
+
+    class MyThing(models.Model):
+        name = models.CharField(help_text=_('This is the help text'))
+
+Always use lazy translations in :ref:`Django models <topics-db-models>`.
+Field names and table names should be marked for translation (otherwise, they
+won't be translated in the admin interface). This means writing explicit
+``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class,
+though, rather than relying on Django's default determination of
+``verbose_name`` and ``verbose_name_plural`` by looking at the model's class
+name::
+
+    from django.utils.translation import ugettext_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')
+
+Working with lazy translation objects
+-------------------------------------
+
+.. highlightlang:: python
+
+Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models
+and utility functions is a common operation. When you're working with these
+objects elsewhere in your code, you should ensure that you don't accidentally
+convert them to strings, because they should be converted as late as possible
+(so that the correct locale is in effect). This necessitates the use of a
+couple of helper functions.
+
+Joining strings: string_concat()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Standard Python string joins (``''.join([...])``) will not work on lists
+containing lazy translation objects. Instead, you can use
+``django.utils.translation.string_concat()``, which creates a lazy object that
+concatenates its contents *and* converts them to strings only when the result
+is included in a string. For example::
+
+    from django.utils.translation import string_concat
+    ...
+    name = ugettext_lazy(u'John Lennon')
+    instrument = ugettext_lazy(u'guitar')
+    result = string_concat([name, ': ', instrument])
+
+In this case, the lazy translations in ``result`` will only be converted to
+strings when ``result`` itself is used in a string (usually at template
+rendering time).
+
+The allow_lazy() decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django offers many utility functions (particularly in ``django.utils``) that
+take a string as their first argument and do something to that string. These
+functions are used by template filters as well as directly in other code.
+
+If you write your own similar functions and deal with translations, you'll
+face the problem of what to do when the first argument is a lazy translation
+object. You don't want to convert it to a string immediately, because you might
+be using this function outside of a view (and hence the current thread's locale
+setting will not be correct).
+
+For cases like this, use the ``django.utils.functional.allow_lazy()``
+decorator. It modifies the function so that *if* it's called with a lazy
+translation as the first argument, the function evaluation is delayed until it
+needs to be converted to a string.
+
+For example::
+
+    from django.utils.functional import allow_lazy
+
+    def fancy_utility_function(s, ...):
+        # Do some conversion on string 's'
+        ...
+    fancy_utility_function = allow_lazy(fancy_utility_function, unicode)
+
+The ``allow_lazy()`` decorator takes, in addition to the function to decorate,
+a number of extra arguments (``*args``) specifying the type(s) that the
+original function can return. Usually, it's enough to include ``unicode`` here
+and ensure that your function returns only Unicode strings.
+
+Using this decorator means you can write your function and assume that the
+input is a proper string, then add support for lazy translation objects at the
+end.
+
+Specifying translation strings: In template code
+================================================
+
+.. highlightlang:: html+django
+
+Translations in :ref:`Django templates <topics-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 either a constant string
+(enclosed in single or double quotes) or variable content::
+
+    <title>{% trans "This is the title." %}</title>
+    <title>{% trans myvar %}</title>
+
+If the ``noop`` option is present, variable lookup still takes place but the
+translation is skipped. This is useful when "stubbing out" content that will
+require translation in the future::
+
+    <title>{% trans "myvar" noop %}</title>
+
+Internally, inline translations use an ``ugettext`` call.
+
+It's not possible to mix a template variable inside a string within ``{% trans
+%}``. If your translations require strings with variables (placeholders), use
+``{% blocktrans %}``::
+
+    {% blocktrans %}This string 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|length as counter %}
+    There is only one {{ name }} object.
+    {% plural %}
+    There are {{ counter }} {{ name }} objects.
+    {% endblocktrans %}
+
+When you use the pluralization feature and bind additional values to local
+variables apart from the counter value that selects the translated literal to be
+used, have in mind that the ``blocktrans`` construct is internally converted
+to an ``ungettext`` call. This means the same :ref:`notes regarding ungettext
+variables <pluralization-var-notes>` apply.
+
+Each ``RequestContext`` has access to three translation-specific variables:
+
+    * ``LANGUAGES`` is a list of tuples in which the first element is the
+      :term:`language code` and the second is the language name (translated into
+      the currently active locale).
+
+    * ``LANGUAGE_CODE`` is the current user's preferred language, as a string.
+      Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`.)
+
+    * ``LANGUAGE_BIDI`` is the current locale'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::
+
+    {% 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.
+
+.. note::
+    In this example, the translation infrastructure will be passed the string
+    ``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The
+    translated string will need to contain the comma so that the filter
+    parsing code knows how to split up the arguments. For example, a German
+    translator might translate the string ``"yes,no"`` as ``"ja,nein"``
+    (keeping the comma intact).
+
+.. _Django templates: ../templates_python/
+
+Specifying translation strings: In JavaScript code
+==================================================
+
+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<packages>\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::
+
+    <script type="text/javascript" src={% url django.views.i18n.javascript_catalog %}"></script>
+
+This uses reverse URL lookup to find the URL of the JavaScript catalog view.
+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 is also an ``ngettext`` interface::
+
+    var object_cnt = 1 // or 0, or 2, or 3, ...
+    s = ngettext('literal for the singular case',
+            'literal for the plural case', object_cnt);
+
+and even a string interpolation function::
+
+    function interpolate(fmt, obj, named);
+
+The interpolation syntax is borrowed from Python, so the ``interpolate``
+function supports both positional and named interpolation:
+
+    * Positional interpolation: ``obj`` contains a JavaScript Array object
+      whose elements values are then sequentially interpolated in their
+      corresponding ``fmt`` placeholders in the same order they appear.
+      For example::
+
+        fmts = ngettext('There is %s object. Remaining: %s',
+                'There are %s objects. Remaining: %s', 11);
+        s = interpolate(fmts, [11, 20]);
+        // s is 'There are 11 objects. Remaining: 20'
+
+    * Named interpolation: This mode is selected by passing the optional
+      boolean ``named`` parameter as true. ``obj`` contains a JavaScript
+      object or associative array. For example::
+
+        d = {
+            count: 10
+            total: 50
+        };
+
+        fmts = ngettext('Total: %(total)s, there is %(count)s object',
+        'there are %(count)s of a total of %(total)s objects', d.count);
+        s = interpolate(fmts, d, true);
+
+You shouldn't go over the top with string interpolation, though: this is still
+JavaScript, so the code has to make 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).
+
+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 ``POST`` method, with a ``language``
+parameter set in request. If session support is enabled, the view
+saves the language choice in the user's session. Otherwise, it saves the
+language choice in a cookie that is by default named ``django_language``.
+(The name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting.)
+
+After setting the language choice, Django redirects the user, following this
+algorithm:
+
+    * Django looks for a ``next`` parameter in the ``POST`` data.
+    * If that doesn't exist, or is empty, Django tries the URL in the
+      ``Referrer`` 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:
+
+.. code-block:: html+django
+
+    <form action="/i18n/setlang/" method="post">
+    <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>

+ 294 - 0
docs/topics/i18n/localization.txt

@@ -0,0 +1,294 @@
+.. _topics-i18n-localization:
+
+============
+Localization
+============
+
+This document covers two localization-related topics: `Creating language
+files`_ and `locale aware date, time and numbers input/output in forms`_
+
+.. _`Creating language files`: how-to-create-language-files_
+.. _`locale aware date, time and numbers input/output in forms`: format-localization_
+
+.. seealso::
+
+    The :ref:`howto-i18n` document included with the Django HOW-TO documents collection.
+
+.. _how-to-create-language-files:
+
+How to create language files
+============================
+
+Once the string literals of an application have been tagged for later
+translation, the translation themselves need to be written (or obtained). Here's
+how that works.
+
+.. _locale-restrictions:
+
+.. 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.
+
+    A good starting point is to copy the Django English ``.po`` file and to
+    translate at least some :term:`translation strings <translation string>`.
+
+Message files
+-------------
+
+The first step is to create a :term:`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, ``django-admin.py makemessages``, that automates the
+creation and upkeep of these files.
+
+.. admonition:: A note to Django veterans
+
+    The old tool ``bin/make-messages.py`` has been moved to the command
+    ``django-admin.py makemessages`` to provide consistency throughout Django.
+
+.. admonition:: Gettext utilities
+
+    The ``makemessages`` command (and ``compilemessages`` discussed later) use
+    commands from the GNU gettext toolset: ``xgetetxt``, ``msgfmt``,
+    ``msgmerge`` and ``msguniq``.
+
+    .. versionchanged:: 1.2
+
+    The minimum version of the ``gettext`` utilities supported is 0.15.
+
+To create or update a message file, run this command::
+
+    django-admin.py makemessages -l de
+
+...where ``de`` is the language code for the message file you want to create.
+The language code, in this case, is in :term:`locale format<locale name>`. For
+example, it's ``pt_BR`` for Brazilian Portuguese and ``de_AT`` for Austrian
+German.
+
+The script should be run from one of two places:
+
+    * The root directory of your Django project.
+    * The root directory of your Django app.
+
+Th script runs over your project source tree or your application source tree and
+pulls out all strings marked for translation. It creates (or updates) a message
+file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de`` example, the
+file will be ``locale/de/LC_MESSAGES/django.po``.
+
+By default ``django-admin.py makemessages`` examines every file that has the
+``.html`` file extension. In case you want to override that default, use the
+``--extension`` or ``-e`` option to specify the file extensions to examine::
+
+    django-admin.py makemessages -l de -e txt
+
+Separate multiple extensions with commas and/or use ``-e`` or ``--extension``
+multiple times::
+
+    django-admin.py makemessages -l de -e html,txt -e xml
+
+When :ref:`creating message files from JavaScript source code
+<creating-message-files-from-js-code>` you need to use the special 'djangojs'
+domain, **not** ``-e js``.
+
+.. admonition:: No gettext?
+
+    If you don't have the ``gettext`` utilities installed, ``django-admin.py
+    makemessages`` will create empty files. If that's the case, either install
+    the ``gettext`` utilities or just copy the English message file
+    (``locale/en/LC_MESSAGES/django.po``) if available and use it as a starting
+    point; it's just an empty translation file.
+
+.. admonition:: Working on Windows?
+
+   If you're using Windows and need to install the GNU gettext utilities so
+   ``django-admin makemessages`` works see :ref:`gettext_on_windows` for more
+   information.
+
+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 ``django-admin.py makemessages`` 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, in the form of a comment line
+      prefixed with ``#`` and located above the ``msgid`` line, 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. Due to the way the ``gettext`` tools
+    work internally and because we want to allow non-ASCII source strings in
+    Django's core and your applications, you **must** use UTF-8 as the encoding
+    for your PO file. This means that everybody will be using the same
+    encoding, which is important when Django processes the PO files.
+
+To reexamine all source code and templates for new translation strings and
+update all message files for **all** languages, run this::
+
+    django-admin.py makemessages -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 ``django-admin.py compilemessages`` 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 ``django-admin.py makemessages``, run ``django-admin.py
+compilemessages`` like this::
+
+   django-admin.py compilemessages
+
+That's it. Your translations are ready for use.
+
+.. admonition:: A note to Django veterans
+
+    The old tool ``bin/compile-messages.py`` has been moved to the command
+    ``django-admin.py compilemessages`` to provide consistency throughout
+    Django.
+
+.. admonition:: Working on Windows?
+
+   If you're using Windows and need to install the GNU gettext utilities so
+   ``django-admin compilemessages`` works see :ref:`gettext_on_windows` for more
+   information.
+
+.. _creating-message-files-from-js-code:
+
+Creating message files from JavaScript source code
+==================================================
+
+You create and update the message files the same way as the other Django message
+files -- with the ``django-admin.py makemessages`` tool. The only difference is
+you need to provide a ``-d djangojs`` parameter, like this::
+
+    django-admin.py makemessages -d djangojs -l de
+
+This would create or update the message file for JavaScript for German.
+After updating message files, just run ``django-admin.py compilemessages``
+the same way as you do with normal Django message files.
+
+.. _gettext_on_windows:
+
+``gettext`` on Windows
+======================
+
+This is only needed for people who either want to extract message IDs or compile
+message files (``.po``). Translation work itself just involves editing existing
+files of this type, but if you want to create your own message files, or want to
+test or compile a changed message file, you will need the ``gettext`` utilities:
+
+    * Download the following zip files from the GNOME servers
+      http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one
+      of its mirrors_
+
+      * ``gettext-runtime-X.zip``
+      * ``gettext-tools-X.zip``
+
+      ``X`` is the version number, we are requiring ``0.15`` or higher.
+
+    * Extract the contents of the ``bin\`` directories in both files to the
+      same folder on your system (i.e. ``C:\Program Files\gettext-utils``)
+
+    * Update the system PATH:
+
+      * ``Control Panel > System > Advanced > Environment Variables``.
+      * In the ``System variables`` list, click ``Path``, click ``Edit``.
+      * Add ``;C:\Program Files\gettext-utils\bin`` at the end of the
+        ``Variable value`` field.
+
+.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS
+
+You may also use ``gettext`` binaries you have obtained elsewhere, so long as
+the ``xgettext --version`` command works properly. Some version 0.14.4 binaries
+have been found to not support this command. Do not attempt to use Django
+translation utilities with a ``gettext`` package if the command ``xgettext
+--version`` entered at a Windows command prompt causes a popup window saying
+"xgettext.exe has generated errors and will be closed by Windows".
+
+.. _format-localization:
+
+Format localization
+===================
+
+Django's formatting system is disabled by default. To enable it, it's necessay
+to set :setting:`USE_L10N = True <USE_L10N>` in your settings file.
+
+When using Django's formatting system, dates and numbers on templates will be
+displayed using the format specified for the current locale. Two users
+accessing the same content, but in different language, will see date and
+number fields formatted in different ways, depending on the format for their
+current locale.
+
+Django will also use localized formats when parsing data in forms. That means
+Django uses different formats for different locales when guessing the format
+used by the user when inputting data on forms. Note that Django uses different
+formats for displaying data, and for parsing it.
+
+Creating custom format files
+----------------------------
+
+Django provides format definitions for many locales, but sometimes you might
+want to create your own, because a format files doesn't exist for your locale,
+or because you want to overwrite some of the values.
+
+To use custom formats, first thing to do, is to specify the path where you'll
+place format files. To do that, just set your :setting:`FORMAT_MODULE_PATH`
+setting to the the path (in the format ``'foo.bar.baz``) where format files
+will exists.
+
+Files are not placed directly in this directory, but in a directory named as
+the locale, and must be named ``formats.py``.
+
+To customize the English formats, a structure like this would be needed::
+
+    mysite/
+        formats/
+            __init__.py
+            en/
+                __init__.py
+                formats.py
+
+where :file:`formats.py` contains custom format definitions. For example::
+
+    THOUSAND_SEPARATOR = ' '
+
+to use a space as a thousand separator, instead of the default for English,
+a comma.

+ 1 - 1
docs/topics/index.txt

@@ -21,7 +21,7 @@ Introductions to all the key parts of Django you'll need to know:
    cache
    conditional-view-processing
    email
-   i18n
+   i18n/index
    pagination
    serialization
    settings