Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions babel/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def format_unit(

.. versionadded:: 2.2.0

:param value: the value to format. If this is a string, no number formatting will be attempted.
:param value: the value to format. If this is a string, no number formatting will be attempted and the number is assumed to be singular for the purposes of unit formatting.
:param measurement_unit: the code of a measurement unit.
Known units can be found in the CLDR Unit Validity XML file:
https://unicode.org/repos/cldr/tags/latest/common/validity/unit.xml
Expand All @@ -137,7 +137,6 @@ def format_unit(
q_unit = _find_unit_pattern(measurement_unit, locale=locale)
if not q_unit:
raise UnknownUnitError(unit=measurement_unit, locale=locale)
unit_patterns = locale._data["unit_patterns"][q_unit].get(length, {})

if isinstance(value, str): # Assume the value is a preformatted singular.
formatted_value = value
Expand All @@ -146,8 +145,23 @@ def format_unit(
formatted_value = format_decimal(value, format, locale, numbering_system=numbering_system)
plural_form = locale.plural_form(value)

if plural_form in unit_patterns:
return unit_patterns[plural_form].format(formatted_value)
unit_patterns = locale._data["unit_patterns"][q_unit]

# We do not support `<alias>` tags at all while ingesting CLDR data,
# so these aliases specified in `root.xml` are hard-coded here:
# <unitLength type="long"><alias source="locale" path="../unitLength[@type='short']"/></unitLength>
# <unitLength type="narrow"><alias source="locale" path="../unitLength[@type='short']"/></unitLength>
lengths_to_check = [length]
if length in ("long", "narrow"):
lengths_to_check.append("short")

for real_length in lengths_to_check:
length_patterns = unit_patterns.get(real_length, {})
# Fall back from the correct plural form to "other"
# (this is specified in LDML "Lateral Inheritance")
pat = length_patterns.get(plural_form) or length_patterns.get("other")
if pat:
return pat.format(formatted_value)

# Fall back to a somewhat bad representation.
# nb: This is marked as no-cover, as the current CLDR seemingly has no way for this to happen.
Expand Down
12 changes: 12 additions & 0 deletions tests/test_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@
])
def test_new_cldr46_units(unit, count, expected):
assert format_unit(count, unit, locale='cs_CZ') == expected


@pytest.mark.parametrize('count, unit, locale, length, expected', [
(1, 'duration-month', 'et', 'long', '1 kuu'),
(1, 'duration-minute', 'et', 'narrow', '1 min'),
(2, 'duration-minute', 'et', 'narrow', '2 min'),
(2, 'digital-byte', 'et', 'long', '2 baiti'),
(1, 'duration-day', 'it', 'long', '1 giorno'),
(1, 'duration-day', 'it', 'short', '1 giorno'),
])
def test_issue_1217(count, unit, locale, length, expected):
assert format_unit(count, unit, length, locale=locale) == expected