plurals.py 7.3 KB

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