Ticket #14924: 14924.2.diff
File 14924.2.diff, 20.5 KB (added by , 14 years ago) |
---|
-
django/utils/translation/__init__.py
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
a b 1 1 """ 2 2 Internationalization support. 3 3 """ 4 import os.path 5 4 6 from django.utils.encoding import force_unicode 5 from django.utils.functional import lazy, curry 7 from django.utils.functional import lazy 8 from django.utils.importlib import import_module 6 9 7 10 8 11 __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext', … … 33 36 performance effect, as access to the function goes the normal path, 34 37 instead of using __getattr__. 35 38 """ 39 cnt = 0 40 36 41 def __getattr__(self, real_name): 37 42 from django.conf import settings 38 43 if settings.USE_I18N: 39 44 from django.utils.translation import trans_real as trans 45 46 if not self.cnt: 47 self.cnt += 1 48 if settings.SETTINGS_MODULE is not None: 49 import warnings 50 parts = settings.SETTINGS_MODULE.split('.') 51 project = import_module(parts[0]) 52 if os.path.isdir(os.path.join(os.path.dirname(project.__file__), 'locale')): 53 warnings.warn( 54 "Translations in the project directory aren't supported anymore. Use LOCALE_PATHS settings instead.", 55 PendingDeprecationWarning 56 ) 57 40 58 else: 41 59 from django.utils.translation import trans_null as trans 42 60 setattr(self, real_name, getattr(trans, real_name)) -
django/utils/translation/trans_real.py
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
a b 125 125 126 126 global _translations 127 127 128 loc = to_locale(lang)129 130 128 res = _translations.get(lang, None) 131 129 if res is not None: 132 130 return res 133 131 132 loc = to_locale(lang) 133 134 134 def _translation(path): 135 135 try: 136 136 t = gettext_module.translation('django', path, [loc], DjangoTranslation) … … 159 159 res.merge(t) 160 160 return res 161 161 162 for localepath in settings.LOCALE_PATHS: 163 if os.path.isdir(localepath): 164 res = _merge(localepath) 165 166 for appname in settings.INSTALLED_APPS: 162 for appname in reversed(settings.INSTALLED_APPS): 167 163 app = import_module(appname) 168 164 apppath = os.path.join(os.path.dirname(app.__file__), 'locale') 169 165 … … 173 169 if projectpath and os.path.isdir(projectpath): 174 170 res = _merge(projectpath) 175 171 172 for localepath in reversed(settings.LOCALE_PATHS): 173 if os.path.isdir(localepath): 174 res = _merge(localepath) 175 176 176 if res is None: 177 177 if fallback is not None: 178 178 res = fallback -
django/views/i18n.py
diff --git a/django/views/i18n.py b/django/views/i18n.py
a b 196 196 paths = [] 197 197 en_selected = locale.startswith('en') 198 198 en_catalog_missing = True 199 # first load all english languages files for defaults199 # paths of requested packages 200 200 for package in packages: 201 201 p = importlib.import_module(package) 202 202 path = os.path.join(os.path.dirname(p.__file__), 'locale') 203 203 paths.append(path) 204 # add the filesystem paths listed in the LOCALE_PATHS setting 205 paths.extend(list(reversed(settings.LOCALE_PATHS))) 206 # first load all english languages files for defaults 207 for path in paths: 204 208 try: 205 209 catalog = gettext_module.translation(domain, path, ['en']) 206 210 t.update(catalog._catalog) … … 278 282 src.append(LibFormatFoot) 279 283 src = ''.join(src) 280 284 return http.HttpResponse(src, 'text/javascript') 281 -
docs/howto/i18n.txt
diff --git a/docs/howto/i18n.txt b/docs/howto/i18n.txt
a b 4 4 Using internationalization in your own projects 5 5 =============================================== 6 6 7 At runtime, Django looks for translations by following this algorithm: 7 At runtime, Django builds a in-memory unified catalog of literals-translations. 8 To achieve this it looks for translations by following this algorithm regarding 9 the order in which it examines the different file paths to load the compiled 10 :term:`message files <message file>` (``.mo``) and the precedence of multiple 11 translations for the same literal: 8 12 9 * First, it looks for a ``locale`` directory in the directory containing 10 your settings file. 11 * Second, it looks for a ``locale`` directory in the project directory. 12 * Third, it looks for a ``locale`` directory in each of the installed apps. 13 It does this in the reverse order of INSTALLED_APPS 14 * Finally, it checks the Django-provided base translation in 15 ``django/conf/locale``. 13 1. The directories listed in :setting:`LOCALE_PATHS` have the highest 14 precedence, with the ones appearing first having higher precedence than 15 the ones appearing later. 16 2. Then, it looks for and uses if it exists a ``locale`` directory in each 17 of the installed apps listed in :setting:`INSTALLED_APPS`. 18 The ones appearing first have higher precedence than the ones appearing 19 later. 20 3. Then, it looks for a ``locale`` directory in the project directory, or 21 more accurately, in the directory containing your settings file. 22 4. Finally, the Django-provided base translation in ``django/conf/locale`` 23 is used as a fallback. 24 25 .. deprecated:: 1.3 26 Lookup in the ``locale`` subdirectory of the directory containing your 27 settings file (item 3 above) is deprecated since the 1.3 release and will be 28 removed in 1.5. You can use the :setting:`LOCALE_PATHS` setting instead, by 29 including the full filesystem path of the same location. 30 31 .. seealso:: 32 33 The translations for literals included in JavaScript assets are looked up 34 following not a quite equivalent but a similar algorithm. See the 35 :ref:`javascript_catalog view documentation <javascript_catalog-view>` for 36 more details. 16 37 17 38 In all cases the name of the directory containing the translation is expected to 18 39 be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``, … … 37 58 * ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` 38 59 * ``$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` 39 60 * All paths listed in ``LOCALE_PATHS`` in your settings file are 40 searched in that orderfor ``<language>/LC_MESSAGES/django.(po|mo)``61 searched for ``<language>/LC_MESSAGES/django.(po|mo)`` 41 62 * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)`` 42 63 43 64 To create message files, you use the :djadmin:`django-admin.py makemessages <makemessages>` … … 50 71 to make the compiler process all the directories in your :setting:`LOCALE_PATHS` 51 72 setting. 52 73 53 Application message files are a bit complicated to discover -- they need the54 :class:`~django.middleware.locale.LocaleMiddleware`. If you don't use the55 middleware, only the Django message files and project message files will be56 installed and available at runtime.57 58 74 Finally, you should give some thought to the structure of your translation 59 75 files. If your applications need to be delivered to other users and will 60 76 be used in other projects, you might want to use app-specific translations. -
docs/topics/i18n/deployment.txt
diff --git a/docs/topics/i18n/deployment.txt b/docs/topics/i18n/deployment.txt
a b 171 171 How Django discovers translations 172 172 --------------------------------- 173 173 174 As described in :ref:`using-translations-in-your-own-projects`, 175 at runtime, Django looks for translations by following this algorithm: 174 As described in :ref:`using-translations-in-your-own-projects`, Django looks for 175 translations by following this algorithm regarding the order in which it 176 examines the different file paths to load the compiled :term:`message files 177 <message file>` (``.mo``) and the precedence of multiple translations for the 178 same literal: 176 179 177 * First, it looks for a ``locale`` directory in the directory containing 178 your settings file. 179 * Second, it looks for a ``locale`` directory in the project directory. 180 * Third, it looks for a ``locale`` directory in each of the installed apps. 181 It does this in the reverse order of INSTALLED_APPS 182 * Finally, it checks the Django-provided base translation in 183 ``django/conf/locale``. 180 1. The directories listed in :setting:`LOCALE_PATHS` have the highest 181 precedence, with the ones appearing first having higher precedence than 182 the ones appearing later. 183 2. Then, it looks for and uses if it exists a ``locale`` directory in each 184 of the installed apps listed in :setting:`INSTALLED_APPS`. 185 The ones appearing first have higher precedence than the ones appearing 186 later. 187 3. Then, it looks for a ``locale`` directory in the project directory, or 188 more accurately, in the directory containing your settings file. 189 4. Finally, the Django-provided base translation in ``django/conf/locale`` 190 is used as a fallback. 191 192 .. deprecated:: 1.3 193 Lookup in the ``locale`` subdirectory of the directory containing your 194 settings file (item 3 above) is deprecated since the 1.3 release and will be 195 removed in 1.5. You can use the :setting:`LOCALE_PATHS` setting instead, by 196 including the full filesystem path of the same location. 197 198 .. seealso:: 199 200 The translations for literals included in JavaScript assets are looked up 201 following not a quite equivalent but a similar algorithm. See the 202 :ref:`javascript_catalog view documentation <javascript_catalog-view>` for 203 more details. 184 204 185 205 In all cases the name of the directory containing the translation is expected to 186 206 be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``, -
docs/topics/i18n/internationalization.txt
diff --git a/docs/topics/i18n/internationalization.txt b/docs/topics/i18n/internationalization.txt
a b 647 647 translations into JavaScript, so you can call ``gettext``, etc., from within 648 648 JavaScript. 649 649 650 .. _javascript_catalog-view: 651 650 652 The ``javascript_catalog`` view 651 653 ------------------------------- 652 654 … … 657 659 The main solution to these problems is the :meth:`django.views.i18n.javascript_catalog` 658 660 view, which sends out a JavaScript code library with functions that mimic the 659 661 ``gettext`` interface, plus an array of translation strings. Those translation 660 strings are taken from the application, project or Django core, according to what 661 you specify in either the info_dict or the URL. 662 strings are taken from the application, paths listed in :setting:`LOCALE_PATHS` 663 or Django core, according to what you specify in either the info_dict or the 664 URL. 662 665 663 666 You hook it up like this:: 664 667 … … 691 694 catalog file. As a security measure, these values can only be either 692 695 ``django.conf`` or any package from the :setting:`INSTALLED_APPS` setting. 693 696 697 The JavaScript translations found in the paths listed in the 698 :setting:`LOCALE_PATHS` setting are also always included (provided they have a 699 ``locale`` subdirectory). 700 701 To keep consistency with the translations lookup order algorithm used for Python 702 and templates, the directories listed in :setting:`LOCALE_PATHS` have the 703 highest precedence with the ones appearing first having higher precedence than 704 the ones appearing later. But Django core and :setting:`INSTALLED_APPS` 705 translations should be explicitly listed in the *packages* parameter. 706 694 707 Using the JavaScript translation catalog 695 708 ---------------------------------------- 696 709 -
tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo
diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.mo index 6db1cb1a8ccf488dc7336d0fd707f6693a873a26..241de05ddb04199df4a515d720dc9ea263a06ca7 GIT binary patch literal 668 zc${sK!EVz)5QewGAZjEIZ~@W7a6oE>HnAO~R&G<Zgj5t9H426UmueeNoQ>?=Xm?#v zgm??YE5MlxZ@^n{;mSiWb|Ok8M*95ESpTfYJ3sGupBTjrVuMJCTf_&pj4#AG@s;q1 zZ^UilJMn<{LEI#M5vOa6{U*I%pVMOOF6or?8tHq|d!!#*%X2=HuCc4pTB*0v>#Moy ze)dc_>^NB>OY29em79SQC3-_~!7K_hnR$;gFlej7vA>yR=V;Cv)5z#KP8>hZ_!~4< zY868^7b@4_&^qgnaiNXlLz~NtKdo}hQyqgpI!Sropm5Z|>p5bGf-vAg#KR{LZpYp3 zW2yr(@-d!Ed&L*>AmmX9Q5bi(dC(<aBCO-75y}?AX%oW>p_H_cpv<s<y?Ij}6iwNd zYO43CN9C2sk*6q1nj2v+!-GP$waNGW;qh>A`BPy#@cVQ@sOU2n3!1~>JJ(qhLaJSu z%!IM%dau(XzH{lT$C;wx12xf^RCx?LXVUqjqB5f3N7|G&2DNBP+lzK#nf5jnJnTWZ t<<~2!%FbJq4mOjM{$VmW9UZ36Uv07fy&DQyZ)x0YNw|M=WH0Fk*dL85s@MPk
-
tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
diff --git a/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po
a b 8 8 "Project-Id-Version: django tests\n" 9 9 "Report-Msgid-Bugs-To: \n" 10 10 "POT-Creation-Date: 2010-02-14 17:33+0100\n" 11 "PO-Revision-Date: 2011-01- 16 17:14+0100\n"11 "PO-Revision-Date: 2011-01-21 21:37-0300\n" 12 12 "Last-Translator: Jannis Leidel <jannis@leidel.info>\n" 13 13 "Language-Team: de <de@li.org>\n" 14 14 "MIME-Version: 1.0\n" … … 18 18 19 19 #: models.py:3 20 20 msgid "Time" 21 msgstr " Time(LOCALE_PATHS)"21 msgstr "Zeit (LOCALE_PATHS)" 22 22 23 23 #: models.py:5 24 msgid "Date/time" 25 msgstr "Datum/Zeit (LOCALE_PATHS)" 26 27 #: models.py:7 24 28 msgctxt "month name" 25 29 msgid "May" 26 30 msgstr "Mai" 27 31 28 #: models.py: 732 #: models.py:9 29 33 msgctxt "verb" 30 34 msgid "May" 31 35 msgstr "Kann" 32 36 33 #: models.py: 937 #: models.py:11 34 38 msgctxt "search" 35 39 msgid "%d result" 36 40 msgid_plural "%d results" 37 41 msgstr[0] "%d Resultat" 38 42 msgstr[1] "%d Resultate" 39 -
tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.mo
diff --git a/tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.mo index 1c37ac5c87e9392a742ea3db6149b902c9667bd9..4d4f202be2e13a07a07dcb894e04f35e03092c91 GIT binary patch literal 492 zc$`&`!A=`75Qg2B9=fNh=N_gv5E`=HAb|`)EXf8%?1ojc;m}L#Chpd-u~)W(;6eIc zeF7xjgxPXPJM!n5k$#VV`{~opZ$|Ns_)HuU?}?nf#&_ZaA&DL0j`;S5v6k{j;t$mk z<!8#Y*ju)ZZYCSapn5^C6|1_fboN#)15Q?Wqny{)2q@FxReG7hO*WfPuBXvVwblhJ ze63e_v8g>)RzOr<S2%P^20Db@SOH1QV~i8zhro|SzrRm?OhTNgd+q<zaf~@891<@2 zM;P}>mrEb8a?<!l2I~Zj7kLiTw8-EzE7D1Ro{mPdY(76Dsi`-zR#+*y7LcdY%SC7T zG|$f)ePCUE78R2s+dhgP#L>{2pbXvd*pi8$9zw5eq&6q8{3V@NVX&yic)ZnhUVbWv znOWMEHno7`A38*3vvIP)v2|-Nz_fo`KS)mCwH)jk_%Z;#7j@sgS@*sw9bh*t%RTl_ F`2u-se*XXf
-
tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.po
diff --git a/tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/i18n/resolution/locale/de/LC_MESSAGES/django.po
a b 9 9 "Project-Id-Version: PACKAGE VERSION\n" 10 10 "Report-Msgid-Bugs-To: \n" 11 11 "POT-Creation-Date: 2010-02-14 17:33+0100\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12 "PO-Revision-Date: 2011-01-21 21:37-0300\n" 13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 14 "Language-Team: LANGUAGE <LL@li.org>\n" 15 15 "MIME-Version: 1.0\n" … … 18 18 "Plural-Forms: nplurals=2; plural=(n != 1)\n" 19 19 20 20 #: models.py:3 21 msgid "Time" 22 msgstr "Zeit (APP)" 23 24 #: models.py:5 21 25 msgid "Date/time" 22 26 msgstr "Datum/Zeit (APP)" -
tests/regressiontests/i18n/tests.py
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
a b 660 660 661 661 def assertUgettext(self, msgid, msgstr): 662 662 result = ugettext(msgid) 663 self.assert _(msgstr in result, ("The string '%s' isn't in the "663 self.assertTrue(msgstr in result, ("The string '%s' isn't in the " 664 664 "translation of '%s'; the actual result is '%s'." % (msgstr, msgid, result))) 665 665 666 666 class AppResolutionOrderI18NTests(ResolutionOrderI18NTests): 667 667 668 668 def setUp(self): 669 669 self.old_installed_apps = settings.INSTALLED_APPS 670 settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) + ['regressiontests.i18n.resolution']670 settings.INSTALLED_APPS = ['regressiontests.i18n.resolution'] + list(settings.INSTALLED_APPS) 671 671 super(AppResolutionOrderI18NTests, self).setUp() 672 672 673 673 def tearDown(self): … … 691 691 def test_locale_paths_translation(self): 692 692 self.assertUgettext('Time', 'LOCALE_PATHS') 693 693 694 def test_locale_paths_override_app_translation(self): 695 old_installed_apps = settings.INSTALLED_APPS 696 settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) + ['regressiontests.i18n.resolution'] 697 try: 698 self.assertUgettext('Time', 'LOCALE_PATHS') 699 finally: 700 settings.INSTALLED_APPS = old_installed_apps 701 702 def test_locale_paths_override_project_translation(self): 703 old_settings_module = settings.SETTINGS_MODULE 704 settings.SETTINGS_MODULE = 'regressiontests' 705 try: 706 self.assertUgettext('Date/time', 'LOCALE_PATHS') 707 finally: 708 settings.SETTINGS_MODULE = old_settings_module 709 694 710 class ProjectResolutionOrderI18NTests(ResolutionOrderI18NTests): 695 711 696 712 def setUp(self): … … 708 724 def test_project_override_app_translation(self): 709 725 old_installed_apps = settings.INSTALLED_APPS 710 726 settings.INSTALLED_APPS = list(settings.INSTALLED_APPS) + ['regressiontests.i18n.resolution'] 711 self.assertUgettext('Date/time', 'PROJECT') 712 settings.INSTALLED_APPS = old_installed_apps 713 714 def test_project_override_locale_paths_translation(self): 715 old_locale_paths = settings.LOCALE_PATHS 716 settings.LOCALE_PATHS += (os.path.join(os.path.dirname(os.path.abspath(__file__)), 'other', 'locale'),) 717 self.assertUgettext('Date/time', 'PROJECT') 718 settings.LOCALE_PATHS = old_locale_paths 727 try: 728 self.assertUgettext('Date/time', 'PROJECT') 729 finally: 730 settings.INSTALLED_APPS = old_installed_apps 719 731 720 732 class DjangoFallbackResolutionOrderI18NTests(ResolutionOrderI18NTests): 721 733 722 734 def test_django_fallback(self): 723 self.assert Ugettext('Date/time', 'Datum/Zeit')735 self.assertEqual(ugettext('Date/time'), 'Datum/Zeit') 724 736 725 737 726 738 class TestModels(TestCase): -
tests/regressiontests/locale/de/LC_MESSAGES/django.mo
diff --git a/tests/regressiontests/locale/de/LC_MESSAGES/django.mo b/tests/regressiontests/locale/de/LC_MESSAGES/django.mo index 2ee860a80b5e75cd9f5fe727c02f74936918dc9c..81616ca7bdabe07ebff028d2480f6cada79b65f3 GIT binary patch literal 500 zc${63!EO^V5QYtu1AE|rIC2<nt<W^<O{G?DQ*}u;RbV$+Z8kk{0h5@mVPmgsrz#J^ zd+`L^cn@ajA%c-V&y4hY{M)}?9Q<GuPl#8<3GtN3*+YCHo)MBbAifbFA2HTZeo6eK z`Z?v_lxeZYY#;qhHjzOMg5D}t_gm@gSG5i}+u)6IURxueOvmrj>kMwPYB^iXqe^ww z1uT4{H~4nfc&x2}s9e-Ic1i|1g#B0nNz7x66XYkrPsMQfhWeO<SgAYh|Iu-bIVKzu zE{3NV4@s9xAFy`P_*Mq%1WZ?X4)e6g;36y1S$>sHCRMgvUXs)_JJ~3#mD~!*)A{wP zw|tT3SFJv_uDOhgS&{7@#gF4?Y)w#x?)cu3iJ<PoplhWz=diw&&Z{t5)l)p%>v}I= zl*7!d?M9nMz}aUVqO#pN+2Yi?truXrzpWo7=kQRD4h_5>0Y8fR@7`?(ACwMoSXPU7 L*|<Jp|FwSrmUDr3
-
tests/regressiontests/locale/de/LC_MESSAGES/django.po
diff --git a/tests/regressiontests/locale/de/LC_MESSAGES/django.po b/tests/regressiontests/locale/de/LC_MESSAGES/django.po
a b 9 9 "Project-Id-Version: PACKAGE VERSION\n" 10 10 "Report-Msgid-Bugs-To: \n" 11 11 "POT-Creation-Date: 2010-02-14 17:33+0100\n" 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12 "PO-Revision-Date: 2011-01-21 21:37-0300\n" 13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 14 "Language-Team: LANGUAGE <LL@li.org>\n" 15 15 "MIME-Version: 1.0\n" … … 18 18 "Plural-Forms: nplurals=2; plural=(n != 1)\n" 19 19 20 20 #: models.py:3 21 msgid "Time" 22 msgstr "Zeit (PROJECT)" 23 24 #: models.py:5 21 25 msgid "Date/time" 22 26 msgstr "Datum/Zeit (PROJECT)" -
tests/regressiontests/views/tests/i18n.py
diff --git a/tests/regressiontests/views/tests/i18n.py b/tests/regressiontests/views/tests/i18n.py
a b 1 1 # -*- coding:utf-8 -*- 2 2 import gettext 3 import os 3 4 4 5 from django.conf import settings 5 6 from django.test import TestCase … … 150 151 response = self.client.get('/views/jsi18n_multi_packages2/') 151 152 self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido')) 152 153 deactivate() 154 155 def testI18NWithLocalePaths(self): 156 settings.LANGUAGE_CODE = 'es-ar' 157 self.old_locale_paths = settings.LOCALE_PATHS 158 settings.LOCALE_PATHS += (os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'app3', 'locale'),) 159 response = self.client.get('/views/jsi18n/') 160 self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido')) 161 settings.LOCALE_PATHS = self.old_locale_paths