annotate babel/plural.py @ 392:2e77d72516d7

Fixed not in plural rules
author aronacher
date Tue, 15 Jul 2008 10:13:55 +0000
parents 3eb859adc5de
children d85b5a78ee9c
rev   line source
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
1 # -*- coding: utf-8 -*-
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
2 #
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
3 # Copyright (C) 2008 Edgewall Software
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
4 # All rights reserved.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
5 #
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
8 # are also available at http://babel.edgewall.org/wiki/License.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
9 #
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
12 # history and logs, available at http://babel.edgewall.org/log/.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
13
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
14 """CLDR Plural support. See UTS #35. EXPERIMENTAL"""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
15
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
16 import re
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
17 try:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
18 set
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
19 except NameError:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
20 from sets import ImmutableSet as frozenset, Set as set
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
21
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
22
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
23 _plural_tags = ('zero', 'one', 'two', 'few', 'many', 'other')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
24 _fallback_tag = 'other'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
25
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
26
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
27 class PluralRule(object):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
28 """Represents a CLDR language pluralization rules. The constructors
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
29 accepts a list of (tag, expr) tuples or a dict of CLDR rules.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
30 The resulting object is callable and accepts one parameter with a
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
31 positive or negative number (both integer and float) for the number
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
32 that indicates the plural form for a string and returns the tag for
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
33 the format:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
34
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
35 >>> rule = PluralRule({'one': 'n is 1'})
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
36 >>> rule(1)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
37 'one'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
38 >>> rule(2)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
39 'other'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
40
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
41 Currently the CLDR defines these tags: zero, one, two, few, many and
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
42 other where other is an implicit default. Rules should be mutually
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
43 exclusive; for a given numeric value, only one rule should apply (i.e.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
44 the condition should only be true for one of the plural rule elements.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
45
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
46 :param rules: a list of ``(tag, expr)``) tuples with the rules conforming
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
47 to UTS #35 or a dict with the tags as keys and expressions
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
48 as values.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
49 :raise: a `RuleError` if the expression is malformed
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
50 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
51
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
52 __slots__ = ('abstract', '_func')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
53
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
54 def __init__(self, rules):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
55 if isinstance(rules, dict):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
56 rules = rules.items()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
57 found = set()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
58 self.abstract = []
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
59 for key, expr in rules:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
60 if key not in _plural_tags:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
61 raise ValueError('unknown tag %r' % key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
62 elif key in found:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
63 raise ValueError('tag %r defined twice' % key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
64 found.add(key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
65 self.abstract.append((key, _Parser(expr).ast))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
66
390
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
67 def __repr__(self):
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
68 return '<%s %r>' % (type(self).__name__, self.abstract)
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
69
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
70 def parse(cls, rules):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
71 """Create a `PluralRule` instance for the given rules. If the rules
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
72 are a `PluralRule` object, that object is returned.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
73
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
74 :param rules: the rules as list or dict, or a `PluralRule` object
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
75 :return: a corresponding `PluralRule` object
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
76 :raise: a `RuleError` if the expression is malformed
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
77 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
78 if isinstance(rules, cls):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
79 return rules
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
80 return cls(rules)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
81 parse = classmethod(parse)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
82
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
83 def rules(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
84 """The `PluralRule` as a dict of unicode plural rules."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
85 _compile = _UnicodeCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
86 return dict([(tag, _compile(ast)) for tag, ast in self.abstract])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
87 rules = property(rules, doc=rules.__doc__)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
88
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
89 def gettext_expr(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
90 """The plural rule as gettext expression. The gettext expression is
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
91 technically limited to integers and returns indices rather than tags.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
92
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
93 >>> PluralRule({'one': 'n is 1', 'two': 'n is 2'}).gettext_expr
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
94 'nplurals=3; plural=((n == 2) ? 1 : (n == 1) ? 0 : 2)'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
95 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
96 used_tags = self.tags | set([_fallback_tag])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
97 _compile = _GettextCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
98 _get_index = [tag for tag in _plural_tags if tag in used_tags].index
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
99
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
100 result = ['nplurals=%d; plural=(' % len(used_tags)]
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
101 for tag, ast in self.abstract:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
102 result.append('%s ? %d : ' % (_compile(ast), _get_index(tag)))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
103 result.append('%d)' % _get_index(_fallback_tag))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
104 return ''.join(result)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
105 gettext_expr = property(gettext_expr, doc=gettext_expr.__doc__)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
106
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
107 tags = property(lambda x: frozenset([i[0] for i in x.abstract]), doc="""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
108 A set of explicitly defined tags in this rule. The implicit default
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
109 ``'other'`` rules is not part of this set unless there is an explicit
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
110 rule for it.""")
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
111
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
112 def __getstate__(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
113 return self.abstract
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
114
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
115 def __setstate__(self, abstract):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
116 self.abstract = abstract
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
117
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
118 def __call__(self, n):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
119 if not hasattr(self, '_func'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
120 self._func = to_python(self)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
121 return self._func(n)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
122
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
123
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
124 def to_javascript(rule):
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
125 """Convert a list/dict of rules or a `PluralRule` object into a JavaScript
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
126 function. This function depends on no external library:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
127
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
128 >>> to_javascript({'one': 'n is 1'})
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
129 "(function(n) { return (n == 1) ? 'one' : 'other'; })"
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
130
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
131 Implementation detail: The function generated will probably evaluate
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
132 expressions involved into range operations multiple times. This has the
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
133 advantage that external helper functions are not required and is not a
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
134 big performance hit for these simple calculations.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
135
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
136 :param rules: the rules as list or dict, or a `PluralRule` object
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
137 :return: a corresponding JavaScript function as `str`
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
138 :raise: a `RuleError` if the expression is malformed
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
139 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
140 to_js = _JavaScriptCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
141 result = ['(function(n) { return ']
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
142 for tag, ast in PluralRule.parse(rule).abstract:
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
143 result.append('%s ? %r : ' % (to_js(ast), tag))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
144 result.append('%r; })' % _fallback_tag)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
145 return ''.join(result)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
146
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
147
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
148 def to_python(rule):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
149 """Convert a list/dict of rules or a `PluralRule` object into a regular
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
150 Python function. This is useful in situations where you need a real
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
151 function and don't are about the actual rule object:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
152
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
153 >>> func = to_python({'one': 'n is 1', 'few': 'n in 2..4'})
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
154 >>> func(1)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
155 'one'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
156 >>> func(3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
157 'few'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
158
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
159 :param rules: the rules as list or dict, or a `PluralRule` object
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
160 :return: a corresponding Python function
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
161 :raise: a `RuleError` if the expression is malformed
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
162 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
163 namespace = {
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
164 'IN': in_range,
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
165 'WITHIN': within_range,
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
166 'MOD': cldr_modulo
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
167 }
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
168 to_python = _PythonCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
169 result = ['def evaluate(n):']
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
170 for tag, ast in rule.abstract:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
171 result.append(' if (%s): return %r' % (to_python(ast), tag))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
172 result.append(' return %r' % _fallback_tag)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
173 exec '\n'.join(result) in namespace
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
174 return namespace['evaluate']
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
175
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
176
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
177 def to_gettext(rule):
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
178 """The plural rule as gettext expression. The gettext expression is
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
179 technically limited to integers and returns indices rather than tags.
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
180
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
181 >>> to_gettext({'one': 'n is 1', 'two': 'n is 2'})
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
182 'nplurals=3; plural=((n == 2) ? 1 : (n == 1) ? 0 : 2)'
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
183 """
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
184 return PluralRule.parse(rule).gettext_expr
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
185
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
186
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
187 def in_range(num, min, max):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
188 """Integer range test. This is the callback for the "in" operator
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
189 of the UTS #35 pluralization rule language:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
190
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
191 >>> in_range(1, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
192 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
193 >>> in_range(3, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
194 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
195 >>> in_range(1.2, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
196 False
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
197 >>> in_range(10, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
198 False
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
199 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
200 return num == int(num) and within_range(num, min, max)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
201
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
202
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
203 def within_range(num, min, max):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
204 """Float range test. This is the callback for the "within" operator
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
205 of the UTS #35 pluralization rule language:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
206
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
207 >>> within_range(1, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
208 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
209 >>> within_range(1.0, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
210 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
211 >>> within_range(1.2, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
212 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
213 >>> within_range(10, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
214 False
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
215 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
216 return num >= min and num <= max
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
217
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
218
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
219 def cldr_modulo(a, b):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
220 """Javaish modulo. This modulo operator returns the value with the sign
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
221 of the dividend rather than the divisor like Python does:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
222
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
223 >>> cldr_modulo(-3, 5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
224 -3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
225 >>> cldr_modulo(-3, -5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
226 -3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
227 >>> cldr_modulo(3, 5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
228 3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
229 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
230 reverse = 0
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
231 if a < 0:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
232 a *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
233 reverse = 1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
234 if b < 0:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
235 b *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
236 rv = a % b
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
237 if reverse:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
238 rv *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
239 return rv
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
240
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
241
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
242 class RuleError(Exception):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
243 """Raised if a rule is malformed."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
244
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
245
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
246 class _Parser(object):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
247 """Internal parser. This class can translate a single rule into an abstract
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
248 tree of tuples. It implements the following grammar::
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
249
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
250 condition = and_condition ('or' and_condition)*
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
251 and_condition = relation ('and' relation)*
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
252 relation = is_relation | in_relation | within_relation | 'n' <EOL>
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
253 is_relation = expr 'is' ('not')? value
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
254 in_relation = expr ('not')? 'in' range
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
255 within_relation = expr ('not')? 'within' range
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
256 expr = 'n' ('mod' value)?
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
257 value = digit+
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
258 digit = 0|1|2|3|4|5|6|7|8|9
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
259 range = value'..'value
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
260
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
261 - Whitespace can occur between or around any of the above tokens.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
262 - Rules should be mutually exclusive; for a given numeric value, only one
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
263 rule should apply (i.e. the condition should only be true for one of
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
264 the plural rule elements.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
265
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
266 The translator parses the expression on instanciation into an attribute
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
267 called `ast`.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
268 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
269
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
270 _rules = [
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
271 (None, re.compile(r'\s+(?u)')),
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
272 ('word', re.compile(r'\b(and|or|is|(?:with)?in|not|mod|n)\b')),
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
273 ('value', re.compile(r'\d+')),
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
274 ('ellipsis', re.compile(r'\.\.'))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
275 ]
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
276
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
277 def __init__(self, string):
390
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
278 string = string.lower()
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
279 result = []
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
280 pos = 0
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
281 end = len(string)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
282 while pos < end:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
283 for tok, rule in self._rules:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
284 match = rule.match(string, pos)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
285 if match is not None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
286 pos = match.end()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
287 if tok:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
288 result.append((tok, match.group()))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
289 break
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
290 else:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
291 raise RuleError('malformed CLDR pluralization rule. '
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
292 'Got unexpected %r' % string[pos])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
293 self.tokens = result[::-1]
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
294
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
295 self.ast = self.condition()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
296 if self.tokens:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
297 raise RuleError('Expected end of rule, got %r' %
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
298 self.tokens[-1][1])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
299
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
300 def test(self, type, value=None):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
301 return self.tokens and self.tokens[-1][0] == type and \
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
302 (value is None or self.tokens[-1][1] == value)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
303
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
304 def skip(self, type, value=None):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
305 if self.test(type, value):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
306 return self.tokens.pop()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
307
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
308 def expect(self, type, value=None, term=None):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
309 token = self.skip(type, value)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
310 if token is not None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
311 return token
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
312 if term is None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
313 term = repr(value is None and type or value)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
314 if not self.tokens:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
315 raise RuleError('expected %s but end of rule reached' % term)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
316 raise RuleError('expected %s but got %r' % (term, self.tokens[-1][1]))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
317
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
318 def condition(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
319 op = self.and_condition()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
320 while self.skip('word', 'or'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
321 op = 'or', (op, self.and_condition())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
322 return op
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
323
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
324 def and_condition(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
325 op = self.relation()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
326 while self.skip('word', 'and'):
390
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
327 op = 'and', (op, self.relation())
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
328 return op
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
329
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
330 def relation(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
331 left = self.expr()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
332 if self.skip('word', 'is'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
333 return self.skip('word', 'not') and 'isnot' or 'is', \
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
334 (left, self.value())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
335 negated = self.skip('word', 'not')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
336 method = 'in'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
337 if self.skip('word', 'within'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
338 method = 'within'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
339 else:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
340 self.expect('word', 'in', term="'within' or 'in'")
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
341 rv = 'relation', (method, left, self.range())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
342 if negated:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
343 rv = 'not', (rv,)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
344 return rv
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
345
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
346 def range(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
347 left = self.value()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
348 self.expect('ellipsis')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
349 return 'range', (left, self.value())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
350
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
351 def expr(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
352 self.expect('word', 'n')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
353 if self.skip('word', 'mod'):
391
3eb859adc5de Fixed a bug in plural.py that caused a traceback for some locales, changed the `__mod__` DateTimePattern to not raise exceptions but return NotImplemented.
aronacher
parents: 390
diff changeset
354 return 'mod', (('n', ()), self.value())
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
355 return 'n', ()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
356
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
357 def value(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
358 return 'value', (int(self.expect('value')[1]),)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
359
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
360
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
361 def _binary_compiler(tmpl):
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
362 """Compiler factory for the `_Compiler`."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
363 return lambda self, l, r: tmpl % (self.compile(l), self.compile(r))
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
364
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
365
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
366 def _unary_compiler(tmpl):
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
367 """Compiler factory for the `_Compiler`."""
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
368 return lambda self, x: tmpl % self.compile(x)
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
369
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
370
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
371 class _Compiler(object):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
372 """The compilers are able to transform the expressions into multiple
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
373 output formats.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
374 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
375
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
376 def compile(self, (op, args)):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
377 return getattr(self, 'compile_' + op)(*args)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
378
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
379 compile_n = lambda x: 'n'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
380 compile_value = lambda x, v: str(v)
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
381 compile_and = _binary_compiler('(%s && %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
382 compile_or = _binary_compiler('(%s || %s)')
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
383 compile_not = _unary_compiler('(!%s)')
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
384 compile_mod = _binary_compiler('(%s %% %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
385 compile_is = _binary_compiler('(%s == %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
386 compile_isnot = _binary_compiler('(%s != %s)')
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
387
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
388 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
389 range = '%s, %s' % tuple(map(self.compile, range[1]))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
390 return '%s(%s, %s)' % (method.upper(), self.compile(expr), range)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
391
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
392
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
393 class _PythonCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
394 """Compiles an expression to Python."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
395
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
396 compile_and = _binary_compiler('(%s and %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
397 compile_or = _binary_compiler('(%s or %s)')
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
398 compile_not = _unary_compiler('(not %s)')
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
399 compile_mod = _binary_compiler('MOD(%s, %s)')
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
400
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
401
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
402 class _GettextCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
403 """Compile into a gettext plural expression."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
404
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
405 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
406 expr = self.compile(expr)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
407 min, max = map(self.compile, range[1])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
408 return '(%s >= %s && %s <= %s)' % (expr, min, expr, max)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
409
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
410
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
411 class _JavaScriptCompiler(_GettextCompiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
412 """Compiles the expression to plain of JavaScript."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
413
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
414 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
415 code = _GettextCompiler.compile_relation(self, method, expr, range)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
416 if method == 'in':
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
417 expr = self.compile(expr)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
418 code = '(parseInt(%s) == %s && %s)' % (expr, expr, code)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
419 return code
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
420
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
421
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
422 class _UnicodeCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
423 """Returns a unicode pluralization rule again."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
424
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
425 compile_is = _binary_compiler('%s is %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
426 compile_isnot = _binary_compiler('%s is not %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
427 compile_and = _binary_compiler('%s and %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
428 compile_or = _binary_compiler('%s or %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
429 compile_mod = _binary_compiler('%s mod %s')
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
430
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
431 def compile_not(self, relation):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
432 return self.compile_relation(negated=True, *relation[1])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
433
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
434 def compile_relation(self, method, expr, range, negated=False):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
435 return '%s%s %s %s' % (
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
436 self.compile(expr), negated and ' not' or '',
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
437 method, '%s..%s' % tuple(map(self.compile, range[1]))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
438 )
Copyright (C) 2012-2017 Edgewall Software