ó AÒðQc@sdZddlZd!ZdZd efd „ƒYZd „Zd „Zd „Zd„Z d„Z d„Z de fd„ƒYZ defd„ƒYZd„Zd„Zdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd „ƒYZdS("s« babel.numbers ~~~~~~~~~~~~~ CLDR Plural support. See UTS #35. :copyright: (c) 2013 by the Babel Team. :license: BSD, see LICENSE for more details. iÿÿÿÿNtzerotonettwotfewtmanytothert PluralRulecBsteZdZd Zd„Zd„Zed„ƒZed„ƒZ ed„dd ƒZ d „Z d „Z d „Z RS(s÷Represents 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. tabstractt_funccCsÁt|tƒr|jƒ}ntƒ}g|_xŠtt|ƒƒD]v\}}|tkrntd|ƒ‚n||krtd|ƒ‚n|j |ƒ|jj |t |ƒj fƒqCWdS(s$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 sunknown tag %rstag %r defined twiceN( t isinstancetdicttitemstsetRtsortedtlistt _plural_tagst ValueErrortaddtappendt_Parsertast(tselftrulestfoundtkeytexpr((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt__init__(s     c CsV|j}dt|ƒjdjgtD]&}||kr%d|||f^q%ƒfS(Ns<%s %r>s, s%s: %s(Rttypet__name__tjoinR(RRttag((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt__repr__<s   cCst||ƒr|S||ƒS(s 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 (tclsR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pytparseDscCs>tƒj}tg|jD]\}}|||ƒf^qƒS(sŸThe `PluralRule` as a dict of unicode plural rules. >>> rule = PluralRule({'one': 'n is 1'}) >>> rule.rules {'one': 'n is 1'} (t_UnicodeCompilertcompileR R(Rt_compileRR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRPs cCs$tg|jD]}|d^q ƒS(Ni(t frozensetR(txti((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt[stdocs° 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.cCs|jS(N(R(R((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt __getstate__`scCs ||_dS(N(R(RR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt __setstate__cscCs.t|dƒs!t|ƒ|_n|j|ƒS(NR(thasattrt to_pythonR(Rtn((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt__call__fs(sabstracts_func(Rt __module__t__doc__t __slots__RRt classmethodR!tpropertyRttagsR*R+R/(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRs       cCsstƒj}dg}x=tj|ƒjD])\}}|jd||ƒ|fƒq(W|jdtƒdj|ƒS(s‚Convert 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 s(function(n) { return s %s ? %r : s%r; })t(t_JavaScriptCompilerR#RR!RRt _fallback_tagR(truletto_jstresultRR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt to_javascriptls   !cCs·itd6td6td6}tƒj}dg}xCtj|ƒjD]/\}}|jd||ƒt |ƒfƒqCW|jdt ƒtdj |ƒdd ƒ}t ||ƒ|d S( s<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 tINtWITHINtMODsdef evaluate(n):s if (%s): return %rs return %rs stexectevaluate( t in_range_listtwithin_range_listt cldr_modulot_PythonCompilerR#RR!RRtstrR8Rteval(R9t namespaceR-R;RRtcode((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR-ƒs   ' cCsÍtj|ƒ}|jttgƒB}tƒj}gtD]}||kr8|^q8j}dt |ƒg}x:|j D]/\}}|j d||ƒ||ƒfƒqvW|j d|tƒƒdj |ƒS(s~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 snplurals=%d; plural=(s %s ? %d : s%d)R6( RR!R5R R8t_GettextCompilerR#RtindextlenRRR(R9t used_tagsR$Rt _get_indexR;R((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt to_gettext§s  ('cCs|t|ƒkot||ƒS(s™Integer 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 (tintRC(tnumt range_list((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRB¾scst‡fd†|DƒƒS(s¶Float 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(N((t.0tmin_tmax_(RQ(s6/usr/local/lib/python2.7/site-packages/babel/plural.pys ãs(tany(RQRR((RQs6/usr/local/lib/python2.7/site-packages/babel/plural.pyRCÒscCs_d}|dkr%|d9}d}n|dkr>|d9}n||}|r[|d9}n|S(sîJavaish 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 iiÿÿÿÿi((tatbtreversetrv((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRDæs        t RuleErrorcBseZdZRS(sRaised if a rule is malformed.(RR0R1(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR[ýsRcBsÝeZdZdejdƒfdejdƒfdejdƒfdejdƒfdejd ƒfgZd „Zdd „Zdd „Z ddd „Z d„Z d„Z d„Z d„Zd„Zd„Zd„ZRS(s…Internal 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)* and_condition = relation ('and' relation)* relation = is_relation | in_relation | within_relation | 'n' is_relation = expr 'is' ('not')? value in_relation = expr ('not')? 'in' range_list within_relation = expr ('not')? 'within' range_list expr = 'n' ('mod' value)? range_list = (range | value) (',' range_list)* value = digit+ digit = 0|1|2|3|4|5|6|7|8|9 range = 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'. The translator parses the expression on instanciation into an attribute called `ast`. s\s+(?u)twords%\b(and|or|is|(?:with)?in|not|mod|n)\btvalues\d+tcommat,tellipsiss\.\.cCs|jƒ}g}d}t|ƒ}xŽ||kr´x{|jD]\\}}|j||ƒ}|dk r=|jƒ}|r•|j||jƒfƒnPq=q=Wtd||ƒ‚q'W|ddd…|_ |j ƒ|_ |j rtd|j ddƒ‚ndS(Nis5malformed CLDR pluralization rule. Got unexpected %riÿÿÿÿsExpected end of rule, got %ri( tlowerRLt_rulestmatchtNonetendRtgroupR[ttokenst conditionR(RtstringR;tposRettokR9Rc((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR$s&     cCsA|jo@|jdd|ko@|dkp@|jdd|kS(Niÿÿÿÿii(RgRd(RRR]((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyttest;s cCs#|j||ƒr|jjƒSdS(N(RlRgtpop(RRR]((s6/usr/local/lib/python2.7/site-packages/babel/plural.pytskip?scCs|j||ƒ}|dk r"|S|dkrOt|dkrC|pF|ƒ}n|jsktd|ƒ‚ntd||jddfƒ‚dS(Ns#expected %s but end of rule reachedsexpected %s but got %riÿÿÿÿi(RnRdtreprRgR[(RRR]ttermttoken((s6/usr/local/lib/python2.7/site-packages/babel/plural.pytexpectCs  ! cCsA|jƒ}x.|jddƒr<d||jƒff}qW|S(NR\tor(t and_conditionRn(Rtop((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRhMs cCsA|jƒ}x.|jddƒr<d||jƒff}qW|S(NR\tand(trelationRn(RRu((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRtSs cCsÌ|jƒ}|jddƒrL|jddƒr6dp9d||jƒffS|jddƒ}d}|jddƒrd}n|jddddƒd |||jƒff}|rÈd|ff}n|S( NR\tistnottisnottintwithinRps'within' or 'in'Rw(RRnR]RrRR(RtlefttnegatedtmethodRZ((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRwYs  cCs9|jƒ}|jdƒr+||jƒfS||fSdS(NR`(R]Rn(RR}((s6/usr/local/lib/python2.7/site-packages/babel/plural.pytrange_or_valueis cCsB|jƒg}x&|jdƒr7|j|jƒƒqWd|fS(NR^RR(R€RnR(RRR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRRpscCsH|jddƒ|jddƒr>dddf|jƒffSddfS(NR\R.tmod(((RrRnR](R((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRvscCs dt|jdƒdƒffS(NR]i(RPRr(R((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR]|sN(RR0R1RdtreR#RbRRlRnRrRhRtRwR€RRRR](((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRs"         cs ‡fd†S(s%Compiler factory for the `_Compiler`.cs ˆ|j|ƒ|j|ƒfS(N(R#(Rtltr(ttmpl(s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR(‚s((R…((R…s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt_binary_compiler€scs ‡fd†S(s%Compiler factory for the `_Compiler`.csˆ|j|ƒS(N(R#(RR&(R…(s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR(‡s((R…((R…s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt_unary_compiler…st _CompilercBszeZdZd„Zd„Zd„ZedƒZedƒZe dƒZ edƒZ edƒZ ed ƒZ d „ZRS( sZThe compilers are able to transform the expressions into multiple output formats. cCs#|\}}t|d|ƒ|ŒS(Ntcompile_(tgetattr(RtargRutargs((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR#s cCsdS(NR.((R&((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR(“scCs t|ƒS(N(RF(R&tv((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR(”ss (%s && %s)s (%s || %s)s(!%s)s (%s %% %s)s (%s == %s)s (%s != %s)cCs tƒ‚dS(N(tNotImplementedError(RRRRR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pytcompile_relationœs(RR0R1R#t compile_nt compile_valueR†t compile_andt compile_orR‡t compile_nott compile_modt compile_ist compile_isnotR(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRˆŠs         REcBsGeZdZedƒZedƒZedƒZedƒZd„Z RS(s!Compiles an expression to Python.s (%s and %s)s (%s or %s)s(not %s)s MOD(%s, %s)c Cs`ddjg|dD]"}dtt|j|ƒƒ^qƒ}d|jƒ|j|ƒ|fS(Ns[%s]R_is(%s, %s)s %s(%s, %s)(RttupletmapR#tupper(RRRRRtrange_tcompile_range_list((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR¨s  4( RR0R1R†R’R“R‡R”R•R(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRE s     RJcBseZdZd„ZRS(s)Compile into a gettext plural expression.cCs«g}|j|ƒ}x‚|dD]v}|d|dkra|jd||j|dƒfƒq t|j|ƒ\}}|jd||||fƒq Wddj|ƒS(Niis (%s == %s)s(%s >= %s && %s <= %s)s(%s)s || (R#RR™R(RRRRRRZtitemtmintmax((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR³s  (RR0R1R(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRJ°sR7cBseZdZd„ZRS(s/Compiles the expression to plain of JavaScript.cCsMtj||||ƒ}|dkrI|j|ƒ}d|||f}n|S(NR{s(parseInt(%s) == %s && %s)(RJRR#(RRRRRRI((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRÊs  (RR0R1R(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR7ÇsR"cBs_eZdZedƒZedƒZedƒZedƒZedƒZd„Z e d„Z RS(s+Returns a unicode pluralization rule again.s%s is %ss %s is not %ss %s and %ss%s or %ss %s mod %scCs|jdt|dŒS(NR~i(RtTrue(RRw((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR”ÜscCs¡g}xf|dD]Z}|d|dkrH|j|j|dƒƒq|jdtt|j|ƒƒƒqWd|j|ƒ|rŠdpd|dj|ƒfS(Niis%s..%ss %s%s %s %ss notR6R_(RR#R˜R™R(RRRRRR~trangesR((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyRßs'( RR0R1R†R–R—R’R“R•R”tFalseR(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyR"Ós      (RRRRRsother(R1R‚RR8tobjectRR<R-RORBRCRDt ExceptionR[RR†R‡RˆRERJR7R"(((s6/usr/local/lib/python2.7/site-packages/babel/plural.pyt s& Y  $