diff --git a/src/humanize/filesize.py b/src/humanize/filesize.py index 063affe0..82fc0531 100644 --- a/src/humanize/filesize.py +++ b/src/humanize/filesize.py @@ -5,6 +5,7 @@ __lazy_modules__ = {"humanize.i18n"} from humanize.i18n import _gettext as _ +from humanize.i18n import decimal_separator suffixes = { "decimal": ( @@ -106,5 +107,10 @@ def naturalsize( if exp < len(suffix) and abs(float(format % (abs_bytes / (base**exp)))) >= base: exp += 1 space = "" if gnu else " " - ret: str = format % (bytes_ / (base**exp)) + space + _(suffix[exp - 1]) - return ret + formatted = format % (bytes_ / (base**exp)) + # Default locales keep ".". Only rewrite when a locale uses another + # decimal separator so the common path stays a single format + concat. + sep = decimal_separator() + if sep != ".": + formatted = formatted.replace(".", sep, 1) + return formatted + space + _(suffix[exp - 1]) diff --git a/tests/test_filesize.py b/tests/test_filesize.py index 645751b9..4cae6b85 100644 --- a/tests/test_filesize.py +++ b/tests/test_filesize.py @@ -2,6 +2,8 @@ from __future__ import annotations +import gettext + import pytest import humanize @@ -101,3 +103,19 @@ def test_naturalsize(test_args: list[int] | list[int | bool], expected: str) -> test_args[0] = f"-{test_args[0]}" assert humanize.naturalsize(*test_args) == "-" + expected + + +def test_naturalsize_uses_locale_decimal_separator() -> None: + """Locales with a comma radix should not keep a dotted mantissa. + + Uses a NullTranslations catalog so this does not depend on compiled .mo files. + """ + humanize.i18n._TRANSLATIONS["fr_FR"] = gettext.NullTranslations() + humanize.i18n._CURRENT.locale = "fr_FR" + try: + assert humanize.naturalsize(1_500_000) == "1,5 MB" + assert humanize.naturalsize(3000, gnu=True) == "2,9K" + assert humanize.naturalsize(3000, binary=True) == "2,9 KiB" + finally: + humanize.i18n.deactivate() + assert humanize.naturalsize(1_500_000) == "1.5 MB" diff --git a/tests/test_i18n.py b/tests/test_i18n.py index 683fe3ce..1dbc039f 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -241,10 +241,11 @@ def test_intword_i18n(locale: str, number: int, expected_result: str) -> None: ("fr_FR", 42, "42 octets"), ("si_LK", 1, "බයිට් 1"), ("si_LK", 42, "බයිට් 42"), - ("fr_FR", 42_000, "42.0 Ko"), - ("fr_FR", 42_000_000, "42.0 Mo"), - ("fr_FR", 42_000_000_000, "42.0 Go"), - ("fr_FR", -42_000, "-42.0 Ko"), + ("fr_FR", 42_000, "42,0 Ko"), + ("fr_FR", 42_000_000, "42,0 Mo"), + ("fr_FR", 42_000_000_000, "42,0 Go"), + ("fr_FR", -42_000, "-42,0 Ko"), + ("fr_FR", 1_500_000, "1,5 Mo"), ], ) def test_naturalsize_i18n(locale: str, value: float, expected_result: str) -> None: @@ -264,7 +265,7 @@ def test_naturalsize_i18n_binary() -> None: except FileNotFoundError: pytest.skip("Generate .mo with scripts/generate-translation-binaries.sh") else: - assert humanize.naturalsize(3000, binary=True) == "2.9 Kio" + assert humanize.naturalsize(3000, binary=True) == "2,9 Kio" finally: humanize.i18n.deactivate()