diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/i18n | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/i18n')
25 files changed, 2019 insertions, 1425 deletions
diff --git a/tests/i18n/commands/__init__.py b/tests/i18n/commands/__init__.py index f0a06505de..e02ea47fff 100644 --- a/tests/i18n/commands/__init__.py +++ b/tests/i18n/commands/__init__.py @@ -1,4 +1,5 @@ -from django.utils.translation import gettext as _, ngettext +from django.utils.translation import gettext as _ +from django.utils.translation import ngettext # Translators: This comment should be extracted dummy1 = _("This is a translatable string.") @@ -9,9 +10,9 @@ dummy2 = _("This is another translatable string.") # This file has a literal with plural forms. When processed first, makemessages # shouldn't create a .po file with duplicate `Plural-Forms` headers number = 3 -dummy3 = ngettext("%(number)s Foo", "%(number)s Foos", number) % {'number': number} +dummy3 = ngettext("%(number)s Foo", "%(number)s Foos", number) % {"number": number} -dummy4 = _('Size') +dummy4 = _("Size") # This string is intentionally duplicated in test.html -dummy5 = _('This literal should be included.') +dummy5 = _("This literal should be included.") diff --git a/tests/i18n/contenttypes/tests.py b/tests/i18n/contenttypes/tests.py index d23e2bdf56..22bbb5d834 100644 --- a/tests/i18n/contenttypes/tests.py +++ b/tests/i18n/contenttypes/tests.py @@ -8,18 +8,18 @@ from django.utils import translation @override_settings( USE_I18N=True, LOCALE_PATHS=[ - os.path.join(os.path.dirname(__file__), 'locale'), + os.path.join(os.path.dirname(__file__), "locale"), ], - LANGUAGE_CODE='en', + LANGUAGE_CODE="en", LANGUAGES=[ - ('en', 'English'), - ('fr', 'French'), + ("en", "English"), + ("fr", "French"), ], ) class ContentTypeTests(TestCase): def test_verbose_name(self): - company_type = ContentType.objects.get(app_label='i18n', model='company') - with translation.override('en'): - self.assertEqual(str(company_type), 'i18n | Company') - with translation.override('fr'): - self.assertEqual(str(company_type), 'i18n | Société') + company_type = ContentType.objects.get(app_label="i18n", model="company") + with translation.override("en"): + self.assertEqual(str(company_type), "i18n | Company") + with translation.override("fr"): + self.assertEqual(str(company_type), "i18n | Société") diff --git a/tests/i18n/forms.py b/tests/i18n/forms.py index 8c290bf664..207ab9403a 100644 --- a/tests/i18n/forms.py +++ b/tests/i18n/forms.py @@ -23,4 +23,4 @@ class CompanyForm(forms.ModelForm): class Meta: model = Company - fields = '__all__' + fields = "__all__" diff --git a/tests/i18n/loading_app/apps.py b/tests/i18n/loading_app/apps.py index 14cfdf776f..855862ec9a 100644 --- a/tests/i18n/loading_app/apps.py +++ b/tests/i18n/loading_app/apps.py @@ -2,4 +2,4 @@ from django.apps import AppConfig class LoadingAppConfig(AppConfig): - name = 'i18n.loading_app' + name = "i18n.loading_app" diff --git a/tests/i18n/models.py b/tests/i18n/models.py index 15b4de57b6..8343276bf2 100644 --- a/tests/i18n/models.py +++ b/tests/i18n/models.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _ class TestModel(models.Model): - text = models.CharField(max_length=10, default=_('Anything')) + text = models.CharField(max_length=10, default=_("Anything")) class Company(models.Model): @@ -15,4 +15,4 @@ class Company(models.Model): products_delivered = models.IntegerField() class Meta: - verbose_name = _('Company') + verbose_name = _("Company") diff --git a/tests/i18n/other/locale/fr/formats.py b/tests/i18n/other/locale/fr/formats.py index d13e245c30..81f2f70886 100644 --- a/tests/i18n/other/locale/fr/formats.py +++ b/tests/i18n/other/locale/fr/formats.py @@ -1,2 +1,2 @@ # A user-defined format -CUSTOM_DAY_FORMAT = 'd/m/Y CUSTOM' +CUSTOM_DAY_FORMAT = "d/m/Y CUSTOM" diff --git a/tests/i18n/patterns/tests.py b/tests/i18n/patterns/tests.py index ebd2430428..eeb41e7d27 100644 --- a/tests/i18n/patterns/tests.py +++ b/tests/i18n/patterns/tests.py @@ -19,28 +19,30 @@ class PermanentRedirectLocaleMiddleWare(LocaleMiddleware): @override_settings( USE_I18N=True, LOCALE_PATHS=[ - os.path.join(os.path.dirname(__file__), 'locale'), + os.path.join(os.path.dirname(__file__), "locale"), ], - LANGUAGE_CODE='en-us', + LANGUAGE_CODE="en-us", LANGUAGES=[ - ('nl', 'Dutch'), - ('en', 'English'), - ('pt-br', 'Brazilian Portuguese'), + ("nl", "Dutch"), + ("en", "English"), + ("pt-br", "Brazilian Portuguese"), ], MIDDLEWARE=[ - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + ], + ROOT_URLCONF="i18n.patterns.urls.default", + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(os.path.dirname(__file__), "templates")], + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.i18n", + ], + }, + } ], - ROOT_URLCONF='i18n.patterns.urls.default', - TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(os.path.dirname(__file__), 'templates')], - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.i18n', - ], - }, - }], ) class URLTestCaseBase(SimpleTestCase): """ @@ -60,53 +62,58 @@ class URLPrefixTests(URLTestCaseBase): """ Tests if the `i18n_patterns` is adding the prefix correctly. """ + def test_not_prefixed(self): - with translation.override('en'): - self.assertEqual(reverse('not-prefixed'), '/not-prefixed/') - self.assertEqual(reverse('not-prefixed-included-url'), '/not-prefixed-include/foo/') - with translation.override('nl'): - self.assertEqual(reverse('not-prefixed'), '/not-prefixed/') - self.assertEqual(reverse('not-prefixed-included-url'), '/not-prefixed-include/foo/') + with translation.override("en"): + self.assertEqual(reverse("not-prefixed"), "/not-prefixed/") + self.assertEqual( + reverse("not-prefixed-included-url"), "/not-prefixed-include/foo/" + ) + with translation.override("nl"): + self.assertEqual(reverse("not-prefixed"), "/not-prefixed/") + self.assertEqual( + reverse("not-prefixed-included-url"), "/not-prefixed-include/foo/" + ) def test_prefixed(self): - with translation.override('en'): - self.assertEqual(reverse('prefixed'), '/en/prefixed/') - with translation.override('nl'): - self.assertEqual(reverse('prefixed'), '/nl/prefixed/') + with translation.override("en"): + self.assertEqual(reverse("prefixed"), "/en/prefixed/") + with translation.override("nl"): + self.assertEqual(reverse("prefixed"), "/nl/prefixed/") with translation.override(None): - self.assertEqual(reverse('prefixed'), '/%s/prefixed/' % settings.LANGUAGE_CODE) + self.assertEqual( + reverse("prefixed"), "/%s/prefixed/" % settings.LANGUAGE_CODE + ) - @override_settings(ROOT_URLCONF='i18n.patterns.urls.wrong') + @override_settings(ROOT_URLCONF="i18n.patterns.urls.wrong") def test_invalid_prefix_use(self): - msg = 'Using i18n_patterns in an included URLconf is not allowed.' + msg = "Using i18n_patterns in an included URLconf is not allowed." with self.assertRaisesMessage(ImproperlyConfigured, msg): - reverse('account:register') + reverse("account:register") -@override_settings(ROOT_URLCONF='i18n.patterns.urls.disabled') +@override_settings(ROOT_URLCONF="i18n.patterns.urls.disabled") class URLDisabledTests(URLTestCaseBase): - @override_settings(USE_I18N=False) def test_prefixed_i18n_disabled(self): - with translation.override('en'): - self.assertEqual(reverse('prefixed'), '/prefixed/') - with translation.override('nl'): - self.assertEqual(reverse('prefixed'), '/prefixed/') + with translation.override("en"): + self.assertEqual(reverse("prefixed"), "/prefixed/") + with translation.override("nl"): + self.assertEqual(reverse("prefixed"), "/prefixed/") class RequestURLConfTests(SimpleTestCase): - - @override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') + @override_settings(ROOT_URLCONF="i18n.patterns.urls.path_unused") def test_request_urlconf_considered(self): - request = RequestFactory().get('/nl/') - request.urlconf = 'i18n.patterns.urls.default' + request = RequestFactory().get("/nl/") + request.urlconf = "i18n.patterns.urls.default" middleware = LocaleMiddleware(lambda req: HttpResponse()) - with translation.override('nl'): + with translation.override("nl"): middleware.process_request(request) - self.assertEqual(request.LANGUAGE_CODE, 'nl') + self.assertEqual(request.LANGUAGE_CODE, "nl") -@override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') +@override_settings(ROOT_URLCONF="i18n.patterns.urls.path_unused") class PathUnusedTests(URLTestCaseBase): """ If no i18n_patterns is used in root URLconfs, then no language activation @@ -114,10 +121,10 @@ class PathUnusedTests(URLTestCaseBase): """ def test_no_lang_activate(self): - response = self.client.get('/nl/foo/') + response = self.client.get("/nl/foo/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'en') - self.assertEqual(response.context['LANGUAGE_CODE'], 'en') + self.assertEqual(response.headers["content-language"], "en") + self.assertEqual(response.context["LANGUAGE_CODE"], "en") class URLTranslationTests(URLTestCaseBase): @@ -125,66 +132,90 @@ class URLTranslationTests(URLTestCaseBase): Tests if the pattern-strings are translated correctly (within the `i18n_patterns` and the normal `patterns` function). """ + def test_no_prefix_translated(self): - with translation.override('en'): - self.assertEqual(reverse('no-prefix-translated'), '/translated/') - self.assertEqual(reverse('no-prefix-translated-slug', kwargs={'slug': 'yeah'}), '/translated/yeah/') + with translation.override("en"): + self.assertEqual(reverse("no-prefix-translated"), "/translated/") + self.assertEqual( + reverse("no-prefix-translated-slug", kwargs={"slug": "yeah"}), + "/translated/yeah/", + ) - with translation.override('nl'): - self.assertEqual(reverse('no-prefix-translated'), '/vertaald/') - self.assertEqual(reverse('no-prefix-translated-slug', kwargs={'slug': 'yeah'}), '/vertaald/yeah/') + with translation.override("nl"): + self.assertEqual(reverse("no-prefix-translated"), "/vertaald/") + self.assertEqual( + reverse("no-prefix-translated-slug", kwargs={"slug": "yeah"}), + "/vertaald/yeah/", + ) - with translation.override('pt-br'): - self.assertEqual(reverse('no-prefix-translated'), '/traduzidos/') - self.assertEqual(reverse('no-prefix-translated-slug', kwargs={'slug': 'yeah'}), '/traduzidos/yeah/') + with translation.override("pt-br"): + self.assertEqual(reverse("no-prefix-translated"), "/traduzidos/") + self.assertEqual( + reverse("no-prefix-translated-slug", kwargs={"slug": "yeah"}), + "/traduzidos/yeah/", + ) def test_users_url(self): - with translation.override('en'): - self.assertEqual(reverse('users'), '/en/users/') + with translation.override("en"): + self.assertEqual(reverse("users"), "/en/users/") - with translation.override('nl'): - self.assertEqual(reverse('users'), '/nl/gebruikers/') - self.assertEqual(reverse('prefixed_xml'), '/nl/prefixed.xml') + with translation.override("nl"): + self.assertEqual(reverse("users"), "/nl/gebruikers/") + self.assertEqual(reverse("prefixed_xml"), "/nl/prefixed.xml") - with translation.override('pt-br'): - self.assertEqual(reverse('users'), '/pt-br/usuarios/') + with translation.override("pt-br"): + self.assertEqual(reverse("users"), "/pt-br/usuarios/") def test_translate_url_utility(self): - with translation.override('en'): - self.assertEqual(translate_url('/en/nonexistent/', 'nl'), '/en/nonexistent/') - self.assertEqual(translate_url('/en/users/', 'nl'), '/nl/gebruikers/') + with translation.override("en"): + self.assertEqual( + translate_url("/en/nonexistent/", "nl"), "/en/nonexistent/" + ) + self.assertEqual(translate_url("/en/users/", "nl"), "/nl/gebruikers/") # Namespaced URL - self.assertEqual(translate_url('/en/account/register/', 'nl'), '/nl/profiel/registreren/') + self.assertEqual( + translate_url("/en/account/register/", "nl"), "/nl/profiel/registreren/" + ) # path() URL pattern - self.assertEqual(translate_url('/en/account/register-as-path/', 'nl'), '/nl/profiel/registreren-als-pad/') - self.assertEqual(translation.get_language(), 'en') + self.assertEqual( + translate_url("/en/account/register-as-path/", "nl"), + "/nl/profiel/registreren-als-pad/", + ) + self.assertEqual(translation.get_language(), "en") # URL with parameters. self.assertEqual( - translate_url('/en/with-arguments/regular-argument/', 'nl'), - '/nl/with-arguments/regular-argument/', + translate_url("/en/with-arguments/regular-argument/", "nl"), + "/nl/with-arguments/regular-argument/", ) self.assertEqual( - translate_url('/en/with-arguments/regular-argument/optional.html', 'nl'), - '/nl/with-arguments/regular-argument/optional.html', + translate_url( + "/en/with-arguments/regular-argument/optional.html", "nl" + ), + "/nl/with-arguments/regular-argument/optional.html", ) - with translation.override('nl'): - self.assertEqual(translate_url('/nl/gebruikers/', 'en'), '/en/users/') - self.assertEqual(translation.get_language(), 'nl') + with translation.override("nl"): + self.assertEqual(translate_url("/nl/gebruikers/", "en"), "/en/users/") + self.assertEqual(translation.get_language(), "nl") class URLNamespaceTests(URLTestCaseBase): """ Tests if the translations are still working within namespaces. """ + def test_account_register(self): - with translation.override('en'): - self.assertEqual(reverse('account:register'), '/en/account/register/') - self.assertEqual(reverse('account:register-as-path'), '/en/account/register-as-path/') + with translation.override("en"): + self.assertEqual(reverse("account:register"), "/en/account/register/") + self.assertEqual( + reverse("account:register-as-path"), "/en/account/register-as-path/" + ) - with translation.override('nl'): - self.assertEqual(reverse('account:register'), '/nl/profiel/registreren/') - self.assertEqual(reverse('account:register-as-path'), '/nl/profiel/registreren-als-pad/') + with translation.override("nl"): + self.assertEqual(reverse("account:register"), "/nl/profiel/registreren/") + self.assertEqual( + reverse("account:register-as-path"), "/nl/profiel/registreren-als-pad/" + ) class URLRedirectTests(URLTestCaseBase): @@ -192,79 +223,81 @@ class URLRedirectTests(URLTestCaseBase): Tests if the user gets redirected to the right URL when there is no language-prefix in the request URL. """ + def test_no_prefix_response(self): - response = self.client.get('/not-prefixed/') + response = self.client.get("/not-prefixed/") self.assertEqual(response.status_code, 200) def test_en_redirect(self): - response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='en') - self.assertRedirects(response, '/en/account/register/') + response = self.client.get("/account/register/", HTTP_ACCEPT_LANGUAGE="en") + self.assertRedirects(response, "/en/account/register/") - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) def test_en_redirect_wrong_url(self): - response = self.client.get('/profiel/registreren/', HTTP_ACCEPT_LANGUAGE='en') + response = self.client.get("/profiel/registreren/", HTTP_ACCEPT_LANGUAGE="en") self.assertEqual(response.status_code, 404) def test_nl_redirect(self): - response = self.client.get('/profiel/registreren/', HTTP_ACCEPT_LANGUAGE='nl') - self.assertRedirects(response, '/nl/profiel/registreren/') + response = self.client.get("/profiel/registreren/", HTTP_ACCEPT_LANGUAGE="nl") + self.assertRedirects(response, "/nl/profiel/registreren/") - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) def test_nl_redirect_wrong_url(self): - response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='nl') + response = self.client.get("/account/register/", HTTP_ACCEPT_LANGUAGE="nl") self.assertEqual(response.status_code, 404) def test_pt_br_redirect(self): - response = self.client.get('/conta/registre-se/', HTTP_ACCEPT_LANGUAGE='pt-br') - self.assertRedirects(response, '/pt-br/conta/registre-se/') + response = self.client.get("/conta/registre-se/", HTTP_ACCEPT_LANGUAGE="pt-br") + self.assertRedirects(response, "/pt-br/conta/registre-se/") - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) def test_pl_pl_redirect(self): # language from outside of the supported LANGUAGES list - response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='pl-pl') - self.assertRedirects(response, '/en/account/register/') + response = self.client.get("/account/register/", HTTP_ACCEPT_LANGUAGE="pl-pl") + self.assertRedirects(response, "/en/account/register/") - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) @override_settings( MIDDLEWARE=[ - 'i18n.patterns.tests.PermanentRedirectLocaleMiddleWare', - 'django.middleware.common.CommonMiddleware', + "i18n.patterns.tests.PermanentRedirectLocaleMiddleWare", + "django.middleware.common.CommonMiddleware", ], ) def test_custom_redirect_class(self): - response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='en') - self.assertRedirects(response, '/en/account/register/', 301) + response = self.client.get("/account/register/", HTTP_ACCEPT_LANGUAGE="en") + self.assertRedirects(response, "/en/account/register/", 301) class URLVaryAcceptLanguageTests(URLTestCaseBase): """ 'Accept-Language' is not added to the Vary header when using prefixed URLs. """ + def test_no_prefix_response(self): - response = self.client.get('/not-prefixed/') + response = self.client.get("/not-prefixed/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.get('Vary'), 'Accept-Language') + self.assertEqual(response.get("Vary"), "Accept-Language") def test_en_redirect(self): """ The redirect to a prefixed URL depends on 'Accept-Language' and 'Cookie', but once prefixed no header is set. """ - response = self.client.get('/account/register/', HTTP_ACCEPT_LANGUAGE='en') - self.assertRedirects(response, '/en/account/register/') - self.assertEqual(response.get('Vary'), 'Accept-Language, Cookie') + response = self.client.get("/account/register/", HTTP_ACCEPT_LANGUAGE="en") + self.assertRedirects(response, "/en/account/register/") + self.assertEqual(response.get("Vary"), "Accept-Language, Cookie") - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) - self.assertFalse(response.get('Vary')) + self.assertFalse(response.get("Vary")) class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase): @@ -272,18 +305,23 @@ class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase): Tests the redirect when the requested URL doesn't end with a slash (`settings.APPEND_SLASH=True`). """ + def test_not_prefixed_redirect(self): - response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en') - self.assertRedirects(response, '/not-prefixed/', 301) + response = self.client.get("/not-prefixed", HTTP_ACCEPT_LANGUAGE="en") + self.assertRedirects(response, "/not-prefixed/", 301) def test_en_redirect(self): - response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en', follow=True) + response = self.client.get( + "/account/register", HTTP_ACCEPT_LANGUAGE="en", follow=True + ) # We only want one redirect, bypassing CommonMiddleware - self.assertEqual(response.redirect_chain, [('/en/account/register/', 302)]) - self.assertRedirects(response, '/en/account/register/', 302) + self.assertEqual(response.redirect_chain, [("/en/account/register/", 302)]) + self.assertRedirects(response, "/en/account/register/", 302) - response = self.client.get('/prefixed.xml', HTTP_ACCEPT_LANGUAGE='en', follow=True) - self.assertRedirects(response, '/en/prefixed.xml', 302) + response = self.client.get( + "/prefixed.xml", HTTP_ACCEPT_LANGUAGE="en", follow=True + ) + self.assertRedirects(response, "/en/prefixed.xml", 302) class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase): @@ -291,105 +329,129 @@ class URLRedirectWithoutTrailingSlashSettingTests(URLTestCaseBase): Tests the redirect when the requested URL doesn't end with a slash (`settings.APPEND_SLASH=False`). """ + @override_settings(APPEND_SLASH=False) def test_not_prefixed_redirect(self): - response = self.client.get('/not-prefixed', HTTP_ACCEPT_LANGUAGE='en') + response = self.client.get("/not-prefixed", HTTP_ACCEPT_LANGUAGE="en") self.assertEqual(response.status_code, 404) @override_settings(APPEND_SLASH=False) def test_en_redirect(self): - response = self.client.get('/account/register-without-slash', HTTP_ACCEPT_LANGUAGE='en') - self.assertRedirects(response, '/en/account/register-without-slash', 302) + response = self.client.get( + "/account/register-without-slash", HTTP_ACCEPT_LANGUAGE="en" + ) + self.assertRedirects(response, "/en/account/register-without-slash", 302) - response = self.client.get(response.headers['location']) + response = self.client.get(response.headers["location"]) self.assertEqual(response.status_code, 200) class URLResponseTests(URLTestCaseBase): """Tests if the response has the correct language code.""" + def test_not_prefixed_with_prefix(self): - response = self.client.get('/en/not-prefixed/') + response = self.client.get("/en/not-prefixed/") self.assertEqual(response.status_code, 404) def test_en_url(self): - response = self.client.get('/en/account/register/') + response = self.client.get("/en/account/register/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'en') - self.assertEqual(response.context['LANGUAGE_CODE'], 'en') + self.assertEqual(response.headers["content-language"], "en") + self.assertEqual(response.context["LANGUAGE_CODE"], "en") def test_nl_url(self): - response = self.client.get('/nl/profiel/registreren/') + response = self.client.get("/nl/profiel/registreren/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'nl') - self.assertEqual(response.context['LANGUAGE_CODE'], 'nl') + self.assertEqual(response.headers["content-language"], "nl") + self.assertEqual(response.context["LANGUAGE_CODE"], "nl") def test_wrong_en_prefix(self): - response = self.client.get('/en/profiel/registreren/') + response = self.client.get("/en/profiel/registreren/") self.assertEqual(response.status_code, 404) def test_wrong_nl_prefix(self): - response = self.client.get('/nl/account/register/') + response = self.client.get("/nl/account/register/") self.assertEqual(response.status_code, 404) def test_pt_br_url(self): - response = self.client.get('/pt-br/conta/registre-se/') + response = self.client.get("/pt-br/conta/registre-se/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'pt-br') - self.assertEqual(response.context['LANGUAGE_CODE'], 'pt-br') + self.assertEqual(response.headers["content-language"], "pt-br") + self.assertEqual(response.context["LANGUAGE_CODE"], "pt-br") def test_en_path(self): - response = self.client.get('/en/account/register-as-path/') + response = self.client.get("/en/account/register-as-path/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'en') - self.assertEqual(response.context['LANGUAGE_CODE'], 'en') + self.assertEqual(response.headers["content-language"], "en") + self.assertEqual(response.context["LANGUAGE_CODE"], "en") def test_nl_path(self): - response = self.client.get('/nl/profiel/registreren-als-pad/') + response = self.client.get("/nl/profiel/registreren-als-pad/") self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers['content-language'], 'nl') - self.assertEqual(response.context['LANGUAGE_CODE'], 'nl') + self.assertEqual(response.headers["content-language"], "nl") + self.assertEqual(response.context["LANGUAGE_CODE"], "nl") class URLRedirectWithScriptAliasTests(URLTestCaseBase): """ #21579 - LocaleMiddleware should respect the script prefix. """ + def test_language_prefix_with_script_prefix(self): - prefix = '/script_prefix' + prefix = "/script_prefix" with override_script_prefix(prefix): - response = self.client.get('/prefixed/', HTTP_ACCEPT_LANGUAGE='en', SCRIPT_NAME=prefix) - self.assertRedirects(response, '%s/en/prefixed/' % prefix, target_status_code=404) + response = self.client.get( + "/prefixed/", HTTP_ACCEPT_LANGUAGE="en", SCRIPT_NAME=prefix + ) + self.assertRedirects( + response, "%s/en/prefixed/" % prefix, target_status_code=404 + ) class URLTagTests(URLTestCaseBase): """ Test if the language tag works. """ + def test_strings_only(self): - t = Template("""{% load i18n %} + t = Template( + """{% load i18n %} {% language 'nl' %}{% url 'no-prefix-translated' %}{% endlanguage %} - {% language 'pt-br' %}{% url 'no-prefix-translated' %}{% endlanguage %}""") - self.assertEqual(t.render(Context({})).strip().split(), - ['/vertaald/', '/traduzidos/']) + {% language 'pt-br' %}{% url 'no-prefix-translated' %}{% endlanguage %}""" + ) + self.assertEqual( + t.render(Context({})).strip().split(), ["/vertaald/", "/traduzidos/"] + ) def test_context(self): - ctx = Context({'lang1': 'nl', 'lang2': 'pt-br'}) - tpl = Template("""{% load i18n %} + ctx = Context({"lang1": "nl", "lang2": "pt-br"}) + tpl = Template( + """{% load i18n %} {% language lang1 %}{% url 'no-prefix-translated' %}{% endlanguage %} - {% language lang2 %}{% url 'no-prefix-translated' %}{% endlanguage %}""") - self.assertEqual(tpl.render(ctx).strip().split(), - ['/vertaald/', '/traduzidos/']) + {% language lang2 %}{% url 'no-prefix-translated' %}{% endlanguage %}""" + ) + self.assertEqual( + tpl.render(ctx).strip().split(), ["/vertaald/", "/traduzidos/"] + ) def test_args(self): - tpl = Template("""{% load i18n %} + tpl = Template( + """{% load i18n %} {% language 'nl' %}{% url 'no-prefix-translated-slug' 'apo' %}{% endlanguage %} - {% language 'pt-br' %}{% url 'no-prefix-translated-slug' 'apo' %}{% endlanguage %}""") - self.assertEqual(tpl.render(Context({})).strip().split(), - ['/vertaald/apo/', '/traduzidos/apo/']) + {% language 'pt-br' %}{% url 'no-prefix-translated-slug' 'apo' %}{% endlanguage %}""" + ) + self.assertEqual( + tpl.render(Context({})).strip().split(), + ["/vertaald/apo/", "/traduzidos/apo/"], + ) def test_kwargs(self): - tpl = Template("""{% load i18n %} + tpl = Template( + """{% load i18n %} {% language 'nl' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %} - {% language 'pt-br' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}""") - self.assertEqual(tpl.render(Context({})).strip().split(), - ['/vertaald/apo/', '/traduzidos/apo/']) + {% language 'pt-br' %}{% url 'no-prefix-translated-slug' slug='apo' %}{% endlanguage %}""" + ) + self.assertEqual( + tpl.render(Context({})).strip().split(), + ["/vertaald/apo/", "/traduzidos/apo/"], + ) diff --git a/tests/i18n/patterns/urls/default.py b/tests/i18n/patterns/urls/default.py index 22fff166b3..c77bf98c73 100644 --- a/tests/i18n/patterns/urls/default.py +++ b/tests/i18n/patterns/urls/default.py @@ -3,23 +3,27 @@ from django.urls import include, path, re_path from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") urlpatterns = [ - path('not-prefixed/', view, name='not-prefixed'), - path('not-prefixed-include/', include('i18n.patterns.urls.included')), - re_path(_(r'^translated/$'), view, name='no-prefix-translated'), - re_path(_(r'^translated/(?P<slug>[\w-]+)/$'), view, name='no-prefix-translated-slug'), + path("not-prefixed/", view, name="not-prefixed"), + path("not-prefixed-include/", include("i18n.patterns.urls.included")), + re_path(_(r"^translated/$"), view, name="no-prefix-translated"), + re_path( + _(r"^translated/(?P<slug>[\w-]+)/$"), view, name="no-prefix-translated-slug" + ), ] urlpatterns += i18n_patterns( - path('prefixed/', view, name='prefixed'), - path('prefixed.xml', view, name='prefixed_xml'), + path("prefixed/", view, name="prefixed"), + path("prefixed.xml", view, name="prefixed_xml"), re_path( - _(r'^with-arguments/(?P<argument>[\w-]+)/(?:(?P<optional>[\w-]+).html)?$'), + _(r"^with-arguments/(?P<argument>[\w-]+)/(?:(?P<optional>[\w-]+).html)?$"), view, - name='with-arguments', + name="with-arguments", + ), + re_path(_(r"^users/$"), view, name="users"), + re_path( + _(r"^account/"), include("i18n.patterns.urls.namespace", namespace="account") ), - re_path(_(r'^users/$'), view, name='users'), - re_path(_(r'^account/'), include('i18n.patterns.urls.namespace', namespace='account')), ) diff --git a/tests/i18n/patterns/urls/disabled.py b/tests/i18n/patterns/urls/disabled.py index 48b0201fe3..11dfe320b0 100644 --- a/tests/i18n/patterns/urls/disabled.py +++ b/tests/i18n/patterns/urls/disabled.py @@ -2,8 +2,8 @@ from django.conf.urls.i18n import i18n_patterns from django.urls import path from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") urlpatterns = i18n_patterns( - path('prefixed/', view, name='prefixed'), + path("prefixed/", view, name="prefixed"), ) diff --git a/tests/i18n/patterns/urls/included.py b/tests/i18n/patterns/urls/included.py index 75658dc961..733e38962a 100644 --- a/tests/i18n/patterns/urls/included.py +++ b/tests/i18n/patterns/urls/included.py @@ -1,8 +1,8 @@ from django.urls import path from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") urlpatterns = [ - path('foo/', view, name='not-prefixed-included-url'), + path("foo/", view, name="not-prefixed-included-url"), ] diff --git a/tests/i18n/patterns/urls/namespace.py b/tests/i18n/patterns/urls/namespace.py index 19cd5694da..466303ac6d 100644 --- a/tests/i18n/patterns/urls/namespace.py +++ b/tests/i18n/patterns/urls/namespace.py @@ -2,11 +2,11 @@ from django.urls import path, re_path from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") -app_name = 'account' +app_name = "account" urlpatterns = [ - re_path(_(r'^register/$'), view, name='register'), - re_path(_(r'^register-without-slash$'), view, name='register-without-slash'), - path(_('register-as-path/'), view, name='register-as-path'), + re_path(_(r"^register/$"), view, name="register"), + re_path(_(r"^register-without-slash$"), view, name="register-without-slash"), + path(_("register-as-path/"), view, name="register-as-path"), ] diff --git a/tests/i18n/patterns/urls/path_unused.py b/tests/i18n/patterns/urls/path_unused.py index 2784d286a1..3df4b46c4c 100644 --- a/tests/i18n/patterns/urls/path_unused.py +++ b/tests/i18n/patterns/urls/path_unused.py @@ -1,8 +1,8 @@ from django.urls import re_path from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") urlpatterns = [ - re_path('^nl/foo/', view, name='not-translated'), + re_path("^nl/foo/", view, name="not-translated"), ] diff --git a/tests/i18n/patterns/urls/wrong.py b/tests/i18n/patterns/urls/wrong.py index 46b4b69718..b4a2e0e16b 100644 --- a/tests/i18n/patterns/urls/wrong.py +++ b/tests/i18n/patterns/urls/wrong.py @@ -3,5 +3,8 @@ from django.urls import include, re_path from django.utils.translation import gettext_lazy as _ urlpatterns = i18n_patterns( - re_path(_(r'^account/'), include('i18n.patterns.urls.wrong_namespace', namespace='account')), + re_path( + _(r"^account/"), + include("i18n.patterns.urls.wrong_namespace", namespace="account"), + ), ) diff --git a/tests/i18n/patterns/urls/wrong_namespace.py b/tests/i18n/patterns/urls/wrong_namespace.py index 7800d90e3c..527dff4543 100644 --- a/tests/i18n/patterns/urls/wrong_namespace.py +++ b/tests/i18n/patterns/urls/wrong_namespace.py @@ -3,9 +3,9 @@ from django.urls import re_path from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView -view = TemplateView.as_view(template_name='dummy.html') +view = TemplateView.as_view(template_name="dummy.html") -app_name = 'account' +app_name = "account" urlpatterns = i18n_patterns( - re_path(_(r'^register/$'), view, name='register'), + re_path(_(r"^register/$"), view, name="register"), ) diff --git a/tests/i18n/sampleproject/manage.py b/tests/i18n/sampleproject/manage.py index 87a0ec369a..717bf4e28f 100755 --- a/tests/i18n/sampleproject/manage.py +++ b/tests/i18n/sampleproject/manage.py @@ -2,7 +2,7 @@ import os import sys -sys.path.append(os.path.abspath(os.path.join('..', '..', '..'))) +sys.path.append(os.path.abspath(os.path.join("..", "..", ".."))) if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sampleproject.settings") diff --git a/tests/i18n/sampleproject/update_catalogs.py b/tests/i18n/sampleproject/update_catalogs.py index 55bf1656a2..8780f629e4 100755 --- a/tests/i18n/sampleproject/update_catalogs.py +++ b/tests/i18n/sampleproject/update_catalogs.py @@ -31,7 +31,7 @@ import re import sys proj_dir = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(os.path.abspath(os.path.join(proj_dir, '..', '..', '..'))) +sys.path.append(os.path.abspath(os.path.join(proj_dir, "..", "..", ".."))) def update_translation_catalogs(): @@ -41,16 +41,16 @@ def update_translation_catalogs(): prev_cwd = os.getcwd() os.chdir(proj_dir) - call_command('makemessages') - call_command('compilemessages') + call_command("makemessages") + call_command("compilemessages") # keep the diff friendly - remove 'POT-Creation-Date' - pofile = os.path.join(proj_dir, 'locale', 'fr', 'LC_MESSAGES', 'django.po') + pofile = os.path.join(proj_dir, "locale", "fr", "LC_MESSAGES", "django.po") with open(pofile) as f: content = f.read() - content = re.sub(r'^"POT-Creation-Date.+$\s', '', content, flags=re.MULTILINE) - with open(pofile, 'w') as f: + content = re.sub(r'^"POT-Creation-Date.+$\s', "", content, flags=re.MULTILINE) + with open(pofile, "w") as f: f.write(content) os.chdir(prev_cwd) diff --git a/tests/i18n/test_compilation.py b/tests/i18n/test_compilation.py index 299c07a93f..259a9668b8 100644 --- a/tests/i18n/test_compilation.py +++ b/tests/i18n/test_compilation.py @@ -7,12 +7,8 @@ from pathlib import Path from subprocess import run from unittest import mock -from django.core.management import ( - CommandError, call_command, execute_from_command_line, -) -from django.core.management.commands.makemessages import ( - Command as MakeMessagesCommand, -) +from django.core.management import CommandError, call_command, execute_from_command_line +from django.core.management.commands.makemessages import Command as MakeMessagesCommand from django.core.management.utils import find_command from django.test import SimpleTestCase, override_settings from django.test.utils import captured_stderr, captured_stdout @@ -21,26 +17,30 @@ from django.utils.translation import gettext from .utils import RunInTmpDirMixin, copytree -has_msgfmt = find_command('msgfmt') +has_msgfmt = find_command("msgfmt") -@unittest.skipUnless(has_msgfmt, 'msgfmt is mandatory for compilation tests') +@unittest.skipUnless(has_msgfmt, "msgfmt is mandatory for compilation tests") class MessageCompilationTests(RunInTmpDirMixin, SimpleTestCase): - work_subdir = 'commands' + work_subdir = "commands" class PoFileTests(MessageCompilationTests): - LOCALE = 'es_AR' - MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE - MO_FILE_EN = 'locale/en/LC_MESSAGES/django.mo' + LOCALE = "es_AR" + MO_FILE = "locale/%s/LC_MESSAGES/django.mo" % LOCALE + MO_FILE_EN = "locale/en/LC_MESSAGES/django.mo" def test_bom_rejection(self): stderr = StringIO() - with self.assertRaisesMessage(CommandError, 'compilemessages generated one or more errors.'): - call_command('compilemessages', locale=[self.LOCALE], verbosity=0, stderr=stderr) - self.assertIn('file has a BOM (Byte Order Mark)', stderr.getvalue()) + with self.assertRaisesMessage( + CommandError, "compilemessages generated one or more errors." + ): + call_command( + "compilemessages", locale=[self.LOCALE], verbosity=0, stderr=stderr + ) + self.assertIn("file has a BOM (Byte Order Mark)", stderr.getvalue()) self.assertFalse(os.path.exists(self.MO_FILE)) def test_no_write_access(self): @@ -50,11 +50,15 @@ class PoFileTests(MessageCompilationTests): old_mode = mo_file_en.stat().st_mode mo_file_en.chmod(stat.S_IREAD) # Ensure .po file is more recent than .mo file. - mo_file_en.with_suffix('.po').touch() + mo_file_en.with_suffix(".po").touch() try: - with self.assertRaisesMessage(CommandError, 'compilemessages generated one or more errors.'): - call_command('compilemessages', locale=['en'], stderr=err_buffer, verbosity=0) - self.assertIn('not writable location', err_buffer.getvalue()) + with self.assertRaisesMessage( + CommandError, "compilemessages generated one or more errors." + ): + call_command( + "compilemessages", locale=["en"], stderr=err_buffer, verbosity=0 + ) + self.assertIn("not writable location", err_buffer.getvalue()) finally: mo_file_en.chmod(old_mode) @@ -62,19 +66,19 @@ class PoFileTests(MessageCompilationTests): mo_file_en = Path(self.MO_FILE_EN) mo_file_en.touch() stdout = StringIO() - call_command('compilemessages', locale=['en'], stdout=stdout, verbosity=1) - msg = '%s” is already compiled and up to date.' % mo_file_en.with_suffix('.po') + call_command("compilemessages", locale=["en"], stdout=stdout, verbosity=1) + msg = "%s” is already compiled and up to date." % mo_file_en.with_suffix(".po") self.assertIn(msg, stdout.getvalue()) class PoFileContentsTests(MessageCompilationTests): # Ticket #11240 - LOCALE = 'fr' - MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE + LOCALE = "fr" + MO_FILE = "locale/%s/LC_MESSAGES/django.mo" % LOCALE def test_percent_symbol_in_po_file(self): - call_command('compilemessages', locale=[self.LOCALE], verbosity=0) + call_command("compilemessages", locale=[self.LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.MO_FILE)) @@ -85,19 +89,19 @@ class MultipleLocaleCompilationTests(MessageCompilationTests): def setUp(self): super().setUp() - localedir = os.path.join(self.test_dir, 'locale') - self.MO_FILE_HR = os.path.join(localedir, 'hr/LC_MESSAGES/django.mo') - self.MO_FILE_FR = os.path.join(localedir, 'fr/LC_MESSAGES/django.mo') + localedir = os.path.join(self.test_dir, "locale") + self.MO_FILE_HR = os.path.join(localedir, "hr/LC_MESSAGES/django.mo") + self.MO_FILE_FR = os.path.join(localedir, "fr/LC_MESSAGES/django.mo") def test_one_locale(self): - with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]): - call_command('compilemessages', locale=['hr'], verbosity=0) + with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, "locale")]): + call_command("compilemessages", locale=["hr"], verbosity=0) self.assertTrue(os.path.exists(self.MO_FILE_HR)) def test_multiple_locales(self): - with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]): - call_command('compilemessages', locale=['hr', 'fr'], verbosity=0) + with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, "locale")]): + call_command("compilemessages", locale=["hr", "fr"], verbosity=0) self.assertTrue(os.path.exists(self.MO_FILE_HR)) self.assertTrue(os.path.exists(self.MO_FILE_FR)) @@ -105,144 +109,164 @@ class MultipleLocaleCompilationTests(MessageCompilationTests): class ExcludedLocaleCompilationTests(MessageCompilationTests): - work_subdir = 'exclude' + work_subdir = "exclude" - MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' + MO_FILE = "locale/%s/LC_MESSAGES/django.mo" def setUp(self): super().setUp() - copytree('canned_locale', 'locale') + copytree("canned_locale", "locale") def test_command_help(self): with captured_stdout(), captured_stderr(): # `call_command` bypasses the parser; by calling # `execute_from_command_line` with the help subcommand we # ensure that there are no issues with the parser itself. - execute_from_command_line(['django-admin', 'help', 'compilemessages']) + execute_from_command_line(["django-admin", "help", "compilemessages"]) def test_one_locale_excluded(self): - call_command('compilemessages', exclude=['it'], verbosity=0) - self.assertTrue(os.path.exists(self.MO_FILE % 'en')) - self.assertTrue(os.path.exists(self.MO_FILE % 'fr')) - self.assertFalse(os.path.exists(self.MO_FILE % 'it')) + call_command("compilemessages", exclude=["it"], verbosity=0) + self.assertTrue(os.path.exists(self.MO_FILE % "en")) + self.assertTrue(os.path.exists(self.MO_FILE % "fr")) + self.assertFalse(os.path.exists(self.MO_FILE % "it")) def test_multiple_locales_excluded(self): - call_command('compilemessages', exclude=['it', 'fr'], verbosity=0) - self.assertTrue(os.path.exists(self.MO_FILE % 'en')) - self.assertFalse(os.path.exists(self.MO_FILE % 'fr')) - self.assertFalse(os.path.exists(self.MO_FILE % 'it')) + call_command("compilemessages", exclude=["it", "fr"], verbosity=0) + self.assertTrue(os.path.exists(self.MO_FILE % "en")) + self.assertFalse(os.path.exists(self.MO_FILE % "fr")) + self.assertFalse(os.path.exists(self.MO_FILE % "it")) def test_one_locale_excluded_with_locale(self): - call_command('compilemessages', locale=['en', 'fr'], exclude=['fr'], verbosity=0) - self.assertTrue(os.path.exists(self.MO_FILE % 'en')) - self.assertFalse(os.path.exists(self.MO_FILE % 'fr')) - self.assertFalse(os.path.exists(self.MO_FILE % 'it')) + call_command( + "compilemessages", locale=["en", "fr"], exclude=["fr"], verbosity=0 + ) + self.assertTrue(os.path.exists(self.MO_FILE % "en")) + self.assertFalse(os.path.exists(self.MO_FILE % "fr")) + self.assertFalse(os.path.exists(self.MO_FILE % "it")) def test_multiple_locales_excluded_with_locale(self): - call_command('compilemessages', locale=['en', 'fr', 'it'], exclude=['fr', 'it'], verbosity=0) - self.assertTrue(os.path.exists(self.MO_FILE % 'en')) - self.assertFalse(os.path.exists(self.MO_FILE % 'fr')) - self.assertFalse(os.path.exists(self.MO_FILE % 'it')) + call_command( + "compilemessages", + locale=["en", "fr", "it"], + exclude=["fr", "it"], + verbosity=0, + ) + self.assertTrue(os.path.exists(self.MO_FILE % "en")) + self.assertFalse(os.path.exists(self.MO_FILE % "fr")) + self.assertFalse(os.path.exists(self.MO_FILE % "it")) class IgnoreDirectoryCompilationTests(MessageCompilationTests): # Reuse the exclude directory since it contains some locale fixtures. - work_subdir = 'exclude' - MO_FILE = '%s/%s/LC_MESSAGES/django.mo' - CACHE_DIR = Path('cache') / 'locale' - NESTED_DIR = Path('outdated') / 'v1' / 'locale' + work_subdir = "exclude" + MO_FILE = "%s/%s/LC_MESSAGES/django.mo" + CACHE_DIR = Path("cache") / "locale" + NESTED_DIR = Path("outdated") / "v1" / "locale" def setUp(self): super().setUp() - copytree('canned_locale', 'locale') - copytree('canned_locale', self.CACHE_DIR) - copytree('canned_locale', self.NESTED_DIR) + copytree("canned_locale", "locale") + copytree("canned_locale", self.CACHE_DIR) + copytree("canned_locale", self.NESTED_DIR) def assertAllExist(self, dir, langs): - self.assertTrue(all(Path(self.MO_FILE % (dir, lang)).exists() for lang in langs)) + self.assertTrue( + all(Path(self.MO_FILE % (dir, lang)).exists() for lang in langs) + ) def assertNoneExist(self, dir, langs): - self.assertTrue(all(Path(self.MO_FILE % (dir, lang)).exists() is False for lang in langs)) + self.assertTrue( + all(Path(self.MO_FILE % (dir, lang)).exists() is False for lang in langs) + ) def test_one_locale_dir_ignored(self): - call_command('compilemessages', ignore=['cache'], verbosity=0) - self.assertAllExist('locale', ['en', 'fr', 'it']) - self.assertNoneExist(self.CACHE_DIR, ['en', 'fr', 'it']) - self.assertAllExist(self.NESTED_DIR, ['en', 'fr', 'it']) + call_command("compilemessages", ignore=["cache"], verbosity=0) + self.assertAllExist("locale", ["en", "fr", "it"]) + self.assertNoneExist(self.CACHE_DIR, ["en", "fr", "it"]) + self.assertAllExist(self.NESTED_DIR, ["en", "fr", "it"]) def test_multiple_locale_dirs_ignored(self): - call_command('compilemessages', ignore=['cache/locale', 'outdated'], verbosity=0) - self.assertAllExist('locale', ['en', 'fr', 'it']) - self.assertNoneExist(self.CACHE_DIR, ['en', 'fr', 'it']) - self.assertNoneExist(self.NESTED_DIR, ['en', 'fr', 'it']) + call_command( + "compilemessages", ignore=["cache/locale", "outdated"], verbosity=0 + ) + self.assertAllExist("locale", ["en", "fr", "it"]) + self.assertNoneExist(self.CACHE_DIR, ["en", "fr", "it"]) + self.assertNoneExist(self.NESTED_DIR, ["en", "fr", "it"]) def test_ignores_based_on_pattern(self): - call_command('compilemessages', ignore=['*/locale'], verbosity=0) - self.assertAllExist('locale', ['en', 'fr', 'it']) - self.assertNoneExist(self.CACHE_DIR, ['en', 'fr', 'it']) - self.assertNoneExist(self.NESTED_DIR, ['en', 'fr', 'it']) + call_command("compilemessages", ignore=["*/locale"], verbosity=0) + self.assertAllExist("locale", ["en", "fr", "it"]) + self.assertNoneExist(self.CACHE_DIR, ["en", "fr", "it"]) + self.assertNoneExist(self.NESTED_DIR, ["en", "fr", "it"]) class CompilationErrorHandling(MessageCompilationTests): def test_error_reported_by_msgfmt(self): # po file contains wrong po formatting. with self.assertRaises(CommandError): - call_command('compilemessages', locale=['ja'], verbosity=0) + call_command("compilemessages", locale=["ja"], verbosity=0) def test_msgfmt_error_including_non_ascii(self): # po file contains invalid msgstr content (triggers non-ascii error content). # Make sure the output of msgfmt is unaffected by the current locale. env = os.environ.copy() - env.update({'LC_ALL': 'C'}) - with mock.patch('django.core.management.utils.run', lambda *args, **kwargs: run(*args, env=env, **kwargs)): + env.update({"LC_ALL": "C"}) + with mock.patch( + "django.core.management.utils.run", + lambda *args, **kwargs: run(*args, env=env, **kwargs), + ): cmd = MakeMessagesCommand() if cmd.gettext_version < (0, 18, 3): self.skipTest("python-brace-format is a recent gettext addition.") stderr = StringIO() - with self.assertRaisesMessage(CommandError, 'compilemessages generated one or more errors'): - call_command('compilemessages', locale=['ko'], stdout=StringIO(), stderr=stderr) + with self.assertRaisesMessage( + CommandError, "compilemessages generated one or more errors" + ): + call_command( + "compilemessages", locale=["ko"], stdout=StringIO(), stderr=stderr + ) self.assertIn("' cannot start a field name", stderr.getvalue()) class ProjectAndAppTests(MessageCompilationTests): - LOCALE = 'ru' - PROJECT_MO_FILE = 'locale/%s/LC_MESSAGES/django.mo' % LOCALE - APP_MO_FILE = 'app_with_locale/locale/%s/LC_MESSAGES/django.mo' % LOCALE + LOCALE = "ru" + PROJECT_MO_FILE = "locale/%s/LC_MESSAGES/django.mo" % LOCALE + APP_MO_FILE = "app_with_locale/locale/%s/LC_MESSAGES/django.mo" % LOCALE class FuzzyTranslationTest(ProjectAndAppTests): - def setUp(self): super().setUp() gettext_module._translations = {} # flush cache or test will be useless def test_nofuzzy_compiling(self): - with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]): - call_command('compilemessages', locale=[self.LOCALE], verbosity=0) + with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, "locale")]): + call_command("compilemessages", locale=[self.LOCALE], verbosity=0) with translation.override(self.LOCALE): - self.assertEqual(gettext('Lenin'), 'Ленин') - self.assertEqual(gettext('Vodka'), 'Vodka') + self.assertEqual(gettext("Lenin"), "Ленин") + self.assertEqual(gettext("Vodka"), "Vodka") def test_fuzzy_compiling(self): - with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, 'locale')]): - call_command('compilemessages', locale=[self.LOCALE], fuzzy=True, verbosity=0) + with override_settings(LOCALE_PATHS=[os.path.join(self.test_dir, "locale")]): + call_command( + "compilemessages", locale=[self.LOCALE], fuzzy=True, verbosity=0 + ) with translation.override(self.LOCALE): - self.assertEqual(gettext('Lenin'), 'Ленин') - self.assertEqual(gettext('Vodka'), 'Водка') + self.assertEqual(gettext("Lenin"), "Ленин") + self.assertEqual(gettext("Vodka"), "Водка") class AppCompilationTest(ProjectAndAppTests): - def test_app_locale_compiled(self): - call_command('compilemessages', locale=[self.LOCALE], verbosity=0) + call_command("compilemessages", locale=[self.LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PROJECT_MO_FILE)) self.assertTrue(os.path.exists(self.APP_MO_FILE)) class PathLibLocaleCompilationTests(MessageCompilationTests): - work_subdir = 'exclude' + work_subdir = "exclude" def test_locale_paths_pathlib(self): - with override_settings(LOCALE_PATHS=[Path(self.test_dir) / 'canned_locale']): - call_command('compilemessages', locale=['fr'], verbosity=0) - self.assertTrue(os.path.exists('canned_locale/fr/LC_MESSAGES/django.mo')) + with override_settings(LOCALE_PATHS=[Path(self.test_dir) / "canned_locale"]): + call_command("compilemessages", locale=["fr"], verbosity=0) + self.assertTrue(os.path.exists("canned_locale/fr/LC_MESSAGES/django.mo")) diff --git a/tests/i18n/test_extraction.py b/tests/i18n/test_extraction.py index 98932fdcbb..c4aeef7339 100644 --- a/tests/i18n/test_extraction.py +++ b/tests/i18n/test_extraction.py @@ -13,9 +13,8 @@ from admin_scripts.tests import AdminScriptTestCase from django.core import management from django.core.management import execute_from_command_line from django.core.management.base import CommandError -from django.core.management.commands.makemessages import ( - Command as MakeMessagesCommand, write_pot_file, -) +from django.core.management.commands.makemessages import Command as MakeMessagesCommand +from django.core.management.commands.makemessages import write_pot_file from django.core.management.utils import find_command from django.test import SimpleTestCase, override_settings from django.test.utils import captured_stderr, captured_stdout @@ -24,22 +23,26 @@ from django.utils.translation import TranslatorCommentWarning from .utils import POFileAssertionMixin, RunInTmpDirMixin, copytree -LOCALE = 'de' -has_xgettext = find_command('xgettext') +LOCALE = "de" +has_xgettext = find_command("xgettext") gettext_version = MakeMessagesCommand().gettext_version if has_xgettext else None -requires_gettext_019 = skipIf(has_xgettext and gettext_version < (0, 19), 'gettext 0.19 required') +requires_gettext_019 = skipIf( + has_xgettext and gettext_version < (0, 19), "gettext 0.19 required" +) -@skipUnless(has_xgettext, 'xgettext is mandatory for extraction tests') +@skipUnless(has_xgettext, "xgettext is mandatory for extraction tests") class ExtractorTests(POFileAssertionMixin, RunInTmpDirMixin, SimpleTestCase): - work_subdir = 'commands' + work_subdir = "commands" - PO_FILE = 'locale/%s/LC_MESSAGES/django.po' % LOCALE + PO_FILE = "locale/%s/LC_MESSAGES/django.po" % LOCALE def _run_makemessages(self, **options): out = StringIO() - management.call_command('makemessages', locale=[LOCALE], verbosity=2, stdout=out, **options) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=2, stdout=out, **options + ) output = out.getvalue() self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: @@ -47,26 +50,30 @@ class ExtractorTests(POFileAssertionMixin, RunInTmpDirMixin, SimpleTestCase): return output, po_contents def assertMsgIdPlural(self, msgid, haystack, use_quotes=True): - return self._assertPoKeyword('msgid_plural', msgid, haystack, use_quotes=use_quotes) + return self._assertPoKeyword( + "msgid_plural", msgid, haystack, use_quotes=use_quotes + ) def assertMsgStr(self, msgstr, haystack, use_quotes=True): - return self._assertPoKeyword('msgstr', msgstr, haystack, use_quotes=use_quotes) + return self._assertPoKeyword("msgstr", msgstr, haystack, use_quotes=use_quotes) def assertNotMsgId(self, msgid, s, use_quotes=True): if use_quotes: msgid = '"%s"' % msgid msgid = re.escape(msgid) - return self.assertTrue(not re.search('^msgid %s' % msgid, s, re.MULTILINE)) + return self.assertTrue(not re.search("^msgid %s" % msgid, s, re.MULTILINE)) - def _assertPoLocComment(self, assert_presence, po_filename, line_number, *comment_parts): + def _assertPoLocComment( + self, assert_presence, po_filename, line_number, *comment_parts + ): with open(po_filename) as fp: po_contents = fp.read() - if os.name == 'nt': + if os.name == "nt": # #: .\path\to\file.html:123 - cwd_prefix = '%s%s' % (os.curdir, os.sep) + cwd_prefix = "%s%s" % (os.curdir, os.sep) else: # #: path/to/file.html:123 - cwd_prefix = '' + cwd_prefix = "" path = os.path.join(cwd_prefix, *comment_parts) parts = [path] @@ -74,21 +81,28 @@ class ExtractorTests(POFileAssertionMixin, RunInTmpDirMixin, SimpleTestCase): if isinstance(line_number, str): line_number = self._get_token_line_number(path, line_number) if line_number is not None: - parts.append(':%d' % line_number) + parts.append(":%d" % line_number) - needle = ''.join(parts) - pattern = re.compile(r'^\#\:.*' + re.escape(needle), re.MULTILINE) + needle = "".join(parts) + pattern = re.compile(r"^\#\:.*" + re.escape(needle), re.MULTILINE) if assert_presence: - return self.assertRegex(po_contents, pattern, '"%s" not found in final .po file.' % needle) + return self.assertRegex( + po_contents, pattern, '"%s" not found in final .po file.' % needle + ) else: - return self.assertNotRegex(po_contents, pattern, '"%s" shouldn\'t be in final .po file.' % needle) + return self.assertNotRegex( + po_contents, pattern, '"%s" shouldn\'t be in final .po file.' % needle + ) def _get_token_line_number(self, path, token): with open(path) as f: for line, content in enumerate(f, 1): if token in content: return line - self.fail("The token '%s' could not be found in %s, please check the test config" % (token, path)) + self.fail( + "The token '%s' could not be found in %s, please check the test config" + % (token, path) + ) def assertLocationCommentPresent(self, po_filename, line_number, *comment_parts): r""" @@ -128,123 +142,147 @@ class ExtractorTests(POFileAssertionMixin, RunInTmpDirMixin, SimpleTestCase): class BasicExtractorTests(ExtractorTests): - @override_settings(USE_I18N=False) def test_use_i18n_false(self): """ makemessages also runs successfully when USE_I18N is False. """ - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) - with open(self.PO_FILE, encoding='utf-8') as fp: + with open(self.PO_FILE, encoding="utf-8") as fp: po_contents = fp.read() # Check two random strings - self.assertIn('#. Translators: One-line translator comment #1', po_contents) + self.assertIn("#. Translators: One-line translator comment #1", po_contents) self.assertIn('msgctxt "Special trans context #1"', po_contents) def test_no_option(self): # One of either the --locale, --exclude, or --all options is required. msg = "Type 'manage.py help makemessages' for usage information." with mock.patch( - 'django.core.management.commands.makemessages.sys.argv', - ['manage.py', 'makemessages'], + "django.core.management.commands.makemessages.sys.argv", + ["manage.py", "makemessages"], ): with self.assertRaisesRegex(CommandError, msg): - management.call_command('makemessages') + management.call_command("makemessages") def test_valid_locale(self): out = StringIO() - management.call_command('makemessages', locale=['de'], stdout=out, verbosity=1) - self.assertNotIn('invalid locale de', out.getvalue()) - self.assertIn('processing locale de', out.getvalue()) + management.call_command("makemessages", locale=["de"], stdout=out, verbosity=1) + self.assertNotIn("invalid locale de", out.getvalue()) + self.assertIn("processing locale de", out.getvalue()) self.assertIs(Path(self.PO_FILE).exists(), True) def test_invalid_locale(self): out = StringIO() - management.call_command('makemessages', locale=['pl-PL'], stdout=out, verbosity=1) - self.assertIn('invalid locale pl-PL, did you mean pl_PL?', out.getvalue()) - self.assertNotIn('processing locale pl-PL', out.getvalue()) - self.assertIs(Path('locale/pl-PL/LC_MESSAGES/django.po').exists(), False) + management.call_command( + "makemessages", locale=["pl-PL"], stdout=out, verbosity=1 + ) + self.assertIn("invalid locale pl-PL, did you mean pl_PL?", out.getvalue()) + self.assertNotIn("processing locale pl-PL", out.getvalue()) + self.assertIs(Path("locale/pl-PL/LC_MESSAGES/django.po").exists(), False) def test_comments_extractor(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) - with open(self.PO_FILE, encoding='utf-8') as fp: + with open(self.PO_FILE, encoding="utf-8") as fp: po_contents = fp.read() - self.assertNotIn('This comment should not be extracted', po_contents) + self.assertNotIn("This comment should not be extracted", po_contents) # Comments in templates - self.assertIn('#. Translators: This comment should be extracted', po_contents) + self.assertIn( + "#. Translators: This comment should be extracted", po_contents + ) self.assertIn( "#. Translators: Django comment block for translators\n#. " "string's meaning unveiled", - po_contents + po_contents, + ) + self.assertIn("#. Translators: One-line translator comment #1", po_contents) + self.assertIn( + "#. Translators: Two-line translator comment #1\n#. continued here.", + po_contents, + ) + self.assertIn("#. Translators: One-line translator comment #2", po_contents) + self.assertIn( + "#. Translators: Two-line translator comment #2\n#. continued here.", + po_contents, + ) + self.assertIn("#. Translators: One-line translator comment #3", po_contents) + self.assertIn( + "#. Translators: Two-line translator comment #3\n#. continued here.", + po_contents, + ) + self.assertIn("#. Translators: One-line translator comment #4", po_contents) + self.assertIn( + "#. Translators: Two-line translator comment #4\n#. continued here.", + po_contents, ) - self.assertIn('#. Translators: One-line translator comment #1', po_contents) - self.assertIn('#. Translators: Two-line translator comment #1\n#. continued here.', po_contents) - self.assertIn('#. Translators: One-line translator comment #2', po_contents) - self.assertIn('#. Translators: Two-line translator comment #2\n#. continued here.', po_contents) - self.assertIn('#. Translators: One-line translator comment #3', po_contents) - self.assertIn('#. Translators: Two-line translator comment #3\n#. continued here.', po_contents) - self.assertIn('#. Translators: One-line translator comment #4', po_contents) - self.assertIn('#. Translators: Two-line translator comment #4\n#. continued here.', po_contents) self.assertIn( - '#. Translators: One-line translator comment #5 -- with ' - 'non ASCII characters: áéíóúö', - po_contents + "#. Translators: One-line translator comment #5 -- with " + "non ASCII characters: áéíóúö", + po_contents, ) self.assertIn( - '#. Translators: Two-line translator comment #5 -- with ' - 'non ASCII characters: áéíóúö\n#. continued here.', - po_contents + "#. Translators: Two-line translator comment #5 -- with " + "non ASCII characters: áéíóúö\n#. continued here.", + po_contents, ) def test_special_char_extracted(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) - with open(self.PO_FILE, encoding='utf-8') as fp: + with open(self.PO_FILE, encoding="utf-8") as fp: po_contents = fp.read() self.assertMsgId("Non-breaking space\u00a0:", po_contents) def test_blocktranslate_trimmed(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() # should not be trimmed - self.assertNotMsgId('Text with a few line breaks.', po_contents) + self.assertNotMsgId("Text with a few line breaks.", po_contents) # should be trimmed - self.assertMsgId("Again some text with a few line breaks, this time should be trimmed.", po_contents) + self.assertMsgId( + "Again some text with a few line breaks, this time should be trimmed.", + po_contents, + ) # #21406 -- Should adjust for eaten line numbers self.assertMsgId("Get my line number", po_contents) - self.assertLocationCommentPresent(self.PO_FILE, 'Get my line number', 'templates', 'test.html') + self.assertLocationCommentPresent( + self.PO_FILE, "Get my line number", "templates", "test.html" + ) def test_extraction_error(self): msg = ( - 'Translation blocks must not include other block tags: blocktranslate ' - '(file %s, line 3)' % os.path.join('templates', 'template_with_error.tpl') + "Translation blocks must not include other block tags: blocktranslate " + "(file %s, line 3)" % os.path.join("templates", "template_with_error.tpl") ) with self.assertRaisesMessage(SyntaxError, msg): - management.call_command('makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0) + management.call_command( + "makemessages", locale=[LOCALE], extensions=["tpl"], verbosity=0 + ) # The temporary files were cleaned up. - self.assertFalse(os.path.exists('./templates/template_with_error.tpl.py')) - self.assertFalse(os.path.exists('./templates/template_0_with_no_error.tpl.py')) + self.assertFalse(os.path.exists("./templates/template_with_error.tpl.py")) + self.assertFalse(os.path.exists("./templates/template_0_with_no_error.tpl.py")) def test_unicode_decode_error(self): - shutil.copyfile('./not_utf8.sample', './not_utf8.txt') + shutil.copyfile("./not_utf8.sample", "./not_utf8.txt") out = StringIO() - management.call_command('makemessages', locale=[LOCALE], stdout=out) - self.assertIn("UnicodeDecodeError: skipped file not_utf8.txt in .", out.getvalue()) + management.call_command("makemessages", locale=[LOCALE], stdout=out) + self.assertIn( + "UnicodeDecodeError: skipped file not_utf8.txt in .", out.getvalue() + ) def test_unicode_file_name(self): - open(os.path.join(self.test_dir, 'vidéo.txt'), 'a').close() - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + open(os.path.join(self.test_dir, "vidéo.txt"), "a").close() + management.call_command("makemessages", locale=[LOCALE], verbosity=0) def test_extraction_warning(self): """test xgettext warning about multiple bare interpolation placeholders""" - shutil.copyfile('./code.sample', './code_sample.py') + shutil.copyfile("./code.sample", "./code_sample.py") out = StringIO() - management.call_command('makemessages', locale=[LOCALE], stdout=out) + management.call_command("makemessages", locale=[LOCALE], stdout=out) self.assertIn("code_sample.py:4", out.getvalue()) def test_template_message_context_extractor(self): @@ -252,7 +290,7 @@ class BasicExtractorTests(ExtractorTests): Message contexts are correctly extracted for the {% translate %} and {% blocktranslate %} template tags (#14806). """ - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() @@ -265,9 +303,15 @@ class BasicExtractorTests(ExtractorTests): self.assertMsgId("Translatable literal #7c", po_contents) # {% translate %} with a filter - for minor_part in 'abcdefgh': # Iterate from #7.1a to #7.1h template markers - self.assertIn('msgctxt "context #7.1{}"'.format(minor_part), po_contents) - self.assertMsgId('Translatable literal #7.1{}'.format(minor_part), po_contents) + for ( + minor_part + ) in "abcdefgh": # Iterate from #7.1a to #7.1h template markers + self.assertIn( + 'msgctxt "context #7.1{}"'.format(minor_part), po_contents + ) + self.assertMsgId( + "Translatable literal #7.1{}".format(minor_part), po_contents + ) # {% blocktranslate %} self.assertIn('msgctxt "Special blocktranslate context #1"', po_contents) @@ -282,11 +326,11 @@ class BasicExtractorTests(ExtractorTests): self.assertMsgId("Translatable literal #8d %(a)s", po_contents) # {% trans %} and {% blocktrans %} - self.assertMsgId('trans text', po_contents) - self.assertMsgId('blocktrans text', po_contents) + self.assertMsgId("trans text", po_contents) + self.assertMsgId("blocktrans text", po_contents) def test_context_in_single_quotes(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() @@ -295,16 +339,24 @@ class BasicExtractorTests(ExtractorTests): self.assertIn('msgctxt "Context wrapped in single quotes"', po_contents) # {% blocktranslate %} - self.assertIn('msgctxt "Special blocktranslate context wrapped in double quotes"', po_contents) - self.assertIn('msgctxt "Special blocktranslate context wrapped in single quotes"', po_contents) + self.assertIn( + 'msgctxt "Special blocktranslate context wrapped in double quotes"', + po_contents, + ) + self.assertIn( + 'msgctxt "Special blocktranslate context wrapped in single quotes"', + po_contents, + ) def test_template_comments(self): """Template comment tags on the same line of other constructs (#19552)""" # Test detection/end user reporting of old, incorrect templates # translator comments syntax with warnings.catch_warnings(record=True) as ws: - warnings.simplefilter('always') - management.call_command('makemessages', locale=[LOCALE], extensions=['thtml'], verbosity=0) + warnings.simplefilter("always") + management.call_command( + "makemessages", locale=[LOCALE], extensions=["thtml"], verbosity=0 + ) self.assertEqual(len(ws), 3) for w in ws: self.assertTrue(issubclass(w.category, TranslatorCommentWarning)) @@ -312,55 +364,55 @@ class BasicExtractorTests(ExtractorTests): str(ws[0].message), r"The translator-targeted comment 'Translators: ignored i18n " r"comment #1' \(file templates[/\\]comments.thtml, line 4\) " - r"was ignored, because it wasn't the last item on the line\." + r"was ignored, because it wasn't the last item on the line\.", ) self.assertRegex( str(ws[1].message), r"The translator-targeted comment 'Translators: ignored i18n " r"comment #3' \(file templates[/\\]comments.thtml, line 6\) " - r"was ignored, because it wasn't the last item on the line\." + r"was ignored, because it wasn't the last item on the line\.", ) self.assertRegex( str(ws[2].message), r"The translator-targeted comment 'Translators: ignored i18n " r"comment #4' \(file templates[/\\]comments.thtml, line 8\) " - r"was ignored, because it wasn't the last item on the line\." + r"was ignored, because it wasn't the last item on the line\.", ) # Now test .po file contents self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() - self.assertMsgId('Translatable literal #9a', po_contents) - self.assertNotIn('ignored comment #1', po_contents) + self.assertMsgId("Translatable literal #9a", po_contents) + self.assertNotIn("ignored comment #1", po_contents) - self.assertNotIn('Translators: ignored i18n comment #1', po_contents) + self.assertNotIn("Translators: ignored i18n comment #1", po_contents) self.assertMsgId("Translatable literal #9b", po_contents) - self.assertNotIn('ignored i18n comment #2', po_contents) - self.assertNotIn('ignored comment #2', po_contents) - self.assertMsgId('Translatable literal #9c', po_contents) + self.assertNotIn("ignored i18n comment #2", po_contents) + self.assertNotIn("ignored comment #2", po_contents) + self.assertMsgId("Translatable literal #9c", po_contents) - self.assertNotIn('ignored comment #3', po_contents) - self.assertNotIn('ignored i18n comment #3', po_contents) - self.assertMsgId('Translatable literal #9d', po_contents) + self.assertNotIn("ignored comment #3", po_contents) + self.assertNotIn("ignored i18n comment #3", po_contents) + self.assertMsgId("Translatable literal #9d", po_contents) - self.assertNotIn('ignored comment #4', po_contents) - self.assertMsgId('Translatable literal #9e', po_contents) - self.assertNotIn('ignored comment #5', po_contents) + self.assertNotIn("ignored comment #4", po_contents) + self.assertMsgId("Translatable literal #9e", po_contents) + self.assertNotIn("ignored comment #5", po_contents) - self.assertNotIn('ignored i18n comment #4', po_contents) - self.assertMsgId('Translatable literal #9f', po_contents) - self.assertIn('#. Translators: valid i18n comment #5', po_contents) + self.assertNotIn("ignored i18n comment #4", po_contents) + self.assertMsgId("Translatable literal #9f", po_contents) + self.assertIn("#. Translators: valid i18n comment #5", po_contents) - self.assertMsgId('Translatable literal #9g', po_contents) - self.assertIn('#. Translators: valid i18n comment #6', po_contents) - self.assertMsgId('Translatable literal #9h', po_contents) - self.assertIn('#. Translators: valid i18n comment #7', po_contents) - self.assertMsgId('Translatable literal #9i', po_contents) + self.assertMsgId("Translatable literal #9g", po_contents) + self.assertIn("#. Translators: valid i18n comment #6", po_contents) + self.assertMsgId("Translatable literal #9h", po_contents) + self.assertIn("#. Translators: valid i18n comment #7", po_contents) + self.assertMsgId("Translatable literal #9i", po_contents) - self.assertRegex(po_contents, r'#\..+Translators: valid i18n comment #8') - self.assertRegex(po_contents, r'#\..+Translators: valid i18n comment #9') + self.assertRegex(po_contents, r"#\..+Translators: valid i18n comment #8") + self.assertRegex(po_contents, r"#\..+Translators: valid i18n comment #9") self.assertMsgId("Translatable literal #9j", po_contents) def test_makemessages_find_files(self): @@ -368,24 +420,24 @@ class BasicExtractorTests(ExtractorTests): find_files only discover files having the proper extensions. """ cmd = MakeMessagesCommand() - cmd.ignore_patterns = ['CVS', '.*', '*~', '*.pyc'] + cmd.ignore_patterns = ["CVS", ".*", "*~", "*.pyc"] cmd.symlinks = False - cmd.domain = 'django' - cmd.extensions = ['html', 'txt', 'py'] + cmd.domain = "django" + cmd.extensions = ["html", "txt", "py"] cmd.verbosity = 0 cmd.locale_paths = [] - cmd.default_locale_path = os.path.join(self.test_dir, 'locale') + cmd.default_locale_path = os.path.join(self.test_dir, "locale") found_files = cmd.find_files(self.test_dir) found_exts = {os.path.splitext(tfile.file)[1] for tfile in found_files} - self.assertEqual(found_exts.difference({'.py', '.html', '.txt'}), set()) + self.assertEqual(found_exts.difference({".py", ".html", ".txt"}), set()) - cmd.extensions = ['js'] - cmd.domain = 'djangojs' + cmd.extensions = ["js"] + cmd.domain = "djangojs" found_files = cmd.find_files(self.test_dir) found_exts = {os.path.splitext(tfile.file)[1] for tfile in found_files} - self.assertEqual(found_exts.difference({'.js'}), set()) + self.assertEqual(found_exts.difference({".js"}), set()) - @mock.patch('django.core.management.commands.makemessages.popen_wrapper') + @mock.patch("django.core.management.commands.makemessages.popen_wrapper") def test_makemessages_gettext_version(self, mocked_popen_wrapper): # "Normal" output: mocked_popen_wrapper.return_value = ( @@ -394,21 +446,28 @@ class BasicExtractorTests(ExtractorTests): "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" - "Written by Ulrich Drepper.\n", '', 0) + "Written by Ulrich Drepper.\n", + "", + 0, + ) cmd = MakeMessagesCommand() self.assertEqual(cmd.gettext_version, (0, 18, 1)) # Version number with only 2 parts (#23788) mocked_popen_wrapper.return_value = ( - "xgettext (GNU gettext-tools) 0.17\n", '', 0) + "xgettext (GNU gettext-tools) 0.17\n", + "", + 0, + ) cmd = MakeMessagesCommand() self.assertEqual(cmd.gettext_version, (0, 17)) # Bad version output - mocked_popen_wrapper.return_value = ( - "any other return value\n", '', 0) + mocked_popen_wrapper.return_value = ("any other return value\n", "", 0) cmd = MakeMessagesCommand() - with self.assertRaisesMessage(CommandError, "Unable to get gettext version. Is it installed?"): + with self.assertRaisesMessage( + CommandError, "Unable to get gettext version. Is it installed?" + ): cmd.gettext_version def test_po_file_encoding_when_updating(self): @@ -416,50 +475,53 @@ class BasicExtractorTests(ExtractorTests): Update of PO file doesn't corrupt it with non-UTF-8 encoding on Windows (#23271). """ - BR_PO_BASE = 'locale/pt_BR/LC_MESSAGES/django' - shutil.copyfile(BR_PO_BASE + '.pristine', BR_PO_BASE + '.po') - management.call_command('makemessages', locale=['pt_BR'], verbosity=0) - self.assertTrue(os.path.exists(BR_PO_BASE + '.po')) - with open(BR_PO_BASE + '.po', encoding='utf-8') as fp: + BR_PO_BASE = "locale/pt_BR/LC_MESSAGES/django" + shutil.copyfile(BR_PO_BASE + ".pristine", BR_PO_BASE + ".po") + management.call_command("makemessages", locale=["pt_BR"], verbosity=0) + self.assertTrue(os.path.exists(BR_PO_BASE + ".po")) + with open(BR_PO_BASE + ".po", encoding="utf-8") as fp: po_contents = fp.read() self.assertMsgStr("Größe", po_contents) def test_pot_charset_header_is_utf8(self): """Content-Type: ... charset=CHARSET is replaced with charset=UTF-8""" msgs = ( - '# SOME DESCRIPTIVE TITLE.\n' - '# (some lines truncated as they are not relevant)\n' + "# SOME DESCRIPTIVE TITLE.\n" + "# (some lines truncated as they are not relevant)\n" '"Content-Type: text/plain; charset=CHARSET\\n"\n' '"Content-Transfer-Encoding: 8bit\\n"\n' - '\n' - '#: somefile.py:8\n' + "\n" + "#: somefile.py:8\n" 'msgid "mañana; charset=CHARSET"\n' 'msgstr ""\n' ) with tempfile.NamedTemporaryFile() as pot_file: pot_filename = pot_file.name write_pot_file(pot_filename, msgs) - with open(pot_filename, encoding='utf-8') as fp: + with open(pot_filename, encoding="utf-8") as fp: pot_contents = fp.read() - self.assertIn('Content-Type: text/plain; charset=UTF-8', pot_contents) - self.assertIn('mañana; charset=CHARSET', pot_contents) + self.assertIn("Content-Type: text/plain; charset=UTF-8", pot_contents) + self.assertIn("mañana; charset=CHARSET", pot_contents) class JavaScriptExtractorTests(ExtractorTests): - PO_FILE = 'locale/%s/LC_MESSAGES/djangojs.po' % LOCALE + PO_FILE = "locale/%s/LC_MESSAGES/djangojs.po" % LOCALE def test_javascript_literals(self): - _, po_contents = self._run_makemessages(domain='djangojs') - self.assertMsgId('This literal should be included.', po_contents) - self.assertMsgId('gettext_noop should, too.', po_contents) - self.assertMsgId('This one as well.', po_contents) - self.assertMsgId(r'He said, \"hello\".', po_contents) + _, po_contents = self._run_makemessages(domain="djangojs") + self.assertMsgId("This literal should be included.", po_contents) + self.assertMsgId("gettext_noop should, too.", po_contents) + self.assertMsgId("This one as well.", po_contents) + self.assertMsgId(r"He said, \"hello\".", po_contents) self.assertMsgId("okkkk", po_contents) self.assertMsgId("TEXT", po_contents) self.assertMsgId("It's at http://example.com", po_contents) self.assertMsgId("String", po_contents) - self.assertMsgId("/* but this one will be too */ 'cause there is no way of telling...", po_contents) + self.assertMsgId( + "/* but this one will be too */ 'cause there is no way of telling...", + po_contents, + ) self.assertMsgId("foo", po_contents) self.assertMsgId("bar", po_contents) self.assertMsgId("baz", po_contents) @@ -470,91 +532,115 @@ class JavaScriptExtractorTests(ExtractorTests): """ Regression test for #23583. """ - with override_settings(STATIC_ROOT=os.path.join(self.test_dir, 'static/'), - MEDIA_ROOT=os.path.join(self.test_dir, 'media_root/')): - _, po_contents = self._run_makemessages(domain='djangojs') - self.assertMsgId("Static content inside app should be included.", po_contents) - self.assertNotMsgId("Content from STATIC_ROOT should not be included", po_contents) + with override_settings( + STATIC_ROOT=os.path.join(self.test_dir, "static/"), + MEDIA_ROOT=os.path.join(self.test_dir, "media_root/"), + ): + _, po_contents = self._run_makemessages(domain="djangojs") + self.assertMsgId( + "Static content inside app should be included.", po_contents + ) + self.assertNotMsgId( + "Content from STATIC_ROOT should not be included", po_contents + ) - @override_settings(STATIC_ROOT=None, MEDIA_ROOT='') + @override_settings(STATIC_ROOT=None, MEDIA_ROOT="") def test_default_root_settings(self): """ Regression test for #23717. """ - _, po_contents = self._run_makemessages(domain='djangojs') + _, po_contents = self._run_makemessages(domain="djangojs") self.assertMsgId("Static content inside app should be included.", po_contents) class IgnoredExtractorTests(ExtractorTests): - def test_ignore_directory(self): - out, po_contents = self._run_makemessages(ignore_patterns=[ - os.path.join('ignore_dir', '*'), - ]) + out, po_contents = self._run_makemessages( + ignore_patterns=[ + os.path.join("ignore_dir", "*"), + ] + ) self.assertIn("ignoring directory ignore_dir", out) - self.assertMsgId('This literal should be included.', po_contents) - self.assertNotMsgId('This should be ignored.', po_contents) + self.assertMsgId("This literal should be included.", po_contents) + self.assertNotMsgId("This should be ignored.", po_contents) def test_ignore_subdirectory(self): - out, po_contents = self._run_makemessages(ignore_patterns=[ - 'templates/*/ignore.html', - 'templates/subdir/*', - ]) + out, po_contents = self._run_makemessages( + ignore_patterns=[ + "templates/*/ignore.html", + "templates/subdir/*", + ] + ) self.assertIn("ignoring directory subdir", out) - self.assertNotMsgId('This subdir should be ignored too.', po_contents) + self.assertNotMsgId("This subdir should be ignored too.", po_contents) def test_ignore_file_patterns(self): - out, po_contents = self._run_makemessages(ignore_patterns=[ - 'xxx_*', - ]) + out, po_contents = self._run_makemessages( + ignore_patterns=[ + "xxx_*", + ] + ) self.assertIn("ignoring file xxx_ignored.html", out) - self.assertNotMsgId('This should be ignored too.', po_contents) + self.assertNotMsgId("This should be ignored too.", po_contents) def test_media_static_dirs_ignored(self): - with override_settings(STATIC_ROOT=os.path.join(self.test_dir, 'static/'), - MEDIA_ROOT=os.path.join(self.test_dir, 'media_root/')): + with override_settings( + STATIC_ROOT=os.path.join(self.test_dir, "static/"), + MEDIA_ROOT=os.path.join(self.test_dir, "media_root/"), + ): out, _ = self._run_makemessages() self.assertIn("ignoring directory static", out) self.assertIn("ignoring directory media_root", out) class SymlinkExtractorTests(ExtractorTests): - def setUp(self): super().setUp() - self.symlinked_dir = os.path.join(self.test_dir, 'templates_symlinked') + self.symlinked_dir = os.path.join(self.test_dir, "templates_symlinked") def test_symlink(self): if symlinks_supported(): - os.symlink(os.path.join(self.test_dir, 'templates'), self.symlinked_dir) + os.symlink(os.path.join(self.test_dir, "templates"), self.symlinked_dir) else: - self.skipTest("os.symlink() not available on this OS + Python version combination.") - management.call_command('makemessages', locale=[LOCALE], verbosity=0, symlinks=True) + self.skipTest( + "os.symlink() not available on this OS + Python version combination." + ) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, symlinks=True + ) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() - self.assertMsgId('This literal should be included.', po_contents) - self.assertLocationCommentPresent(self.PO_FILE, None, 'templates_symlinked', 'test.html') + self.assertMsgId("This literal should be included.", po_contents) + self.assertLocationCommentPresent( + self.PO_FILE, None, "templates_symlinked", "test.html" + ) class CopyPluralFormsExtractorTests(ExtractorTests): - PO_FILE_ES = 'locale/es/LC_MESSAGES/django.po' + PO_FILE_ES = "locale/es/LC_MESSAGES/django.po" def test_copy_plural_forms(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() - self.assertIn('Plural-Forms: nplurals=2; plural=(n != 1)', po_contents) + self.assertIn("Plural-Forms: nplurals=2; plural=(n != 1)", po_contents) def test_override_plural_forms(self): """Ticket #20311.""" - management.call_command('makemessages', locale=['es'], extensions=['djtpl'], verbosity=0) + management.call_command( + "makemessages", locale=["es"], extensions=["djtpl"], verbosity=0 + ) self.assertTrue(os.path.exists(self.PO_FILE_ES)) - with open(self.PO_FILE_ES, encoding='utf-8') as fp: + with open(self.PO_FILE_ES, encoding="utf-8") as fp: po_contents = fp.read() - found = re.findall(r'^(?P<value>"Plural-Forms.+?\\n")\s*$', po_contents, re.MULTILINE | re.DOTALL) + found = re.findall( + r'^(?P<value>"Plural-Forms.+?\\n")\s*$', + po_contents, + re.MULTILINE | re.DOTALL, + ) self.assertEqual(1, len(found)) def test_translate_and_plural_blocktranslate_collision(self): @@ -563,30 +649,42 @@ class CopyPluralFormsExtractorTests(ExtractorTests): found inside a {% translate %} tag and also in another file inside a {% blocktranslate %} with a plural (#17375). """ - management.call_command('makemessages', locale=[LOCALE], extensions=['html', 'djtpl'], verbosity=0) + management.call_command( + "makemessages", locale=[LOCALE], extensions=["html", "djtpl"], verbosity=0 + ) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() - self.assertNotIn("#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\\n", po_contents) - self.assertMsgId('First `translate`, then `blocktranslate` with a plural', po_contents) - self.assertMsgIdPlural('Plural for a `translate` and `blocktranslate` collision case', po_contents) + self.assertNotIn( + "#-#-#-#-# django.pot (PACKAGE VERSION) #-#-#-#-#\\n", po_contents + ) + self.assertMsgId( + "First `translate`, then `blocktranslate` with a plural", po_contents + ) + self.assertMsgIdPlural( + "Plural for a `translate` and `blocktranslate` collision case", + po_contents, + ) class NoWrapExtractorTests(ExtractorTests): - def test_no_wrap_enabled(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=True) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, no_wrap=True + ) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() self.assertMsgId( - 'This literal should also be included wrapped or not wrapped ' - 'depending on the use of the --no-wrap option.', - po_contents + "This literal should also be included wrapped or not wrapped " + "depending on the use of the --no-wrap option.", + po_contents, ) def test_no_wrap_disabled(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_wrap=False) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, no_wrap=False + ) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() @@ -594,64 +692,82 @@ class NoWrapExtractorTests(ExtractorTests): '""\n"This literal should also be included wrapped or not ' 'wrapped depending on the "\n"use of the --no-wrap option."', po_contents, - use_quotes=False + use_quotes=False, ) class LocationCommentsTests(ExtractorTests): - def test_no_location_enabled(self): """Behavior is correct if --no-location switch is specified. See #16903.""" - management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=True) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, no_location=True + ) self.assertTrue(os.path.exists(self.PO_FILE)) - self.assertLocationCommentNotPresent(self.PO_FILE, None, 'test.html') + self.assertLocationCommentNotPresent(self.PO_FILE, None, "test.html") def test_no_location_disabled(self): """Behavior is correct if --no-location switch isn't specified.""" - management.call_command('makemessages', locale=[LOCALE], verbosity=0, no_location=False) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, no_location=False + ) self.assertTrue(os.path.exists(self.PO_FILE)) # #16903 -- Standard comment with source file relative path should be present - self.assertLocationCommentPresent(self.PO_FILE, 'Translatable literal #6b', 'templates', 'test.html') + self.assertLocationCommentPresent( + self.PO_FILE, "Translatable literal #6b", "templates", "test.html" + ) def test_location_comments_for_templatized_files(self): """ Ensure no leaky paths in comments, e.g. #: path\to\file.html.py:123 Refs #21209/#26341. """ - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE)) with open(self.PO_FILE) as fp: po_contents = fp.read() - self.assertMsgId('#: templates/test.html.py', po_contents) - self.assertLocationCommentNotPresent(self.PO_FILE, None, '.html.py') - self.assertLocationCommentPresent(self.PO_FILE, 5, 'templates', 'test.html') + self.assertMsgId("#: templates/test.html.py", po_contents) + self.assertLocationCommentNotPresent(self.PO_FILE, None, ".html.py") + self.assertLocationCommentPresent(self.PO_FILE, 5, "templates", "test.html") @requires_gettext_019 def test_add_location_full(self): """makemessages --add-location=full""" - management.call_command('makemessages', locale=[LOCALE], verbosity=0, add_location='full') + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, add_location="full" + ) self.assertTrue(os.path.exists(self.PO_FILE)) # Comment with source file relative path and line number is present. - self.assertLocationCommentPresent(self.PO_FILE, 'Translatable literal #6b', 'templates', 'test.html') + self.assertLocationCommentPresent( + self.PO_FILE, "Translatable literal #6b", "templates", "test.html" + ) @requires_gettext_019 def test_add_location_file(self): """makemessages --add-location=file""" - management.call_command('makemessages', locale=[LOCALE], verbosity=0, add_location='file') + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, add_location="file" + ) self.assertTrue(os.path.exists(self.PO_FILE)) # Comment with source file relative path is present. - self.assertLocationCommentPresent(self.PO_FILE, None, 'templates', 'test.html') + self.assertLocationCommentPresent(self.PO_FILE, None, "templates", "test.html") # But it should not contain the line number. - self.assertLocationCommentNotPresent(self.PO_FILE, 'Translatable literal #6b', 'templates', 'test.html') + self.assertLocationCommentNotPresent( + self.PO_FILE, "Translatable literal #6b", "templates", "test.html" + ) @requires_gettext_019 def test_add_location_never(self): """makemessages --add-location=never""" - management.call_command('makemessages', locale=[LOCALE], verbosity=0, add_location='never') + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, add_location="never" + ) self.assertTrue(os.path.exists(self.PO_FILE)) - self.assertLocationCommentNotPresent(self.PO_FILE, None, 'test.html') + self.assertLocationCommentNotPresent(self.PO_FILE, None, "test.html") - @mock.patch('django.core.management.commands.makemessages.Command.gettext_version', new=(0, 18, 99)) + @mock.patch( + "django.core.management.commands.makemessages.Command.gettext_version", + new=(0, 18, 99), + ) def test_add_location_gettext_version_check(self): """ CommandError is raised when using makemessages --add-location with @@ -659,34 +775,40 @@ class LocationCommentsTests(ExtractorTests): """ msg = "The --add-location option requires gettext 0.19 or later. You have 0.18.99." with self.assertRaisesMessage(CommandError, msg): - management.call_command('makemessages', locale=[LOCALE], verbosity=0, add_location='full') + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, add_location="full" + ) class KeepPotFileExtractorTests(ExtractorTests): - POT_FILE = 'locale/django.pot' + POT_FILE = "locale/django.pot" def test_keep_pot_disabled_by_default(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) self.assertFalse(os.path.exists(self.POT_FILE)) def test_keep_pot_explicitly_disabled(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0, keep_pot=False) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, keep_pot=False + ) self.assertFalse(os.path.exists(self.POT_FILE)) def test_keep_pot_enabled(self): - management.call_command('makemessages', locale=[LOCALE], verbosity=0, keep_pot=True) + management.call_command( + "makemessages", locale=[LOCALE], verbosity=0, keep_pot=True + ) self.assertTrue(os.path.exists(self.POT_FILE)) class MultipleLocaleExtractionTests(ExtractorTests): - PO_FILE_PT = 'locale/pt/LC_MESSAGES/django.po' - PO_FILE_DE = 'locale/de/LC_MESSAGES/django.po' - PO_FILE_KO = 'locale/ko/LC_MESSAGES/django.po' - LOCALES = ['pt', 'de', 'ch'] + PO_FILE_PT = "locale/pt/LC_MESSAGES/django.po" + PO_FILE_DE = "locale/de/LC_MESSAGES/django.po" + PO_FILE_KO = "locale/ko/LC_MESSAGES/django.po" + LOCALES = ["pt", "de", "ch"] def test_multiple_locales(self): - management.call_command('makemessages', locale=['pt', 'de'], verbosity=0) + management.call_command("makemessages", locale=["pt", "de"], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE_PT)) self.assertTrue(os.path.exists(self.PO_FILE_DE)) @@ -696,19 +818,19 @@ class MultipleLocaleExtractionTests(ExtractorTests): are considered as language directories, except if the directory doesn't start with two letters (which excludes __pycache__, .gitignore, etc.). """ - os.mkdir(os.path.join('locale', '_do_not_pick')) + os.mkdir(os.path.join("locale", "_do_not_pick")) # Excluding locales that do not compile - management.call_command('makemessages', exclude=['ja', 'es_AR'], verbosity=0) + management.call_command("makemessages", exclude=["ja", "es_AR"], verbosity=0) self.assertTrue(os.path.exists(self.PO_FILE_KO)) - self.assertFalse(os.path.exists('locale/_do_not_pick/LC_MESSAGES/django.po')) + self.assertFalse(os.path.exists("locale/_do_not_pick/LC_MESSAGES/django.po")) class ExcludedLocaleExtractionTests(ExtractorTests): - work_subdir = 'exclude' + work_subdir = "exclude" - LOCALES = ['en', 'fr', 'it'] - PO_FILE = 'locale/%s/LC_MESSAGES/django.po' + LOCALES = ["en", "fr", "it"] + PO_FILE = "locale/%s/LC_MESSAGES/django.po" def _set_times_for_all_po_files(self): """ @@ -719,7 +841,7 @@ class ExcludedLocaleExtractionTests(ExtractorTests): def setUp(self): super().setUp() - copytree('canned_locale', 'locale') + copytree("canned_locale", "locale") self._set_times_for_all_po_files() def test_command_help(self): @@ -727,36 +849,40 @@ class ExcludedLocaleExtractionTests(ExtractorTests): # `call_command` bypasses the parser; by calling # `execute_from_command_line` with the help subcommand we # ensure that there are no issues with the parser itself. - execute_from_command_line(['django-admin', 'help', 'makemessages']) + execute_from_command_line(["django-admin", "help", "makemessages"]) def test_one_locale_excluded(self): - management.call_command('makemessages', exclude=['it'], verbosity=0) - self.assertRecentlyModified(self.PO_FILE % 'en') - self.assertRecentlyModified(self.PO_FILE % 'fr') - self.assertNotRecentlyModified(self.PO_FILE % 'it') + management.call_command("makemessages", exclude=["it"], verbosity=0) + self.assertRecentlyModified(self.PO_FILE % "en") + self.assertRecentlyModified(self.PO_FILE % "fr") + self.assertNotRecentlyModified(self.PO_FILE % "it") def test_multiple_locales_excluded(self): - management.call_command('makemessages', exclude=['it', 'fr'], verbosity=0) - self.assertRecentlyModified(self.PO_FILE % 'en') - self.assertNotRecentlyModified(self.PO_FILE % 'fr') - self.assertNotRecentlyModified(self.PO_FILE % 'it') + management.call_command("makemessages", exclude=["it", "fr"], verbosity=0) + self.assertRecentlyModified(self.PO_FILE % "en") + self.assertNotRecentlyModified(self.PO_FILE % "fr") + self.assertNotRecentlyModified(self.PO_FILE % "it") def test_one_locale_excluded_with_locale(self): - management.call_command('makemessages', locale=['en', 'fr'], exclude=['fr'], verbosity=0) - self.assertRecentlyModified(self.PO_FILE % 'en') - self.assertNotRecentlyModified(self.PO_FILE % 'fr') - self.assertNotRecentlyModified(self.PO_FILE % 'it') + management.call_command( + "makemessages", locale=["en", "fr"], exclude=["fr"], verbosity=0 + ) + self.assertRecentlyModified(self.PO_FILE % "en") + self.assertNotRecentlyModified(self.PO_FILE % "fr") + self.assertNotRecentlyModified(self.PO_FILE % "it") def test_multiple_locales_excluded_with_locale(self): - management.call_command('makemessages', locale=['en', 'fr', 'it'], exclude=['fr', 'it'], verbosity=0) - self.assertRecentlyModified(self.PO_FILE % 'en') - self.assertNotRecentlyModified(self.PO_FILE % 'fr') - self.assertNotRecentlyModified(self.PO_FILE % 'it') + management.call_command( + "makemessages", locale=["en", "fr", "it"], exclude=["fr", "it"], verbosity=0 + ) + self.assertRecentlyModified(self.PO_FILE % "en") + self.assertNotRecentlyModified(self.PO_FILE % "fr") + self.assertNotRecentlyModified(self.PO_FILE % "it") class CustomLayoutExtractionTests(ExtractorTests): - work_subdir = 'project_dir' + work_subdir = "project_dir" def test_no_locale_raises(self): msg = ( @@ -765,15 +891,15 @@ class CustomLayoutExtractionTests(ExtractorTests): "or LOCALE_PATHS setting is set." ) with self.assertRaisesMessage(management.CommandError, msg): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) # Working files are cleaned up on an error. - self.assertFalse(os.path.exists('./app_no_locale/test.html.py')) + self.assertFalse(os.path.exists("./app_no_locale/test.html.py")) def test_project_locale_paths(self): - self._test_project_locale_paths(os.path.join(self.test_dir, 'project_locale')) + self._test_project_locale_paths(os.path.join(self.test_dir, "project_locale")) def test_project_locale_paths_pathlib(self): - self._test_project_locale_paths(Path(self.test_dir) / 'project_locale') + self._test_project_locale_paths(Path(self.test_dir) / "project_locale") def _test_project_locale_paths(self, locale_path): """ @@ -781,43 +907,50 @@ class CustomLayoutExtractionTests(ExtractorTests): * translations outside of that app are in LOCALE_PATHS[0] """ with override_settings(LOCALE_PATHS=[locale_path]): - management.call_command('makemessages', locale=[LOCALE], verbosity=0) + management.call_command("makemessages", locale=[LOCALE], verbosity=0) project_de_locale = os.path.join( - self.test_dir, 'project_locale', 'de', 'LC_MESSAGES', 'django.po') + self.test_dir, "project_locale", "de", "LC_MESSAGES", "django.po" + ) app_de_locale = os.path.join( - self.test_dir, 'app_with_locale', 'locale', 'de', 'LC_MESSAGES', 'django.po') + self.test_dir, + "app_with_locale", + "locale", + "de", + "LC_MESSAGES", + "django.po", + ) self.assertTrue(os.path.exists(project_de_locale)) self.assertTrue(os.path.exists(app_de_locale)) with open(project_de_locale) as fp: po_contents = fp.read() - self.assertMsgId('This app has no locale directory', po_contents) - self.assertMsgId('This is a project-level string', po_contents) + self.assertMsgId("This app has no locale directory", po_contents) + self.assertMsgId("This is a project-level string", po_contents) with open(app_de_locale) as fp: po_contents = fp.read() - self.assertMsgId('This app has a locale directory', po_contents) + self.assertMsgId("This app has a locale directory", po_contents) -@skipUnless(has_xgettext, 'xgettext is mandatory for extraction tests') +@skipUnless(has_xgettext, "xgettext is mandatory for extraction tests") class NoSettingsExtractionTests(AdminScriptTestCase): def test_makemessages_no_settings(self): - out, err = self.run_django_admin(['makemessages', '-l', 'en', '-v', '0']) + out, err = self.run_django_admin(["makemessages", "-l", "en", "-v", "0"]) self.assertNoOutput(err) self.assertNoOutput(out) class UnchangedPoExtractionTests(ExtractorTests): - work_subdir = 'unchanged' + work_subdir = "unchanged" def setUp(self): super().setUp() po_file = Path(self.PO_FILE) - po_file_tmp = Path(self.PO_FILE + '.tmp') - if os.name == 'nt': + po_file_tmp = Path(self.PO_FILE + ".tmp") + if os.name == "nt": # msgmerge outputs Windows style paths on Windows. po_contents = po_file_tmp.read_text().replace( - '#: __init__.py', - '#: .\\__init__.py', + "#: __init__.py", + "#: .\\__init__.py", ) po_file.write_text(po_contents) else: @@ -831,10 +964,10 @@ class UnchangedPoExtractionTests(ExtractorTests): def test_po_changed_with_new_strings(self): """PO files are updated when new changes are detected.""" - Path('models.py.tmp').rename('models.py') + Path("models.py.tmp").rename("models.py") _, po_contents = self._run_makemessages() self.assertNotEqual(po_contents, self.original_po_contents) self.assertMsgId( - 'This is a hitherto undiscovered translatable string.', + "This is a hitherto undiscovered translatable string.", po_contents, ) diff --git a/tests/i18n/test_management.py b/tests/i18n/test_management.py index c464a13295..332702c0f4 100644 --- a/tests/i18n/test_management.py +++ b/tests/i18n/test_management.py @@ -5,18 +5,28 @@ from django.test import SimpleTestCase class TranslatableFileTests(SimpleTestCase): - def test_repr(self): - dirpath = 'dir' - file_name = 'example' - trans_file = TranslatableFile(dirpath=dirpath, file_name=file_name, locale_dir=None) - self.assertEqual(repr(trans_file), '<TranslatableFile: %s>' % os.path.join(dirpath, file_name)) + dirpath = "dir" + file_name = "example" + trans_file = TranslatableFile( + dirpath=dirpath, file_name=file_name, locale_dir=None + ) + self.assertEqual( + repr(trans_file), + "<TranslatableFile: %s>" % os.path.join(dirpath, file_name), + ) def test_eq(self): - dirpath = 'dir' - file_name = 'example' - trans_file = TranslatableFile(dirpath=dirpath, file_name=file_name, locale_dir=None) - trans_file_eq = TranslatableFile(dirpath=dirpath, file_name=file_name, locale_dir=None) - trans_file_not_eq = TranslatableFile(dirpath='tmp', file_name=file_name, locale_dir=None) + dirpath = "dir" + file_name = "example" + trans_file = TranslatableFile( + dirpath=dirpath, file_name=file_name, locale_dir=None + ) + trans_file_eq = TranslatableFile( + dirpath=dirpath, file_name=file_name, locale_dir=None + ) + trans_file_not_eq = TranslatableFile( + dirpath="tmp", file_name=file_name, locale_dir=None + ) self.assertEqual(trans_file, trans_file_eq) self.assertNotEqual(trans_file, trans_file_not_eq) diff --git a/tests/i18n/test_percents.py b/tests/i18n/test_percents.py index 5362ace0a7..f1dce0c7c6 100644 --- a/tests/i18n/test_percents.py +++ b/tests/i18n/test_percents.py @@ -6,20 +6,22 @@ from django.utils.translation import activate, get_language, trans_real from .utils import POFileAssertionMixin -SAMPLEPROJECT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sampleproject') -SAMPLEPROJECT_LOCALE = os.path.join(SAMPLEPROJECT_DIR, 'locale') +SAMPLEPROJECT_DIR = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "sampleproject" +) +SAMPLEPROJECT_LOCALE = os.path.join(SAMPLEPROJECT_DIR, "locale") @override_settings(LOCALE_PATHS=[SAMPLEPROJECT_LOCALE]) class FrenchTestCase(SimpleTestCase): """Tests using the French translations of the sampleproject.""" - PO_FILE = os.path.join(SAMPLEPROJECT_LOCALE, 'fr', 'LC_MESSAGES', 'django.po') + PO_FILE = os.path.join(SAMPLEPROJECT_LOCALE, "fr", "LC_MESSAGES", "django.po") def setUp(self): self._language = get_language() self._translations = trans_real._translations - activate('fr') + activate("fr") def tearDown(self): trans_real._translations = self._translations @@ -42,19 +44,34 @@ class ExtractingStringsWithPercentSigns(POFileAssertionMixin, FrenchTestCase): self.po_contents = fp.read() def test_trans_tag_with_percent_symbol_at_the_end(self): - self.assertMsgId('Literal with a percent symbol at the end %%', self.po_contents) + self.assertMsgId( + "Literal with a percent symbol at the end %%", self.po_contents + ) def test_trans_tag_with_percent_symbol_in_the_middle(self): - self.assertMsgId('Literal with a percent %% symbol in the middle', self.po_contents) - self.assertMsgId('It is 100%%', self.po_contents) + self.assertMsgId( + "Literal with a percent %% symbol in the middle", self.po_contents + ) + self.assertMsgId("It is 100%%", self.po_contents) def test_trans_tag_with_string_that_look_like_fmt_spec(self): - self.assertMsgId('Looks like a str fmt spec %%s but should not be interpreted as such', self.po_contents) - self.assertMsgId('Looks like a str fmt spec %% o but should not be interpreted as such', self.po_contents) + self.assertMsgId( + "Looks like a str fmt spec %%s but should not be interpreted as such", + self.po_contents, + ) + self.assertMsgId( + "Looks like a str fmt spec %% o but should not be interpreted as such", + self.po_contents, + ) def test_adds_python_format_to_all_percent_signs(self): - self.assertMsgId('1 percent sign %%, 2 percent signs %%%%, 3 percent signs %%%%%%', self.po_contents) - self.assertMsgId('%(name)s says: 1 percent sign %%, 2 percent signs %%%%', self.po_contents) + self.assertMsgId( + "1 percent sign %%, 2 percent signs %%%%, 3 percent signs %%%%%%", + self.po_contents, + ) + self.assertMsgId( + "%(name)s says: 1 percent sign %%, 2 percent signs %%%%", self.po_contents + ) class RenderingTemplatesWithPercentSigns(FrenchTestCase): @@ -67,69 +84,79 @@ class RenderingTemplatesWithPercentSigns(FrenchTestCase): """ def test_translates_with_a_percent_symbol_at_the_end(self): - expected = 'Littérale avec un symbole de pour cent à la fin %' + expected = "Littérale avec un symbole de pour cent à la fin %" - trans_tpl = Template('{% load i18n %}{% translate "Literal with a percent symbol at the end %" %}') + trans_tpl = Template( + '{% load i18n %}{% translate "Literal with a percent symbol at the end %" %}' + ) self.assertEqual(trans_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}Literal with a percent symbol at ' - 'the end %{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}Literal with a percent symbol at " + "the end %{% endblocktranslate %}" ) self.assertEqual(block_tpl.render(Context({})), expected) def test_translates_with_percent_symbol_in_the_middle(self): - expected = 'Pour cent littérale % avec un symbole au milieu' + expected = "Pour cent littérale % avec un symbole au milieu" - trans_tpl = Template('{% load i18n %}{% translate "Literal with a percent % symbol in the middle" %}') + trans_tpl = Template( + '{% load i18n %}{% translate "Literal with a percent % symbol in the middle" %}' + ) self.assertEqual(trans_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}Literal with a percent % symbol ' - 'in the middle{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}Literal with a percent % symbol " + "in the middle{% endblocktranslate %}" ) self.assertEqual(block_tpl.render(Context({})), expected) def test_translates_with_percent_symbol_using_context(self): trans_tpl = Template('{% load i18n %}{% translate "It is 100%" %}') - self.assertEqual(trans_tpl.render(Context({})), 'Il est de 100%') - trans_tpl = Template('{% load i18n %}{% translate "It is 100%" context "female" %}') - self.assertEqual(trans_tpl.render(Context({})), 'Elle est de 100%') + self.assertEqual(trans_tpl.render(Context({})), "Il est de 100%") + trans_tpl = Template( + '{% load i18n %}{% translate "It is 100%" context "female" %}' + ) + self.assertEqual(trans_tpl.render(Context({})), "Elle est de 100%") - block_tpl = Template('{% load i18n %}{% blocktranslate %}It is 100%{% endblocktranslate %}') - self.assertEqual(block_tpl.render(Context({})), 'Il est de 100%') - block_tpl = Template('{% load i18n %}{% blocktranslate context "female" %}It is 100%{% endblocktranslate %}') - self.assertEqual(block_tpl.render(Context({})), 'Elle est de 100%') + block_tpl = Template( + "{% load i18n %}{% blocktranslate %}It is 100%{% endblocktranslate %}" + ) + self.assertEqual(block_tpl.render(Context({})), "Il est de 100%") + block_tpl = Template( + '{% load i18n %}{% blocktranslate context "female" %}It is 100%{% endblocktranslate %}' + ) + self.assertEqual(block_tpl.render(Context({})), "Elle est de 100%") def test_translates_with_string_that_look_like_fmt_spec_with_trans(self): # tests "%s" - expected = ('On dirait un spec str fmt %s mais ne devrait pas être interprété comme plus disponible') + expected = "On dirait un spec str fmt %s mais ne devrait pas être interprété comme plus disponible" trans_tpl = Template( '{% load i18n %}{% translate "Looks like a str fmt spec %s but ' 'should not be interpreted as such" %}' ) self.assertEqual(trans_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}Looks like a str fmt spec %s but ' - 'should not be interpreted as such{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}Looks like a str fmt spec %s but " + "should not be interpreted as such{% endblocktranslate %}" ) self.assertEqual(block_tpl.render(Context({})), expected) # tests "% o" - expected = ('On dirait un spec str fmt % o mais ne devrait pas être interprété comme plus disponible') + expected = "On dirait un spec str fmt % o mais ne devrait pas être interprété comme plus disponible" trans_tpl = Template( '{% load i18n %}{% translate "Looks like a str fmt spec % o but should not be ' 'interpreted as such" %}' ) self.assertEqual(trans_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}Looks like a str fmt spec % o but should not be ' - 'interpreted as such{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}Looks like a str fmt spec % o but should not be " + "interpreted as such{% endblocktranslate %}" ) self.assertEqual(block_tpl.render(Context({})), expected) def test_translates_multiple_percent_signs(self): - expected = ('1 % signe pour cent, signes %% 2 pour cent, trois signes de pourcentage %%%') + expected = "1 % signe pour cent, signes %% 2 pour cent, trois signes de pourcentage %%%" trans_tpl = Template( '{% load i18n %}{% translate "1 percent sign %, 2 percent signs %%, ' @@ -137,16 +164,16 @@ class RenderingTemplatesWithPercentSigns(FrenchTestCase): ) self.assertEqual(trans_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}1 percent sign %, 2 percent signs ' - '%%, 3 percent signs %%%{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}1 percent sign %, 2 percent signs " + "%%, 3 percent signs %%%{% endblocktranslate %}" ) self.assertEqual(block_tpl.render(Context({})), expected) block_tpl = Template( - '{% load i18n %}{% blocktranslate %}{{name}} says: 1 percent sign %, ' - '2 percent signs %%{% endblocktranslate %}' + "{% load i18n %}{% blocktranslate %}{{name}} says: 1 percent sign %, " + "2 percent signs %%{% endblocktranslate %}" ) self.assertEqual( block_tpl.render(Context({"name": "Django"})), - 'Django dit: 1 pour cent signe %, deux signes de pourcentage %%' + "Django dit: 1 pour cent signe %, deux signes de pourcentage %%", ) diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 3dbb8236d7..aa77657471 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -19,26 +19,51 @@ from django.conf.locale import LANG_INFO from django.conf.urls.i18n import i18n_patterns from django.template import Context, Template from django.test import ( - RequestFactory, SimpleTestCase, TestCase, ignore_warnings, + RequestFactory, + SimpleTestCase, + TestCase, + ignore_warnings, override_settings, ) from django.utils import translation from django.utils.deprecation import RemovedInDjango50Warning from django.utils.formats import ( - date_format, get_format, iter_format_modules, localize, localize_input, - reset_format_cache, sanitize_separators, sanitize_strftime_format, + date_format, + get_format, + iter_format_modules, + localize, + localize_input, + reset_format_cache, + sanitize_separators, + sanitize_strftime_format, time_format, ) from django.utils.numberformat import format as nformat from django.utils.safestring import SafeString, mark_safe from django.utils.translation import ( - activate, check_for_language, deactivate, get_language, get_language_bidi, - get_language_from_request, get_language_info, gettext, gettext_lazy, - ngettext, ngettext_lazy, npgettext, npgettext_lazy, pgettext, - round_away_from_one, to_language, to_locale, trans_null, trans_real, + activate, + check_for_language, + deactivate, + get_language, + get_language_bidi, + get_language_from_request, + get_language_info, + gettext, + gettext_lazy, + ngettext, + ngettext_lazy, + npgettext, + npgettext_lazy, + pgettext, + round_away_from_one, + to_language, + to_locale, + trans_null, + trans_real, ) from django.utils.translation.reloader import ( - translation_file_changed, watch_for_translation_changes, + translation_file_changed, + watch_for_translation_changes, ) from .forms import CompanyForm, I18nForm, SelectDateForm @@ -46,7 +71,7 @@ from .models import Company, TestModel here = os.path.dirname(os.path.abspath(__file__)) extended_locale_paths = settings.LOCALE_PATHS + [ - os.path.join(here, 'other', 'locale'), + os.path.join(here, "other", "locale"), ] @@ -69,30 +94,34 @@ def patch_formats(lang, **settings): class TranslationTests(SimpleTestCase): - @translation.override('fr') + @translation.override("fr") def test_plural(self): """ Test plurals with ngettext. French differs from English in that 0 is singular. """ self.assertEqual( - ngettext('%(num)d year', '%(num)d years', 0) % {'num': 0}, - '0 année', + ngettext("%(num)d year", "%(num)d years", 0) % {"num": 0}, + "0 année", ) self.assertEqual( - ngettext('%(num)d year', '%(num)d years', 2) % {'num': 2}, - '2 années', + ngettext("%(num)d year", "%(num)d years", 2) % {"num": 2}, + "2 années", + ) + self.assertEqual( + ngettext("%(size)d byte", "%(size)d bytes", 0) % {"size": 0}, "0 octet" + ) + self.assertEqual( + ngettext("%(size)d byte", "%(size)d bytes", 2) % {"size": 2}, "2 octets" ) - self.assertEqual(ngettext("%(size)d byte", "%(size)d bytes", 0) % {'size': 0}, "0 octet") - self.assertEqual(ngettext("%(size)d byte", "%(size)d bytes", 2) % {'size': 2}, "2 octets") def test_plural_null(self): g = trans_null.ngettext - self.assertEqual(g('%(num)d year', '%(num)d years', 0) % {'num': 0}, '0 years') - self.assertEqual(g('%(num)d year', '%(num)d years', 1) % {'num': 1}, '1 year') - self.assertEqual(g('%(num)d year', '%(num)d years', 2) % {'num': 2}, '2 years') + self.assertEqual(g("%(num)d year", "%(num)d years", 0) % {"num": 0}, "0 years") + self.assertEqual(g("%(num)d year", "%(num)d years", 1) % {"num": 1}, "1 year") + self.assertEqual(g("%(num)d year", "%(num)d years", 2) % {"num": 2}, "2 years") @override_settings(LOCALE_PATHS=extended_locale_paths) - @translation.override('fr') + @translation.override("fr") def test_multiple_plurals_per_language(self): """ Normally, French has 2 plurals. As other/locale/fr/LC_MESSAGES/django.po @@ -104,40 +133,39 @@ class TranslationTests(SimpleTestCase): self.assertEqual(ngettext("%d singular", "%d plural", 2) % 2, "2 pluriel2") french = trans_real.catalog() # Internal _catalog can query subcatalogs (from different po files). - self.assertEqual(french._catalog[('%d singular', 0)], '%d singulier') - self.assertEqual(french._catalog[('%(num)d hour', 0)], '%(num)d heure') + self.assertEqual(french._catalog[("%d singular", 0)], "%d singulier") + self.assertEqual(french._catalog[("%(num)d hour", 0)], "%(num)d heure") def test_override(self): - activate('de') + activate("de") try: - with translation.override('pl'): - self.assertEqual(get_language(), 'pl') - self.assertEqual(get_language(), 'de') + with translation.override("pl"): + self.assertEqual(get_language(), "pl") + self.assertEqual(get_language(), "de") with translation.override(None): self.assertIsNone(get_language()) - with translation.override('pl'): + with translation.override("pl"): pass self.assertIsNone(get_language()) - self.assertEqual(get_language(), 'de') + self.assertEqual(get_language(), "de") finally: deactivate() def test_override_decorator(self): - - @translation.override('pl') + @translation.override("pl") def func_pl(): - self.assertEqual(get_language(), 'pl') + self.assertEqual(get_language(), "pl") @translation.override(None) def func_none(): self.assertIsNone(get_language()) try: - activate('de') + activate("de") func_pl() - self.assertEqual(get_language(), 'de') + self.assertEqual(get_language(), "de") func_none() - self.assertEqual(get_language(), 'de') + self.assertEqual(get_language(), "de") finally: deactivate() @@ -146,17 +174,18 @@ class TranslationTests(SimpleTestCase): The language restored is the one used when the function was called, not the one used when the decorator was initialized (#23381). """ - activate('fr') + activate("fr") - @translation.override('pl') + @translation.override("pl") def func_pl(): pass + deactivate() try: - activate('en') + activate("en") func_pl() - self.assertEqual(get_language(), 'en') + self.assertEqual(get_language(), "en") finally: deactivate() @@ -164,22 +193,22 @@ class TranslationTests(SimpleTestCase): """ Format string interpolation should work with *_lazy objects. """ - s = gettext_lazy('Add %(name)s') - d = {'name': 'Ringo'} - self.assertEqual('Add Ringo', s % d) - with translation.override('de', deactivate=True): - self.assertEqual('Ringo hinzuf\xfcgen', s % d) - with translation.override('pl'): - self.assertEqual('Dodaj Ringo', s % d) + s = gettext_lazy("Add %(name)s") + d = {"name": "Ringo"} + self.assertEqual("Add Ringo", s % d) + with translation.override("de", deactivate=True): + self.assertEqual("Ringo hinzuf\xfcgen", s % d) + with translation.override("pl"): + self.assertEqual("Dodaj Ringo", s % d) # It should be possible to compare *_lazy objects. - s1 = gettext_lazy('Add %(name)s') + s1 = gettext_lazy("Add %(name)s") self.assertEqual(s, s1) - s2 = gettext_lazy('Add %(name)s') - s3 = gettext_lazy('Add %(name)s') + s2 = gettext_lazy("Add %(name)s") + s3 = gettext_lazy("Add %(name)s") self.assertEqual(s2, s3) self.assertEqual(s, s2) - s4 = gettext_lazy('Some other string') + s4 = gettext_lazy("Some other string") self.assertNotEqual(s, s4) def test_lazy_pickle(self): @@ -190,99 +219,159 @@ class TranslationTests(SimpleTestCase): @override_settings(LOCALE_PATHS=extended_locale_paths) def test_ngettext_lazy(self): - simple_with_format = ngettext_lazy('%d good result', '%d good results') - simple_context_with_format = npgettext_lazy('Exclamation', '%d good result', '%d good results') - simple_without_format = ngettext_lazy('good result', 'good results') - with translation.override('de'): - self.assertEqual(simple_with_format % 1, '1 gutes Resultat') - self.assertEqual(simple_with_format % 4, '4 guten Resultate') - self.assertEqual(simple_context_with_format % 1, '1 gutes Resultat!') - self.assertEqual(simple_context_with_format % 4, '4 guten Resultate!') - self.assertEqual(simple_without_format % 1, 'gutes Resultat') - self.assertEqual(simple_without_format % 4, 'guten Resultate') - - complex_nonlazy = ngettext_lazy('Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4) + simple_with_format = ngettext_lazy("%d good result", "%d good results") + simple_context_with_format = npgettext_lazy( + "Exclamation", "%d good result", "%d good results" + ) + simple_without_format = ngettext_lazy("good result", "good results") + with translation.override("de"): + self.assertEqual(simple_with_format % 1, "1 gutes Resultat") + self.assertEqual(simple_with_format % 4, "4 guten Resultate") + self.assertEqual(simple_context_with_format % 1, "1 gutes Resultat!") + self.assertEqual(simple_context_with_format % 4, "4 guten Resultate!") + self.assertEqual(simple_without_format % 1, "gutes Resultat") + self.assertEqual(simple_without_format % 4, "guten Resultate") + + complex_nonlazy = ngettext_lazy( + "Hi %(name)s, %(num)d good result", "Hi %(name)s, %(num)d good results", 4 + ) complex_deferred = ngettext_lazy( - 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num' + "Hi %(name)s, %(num)d good result", + "Hi %(name)s, %(num)d good results", + "num", ) complex_context_nonlazy = npgettext_lazy( - 'Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 4 + "Greeting", + "Hi %(name)s, %(num)d good result", + "Hi %(name)s, %(num)d good results", + 4, ) complex_context_deferred = npgettext_lazy( - 'Greeting', 'Hi %(name)s, %(num)d good result', 'Hi %(name)s, %(num)d good results', 'num' + "Greeting", + "Hi %(name)s, %(num)d good result", + "Hi %(name)s, %(num)d good results", + "num", ) - with translation.override('de'): - self.assertEqual(complex_nonlazy % {'num': 4, 'name': 'Jim'}, 'Hallo Jim, 4 guten Resultate') - self.assertEqual(complex_deferred % {'name': 'Jim', 'num': 1}, 'Hallo Jim, 1 gutes Resultat') - self.assertEqual(complex_deferred % {'name': 'Jim', 'num': 5}, 'Hallo Jim, 5 guten Resultate') - with self.assertRaisesMessage(KeyError, 'Your dictionary lacks key'): - complex_deferred % {'name': 'Jim'} - self.assertEqual(complex_context_nonlazy % {'num': 4, 'name': 'Jim'}, 'Willkommen Jim, 4 guten Resultate') - self.assertEqual(complex_context_deferred % {'name': 'Jim', 'num': 1}, 'Willkommen Jim, 1 gutes Resultat') - self.assertEqual(complex_context_deferred % {'name': 'Jim', 'num': 5}, 'Willkommen Jim, 5 guten Resultate') - with self.assertRaisesMessage(KeyError, 'Your dictionary lacks key'): - complex_context_deferred % {'name': 'Jim'} + with translation.override("de"): + self.assertEqual( + complex_nonlazy % {"num": 4, "name": "Jim"}, + "Hallo Jim, 4 guten Resultate", + ) + self.assertEqual( + complex_deferred % {"name": "Jim", "num": 1}, + "Hallo Jim, 1 gutes Resultat", + ) + self.assertEqual( + complex_deferred % {"name": "Jim", "num": 5}, + "Hallo Jim, 5 guten Resultate", + ) + with self.assertRaisesMessage(KeyError, "Your dictionary lacks key"): + complex_deferred % {"name": "Jim"} + self.assertEqual( + complex_context_nonlazy % {"num": 4, "name": "Jim"}, + "Willkommen Jim, 4 guten Resultate", + ) + self.assertEqual( + complex_context_deferred % {"name": "Jim", "num": 1}, + "Willkommen Jim, 1 gutes Resultat", + ) + self.assertEqual( + complex_context_deferred % {"name": "Jim", "num": 5}, + "Willkommen Jim, 5 guten Resultate", + ) + with self.assertRaisesMessage(KeyError, "Your dictionary lacks key"): + complex_context_deferred % {"name": "Jim"} @override_settings(LOCALE_PATHS=extended_locale_paths) def test_ngettext_lazy_format_style(self): - simple_with_format = ngettext_lazy('{} good result', '{} good results') - simple_context_with_format = npgettext_lazy('Exclamation', '{} good result', '{} good results') + simple_with_format = ngettext_lazy("{} good result", "{} good results") + simple_context_with_format = npgettext_lazy( + "Exclamation", "{} good result", "{} good results" + ) - with translation.override('de'): - self.assertEqual(simple_with_format.format(1), '1 gutes Resultat') - self.assertEqual(simple_with_format.format(4), '4 guten Resultate') - self.assertEqual(simple_context_with_format.format(1), '1 gutes Resultat!') - self.assertEqual(simple_context_with_format.format(4), '4 guten Resultate!') + with translation.override("de"): + self.assertEqual(simple_with_format.format(1), "1 gutes Resultat") + self.assertEqual(simple_with_format.format(4), "4 guten Resultate") + self.assertEqual(simple_context_with_format.format(1), "1 gutes Resultat!") + self.assertEqual(simple_context_with_format.format(4), "4 guten Resultate!") - complex_nonlazy = ngettext_lazy('Hi {name}, {num} good result', 'Hi {name}, {num} good results', 4) + complex_nonlazy = ngettext_lazy( + "Hi {name}, {num} good result", "Hi {name}, {num} good results", 4 + ) complex_deferred = ngettext_lazy( - 'Hi {name}, {num} good result', 'Hi {name}, {num} good results', 'num' + "Hi {name}, {num} good result", "Hi {name}, {num} good results", "num" ) complex_context_nonlazy = npgettext_lazy( - 'Greeting', 'Hi {name}, {num} good result', 'Hi {name}, {num} good results', 4 + "Greeting", + "Hi {name}, {num} good result", + "Hi {name}, {num} good results", + 4, ) complex_context_deferred = npgettext_lazy( - 'Greeting', 'Hi {name}, {num} good result', 'Hi {name}, {num} good results', 'num' + "Greeting", + "Hi {name}, {num} good result", + "Hi {name}, {num} good results", + "num", ) - with translation.override('de'): - self.assertEqual(complex_nonlazy.format(num=4, name='Jim'), 'Hallo Jim, 4 guten Resultate') - self.assertEqual(complex_deferred.format(name='Jim', num=1), 'Hallo Jim, 1 gutes Resultat') - self.assertEqual(complex_deferred.format(name='Jim', num=5), 'Hallo Jim, 5 guten Resultate') - with self.assertRaisesMessage(KeyError, 'Your dictionary lacks key'): - complex_deferred.format(name='Jim') - self.assertEqual(complex_context_nonlazy.format(num=4, name='Jim'), 'Willkommen Jim, 4 guten Resultate') - self.assertEqual(complex_context_deferred.format(name='Jim', num=1), 'Willkommen Jim, 1 gutes Resultat') - self.assertEqual(complex_context_deferred.format(name='Jim', num=5), 'Willkommen Jim, 5 guten Resultate') - with self.assertRaisesMessage(KeyError, 'Your dictionary lacks key'): - complex_context_deferred.format(name='Jim') + with translation.override("de"): + self.assertEqual( + complex_nonlazy.format(num=4, name="Jim"), + "Hallo Jim, 4 guten Resultate", + ) + self.assertEqual( + complex_deferred.format(name="Jim", num=1), + "Hallo Jim, 1 gutes Resultat", + ) + self.assertEqual( + complex_deferred.format(name="Jim", num=5), + "Hallo Jim, 5 guten Resultate", + ) + with self.assertRaisesMessage(KeyError, "Your dictionary lacks key"): + complex_deferred.format(name="Jim") + self.assertEqual( + complex_context_nonlazy.format(num=4, name="Jim"), + "Willkommen Jim, 4 guten Resultate", + ) + self.assertEqual( + complex_context_deferred.format(name="Jim", num=1), + "Willkommen Jim, 1 gutes Resultat", + ) + self.assertEqual( + complex_context_deferred.format(name="Jim", num=5), + "Willkommen Jim, 5 guten Resultate", + ) + with self.assertRaisesMessage(KeyError, "Your dictionary lacks key"): + complex_context_deferred.format(name="Jim") def test_ngettext_lazy_bool(self): - self.assertTrue(ngettext_lazy('%d good result', '%d good results')) - self.assertFalse(ngettext_lazy('', '')) + self.assertTrue(ngettext_lazy("%d good result", "%d good results")) + self.assertFalse(ngettext_lazy("", "")) def test_ngettext_lazy_pickle(self): - s1 = ngettext_lazy('%d good result', '%d good results') - self.assertEqual(s1 % 1, '1 good result') - self.assertEqual(s1 % 8, '8 good results') + s1 = ngettext_lazy("%d good result", "%d good results") + self.assertEqual(s1 % 1, "1 good result") + self.assertEqual(s1 % 8, "8 good results") s2 = pickle.loads(pickle.dumps(s1)) - self.assertEqual(s2 % 1, '1 good result') - self.assertEqual(s2 % 8, '8 good results') + self.assertEqual(s2 % 1, "1 good result") + self.assertEqual(s2 % 8, "8 good results") @override_settings(LOCALE_PATHS=extended_locale_paths) def test_pgettext(self): trans_real._active = Local() trans_real._translations = {} - with translation.override('de'): + with translation.override("de"): self.assertEqual(pgettext("unexisting", "May"), "May") self.assertEqual(pgettext("month name", "May"), "Mai") self.assertEqual(pgettext("verb", "May"), "Kann") - self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, "4 Resultate") + self.assertEqual( + npgettext("search", "%d result", "%d results", 4) % 4, "4 Resultate" + ) def test_empty_value(self): """Empty value must stay empty after being translated (#23196).""" - with translation.override('de'): - self.assertEqual('', gettext('')) - s = mark_safe('') + with translation.override("de"): + self.assertEqual("", gettext("")) + s = mark_safe("") self.assertEqual(s, gettext(s)) @override_settings(LOCALE_PATHS=extended_locale_paths) @@ -293,58 +382,58 @@ class TranslationTests(SimpleTestCase): """ trans_real._active = Local() trans_real._translations = {} - s1 = mark_safe('Password') - s2 = mark_safe('May') - with translation.override('de', deactivate=True): + s1 = mark_safe("Password") + s2 = mark_safe("May") + with translation.override("de", deactivate=True): self.assertIs(type(gettext(s1)), SafeString) - self.assertIs(type(pgettext('month name', s2)), SafeString) - self.assertEqual('aPassword', SafeString('a') + s1) - self.assertEqual('Passworda', s1 + SafeString('a')) - self.assertEqual('Passworda', s1 + mark_safe('a')) - self.assertEqual('aPassword', mark_safe('a') + s1) - self.assertEqual('as', mark_safe('a') + mark_safe('s')) + self.assertIs(type(pgettext("month name", s2)), SafeString) + self.assertEqual("aPassword", SafeString("a") + s1) + self.assertEqual("Passworda", s1 + SafeString("a")) + self.assertEqual("Passworda", s1 + mark_safe("a")) + self.assertEqual("aPassword", mark_safe("a") + s1) + self.assertEqual("as", mark_safe("a") + mark_safe("s")) def test_maclines(self): """ Translations on files with Mac or DOS end of lines will be converted to unix EOF in .po catalogs. """ - ca_translation = trans_real.translation('ca') - ca_translation._catalog['Mac\nEOF\n'] = 'Catalan Mac\nEOF\n' - ca_translation._catalog['Win\nEOF\n'] = 'Catalan Win\nEOF\n' - with translation.override('ca', deactivate=True): - self.assertEqual('Catalan Mac\nEOF\n', gettext('Mac\rEOF\r')) - self.assertEqual('Catalan Win\nEOF\n', gettext('Win\r\nEOF\r\n')) + ca_translation = trans_real.translation("ca") + ca_translation._catalog["Mac\nEOF\n"] = "Catalan Mac\nEOF\n" + ca_translation._catalog["Win\nEOF\n"] = "Catalan Win\nEOF\n" + with translation.override("ca", deactivate=True): + self.assertEqual("Catalan Mac\nEOF\n", gettext("Mac\rEOF\r")) + self.assertEqual("Catalan Win\nEOF\n", gettext("Win\r\nEOF\r\n")) def test_to_locale(self): tests = ( - ('en', 'en'), - ('EN', 'en'), - ('en-us', 'en_US'), - ('EN-US', 'en_US'), - ('en_US', 'en_US'), + ("en", "en"), + ("EN", "en"), + ("en-us", "en_US"), + ("EN-US", "en_US"), + ("en_US", "en_US"), # With > 2 characters after the dash. - ('sr-latn', 'sr_Latn'), - ('sr-LATN', 'sr_Latn'), - ('sr_Latn', 'sr_Latn'), + ("sr-latn", "sr_Latn"), + ("sr-LATN", "sr_Latn"), + ("sr_Latn", "sr_Latn"), # 3-char language codes. - ('ber-MA', 'ber_MA'), - ('BER-MA', 'ber_MA'), - ('BER_MA', 'ber_MA'), - ('ber_MA', 'ber_MA'), + ("ber-MA", "ber_MA"), + ("BER-MA", "ber_MA"), + ("BER_MA", "ber_MA"), + ("ber_MA", "ber_MA"), # With private use subtag (x-informal). - ('nl-nl-x-informal', 'nl_NL-x-informal'), - ('NL-NL-X-INFORMAL', 'nl_NL-x-informal'), - ('sr-latn-x-informal', 'sr_Latn-x-informal'), - ('SR-LATN-X-INFORMAL', 'sr_Latn-x-informal'), + ("nl-nl-x-informal", "nl_NL-x-informal"), + ("NL-NL-X-INFORMAL", "nl_NL-x-informal"), + ("sr-latn-x-informal", "sr_Latn-x-informal"), + ("SR-LATN-X-INFORMAL", "sr_Latn-x-informal"), ) for lang, locale in tests: with self.subTest(lang=lang): self.assertEqual(to_locale(lang), locale) def test_to_language(self): - self.assertEqual(to_language('en_US'), 'en-us') - self.assertEqual(to_language('sr_Lat'), 'sr-lat') + self.assertEqual(to_language("en_US"), "en-us") + self.assertEqual(to_language("sr_Lat"), "sr-lat") def test_language_bidi(self): self.assertIs(get_language_bidi(), False) @@ -353,7 +442,7 @@ class TranslationTests(SimpleTestCase): def test_language_bidi_null(self): self.assertIs(trans_null.get_language_bidi(), False) - with override_settings(LANGUAGE_CODE='he'): + with override_settings(LANGUAGE_CODE="he"): self.assertIs(get_language_bidi(), True) @@ -371,15 +460,15 @@ class TranslationLoadingTests(SimpleTestCase): @override_settings( USE_I18N=True, - LANGUAGE_CODE='en', + LANGUAGE_CODE="en", LANGUAGES=[ - ('en', 'English'), - ('en-ca', 'English (Canada)'), - ('en-nz', 'English (New Zealand)'), - ('en-au', 'English (Australia)'), + ("en", "English"), + ("en-ca", "English (Canada)"), + ("en-nz", "English (New Zealand)"), + ("en-au", "English (Australia)"), ], - LOCALE_PATHS=[os.path.join(here, 'loading')], - INSTALLED_APPS=['i18n.loading_app'], + LOCALE_PATHS=[os.path.join(here, "loading")], + INSTALLED_APPS=["i18n.loading_app"], ) def test_translation_loading(self): """ @@ -387,10 +476,10 @@ class TranslationLoadingTests(SimpleTestCase): "loading". Catalogs are merged correctly. """ tests = [ - ('en', 'local country person'), - ('en_AU', 'aussie'), - ('en_NZ', 'kiwi'), - ('en_CA', 'canuck'), + ("en", "local country person"), + ("en_AU", "aussie"), + ("en_NZ", "kiwi"), + ("en_CA", "canuck"), ] # Load all relevant translations. for language, _ in tests: @@ -399,11 +488,10 @@ class TranslationLoadingTests(SimpleTestCase): for language, nickname in tests: with self.subTest(language=language): activate(language) - self.assertEqual(gettext('local country person'), nickname) + self.assertEqual(gettext("local country person"), nickname) class TranslationThreadSafetyTests(SimpleTestCase): - def setUp(self): self._old_language = get_language() self._translations = trans_real._translations @@ -413,10 +501,10 @@ class TranslationThreadSafetyTests(SimpleTestCase): class sideeffect_str(str): def split(self, *args, **kwargs): res = str.split(self, *args, **kwargs) - trans_real._translations['en-YY'] = None + trans_real._translations["en-YY"] = None return res - trans_real._translations = {sideeffect_str('en-XX'): None} + trans_real._translations = {sideeffect_str("en-XX"): None} def tearDown(self): trans_real._translations = self._translations @@ -425,29 +513,30 @@ class TranslationThreadSafetyTests(SimpleTestCase): def test_bug14894_translation_activate_thread_safety(self): translation_count = len(trans_real._translations) # May raise RuntimeError if translation.activate() isn't thread-safe. - translation.activate('pl') + translation.activate("pl") # make sure sideeffect_str actually added a new translation self.assertLess(translation_count, len(trans_real._translations)) class FormattingTests(SimpleTestCase): - def setUp(self): super().setUp() - self.n = decimal.Decimal('66666.666') + self.n = decimal.Decimal("66666.666") self.f = 99999.999 self.d = datetime.date(2009, 12, 31) self.dt = datetime.datetime(2009, 12, 31, 20, 50) self.t = datetime.time(10, 15, 48) self.long = 10000 - self.ctxt = Context({ - 'n': self.n, - 't': self.t, - 'd': self.d, - 'dt': self.dt, - 'f': self.f, - 'l': self.long, - }) + self.ctxt = Context( + { + "n": self.n, + "t": self.t, + "d": self.d, + "dt": self.dt, + "f": self.f, + "l": self.long, + } + ) def test_all_format_strings(self): all_locales = LANG_INFO.keys() @@ -455,55 +544,129 @@ class FormattingTests(SimpleTestCase): some_datetime = datetime.datetime(2017, 10, 14, 10, 23) for locale in all_locales: with self.subTest(locale=locale), translation.override(locale): - self.assertIn('2017', date_format(some_date)) # Uses DATE_FORMAT by default - self.assertIn('23', time_format(some_datetime)) # Uses TIME_FORMAT by default - self.assertIn('2017', date_format(some_datetime, format=get_format('DATETIME_FORMAT'))) - self.assertIn('2017', date_format(some_date, format=get_format('YEAR_MONTH_FORMAT'))) - self.assertIn('14', date_format(some_date, format=get_format('MONTH_DAY_FORMAT'))) - self.assertIn('2017', date_format(some_date, format=get_format('SHORT_DATE_FORMAT'))) - self.assertIn('2017', date_format(some_datetime, format=get_format('SHORT_DATETIME_FORMAT'))) + self.assertIn( + "2017", date_format(some_date) + ) # Uses DATE_FORMAT by default + self.assertIn( + "23", time_format(some_datetime) + ) # Uses TIME_FORMAT by default + self.assertIn( + "2017", + date_format(some_datetime, format=get_format("DATETIME_FORMAT")), + ) + self.assertIn( + "2017", + date_format(some_date, format=get_format("YEAR_MONTH_FORMAT")), + ) + self.assertIn( + "14", date_format(some_date, format=get_format("MONTH_DAY_FORMAT")) + ) + self.assertIn( + "2017", + date_format(some_date, format=get_format("SHORT_DATE_FORMAT")), + ) + self.assertIn( + "2017", + date_format( + some_datetime, format=get_format("SHORT_DATETIME_FORMAT") + ), + ) def test_locale_independent(self): """ Localization of numbers """ with self.settings(USE_THOUSAND_SEPARATOR=False): - self.assertEqual('66666.66', nformat(self.n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',')) - self.assertEqual('66666A6', nformat(self.n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B')) - self.assertEqual('66666', nformat(self.n, decimal_sep='X', decimal_pos=0, grouping=1, thousand_sep='Y')) + self.assertEqual( + "66666.66", + nformat( + self.n, decimal_sep=".", decimal_pos=2, grouping=3, thousand_sep="," + ), + ) + self.assertEqual( + "66666A6", + nformat( + self.n, decimal_sep="A", decimal_pos=1, grouping=1, thousand_sep="B" + ), + ) + self.assertEqual( + "66666", + nformat( + self.n, decimal_sep="X", decimal_pos=0, grouping=1, thousand_sep="Y" + ), + ) with self.settings(USE_THOUSAND_SEPARATOR=True): self.assertEqual( - '66,666.66', - nformat(self.n, decimal_sep='.', decimal_pos=2, grouping=3, thousand_sep=',') + "66,666.66", + nformat( + self.n, decimal_sep=".", decimal_pos=2, grouping=3, thousand_sep="," + ), + ) + self.assertEqual( + "6B6B6B6B6A6", + nformat( + self.n, decimal_sep="A", decimal_pos=1, grouping=1, thousand_sep="B" + ), ) self.assertEqual( - '6B6B6B6B6A6', - nformat(self.n, decimal_sep='A', decimal_pos=1, grouping=1, thousand_sep='B') + "-66666.6", nformat(-66666.666, decimal_sep=".", decimal_pos=1) ) - self.assertEqual('-66666.6', nformat(-66666.666, decimal_sep='.', decimal_pos=1)) - self.assertEqual('-66666.0', nformat(int('-66666'), decimal_sep='.', decimal_pos=1)) - self.assertEqual('10000.0', nformat(self.long, decimal_sep='.', decimal_pos=1)) self.assertEqual( - '10,00,00,000.00', - nformat(100000000.00, decimal_sep='.', decimal_pos=2, grouping=(3, 2, 0), thousand_sep=',') + "-66666.0", nformat(int("-66666"), decimal_sep=".", decimal_pos=1) ) self.assertEqual( - '1,0,00,000,0000.00', - nformat(10000000000.00, decimal_sep='.', decimal_pos=2, grouping=(4, 3, 2, 1, 0), thousand_sep=',') + "10000.0", nformat(self.long, decimal_sep=".", decimal_pos=1) ) self.assertEqual( - '10000,00,000.00', - nformat(1000000000.00, decimal_sep='.', decimal_pos=2, grouping=(3, 2, -1), thousand_sep=',') + "10,00,00,000.00", + nformat( + 100000000.00, + decimal_sep=".", + decimal_pos=2, + grouping=(3, 2, 0), + thousand_sep=",", + ), + ) + self.assertEqual( + "1,0,00,000,0000.00", + nformat( + 10000000000.00, + decimal_sep=".", + decimal_pos=2, + grouping=(4, 3, 2, 1, 0), + thousand_sep=",", + ), + ) + self.assertEqual( + "10000,00,000.00", + nformat( + 1000000000.00, + decimal_sep=".", + decimal_pos=2, + grouping=(3, 2, -1), + thousand_sep=",", + ), ) # This unusual grouping/force_grouping combination may be triggered by the intcomma filter (#17414) self.assertEqual( - '10000', - nformat(self.long, decimal_sep='.', decimal_pos=0, grouping=0, force_grouping=True) + "10000", + nformat( + self.long, + decimal_sep=".", + decimal_pos=0, + grouping=0, + force_grouping=True, + ), ) # date filter - self.assertEqual('31.12.2009 в 20:50', Template('{{ dt|date:"d.m.Y в H:i" }}').render(self.ctxt)) - self.assertEqual('⌚ 10:15', Template('{{ t|time:"⌚ H:i" }}').render(self.ctxt)) + self.assertEqual( + "31.12.2009 в 20:50", + Template('{{ dt|date:"d.m.Y в H:i" }}').render(self.ctxt), + ) + self.assertEqual( + "⌚ 10:15", Template('{{ t|time:"⌚ H:i" }}').render(self.ctxt) + ) @ignore_warnings(category=RemovedInDjango50Warning) @override_settings(USE_L10N=False) @@ -512,63 +675,92 @@ class FormattingTests(SimpleTestCase): Catalan locale with format i18n disabled translations will be used, but not formats """ - with translation.override('ca', deactivate=True): + with translation.override("ca", deactivate=True): self.maxDiff = 3000 - self.assertEqual('N j, Y', get_format('DATE_FORMAT')) - self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK')) - self.assertEqual('.', get_format('DECIMAL_SEPARATOR')) - self.assertEqual('10:15 a.m.', time_format(self.t)) - self.assertEqual('Des. 31, 2009', date_format(self.d)) - self.assertEqual('desembre 2009', date_format(self.d, 'YEAR_MONTH_FORMAT')) - self.assertEqual('12/31/2009 8:50 p.m.', date_format(self.dt, 'SHORT_DATETIME_FORMAT')) - self.assertEqual('No localizable', localize('No localizable')) - self.assertEqual('66666.666', localize(self.n)) - self.assertEqual('99999.999', localize(self.f)) - self.assertEqual('10000', localize(self.long)) - self.assertEqual('Des. 31, 2009', localize(self.d)) - self.assertEqual('Des. 31, 2009, 8:50 p.m.', localize(self.dt)) - self.assertEqual('66666.666', Template('{{ n }}').render(self.ctxt)) - self.assertEqual('99999.999', Template('{{ f }}').render(self.ctxt)) - self.assertEqual('Des. 31, 2009', Template('{{ d }}').render(self.ctxt)) - self.assertEqual('Des. 31, 2009, 8:50 p.m.', Template('{{ dt }}').render(self.ctxt)) - self.assertEqual('66666.67', Template('{{ n|floatformat:"2u" }}').render(self.ctxt)) - self.assertEqual('100000.0', Template('{{ f|floatformat:"u" }}').render(self.ctxt)) + self.assertEqual("N j, Y", get_format("DATE_FORMAT")) + self.assertEqual(0, get_format("FIRST_DAY_OF_WEEK")) + self.assertEqual(".", get_format("DECIMAL_SEPARATOR")) + self.assertEqual("10:15 a.m.", time_format(self.t)) + self.assertEqual("Des. 31, 2009", date_format(self.d)) + self.assertEqual("desembre 2009", date_format(self.d, "YEAR_MONTH_FORMAT")) + self.assertEqual( + "12/31/2009 8:50 p.m.", date_format(self.dt, "SHORT_DATETIME_FORMAT") + ) + self.assertEqual("No localizable", localize("No localizable")) + self.assertEqual("66666.666", localize(self.n)) + self.assertEqual("99999.999", localize(self.f)) + self.assertEqual("10000", localize(self.long)) + self.assertEqual("Des. 31, 2009", localize(self.d)) + self.assertEqual("Des. 31, 2009, 8:50 p.m.", localize(self.dt)) + self.assertEqual("66666.666", Template("{{ n }}").render(self.ctxt)) + self.assertEqual("99999.999", Template("{{ f }}").render(self.ctxt)) + self.assertEqual("Des. 31, 2009", Template("{{ d }}").render(self.ctxt)) + self.assertEqual( + "Des. 31, 2009, 8:50 p.m.", Template("{{ dt }}").render(self.ctxt) + ) self.assertEqual( - '66666.67', + "66666.67", Template('{{ n|floatformat:"2u" }}').render(self.ctxt) + ) + self.assertEqual( + "100000.0", Template('{{ f|floatformat:"u" }}').render(self.ctxt) + ) + self.assertEqual( + "66666.67", Template('{{ n|floatformat:"2gu" }}').render(self.ctxt), ) self.assertEqual( - '100000.0', + "100000.0", Template('{{ f|floatformat:"ug" }}').render(self.ctxt), ) - self.assertEqual('10:15 a.m.', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt)) - self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual( - '12/31/2009 8:50 p.m.', Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt) + "10:15 a.m.", Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt) + ) + self.assertEqual( + "12/31/2009", + Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt), + ) + self.assertEqual( + "12/31/2009 8:50 p.m.", + Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt), ) - form = I18nForm({ - 'decimal_field': '66666,666', - 'float_field': '99999,999', - 'date_field': '31/12/2009', - 'datetime_field': '31/12/2009 20:50', - 'time_field': '20:50', - 'integer_field': '1.234', - }) + form = I18nForm( + { + "decimal_field": "66666,666", + "float_field": "99999,999", + "date_field": "31/12/2009", + "datetime_field": "31/12/2009 20:50", + "time_field": "20:50", + "integer_field": "1.234", + } + ) self.assertFalse(form.is_valid()) - self.assertEqual(['Introdu\xefu un n\xfamero.'], form.errors['float_field']) - self.assertEqual(['Introdu\xefu un n\xfamero.'], form.errors['decimal_field']) - self.assertEqual(['Introdu\xefu una data v\xe0lida.'], form.errors['date_field']) - self.assertEqual(['Introdu\xefu una data/hora v\xe0lides.'], form.errors['datetime_field']) - self.assertEqual(['Introdu\xefu un n\xfamero enter.'], form.errors['integer_field']) - - form2 = SelectDateForm({ - 'date_field_month': '12', - 'date_field_day': '31', - 'date_field_year': '2009' - }) + self.assertEqual(["Introdu\xefu un n\xfamero."], form.errors["float_field"]) + self.assertEqual( + ["Introdu\xefu un n\xfamero."], form.errors["decimal_field"] + ) + self.assertEqual( + ["Introdu\xefu una data v\xe0lida."], form.errors["date_field"] + ) + self.assertEqual( + ["Introdu\xefu una data/hora v\xe0lides."], + form.errors["datetime_field"], + ) + self.assertEqual( + ["Introdu\xefu un n\xfamero enter."], form.errors["integer_field"] + ) + + form2 = SelectDateForm( + { + "date_field_month": "12", + "date_field_day": "31", + "date_field_year": "2009", + } + ) self.assertTrue(form2.is_valid()) - self.assertEqual(datetime.date(2009, 12, 31), form2.cleaned_data['date_field']) + self.assertEqual( + datetime.date(2009, 12, 31), form2.cleaned_data["date_field"] + ) self.assertHTMLEqual( '<select name="mydate_month" id="id_mydate_month">' '<option value="">---</option>' @@ -584,7 +776,7 @@ class FormattingTests(SimpleTestCase): '<option value="10">octubre</option>' '<option value="11">novembre</option>' '<option value="12" selected>desembre</option>' - '</select>' + "</select>" '<select name="mydate_day" id="id_mydate_day">' '<option value="">---</option>' '<option value="1">1</option>' @@ -618,7 +810,7 @@ class FormattingTests(SimpleTestCase): '<option value="29">29</option>' '<option value="30">30</option>' '<option value="31" selected>31</option>' - '</select>' + "</select>" '<select name="mydate_year" id="id_mydate_year">' '<option value="">---</option>' '<option value="2009" selected>2009</option>' @@ -631,17 +823,25 @@ class FormattingTests(SimpleTestCase): '<option value="2016">2016</option>' '<option value="2017">2017</option>' '<option value="2018">2018</option>' - '</select>', - forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) + "</select>", + forms.SelectDateWidget(years=range(2009, 2019)).render( + "mydate", datetime.date(2009, 12, 31) + ), ) # We shouldn't change the behavior of the floatformat filter re: # thousand separator and grouping when localization is disabled # even if the USE_THOUSAND_SEPARATOR, NUMBER_GROUPING and # THOUSAND_SEPARATOR settings are specified. - with self.settings(USE_THOUSAND_SEPARATOR=True, NUMBER_GROUPING=1, THOUSAND_SEPARATOR='!'): - self.assertEqual('66666.67', Template('{{ n|floatformat:"2u" }}').render(self.ctxt)) - self.assertEqual('100000.0', Template('{{ f|floatformat:"u" }}').render(self.ctxt)) + with self.settings( + USE_THOUSAND_SEPARATOR=True, NUMBER_GROUPING=1, THOUSAND_SEPARATOR="!" + ): + self.assertEqual( + "66666.67", Template('{{ n|floatformat:"2u" }}').render(self.ctxt) + ) + self.assertEqual( + "100000.0", Template('{{ f|floatformat:"u" }}').render(self.ctxt) + ) def test_false_like_locale_formats(self): """ @@ -649,113 +849,161 @@ class FormattingTests(SimpleTestCase): even if they would be interpreted as False in a conditional test (e.g. 0 or empty string) (#16938). """ - with translation.override('fr'): - with self.settings(USE_THOUSAND_SEPARATOR=True, THOUSAND_SEPARATOR='!'): - self.assertEqual('\xa0', get_format('THOUSAND_SEPARATOR')) + with translation.override("fr"): + with self.settings(USE_THOUSAND_SEPARATOR=True, THOUSAND_SEPARATOR="!"): + self.assertEqual("\xa0", get_format("THOUSAND_SEPARATOR")) # Even a second time (after the format has been cached)... - self.assertEqual('\xa0', get_format('THOUSAND_SEPARATOR')) + self.assertEqual("\xa0", get_format("THOUSAND_SEPARATOR")) with self.settings(FIRST_DAY_OF_WEEK=0): - self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK')) + self.assertEqual(1, get_format("FIRST_DAY_OF_WEEK")) # Even a second time (after the format has been cached)... - self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK')) + self.assertEqual(1, get_format("FIRST_DAY_OF_WEEK")) def test_l10n_enabled(self): self.maxDiff = 3000 # Catalan locale - with translation.override('ca', deactivate=True): - self.assertEqual(r'j \d\e F \d\e Y', get_format('DATE_FORMAT')) - self.assertEqual(1, get_format('FIRST_DAY_OF_WEEK')) - self.assertEqual(',', get_format('DECIMAL_SEPARATOR')) - self.assertEqual('10:15', time_format(self.t)) - self.assertEqual('31 de desembre de 2009', date_format(self.d)) - self.assertEqual('desembre del 2009', date_format(self.d, 'YEAR_MONTH_FORMAT')) - self.assertEqual('31/12/2009 20:50', date_format(self.dt, 'SHORT_DATETIME_FORMAT')) - self.assertEqual('No localizable', localize('No localizable')) + with translation.override("ca", deactivate=True): + self.assertEqual(r"j \d\e F \d\e Y", get_format("DATE_FORMAT")) + self.assertEqual(1, get_format("FIRST_DAY_OF_WEEK")) + self.assertEqual(",", get_format("DECIMAL_SEPARATOR")) + self.assertEqual("10:15", time_format(self.t)) + self.assertEqual("31 de desembre de 2009", date_format(self.d)) + self.assertEqual( + "desembre del 2009", date_format(self.d, "YEAR_MONTH_FORMAT") + ) + self.assertEqual( + "31/12/2009 20:50", date_format(self.dt, "SHORT_DATETIME_FORMAT") + ) + self.assertEqual("No localizable", localize("No localizable")) with self.settings(USE_THOUSAND_SEPARATOR=True): - self.assertEqual('66.666,666', localize(self.n)) - self.assertEqual('99.999,999', localize(self.f)) - self.assertEqual('10.000', localize(self.long)) - self.assertEqual('True', localize(True)) + self.assertEqual("66.666,666", localize(self.n)) + self.assertEqual("99.999,999", localize(self.f)) + self.assertEqual("10.000", localize(self.long)) + self.assertEqual("True", localize(True)) with self.settings(USE_THOUSAND_SEPARATOR=False): - self.assertEqual('66666,666', localize(self.n)) - self.assertEqual('99999,999', localize(self.f)) - self.assertEqual('10000', localize(self.long)) - self.assertEqual('31 de desembre de 2009', localize(self.d)) - self.assertEqual('31 de desembre de 2009 a les 20:50', localize(self.dt)) + self.assertEqual("66666,666", localize(self.n)) + self.assertEqual("99999,999", localize(self.f)) + self.assertEqual("10000", localize(self.long)) + self.assertEqual("31 de desembre de 2009", localize(self.d)) + self.assertEqual( + "31 de desembre de 2009 a les 20:50", localize(self.dt) + ) with self.settings(USE_THOUSAND_SEPARATOR=True): - self.assertEqual('66.666,666', Template('{{ n }}').render(self.ctxt)) - self.assertEqual('99.999,999', Template('{{ f }}').render(self.ctxt)) - self.assertEqual('10.000', Template('{{ l }}').render(self.ctxt)) + self.assertEqual("66.666,666", Template("{{ n }}").render(self.ctxt)) + self.assertEqual("99.999,999", Template("{{ f }}").render(self.ctxt)) + self.assertEqual("10.000", Template("{{ l }}").render(self.ctxt)) with self.settings(USE_THOUSAND_SEPARATOR=True): - form3 = I18nForm({ - 'decimal_field': '66.666,666', - 'float_field': '99.999,999', - 'date_field': '31/12/2009', - 'datetime_field': '31/12/2009 20:50', - 'time_field': '20:50', - 'integer_field': '1.234', - }) + form3 = I18nForm( + { + "decimal_field": "66.666,666", + "float_field": "99.999,999", + "date_field": "31/12/2009", + "datetime_field": "31/12/2009 20:50", + "time_field": "20:50", + "integer_field": "1.234", + } + ) self.assertTrue(form3.is_valid()) - self.assertEqual(decimal.Decimal('66666.666'), form3.cleaned_data['decimal_field']) - self.assertEqual(99999.999, form3.cleaned_data['float_field']) - self.assertEqual(datetime.date(2009, 12, 31), form3.cleaned_data['date_field']) - self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), form3.cleaned_data['datetime_field']) - self.assertEqual(datetime.time(20, 50), form3.cleaned_data['time_field']) - self.assertEqual(1234, form3.cleaned_data['integer_field']) + self.assertEqual( + decimal.Decimal("66666.666"), form3.cleaned_data["decimal_field"] + ) + self.assertEqual(99999.999, form3.cleaned_data["float_field"]) + self.assertEqual( + datetime.date(2009, 12, 31), form3.cleaned_data["date_field"] + ) + self.assertEqual( + datetime.datetime(2009, 12, 31, 20, 50), + form3.cleaned_data["datetime_field"], + ) + self.assertEqual( + datetime.time(20, 50), form3.cleaned_data["time_field"] + ) + self.assertEqual(1234, form3.cleaned_data["integer_field"]) with self.settings(USE_THOUSAND_SEPARATOR=False): - self.assertEqual('66666,666', Template('{{ n }}').render(self.ctxt)) - self.assertEqual('99999,999', Template('{{ f }}').render(self.ctxt)) - self.assertEqual('31 de desembre de 2009', Template('{{ d }}').render(self.ctxt)) - self.assertEqual('31 de desembre de 2009 a les 20:50', Template('{{ dt }}').render(self.ctxt)) - self.assertEqual('66666,67', Template('{{ n|floatformat:2 }}').render(self.ctxt)) - self.assertEqual('100000,0', Template('{{ f|floatformat }}').render(self.ctxt)) + self.assertEqual("66666,666", Template("{{ n }}").render(self.ctxt)) + self.assertEqual("99999,999", Template("{{ f }}").render(self.ctxt)) + self.assertEqual( + "31 de desembre de 2009", Template("{{ d }}").render(self.ctxt) + ) + self.assertEqual( + "31 de desembre de 2009 a les 20:50", + Template("{{ dt }}").render(self.ctxt), + ) self.assertEqual( - '66.666,67', + "66666,67", Template("{{ n|floatformat:2 }}").render(self.ctxt) + ) + self.assertEqual( + "100000,0", Template("{{ f|floatformat }}").render(self.ctxt) + ) + self.assertEqual( + "66.666,67", Template('{{ n|floatformat:"2g" }}').render(self.ctxt), ) self.assertEqual( - '100.000,0', + "100.000,0", Template('{{ f|floatformat:"g" }}').render(self.ctxt), ) - self.assertEqual('10:15', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt)) - self.assertEqual('31/12/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual( - '31/12/2009 20:50', - Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt) + "10:15", Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt) + ) + self.assertEqual( + "31/12/2009", + Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt), + ) + self.assertEqual( + "31/12/2009 20:50", + Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt), + ) + self.assertEqual( + date_format(datetime.datetime.now(), "DATE_FORMAT"), + Template('{% now "DATE_FORMAT" %}').render(self.ctxt), ) - self.assertEqual(date_format(datetime.datetime.now(), "DATE_FORMAT"), - Template('{% now "DATE_FORMAT" %}').render(self.ctxt)) with self.settings(USE_THOUSAND_SEPARATOR=False): - form4 = I18nForm({ - 'decimal_field': '66666,666', - 'float_field': '99999,999', - 'date_field': '31/12/2009', - 'datetime_field': '31/12/2009 20:50', - 'time_field': '20:50', - 'integer_field': '1234', - }) + form4 = I18nForm( + { + "decimal_field": "66666,666", + "float_field": "99999,999", + "date_field": "31/12/2009", + "datetime_field": "31/12/2009 20:50", + "time_field": "20:50", + "integer_field": "1234", + } + ) self.assertTrue(form4.is_valid()) - self.assertEqual(decimal.Decimal('66666.666'), form4.cleaned_data['decimal_field']) - self.assertEqual(99999.999, form4.cleaned_data['float_field']) - self.assertEqual(datetime.date(2009, 12, 31), form4.cleaned_data['date_field']) - self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), form4.cleaned_data['datetime_field']) - self.assertEqual(datetime.time(20, 50), form4.cleaned_data['time_field']) - self.assertEqual(1234, form4.cleaned_data['integer_field']) - - form5 = SelectDateForm({ - 'date_field_month': '12', - 'date_field_day': '31', - 'date_field_year': '2009' - }) + self.assertEqual( + decimal.Decimal("66666.666"), form4.cleaned_data["decimal_field"] + ) + self.assertEqual(99999.999, form4.cleaned_data["float_field"]) + self.assertEqual( + datetime.date(2009, 12, 31), form4.cleaned_data["date_field"] + ) + self.assertEqual( + datetime.datetime(2009, 12, 31, 20, 50), + form4.cleaned_data["datetime_field"], + ) + self.assertEqual( + datetime.time(20, 50), form4.cleaned_data["time_field"] + ) + self.assertEqual(1234, form4.cleaned_data["integer_field"]) + + form5 = SelectDateForm( + { + "date_field_month": "12", + "date_field_day": "31", + "date_field_year": "2009", + } + ) self.assertTrue(form5.is_valid()) - self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field']) + self.assertEqual( + datetime.date(2009, 12, 31), form5.cleaned_data["date_field"] + ) self.assertHTMLEqual( '<select name="mydate_day" id="id_mydate_day">' '<option value="">---</option>' @@ -790,7 +1038,7 @@ class FormattingTests(SimpleTestCase): '<option value="29">29</option>' '<option value="30">30</option>' '<option value="31" selected>31</option>' - '</select>' + "</select>" '<select name="mydate_month" id="id_mydate_month">' '<option value="">---</option>' '<option value="1">gener</option>' @@ -805,7 +1053,7 @@ class FormattingTests(SimpleTestCase): '<option value="10">octubre</option>' '<option value="11">novembre</option>' '<option value="12" selected>desembre</option>' - '</select>' + "</select>" '<select name="mydate_year" id="id_mydate_year">' '<option value="">---</option>' '<option value="2009" selected>2009</option>' @@ -818,12 +1066,14 @@ class FormattingTests(SimpleTestCase): '<option value="2016">2016</option>' '<option value="2017">2017</option>' '<option value="2018">2018</option>' - '</select>', - forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) + "</select>", + forms.SelectDateWidget(years=range(2009, 2019)).render( + "mydate", datetime.date(2009, 12, 31) + ), ) # Russian locale (with E as month) - with translation.override('ru', deactivate=True): + with translation.override("ru", deactivate=True): self.assertHTMLEqual( '<select name="mydate_day" id="id_mydate_day">' '<option value="">---</option>' @@ -858,7 +1108,7 @@ class FormattingTests(SimpleTestCase): '<option value="29">29</option>' '<option value="30">30</option>' '<option value="31" selected>31</option>' - '</select>' + "</select>" '<select name="mydate_month" id="id_mydate_month">' '<option value="">---</option>' '<option value="1">\u042f\u043d\u0432\u0430\u0440\u044c</option>' @@ -873,7 +1123,7 @@ class FormattingTests(SimpleTestCase): '<option value="10">\u041e\u043a\u0442\u044f\u0431\u0440\u044c</option>' '<option value="11">\u041d\u043e\u044f\u0431\u0440\u044c</option>' '<option value="12" selected>\u0414\u0435\u043a\u0430\u0431\u0440\u044c</option>' - '</select>' + "</select>" '<select name="mydate_year" id="id_mydate_year">' '<option value="">---</option>' '<option value="2009" selected>2009</option>' @@ -886,81 +1136,107 @@ class FormattingTests(SimpleTestCase): '<option value="2016">2016</option>' '<option value="2017">2017</option>' '<option value="2018">2018</option>' - '</select>', - forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) + "</select>", + forms.SelectDateWidget(years=range(2009, 2019)).render( + "mydate", datetime.date(2009, 12, 31) + ), ) # English locale - with translation.override('en', deactivate=True): - self.assertEqual('N j, Y', get_format('DATE_FORMAT')) - self.assertEqual(0, get_format('FIRST_DAY_OF_WEEK')) - self.assertEqual('.', get_format('DECIMAL_SEPARATOR')) - self.assertEqual('Dec. 31, 2009', date_format(self.d)) - self.assertEqual('December 2009', date_format(self.d, 'YEAR_MONTH_FORMAT')) - self.assertEqual('12/31/2009 8:50 p.m.', date_format(self.dt, 'SHORT_DATETIME_FORMAT')) - self.assertEqual('No localizable', localize('No localizable')) + with translation.override("en", deactivate=True): + self.assertEqual("N j, Y", get_format("DATE_FORMAT")) + self.assertEqual(0, get_format("FIRST_DAY_OF_WEEK")) + self.assertEqual(".", get_format("DECIMAL_SEPARATOR")) + self.assertEqual("Dec. 31, 2009", date_format(self.d)) + self.assertEqual("December 2009", date_format(self.d, "YEAR_MONTH_FORMAT")) + self.assertEqual( + "12/31/2009 8:50 p.m.", date_format(self.dt, "SHORT_DATETIME_FORMAT") + ) + self.assertEqual("No localizable", localize("No localizable")) with self.settings(USE_THOUSAND_SEPARATOR=True): - self.assertEqual('66,666.666', localize(self.n)) - self.assertEqual('99,999.999', localize(self.f)) - self.assertEqual('10,000', localize(self.long)) + self.assertEqual("66,666.666", localize(self.n)) + self.assertEqual("99,999.999", localize(self.f)) + self.assertEqual("10,000", localize(self.long)) with self.settings(USE_THOUSAND_SEPARATOR=False): - self.assertEqual('66666.666', localize(self.n)) - self.assertEqual('99999.999', localize(self.f)) - self.assertEqual('10000', localize(self.long)) - self.assertEqual('Dec. 31, 2009', localize(self.d)) - self.assertEqual('Dec. 31, 2009, 8:50 p.m.', localize(self.dt)) + self.assertEqual("66666.666", localize(self.n)) + self.assertEqual("99999.999", localize(self.f)) + self.assertEqual("10000", localize(self.long)) + self.assertEqual("Dec. 31, 2009", localize(self.d)) + self.assertEqual("Dec. 31, 2009, 8:50 p.m.", localize(self.dt)) with self.settings(USE_THOUSAND_SEPARATOR=True): - self.assertEqual('66,666.666', Template('{{ n }}').render(self.ctxt)) - self.assertEqual('99,999.999', Template('{{ f }}').render(self.ctxt)) - self.assertEqual('10,000', Template('{{ l }}').render(self.ctxt)) + self.assertEqual("66,666.666", Template("{{ n }}").render(self.ctxt)) + self.assertEqual("99,999.999", Template("{{ f }}").render(self.ctxt)) + self.assertEqual("10,000", Template("{{ l }}").render(self.ctxt)) with self.settings(USE_THOUSAND_SEPARATOR=False): - self.assertEqual('66666.666', Template('{{ n }}').render(self.ctxt)) - self.assertEqual('99999.999', Template('{{ f }}').render(self.ctxt)) - self.assertEqual('Dec. 31, 2009', Template('{{ d }}').render(self.ctxt)) - self.assertEqual('Dec. 31, 2009, 8:50 p.m.', Template('{{ dt }}').render(self.ctxt)) - self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt)) - self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt)) + self.assertEqual("66666.666", Template("{{ n }}").render(self.ctxt)) + self.assertEqual("99999.999", Template("{{ f }}").render(self.ctxt)) + self.assertEqual("Dec. 31, 2009", Template("{{ d }}").render(self.ctxt)) + self.assertEqual( + "Dec. 31, 2009, 8:50 p.m.", Template("{{ dt }}").render(self.ctxt) + ) + self.assertEqual( + "66666.67", Template("{{ n|floatformat:2 }}").render(self.ctxt) + ) self.assertEqual( - '66,666.67', + "100000.0", Template("{{ f|floatformat }}").render(self.ctxt) + ) + self.assertEqual( + "66,666.67", Template('{{ n|floatformat:"2g" }}').render(self.ctxt), ) self.assertEqual( - '100,000.0', + "100,000.0", Template('{{ f|floatformat:"g" }}').render(self.ctxt), ) - self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt)) self.assertEqual( - '12/31/2009 8:50 p.m.', - Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt) + "12/31/2009", + Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt), + ) + self.assertEqual( + "12/31/2009 8:50 p.m.", + Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt), ) - form5 = I18nForm({ - 'decimal_field': '66666.666', - 'float_field': '99999.999', - 'date_field': '12/31/2009', - 'datetime_field': '12/31/2009 20:50', - 'time_field': '20:50', - 'integer_field': '1234', - }) + form5 = I18nForm( + { + "decimal_field": "66666.666", + "float_field": "99999.999", + "date_field": "12/31/2009", + "datetime_field": "12/31/2009 20:50", + "time_field": "20:50", + "integer_field": "1234", + } + ) self.assertTrue(form5.is_valid()) - self.assertEqual(decimal.Decimal('66666.666'), form5.cleaned_data['decimal_field']) - self.assertEqual(99999.999, form5.cleaned_data['float_field']) - self.assertEqual(datetime.date(2009, 12, 31), form5.cleaned_data['date_field']) - self.assertEqual(datetime.datetime(2009, 12, 31, 20, 50), form5.cleaned_data['datetime_field']) - self.assertEqual(datetime.time(20, 50), form5.cleaned_data['time_field']) - self.assertEqual(1234, form5.cleaned_data['integer_field']) - - form6 = SelectDateForm({ - 'date_field_month': '12', - 'date_field_day': '31', - 'date_field_year': '2009' - }) + self.assertEqual( + decimal.Decimal("66666.666"), form5.cleaned_data["decimal_field"] + ) + self.assertEqual(99999.999, form5.cleaned_data["float_field"]) + self.assertEqual( + datetime.date(2009, 12, 31), form5.cleaned_data["date_field"] + ) + self.assertEqual( + datetime.datetime(2009, 12, 31, 20, 50), + form5.cleaned_data["datetime_field"], + ) + self.assertEqual(datetime.time(20, 50), form5.cleaned_data["time_field"]) + self.assertEqual(1234, form5.cleaned_data["integer_field"]) + + form6 = SelectDateForm( + { + "date_field_month": "12", + "date_field_day": "31", + "date_field_year": "2009", + } + ) self.assertTrue(form6.is_valid()) - self.assertEqual(datetime.date(2009, 12, 31), form6.cleaned_data['date_field']) + self.assertEqual( + datetime.date(2009, 12, 31), form6.cleaned_data["date_field"] + ) self.assertHTMLEqual( '<select name="mydate_month" id="id_mydate_month">' '<option value="">---</option>' @@ -976,7 +1252,7 @@ class FormattingTests(SimpleTestCase): '<option value="10">October</option>' '<option value="11">November</option>' '<option value="12" selected>December</option>' - '</select>' + "</select>" '<select name="mydate_day" id="id_mydate_day">' '<option value="">---</option>' '<option value="1">1</option>' @@ -1010,7 +1286,7 @@ class FormattingTests(SimpleTestCase): '<option value="29">29</option>' '<option value="30">30</option>' '<option value="31" selected>31</option>' - '</select>' + "</select>" '<select name="mydate_year" id="id_mydate_year">' '<option value="">---</option>' '<option value="2009" selected>2009</option>' @@ -1023,8 +1299,10 @@ class FormattingTests(SimpleTestCase): '<option value="2016">2016</option>' '<option value="2017">2017</option>' '<option value="2018">2018</option>' - '</select>', - forms.SelectDateWidget(years=range(2009, 2019)).render('mydate', datetime.date(2009, 12, 31)) + "</select>", + forms.SelectDateWidget(years=range(2009, 2019)).render( + "mydate", datetime.date(2009, 12, 31) + ), ) def test_sub_locales(self): @@ -1032,23 +1310,25 @@ class FormattingTests(SimpleTestCase): Check if sublocales fall back to the main locale """ with self.settings(USE_THOUSAND_SEPARATOR=True): - with translation.override('de-at', deactivate=True): - self.assertEqual('66.666,666', Template('{{ n }}').render(self.ctxt)) - with translation.override('es-us', deactivate=True): - self.assertEqual('31 de Diciembre de 2009', date_format(self.d)) + with translation.override("de-at", deactivate=True): + self.assertEqual("66.666,666", Template("{{ n }}").render(self.ctxt)) + with translation.override("es-us", deactivate=True): + self.assertEqual("31 de Diciembre de 2009", date_format(self.d)) def test_localized_input(self): """ Tests if form input is correctly localized """ self.maxDiff = 1200 - with translation.override('de-at', deactivate=True): - form6 = CompanyForm({ - 'name': 'acme', - 'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0), - 'cents_paid': decimal.Decimal('59.47'), - 'products_delivered': 12000, - }) + with translation.override("de-at", deactivate=True): + form6 = CompanyForm( + { + "name": "acme", + "date_added": datetime.datetime(2009, 12, 31, 6, 0, 0), + "cents_paid": decimal.Decimal("59.47"), + "products_delivered": 12000, + } + ) self.assertTrue(form6.is_valid()) self.assertHTMLEqual( form6.as_ul(), @@ -1060,23 +1340,29 @@ class FormattingTests(SimpleTestCase): '<input type="text" name="cents_paid" value="59,47" id="id_cents_paid" required></li>' '<li><label for="id_products_delivered">Products delivered:</label>' '<input type="text" name="products_delivered" value="12000" id="id_products_delivered" required>' - '</li>' + "</li>", + ) + self.assertEqual( + localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), + "31.12.2009 06:00:00", + ) + self.assertEqual( + datetime.datetime(2009, 12, 31, 6, 0, 0), + form6.cleaned_data["date_added"], ) - self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00') - self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added']) with self.settings(USE_THOUSAND_SEPARATOR=True): # Checking for the localized "products_delivered" field self.assertInHTML( '<input type="text" name="products_delivered" ' 'value="12.000" id="id_products_delivered" required>', - form6.as_ul() + form6.as_ul(), ) def test_localized_input_func(self): tests = ( - (True, 'True'), - (datetime.date(1, 1, 1), '0001-01-01'), - (datetime.datetime(1, 1, 1), '0001-01-01 00:00:00'), + (True, "True"), + (datetime.date(1, 1, 1), "0001-01-01"), + (datetime.datetime(1, 1, 1), "0001-01-01 00:00:00"), ) with self.settings(USE_THOUSAND_SEPARATOR=True): for value, expected in tests: @@ -1087,10 +1373,10 @@ class FormattingTests(SimpleTestCase): for year in (1, 99, 999, 1000): dt = datetime.date(year, 1, 1) for fmt, expected in [ - ('%C', '%02d' % (year // 100)), - ('%F', '%04d-01-01' % year), - ('%G', '%04d' % year), - ('%Y', '%04d' % year), + ("%C", "%02d" % (year // 100)), + ("%F", "%04d-01-01" % year), + ("%G", "%04d" % year), + ("%Y", "%04d" % year), ]: with self.subTest(year=year, fmt=fmt): fmt = sanitize_strftime_format(fmt) @@ -1099,14 +1385,14 @@ class FormattingTests(SimpleTestCase): def test_sanitize_strftime_format_with_escaped_percent(self): dt = datetime.date(1, 1, 1) for fmt, expected in [ - ('%%C', '%C'), - ('%%F', '%F'), - ('%%G', '%G'), - ('%%Y', '%Y'), - ('%%%%C', '%%C'), - ('%%%%F', '%%F'), - ('%%%%G', '%%G'), - ('%%%%Y', '%%Y'), + ("%%C", "%C"), + ("%%F", "%F"), + ("%%G", "%G"), + ("%%Y", "%Y"), + ("%%%%C", "%%C"), + ("%%%%F", "%%F"), + ("%%%%G", "%%G"), + ("%%%%Y", "%%Y"), ]: with self.subTest(fmt=fmt): fmt = sanitize_strftime_format(fmt) @@ -1115,14 +1401,14 @@ class FormattingTests(SimpleTestCase): for year in (1, 99, 999, 1000): dt = datetime.date(year, 1, 1) for fmt, expected in [ - ('%%%C', '%%%02d' % (year // 100)), - ('%%%F', '%%%04d-01-01' % year), - ('%%%G', '%%%04d' % year), - ('%%%Y', '%%%04d' % year), - ('%%%%%C', '%%%%%02d' % (year // 100)), - ('%%%%%F', '%%%%%04d-01-01' % year), - ('%%%%%G', '%%%%%04d' % year), - ('%%%%%Y', '%%%%%04d' % year), + ("%%%C", "%%%02d" % (year // 100)), + ("%%%F", "%%%04d-01-01" % year), + ("%%%G", "%%%04d" % year), + ("%%%Y", "%%%04d" % year), + ("%%%%%C", "%%%%%02d" % (year // 100)), + ("%%%%%F", "%%%%%04d-01-01" % year), + ("%%%%%G", "%%%%%04d" % year), + ("%%%%%Y", "%%%%%04d" % year), ]: with self.subTest(year=year, fmt=fmt): fmt = sanitize_strftime_format(fmt) @@ -1135,23 +1421,25 @@ class FormattingTests(SimpleTestCase): # Non-strings are untouched self.assertEqual(sanitize_separators(123), 123) - with translation.override('ru', deactivate=True): + with translation.override("ru", deactivate=True): # Russian locale has non-breaking space (\xa0) as thousand separator # Usual space is accepted too when sanitizing inputs with self.settings(USE_THOUSAND_SEPARATOR=True): - self.assertEqual(sanitize_separators('1\xa0234\xa0567'), '1234567') - self.assertEqual(sanitize_separators('77\xa0777,777'), '77777.777') - self.assertEqual(sanitize_separators('12 345'), '12345') - self.assertEqual(sanitize_separators('77 777,777'), '77777.777') + self.assertEqual(sanitize_separators("1\xa0234\xa0567"), "1234567") + self.assertEqual(sanitize_separators("77\xa0777,777"), "77777.777") + self.assertEqual(sanitize_separators("12 345"), "12345") + self.assertEqual(sanitize_separators("77 777,777"), "77777.777") with translation.override(None): # RemovedInDjango50Warning - with self.settings(USE_THOUSAND_SEPARATOR=True, THOUSAND_SEPARATOR='.'): - self.assertEqual(sanitize_separators('12\xa0345'), '12\xa0345') + with self.settings(USE_THOUSAND_SEPARATOR=True, THOUSAND_SEPARATOR="."): + self.assertEqual(sanitize_separators("12\xa0345"), "12\xa0345") with self.settings(USE_THOUSAND_SEPARATOR=True): - with patch_formats(get_language(), THOUSAND_SEPARATOR='.', DECIMAL_SEPARATOR=','): - self.assertEqual(sanitize_separators('10.234'), '10234') + with patch_formats( + get_language(), THOUSAND_SEPARATOR=".", DECIMAL_SEPARATOR="," + ): + self.assertEqual(sanitize_separators("10.234"), "10234") # Suspicion that user entered dot as decimal separator (#22171) - self.assertEqual(sanitize_separators('10.10'), '10.10') + self.assertEqual(sanitize_separators("10.10"), "10.10") # RemovedInDjango50Warning: When the deprecation ends, remove # @ignore_warnings and USE_L10N=False. The assertions should remain @@ -1159,19 +1447,19 @@ class FormattingTests(SimpleTestCase): # locale-dictated formats. with ignore_warnings(category=RemovedInDjango50Warning): with self.settings(USE_L10N=False): - with self.settings(DECIMAL_SEPARATOR=','): - self.assertEqual(sanitize_separators('1001,10'), '1001.10') - self.assertEqual(sanitize_separators('1001.10'), '1001.10') + with self.settings(DECIMAL_SEPARATOR=","): + self.assertEqual(sanitize_separators("1001,10"), "1001.10") + self.assertEqual(sanitize_separators("1001.10"), "1001.10") with self.settings( - DECIMAL_SEPARATOR=',', - THOUSAND_SEPARATOR='.', + DECIMAL_SEPARATOR=",", + THOUSAND_SEPARATOR=".", USE_THOUSAND_SEPARATOR=True, ): - self.assertEqual(sanitize_separators('1.001,10'), '1001.10') - self.assertEqual(sanitize_separators('1001,10'), '1001.10') - self.assertEqual(sanitize_separators('1001.10'), '1001.10') + self.assertEqual(sanitize_separators("1.001,10"), "1001.10") + self.assertEqual(sanitize_separators("1001,10"), "1001.10") + self.assertEqual(sanitize_separators("1001.10"), "1001.10") # Invalid output. - self.assertEqual(sanitize_separators('1,001.10'), '1.001.10') + self.assertEqual(sanitize_separators("1,001.10"), "1.001.10") def test_iter_format_modules(self): """ @@ -1179,68 +1467,80 @@ class FormattingTests(SimpleTestCase): """ # Importing some format modules so that we can compare the returned # modules with these expected modules - default_mod = import_module('django.conf.locale.de.formats') - test_mod = import_module('i18n.other.locale.de.formats') - test_mod2 = import_module('i18n.other2.locale.de.formats') + default_mod = import_module("django.conf.locale.de.formats") + test_mod = import_module("i18n.other.locale.de.formats") + test_mod2 = import_module("i18n.other2.locale.de.formats") - with translation.override('de-at', deactivate=True): + with translation.override("de-at", deactivate=True): # Should return the correct default module when no setting is set - self.assertEqual(list(iter_format_modules('de')), [default_mod]) + self.assertEqual(list(iter_format_modules("de")), [default_mod]) # When the setting is a string, should return the given module and # the default module self.assertEqual( - list(iter_format_modules('de', 'i18n.other.locale')), - [test_mod, default_mod]) + list(iter_format_modules("de", "i18n.other.locale")), + [test_mod, default_mod], + ) # When setting is a list of strings, should return the given # modules and the default module self.assertEqual( - list(iter_format_modules('de', ['i18n.other.locale', 'i18n.other2.locale'])), - [test_mod, test_mod2, default_mod]) + list( + iter_format_modules( + "de", ["i18n.other.locale", "i18n.other2.locale"] + ) + ), + [test_mod, test_mod2, default_mod], + ) def test_iter_format_modules_stability(self): """ Tests the iter_format_modules function always yields format modules in a stable and correct order in presence of both base ll and ll_CC formats. """ - en_format_mod = import_module('django.conf.locale.en.formats') - en_gb_format_mod = import_module('django.conf.locale.en_GB.formats') - self.assertEqual(list(iter_format_modules('en-gb')), [en_gb_format_mod, en_format_mod]) + en_format_mod = import_module("django.conf.locale.en.formats") + en_gb_format_mod = import_module("django.conf.locale.en_GB.formats") + self.assertEqual( + list(iter_format_modules("en-gb")), [en_gb_format_mod, en_format_mod] + ) def test_get_format_modules_lang(self): - with translation.override('de', deactivate=True): - self.assertEqual('.', get_format('DECIMAL_SEPARATOR', lang='en')) + with translation.override("de", deactivate=True): + self.assertEqual(".", get_format("DECIMAL_SEPARATOR", lang="en")) def test_localize_templatetag_and_filter(self): """ Test the {% localize %} templatetag and the localize/unlocalize filters. """ - context = Context({'int': 1455, 'float': 3.14, 'date': datetime.date(2016, 12, 31)}) + context = Context( + {"int": 1455, "float": 3.14, "date": datetime.date(2016, 12, 31)} + ) template1 = Template( - '{% load l10n %}{% localize %}{{ int }}/{{ float }}/{{ date }}{% endlocalize %}; ' - '{% localize on %}{{ int }}/{{ float }}/{{ date }}{% endlocalize %}' + "{% load l10n %}{% localize %}{{ int }}/{{ float }}/{{ date }}{% endlocalize %}; " + "{% localize on %}{{ int }}/{{ float }}/{{ date }}{% endlocalize %}" ) template2 = Template( - '{% load l10n %}{{ int }}/{{ float }}/{{ date }}; ' - '{% localize off %}{{ int }}/{{ float }}/{{ date }};{% endlocalize %} ' - '{{ int }}/{{ float }}/{{ date }}' + "{% load l10n %}{{ int }}/{{ float }}/{{ date }}; " + "{% localize off %}{{ int }}/{{ float }}/{{ date }};{% endlocalize %} " + "{{ int }}/{{ float }}/{{ date }}" ) template3 = Template( - '{% load l10n %}{{ int }}/{{ float }}/{{ date }}; ' - '{{ int|unlocalize }}/{{ float|unlocalize }}/{{ date|unlocalize }}' + "{% load l10n %}{{ int }}/{{ float }}/{{ date }}; " + "{{ int|unlocalize }}/{{ float|unlocalize }}/{{ date|unlocalize }}" ) template4 = Template( - '{% load l10n %}{{ int }}/{{ float }}/{{ date }}; ' - '{{ int|localize }}/{{ float|localize }}/{{ date|localize }}' + "{% load l10n %}{{ int }}/{{ float }}/{{ date }}; " + "{{ int|localize }}/{{ float|localize }}/{{ date|localize }}" + ) + expected_localized = "1.455/3,14/31. Dezember 2016" + expected_unlocalized = "1455/3.14/Dez. 31, 2016" + output1 = "; ".join([expected_localized, expected_localized]) + output2 = "; ".join( + [expected_localized, expected_unlocalized, expected_localized] ) - expected_localized = '1.455/3,14/31. Dezember 2016' - expected_unlocalized = '1455/3.14/Dez. 31, 2016' - output1 = '; '.join([expected_localized, expected_localized]) - output2 = '; '.join([expected_localized, expected_unlocalized, expected_localized]) - output3 = '; '.join([expected_localized, expected_unlocalized]) - output4 = '; '.join([expected_unlocalized, expected_localized]) - with translation.override('de', deactivate=True): + output3 = "; ".join([expected_localized, expected_unlocalized]) + output4 = "; ".join([expected_unlocalized, expected_localized]) + with translation.override("de", deactivate=True): # RemovedInDjango50Warning: When the deprecation ends, remove # @ignore_warnings and USE_L10N=False. The assertions should remain # because format-related settings will take precedence over @@ -1248,8 +1548,8 @@ class FormattingTests(SimpleTestCase): with ignore_warnings(category=RemovedInDjango50Warning): with self.settings( USE_L10N=False, - DATE_FORMAT='N j, Y', - DECIMAL_SEPARATOR='.', + DATE_FORMAT="N j, Y", + DECIMAL_SEPARATOR=".", NUMBER_GROUPING=0, USE_THOUSAND_SEPARATOR=True, ): @@ -1263,29 +1563,29 @@ class FormattingTests(SimpleTestCase): def test_localized_off_numbers(self): """A string representation is returned for unlocalized numbers.""" template = Template( - '{% load l10n %}{% localize off %}' - '{{ int }}/{{ float }}/{{ decimal }}{% endlocalize %}' + "{% load l10n %}{% localize off %}" + "{{ int }}/{{ float }}/{{ decimal }}{% endlocalize %}" ) context = Context( - {'int': 1455, 'float': 3.14, 'decimal': decimal.Decimal('24.1567')} + {"int": 1455, "float": 3.14, "decimal": decimal.Decimal("24.1567")} ) with self.settings( - DECIMAL_SEPARATOR=',', + DECIMAL_SEPARATOR=",", USE_THOUSAND_SEPARATOR=True, - THOUSAND_SEPARATOR='°', + THOUSAND_SEPARATOR="°", NUMBER_GROUPING=2, ): - self.assertEqual(template.render(context), '1455/3.14/24.1567') + self.assertEqual(template.render(context), "1455/3.14/24.1567") # RemovedInDjango50Warning. with ignore_warnings(category=RemovedInDjango50Warning): with self.settings( USE_L10N=False, - DECIMAL_SEPARATOR=',', + DECIMAL_SEPARATOR=",", USE_THOUSAND_SEPARATOR=True, - THOUSAND_SEPARATOR='°', + THOUSAND_SEPARATOR="°", NUMBER_GROUPING=2, ): - self.assertEqual(template.render(context), '1455/3.14/24.1567') + self.assertEqual(template.render(context), "1455/3.14/24.1567") def test_localized_as_text_as_hidden_input(self): """ @@ -1293,45 +1593,51 @@ class FormattingTests(SimpleTestCase): """ self.maxDiff = 1200 - with translation.override('de-at', deactivate=True): - template = Template('{% load l10n %}{{ form.date_added }}; {{ form.cents_paid }}') - template_as_text = Template('{% load l10n %}{{ form.date_added.as_text }}; {{ form.cents_paid.as_text }}') + with translation.override("de-at", deactivate=True): + template = Template( + "{% load l10n %}{{ form.date_added }}; {{ form.cents_paid }}" + ) + template_as_text = Template( + "{% load l10n %}{{ form.date_added.as_text }}; {{ form.cents_paid.as_text }}" + ) template_as_hidden = Template( - '{% load l10n %}{{ form.date_added.as_hidden }}; {{ form.cents_paid.as_hidden }}' - ) - form = CompanyForm({ - 'name': 'acme', - 'date_added': datetime.datetime(2009, 12, 31, 6, 0, 0), - 'cents_paid': decimal.Decimal('59.47'), - 'products_delivered': 12000, - }) - context = Context({'form': form}) + "{% load l10n %}{{ form.date_added.as_hidden }}; {{ form.cents_paid.as_hidden }}" + ) + form = CompanyForm( + { + "name": "acme", + "date_added": datetime.datetime(2009, 12, 31, 6, 0, 0), + "cents_paid": decimal.Decimal("59.47"), + "products_delivered": 12000, + } + ) + context = Context({"form": form}) self.assertTrue(form.is_valid()) self.assertHTMLEqual( template.render(context), '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" required>;' - '<input id="id_cents_paid" name="cents_paid" type="text" value="59,47" required>' + '<input id="id_cents_paid" name="cents_paid" type="text" value="59,47" required>', ) self.assertHTMLEqual( template_as_text.render(context), '<input id="id_date_added" name="date_added" type="text" value="31.12.2009 06:00:00" required>;' - ' <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" required>' + ' <input id="id_cents_paid" name="cents_paid" type="text" value="59,47" required>', ) self.assertHTMLEqual( template_as_hidden.render(context), '<input id="id_date_added" name="date_added" type="hidden" value="31.12.2009 06:00:00">;' - '<input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47">' + '<input id="id_cents_paid" name="cents_paid" type="hidden" value="59,47">', ) def test_format_arbitrary_settings(self): - self.assertEqual(get_format('DEBUG'), 'DEBUG') + self.assertEqual(get_format("DEBUG"), "DEBUG") def test_get_custom_format(self): reset_format_cache() - with self.settings(FORMAT_MODULE_PATH='i18n.other.locale'): - with translation.override('fr', deactivate=True): - self.assertEqual('d/m/Y CUSTOM', get_format('CUSTOM_DAY_FORMAT')) + with self.settings(FORMAT_MODULE_PATH="i18n.other.locale"): + with translation.override("fr", deactivate=True): + self.assertEqual("d/m/Y CUSTOM", get_format("CUSTOM_DAY_FORMAT")) def test_admin_javascript_supported_input_formats(self): """ @@ -1339,21 +1645,27 @@ class FormattingTests(SimpleTestCase): DATETIME_INPUT_FORMATS must not contain %f since that's unsupported by the admin's time picker widget. """ - regex = re.compile('%([^BcdHImMpSwxXyY%])') + regex = re.compile("%([^BcdHImMpSwxXyY%])") for language_code, language_name in settings.LANGUAGES: - for format_name in ('DATE_INPUT_FORMATS', 'TIME_INPUT_FORMATS', 'DATETIME_INPUT_FORMATS'): + for format_name in ( + "DATE_INPUT_FORMATS", + "TIME_INPUT_FORMATS", + "DATETIME_INPUT_FORMATS", + ): with self.subTest(language=language_code, format=format_name): formatter = get_format(format_name, lang=language_code)[0] self.assertEqual( - regex.findall(formatter), [], - "%s locale's %s uses an unsupported format code." % (language_code, format_name) + regex.findall(formatter), + [], + "%s locale's %s uses an unsupported format code." + % (language_code, format_name), ) class MiscTests(SimpleTestCase): rf = RequestFactory() - @override_settings(LANGUAGE_CODE='de') + @override_settings(LANGUAGE_CODE="de") def test_english_fallback(self): """ With a non-English LANGUAGE_CODE and if the active language is English @@ -1361,11 +1673,11 @@ class MiscTests(SimpleTestCase): (instead of falling back to LANGUAGE_CODE) (See #24413). """ self.assertEqual(gettext("Image"), "Bild") - with translation.override('en'): + with translation.override("en"): self.assertEqual(gettext("Image"), "Image") - with translation.override('en-us'): + with translation.override("en-us"): self.assertEqual(gettext("Image"), "Image") - with translation.override('en-ca'): + with translation.override("en-ca"): self.assertEqual(gettext("Image"), "Image") def test_parse_spec_http_header(self): @@ -1376,98 +1688,109 @@ class MiscTests(SimpleTestCase): """ tests = [ # Good headers - ('de', [('de', 1.0)]), - ('en-AU', [('en-au', 1.0)]), - ('es-419', [('es-419', 1.0)]), - ('*;q=1.00', [('*', 1.0)]), - ('en-AU;q=0.123', [('en-au', 0.123)]), - ('en-au;q=0.5', [('en-au', 0.5)]), - ('en-au;q=1.0', [('en-au', 1.0)]), - ('da, en-gb;q=0.25, en;q=0.5', [('da', 1.0), ('en', 0.5), ('en-gb', 0.25)]), - ('en-au-xx', [('en-au-xx', 1.0)]), - ('de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125', - [('de', 1.0), ('en-au', 0.75), ('en-us', 0.5), ('en', 0.25), ('es', 0.125), ('fa', 0.125)]), - ('*', [('*', 1.0)]), - ('de;q=0.', [('de', 0.0)]), - ('en; q=1,', [('en', 1.0)]), - ('en; q=1.0, * ; q=0.5', [('en', 1.0), ('*', 0.5)]), + ("de", [("de", 1.0)]), + ("en-AU", [("en-au", 1.0)]), + ("es-419", [("es-419", 1.0)]), + ("*;q=1.00", [("*", 1.0)]), + ("en-AU;q=0.123", [("en-au", 0.123)]), + ("en-au;q=0.5", [("en-au", 0.5)]), + ("en-au;q=1.0", [("en-au", 1.0)]), + ("da, en-gb;q=0.25, en;q=0.5", [("da", 1.0), ("en", 0.5), ("en-gb", 0.25)]), + ("en-au-xx", [("en-au-xx", 1.0)]), + ( + "de,en-au;q=0.75,en-us;q=0.5,en;q=0.25,es;q=0.125,fa;q=0.125", + [ + ("de", 1.0), + ("en-au", 0.75), + ("en-us", 0.5), + ("en", 0.25), + ("es", 0.125), + ("fa", 0.125), + ], + ), + ("*", [("*", 1.0)]), + ("de;q=0.", [("de", 0.0)]), + ("en; q=1,", [("en", 1.0)]), + ("en; q=1.0, * ; q=0.5", [("en", 1.0), ("*", 0.5)]), # Bad headers - ('en-gb;q=1.0000', []), - ('en;q=0.1234', []), - ('en;q=.2', []), - ('abcdefghi-au', []), - ('**', []), - ('en,,gb', []), - ('en-au;q=0.1.0', []), - (('X' * 97) + 'Z,en', []), - ('da, en-gb;q=0.8, en;q=0.7,#', []), - ('de;q=2.0', []), - ('de;q=0.a', []), - ('12-345', []), - ('', []), - ('en;q=1e0', []), - ('en-au;q=1.0', []), + ("en-gb;q=1.0000", []), + ("en;q=0.1234", []), + ("en;q=.2", []), + ("abcdefghi-au", []), + ("**", []), + ("en,,gb", []), + ("en-au;q=0.1.0", []), + (("X" * 97) + "Z,en", []), + ("da, en-gb;q=0.8, en;q=0.7,#", []), + ("de;q=2.0", []), + ("de;q=0.a", []), + ("12-345", []), + ("", []), + ("en;q=1e0", []), + ("en-au;q=1.0", []), ] for value, expected in tests: with self.subTest(value=value): - self.assertEqual(trans_real.parse_accept_lang_header(value), tuple(expected)) + self.assertEqual( + trans_real.parse_accept_lang_header(value), tuple(expected) + ) def test_parse_literal_http_header(self): """ Now test that we parse a literal HTTP header correctly. """ g = get_language_from_request - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-br'} - self.assertEqual('pt-br', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "pt-br"} + self.assertEqual("pt-br", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt'} - self.assertEqual('pt', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "pt"} + self.assertEqual("pt", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'es,de'} - self.assertEqual('es', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "es,de"} + self.assertEqual("es", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-ar,de'} - self.assertEqual('es-ar', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "es-ar,de"} + self.assertEqual("es-ar", g(r)) # This test assumes there won't be a Django translation to a US # variation of the Spanish language, a safe assumption. When the # user sets it as the preferred language, the main 'es' # translation should be selected instead. - r.META = {'HTTP_ACCEPT_LANGUAGE': 'es-us'} - self.assertEqual(g(r), 'es') + r.META = {"HTTP_ACCEPT_LANGUAGE": "es-us"} + self.assertEqual(g(r), "es") # This tests the following scenario: there isn't a main language (zh) # translation of Django but there is a translation to variation (zh-hans) # the user sets zh-hans as the preferred language, it should be selected # by Django without falling back nor ignoring it. - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-hans,de'} - self.assertEqual(g(r), 'zh-hans') + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-hans,de"} + self.assertEqual(g(r), "zh-hans") - r.META = {'HTTP_ACCEPT_LANGUAGE': 'NL'} - self.assertEqual('nl', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "NL"} + self.assertEqual("nl", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'fy'} - self.assertEqual('fy', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "fy"} + self.assertEqual("fy", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'ia'} - self.assertEqual('ia', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "ia"} + self.assertEqual("ia", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'sr-latn'} - self.assertEqual('sr-latn', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "sr-latn"} + self.assertEqual("sr-latn", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-hans'} - self.assertEqual('zh-hans', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-hans"} + self.assertEqual("zh-hans", g(r)) - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-hant'} - self.assertEqual('zh-hant', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-hant"} + self.assertEqual("zh-hant", g(r)) @override_settings( LANGUAGES=[ - ('en', 'English'), - ('zh-hans', 'Simplified Chinese'), - ('zh-hant', 'Traditional Chinese'), + ("en", "English"), + ("zh-hans", "Simplified Chinese"), + ("zh-hant", "Traditional Chinese"), ] ) def test_support_for_deprecated_chinese_language_codes(self): @@ -1481,23 +1804,23 @@ class MiscTests(SimpleTestCase): refs #18419 -- this is explicitly for browser compatibility """ g = get_language_from_request - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-cn,en'} - self.assertEqual(g(r), 'zh-hans') + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-cn,en"} + self.assertEqual(g(r), "zh-hans") - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-tw,en'} - self.assertEqual(g(r), 'zh-hant') + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-tw,en"} + self.assertEqual(g(r), "zh-hant") def test_special_fallback_language(self): """ Some languages may have special fallbacks that don't follow the simple 'fr-ca' -> 'fr' logic (notably Chinese codes). """ - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'zh-my,en'} - self.assertEqual(get_language_from_request(r), 'zh-hans') + r.META = {"HTTP_ACCEPT_LANGUAGE": "zh-my,en"} + self.assertEqual(get_language_from_request(r), "zh-hans") def test_subsequent_code_fallback_language(self): """ @@ -1505,18 +1828,18 @@ class MiscTests(SimpleTestCase): supported. """ tests = [ - ('zh-Hans-CN', 'zh-hans'), - ('zh-hans-mo', 'zh-hans'), - ('zh-hans-HK', 'zh-hans'), - ('zh-Hant-HK', 'zh-hant'), - ('zh-hant-tw', 'zh-hant'), - ('zh-hant-SG', 'zh-hant'), + ("zh-Hans-CN", "zh-hans"), + ("zh-hans-mo", "zh-hans"), + ("zh-hans-HK", "zh-hans"), + ("zh-Hant-HK", "zh-hant"), + ("zh-hant-tw", "zh-hant"), + ("zh-hant-SG", "zh-hant"), ] - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} for value, expected in tests: with self.subTest(value=value): - r.META = {'HTTP_ACCEPT_LANGUAGE': f'{value},en'} + r.META = {"HTTP_ACCEPT_LANGUAGE": f"{value},en"} self.assertEqual(get_language_from_request(r), expected) def test_parse_language_cookie(self): @@ -1524,113 +1847,113 @@ class MiscTests(SimpleTestCase): Now test that we parse language preferences stored in a cookie correctly. """ g = get_language_from_request - r = self.rf.get('/') - r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: 'pt-br'} + r = self.rf.get("/") + r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: "pt-br"} r.META = {} - self.assertEqual('pt-br', g(r)) + self.assertEqual("pt-br", g(r)) - r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: 'pt'} + r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: "pt"} r.META = {} - self.assertEqual('pt', g(r)) + self.assertEqual("pt", g(r)) - r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: 'es'} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'de'} - self.assertEqual('es', g(r)) + r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: "es"} + r.META = {"HTTP_ACCEPT_LANGUAGE": "de"} + self.assertEqual("es", g(r)) # This test assumes there won't be a Django translation to a US # variation of the Spanish language, a safe assumption. When the # user sets it as the preferred language, the main 'es' # translation should be selected instead. - r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: 'es-us'} + r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: "es-us"} r.META = {} - self.assertEqual(g(r), 'es') + self.assertEqual(g(r), "es") # This tests the following scenario: there isn't a main language (zh) # translation of Django but there is a translation to variation (zh-hans) # the user sets zh-hans as the preferred language, it should be selected # by Django without falling back nor ignoring it. - r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: 'zh-hans'} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'de'} - self.assertEqual(g(r), 'zh-hans') + r.COOKIES = {settings.LANGUAGE_COOKIE_NAME: "zh-hans"} + r.META = {"HTTP_ACCEPT_LANGUAGE": "de"} + self.assertEqual(g(r), "zh-hans") @override_settings( USE_I18N=True, LANGUAGES=[ - ('en', 'English'), - ('de', 'German'), - ('de-at', 'Austrian German'), - ('pt-br', 'Portuguese (Brazil)'), + ("en", "English"), + ("de", "German"), + ("de-at", "Austrian German"), + ("pt-br", "Portuguese (Brazil)"), ], ) def test_get_supported_language_variant_real(self): g = trans_real.get_supported_language_variant - self.assertEqual(g('en'), 'en') - self.assertEqual(g('en-gb'), 'en') - self.assertEqual(g('de'), 'de') - self.assertEqual(g('de-at'), 'de-at') - self.assertEqual(g('de-ch'), 'de') - self.assertEqual(g('pt-br'), 'pt-br') - self.assertEqual(g('pt'), 'pt-br') - self.assertEqual(g('pt-pt'), 'pt-br') + self.assertEqual(g("en"), "en") + self.assertEqual(g("en-gb"), "en") + self.assertEqual(g("de"), "de") + self.assertEqual(g("de-at"), "de-at") + self.assertEqual(g("de-ch"), "de") + self.assertEqual(g("pt-br"), "pt-br") + self.assertEqual(g("pt"), "pt-br") + self.assertEqual(g("pt-pt"), "pt-br") with self.assertRaises(LookupError): - g('pt', strict=True) + g("pt", strict=True) with self.assertRaises(LookupError): - g('pt-pt', strict=True) + g("pt-pt", strict=True) with self.assertRaises(LookupError): - g('xyz') + g("xyz") with self.assertRaises(LookupError): - g('xy-zz') + g("xy-zz") def test_get_supported_language_variant_null(self): g = trans_null.get_supported_language_variant self.assertEqual(g(settings.LANGUAGE_CODE), settings.LANGUAGE_CODE) with self.assertRaises(LookupError): - g('pt') + g("pt") with self.assertRaises(LookupError): - g('de') + g("de") with self.assertRaises(LookupError): - g('de-at') + g("de-at") with self.assertRaises(LookupError): - g('de', strict=True) + g("de", strict=True) with self.assertRaises(LookupError): - g('de-at', strict=True) + g("de-at", strict=True) with self.assertRaises(LookupError): - g('xyz') + g("xyz") @override_settings( LANGUAGES=[ - ('en', 'English'), - ('en-latn-us', 'Latin English'), - ('en-Latn-US', 'BCP 47 case format'), - ('de', 'German'), - ('de-1996', 'German, orthography of 1996'), - ('de-at', 'Austrian German'), - ('de-ch-1901', 'German, Swiss variant, traditional orthography'), - ('i-mingo', 'Mingo'), - ('kl-tunumiit', 'Tunumiisiut'), - ('nan-hani-tw', 'Hanji'), - ('pl', 'Polish'), + ("en", "English"), + ("en-latn-us", "Latin English"), + ("en-Latn-US", "BCP 47 case format"), + ("de", "German"), + ("de-1996", "German, orthography of 1996"), + ("de-at", "Austrian German"), + ("de-ch-1901", "German, Swiss variant, traditional orthography"), + ("i-mingo", "Mingo"), + ("kl-tunumiit", "Tunumiisiut"), + ("nan-hani-tw", "Hanji"), + ("pl", "Polish"), ], ) def test_get_language_from_path_real(self): g = trans_real.get_language_from_path tests = [ - ('/pl/', 'pl'), - ('/pl', 'pl'), - ('/xyz/', None), - ('/en/', 'en'), - ('/en-gb/', 'en'), - ('/en-latn-us/', 'en-latn-us'), - ('/en-Latn-US/', 'en-Latn-US'), - ('/de/', 'de'), - ('/de-1996/', 'de-1996'), - ('/de-at/', 'de-at'), - ('/de-ch/', 'de'), - ('/de-ch-1901/', 'de-ch-1901'), - ('/de-simple-page-test/', None), - ('/i-mingo/', 'i-mingo'), - ('/kl-tunumiit/', 'kl-tunumiit'), - ('/nan-hani-tw/', 'nan-hani-tw'), + ("/pl/", "pl"), + ("/pl", "pl"), + ("/xyz/", None), + ("/en/", "en"), + ("/en-gb/", "en"), + ("/en-latn-us/", "en-latn-us"), + ("/en-Latn-US/", "en-Latn-US"), + ("/de/", "de"), + ("/de-1996/", "de-1996"), + ("/de-at/", "de-at"), + ("/de-ch/", "de"), + ("/de-ch-1901/", "de-ch-1901"), + ("/de-simple-page-test/", None), + ("/i-mingo/", "i-mingo"), + ("/kl-tunumiit/", "kl-tunumiit"), + ("/nan-hani-tw/", "nan-hani-tw"), ] for path, language in tests: with self.subTest(path=path): @@ -1638,9 +1961,9 @@ class MiscTests(SimpleTestCase): def test_get_language_from_path_null(self): g = trans_null.get_language_from_path - self.assertIsNone(g('/pl/')) - self.assertIsNone(g('/pl')) - self.assertIsNone(g('/xyz/')) + self.assertIsNone(g("/pl/")) + self.assertIsNone(g("/pl")) + self.assertIsNone(g("/xyz/")) def test_cache_resetting(self): """ @@ -1648,12 +1971,12 @@ class MiscTests(SimpleTestCase): previously valid should not be used (#14170). """ g = get_language_from_request - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-br'} - self.assertEqual('pt-br', g(r)) - with self.settings(LANGUAGES=[('en', 'English')]): - self.assertNotEqual('pt-br', g(r)) + r.META = {"HTTP_ACCEPT_LANGUAGE": "pt-br"} + self.assertEqual("pt-br", g(r)) + with self.settings(LANGUAGES=[("en", "English")]): + self.assertNotEqual("pt-br", g(r)) def test_i18n_patterns_returns_list(self): with override_settings(USE_I18N=False): @@ -1663,10 +1986,9 @@ class MiscTests(SimpleTestCase): class ResolutionOrderI18NTests(SimpleTestCase): - def setUp(self): super().setUp() - activate('de') + activate("de") def tearDown(self): deactivate() @@ -1675,64 +1997,63 @@ class ResolutionOrderI18NTests(SimpleTestCase): def assertGettext(self, msgid, msgstr): result = gettext(msgid) self.assertIn( - msgstr, result, + msgstr, + result, "The string '%s' isn't in the translation of '%s'; the actual result is '%s'." - % (msgstr, msgid, result) + % (msgstr, msgid, result), ) class AppResolutionOrderI18NTests(ResolutionOrderI18NTests): - - @override_settings(LANGUAGE_CODE='de') + @override_settings(LANGUAGE_CODE="de") def test_app_translation(self): # Original translation. - self.assertGettext('Date/time', 'Datum/Zeit') + self.assertGettext("Date/time", "Datum/Zeit") # Different translation. - with self.modify_settings(INSTALLED_APPS={'append': 'i18n.resolution'}): + with self.modify_settings(INSTALLED_APPS={"append": "i18n.resolution"}): # Force refreshing translations. - activate('de') + activate("de") # Doesn't work because it's added later in the list. - self.assertGettext('Date/time', 'Datum/Zeit') + self.assertGettext("Date/time", "Datum/Zeit") - with self.modify_settings(INSTALLED_APPS={'remove': 'django.contrib.admin.apps.SimpleAdminConfig'}): + with self.modify_settings( + INSTALLED_APPS={"remove": "django.contrib.admin.apps.SimpleAdminConfig"} + ): # Force refreshing translations. - activate('de') + activate("de") # Unless the original is removed from the list. - self.assertGettext('Date/time', 'Datum/Zeit (APP)') + self.assertGettext("Date/time", "Datum/Zeit (APP)") @override_settings(LOCALE_PATHS=extended_locale_paths) class LocalePathsResolutionOrderI18NTests(ResolutionOrderI18NTests): - def test_locale_paths_translation(self): - self.assertGettext('Time', 'LOCALE_PATHS') + self.assertGettext("Time", "LOCALE_PATHS") def test_locale_paths_override_app_translation(self): - with self.settings(INSTALLED_APPS=['i18n.resolution']): - self.assertGettext('Time', 'LOCALE_PATHS') + with self.settings(INSTALLED_APPS=["i18n.resolution"]): + self.assertGettext("Time", "LOCALE_PATHS") class DjangoFallbackResolutionOrderI18NTests(ResolutionOrderI18NTests): - def test_django_fallback(self): - self.assertEqual(gettext('Date/time'), 'Datum/Zeit') + self.assertEqual(gettext("Date/time"), "Datum/Zeit") -@override_settings(INSTALLED_APPS=['i18n.territorial_fallback']) +@override_settings(INSTALLED_APPS=["i18n.territorial_fallback"]) class TranslationFallbackI18NTests(ResolutionOrderI18NTests): - def test_sparse_territory_catalog(self): """ Untranslated strings for territorial language variants use the translations of the generic language. In this case, the de-de translation falls back to de. """ - with translation.override('de-de'): - self.assertGettext('Test 1 (en)', '(de-de)') - self.assertGettext('Test 2 (en)', '(de)') + with translation.override("de-de"): + self.assertGettext("Test 1 (en)", "(de-de)") + self.assertGettext("Test 2 (en)", "(de)") class TestModels(TestCase): @@ -1742,83 +2063,82 @@ class TestModels(TestCase): def test_safestr(self): c = Company(cents_paid=12, products_delivered=1) - c.name = SafeString('Iñtërnâtiônàlizætiøn1') + c.name = SafeString("Iñtërnâtiônàlizætiøn1") c.save() class TestLanguageInfo(SimpleTestCase): def test_localized_language_info(self): - li = get_language_info('de') - self.assertEqual(li['code'], 'de') - self.assertEqual(li['name_local'], 'Deutsch') - self.assertEqual(li['name'], 'German') - self.assertIs(li['bidi'], False) + li = get_language_info("de") + self.assertEqual(li["code"], "de") + self.assertEqual(li["name_local"], "Deutsch") + self.assertEqual(li["name"], "German") + self.assertIs(li["bidi"], False) def test_unknown_language_code(self): with self.assertRaisesMessage(KeyError, "Unknown language code xx"): - get_language_info('xx') - with translation.override('xx'): + get_language_info("xx") + with translation.override("xx"): # A language with no translation catalogs should fallback to the # untranslated string. self.assertEqual(gettext("Title"), "Title") def test_unknown_only_country_code(self): - li = get_language_info('de-xx') - self.assertEqual(li['code'], 'de') - self.assertEqual(li['name_local'], 'Deutsch') - self.assertEqual(li['name'], 'German') - self.assertIs(li['bidi'], False) + li = get_language_info("de-xx") + self.assertEqual(li["code"], "de") + self.assertEqual(li["name_local"], "Deutsch") + self.assertEqual(li["name"], "German") + self.assertIs(li["bidi"], False) def test_unknown_language_code_and_country_code(self): with self.assertRaisesMessage(KeyError, "Unknown language code xx-xx and xx"): - get_language_info('xx-xx') + get_language_info("xx-xx") def test_fallback_language_code(self): """ get_language_info return the first fallback language info if the lang_info struct does not contain the 'name' key. """ - li = get_language_info('zh-my') - self.assertEqual(li['code'], 'zh-hans') - li = get_language_info('zh-hans') - self.assertEqual(li['code'], 'zh-hans') + li = get_language_info("zh-my") + self.assertEqual(li["code"], "zh-hans") + li = get_language_info("zh-hans") + self.assertEqual(li["code"], "zh-hans") @override_settings( USE_I18N=True, LANGUAGES=[ - ('en', 'English'), - ('fr', 'French'), + ("en", "English"), + ("fr", "French"), ], MIDDLEWARE=[ - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", ], - ROOT_URLCONF='i18n.urls', + ROOT_URLCONF="i18n.urls", ) class LocaleMiddlewareTests(TestCase): - def test_streaming_response(self): # Regression test for #5241 - response = self.client.get('/fr/streaming/') + response = self.client.get("/fr/streaming/") self.assertContains(response, "Oui/Non") - response = self.client.get('/en/streaming/') + response = self.client.get("/en/streaming/") self.assertContains(response, "Yes/No") @override_settings( USE_I18N=True, LANGUAGES=[ - ('en', 'English'), - ('de', 'German'), - ('fr', 'French'), + ("en", "English"), + ("de", "German"), + ("fr", "French"), ], MIDDLEWARE=[ - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", ], - ROOT_URLCONF='i18n.urls_default_unprefixed', - LANGUAGE_CODE='en', + ROOT_URLCONF="i18n.urls_default_unprefixed", + LANGUAGE_CODE="en", ) class UnprefixedDefaultLanguageTests(SimpleTestCase): def test_default_lang_without_prefix(self): @@ -1826,21 +2146,21 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase): With i18n_patterns(..., prefix_default_language=False), the default language (settings.LANGUAGE_CODE) should be accessible without a prefix. """ - response = self.client.get('/simple/') - self.assertEqual(response.content, b'Yes') + response = self.client.get("/simple/") + self.assertEqual(response.content, b"Yes") def test_other_lang_with_prefix(self): - response = self.client.get('/fr/simple/') - self.assertEqual(response.content, b'Oui') + response = self.client.get("/fr/simple/") + self.assertEqual(response.content, b"Oui") def test_unprefixed_language_other_than_accept_language(self): - response = self.client.get('/simple/', HTTP_ACCEPT_LANGUAGE='fr') - self.assertEqual(response.content, b'Yes') + response = self.client.get("/simple/", HTTP_ACCEPT_LANGUAGE="fr") + self.assertEqual(response.content, b"Yes") def test_page_with_dash(self): # A page starting with /de* shouldn't match the 'de' language code. - response = self.client.get('/de-simple-page-test/') - self.assertEqual(response.content, b'Yes') + response = self.client.get("/de-simple-page-test/") + self.assertEqual(response.content, b"Yes") def test_no_redirect_on_404(self): """ @@ -1850,86 +2170,85 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase): """ # A match for /group1/group2/ must exist for this to act as a # regression test. - response = self.client.get('/group1/group2/') + response = self.client.get("/group1/group2/") self.assertEqual(response.status_code, 200) - response = self.client.get('/nonexistent/') + response = self.client.get("/nonexistent/") self.assertEqual(response.status_code, 404) @override_settings( USE_I18N=True, LANGUAGES=[ - ('bg', 'Bulgarian'), - ('en-us', 'English'), - ('pt-br', 'Portuguese (Brazil)'), + ("bg", "Bulgarian"), + ("en-us", "English"), + ("pt-br", "Portuguese (Brazil)"), ], MIDDLEWARE=[ - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", ], - ROOT_URLCONF='i18n.urls' + ROOT_URLCONF="i18n.urls", ) class CountrySpecificLanguageTests(SimpleTestCase): rf = RequestFactory() def test_check_for_language(self): - self.assertTrue(check_for_language('en')) - self.assertTrue(check_for_language('en-us')) - self.assertTrue(check_for_language('en-US')) - self.assertFalse(check_for_language('en_US')) - self.assertTrue(check_for_language('be')) - self.assertTrue(check_for_language('be@latin')) - self.assertTrue(check_for_language('sr-RS@latin')) - self.assertTrue(check_for_language('sr-RS@12345')) - self.assertFalse(check_for_language('en-ü')) - self.assertFalse(check_for_language('en\x00')) + self.assertTrue(check_for_language("en")) + self.assertTrue(check_for_language("en-us")) + self.assertTrue(check_for_language("en-US")) + self.assertFalse(check_for_language("en_US")) + self.assertTrue(check_for_language("be")) + self.assertTrue(check_for_language("be@latin")) + self.assertTrue(check_for_language("sr-RS@latin")) + self.assertTrue(check_for_language("sr-RS@12345")) + self.assertFalse(check_for_language("en-ü")) + self.assertFalse(check_for_language("en\x00")) self.assertFalse(check_for_language(None)) - self.assertFalse(check_for_language('be@ ')) + self.assertFalse(check_for_language("be@ ")) # Specifying encoding is not supported (Django enforces UTF-8) - self.assertFalse(check_for_language('tr-TR.UTF-8')) - self.assertFalse(check_for_language('tr-TR.UTF8')) - self.assertFalse(check_for_language('de-DE.utf-8')) + self.assertFalse(check_for_language("tr-TR.UTF-8")) + self.assertFalse(check_for_language("tr-TR.UTF8")) + self.assertFalse(check_for_language("de-DE.utf-8")) def test_check_for_language_null(self): - self.assertIs(trans_null.check_for_language('en'), True) + self.assertIs(trans_null.check_for_language("en"), True) def test_get_language_from_request(self): # issue 19919 - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8,bg;q=0.6,ru;q=0.4'} + r.META = {"HTTP_ACCEPT_LANGUAGE": "en-US,en;q=0.8,bg;q=0.6,ru;q=0.4"} lang = get_language_from_request(r) - self.assertEqual('en-us', lang) - r = self.rf.get('/') + self.assertEqual("en-us", lang) + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'bg-bg,en-US;q=0.8,en;q=0.6,ru;q=0.4'} + r.META = {"HTTP_ACCEPT_LANGUAGE": "bg-bg,en-US;q=0.8,en;q=0.6,ru;q=0.4"} lang = get_language_from_request(r) - self.assertEqual('bg', lang) + self.assertEqual("bg", lang) def test_get_language_from_request_null(self): lang = trans_null.get_language_from_request(None) - self.assertEqual(lang, 'en') - with override_settings(LANGUAGE_CODE='de'): + self.assertEqual(lang, "en") + with override_settings(LANGUAGE_CODE="de"): lang = trans_null.get_language_from_request(None) - self.assertEqual(lang, 'de') + self.assertEqual(lang, "de") def test_specific_language_codes(self): # issue 11915 - r = self.rf.get('/') + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt,en-US;q=0.8,en;q=0.6,ru;q=0.4'} + r.META = {"HTTP_ACCEPT_LANGUAGE": "pt,en-US;q=0.8,en;q=0.6,ru;q=0.4"} lang = get_language_from_request(r) - self.assertEqual('pt-br', lang) - r = self.rf.get('/') + self.assertEqual("pt-br", lang) + r = self.rf.get("/") r.COOKIES = {} - r.META = {'HTTP_ACCEPT_LANGUAGE': 'pt-pt,en-US;q=0.8,en;q=0.6,ru;q=0.4'} + r.META = {"HTTP_ACCEPT_LANGUAGE": "pt-pt,en-US;q=0.8,en;q=0.6,ru;q=0.4"} lang = get_language_from_request(r) - self.assertEqual('pt-br', lang) + self.assertEqual("pt-br", lang) class TranslationFilesMissing(SimpleTestCase): - def setUp(self): super().setUp() self.gettext_find_builtin = gettext_module.find @@ -1946,7 +2265,7 @@ class TranslationFilesMissing(SimpleTestCase): self.patchGettextFind() trans_real._translations = {} with self.assertRaises(OSError): - activate('en') + activate("en") class NonDjangoLanguageTests(SimpleTestCase): @@ -1954,40 +2273,48 @@ class NonDjangoLanguageTests(SimpleTestCase): A language non present in default Django languages can still be installed/used by a Django project. """ + @override_settings( USE_I18N=True, LANGUAGES=[ - ('en-us', 'English'), - ('xxx', 'Somelanguage'), + ("en-us", "English"), + ("xxx", "Somelanguage"), ], - LANGUAGE_CODE='xxx', - LOCALE_PATHS=[os.path.join(here, 'commands', 'locale')], + LANGUAGE_CODE="xxx", + LOCALE_PATHS=[os.path.join(here, "commands", "locale")], ) def test_non_django_language(self): - self.assertEqual(get_language(), 'xxx') + self.assertEqual(get_language(), "xxx") self.assertEqual(gettext("year"), "reay") @override_settings(USE_I18N=True) def test_check_for_language(self): with tempfile.TemporaryDirectory() as app_dir: - os.makedirs(os.path.join(app_dir, 'locale', 'dummy_Lang', 'LC_MESSAGES')) - open(os.path.join(app_dir, 'locale', 'dummy_Lang', 'LC_MESSAGES', 'django.mo'), 'w').close() - app_config = AppConfig('dummy_app', AppModuleStub(__path__=[app_dir])) - with mock.patch('django.apps.apps.get_app_configs', return_value=[app_config]): - self.assertIs(check_for_language('dummy-lang'), True) + os.makedirs(os.path.join(app_dir, "locale", "dummy_Lang", "LC_MESSAGES")) + open( + os.path.join( + app_dir, "locale", "dummy_Lang", "LC_MESSAGES", "django.mo" + ), + "w", + ).close() + app_config = AppConfig("dummy_app", AppModuleStub(__path__=[app_dir])) + with mock.patch( + "django.apps.apps.get_app_configs", return_value=[app_config] + ): + self.assertIs(check_for_language("dummy-lang"), True) @override_settings( USE_I18N=True, LANGUAGES=[ - ('en-us', 'English'), + ("en-us", "English"), # xyz language has no locale files - ('xyz', 'XYZ'), + ("xyz", "XYZ"), ], ) - @translation.override('xyz') + @translation.override("xyz") def test_plural_non_django_language(self): - self.assertEqual(get_language(), 'xyz') - self.assertEqual(ngettext('year', 'years', 2), 'years') + self.assertEqual(get_language(), "xyz") + self.assertEqual(ngettext("year", "years", 2), "years") @override_settings(USE_I18N=True) @@ -2008,26 +2335,26 @@ class WatchForTranslationChangesTests(SimpleTestCase): with tempfile.TemporaryDirectory() as app_dir: with self.settings(LOCALE_PATHS=[app_dir]): watch_for_translation_changes(mocked_sender) - mocked_sender.watch_dir.assert_any_call(Path(app_dir), '**/*.mo') + mocked_sender.watch_dir.assert_any_call(Path(app_dir), "**/*.mo") def test_i18n_app_dirs(self): mocked_sender = mock.MagicMock() - with self.settings(INSTALLED_APPS=['tests.i18n.sampleproject']): + with self.settings(INSTALLED_APPS=["tests.i18n.sampleproject"]): watch_for_translation_changes(mocked_sender) - project_dir = Path(__file__).parent / 'sampleproject' / 'locale' - mocked_sender.watch_dir.assert_any_call(project_dir, '**/*.mo') + project_dir = Path(__file__).parent / "sampleproject" / "locale" + mocked_sender.watch_dir.assert_any_call(project_dir, "**/*.mo") def test_i18n_app_dirs_ignore_django_apps(self): mocked_sender = mock.MagicMock() - with self.settings(INSTALLED_APPS=['django.contrib.admin']): + with self.settings(INSTALLED_APPS=["django.contrib.admin"]): watch_for_translation_changes(mocked_sender) - mocked_sender.watch_dir.assert_called_once_with(Path('locale'), '**/*.mo') + mocked_sender.watch_dir.assert_called_once_with(Path("locale"), "**/*.mo") def test_i18n_local_locale(self): mocked_sender = mock.MagicMock() watch_for_translation_changes(mocked_sender) - locale_dir = Path(__file__).parent / 'locale' - mocked_sender.watch_dir.assert_any_call(locale_dir, '**/*.mo') + locale_dir = Path(__file__).parent / "locale" + mocked_sender.watch_dir.assert_any_call(locale_dir, "**/*.mo") class TranslationFileChangedTests(SimpleTestCase): @@ -2040,17 +2367,17 @@ class TranslationFileChangedTests(SimpleTestCase): trans_real._translations = self.trans_real_translations def test_ignores_non_mo_files(self): - gettext_module._translations = {'foo': 'bar'} - path = Path('test.py') + gettext_module._translations = {"foo": "bar"} + path = Path("test.py") self.assertIsNone(translation_file_changed(None, path)) - self.assertEqual(gettext_module._translations, {'foo': 'bar'}) + self.assertEqual(gettext_module._translations, {"foo": "bar"}) def test_resets_cache_with_mo_files(self): - gettext_module._translations = {'foo': 'bar'} - trans_real._translations = {'foo': 'bar'} + gettext_module._translations = {"foo": "bar"} + trans_real._translations = {"foo": "bar"} trans_real._default = 1 trans_real._active = False - path = Path('test.mo') + path = Path("test.mo") self.assertIs(translation_file_changed(None, path), True) self.assertEqual(gettext_module._translations, {}) self.assertEqual(trans_real._translations, {}) @@ -2062,21 +2389,21 @@ class UtilsTests(SimpleTestCase): def test_round_away_from_one(self): tests = [ (0, 0), - (0., 0), + (0.0, 0), (0.25, 0), (0.5, 0), (0.75, 0), (1, 1), - (1., 1), + (1.0, 1), (1.25, 2), (1.5, 2), (1.75, 2), - (-0., 0), + (-0.0, 0), (-0.25, -1), (-0.5, -1), (-0.75, -1), (-1, -1), - (-1., -1), + (-1.0, -1), (-1.25, -2), (-1.5, -2), (-1.75, -2), diff --git a/tests/i18n/unchanged/__init__.py b/tests/i18n/unchanged/__init__.py index 0ff42ffd6c..afcadcbcb7 100644 --- a/tests/i18n/unchanged/__init__.py +++ b/tests/i18n/unchanged/__init__.py @@ -1,4 +1,4 @@ from django.utils.translation import gettext as _ -string1 = _('This is a translatable string.') -string2 = _('This is another translatable string.') +string1 = _("This is a translatable string.") +string2 = _("This is another translatable string.") diff --git a/tests/i18n/urls.py b/tests/i18n/urls.py index 6a1dd75e24..6e2ffab83f 100644 --- a/tests/i18n/urls.py +++ b/tests/i18n/urls.py @@ -4,6 +4,6 @@ from django.urls import path from django.utils.translation import gettext_lazy as _ urlpatterns = i18n_patterns( - path('simple/', lambda r: HttpResponse()), - path('streaming/', lambda r: StreamingHttpResponse([_('Yes'), '/', _('No')])), + path("simple/", lambda r: HttpResponse()), + path("streaming/", lambda r: StreamingHttpResponse([_("Yes"), "/", _("No")])), ) diff --git a/tests/i18n/urls_default_unprefixed.py b/tests/i18n/urls_default_unprefixed.py index 8801d078f4..f14b059d37 100644 --- a/tests/i18n/urls_default_unprefixed.py +++ b/tests/i18n/urls_default_unprefixed.py @@ -4,8 +4,8 @@ from django.urls import path, re_path from django.utils.translation import gettext_lazy as _ urlpatterns = i18n_patterns( - re_path(r'^(?P<arg>[\w-]+)-page', lambda request, **arg: HttpResponse(_('Yes'))), - path('simple/', lambda r: HttpResponse(_('Yes'))), - re_path(r'^(.+)/(.+)/$', lambda *args: HttpResponse()), + re_path(r"^(?P<arg>[\w-]+)-page", lambda request, **arg: HttpResponse(_("Yes"))), + path("simple/", lambda r: HttpResponse(_("Yes"))), + re_path(r"^(.+)/(.+)/$", lambda *args: HttpResponse()), prefix_default_language=False, ) diff --git a/tests/i18n/utils.py b/tests/i18n/utils.py index d6cae260aa..625f4a8841 100644 --- a/tests/i18n/utils.py +++ b/tests/i18n/utils.py @@ -7,25 +7,25 @@ source_code_dir = os.path.dirname(__file__) def copytree(src, dst): - shutil.copytree(src, dst, ignore=shutil.ignore_patterns('__pycache__')) + shutil.copytree(src, dst, ignore=shutil.ignore_patterns("__pycache__")) class POFileAssertionMixin: - def _assertPoKeyword(self, keyword, expected_value, haystack, use_quotes=True): q = '"' if use_quotes: expected_value = '"%s"' % expected_value q = "'" - needle = '%s %s' % (keyword, expected_value) + needle = "%s %s" % (keyword, expected_value) expected_value = re.escape(expected_value) return self.assertTrue( - re.search('^%s %s' % (keyword, expected_value), haystack, re.MULTILINE), - 'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n': needle, 'q': q} + re.search("^%s %s" % (keyword, expected_value), haystack, re.MULTILINE), + "Could not find %(q)s%(n)s%(q)s in generated PO file" + % {"n": needle, "q": q}, ) def assertMsgId(self, msgid, haystack, use_quotes=True): - return self._assertPoKeyword('msgid', msgid, haystack, use_quotes=use_quotes) + return self._assertPoKeyword("msgid", msgid, haystack, use_quotes=use_quotes) class RunInTmpDirMixin: @@ -44,7 +44,7 @@ class RunInTmpDirMixin: def setUp(self): self._cwd = os.getcwd() - self.work_dir = tempfile.mkdtemp(prefix='i18n_') + self.work_dir = tempfile.mkdtemp(prefix="i18n_") # Resolve symlinks, if any, in test directory paths. self.test_dir = os.path.realpath(os.path.join(self.work_dir, self.work_subdir)) copytree(os.path.join(source_code_dir, self.work_subdir), self.test_dir) @@ -56,6 +56,9 @@ class RunInTmpDirMixin: os.chdir(self.test_dir) def _rmrf(self, dname): - if os.path.commonprefix([self.test_dir, os.path.abspath(dname)]) != self.test_dir: + if ( + os.path.commonprefix([self.test_dir, os.path.abspath(dname)]) + != self.test_dir + ): return shutil.rmtree(dname) |