From 862748a7acd3db1257418101eec626688e0d3c78 Mon Sep 17 00:00:00 2001 From: Luflosi Date: Tue, 23 Aug 2022 17:50:28 +0200 Subject: [PATCH] Internationalise the decimal separator in intcomma() --- src/humanize/__init__.py | 3 ++- src/humanize/i18n.py | 20 +++++++++++++++++++- src/humanize/number.py | 10 ++++++---- tests/test_i18n.py | 6 ++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/humanize/__init__.py b/src/humanize/__init__.py index 25c0ba1..7d3ae65 100644 --- a/src/humanize/__init__.py +++ b/src/humanize/__init__.py @@ -1,7 +1,7 @@ """Main package for humanize.""" from humanize.filesize import naturalsize -from humanize.i18n import activate, deactivate, thousands_separator +from humanize.i18n import activate, deactivate, decimal_separator, thousands_separator from humanize.number import ( apnumber, clamp, @@ -36,6 +36,7 @@ "apnumber", "clamp", "deactivate", + "decimal_separator", "fractional", "intcomma", "intword", diff --git a/src/humanize/i18n.py b/src/humanize/i18n.py index 8c02923..664b074 100644 --- a/src/humanize/i18n.py +++ b/src/humanize/i18n.py @@ -5,7 +5,7 @@ import os.path from threading import local -__all__ = ["activate", "deactivate", "thousands_separator"] +__all__ = ["activate", "deactivate", "decimal_separator", "thousands_separator"] _TRANSLATIONS: dict[str | None, gettext_module.NullTranslations] = { None: gettext_module.NullTranslations() @@ -19,6 +19,11 @@ "fr_FR": " ", } +# Mapping of locale to decimal separator +_DECIMAL_SEPARATOR = { + "de_DE": ",", +} + def _get_default_locale_path() -> str | None: try: @@ -173,3 +178,16 @@ def thousands_separator() -> str: except (AttributeError, KeyError): sep = "," return sep + + +def decimal_separator() -> str: + """Return the decimal separator for a locale, default to dot. + + Returns: + str: Decimal separator. + """ + try: + sep = _DECIMAL_SEPARATOR[_CURRENT.locale] + except (AttributeError, KeyError): + sep = "." + return sep diff --git a/src/humanize/number.py b/src/humanize/number.py index ac134e3..bfd2b48 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -13,7 +13,7 @@ from .i18n import _ngettext from .i18n import _ngettext_noop as NS_ from .i18n import _pgettext as P_ -from .i18n import thousands_separator +from .i18n import decimal_separator, thousands_separator if TYPE_CHECKING: if sys.version_info >= (3, 10): @@ -130,10 +130,11 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str: Returns: str: String containing commas every three digits. """ - sep = thousands_separator() + thousands_sep = thousands_separator() + decimal_sep = decimal_separator() try: if isinstance(value, str): - value = value.replace(sep, "") + value = value.replace(thousands_sep, "").replace(decimal_sep, ".") if "." in value: value = float(value) else: @@ -147,8 +148,9 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str: orig = "{0:.{1}f}".format(value, ndigits) else: orig = str(value) + orig = orig.replace(".", decimal_sep) while True: - new = re.sub(r"^(-?\d+)(\d{3})", rf"\g<1>{sep}\g<2>", orig) + new = re.sub(r"^(-?\d+)(\d{3})", rf"\g<1>{thousands_sep}\g<2>", orig) if orig == new: return new orig = new diff --git a/tests/test_i18n.py b/tests/test_i18n.py index 4a60af1..f8782f8 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -44,6 +44,12 @@ def test_intcomma() -> None: try: humanize.i18n.activate("de_DE") assert humanize.intcomma(number) == "10.000.000" + assert humanize.intcomma(1_234_567.8901) == "1.234.567,8901" + assert humanize.intcomma(1_234_567.89) == "1.234.567,89" + assert humanize.intcomma("1234567,89") == "1.234.567,89" + assert humanize.intcomma("1.234.567,89") == "1.234.567,89" + assert humanize.intcomma("1.234.567,8") == "1.234.567,8" + humanize.i18n.activate("fr_FR") assert humanize.intcomma(number) == "10 000 000"