1"""
2babel.messages.plurals
3~~~~~~~~~~~~~~~~~~~~~~
4
5Plural form definitions.
6
7:copyright: (c) 2013-2025 by the Babel Team.
8:license: BSD, see LICENSE for more details.
9"""
10
11from __future__ import annotations
12
13from babel.core import Locale, default_locale
14
15# XXX: remove this file, duplication with babel.plural
16
17
18LC_CTYPE: str | None = default_locale('LC_CTYPE')
19
20
21PLURALS: dict[str, tuple[int, str]] = {
22 # Afar
23 # 'aa': (),
24 # Abkhazian
25 # 'ab': (),
26 # Avestan
27 # 'ae': (),
28 # Afrikaans - From Pootle's PO's
29 'af': (2, '(n != 1)'),
30 # Akan
31 # 'ak': (),
32 # Amharic
33 # 'am': (),
34 # Aragonese
35 # 'an': (),
36 # Arabic - From Pootle's PO's
37 'ar': (6, '(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=0 && n%100<=2 ? 4 : 5)'),
38 # Assamese
39 # 'as': (),
40 # Avaric
41 # 'av': (),
42 # Aymara
43 # 'ay': (),
44 # Azerbaijani
45 # 'az': (),
46 # Bashkir
47 # 'ba': (),
48 # Belarusian
49 'be': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
50 # Bulgarian - From Pootle's PO's
51 'bg': (2, '(n != 1)'),
52 # Bihari
53 # 'bh': (),
54 # Bislama
55 # 'bi': (),
56 # Bambara
57 # 'bm': (),
58 # Bengali - From Pootle's PO's
59 'bn': (2, '(n != 1)'),
60 # Tibetan - as discussed in private with Andrew West
61 'bo': (1, '0'),
62 # Breton
63 'br': (
64 6,
65 '(n==1 ? 0 : n%10==1 && n%100!=11 && n%100!=71 && n%100!=91 ? 1 : n%10==2 && n%100!=12 && n%100!=72 && '
66 'n%100!=92 ? 2 : (n%10==3 || n%10==4 || n%10==9) && n%100!=13 && n%100!=14 && n%100!=19 && n%100!=73 && '
67 'n%100!=74 && n%100!=79 && n%100!=93 && n%100!=94 && n%100!=99 ? 3 : n%1000000==0 ? 4 : 5)',
68 ),
69 # Bosnian
70 'bs': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
71 # Catalan - From Pootle's PO's
72 'ca': (2, '(n != 1)'),
73 # Chechen
74 # 'ce': (),
75 # Chamorro
76 # 'ch': (),
77 # Corsican
78 # 'co': (),
79 # Cree
80 # 'cr': (),
81 # Czech
82 'cs': (3, '((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2)'),
83 # Church Slavic
84 # 'cu': (),
85 # Chuvash
86 'cv': (1, '0'),
87 # Welsh
88 'cy': (5, '(n==1 ? 1 : n==2 ? 2 : n==3 ? 3 : n==6 ? 4 : 0)'),
89 # Danish
90 'da': (2, '(n != 1)'),
91 # German
92 'de': (2, '(n != 1)'),
93 # Divehi
94 # 'dv': (),
95 # Dzongkha
96 'dz': (1, '0'),
97 # Greek
98 'el': (2, '(n != 1)'),
99 # English
100 'en': (2, '(n != 1)'),
101 # Esperanto
102 'eo': (2, '(n != 1)'),
103 # Spanish
104 'es': (2, '(n != 1)'),
105 # Estonian
106 'et': (2, '(n != 1)'),
107 # Basque - From Pootle's PO's
108 'eu': (2, '(n != 1)'),
109 # Persian - From Pootle's PO's
110 'fa': (1, '0'),
111 # Finnish
112 'fi': (2, '(n != 1)'),
113 # French
114 'fr': (2, '(n > 1)'),
115 # Friulian - From Pootle's PO's
116 'fur': (2, '(n > 1)'),
117 # Irish
118 'ga': (5, '(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)'),
119 # Galician - From Pootle's PO's
120 'gl': (2, '(n != 1)'),
121 # Hausa - From Pootle's PO's
122 'ha': (2, '(n != 1)'),
123 # Hebrew
124 'he': (2, '(n != 1)'),
125 # Hindi - From Pootle's PO's
126 'hi': (2, '(n != 1)'),
127 # Croatian
128 'hr': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
129 # Hungarian
130 'hu': (1, '0'),
131 # Armenian - From Pootle's PO's
132 'hy': (1, '0'),
133 # Icelandic - From Pootle's PO's
134 'is': (2, '(n%10==1 && n%100!=11 ? 0 : 1)'),
135 # Italian
136 'it': (2, '(n != 1)'),
137 # Japanese
138 'ja': (1, '0'),
139 # Georgian - From Pootle's PO's
140 'ka': (1, '0'),
141 # Kongo - From Pootle's PO's
142 'kg': (2, '(n != 1)'),
143 # Khmer - From Pootle's PO's
144 'km': (1, '0'),
145 # Korean
146 'ko': (1, '0'),
147 # Kurdish - From Pootle's PO's
148 'ku': (2, '(n != 1)'),
149 # Lao - Another member of the Tai language family, like Thai.
150 'lo': (1, '0'),
151 # Lithuanian
152 'lt': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2)'),
153 # Latvian
154 'lv': (3, '(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2)'),
155 # Maltese - From Pootle's PO's
156 'mt': (4, '(n==1 ? 0 : n==0 || ( n%100>=1 && n%100<=10) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3)'),
157 # Norwegian Bokmål
158 'nb': (2, '(n != 1)'),
159 # Dutch
160 'nl': (2, '(n != 1)'),
161 # Norwegian Nynorsk
162 'nn': (2, '(n != 1)'),
163 # Norwegian
164 'no': (2, '(n != 1)'),
165 # Punjabi - From Pootle's PO's
166 'pa': (2, '(n != 1)'),
167 # Polish
168 'pl': (3, '(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
169 # Portuguese
170 'pt': (2, '(n != 1)'),
171 # Brazilian
172 'pt_BR': (2, '(n > 1)'),
173 # Romanian - From Pootle's PO's
174 'ro': (3, '(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2)'),
175 # Russian
176 'ru': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
177 # Slovak
178 'sk': (3, '((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2)'),
179 # Slovenian
180 'sl': (4, '(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)'),
181 # Serbian - From Pootle's PO's
182 'sr': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
183 # Southern Sotho - From Pootle's PO's
184 'st': (2, '(n != 1)'),
185 # Swedish
186 'sv': (2, '(n != 1)'),
187 # Thai
188 'th': (1, '0'),
189 # Turkish
190 'tr': (1, '0'),
191 # Ukrainian
192 'uk': (3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
193 # Venda - From Pootle's PO's
194 've': (2, '(n != 1)'),
195 # Vietnamese - From Pootle's PO's
196 'vi': (1, '0'),
197 # Xhosa - From Pootle's PO's
198 'xh': (2, '(n != 1)'),
199 # Chinese - From Pootle's PO's (modified)
200 'zh': (1, '0'),
201} # fmt: skip
202
203
204DEFAULT_PLURAL: tuple[int, str] = (2, '(n != 1)')
205
206
207class _PluralTuple(tuple):
208 """A tuple with plural information."""
209
210 __slots__ = ()
211
212 @property
213 def num_plurals(self) -> int:
214 """The number of plurals used by the locale."""
215 return self[0]
216
217 @property
218 def plural_expr(self) -> str:
219 """The plural expression used by the locale."""
220 return self[1]
221
222 @property
223 def plural_forms(self) -> str:
224 """The plural expression used by the catalog or locale."""
225 return f'nplurals={self[0]}; plural={self[1]};'
226
227 def __str__(self) -> str:
228 return self.plural_forms
229
230
231def get_plural(locale: Locale | str | None = None) -> _PluralTuple:
232 """A tuple with the information catalogs need to perform proper
233 pluralization. The first item of the tuple is the number of plural
234 forms, the second the plural expression.
235
236 :param locale: the `Locale` object or locale identifier. Defaults to the system character type locale.
237
238 >>> get_plural(locale='en')
239 (2, '(n != 1)')
240 >>> get_plural(locale='ga')
241 (5, '(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)')
242
243 The object returned is a special tuple with additional members:
244
245 >>> tup = get_plural("ja")
246 >>> tup.num_plurals
247 1
248 >>> tup.plural_expr
249 '0'
250 >>> tup.plural_forms
251 'nplurals=1; plural=0;'
252
253 Converting the tuple into a string prints the plural forms for a
254 gettext catalog:
255
256 >>> str(tup)
257 'nplurals=1; plural=0;'
258 """
259 locale = Locale.parse(locale or LC_CTYPE)
260 try:
261 tup = PLURALS[str(locale)]
262 except KeyError:
263 try:
264 tup = PLURALS[locale.language]
265 except KeyError:
266 tup = DEFAULT_PLURAL
267 return _PluralTuple(tup)