Skip to content

Commit

Permalink
plural: parse new c, e operands (otherwise unsupported though)
Browse files Browse the repository at this point in the history
  • Loading branch information
akx committed Jan 28, 2022
1 parent b815e9c commit 6ab7dab
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
31 changes: 22 additions & 9 deletions babel/plural.py
Expand Up @@ -19,7 +19,7 @@
def extract_operands(source):
"""Extract operands from a decimal, a float or an int, according to `CLDR rules`_.
The result is a 6-tuple (n, i, v, w, f, t), where those symbols are as follows:
The result is a 8-tuple (n, i, v, w, f, t, c, e), where those symbols are as follows:
====== ===============================================================
Symbol Value
Expand All @@ -30,14 +30,16 @@ def extract_operands(source):
w number of visible fraction digits in n, without trailing zeros.
f visible fractional digits in n, with trailing zeros.
t visible fractional digits in n, without trailing zeros.
c compact decimal exponent value: exponent of the power of 10 used in compact decimal formatting.
e currently, synonym for ‘c’. however, may be redefined in the future.
====== ===============================================================
.. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Operands
.. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-61/tr35-numbers.html#Operands
:param source: A real number
:type source: int|float|decimal.Decimal
:return: A n-i-v-w-f-t tuple
:rtype: tuple[decimal.Decimal, int, int, int, int, int]
:return: A n-i-v-w-f-t-c-e tuple
:rtype: tuple[decimal.Decimal, int, int, int, int, int, int, int]
"""
n = abs(source)
i = int(n)
Expand Down Expand Up @@ -69,7 +71,8 @@ def extract_operands(source):
t = int(no_trailing or 0)
else:
v = w = f = t = 0
return n, i, v, w, f, t
c = e = 0 # TODO: c and e are not supported
return n, i, v, w, f, t, c, e


class PluralRule(object):
Expand Down Expand Up @@ -216,7 +219,7 @@ def to_python(rule):
to_python_func = _PythonCompiler().compile
result = [
'def evaluate(n):',
' n, i, v, w, f, t = extract_operands(n)',
' n, i, v, w, f, t, c, e = extract_operands(n)',
]
for tag, ast in PluralRule.parse(rule).abstract:
# the str() call is to coerce the tag to the native string. It's
Expand Down Expand Up @@ -317,12 +320,20 @@ def cldr_modulo(a, b):
class RuleError(Exception):
"""Raised if a rule is malformed."""

_VARS = 'nivwft'
_VARS = {
'n', # absolute value of the source number.
'i', # integer digits of n.
'v', # number of visible fraction digits in n, with trailing zeros.*
'w', # number of visible fraction digits in n, without trailing zeros.*
'f', # visible fraction digits in n, with trailing zeros.*
't', # visible fraction digits in n, without trailing zeros.*
'c', # compact decimal exponent value: exponent of the power of 10 used in compact decimal formatting.
'e', # currently, synonym for ‘c’. however, may be redefined in the future.
}

_RULES = [
(None, re.compile(r'\s+', re.UNICODE)),
('word', re.compile(r'\b(and|or|is|(?:with)?in|not|mod|[{0}])\b'
.format(_VARS))),
('word', re.compile(fr'\b(and|or|is|(?:with)?in|not|mod|[{"".join(_VARS)}])\b')),
('value', re.compile(r'\d+')),
('symbol', re.compile(r'%|,|!=|=')),
('ellipsis', re.compile(r'\.{2,3}|\u2026', re.UNICODE)) # U+2026: ELLIPSIS
Expand Down Expand Up @@ -525,6 +536,8 @@ def compile(self, arg):
compile_w = lambda x: 'w'
compile_f = lambda x: 'f'
compile_t = lambda x: 't'
compile_c = lambda x: 'c'
compile_e = lambda x: 'e'
compile_value = lambda x, v: str(v)
compile_and = _binary_compiler('(%s && %s)')
compile_or = _binary_compiler('(%s || %s)')
Expand Down
4 changes: 3 additions & 1 deletion tests/test_plural.py
Expand Up @@ -255,13 +255,15 @@ def test_or_and(self):

@pytest.mark.parametrize('source,n,i,v,w,f,t', EXTRACT_OPERANDS_TESTS)
def test_extract_operands(source, n, i, v, w, f, t):
e_n, e_i, e_v, e_w, e_f, e_t = plural.extract_operands(source)
e_n, e_i, e_v, e_w, e_f, e_t, e_c, e_e = plural.extract_operands(source)
assert abs(e_n - decimal.Decimal(n)) <= EPSILON # float-decimal conversion inaccuracy
assert e_i == i
assert e_v == v
assert e_w == w
assert e_f == f
assert e_t == t
assert not e_c # Not supported at present
assert not e_e # Not supported at present


@pytest.mark.parametrize('locale', ('ru', 'pl'))
Expand Down

0 comments on commit 6ab7dab

Please sign in to comment.