diff --git a/django/contrib/auth/password_validation.py b/django/contrib/auth/password_validation.py index 6067858b00..38e7c5c3a8 100644 --- a/django/contrib/auth/password_validation.py +++ b/django/contrib/auth/password_validation.py @@ -106,15 +106,20 @@ class MinimumLengthValidator: def validate(self, password, user=None): if len(password) < self.min_length: - raise ValidationError(self.get_error_message(), code="password_too_short") + raise ValidationError( + self.get_error_message(), + code="password_too_short", + params={"min_length": self.min_length}, + ) def get_error_message(self): - return ngettext( - "This password is too short. It must contain at least %d character." - % self.min_length, - "This password is too short. It must contain at least %d characters." - % self.min_length, - self.min_length, + return ( + ngettext( + "This password is too short. It must contain at least %d character.", + "This password is too short. It must contain at least %d characters.", + self.min_length, + ) + % self.min_length ) def get_help_text(self): diff --git a/docs/releases/5.2.1.txt b/docs/releases/5.2.1.txt index cc12e7b34f..81fb750847 100644 --- a/docs/releases/5.2.1.txt +++ b/docs/releases/5.2.1.txt @@ -36,3 +36,7 @@ Bugfixes * Fixed a regression in Django 5.2 that caused improper values to be returned from ``QuerySet.values_list()`` when duplicate field names were specified (:ticket:`36288`). + +* Fixed a regression in Django 5.2 where the password validation error message + from ``MinimumLengthValidator`` was not translated when using non-English + locales (:ticket:`36314`). diff --git a/tests/auth_tests/test_validators.py b/tests/auth_tests/test_validators.py index ea75c4a080..fdbf495ff5 100644 --- a/tests/auth_tests/test_validators.py +++ b/tests/auth_tests/test_validators.py @@ -1,4 +1,5 @@ import os +from unittest import mock from django.contrib.auth import validators from django.contrib.auth.models import User @@ -132,11 +133,16 @@ class MinimumLengthValidatorTest(SimpleTestCase): with self.assertRaises(ValidationError) as cm: MinimumLengthValidator().validate("1234567") self.assertEqual(cm.exception.messages, [expected_error % 8]) - self.assertEqual(cm.exception.error_list[0].code, "password_too_short") + error = cm.exception.error_list[0] + self.assertEqual(error.code, "password_too_short") + self.assertEqual(error.params, {"min_length": 8}) with self.assertRaises(ValidationError) as cm: MinimumLengthValidator(min_length=3).validate("12") self.assertEqual(cm.exception.messages, [expected_error % 3]) + error = cm.exception.error_list[0] + self.assertEqual(error.code, "password_too_short") + self.assertEqual(error.params, {"min_length": 3}) def test_help_text(self): self.assertEqual( @@ -144,6 +150,24 @@ class MinimumLengthValidatorTest(SimpleTestCase): "Your password must contain at least 8 characters.", ) + @mock.patch("django.contrib.auth.password_validation.ngettext") + def test_l10n(self, mock_ngettext): + with self.subTest("get_error_message"): + MinimumLengthValidator().get_error_message() + mock_ngettext.assert_called_with( + "This password is too short. It must contain at least %d character.", + "This password is too short. It must contain at least %d characters.", + 8, + ) + mock_ngettext.reset() + with self.subTest("get_help_text"): + MinimumLengthValidator().get_help_text() + mock_ngettext.assert_called_with( + "Your password must contain at least %(min_length)d " "character.", + "Your password must contain at least %(min_length)d " "characters.", + 8, + ) + def test_custom_error(self): class CustomMinimumLengthValidator(MinimumLengthValidator): def get_error_message(self):