Opened 17 months ago

Last modified 15 months ago

#34221 assigned Bug

Plural-Forms in .po files break Django's translation precedence.

Reported by: Stefano Parmesan Owned by: rajdesai24
Component: Internationalization Version: 4.1
Severity: Normal Keywords: i18n
Cc: Claude Paroz Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

According to the documentation, Django reads translations from LOCALE_PATHS first, then from apps in INSTALLED_APPS, and then from its own folders.

This behaviour breaks if the files in LOCALE_PATHS contain Plural-Forms while those found in INSTALLED_APPS don't.

To test this behaviour I created a test project on github here:

https://github.com/armisael/test-django-i18n-preference

The project contains a .po file with Plural-Forms and a single translation that is also included in one of the dependencies. A single test checks which translation is picked.

With the current configuration, the test fails by using the dependency translation. It passes if:
1) the dependency is removed from INSTALLED_APPS; or if
2) Plural-Forms is removed from the .po file.

1) proves that i18n is correctly configured, and that the dependency translation is picked over the project one; 2) proves that Plural-Forms is involved in the bug.

Change History (6)

comment:1 by Mariusz Felisiak, 17 months ago

Cc: Claude Paroz added

comment:2 by Claude Paroz, 17 months ago

Triage Stage: UnreviewedAccepted

Thanks for the detailed report and test project!

To solve #30439 and allow for different plural forms for a same language, we had to refrain from merging all translations in a unique catalog, as was done before. However, your setup demonstrates that the algorithm to decide between merge or separating catalogs is flawed (the third catalog from LOCALE_PATH having the same plural forms as the Django one, it is merge with it, hence loosing it's priority over the intermediary django-extension catalog).

The following patch should fix the issue:

diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index c1e64d4ebd..f4d05b8f76 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -96,11 +96,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)

comment:3 by Bhuvnesh, 16 months ago

Hi, I'm stuck at writing test for this one, how do i include dependency in the test?

comment:4 by rajdesai24, 15 months ago

Owner: changed from nobody to rajdesai24
Status: newassigned

comment:5 by rajdesai24, 15 months ago

hey Claude, I tested the patch with the test project that Stefano has provided but it did not work.

comment:6 by rajdesai24, 15 months ago

will figure out what can we add to the current patch

Note: See TracTickets for help on using tickets.
Back to Top