annotate babel/plural.py @ 530:85e1beadacb0

Update the copyright line.
author jruigrok
date Sat, 05 Mar 2011 15:22:28 +0000
parents eef19ada4296
children
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 #
530
85e1beadacb0 Update the copyright line.
jruigrok
parents: 525
diff changeset
3 # Copyright (C) 2008-2011 Edgewall Software
386
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
414
ea0da9db79ef fix Python 2.3 compat: rearrange set/itemgetter/rsplit/sorted/unicode.decode
pjenvey
parents: 411
diff changeset
17
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
18 __all__ = ['PluralRule', 'RuleError', 'to_gettext', 'to_javascript',
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
19 'to_python']
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
20 __docformat__ = 'restructuredtext en'
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
21
386
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):
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
28 """Represents a set of language pluralization rules. The constructor
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
29 accepts a list of (tag, expr) tuples or a dict of CLDR rules. The
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
30 resulting object is callable and accepts one parameter with a positive or
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
31 negative number (both integer and float) for the number that indicates the
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
32 plural form for a string and returns the tag for the format:
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
33
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
34 >>> rule = PluralRule({'one': 'n is 1'})
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
35 >>> rule(1)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
36 'one'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
37 >>> rule(2)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
38 'other'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
39
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
40 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
41 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
42 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
43 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
44 """
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 __slots__ = ('abstract', '_func')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
47
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
48 def __init__(self, rules):
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
49 """Initialize the rule instance.
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
50
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
51 :param rules: a list of ``(tag, expr)``) tuples with the rules
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
52 conforming to UTS #35 or a dict with the tags as keys
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
53 and expressions as values.
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
54 :raise RuleError: if the expression is malformed
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
55 """
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
56 if isinstance(rules, dict):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
57 rules = rules.items()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
58 found = set()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
59 self.abstract = []
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
60 for key, expr in rules:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
61 if key not in _plural_tags:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
62 raise ValueError('unknown tag %r' % key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
63 elif key in found:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
64 raise ValueError('tag %r defined twice' % key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
65 found.add(key)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
66 self.abstract.append((key, _Parser(expr).ast))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
67
390
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
68 def __repr__(self):
393
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
69 rules = self.rules
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
70 return '<%s %r>' % (
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
71 type(self).__name__,
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
72 ', '.join(['%s: %s' % (tag, rules[tag]) for tag in _plural_tags
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
73 if tag in rules])
d85b5a78ee9c alternative repr for plural rules
aronacher
parents: 392
diff changeset
74 )
390
ecf110e7f604 Preliminary support for timedelta formatting (see #126), and import/expose the locale plural rules from the CLDR.
cmlenz
parents: 387
diff changeset
75
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
76 def parse(cls, rules):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
77 """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
78 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
79
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
80 :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
81 :return: a corresponding `PluralRule` object
410
be5e0f69137b Fix some epydoc usage in the `plural` module.
cmlenz
parents: 393
diff changeset
82 :raise Ruleerror: if the expression is malformed
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
83 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
84 if isinstance(rules, cls):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
85 return rules
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
86 return cls(rules)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
87 parse = classmethod(parse)
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 rules(self):
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
90 """The `PluralRule` as a dict of unicode plural rules.
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
91
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
92 >>> rule = PluralRule({'one': 'n is 1'})
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
93 >>> rule.rules
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
94 {'one': 'n is 1'}
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
95 """
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
96 _compile = _UnicodeCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
97 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
98 rules = property(rules, doc=rules.__doc__)
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 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
101 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
102 ``'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
103 rule for it.""")
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
104
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
105 def __getstate__(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
106 return self.abstract
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
107
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
108 def __setstate__(self, abstract):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
109 self.abstract = abstract
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
110
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
111 def __call__(self, n):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
112 if not hasattr(self, '_func'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
113 self._func = to_python(self)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
114 return self._func(n)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
115
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
116
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
117 def to_javascript(rule):
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
118 """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
119 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
120
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
121 >>> to_javascript({'one': 'n is 1'})
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
122 "(function(n) { return (n == 1) ? 'one' : 'other'; })"
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
123
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
124 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
125 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
126 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
127 big performance hit for these simple calculations.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
128
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
129 :param rule: the rules as list or dict, or a `PluralRule` object
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
130 :return: a corresponding JavaScript function as `str`
410
be5e0f69137b Fix some epydoc usage in the `plural` module.
cmlenz
parents: 393
diff changeset
131 :raise RuleError: if the expression is malformed
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
132 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
133 to_js = _JavaScriptCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
134 result = ['(function(n) { return ']
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
135 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
136 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
137 result.append('%r; })' % _fallback_tag)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
138 return ''.join(result)
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
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
141 def to_python(rule):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
142 """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
143 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
144 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
145
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
146 >>> 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
147 >>> func(1)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
148 'one'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
149 >>> func(3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
150 'few'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
151
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
152 :param rule: the rules as list or dict, or a `PluralRule` object
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
153 :return: a corresponding Python function
410
be5e0f69137b Fix some epydoc usage in the `plural` module.
cmlenz
parents: 393
diff changeset
154 :raise RuleError: if the expression is malformed
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
155 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
156 namespace = {
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
157 'IN': in_range,
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
158 'WITHIN': within_range,
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
159 'MOD': cldr_modulo
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
160 }
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
161 to_python = _PythonCompiler().compile
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
162 result = ['def evaluate(n):']
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
163 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
164 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
165 result.append(' return %r' % _fallback_tag)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
166 exec '\n'.join(result) in namespace
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
167 return namespace['evaluate']
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
168
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
169
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
170 def to_gettext(rule):
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
171 """The plural rule as gettext expression. The gettext expression is
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
172 technically limited to integers and returns indices rather than tags.
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
173
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
174 >>> to_gettext({'one': 'n is 1', 'two': 'n is 2'})
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
175 'nplurals=3; plural=((n == 2) ? 1 : (n == 1) ? 0 : 2)'
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
176
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
177 :param rule: the rules as list or dict, or a `PluralRule` object
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
178 :return: an equivalent gettext-style plural expression
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
179 :raise RuleError: if the expression is malformed
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
180 """
411
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
181 rule = PluralRule.parse(rule)
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
182
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
183 used_tags = rule.tags | set([_fallback_tag])
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
184 _compile = _GettextCompiler().compile
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
185 _get_index = [tag for tag in _plural_tags if tag in used_tags].index
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
186
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
187 result = ['nplurals=%d; plural=(' % len(used_tags)]
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
188 for tag, ast in rule.abstract:
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
189 result.append('%s ? %d : ' % (_compile(ast), _get_index(tag)))
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
190 result.append('%d)' % _get_index(_fallback_tag))
3fb050ad01ae More plural module cleanup and fixes.
cmlenz
parents: 410
diff changeset
191 return ''.join(result)
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
192
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
193
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
194 def in_range(num, min, max):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
195 """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
196 of the UTS #35 pluralization rule language:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
197
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
198 >>> in_range(1, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
199 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
200 >>> in_range(3, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
201 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
202 >>> in_range(1.2, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
203 False
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
204 >>> in_range(10, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
205 False
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 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
208
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
209
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
210 def within_range(num, min, max):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
211 """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
212 of the UTS #35 pluralization rule language:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
213
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
214 >>> within_range(1, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
215 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
216 >>> within_range(1.0, 1, 3)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
217 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
218 >>> within_range(1.2, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
219 True
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
220 >>> within_range(10, 1, 4)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
221 False
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 return num >= min and num <= max
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
224
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
225
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
226 def cldr_modulo(a, b):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
227 """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
228 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
229
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
230 >>> cldr_modulo(-3, 5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
231 -3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
232 >>> cldr_modulo(-3, -5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
233 -3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
234 >>> cldr_modulo(3, 5)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
235 3
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
236 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
237 reverse = 0
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
238 if a < 0:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
239 a *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
240 reverse = 1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
241 if b < 0:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
242 b *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
243 rv = a % b
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
244 if reverse:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
245 rv *= -1
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
246 return rv
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
247
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
248
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
249 class RuleError(Exception):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
250 """Raised if a rule is malformed."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
251
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
252
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
253 class _Parser(object):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
254 """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
255 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
256
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
257 condition = and_condition ('or' and_condition)*
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
258 and_condition = relation ('and' relation)*
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
259 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
260 is_relation = expr 'is' ('not')? value
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
261 in_relation = expr ('not')? 'in' range
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
262 within_relation = expr ('not')? 'within' range
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
263 expr = 'n' ('mod' value)?
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
264 value = digit+
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
265 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
266 range = value'..'value
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
267
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
268 - 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
269 - 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
270 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
271 the plural rule elements.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
272
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
273 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
274 called `ast`.
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 _rules = [
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
278 (None, re.compile(r'\s+(?u)')),
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
279 ('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
280 ('value', re.compile(r'\d+')),
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
281 ('ellipsis', re.compile(r'\.\.'))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
282 ]
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
283
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
284 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
285 string = string.lower()
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
286 result = []
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
287 pos = 0
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
288 end = len(string)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
289 while pos < end:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
290 for tok, rule in self._rules:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
291 match = rule.match(string, pos)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
292 if match is not None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
293 pos = match.end()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
294 if tok:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
295 result.append((tok, match.group()))
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
296 break
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
297 else:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
298 raise RuleError('malformed CLDR pluralization rule. '
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
299 'Got unexpected %r' % string[pos])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
300 self.tokens = result[::-1]
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
301
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
302 self.ast = self.condition()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
303 if self.tokens:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
304 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
305 self.tokens[-1][1])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
306
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
307 def test(self, type, value=None):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
308 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
309 (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
310
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
311 def skip(self, type, value=None):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
312 if self.test(type, value):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
313 return self.tokens.pop()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
314
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
315 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
316 token = self.skip(type, value)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
317 if token is not None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
318 return token
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
319 if term is None:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
320 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
321 if not self.tokens:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
322 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
323 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
324
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
325 def condition(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
326 op = self.and_condition()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
327 while self.skip('word', 'or'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
328 op = 'or', (op, self.and_condition())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
329 return op
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
330
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
331 def and_condition(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
332 op = self.relation()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
333 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
334 op = 'and', (op, self.relation())
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
335 return op
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
336
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
337 def relation(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
338 left = self.expr()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
339 if self.skip('word', 'is'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
340 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
341 (left, self.value())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
342 negated = self.skip('word', 'not')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
343 method = 'in'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
344 if self.skip('word', 'within'):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
345 method = 'within'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
346 else:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
347 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
348 rv = 'relation', (method, left, self.range())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
349 if negated:
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
350 rv = 'not', (rv,)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
351 return rv
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
352
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
353 def range(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
354 left = self.value()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
355 self.expect('ellipsis')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
356 return 'range', (left, self.value())
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
357
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
358 def expr(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
359 self.expect('word', 'n')
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
360 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
361 return 'mod', (('n', ()), self.value())
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
362 return 'n', ()
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
363
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
364 def value(self):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
365 return 'value', (int(self.expect('value')[1]),)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
366
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
367
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
368 def _binary_compiler(tmpl):
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
369 """Compiler factory for the `_Compiler`."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
370 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
371
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
372
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
373 def _unary_compiler(tmpl):
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
374 """Compiler factory for the `_Compiler`."""
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
375 return lambda self, x: tmpl % self.compile(x)
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
376
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
377
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
378 class _Compiler(object):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
379 """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
380 output formats.
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
381 """
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
382
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
383 def compile(self, (op, args)):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
384 return getattr(self, 'compile_' + op)(*args)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
385
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
386 compile_n = lambda x: 'n'
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
387 compile_value = lambda x, v: str(v)
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
388 compile_and = _binary_compiler('(%s && %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
389 compile_or = _binary_compiler('(%s || %s)')
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
390 compile_not = _unary_compiler('(!%s)')
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
391 compile_mod = _binary_compiler('(%s %% %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
392 compile_is = _binary_compiler('(%s == %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
393 compile_isnot = _binary_compiler('(%s != %s)')
386
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
394
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
395 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
396 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
397 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
398
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
399
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
400 class _PythonCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
401 """Compiles an expression to Python."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
402
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
403 compile_and = _binary_compiler('(%s and %s)')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
404 compile_or = _binary_compiler('(%s or %s)')
392
2e77d72516d7 Fixed not in plural rules
aronacher
parents: 391
diff changeset
405 compile_not = _unary_compiler('(not %s)')
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
406 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
407
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
408
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
409 class _GettextCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
410 """Compile into a gettext plural expression."""
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
411
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
412 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
413 expr = self.compile(expr)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
414 min, max = map(self.compile, range[1])
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
415 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
416
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
417
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
418 class _JavaScriptCompiler(_GettextCompiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
419 """Compiles the expression to plain of JavaScript."""
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 def compile_relation(self, method, expr, range):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
422 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
423 if method == 'in':
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
424 expr = self.compile(expr)
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
425 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
426 return code
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
427
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
428
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
429 class _UnicodeCompiler(_Compiler):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
430 """Returns a unicode pluralization rule again."""
387
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
431
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
432 compile_is = _binary_compiler('%s is %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
433 compile_isnot = _binary_compiler('%s is not %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
434 compile_and = _binary_compiler('%s and %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
435 compile_or = _binary_compiler('%s or %s')
2edbea56d2bd Some refactoring in plural.py
aronacher
parents: 386
diff changeset
436 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
437
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
438 def compile_not(self, relation):
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
439 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
440
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
441 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
442 return '%s%s %s %s' % (
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
443 self.compile(expr), negated and ' not' or '',
4d345ad621c2 Added pluralization support module for the plural definitions from the latest CLDR
aronacher
parents:
diff changeset
444 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
445 )
Copyright (C) 2012-2017 Edgewall Software