o V\BS @sdZddlZddlmZdZdZddZGdd d eZd d Z d d Z ddZ ddZ ddZ ddZGdddeZdZdedejfdedefdedfdedfd ed!ejfgZd"d#ZdBd$d%ZdBd&d'Zd(d)Zd*d+Zd,d-Zd.d/ZGd0d1d1eZd2d3Zd4d5Zd6d7Z Gd8d9d9eZ!Gd:d;d;e!Z"Gdd?d?e#Z$Gd@dAdAe!Z%dS)Cz babel.numbers ~~~~~~~~~~~~~ CLDR Plural support. See UTS #35. :copyright: (c) 2013-2019 by the Babel Team. :license: BSD, see LICENSE for more details. N)decimal)zeroonetwofewmanyotherrc Cst|}t|}t|tr||kr|}ntt|}t|tjrY|}|j}|dkr3|j |dnd}d dd|D}| d}t |}t |} t|pPd} t|pVd} nd}} } } |||| | | fS)a#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: ====== =============================================================== Symbol Value ------ --------------------------------------------------------------- n absolute value of the source number (integer and decimals). 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 fractional digits in n, with trailing zeros. t visible fractional digits in n, without trailing zeros. ====== =============================================================== .. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-33/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] rNcss|]}t|VqdSNstr).0dr r ./usr/lib/python3/dist-packages/babel/plural.py Asz#extract_operands..0) absint isinstancefloatrDecimalr as_tupleexponentdigitsjoinrstriplen) sourceni dec_tupleexpfraction_digitstrailing no_trailingvwftr r rextract_operandss$    r*c@sdeZdZdZdZddZddZeddZe d d Z e d d d dZ ddZ ddZ ddZdS) PluralRuleafRepresents a set of language pluralization rules. The constructor accepts a list of (tag, expr) tuples or a dict of `CLDR rules`_. The resulting object is callable and accepts one parameter with a positive or negative number (both integer and float) for the number that indicates the plural form for a string and returns the tag for the format: >>> rule = PluralRule({'one': 'n is 1'}) >>> rule(1) 'one' >>> rule(2) 'other' Currently the CLDR defines these tags: zero, one, two, few, many and other where other is an implicit default. Rules should be mutually exclusive; for a given numeric value, only one rule should apply (i.e. the condition should only be true for one of the plural rule elements. .. _`CLDR rules`: https://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Language_Plural_Rules )abstract_funccCst|tr |}t}g|_tt|D],\}}|tvr#td|||vr-td|| |t |j }|rA|j ||fqdS)a$Initialize the rule instance. :param rules: a list of ``(tag, expr)``) tuples with the rules conforming to UTS #35 or a dict with the tags as keys and expressions as values. :raise RuleError: if the expression is malformed zunknown tag %rztag %r defined twiceN) rdictitemssetr,sortedlist _plural_tags ValueErroradd_Parserastappend)selfrulesfoundkeyexprr7r r r__init__cs     zPluralRule.__init__cs,|jdt|jdfddtDfS)Nz<%s %r>z, cs$g|]}|vrd||fqS)z%s: %sr rtagr:r r }sz'PluralRule.__repr__..)r:type__name__rr3r9r rAr__repr__ys zPluralRule.__repr__cCst||r|S||S)a Create a `PluralRule` instance for the given rules. If the rules are a `PluralRule` object, that object is returned. :param rules: the rules as list or dict, or a `PluralRule` object :raise RuleError: if the expression is malformed )r)clsr:r r rparses zPluralRule.parsecs tjtfdd|jDS)zThe `PluralRule` as a dict of unicode plural rules. >>> rule = PluralRule({'one': 'n is 1'}) >>> rule.rules {'one': 'n is 1'} csg|] \}}||fqSr r )rr@r7_compiler rrBsz$PluralRule.rules..)_UnicodeCompilercompiler.r,rEr rIrr:szPluralRule.rulescCstdd|jDS)NcSsg|]}|dqS)rr )rr r r rrBz'PluralRule...) frozensetr,xr r rrMzPluralRule.z A set of explicitly defined tags in this rule. The implicit default ``'other'`` rules is not part of this set unless there is an explicit rule for it.)doccCs|jSr r,rEr r r __getstate__zPluralRule.__getstate__cCs ||_dSr rS)r9r,r r r __setstate__ zPluralRule.__setstate__cCst|ds t||_||S)Nr-)hasattr to_pythonr-)r9rr r r__call__s   zPluralRule.__call__N)rD __module__ __qualname____doc__ __slots__r>rF classmethodrHpropertyr:tagsrTrVrZr r r rr+Ls    r+cCsRtj}dg}t|jD]\}}|d|||fq |dtd|S)aConvert a list/dict of rules or a `PluralRule` object into a JavaScript function. This function depends on no external library: >>> to_javascript({'one': 'n is 1'}) "(function(n) { return (n == 1) ? 'one' : 'other'; })" Implementation detail: The function generated will probably evaluate expressions involved into range operations multiple times. This has the advantage that external helper functions are not required and is not a big performance hit for these simple calculations. :param rule: the rules as list or dict, or a `PluralRule` object :raise RuleError: if the expression is malformed z(function(n) { return z %s ? %r : z%r; })r )_JavaScriptCompilerrLr+rHr,r8 _fallback_tagr)ruleto_jsresultr@r7r r r to_javascripts  rgcCsttttd}tj}ddg}t|jD]\}}| d||t |fq| dt td |dd}t |||d S) a<Convert a list/dict of rules or a `PluralRule` object into a regular Python function. This is useful in situations where you need a real function and don't are about the actual rule object: >>> func = to_python({'one': 'n is 1', 'few': 'n in 2..4'}) >>> func(1) 'one' >>> func(3) 'few' >>> func = to_python({'one': 'n in 1,11', 'few': 'n in 3..10,13..19'}) >>> func(11) 'one' >>> func(15) 'few' :param rule: the rules as list or dict, or a `PluralRule` object :raise RuleError: if the expression is malformed )INWITHINMODr*zdef evaluate(n):z' n, i, v, w, f, t = extract_operands(n)z if (%s): return %rz return %r zexecevaluate) in_range_listwithin_range_list cldr_modulor*_PythonCompilerrLr+rHr,r8r rcreval)rd namespaceto_python_funcrfr@r7coder r rrYs rYcst|}|jthBtj}fddtDj}dtg}|j D]\}}| d||||fq#| d|td |S)a~The plural rule as gettext expression. The gettext expression is technically limited to integers and returns indices rather than tags. >>> to_gettext({'one': 'n is 1', 'two': 'n is 2'}) 'nplurals=3; plural=((n == 1) ? 0 : (n == 2) ? 1 : 2)' :param rule: the rules as list or dict, or a `PluralRule` object :raise RuleError: if the expression is malformed csg|]}|vr|qSr r r? used_tagsr rrBzto_gettext..znplurals=%d; plural=(z %s ? %d : z%d)r ) r+rHrarc_GettextCompilerrLr3indexrr,r8r)rdrJ _get_indexrfr@r7r rvr to_gettexts  r|cCs|t|ko t||S)aInteger range list test. This is the callback for the "in" operator of the UTS #35 pluralization rule language: >>> in_range_list(1, [(1, 3)]) True >>> in_range_list(3, [(1, 3)]) True >>> in_range_list(3, [(1, 3), (5, 8)]) True >>> in_range_list(1.2, [(1, 4)]) False >>> in_range_list(10, [(1, 4)]) False >>> in_range_list(10, [(1, 4), (6, 8)]) False )rronum range_listr r rrnrncstfdd|DS)aFloat range test. This is the callback for the "within" operator of the UTS #35 pluralization rule language: >>> within_range_list(1, [(1, 3)]) True >>> within_range_list(1.0, [(1, 3)]) True >>> within_range_list(1.2, [(1, 4)]) True >>> within_range_list(8.8, [(1, 4), (7, 15)]) True >>> within_range_list(10, [(1, 4)]) False >>> within_range_list(10.5, [(1, 4), (20, 30)]) False c3s$|] \}}|ko |kVqdSr r )rmin_max_r~r rr$s"z$within_range_list..)anyr}r rrrorrocCs@d}|dkr |d9}d}|dkr|d9}||}|r|d9}|S)zJavaish modulo. This modulo operator returns the value with the sign of the dividend rather than the divisor like Python does: >>> cldr_modulo(-3, 5) -3 >>> cldr_modulo(-3, -5) -3 >>> cldr_modulo(3, 5) 3 rr )abreverservr r rrp's rpc@seZdZdZdS) RuleErrorzRaised if a rule is malformed.N)rDr[r\r]r r r rr>srnivwftz\s+wordz)\b(and|or|is|(?:with)?in|not|mod|[{0}])\bvaluez\d+symbolz%|,|!=|=ellipsisz\.{2,3}|\u2026cCs|dd}g}d}t|}||krAtD]\}}|||}|dur4|}|r2|||fn qtd||||ks|dddS)N@rz5malformed CLDR pluralization rule. Got unexpected %rr)splitr_RULESmatchendr8groupr)srfposrtokrdrr r r tokenize_ruleMs$   rcCs,|o|dd|ko|dup|dd|kS)Nrrrr tokenstype_rr r rtest_next_token`srcCst|||r |SdSr )rpoprr r r skip_tokenes rcC d|ffS)Nrr )rr r r value_nodejrWrcCs|dfS)Nr r )namer r r ident_nodenrcCsd|fS)Nrr )rr r rrange_list_noderrrcCr)Nnotr )rr r rnegatevrWrc@sbeZdZdZddZdddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ dS)r6uInternal parser. This class can translate a single rule into an abstract tree of tuples. It implements the following grammar:: condition = and_condition ('or' and_condition)* ('@integer' samples)? ('@decimal' samples)? and_condition = relation ('and' relation)* relation = is_relation | in_relation | within_relation is_relation = expr 'is' ('not')? value in_relation = expr (('not')? 'in' | '=' | '!=') range_list within_relation = expr ('not')? 'within' range_list expr = operand (('mod' | '%') value)? operand = 'n' | 'i' | 'f' | 't' | 'v' | 'w' range_list = (range | value) (',' range_list)* value = digit+ digit = 0|1|2|3|4|5|6|7|8|9 range = value'..'value samples = sampleRange (',' sampleRange)* (',' ('…'|'...'))? sampleRange = decimalValue '~' decimalValue decimalValue = value ('.' value)? - Whitespace can occur between or around any of the above tokens. - Rules should be mutually exclusive; for a given numeric value, only one rule should apply (i.e. the condition should only be true for one of the plural rule elements). - The in and within relations can take comma-separated lists, such as: 'n in 3,5,7..15'. - Samples are ignored. The translator parses the expression on instanciation into an attribute called `ast`. cCsDt||_|js d|_dS||_|jr td|jdddS)NzExpected end of rule, got %rrr)rrr7 conditionr)r9stringr r rr>s   z_Parser.__init__NcCsbt|j||}|dur |S|durt|dur|p|}|js$td|td||jddf)Nz#expected %s but end of rule reachedzexpected %s but got %rrr)rrreprr)r9rrtermtokenr r rexpects z_Parser.expectcC8|}t|jddrd||ff}t|jdds |S)Nror) and_conditionrrr9opr r rr z_Parser.conditioncCr)Nrand)relationrrrr r rrrz_Parser.and_conditioncCs|}t|jddrt|jddrdpd||ffSt|jdd}d}t|jddr/d}nt|jddsA|r.r rr rr_binary_compiler rcr)rcs||Sr r)r9rPrr rrQsz!_unary_compiler..r rr rr_unary_compilerrrcCdS)Nrr rOr r rrQrQc@seZdZdZddZddZddZddZddZd dZ d dZ d dZ e d Z e d ZedZe dZe dZe dZddZdS) _CompilerzZThe compilers are able to transform the expressions into multiple output formats. cCs|\}}t|d||S)Ncompile_)getattr)r9argrargsr r rrLsz_Compiler.compilecCr)Nrr rOr r rrQ rz_Compiler.cCr)Nr r rOr r rrQ rcCr)Nr&r rOr r rrQ rcCr)Nr'r rOr r rrQrcCr)Nr(r rOr r rrQrcCr)Nr)r rOr r rrQrcCst|Sr r )rPr&r r rrQsz (%s && %s)z (%s || %s)z(!%s)z (%s %% %s) (%s == %s)z (%s != %s)cCstr )NotImplementedError)r9rr=rr r rcompile_relationrUz_Compiler.compile_relationN)rDr[r\r]rL compile_n compile_i compile_v compile_w compile_f compile_t compile_valuer compile_and compile_orr compile_not compile_mod compile_is compile_isnotrr r r rrs" rc@s8eZdZdZedZedZedZedZ ddZ dS) rqz!Compiles an expression to Python.z (%s and %s)z (%s or %s)z(not %s)z MOD(%s, %s)cs8ddfdd|dD}d|||fS)Nz[%s]rcs g|] }dttj|qS)z(%s, %s))tuplemaprL)rrange_rEr rrB'sz4_PythonCompiler.compile_relation..rz %s(%s, %s))rupperrL)r9rr=rcompile_range_listr rErr%s z _PythonCompiler.compile_relationN) rDr[r\r]rrrrrrrr r r rrqs rqc@s.eZdZdZejZeZeZ eZ eZ ddZ dS)ryz)Compile into a gettext plural expression.c Cs~g}||}|dD],}|d|dkr$|d|||dfq t|j|\}}|d||||fq dd|S)Nrrrz(%s >= %s && %s <= %s)z(%s)z || )rLr8rr)r9rr=rritemminmaxr r rr6s      z!_GettextCompiler.compile_relationN) rDr[r\r]rrr compile_zerorrrrrr r r rry-s ryc@s0eZdZdZddZeZeZeZeZ ddZ dS)rbz/Compiles the expression to plain of JavaScript.cCr)NzparseInt(n, 10)r rOr r rrQOrz_JavaScriptCompiler.cCs4t||||}|dkr||}d|||f}|S)Nrz(parseInt(%s, 10) == %s && %s))ryrrL)r9rr=rrur r rrUs z$_JavaScriptCompiler.compile_relationN) rDr[r\r]rrrrrrrr r r rrbJs rbc@sJeZdZdZedZedZedZedZedZ ddZ d d d Z d S)rKz+Returns a unicode pluralization rule again.z%s is %sz %s is not %sz %s and %sz%s or %sz %s mod %scCs|j|dddiS)NrrT)r)r9rr r rrksz_UnicodeCompiler.compile_notFcCsvg}|dD]"}|d|dkr|||dq|dtt|j|qd|||r2dp3d|d|fS)Nrrz%s..%sz %s%s %s %sz notr r)r8rLrrr)r9rr=rrrangesrr r rrns  z!_UnicodeCompiler.compile_relationN)F) rDr[r\r]rrrrrrrrr r r rrK^srKr )&r]re babel._compatrr3rcr*objectr+rgrYr|rnrorp ExceptionrrrLUNICODEformatrrrrrrrrr6rrrrrqryrbrKr r r rsN 8](    {