]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Simplify format_currency code by pulling out/using helpers. 585/head
authorLuke Plant <L.Plant.98@cantab.net>
Thu, 7 Jun 2018 12:21:19 +0000 (15:21 +0300)
committerLuke Plant <L.Plant.98@cantab.net>
Thu, 7 Jun 2018 12:37:27 +0000 (15:37 +0300)
In detail:

1. Use the already existing get_currency_name function which does
   the plural form logic already.

2. Create a similar `get_currency_unit_pattern` function.
   This function could be useful if someone wanted to write
   something very similar to the _format_currency_long_name
   functionality but with some different customizations,
   so it is now publicly documented.

3. Simplify the _format_currency_long_name function - it
   is now much flatter.

4. Add more tests to ensure certain cases are really covered.
   (e.g. different unit patterns depending on the count)

An upshot of the changes is that we have reduced (and made more consistent)
the number of places where we need to peek into `Locale._data` -
get_currency_name and get_currency_unit_pattern are the only places that
babel.numbers does this.

babel/numbers.py
docs/api/numbers.rst
tests/test_numbers.py

index 9df19e9314479d2e603c1486554d3e81fe46c625..cc825c866dd67979f58776715e00261be6774766 100644 (file)
@@ -157,6 +157,36 @@ def get_currency_precision(currency):
     return precisions.get(currency, precisions['DEFAULT'])[0]
 
 
+def get_currency_unit_pattern(currency, count=None, locale=LC_NUMERIC):
+    """
+    Return the unit pattern used for long display of a currency value
+    for a given locale.
+    This is a string containing ``{0}`` where the numeric part
+    should be substituted and ``{1}`` where the currency long display
+    name should be substituted.
+
+    >>> get_currency_unit_pattern('USD', locale='en_US', count=10)
+    u'{0} {1}'
+
+    .. versionadded:: 2.7.0
+
+    :param currency: the currency code.
+    :param count: the optional count.  If provided the unit
+                  pattern for that number will be returned.
+    :param locale: the `Locale` object or locale identifier.
+    """
+    loc = Locale.parse(locale)
+    if count is not None:
+        plural_form = loc.plural_form(count)
+        try:
+            return loc._data['currency_unit_patterns'][plural_form]
+        except LookupError:
+            # Fall back to 'other'
+            pass
+
+    return loc._data['currency_unit_patterns']['other']
+
+
 def get_territory_currencies(territory, start_date=None, end_date=None,
                              tender=True, non_tender=False,
                              include_details=False):
@@ -501,28 +531,18 @@ def _format_currency_long_name(
     # There are no examples of items with explicit count (0 or 1) in current
     # locale data. So there is no point implementing that.
     # Step 2.
+
+    # Correct number to numeric type, important for looking up plural rules:
     if isinstance(number, string_types):
-        plural_category = locale.plural_form(float(number))
+        number_n = float(number)
     else:
-        plural_category = locale.plural_form(number)
+        number_n = number
 
     # Step 3.
-    try:
-        unit_pattern = locale._data['currency_unit_patterns'][plural_category]
-    except LookupError:
-        unit_pattern = locale._data['currency_unit_patterns']['other']
+    unit_pattern = get_currency_unit_pattern(currency, count=number_n, locale=locale)
 
     # Step 4.
-    try:
-        display_name = locale._data['currency_names_plural'][currency][plural_category]
-    except LookupError:
-        try:
-            display_name = locale._data['currency_names_plural'][currency]['other']
-        except LookupError:
-            try:
-                display_name = locale._data['currency_names'][currency]
-            except LookupError:
-                display_name = currency
+    display_name = get_currency_name(currency, count=number_n, locale=locale)
 
     # Step 5.
     if not format:
index 1b21425ee97fc55d09322f948b8aa64a0fd16bd1..758cebaf320e3a94559fbead89db0fae865e8fd3 100644 (file)
@@ -38,6 +38,8 @@ Data Access
 
 .. autofunction:: get_currency_symbol
 
+.. autofunction:: get_currency_unit_pattern
+
 .. autofunction:: get_decimal_symbol
 
 .. autofunction:: get_plus_sign_symbol
index f0239cb3ad6cfdf641fc089d5e0ce3dc6a4f13f2..32f4280e76eea6b7a5723cc5ecae199f7d985a62 100644 (file)
@@ -19,7 +19,7 @@ from datetime import date
 from babel import Locale, localedata, numbers
 from babel.numbers import (
     list_currencies, validate_currency, UnknownCurrencyError, is_currency, normalize_currency,
-    get_currency_precision, get_decimal_precision)
+    get_currency_precision, get_decimal_precision, get_currency_unit_pattern)
 from babel.localedata import locale_identifiers
 from babel._compat import decimal
 
@@ -228,6 +228,17 @@ def test_get_currency_precision():
     assert get_currency_precision('JPY') == 0
 
 
+def test_get_currency_unit_pattern():
+    assert get_currency_unit_pattern('USD', locale='en_US') == '{0} {1}'
+    assert get_currency_unit_pattern('USD', locale='es_GT') == '{1} {0}'
+
+    # 'ro' locale various pattern according to count
+    assert get_currency_unit_pattern('USD', locale='ro', count=1) == '{0} {1}'
+    assert get_currency_unit_pattern('USD', locale='ro', count=2) == '{0} {1}'
+    assert get_currency_unit_pattern('USD', locale='ro', count=100) == '{0} de {1}'
+    assert get_currency_unit_pattern('USD', locale='ro') == '{0} de {1}'
+
+
 def test_get_territory_currencies():
     assert numbers.get_territory_currencies('AT', date(1995, 1, 1)) == ['ATS']
     assert numbers.get_territory_currencies('AT', date(2011, 1, 1)) == ['EUR']
@@ -434,6 +445,14 @@ def test_format_currency_long_display_name():
     assert (numbers.format_currency(1099.98, 'XAB', locale='en_US', format_type='name')
             == u'1,099.98 XAB')
 
+    # Test for finding different unit patterns depending on count
+    assert (numbers.format_currency(1, 'USD', locale='ro', format_type='name')
+            == u'1,00 dolar american')
+    assert (numbers.format_currency(2, 'USD', locale='ro', format_type='name')
+            == u'2,00 dolari americani')
+    assert (numbers.format_currency(100, 'USD', locale='ro', format_type='name')
+            == u'100,00 de dolari americani')
+
 
 def test_format_currency_long_display_name_all():
     for locale_code in localedata.locale_identifiers():