summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Plant <L.Plant.98@cantab.net>2018-06-07 15:21:19 +0300
committerLuke Plant <L.Plant.98@cantab.net>2018-06-07 15:37:27 +0300
commit4c7e9b645cfec72672f836e04d8587ca66ba98c3 (patch)
tree7be9d2495b8fc3799643299c0adcd070bca90a9e
parent4b5097f6064dda281ce7a1c5ef74e047cfdc558c (diff)
downloadbabel-4c7e9b645cfec72672f836e04d8587ca66ba98c3.tar.gz
Simplify format_currency code by pulling out/using helpers.
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.
-rw-r--r--babel/numbers.py52
-rw-r--r--docs/api/numbers.rst2
-rw-r--r--tests/test_numbers.py21
3 files changed, 58 insertions, 17 deletions
diff --git a/babel/numbers.py b/babel/numbers.py
index 9df19e9..cc825c8 100644
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -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:
diff --git a/docs/api/numbers.rst b/docs/api/numbers.rst
index 1b21425..758ceba 100644
--- a/docs/api/numbers.rst
+++ b/docs/api/numbers.rst
@@ -38,6 +38,8 @@ Data Access
.. autofunction:: get_currency_symbol
+.. autofunction:: get_currency_unit_pattern
+
.. autofunction:: get_decimal_symbol
.. autofunction:: get_plus_sign_symbol
diff --git a/tests/test_numbers.py b/tests/test_numbers.py
index f0239cb..32f4280 100644
--- a/tests/test_numbers.py
+++ b/tests/test_numbers.py
@@ -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():