From 9adc205b6d0269a81ce93a7e6d6b0f375f6bd526 Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Wed, 15 Jan 2025 13:18:06 +0100 Subject: [PATCH] Refs #28877 -- Added special ordinal context when humanizing value 1. Some languages use a different ordinal suffix for the number 1 than for other values ending in 1 (e.g. 21, 31). Added a dedicated pgettext context "ordinal is 1" to allow translators to handle this distinction. For example, in French, 1 is written as "1er" while 21, 31, etc. use "21e", "31e", etc. Co-authored-by: Natalia <124304+nessita@users.noreply.github.com> --- .../contrib/humanize/templatetags/humanize.py | 5 +- .../locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 806 bytes .../locale/fr/LC_MESSAGES/django.po | 74 ++++++++++++++++++ tests/humanize_tests/tests.py | 10 ++- 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 tests/humanize_tests/locale/fr/LC_MESSAGES/django.mo create mode 100644 tests/humanize_tests/locale/fr/LC_MESSAGES/django.po diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py index 26a9dd3a3f68..79d2e1566721 100644 --- a/django/contrib/humanize/templatetags/humanize.py +++ b/django/contrib/humanize/templatetags/humanize.py @@ -32,7 +32,10 @@ def ordinal(value): return value if value < 0: return str(value) - if value % 100 in (11, 12, 13): + if value == 1: + # Translators: Ordinal format when value is 1 (1st). + value = pgettext("ordinal is 1", "{}st").format(value) + elif value % 100 in (11, 12, 13): # Translators: Ordinal format for 11 (11th), 12 (12th), and 13 (13th). value = pgettext("ordinal 11, 12, 13", "{}th").format(value) else: diff --git a/tests/humanize_tests/locale/fr/LC_MESSAGES/django.mo b/tests/humanize_tests/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..0cdef6c211ceb4d4a2efd9f16b26937a0b59b65c GIT binary patch literal 806 zcmd6izb^zq7={POv3`YuMlmIc&E1~ExnGfpt0WZX4_J45dz-A;H8UsVa-pEs&}!5g zwMMN`E2t$JozlDRbC>-OO!DTLXZM@$n|Yf}+%T+3WC6KAW{^)LTIm7Cra+6h3C_cJ z$z9?x@sfB=ydypkpNKDDH0K>W1Hb6|(O`GpIq`~kOS~sO5}%2$#1G;(F*(H8H2Tkh z7{SJo=&i%Z-x|ecf+R^yfH=a&5CcIwHiED~);(eSJe_EFbhD=xRO!B2%iPK!EAg@n zRMdNA(O=ouY`l0iu4{2!k83Wj8*%j%ryFhsLOVj6)zi?)bM2hyROs8DDDYa-mdeqk z{c6R`8NE7b3)OI>xh-k|p6=#(?!eQ=jxF4l?V?9R8hd_A+P+x{ 1);\n" + +msgid "Humanize" +msgstr "Humanisation" + +#. Translators: Ordinal format when value is 1 (1st). +#: contrib/humanize/templatetags/humanize.py:37 +#, fuzzy +#| msgctxt "ordinal 1" +#| msgid "{}st" +msgctxt "ordinal is 1" +msgid "{}st" +msgstr "{}er" + +#. Translators: Ordinal format for 11 (11th), 12 (12th), and 13 (13th). +msgctxt "ordinal 11, 12, 13" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 0, e.g. 80th. +msgctxt "ordinal 0" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 1, e.g. 81st, except 11. +msgctxt "ordinal 1" +msgid "{}st" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 2, e.g. 82nd, except 12. +msgctxt "ordinal 2" +msgid "{}nd" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 3, e.g. 83rd, except 13. +msgctxt "ordinal 3" +msgid "{}rd" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 4, e.g. 84th. +msgctxt "ordinal 4" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 5, e.g. 85th. +msgctxt "ordinal 5" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 6, e.g. 86th. +msgctxt "ordinal 6" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 7, e.g. 87th. +msgctxt "ordinal 7" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 8, e.g. 88th. +msgctxt "ordinal 8" +msgid "{}th" +msgstr "{}e" + +#. Translators: Ordinal format when value ends with 9, e.g. 89th. +msgctxt "ordinal 9" +msgid "{}th" +msgstr "{}e" diff --git a/tests/humanize_tests/tests.py b/tests/humanize_tests/tests.py index 7c2863d3c478..91e9127a65bf 100644 --- a/tests/humanize_tests/tests.py +++ b/tests/humanize_tests/tests.py @@ -1,4 +1,5 @@ import datetime +import os from decimal import Decimal from django.contrib.humanize.templatetags import humanize @@ -9,10 +10,10 @@ from django.utils.timezone import get_fixed_timezone from django.utils.translation import gettext as _ +here = os.path.dirname(os.path.abspath(__file__)) # Mock out datetime in some tests so they don't fail occasionally when they # run too slow. Use a fixed datetime for datetime.now(). DST change in # America/Chicago (the default time zone) happened on March 11th in 2012. - now = datetime.datetime(2012, 3, 9, 22, 30) @@ -83,6 +84,7 @@ def test_ordinal(self): with translation.override("en"): self.humanize_tester(test_list, result_list, "ordinal") + @override_settings(LOCALE_PATHS=[os.path.join(here, "locale")]) def test_i18n_html_ordinal(self): """Allow html in output on i18n strings""" test_list = ( @@ -93,6 +95,8 @@ def test_i18n_html_ordinal(self): "11", "12", "13", + "21", + "31", "101", "102", "103", @@ -108,7 +112,9 @@ def test_i18n_html_ordinal(self): "11e", "12e", "13e", - "101er", + "21e", + "31e", + "101e", "102e", "103e", "111e",