0
# Plural Rules and Language Data
1
2
Plural rule handling for different languages, language territory information, and list formatting according to locale conventions. Babel provides comprehensive support for CLDR plural rules and language-specific data.
3
4
## Capabilities
5
6
### Plural Rule Class
7
8
Represents and evaluates CLDR plural rules for different languages.
9
10
```python { .api }
11
class PluralRule:
12
"""
13
Represents a set of language pluralization rules based on CLDR data.
14
15
Attributes:
16
rules (dict): Rules mapping plural tags to conditions
17
tags (set): Set of defined plural tags for this rule
18
"""
19
def __init__(self, rules):
20
"""
21
Initialize plural rule with rule definitions.
22
23
Args:
24
rules (dict): Mapping of plural tags to rule conditions
25
"""
26
27
@classmethod
28
def parse(cls, rules):
29
"""
30
Parse plural rules from various formats.
31
32
Args:
33
rules (str|dict|PluralRule): Rules in string, dict, or PluralRule format
34
35
Returns:
36
PluralRule: Parsed plural rule object
37
"""
38
39
def __call__(self, n):
40
"""
41
Get plural form for a number.
42
43
Args:
44
n (int|float|Decimal): Number to evaluate
45
46
Returns:
47
str: Plural form tag ('zero', 'one', 'two', 'few', 'many', 'other')
48
"""
49
```
50
51
Usage example:
52
53
```python
54
from babel.plural import PluralRule
55
56
# English plural rule (simple: one vs other)
57
en_rule = PluralRule({'one': 'n == 1'})
58
print(en_rule(1)) # 'one'
59
print(en_rule(2)) # 'other'
60
61
# French plural rule
62
fr_rule = PluralRule({'one': 'n >= 0 and n < 2'})
63
print(fr_rule(0)) # 'one'
64
print(fr_rule(1)) # 'one'
65
print(fr_rule(2)) # 'other'
66
```
67
68
### CLDR Operand Extraction
69
70
Extract operands from numbers for use in CLDR plural rule evaluation.
71
72
```python { .api }
73
def extract_operands(source):
74
"""
75
Extract CLDR operands from a number for plural rule evaluation.
76
77
Args:
78
source (float|Decimal): Number to extract operands from
79
80
Returns:
81
tuple: (n, i, v, w, f, t, c, e) operands where:
82
n: absolute value of the source number
83
i: integer digits of n
84
v: number of visible fraction digits in n
85
w: number of fraction digits in n without trailing zeros
86
f: visible fraction digits in n as an integer
87
t: fraction digits in n without trailing zeros as an integer
88
c: compact decimal exponent value
89
e: deprecated, use 'c'
90
"""
91
```
92
93
Usage example:
94
95
```python
96
from babel.plural import extract_operands
97
98
# Extract operands for different numbers
99
print(extract_operands(1.23)) # (1.23, 1, 2, 2, 23, 23, 0, 0)
100
print(extract_operands(5.00)) # (5.0, 5, 2, 0, 0, 0, 0, 0)
101
print(extract_operands(1000)) # (1000, 1000, 0, 0, 0, 0, 0, 0)
102
```
103
104
### Plural Rule Conversion
105
106
Convert plural rules to different formats for use in various systems.
107
108
```python { .api }
109
def to_javascript(rule):
110
"""
111
Convert plural rule to JavaScript function code.
112
113
Args:
114
rule (PluralRule): Plural rule to convert
115
116
Returns:
117
str: JavaScript function code for evaluating plural forms
118
"""
119
120
def to_python(rule):
121
"""
122
Convert plural rule to Python function.
123
124
Args:
125
rule (PluralRule): Plural rule to convert
126
127
Returns:
128
callable: Python function for evaluating plural forms
129
"""
130
131
def to_gettext(rule):
132
"""
133
Convert plural rule to gettext format.
134
135
Args:
136
rule (PluralRule): Plural rule to convert
137
138
Returns:
139
str: Gettext plural expression string
140
"""
141
```
142
143
Usage example:
144
145
```python
146
from babel.plural import PluralRule, to_javascript, to_python, to_gettext
147
148
rule = PluralRule({'one': 'n == 1'})
149
150
js_code = to_javascript(rule)
151
py_func = to_python(rule)
152
gettext_expr = to_gettext(rule)
153
154
print(py_func(1)) # 'one'
155
print(py_func(2)) # 'other'
156
```
157
158
### Range List Operations
159
160
Test if numbers fall within CLDR range specifications.
161
162
```python { .api }
163
def in_range_list(num, range_list):
164
"""
165
Test if integer is in a range list.
166
167
Args:
168
num (int): Integer to test
169
range_list (list): List of range specifications
170
171
Returns:
172
bool: True if number is in any of the ranges
173
"""
174
175
def within_range_list(num, range_list):
176
"""
177
Test if number is within a range list (including decimals).
178
179
Args:
180
num (float|Decimal): Number to test
181
range_list (list): List of range specifications
182
183
Returns:
184
bool: True if number is within any of the ranges
185
"""
186
187
def cldr_modulo(a, b):
188
"""
189
CLDR-compatible modulo operation.
190
191
Args:
192
a (float): Dividend
193
b (float): Divisor
194
195
Returns:
196
float: Modulo result following CLDR rules
197
"""
198
```
199
200
### Language Territory Information
201
202
Access information about languages used in different territories.
203
204
```python { .api }
205
def get_official_languages(territory, regional=False, de_facto=False):
206
"""
207
Get official languages for a territory.
208
209
Args:
210
territory (str): Territory code (e.g., 'US', 'CA', 'CH')
211
regional (bool): Include regional languages
212
de_facto (bool): Include de facto official languages
213
214
Returns:
215
tuple[str, ...]: Language codes in order of popularity/usage
216
"""
217
218
def get_territory_language_info(territory):
219
"""
220
Get detailed language information for a territory.
221
222
Args:
223
territory (str): Territory code
224
225
Returns:
226
dict: Mapping of language codes to detailed information including:
227
- population_percent: Percentage of population using language
228
- literacy_percent: Literacy rate for language
229
- writing_percent: Percentage using written form
230
- official_status: Official status information
231
"""
232
```
233
234
Usage example:
235
236
```python
237
from babel.languages import get_official_languages, get_territory_language_info
238
239
# Get official languages for territories
240
us_languages = get_official_languages('US') # ('en',)
241
ca_languages = get_official_languages('CA') # ('en', 'fr')
242
ch_languages = get_official_languages('CH') # ('de', 'fr', 'it')
243
244
# Get detailed language info
245
us_info = get_territory_language_info('US')
246
print(us_info['en']['population_percent']) # Population percentage for English in US
247
```
248
249
### List Formatting
250
251
Format sequences of items as lists according to locale conventions.
252
253
```python { .api }
254
def format_list(lst, style='standard', locale=default_locale()):
255
"""
256
Format a sequence of items as a list according to locale conventions.
257
258
Args:
259
lst (Sequence[str]): Sequence of string items to format
260
style (str): List style ('standard', 'standard-short', 'or', 'or-short', 'unit', 'unit-short', 'unit-narrow')
261
locale (Locale|str): Target locale for formatting
262
263
Returns:
264
str: Properly formatted list string
265
"""
266
```
267
268
Usage example:
269
270
```python
271
from babel.lists import format_list
272
from babel import Locale
273
274
items = ['apples', 'oranges', 'bananas']
275
276
# English formatting
277
en_result = format_list(items, locale='en_US')
278
print(en_result) # "apples, oranges, and bananas"
279
280
# Different styles
281
or_result = format_list(items, style='or', locale='en_US')
282
print(or_result) # "apples, oranges, or bananas"
283
284
# French formatting
285
fr_result = format_list(items, locale='fr_FR')
286
print(fr_result) # "apples, oranges et bananas"
287
288
# German formatting
289
de_result = format_list(items, locale='de_DE')
290
print(de_result) # "apples, oranges und bananas"
291
292
# Short styles
293
short_items = ['NYC', 'LA', 'CHI']
294
short_result = format_list(short_items, style='standard-short', locale='en_US')
295
print(short_result) # "NYC, LA, & CHI"
296
```
297
298
Different list styles:
299
- `'standard'`: Standard list with "and" (e.g., "A, B, and C")
300
- `'standard-short'`: Short standard list (e.g., "A, B, & C")
301
- `'or'`: Disjunctive list with "or" (e.g., "A, B, or C")
302
- `'or-short'`: Short disjunctive list (e.g., "A, B, or C")
303
- `'unit'`: Unit list for measurements (e.g., "A B C")
304
- `'unit-short'`: Short unit list
305
- `'unit-narrow'`: Narrow unit list
306
307
## Exception Classes
308
309
```python { .api }
310
class RuleError(Exception):
311
"""Raised when plural rule parsing or evaluation fails."""
312
```
313
314
## Advanced Plural Rule Examples
315
316
Different languages have varying plural rule complexity:
317
318
```python
319
from babel.plural import PluralRule
320
321
# English: Simple two-form rule
322
english_rule = PluralRule({
323
'one': 'n == 1',
324
'other': '' # default case
325
})
326
327
# Polish: Complex six-form rule
328
polish_rule = PluralRule({
329
'one': 'n == 1',
330
'few': 'n % 10 >= 2 and n % 10 <= 4 and (n % 100 < 12 or n % 100 > 14)',
331
'many': '(n % 10 == 0 or n % 10 == 1 or n % 10 >= 5 and n % 10 <= 9) and (n % 100 >= 12 and n % 100 <= 14)',
332
'other': ''
333
})
334
335
# Arabic: Six-form rule with zero
336
arabic_rule = PluralRule({
337
'zero': 'n == 0',
338
'one': 'n == 1',
339
'two': 'n == 2',
340
'few': 'n % 100 >= 3 and n % 100 <= 10',
341
'many': 'n % 100 >= 11 and n % 100 <= 99',
342
'other': ''
343
})
344
345
# Test different numbers
346
for num in [0, 1, 2, 3, 5, 11, 21, 101]:
347
print(f"{num}: {english_rule(num)} (en), {polish_rule(num)} (pl), {arabic_rule(num)} (ar)")
348
```