From dd1ca50b096bf0351819aabc862e91a9797ddaca Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 28 May 2020 10:26:41 +0200 Subject: [PATCH] Fixed #31570 -- Corrected translation loading for apps providing territorial language variants with different plural equations. Regression in e3e48b00127c09eafe6439d980a82fc5c591b673. Thanks to Shai Berger for report, reproduce and suggested fix. --- django/utils/translation/trans_real.py | 2 +- docs/releases/2.2.13.txt | 7 ++- docs/releases/3.0.7.txt | 5 ++ tests/i18n/loading/en/LC_MESSAGES/django.mo | Bin 0 -> 446 bytes tests/i18n/loading/en/LC_MESSAGES/django.po | 23 +++++++++ .../i18n/loading/en_AU/LC_MESSAGES/django.mo | Bin 0 -> 432 bytes .../i18n/loading/en_AU/LC_MESSAGES/django.po | 23 +++++++++ .../i18n/loading/en_CA/LC_MESSAGES/django.mo | Bin 0 -> 389 bytes .../i18n/loading/en_CA/LC_MESSAGES/django.po | 22 +++++++++ .../i18n/loading/en_NZ/LC_MESSAGES/django.mo | Bin 0 -> 387 bytes .../i18n/loading/en_NZ/LC_MESSAGES/django.po | 22 +++++++++ tests/i18n/loading_app/__init__.py | 0 tests/i18n/loading_app/apps.py | 5 ++ .../locale/en/LC_MESSAGES/django.mo | Bin 0 -> 380 bytes .../locale/en/LC_MESSAGES/django.po | 25 ++++++++++ tests/i18n/tests.py | 45 ++++++++++++++++++ 16 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 tests/i18n/loading/en/LC_MESSAGES/django.mo create mode 100644 tests/i18n/loading/en/LC_MESSAGES/django.po create mode 100644 tests/i18n/loading/en_AU/LC_MESSAGES/django.mo create mode 100644 tests/i18n/loading/en_AU/LC_MESSAGES/django.po create mode 100644 tests/i18n/loading/en_CA/LC_MESSAGES/django.mo create mode 100644 tests/i18n/loading/en_CA/LC_MESSAGES/django.po create mode 100644 tests/i18n/loading/en_NZ/LC_MESSAGES/django.mo create mode 100644 tests/i18n/loading/en_NZ/LC_MESSAGES/django.po create mode 100644 tests/i18n/loading_app/__init__.py create mode 100644 tests/i18n/loading_app/apps.py create mode 100644 tests/i18n/loading_app/locale/en/LC_MESSAGES/django.mo create mode 100644 tests/i18n/loading_app/locale/en/LC_MESSAGES/django.po diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index eed4705f6e..8042f6fdc4 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -96,7 +96,7 @@ class TranslationCatalog: cat.update(trans._catalog) break else: - self._catalogs.insert(0, trans._catalog) + self._catalogs.insert(0, trans._catalog.copy()) self._plurals.insert(0, trans.plural) def get(self, key, default=None): diff --git a/docs/releases/2.2.13.txt b/docs/releases/2.2.13.txt index 450f7acdbf..cc0739e646 100644 --- a/docs/releases/2.2.13.txt +++ b/docs/releases/2.2.13.txt @@ -4,9 +4,12 @@ Django 2.2.13 release notes *Expected June 3, 2020* -Django 2.2.13 fixes two security issues and a bug in 2.2.12. +Django 2.2.13 fixes two security issues and a regression in 2.2.12. Bugfixes ======== -* ... +* Fixed a regression in Django 2.2.12 that affected translation loading for + apps providing translations for territorial language variants as well as a + generic language, where the project has different plural equations for the + language (:ticket:`31570`). diff --git a/docs/releases/3.0.7.txt b/docs/releases/3.0.7.txt index c7bc3730fd..b38a8d8059 100644 --- a/docs/releases/3.0.7.txt +++ b/docs/releases/3.0.7.txt @@ -25,3 +25,8 @@ Bugfixes * Fixed a regression in Django 3.0 where all resolved ``Subquery()`` expressions were considered equal (:ticket:`31607`). + +* Fixed a regression in Django 3.0.5 that affected translation loading for apps + providing translations for territorial language variants as well as a generic + language, where the project has different plural equations for the language + (:ticket:`31570`). diff --git a/tests/i18n/loading/en/LC_MESSAGES/django.mo b/tests/i18n/loading/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f666550adb782b6455e855ebbf14df0c04b8a750 GIT binary patch literal 446 zcmZvYO-{ow5QPJRO_qoyi(v->7s{$i8`PAzB_e;MX(ia1)D1zY9XSr72jLK0inA~& zNZIh@Pcvh^k)Qm1bnt1Q_K_3h5;;UhNUIn*MjnyLo?)#2<}d8=?Dnv9DrLq>$Ydk5 z+Cs%uErk&)`NlI%ycJpEO(BH^v2*v}%qT2rGWVj;On4=gCPAGSD>7;FnxxVKGmc2Y z--~vKxJ+{ko~V72UWLhcY0~!32R9&@OhrcWvHDp}D~4wiV{l{6k+= zB`d@bvR9^RuI)uSC4, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-13 08:42+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: trans/tests.py:16 +msgid "local country person" +msgstr "local country person" diff --git a/tests/i18n/loading/en_AU/LC_MESSAGES/django.mo b/tests/i18n/loading/en_AU/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..98b016bc6c35870cdf4ed86e2bb538fc89dc00c5 GIT binary patch literal 432 zcmYL@O-{ow5QPH*7Fi;eEQTEjTqvt5ZBWzJEfGl*(jN(SCUt{RYDcz%=s`FHm*Ol; z%OX$nX~xzY&HFt)`gTx<$T@O@93wqsrxZCuo{_, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-13 08:42+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: trans/tests.py:16 +msgid "local country person" +msgstr "aussie" diff --git a/tests/i18n/loading/en_CA/LC_MESSAGES/django.mo b/tests/i18n/loading/en_CA/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4d6da00f6539ee98e89d50081e8141ca436a3778 GIT binary patch literal 389 zcmYL@u};G<6h#99hKvY_g~2?EXVCD@GXhCr|*$3b-AFZeyag%_4w z`RG~Jee(G|-1`Y2yTA!>2J8b9pic%I0gu4(P7rKh9su8Phx5M&V@Pe4tdX*v@otM6 z?OJPs%-J`sJdW3R1uvB~1ZDK@fzBCPv3wDyNto-#I*&zLR%?9Ql`SqTL1C8STz^*m z4vwVP1U)gDW0B&BqWhGH`1CnVSjc7Tap9zCYw4{cXtv}WB~&mpVS>hdN~0)ei^UC8 zP1(s(<3h_1f;dg)%id(d`LwP^)|EpC3`8v0pnW;I2=A=%+Q4_)27J8!^5;!0D|3a^ kt8}gQ*UMst$3w5z+GvNFQFdLKlA!TR<-, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-13 08:42+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: trans/tests.py:16 +msgid "local country person" +msgstr "canuck" diff --git a/tests/i18n/loading/en_NZ/LC_MESSAGES/django.mo b/tests/i18n/loading/en_NZ/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f71850a5b1a06715d127ed1eaff29ccc93b400b4 GIT binary patch literal 387 zcmYL@u};G<6h#9nOGbpm!r&cTV5>|)HH}*$>?EXVCD=^r21BqT#|66Z7yKUI!V62T zeDo~qKKc9}4t@g2K5zn@0SCYs=#l|Pzyol+7X%xa1K=C(aQ^pT^r>wrYgF2;@otA2 ziQpfF2uu0C|P zgCpq`L63~)Sfn_j=q@E9K7C3P7IN8oTsUdkT6*gUnk_j;2^9>DnV>PB&?w5;VsQgi zQ*C9XaG~ToL7XP@WoI(xd{XP7byeR10}%_>YhMm8!l^Z08TfA3fR9&S{=BKBHdm;8 jk*-z#dRffysPA=J8|5%FrCn=N5j1+%J`CRUrw;xA! literal 0 HcmV?d00001 diff --git a/tests/i18n/loading/en_NZ/LC_MESSAGES/django.po b/tests/i18n/loading/en_NZ/LC_MESSAGES/django.po new file mode 100644 index 0000000000..41b7499291 --- /dev/null +++ b/tests/i18n/loading/en_NZ/LC_MESSAGES/django.po @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-13 08:42+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: trans/tests.py:16 +msgid "local country person" +msgstr "kiwi" diff --git a/tests/i18n/loading_app/__init__.py b/tests/i18n/loading_app/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/i18n/loading_app/apps.py b/tests/i18n/loading_app/apps.py new file mode 100644 index 0000000000..b4cdece232 --- /dev/null +++ b/tests/i18n/loading_app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class LoadingAppConfig(AppConfig): + name = 'loading_app' diff --git a/tests/i18n/loading_app/locale/en/LC_MESSAGES/django.mo b/tests/i18n/loading_app/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..71cbdf3e9d8d54be31066ec4ad8628bc2c1f2845 GIT binary patch literal 380 zcmYL@K~KUk7=|%=+R?Lz&%}d9i{c3jGZa>EvE7z2Nc2{r&Y96JZ6W$Y{CoZuJ5A(G zp7i_Dx9RhJeDu}vIq;l#&OC>nD^HugXY4QU{MmN?lNtRkR}RH%w3NnHT4Bh@vF%H^(V-=Ii1iQ$Qo9Pt!I1Rhe%oml#`f^NEGFCKEL->Rc=KoQ6a?!10%_7(V7ey8`V`;n{war z20Z3;uifk31QV^CRQ|iq#``$=;jWunRB8aLH({)F;i8zL{=V00y-I_qTIqGAN(}v% i$^}`yHKImSZ8jEzYJOK6-VWez49^vuhS0kh1f3tbb!oc* literal 0 HcmV?d00001 diff --git a/tests/i18n/loading_app/locale/en/LC_MESSAGES/django.po b/tests/i18n/loading_app/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000000..e1422f19da --- /dev/null +++ b/tests/i18n/loading_app/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,25 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-13 11:39+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: apps.py:8 +msgid "" +"An app with its own translation files, with one for 'en' but not the " +"regional dialects of English" +msgstr "" diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 8f07c14247..feca7b856f 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -384,6 +384,51 @@ class TranslationTests(SimpleTestCase): self.assertIs(get_language_bidi(), True) +class TranslationLoadingTests(SimpleTestCase): + def setUp(self): + """Clear translation state.""" + self._old_language = get_language() + self._old_translations = trans_real._translations + deactivate() + trans_real._translations = {} + + def tearDown(self): + trans_real._translations = self._old_translations + activate(self._old_language) + + @override_settings( + USE_I18N=True, + LANGUAGE_CODE='en', + LANGUAGES=[ + ('en', 'English'), + ('en-ca', 'English (Canada)'), + ('en-nz', 'English (New Zealand)'), + ('en-au', 'English (Australia)'), + ], + LOCALE_PATHS=[os.path.join(here, 'loading')], + INSTALLED_APPS=['i18n.loading_app'], + ) + def test_translation_loading(self): + """ + "loading_app" does not have translations for all languages provided by + "loading". Catalogs are merged correctly. + """ + tests = [ + ('en', 'local country person'), + ('en_AU', 'aussie'), + ('en_NZ', 'kiwi'), + ('en_CA', 'canuck'), + ] + # Load all relevant translations. + for language, _ in tests: + activate(language) + # Catalogs are merged correctly. + for language, nickname in tests: + with self.subTest(language=language): + activate(language) + self.assertEqual(gettext('local country person'), nickname) + + class TranslationThreadSafetyTests(SimpleTestCase): def setUp(self):