dbfdg 3 HX@S@sdZddlZddlmZdFZd Zd d ZGd d d eZddZ ddZ ddZ ddZ ddZ ddZGdddeZdZdejdejfdejdjefd ejd!fd"ejd#fd$ejd%ejfgZd&d'ZdGd(d)ZdHd*d+Zd,d-Zd.d/Zd0d1Zd2d3ZGd4d5d5eZd6d7Zd8d9Zd:d;Z Gdd?d?e!Z"Gd@dAdAe!Z#GdBdCdCe#Z$GdDdEdEe!Z%dS)Iz babel.numbers ~~~~~~~~~~~~~ CLDR Plural support. See UTS #35. :copyright: (c) 2013 by the Babel Team. :license: BSD, see LICENSE for more details. N)decimalzeroonetwofewmanyotherc Cst|}t|}t|tr6||kr(|}ntjt|}t|tjr|j}|j}|dkrf|j |dnf}dj dd|D}|j d}t |}t |} t|pd} t|pd} 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`: http://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|VqdS)N)str).0dr /usr/lib/python3.6/plural.py Asz#extract_operands..0) absint isinstancefloatrZDecimalr Zas_tupleZexponentZdigitsjoinrstriplen) sourceniZ dec_tupleZexpZfraction_digitsZtrailingZ no_trailingvwftr r rextract_operandss$     rc@sdeZdZdZdZddZddZedd Ze d d Z e d d ddZ ddZ ddZ ddZdS) PluralRuleaeRepresents 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`: http://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#Language_Plural_Rules abstract_funccCst|tr|j}t}g|_xjtt|D]Z\}}|tkrJtd|n||kr^td||j |t |j }|r,|jj ||fq,WdS)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)selfrulesfoundkeyexprr,r r r__init__cs    zPluralRule.__init__cs,|jdt|jdjfddtDfS)Nz<%s %r>z, cs$g|]}|krd||fqS)z%s: %sr )r tag)r/r r }sz'PluralRule.__repr__..)r/type__name__rr()r.r )r/r__repr__yszPluralRule.__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 )r r4r,)_compiler rr5sz$PluralRule.rules..)_UnicodeCompilercompiler#r!)r.r )r;rr/szPluralRule.rulescCstdd|jDS)NcSsg|] }|dqS)rr )r rr r rr5sz'PluralRule...) frozensetr!)xr r rszPluralRule.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|jS)N)r!)r.r r r __getstate__szPluralRule.__getstate__cCs ||_dS)N)r!)r.r!r r r __setstate__szPluralRule.__setstate__cCst|dst||_|j|S)Nr")hasattr to_pythonr")r.rr r r__call__s  zPluralRule.__call__N)r!r")r7 __module__ __qualname____doc__ __slots__r3r8 classmethodr:propertyr/tagsrBrCrFr r r rr Ls r cCsVtj}dg}x.tj|jD]\}}|jd|||fqW|jdtdj|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 )_JavaScriptCompilerr=r r:r!r- _fallback_tagr)ruleZto_jsresultr4r,r r r to_javascripts rRcCsttttd}tj}ddg}x2tj|jD]"\}}|j d||t |fq,W|j dt tdj |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 )INZWITHINZMODrzdef evaluate(n):z' n, i, v, w, f, t = extract_operands(n)z if (%s): return %rz return %r zexecZevaluate) in_range_listwithin_range_list cldr_modulor_PythonCompilerr=r r:r!r-r rOreval)rP namespaceZto_python_funcrQr4r,coder r rrEs rEcstj|}|jttgBtj}fddtDj}dt g}x,|j D]"\}}|j d||||fqLW|j d|tdj |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|]}|kr|qSr r )r r4) used_tagsr rr5szto_gettext..znplurals=%d; plural=(z %s ? %d : z%d)r ) r r:rMr%rO_GettextCompilerr=r(indexrr!r-r)rPr;Z _get_indexrQr4r,r )r]r to_gettexts r`cCs|t|kot||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 )rrW)num range_listr r rrVsrVcstfdd|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|kVqdS)Nr )r Zmin_Zmax_)rar rr$sz$within_range_list..)any)rarbr )rarrWsrWcCs@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 rrerer )abreverservr r rrX's rXc@seZdZdZdS) RuleErrorzRaised if a rule is malformed.N)r7rGrHrIr r r rrj>srjZnivwftz\s+wordz)\b(and|or|is|(?:with)?in|not|mod|[{0}])\bvaluez\d+symbolz%|,|!=|=ellipsisz\.{2,3}|\u2026cCs|jdd}g}d}t|}xb||krxTtD]<\}}|j||}|dk r.|j}|rh|j||jfPq.Wtd||q W|dddS)N@rz5malformed CLDR pluralization rule. Got unexpected %rrdre)splitr_RULESmatchendr-grouprj)srQposrstokrPrrr r r tokenize_ruleMs  rxcCs,|o*|dd|ko*|dkp*|dd|kS)Nrdrrerer )tokenstype_rlr r rtest_next_token`sr{cCst|||r|jSdS)N)r{pop)ryrzrlr r r skip_tokenes r}cCs d|ffS)Nrlr )rlr r r value_nodejsr~cCs|ffS)Nr )namer r r ident_nodensrcCsd|fS)Nrbr )rbr r rrange_list_nodersrcCs d|ffS)Nnotr )rir r rnegatevsrc@sbeZdZdZddZdddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ dS)r+uInternal 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||_|jsd|_dS|j|_|jr@td|jdddS)NzExpected end of rule, got %rrdre)rxryr, conditionrj)r.stringr r rr3s  z_Parser.__init__NcCsft|j||}|dk r|S|dkr6t|dkr0|p2|}|jsHtd|td||jddfdS)Nz#expected %s but end of rule reachedzexpected %s but got %rrdre)r}ryreprrj)r.rzrlZtermtokenr r rexpects z_Parser.expectcCs0|j}x"t|jddr*d||jff}q W|S)Nrkor) and_conditionr}ry)r.opr r rrsz_Parser.conditioncCs0|j}x"t|jddr*d||jff}q W|S)Nrkand)relationr}ry)r.rr r rrsz_Parser.and_conditioncCs|j}t|jddr8t|jddr(dp*d||jffSt|jdd}d}t|jddr^d}n$t|jdds|rxtd|j|Sd|||jff}|rt|S|S) NrkisrZisnotinZwithinz#Cannot negate operator based rules.r)r2r}ryrlrjnewfangled_relationrbr)r.leftnegatedmethodrir r rrs z_Parser.relationcCsRt|jddrd}nt|jddr(d}ntddd||jff}|rNt|S|S) Nrm=Fz!=Tz'Expected "=" or "!=" or legacy relationrr)r}ryrjrbr)r.rrrir r rrsz_Parser.newfangled_relationcCs,|j}t|jdr ||jfS||fSdS)Nrn)rlr}ry)r.rr r rrange_or_values  z_Parser.range_or_valuecCs4|jg}x t|jddr*|j|jq Wt|S)Nrm,)rr}ryr-r)r.rbr r rrbs z_Parser.range_listcCs|t|jd}|dks |dtkr(td|d}t|jddrRd|ff|jffSt|jddrtd|ff|jffSt|S)NrkrdzExpected identifier variablemodrm%)r}ry_VARSrjrlr)r.rkrr r rr2s z _Parser.exprcCstt|jddS)Nrlrd)r~rr)r.r r rrlsz _Parser.value)NN)r7rGrHrIr3rrrrrrrbr2rlr r r rr+zs    r+cs fddS)z%Compiler factory for the `_Compiler`.cs|j||j|fS)N)r=)r.lr)tmplr rr@sz"_binary_compiler..r )rr )rr_binary_compilersrcs fddS)z%Compiler factory for the `_Compiler`.cs|j|S)N)r=)r.r?)rr rr@sz!_unary_compiler..r )rr )rr_unary_compilersrcCsdS)Nrr )r?r r rr@sr@c@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)NZcompile_)getattr)r.argrargsr r rr=sz_Compiler.compilecCsdS)Nrr )r?r r rr@ sz_Compiler.cCsdS)Nrr )r?r r rr@ scCsdS)Nrr )r?r r rr@ scCsdS)Nrr )r?r r rr@scCsdS)Nrr )r?r r rr@scCsdS)Nrr )r?r r rr@scCst|S)N)r )r?rr r rr@sz (%s && %s)z (%s || %s)z(!%s)z (%s %% %s)z (%s == %s)z (%s != %s)cCs tdS)N)NotImplementedError)r.rr2rbr r rcompile_relationsz_Compiler.compile_relationN)r7rGrHrIr= compile_n compile_i compile_v compile_w compile_f compile_tZ compile_valuer compile_and compile_orr compile_not compile_mod compile_is compile_isnotrr r r rrs rc@s8eZdZdZedZedZedZedZ ddZ dS) rYz!Compiles an expression to Python.z (%s and %s)z (%s or %s)z(not %s)z MOD(%s, %s)cs8ddjfdd|dD}d|jj||fS)Nz[%s]rcs g|]}dttj|qS)z(%s, %s))tuplemapr=)r Zrange_)r.r rr5'sz4_PythonCompiler.compile_relation..rdz %s(%s, %s))rupperr=)r.rr2rbZcompile_range_listr )r.rr%s  z _PythonCompiler.compile_relationN) r7rGrHrIrrrrrrrr r r rrYs rYc@s.eZdZdZejZeZeZ eZ eZ ddZ dS)r^z)Compile into a gettext plural expression.cCsg}|j|}xd|dD]X}|d|dkrJ|jd||j|dfqt|j|\}}|jd||||fqWddj|S)Nrdrz (%s == %s)z(%s >= %s && %s <= %s)z(%s)z || )r=r-rr)r.rr2rbriitemminmaxr r rr6s z!_GettextCompiler.compile_relationN) r7rGrHrIrrr compile_zerorrrrrr r r rr^-sr^c@s0eZdZdZddZeZeZeZeZ ddZ dS)rNz/Compiles the expression to plain of JavaScript.cCsdS)NzparseInt(n, 10)r )r?r r rr@Osz_JavaScriptCompiler.cCs4tj||||}|dkr0|j|}d|||f}|S)Nrz(parseInt(%s, 10) == %s && %s))r^rr=)r.rr2rbr\r r rrUs   z$_JavaScriptCompiler.compile_relationN) r7rGrHrIrrrrrrrr r r rrNJsrNc@sJeZdZdZedZedZedZedZedZ ddZ d d d Z d S)r<z+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)NrdrT)r)r.rr r rrksz_UnicodeCompiler.compile_notFcCszg}xP|dD]D}|d|dkr8|j|j|dq|jdtt|j|qWd|j||rhdpjd|dj|fS)Nrdrz%s..%sz %s%s %s %sz notr r)r-r=rrr)r.rr2rbrZrangesrr r rrnsz!_UnicodeCompiler.compile_relationN)F) r7rGrHrIrrrrrrrrr r r rr<^sr<)rrrrrr)N)N)&rIreZ babel._compatrr(rOrobjectr rRrEr`rVrWrX Exceptionrjrr=UNICODEformatrqrxr{r}r~rrrr+rrrrrYr^rNr<r r r r sH 8](     {