diff --git a/django/core/context_processors.py b/django/core/context_processors.py
index a5f29df..d812ded 100644
a
|
b
|
RequestContext.
|
10 | 10 | from django.conf import settings |
11 | 11 | from django.middleware.csrf import get_token |
12 | 12 | from django.utils.functional import lazy |
| 13 | from django.utils.translation import get_language_names |
13 | 14 | |
14 | 15 | def auth(request): |
15 | 16 | """ |
… |
… |
def debug(request):
|
57 | 58 | return context_extras |
58 | 59 | |
59 | 60 | def i18n(request): |
| 61 | """ Returns context variables helpful for i18n and l10n """ |
60 | 62 | from django.utils import translation |
61 | | |
62 | 63 | context_extras = {} |
63 | | context_extras['LANGUAGES'] = settings.LANGUAGES |
| 64 | context_extras['LANGUAGES'] = get_language_names() |
64 | 65 | context_extras['LANGUAGE_CODE'] = translation.get_language() |
65 | 66 | context_extras['LANGUAGE_BIDI'] = translation.get_language_bidi() |
66 | | |
67 | 67 | return context_extras |
68 | 68 | |
69 | 69 | def media(request): |
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py
index 10ac900..346e413 100644
a
|
b
|
from django.template import TemplateSyntaxError, TokenParser, Library
|
5 | 5 | from django.template import TOKEN_TEXT, TOKEN_VAR |
6 | 6 | from django.utils import translation |
7 | 7 | from django.utils.encoding import force_unicode |
| 8 | from django.utils.translation import get_language_names |
8 | 9 | |
9 | 10 | register = Library() |
10 | 11 | |
… |
… |
class GetAvailableLanguagesNode(Node):
|
14 | 15 | |
15 | 16 | def render(self, context): |
16 | 17 | from django.conf import settings |
17 | | context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES] |
| 18 | context[self.variable] = get_language_names() |
18 | 19 | return '' |
19 | 20 | |
20 | 21 | class GetCurrentLanguageNode(Node): |
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index 6d81726..c64195b 100644
a
|
b
|
__all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext',
|
10 | 10 | 'get_language', 'get_language_bidi', 'get_date_formats', |
11 | 11 | 'get_partial_date_formats', 'check_for_language', 'to_locale', |
12 | 12 | 'get_language_from_request', 'templatize', 'ugettext', 'ugettext_lazy', |
13 | | 'ungettext', 'deactivate_all'] |
| 13 | 'ungettext', 'deactivate_all', 'get_language_names'] |
14 | 14 | |
15 | 15 | # Here be dragons, so a short explanation of the logic won't hurt: |
16 | 16 | # We are trying to solve two problems: (1) access settings, in particular |
… |
… |
def templatize(src):
|
95 | 95 | def deactivate_all(): |
96 | 96 | return real_deactivate_all() |
97 | 97 | |
| 98 | def get_language_names(): |
| 99 | return real_get_language_names() |
| 100 | |
98 | 101 | def _string_concat(*strings): |
99 | 102 | """ |
100 | 103 | Lazy variant of string concatenation, needed for translations that are |
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index b528f8e..4fdd775 100644
a
|
b
|
_active = {}
|
20 | 20 | # The default translation is based on the settings file. |
21 | 21 | _default = None |
22 | 22 | |
| 23 | # The translation of LANGUAGES is cached |
| 24 | _language_names = False |
| 25 | |
23 | 26 | # This is a cache for normalized accept-header languages to prevent multiple |
24 | 27 | # file lookups when checking the same locale on repeated requests. |
25 | 28 | _accepted = {} |
… |
… |
def get_partial_date_formats():
|
547 | 550 | month_day_format = settings.MONTH_DAY_FORMAT |
548 | 551 | return year_month_format, month_day_format |
549 | 552 | |
| 553 | def get_language_names(): |
| 554 | """ |
| 555 | Returns an array of language names where each language translated |
| 556 | to its native language. |
| 557 | """ |
| 558 | from django.conf import settings |
| 559 | global _language_names |
| 560 | if _language_names: |
| 561 | return _language_names |
| 562 | else: |
| 563 | languages = [] |
| 564 | current_language = get_language() |
| 565 | for lang, english_name in settings.LANGUAGES: |
| 566 | activate(lang) |
| 567 | languages.append((lang, ugettext(english_name))) |
| 568 | _language_names = languages |
| 569 | if current_language != get_language(): |
| 570 | activate(current_language) |
| 571 | ''' |
| 572 | deactivate() |
| 573 | for lang, english_name in settings.LANGUAGES: |
| 574 | activate(lang) |
| 575 | languages.append((lang, ugettext(english_name))) |
| 576 | deactivate() |
| 577 | _language_names = languages |
| 578 | ''' |
| 579 | return languages |
diff --git a/docs/topics/i18n/deployment.txt b/docs/topics/i18n/deployment.txt
index 1a4f5fa..f2bf15a 100644
a
|
b
|
Notes:
|
116 | 116 | set ``LANGUAGES`` to a list of languages. For example:: |
117 | 117 | |
118 | 118 | LANGUAGES = ( |
119 | | ('de', _('German')), |
120 | | ('en', _('English')), |
| 119 | ('de', 'German'), |
| 120 | ('en', 'English'), |
121 | 121 | ) |
122 | 122 | |
123 | 123 | This example restricts languages that are available for automatic |
124 | 124 | selection to German and English (and any sublanguage, like de-ch or |
125 | 125 | en-us). |
126 | 126 | |
127 | | * If you define a custom ``LANGUAGES`` setting, as explained in the |
128 | | previous bullet, it's OK to mark the languages as translation strings |
129 | | -- but use a "dummy" ``ugettext()`` function, not the one in |
130 | | ``django.utils.translation``. You should *never* import |
131 | | ``django.utils.translation`` from within your settings file, because that |
132 | | module in itself depends on the settings, and that would cause a circular |
133 | | import. |
134 | | |
135 | | The solution is to use a "dummy" ``ugettext()`` function. Here's a sample |
136 | | settings file:: |
137 | | |
138 | | ugettext = lambda s: s |
139 | | |
140 | | LANGUAGES = ( |
141 | | ('de', ugettext('German')), |
142 | | ('en', ugettext('English')), |
143 | | ) |
144 | | |
145 | | With this arrangement, ``django-admin.py makemessages`` will still find |
146 | | and mark these strings for translation, but the translation won't happen |
147 | | at runtime -- so you'll have to remember to wrap the languages in the |
148 | | *real* ``ugettext()`` in any code that uses ``LANGUAGES`` at runtime. |
149 | | |
150 | 127 | * The ``LocaleMiddleware`` can only select languages for which there is a |
151 | 128 | Django-provided base translation. If you want to provide translations |
152 | 129 | for your application that aren't already in the set of translations |
diff --git a/docs/topics/i18n/internationalization.txt b/docs/topics/i18n/internationalization.txt
index 7ae8d18..b604df7 100644
a
|
b
|
Other tags
|
429 | 429 | Each ``RequestContext`` has access to three translation-specific variables: |
430 | 430 | |
431 | 431 | * ``LANGUAGES`` is a list of tuples in which the first element is the |
432 | | :term:`language code` and the second is the language name (translated into |
433 | | the currently active locale). |
| 432 | :term:`language code` and the second is the language name in English |
| 433 | (magically translated into its native language). |
434 | 434 | |
435 | 435 | * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. |
436 | 436 | Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`.) |
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 5902e8d..6b37277 100644
a
|
b
|
class Templates(unittest.TestCase):
|
391 | 391 | output = self.render(test_template, vals) |
392 | 392 | end = datetime.now() |
393 | 393 | if end-start > timedelta(seconds=0.2): |
394 | | failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Took too long to render test" % (is_cached, invalid_str, name)) |
| 394 | # give it another try allowing caching to spee things up |
| 395 | start = datetime.now() |
| 396 | output = self.render(test_template, vals) |
| 397 | end = datetime.now() |
| 398 | if end-start > timedelta(seconds=0.2): |
| 399 | failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Took too long to render test" % (is_cached, invalid_str, name)) |
395 | 400 | except ContextStackException: |
396 | 401 | failures.append("Template test (Cached='%s', TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Context stack was left imbalanced" % (is_cached, invalid_str, name)) |
397 | 402 | continue |
… |
… |
class Templates(unittest.TestCase):
|
1082 | 1087 | 'i18n11': ('{{ bool|yesno:"ja,nein" }}', {'bool': True}, 'ja'), |
1083 | 1088 | |
1084 | 1089 | # usage of the get_available_languages tag |
1085 | | 'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.0 }}{% endifequal %}{% endfor %}', {}, 'de'), |
| 1090 | 'i18n12': ('{% load i18n %}{% get_available_languages as langs %}{% for lang in langs %}{% ifequal lang.0 "de" %}{{ lang.1 }}{% endifequal %}{% endfor %}', {}, u'Deutsch'), |
1086 | 1091 | |
1087 | 1092 | # translation of constant strings |
1088 | 1093 | 'i18n13': ('{{ _("Password") }}', {'LANGUAGE_CODE': 'de'}, 'Passwort'), |