From 98fada7244f135022540ec5d2383fb0115844bb4 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 28 May 2020 10:26:41 +0200 Subject: [PATCH] [3.1.x] 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. Backport of dd1ca50b096bf0351819aabc862e91a9797ddaca from master --- 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):