ƪbQV PdZddlZddlZdZdZdZGddZdZd Zd Z d Z d Z d Z Gdde ZhdZdej dej"fdej ddj%edfdej dfdej dfdej dej"fgZdZd2dZd2dZdZd Zd!Zd"ZGd#d$Zd%Zd&Zd'ZGd(d)ZGd*d+eZ Gd,d-eZ!Gd.d/e!Z"Gd0d1eZ#y)3z babel.numbers ~~~~~~~~~~~~~ CLDR Plural support. See UTS #35. :copyright: (c) 2013-2022 by the Babel Team. :license: BSD, see LICENSE for more details. N)zeroonetwofewmanyotherrct|}t|}t|tr&||k(r|}nt j t |}t|tj r|j}|j}|dkr|j|dnd}djd|D}|jd}t|}t|} t|xsd} t|xsd} ndx}x} x} } dx} } |||| | | | | fS)uExtract operands from a decimal, a float or an int, according to `CLDR rules`_. The result is a 8-tuple (n, i, v, w, f, t, c, e), 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. 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-61/tr35-numbers.html#Operands :param source: A real number :type source: int|float|decimal.Decimal :return: A n-i-v-w-f-t-c-e tuple :rtype: tuple[decimal.Decimal, int, int, int, int, int, int, int] rNc32K|]}t|ywNstr).0ds ./usr/lib/python3/dist-packages/babel/plural.py z#extract_operands..As;a3q6;s0) absint isinstancefloatdecimalDecimalras_tupleexponentdigitsjoinrstriplen)sourceni dec_tupleexpfraction_digitstrailing no_trailingvwftces rextract_operandsr/s2 F A AA!U 6AA'A!W__%JJL   47!G)**34077;?;;ooc* M    A    q !AA IA aAq!Q !!cheZdZdZdZdZdZedZe dZ e dd Z d Z d Z d Zy ) 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_funcczt|tr|j}t}g|_t t |D]s\}}|tvrtd|z||vrtd|z|j|t|j}|sW|jj||fuy)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) rdictitemssetr3sortedlist _plural_tags ValueErroradd_Parserastappend)selfrulesfoundkeyexprr?s r__init__zPluralRule.__init__ds eT "KKME U , 1IC,& !1C!788 !7#!=>> IIcN$-##C $$c3Z0 1r0c |j}dt|jddjtDcgc]}||vr |d||c}dScc}w)N< , z: >)rBtype__name__rr;)rArBtags r__repr__zPluralRule.__repr__zsW  J   II|(,$'c 3( )  (sAc.t||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)clsrBs rparsezPluralRule.parses eS !L5zr0ctj}|jDcic]\}}|||c}}Scc}}w)zThe `PluralRule` as a dict of unicode plural rules. >>> rule = PluralRule({'one': 'n is 1'}) >>> rule.rules {'one': 'n is 1'} )_UnicodeCompilercompiler3)rA_compilerNr?s rrBzPluralRule.ruless7$%--37==AxsCXc]"AAAs;c:td|jDS)Nc3&K|] }|d yw)rNr )rr#s rrz&PluralRule...s'A!'As) frozensetr3xs rzPluralRule.si'Aajj'AAr0z 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.)docc|jSr r3rAs r __getstate__zPluralRule.__getstate__s }}r0c||_yr r_)rAr3s r __setstate__zPluralRule.__setstate__s   r0c\t|dst||_|j|S)Nr4)hasattr to_pythonr4)rAr"s r__call__zPluralRule.__call__s%tW%"4DJzz!}r0N)rM __module__ __qualname____doc__ __slots__rFrO classmethodrRpropertyrBtagsrarcrgr r0rr2r2Msf(&I1,   BB AH D !r0r2c tj}dg}tj|jD]"\}}|j ||d|d$|j dt zdj|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 ? z : z%r; })r )_JavaScriptCompilerrUr2rRr3r@ _fallback_tagr)ruleto_jsresultrNr?s r to_javascriptrusr ! ) )E& 'F$$T*338S eCj#678 MM(]*+ 776?r0c ttttd}t j }ddg}t j|jD]+\}}|jd||dt|-|jdtzt dj|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, c, e = extract_operands(n)z if (z ): return z return %r zexecevaluate) in_range_listwithin_range_list cldr_modulor/_PythonCompilerrUr2rRr3r@rrqreval)rr namespaceto_python_funcrtrNr?codes rrfrfs(#, I %&..N7F$$T*33OS  ~c/BCHMNO MM,./ 499V$h 7Dy Z  r0ctj|}|jthz}t j }t Dcgc] }||vs| c}j}dt|zg}|jD]'\}}|jd||||fz)|jd|tzdj|Scc}w)aThe 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 znplurals=%d; plural=(z %s ? %d : z%d);r ) r2rRrnrq_GettextCompilerrUr;indexr r3r@r)rr used_tagsrVrN _get_indexrtr?s r to_gettextrs   D !D ]O+I!))H!-B# 1A#BHHJ%I6 7FMMGS lhsmZ_%EEFG MM&:m445 776? Cs  CCc:|t|k(xr 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 )rr~num range_lists rr}r}s" #c(? A0jAAr0c,tfd|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 c3<K|]\}}|k\xr|kywr r )rmin_max_rs rrz$within_range_list..%s%HztTsd{*sd{*Hs)anyrs` rr~r~s" HZH HHr0cNd}|dkr|dz}d}|dkr|dz}||z}|r|dz}|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 )abreverservs rrr(sHG1u R1u R QB b Ir0ceZdZdZy) RuleErrorzRaised if a rule is malformed.N)rMrhrirjr r0rrr?s(r0r>r-r.r+r#r"r,r)r*z\s+wordz"\b(and|or|is|(?:with)?in|not|mod|[r z])\bvaluez\d+symbolz%|,|!=|=ellipsisz\.{2,3}|\u2026c>|jdd}g}d}t|}||krntD]N\}}|j||}||j }|r!|j ||j fntd||z||krn|dddS)N@rz5malformed CLDR pluralization rule. Got unexpected %rr)splitr _RULESmatchendr@groupr)srtposrtokrrrs r tokenize_rulerVs  QA F C a&C ) :ICJJq#&E iikMM3 "67 :023C&9: : ) $B$<r0cF|xr|dd|k(xr|duxs |dd|k(S)Nrrrr tokenstype_rs rtest_next_tokenris<  2fRjmu, 2 $ 0&*Q-502r0c>t|||r|jSyr )rpoprs r skip_tokenrnsvue,zz|-r0c d|ffS)Nrr )rs r value_noderss UI r0c |dfS)Nr r )names r ident_noderws 8Or0c d|fS)Nrr )rs rrange_list_noder{s  ##r0c d|ffS)Nnotr )rs rnegaters 2%<r0cNeZdZdZdZd dZdZdZdZdZ d Z d Z d Z d Z y)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`. ct||_|jsd|_y|j|_|jrt d|jddzy)NzExpected end of rule, got %rrr)rrr? conditionr)rAstrings rrFz_Parser.__init__s`#F+ {{DH >># ;;: KKOA./0 0 r0Nct|j||}||S|t|duxr|xs|}|jstd|ztd|d|jdd)Nz#expected %s but end of rule reachedz expected z but got rr)rrreprr)rArrtermtokens rexpectz_Parser.expectsq4;;u5  L < /%859D{{ADHI ID$++b/!:LMNNr0c|j}t|jddr,d||jff}t|jddr,|S)Nror) and_conditionrrrAops rrz_Parser.conditionsO    !fd3D..011Bfd3 r0c|j}t|jddr,d||jff}t|jddr,|S)Nrand)relationrrrs rrz_Parser.and_conditionsI ]]_fe4T]]_--Bfe4 r0c|j}t|jddr1t|jddxrdxsd||jffSt|jdd}d}t|jddrd}n5t|jdds|r t d|j |Sd|||j ff}|r t|S|S) Nrisrisnotinwithinz#Cannot negate operator based rules.r)rErrrrnewfangled_relationrr)rAleftnegatedmethodrs rrz_Parser.relationsyy{ dkk64 0dkk659EgMtzz|$% %T[[&%8 dkk68 4Fdkk648#$IJJ//55 &$(9: :$vbz,",r0ct|jddrd}n%t|jddrd}n tddd||jff}|r t |S|S) Nr=Fz!=Tz'Expected "=" or "!=" or legacy relationrr)rrrrr)rArrrs rrz_Parser.newfangled_relationsa dkk8S 1G  Xt 4GEF F $doo&78 8$vbz,",r0cz|j}t|jdr||jfS||fS)Nr)rrr)rArs rrange_or_valuez_Parser.range_or_values6zz| dkk: .% %: r0c|jg}t|jddr7|j|jt|jddr7t |S)Nr,)rrrr@r)rArs rrz_Parser.range_listsW))+, h4   d113 4h4z**r0c2t|jd}| |dtvr td|d}t|jddrd|df|j ffSt|jddrd|df|j ffSt |S)NrrzExpected identifier variablemodr r%)rr_VARSrrr)rArrs rrEz _Parser.exprs$++v. <47%/:; ;Aw dkk65 1D":tzz|44 4  Xs 3D":tzz|44 4$r0cNtt|jddS)Nrr)rrrr`s rrz _Parser.values #dkk'215677r0)NN)rMrhrirjrFrrrrrrrrErr r0rr>r>s;B 0O  -"-+  8r0r>cfdS)%Compiler factory for the `_Compiler`.cN|j||j|fzSr rU)rAlrtmpls rr\z"_binary_compiler..s!ddll1ot||A%GGr0r rs`r_binary_compilerrs GGr0cfdS)rc,|j|zSr r)rAr[rs rr\z!_unary_compiler..s4$,,q/1r0r rs`r_unary_compilerrs 11r0cy)Nrr rZs rr\r\r0ceZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z ed Zed ZedZedZedZedZdZy) _CompilerzZThe compilers are able to transform the expressions into multiple output formats. c0|\}}t|d|z|S)Ncompile_)getattr)rAargrargss rrUz_Compiler.compiles#D-wtZ"_-t44r0cy)Nr"r rZs rr\z_Compiler.rr0cy)Nr#r rZs rr\z_Compiler.rr0cy)Nr)r rZs rr\z_Compiler.rr0cy)Nr*r rZs rr\z_Compiler.rr0cy)Nr+r rZs rr\z_Compiler.rr0cy)Nr,r rZs rr\z_Compiler.rr0cy)Nr-r rZs rr\z_Compiler.rr0cy)Nr.r rZs rr\z_Compiler.rr0ct|Sr r)r[r)s rr\z_Compiler.s Qr0z (%s && %s)z (%s || %s)z(!%s)z (%s %% %s)z (%s == %s)z (%s != %s)ctr )NotImplementedError)rArrErs rcompile_relationz_Compiler.compile_relation$s !##r0N)rMrhrirjrU compile_n compile_i compile_v compile_w compile_f compile_t compile_c compile_e compile_valuer compile_and compile_orr compile_not compile_mod compile_is compile_isnotrr r0rrr s|5IIIIIIII'M"<0K!,/J!'*K"<0K!,/J$\2M$r0rcVeZdZdZedZedZedZedZ dZ y)rz!Compiles an expression to Python.z (%s and %s)z (%s or %s)z(not %s)z MOD(%s, %s)c ddj|dDcgc]$}dtt|j|z&c}z}|j d|j|d|dScc}w)Nz[%s]rrz(%s, %s)(rJ))rtuplemaprUupper)rArrErrange_compile_range_lists rrz _PythonCompiler.compile_relation0so#chh%a= *%DLL& 9: : *'++ &||~t||D/A13 3 *s)A. N) rMrhrirjrr rrrrrr r0rrr(s2+"=1K!,/J!*-K"=1K3r0rc>eZdZdZej ZeZeZ eZ eZ dZ y)rz)Compile into a gettext plural expression.c >g}|j|}|dD]o}|d|dk(r+|jd|d|j|dd9t|j|\}}|jd|d|d|d|d qd d j|zS) Nrrrz == rz >=  && z <= z(%s)z || )rUr@rr)rArrErritemminmaxs rrz!_GettextCompiler.compile_relationAs ||D!qM DAw$q'! LLa) t||T2S    B''r0N) rMrhrirjrrr compile_zerorrrr rr r0rrr8s)3##IIIII(r0rc,eZdZdZdZeZeZeZeZ dZ y)rpz/Compiles the expression to plain of JavaScript.cy)NzparseInt(n, 10)r rZs rr\z_JavaScriptCompiler.Zrr0cztj||||}|dk(r|j|}d|d|d|d}|S)Nrz (parseInt(z , 10) == rr)rrrU)rArrErrs rrz$_JavaScriptCompiler.compile_relation`sA00 &$ , T><<%D7;T4HD r0N) rMrhrirjrr"rrrr rr r0rrprpUs%9,IIIIIr0rpcneZdZdZedZedZedZedZedZ dZ d dZ y ) rTz+Returns a unicode pluralization rule again.z%s is %sz %s is not %sz %s and %sz%s or %sz %s mod %sc,|j|dddiS)NrrT)r)rArs rrz_UnicodeCompiler.compile_notvs$t$$HQK@T@@r0c >g}|dD]b}|d|dk(r$|j|j|d2|jdtt|j|zd|j||xrdxsdd|ddj |S)Nrrz%s..%sz notr rIr)r@rUrrr)rArrErrrangesrs rrz!_UnicodeCompiler.compile_relationysqM IDAw$q'! dll4734 hs4<</F)GGH  I LL  2F 8b 8 CHHV$  r0N)F) rMrhrirjrrrr rrrrr r0rrTrTisD5 "*-J$^4M";/K!*-J";/KA  r0rTr )$rjrrer;rqr/r2rurfrr}r~r ExceptionrrrUUNICODErrrrrrrrrr>rrr"rrrrprTr r0rr-sj >  8"vZZz.%!P.B(I(.) )  :2::fbjj )* ZRZZ=bggen=MTR ST jbjj ! zrzz+&'-rzz:;  &2  $x8x8vH 2  $$: 3i 3 (y(:*( y r0