diff options
Diffstat (limited to 'babel/numbers.py')
-rw-r--r-- | babel/numbers.py | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/babel/numbers.py b/babel/numbers.py index b8971bc..192e3ed 100644 --- a/babel/numbers.py +++ b/babel/numbers.py @@ -425,6 +425,63 @@ def format_decimal( number, locale, decimal_quantization=decimal_quantization, group_separator=group_separator) +def format_compact_decimal(number, *, format_type="short", locale=LC_NUMERIC, fraction_digits=0): + u"""Return the given decimal number formatted for a specific locale in compact form. + + >>> format_compact_decimal(12345, format_type="short", locale='en_US') + u'12K' + >>> format_compact_decimal(12345, format_type="long", locale='en_US') + u'12 thousand' + >>> format_compact_decimal(12345, format_type="short", locale='en_US', fraction_digits=2) + u'12.35K' + >>> format_compact_decimal(1234567, format_type="short", locale="ja_JP") + u'123万' + >>> format_compact_decimal(2345678, format_type="long", locale="mk") + u'2 милиони' + >>> format_compact_decimal(21098765, format_type="long", locale="mk") + u'21 милион' + + :param number: the number to format + :param format_type: Compact format to use ("short" or "long") + :param locale: the `Locale` object or locale identifier + :param fraction_digits: Number of digits after the decimal point to use. Defaults to `0`. + """ + locale = Locale.parse(locale) + number, format = _get_compact_format(number, format_type, locale, fraction_digits) + pattern = parse_pattern(format) + return pattern.apply(number, locale, decimal_quantization=False) + + +def _get_compact_format(number, format_type, locale, fraction_digits=0): + """Returns the number after dividing by the unit and the format pattern to use. + The algorithm is described here: + https://www.unicode.org/reports/tr35/tr35-45/tr35-numbers.html#Compact_Number_Formats. + """ + format = None + compact_format = locale.compact_decimal_formats[format_type] + for magnitude in sorted([int(m) for m in compact_format["other"]], reverse=True): + if abs(number) >= magnitude: + # check the pattern using "other" as the amount + format = compact_format["other"][str(magnitude)] + pattern = parse_pattern(format).pattern + # if the pattern is "0", we do not divide the number + if pattern == "0": + break + # otherwise, we need to divide the number by the magnitude but remove zeros + # equal to the number of 0's in the pattern minus 1 + number = number / (magnitude / (10 ** (pattern.count("0") - 1))) + # round to the number of fraction digits requested + number = round(number, fraction_digits) + # if the remaining number is singular, use the singular format + plural_form = locale.plural_form(abs(number)) + plural_form = plural_form if plural_form in compact_format else "other" + format = compact_format[plural_form][str(magnitude)] + break + if format is None: # Did not find a format, fall back. + format = locale.decimal_formats.get(None) + return number, format + + class UnknownCurrencyFormatError(KeyError): """Exception raised when an unknown currency format is requested.""" |