#32797: model_ngettext incorrectly tries to translate already translated words -------------------------------------+------------------------------------- Reporter: Maciej | Owner: Maciej Olko Olko | Type: Bug | Status: assigned Component: | Version: 3.2 contrib.admin | Keywords: i18n, gettext, Severity: Normal | ngettext Triage Stage: | Has patch: 1 Unreviewed | Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 1 | -------------------------------------+------------------------------------- `model_ngettext()` util function doesn't handle `gettext_lazy` objects as model's `verbose_name` and `verbose_name_plural`.
`translation`'s module `ngettext()` function is intended to be called with not translated source strings, whereas `model_ngettext()` puts `verbose_name` and `verbose_name_plural`, which may be a `gettext_lazy` objects, as its arguments. Effectively it makes Django not use correct plural translations for verbose name for any language that has other plural rules then English for phrases * `Successfully deleted %(count)d %(items)s.` * and `%(count)s %(name)s were changed successfully.` in admin panel (they use `model_ngettext` function to render `items` and `name` respectively). Following test: {{{ Index: tests/admin_utils/tests.py IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/tests/admin_utils/tests.py b/tests/admin_utils/tests.py --- a/tests/admin_utils/tests.py (revision d270dd584e0af12fe6229fb712d0704c232dc7e5) +++ b/tests/admin_utils/tests.py (date 1622333679821) @@ -1,5 +1,6 @@ from datetime import datetime from decimal import Decimal +from unittest.mock import patch from django import forms from django.conf import settings @@ -8,7 +9,7 @@ from django.contrib.admin.utils import ( NestedObjects, display_for_field, display_for_value, flatten, flatten_fieldsets, help_text_for_field, label_for_field, lookup_field, - quote, + quote, model_ngettext, ) from django.db import DEFAULT_DB_ALIAS, models from django.test import SimpleTestCase, TestCase, override_settings @@ -16,7 +17,7 @@ from django.utils.safestring import mark_safe from .models import ( - Article, Car, Count, Event, EventGuide, Location, Site, Vehicle, + Article, Car, Count, Event, EventGuide, Location, Site, Vehicle, Foo, ) @@ -410,3 +411,9 @@ def test_quote(self): self.assertEqual(quote('something\nor\nother'), 'something_0Aor_0Aother') + + @patch('django.contrib.admin.utils.ngettext') + def test_model_ngettext(self, ngettext): + model_ngettext(Foo(), None) + self.assertIsInstance(ngettext.call_args.args[0], str, type(ngettext.call_args.args[0])) + self.assertIsInstance(ngettext.call_args.args[1], str, type(ngettext.call_args.args[1])) Index: tests/admin_utils/models.py IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/tests/admin_utils/models.py b/tests/admin_utils/models.py --- a/tests/admin_utils/models.py (revision d270dd584e0af12fe6229fb712d0704c232dc7e5) +++ b/tests/admin_utils/models.py (date 1622333679823) @@ -85,3 +85,9 @@ class Car(VehicleMixin): pass + + +class Foo(models.Model): + class Meta: + verbose_name = _('foo') + verbose_name_plural = _('foos') }}} Fails with: {{{ Traceback (most recent call last): File "my-venv/versions/3.9.1/lib/python3.9/unittest/mock.py", line 1337, in patched return func(*newargs, **newkeywargs) File "django/tests/admin_utils/tests.py", line 419, in test_model_ngettext self.assertIsInstance(ngettext.call_args.args[0], str, type(ngettext.call_args.args[0])) AssertionError: 'foo' is not an instance of <class 'str'> : <class 'django.utils.functional.lazy.<locals>.__proxy__'> }}} A fix requires us to recognize `gettext_lazy` objects as verbose names, and passing their source strings instead of translations to ngettext function. **Backwards compatibility** As third party libraries does not provide us with plural translations of models, we should keep the current behavior in case of missing plural translation of model name. Let me create a pull request after having ticket number assigned. -- Ticket URL: <https://code.djangoproject.com/ticket/32797> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/050.1a19ffb104f6f6d1bbc365c00239f0e4%40djangoproject.com.