From f2dd652245987465754c7242b60ccaba03a20f06 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 23 Jul 2022 11:44:45 -0400 Subject: [PATCH] Fixed #33863 -- Fixed JavaScriptCatalog with more than 1 level of fallback translations. Co-authored-by: Carlos Mermingas --- django/views/i18n.py | 36 +++++++++--------- .../es/LC_MESSAGES/djangojs.mo | Bin 0 -> 444 bytes .../es/LC_MESSAGES/djangojs.po | 20 ++++++++++ .../es_MX/LC_MESSAGES/djangojs.mo | Bin 0 -> 326 bytes .../es_MX/LC_MESSAGES/djangojs.po | 20 ++++++++++ tests/view_tests/tests/test_i18n.py | 21 ++++++++++ tests/view_tests/urls.py | 1 + 7 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.mo create mode 100644 tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.po create mode 100644 tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.mo create mode 100644 tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.po diff --git a/django/views/i18n.py b/django/views/i18n.py index 2cf24d35407..91f797dce90 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -1,4 +1,3 @@ -import itertools import json import os import re @@ -273,26 +272,27 @@ class JavaScriptCatalog(View): def get_catalog(self): pdict = {} - num_plurals = self._num_plurals catalog = {} - trans_cat = self.translation._catalog - trans_fallback_cat = ( - self.translation._fallback._catalog if self.translation._fallback else {} - ) + translation = self.translation seen_keys = set() - for key, value in itertools.chain( - trans_cat.items(), trans_fallback_cat.items() - ): - if key == "" or key in seen_keys: - continue - if isinstance(key, str): - catalog[key] = value - elif isinstance(key, tuple): - msgid, cnt = key - pdict.setdefault(msgid, {})[cnt] = value + while True: + for key, value in translation._catalog.items(): + if key == "" or key in seen_keys: + continue + if isinstance(key, str): + catalog[key] = value + elif isinstance(key, tuple): + msgid, cnt = key + pdict.setdefault(msgid, {})[cnt] = value + else: + raise TypeError(key) + seen_keys.add(key) + if translation._fallback: + translation = translation._fallback else: - raise TypeError(key) - seen_keys.add(key) + break + + num_plurals = self._num_plurals for k, v in pdict.items(): catalog[k] = [v.get(i, "") for i in range(num_plurals)] return catalog diff --git a/tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.mo b/tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..181b61fd9c81f81397480cd3d013820ac874806e GIT binary patch literal 444 zcmZvY!A`}E5w^XLCOJ^FA+hr}6iP8<_mqEf#bZ<=@IXAr}|bs`>U)nR_)fM z%6N(EJ-1sQ>{b|{vI;f`R&!}eZZUTftsXJ6Y?8ATY9o~NAqfU|!8n9fIA2U=Q+JMg zr7eq1A#!$G6^5nC2RE6qIX;Veh7IX6A6j11V_uszThMIz?JMS8dY&6`V_EvMQfVJX z%P4|r5QoqW<6si?gW+%)x6<4GL;d2Kd4 zcc7$2NjqNmWWwT$z1Wvr$ZN>9TpP4E%XGv#e|@!=2h=Q-naYJMeCTY1b)El`LkbhD SK#A~FAsEzke0i0LTsdFOntN{m literal 0 HcmV?d00001 diff --git a/tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.po b/tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.po new file mode 100644 index 00000000000..12e0c367bad --- /dev/null +++ b/tests/view_tests/custom_locale_path/es/LC_MESSAGES/djangojs.po @@ -0,0 +1,20 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 16:45+0200\n" +"PO-Revision-Date: 2010-05-12 12:57-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: media/js/translate.js:1 +msgid "custom_locale_path: this is to be translated" +msgstr "custom_locale_path: esto tiene que ser traducido" diff --git a/tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.mo b/tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000000000000000000000000000000000000..045c5ec5832fabe36df5a6a2db459b76cbb4ec56 GIT binary patch literal 326 zcmYL@y-ve06h@0+ikO%gJTP*L6I2mQsTvx$ig3~>Kiy4Yf>E&}$3^fUydKYjv(QgE zy2Jgh?)kkq`$IgFpqu)hiA!%VJ%pkQQD34ap(T1WO zEy`q@d4=e;v5*d(Y~kt94Nz%|)f#M}yk0_f`1UiqHI%-CUeG?dpXsnTX<=b z(xaRgG??>Ie#7r1d6$ Dv7%Op literal 0 HcmV?d00001 diff --git a/tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.po b/tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.po new file mode 100644 index 00000000000..22c708a891a --- /dev/null +++ b/tests/view_tests/custom_locale_path/es_MX/LC_MESSAGES/djangojs.po @@ -0,0 +1,20 @@ +# 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. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-09-15 16:45+0200\n" +"PO-Revision-Date: 2010-05-12 12:57-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: media/js/translate.js:1 +msgid "custom_locale_path: this is to be translated" +msgstr "" diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py index 3aacded7c6d..aff920c2c43 100644 --- a/tests/view_tests/tests/test_i18n.py +++ b/tests/view_tests/tests/test_i18n.py @@ -344,6 +344,27 @@ class I18NViewTests(SimpleTestCase): self.assertContains(response, "il faut le traduire") self.assertNotContains(response, "Untranslated string") + def test_jsi18n_fallback_language_with_custom_locale_dir(self): + """ + The fallback language works when there are several levels of fallback + translation catalogs. + """ + locale_paths = [ + path.join( + path.dirname(path.dirname(path.abspath(__file__))), + "custom_locale_path", + ), + ] + with self.settings(LOCALE_PATHS=locale_paths), override("es_MX"): + response = self.client.get("/jsi18n/") + self.assertContains( + response, "custom_locale_path: esto tiene que ser traducido" + ) + response = self.client.get("/jsi18n_no_packages/") + self.assertContains( + response, "custom_locale_path: esto tiene que ser traducido" + ) + def test_i18n_fallback_language_plural(self): """ The fallback to a language with less plural forms maintains the real diff --git a/tests/view_tests/urls.py b/tests/view_tests/urls.py index cec156b5da4..c9a5c28573d 100644 --- a/tests/view_tests/urls.py +++ b/tests/view_tests/urls.py @@ -31,6 +31,7 @@ urlpatterns = [ # i18n views path("i18n/", include("django.conf.urls.i18n")), path("jsi18n/", i18n.JavaScriptCatalog.as_view(packages=["view_tests"])), + path("jsi18n_no_packages/", i18n.JavaScriptCatalog.as_view()), path("jsi18n/app1/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app1"])), path("jsi18n/app2/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app2"])), path("jsi18n/app5/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app5"])),