浏览代码

Fixed #34221 -- Honored translation precedence with mixed plural forms.

Claude Paroz 6 月之前
父节点
当前提交
b579485d99
共有 2 个文件被更改,包括 48 次插入6 次删除
  1. 3 5
      django/utils/translation/trans_real.py
  2. 45 1
      tests/i18n/tests.py

+ 3 - 5
django/utils/translation/trans_real.py

@@ -103,11 +103,9 @@ class TranslationCatalog:
             yield from cat.keys()
 
     def update(self, trans):
-        # Merge if plural function is the same, else prepend.
-        for cat, plural in zip(self._catalogs, self._plurals):
-            if trans.plural.__code__ == plural.__code__:
-                cat.update(trans._catalog)
-                break
+        # Merge if plural function is the same as the top catalog, else prepend.
+        if trans.plural.__code__ == self._plurals[0]:
+            self._catalogs[0].update(trans._catalog)
         else:
             self._catalogs.insert(0, trans._catalog.copy())
             self._plurals.insert(0, trans.plural)

+ 45 - 1
tests/i18n/tests.py

@@ -8,7 +8,7 @@ import tempfile
 from contextlib import contextmanager
 from importlib import import_module
 from pathlib import Path
-from unittest import mock
+from unittest import mock, skipUnless
 
 from asgiref.local import Local
 
@@ -17,6 +17,7 @@ from django.apps import AppConfig
 from django.conf import settings
 from django.conf.locale import LANG_INFO
 from django.conf.urls.i18n import i18n_patterns
+from django.core.management.utils import find_command, popen_wrapper
 from django.template import Context, Template
 from django.test import RequestFactory, SimpleTestCase, TestCase, override_settings
 from django.utils import translation
@@ -130,6 +131,49 @@ class TranslationTests(SimpleTestCase):
         self.assertEqual(french._catalog[("%d singular", 0)], "%d singulier")
         self.assertEqual(french._catalog[("%(num)d hour", 0)], "%(num)d heure")
 
+    @translation.override("fr")
+    @skipUnless(find_command("msgfmt"), "msgfmt is mandatory for this test")
+    def test_multiple_plurals_merge(self):
+        def _create_translation_from_string(content):
+            with tempfile.TemporaryDirectory() as dirname:
+                po_path = Path(dirname).joinpath("fr", "LC_MESSAGES", "django.po")
+                po_path.parent.mkdir(parents=True)
+                po_path.write_text(content)
+                errors = popen_wrapper(
+                    ["msgfmt", "-o", po_path.with_suffix(".mo"), po_path]
+                )[1]
+                if errors:
+                    self.fail(f"msgfmt compilation error: {errors}")
+                return gettext_module.translation(
+                    domain="django",
+                    localedir=dirname,
+                    languages=["fr"],
+                )
+
+        french = trans_real.catalog()
+        # Merge a new translation file with different plural forms.
+        catalog1 = _create_translation_from_string(
+            'msgid ""\n'
+            'msgstr ""\n'
+            '"Content-Type: text/plain; charset=UTF-8\\n"\n'
+            '"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 ? 1 : 2);\\n"\n'
+            'msgid "I win"\n'
+            'msgstr "Je perds"\n'
+        )
+        french.merge(catalog1)
+        # Merge a second translation file with plural forms from django.conf.
+        catalog2 = _create_translation_from_string(
+            'msgid ""\n'
+            'msgstr ""\n'
+            '"Content-Type: text/plain; charset=UTF-8\\n"\n'
+            '"Plural-Forms: Plural-Forms: nplurals=2; plural=(n > 1);\\n"\n'
+            'msgid "I win"\n'
+            'msgstr "Je gagne"\n'
+        )
+        french.merge(catalog2)
+        # Translations from this last one are supposed to win.
+        self.assertEqual(french.gettext("I win"), "Je gagne")
+
     def test_override(self):
         activate("de")
         try: