num2words2 0.1.0.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. num2words2/README.md +69 -0
  2. num2words2/__init__.py +196 -0
  3. num2words2/_version.py +3 -0
  4. num2words2/base.py +377 -0
  5. num2words2/compat.py +29 -0
  6. num2words2/currency.py +60 -0
  7. num2words2/lang_AF.py +202 -0
  8. num2words2/lang_AM.py +193 -0
  9. num2words2/lang_AR.py +435 -0
  10. num2words2/lang_AS.py +119 -0
  11. num2words2/lang_AZ.py +208 -0
  12. num2words2/lang_BA.py +119 -0
  13. num2words2/lang_BE.py +356 -0
  14. num2words2/lang_BG.py +393 -0
  15. num2words2/lang_BN.py +242 -0
  16. num2words2/lang_BO.py +122 -0
  17. num2words2/lang_BR.py +135 -0
  18. num2words2/lang_BS.py +189 -0
  19. num2words2/lang_CA.py +476 -0
  20. num2words2/lang_CE.py +546 -0
  21. num2words2/lang_CS.py +260 -0
  22. num2words2/lang_CY.py +574 -0
  23. num2words2/lang_DA.py +170 -0
  24. num2words2/lang_DE.py +180 -0
  25. num2words2/lang_EL.py +338 -0
  26. num2words2/lang_EN.py +118 -0
  27. num2words2/lang_EN_IN.py +26 -0
  28. num2words2/lang_EN_NG.py +45 -0
  29. num2words2/lang_EO.py +130 -0
  30. num2words2/lang_ES.py +399 -0
  31. num2words2/lang_ES_CO.py +37 -0
  32. num2words2/lang_ES_CR.py +38 -0
  33. num2words2/lang_ES_GT.py +37 -0
  34. num2words2/lang_ES_NI.py +35 -0
  35. num2words2/lang_ES_VE.py +43 -0
  36. num2words2/lang_ET.py +393 -0
  37. num2words2/lang_EU.py +158 -0
  38. num2words2/lang_EUR.py +104 -0
  39. num2words2/lang_FA.py +187 -0
  40. num2words2/lang_FI.py +759 -0
  41. num2words2/lang_FO.py +136 -0
  42. num2words2/lang_FR.py +133 -0
  43. num2words2/lang_FR_BE.py +49 -0
  44. num2words2/lang_FR_CH.py +48 -0
  45. num2words2/lang_FR_DZ.py +35 -0
  46. num2words2/lang_GL.py +135 -0
  47. num2words2/lang_GU.py +172 -0
  48. num2words2/lang_HA.py +293 -0
  49. num2words2/lang_HAW.py +144 -0
  50. num2words2/lang_HE.py +314 -0
  51. num2words2/lang_HI.py +243 -0
  52. num2words2/lang_HR.py +304 -0
  53. num2words2/lang_HT.py +136 -0
  54. num2words2/lang_HU.py +189 -0
  55. num2words2/lang_HY.py +364 -0
  56. num2words2/lang_ID.py +242 -0
  57. num2words2/lang_IS.py +208 -0
  58. num2words2/lang_IT.py +265 -0
  59. num2words2/lang_JA.py +615 -0
  60. num2words2/lang_JW.py +136 -0
  61. num2words2/lang_KA.py +169 -0
  62. num2words2/lang_KK.py +136 -0
  63. num2words2/lang_KM.py +173 -0
  64. num2words2/lang_KN.py +182 -0
  65. num2words2/lang_KO.py +175 -0
  66. num2words2/lang_KZ.py +161 -0
  67. num2words2/lang_LA.py +135 -0
  68. num2words2/lang_LB.py +135 -0
  69. num2words2/lang_LN.py +136 -0
  70. num2words2/lang_LO.py +149 -0
  71. num2words2/lang_LT.py +283 -0
  72. num2words2/lang_LV.py +266 -0
  73. num2words2/lang_MG.py +143 -0
  74. num2words2/lang_MI.py +151 -0
  75. num2words2/lang_MK.py +136 -0
  76. num2words2/lang_ML.py +159 -0
  77. num2words2/lang_MN.py +319 -0
  78. num2words2/lang_MR.py +187 -0
  79. num2words2/lang_MS.py +293 -0
  80. num2words2/lang_MT.py +159 -0
  81. num2words2/lang_MY.py +152 -0
  82. num2words2/lang_NE.py +157 -0
  83. num2words2/lang_NL.py +204 -0
  84. num2words2/lang_NN.py +136 -0
  85. num2words2/lang_NO.py +143 -0
  86. num2words2/lang_OC.py +135 -0
  87. num2words2/lang_PA.py +159 -0
  88. num2words2/lang_PL.py +336 -0
  89. num2words2/lang_PS.py +136 -0
  90. num2words2/lang_PT.py +280 -0
  91. num2words2/lang_PT_BR.py +224 -0
  92. num2words2/lang_RO.py +183 -0
  93. num2words2/lang_RU.py +570 -0
  94. num2words2/lang_SA.py +136 -0
  95. num2words2/lang_SD.py +136 -0
  96. num2words2/lang_SI.py +152 -0
  97. num2words2/lang_SK.py +250 -0
  98. num2words2/lang_SL.py +306 -0
  99. num2words2/lang_SN.py +447 -0
  100. num2words2/lang_SO.py +136 -0
  101. num2words2/lang_SQ.py +252 -0
  102. num2words2/lang_SR.py +254 -0
  103. num2words2/lang_SU.py +136 -0
  104. num2words2/lang_SV.py +169 -0
  105. num2words2/lang_SW.py +219 -0
  106. num2words2/lang_TA.py +303 -0
  107. num2words2/lang_TE.py +169 -0
  108. num2words2/lang_TET.py +285 -0
  109. num2words2/lang_TG.py +149 -0
  110. num2words2/lang_TH.py +214 -0
  111. num2words2/lang_TK.py +136 -0
  112. num2words2/lang_TL.py +145 -0
  113. num2words2/lang_TR.py +882 -0
  114. num2words2/lang_TT.py +136 -0
  115. num2words2/lang_UK.py +1101 -0
  116. num2words2/lang_UR.py +168 -0
  117. num2words2/lang_UZ.py +136 -0
  118. num2words2/lang_VI.py +143 -0
  119. num2words2/lang_WO.py +136 -0
  120. num2words2/lang_YI.py +135 -0
  121. num2words2/lang_YO.py +136 -0
  122. num2words2/lang_ZH.py +296 -0
  123. num2words2/lang_ZH_CN.py +85 -0
  124. num2words2/lang_ZH_HK.py +48 -0
  125. num2words2/lang_ZH_TW.py +198 -0
  126. num2words2/utils.py +35 -0
  127. num2words2-0.1.0.dev1.data/scripts/num2words2 +98 -0
  128. num2words2-0.1.0.dev1.dist-info/METADATA +244 -0
  129. num2words2-0.1.0.dev1.dist-info/RECORD +133 -0
  130. num2words2-0.1.0.dev1.dist-info/WHEEL +5 -0
  131. num2words2-0.1.0.dev1.dist-info/entry_points.txt +2 -0
  132. num2words2-0.1.0.dev1.dist-info/licenses/COPYING +145 -0
  133. num2words2-0.1.0.dev1.dist-info/top_level.txt +1 -0
num2words2/lang_AZ.py ADDED
@@ -0,0 +1,208 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
3
+ # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
4
+
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ # MA 02110-1301 USA
17
+
18
+ from __future__ import unicode_literals
19
+
20
+ from .base import Num2Word_Base
21
+
22
+
23
+ class Num2Word_AZ(Num2Word_Base):
24
+ DIGITS = {
25
+ 0: u"sıfır",
26
+ 1: u"bir",
27
+ 2: u"iki",
28
+ 3: u"üç",
29
+ 4: u"dörd",
30
+ 5: u"beş",
31
+ 6: u"altı",
32
+ 7: u"yeddi",
33
+ 8: u"səkkiz",
34
+ 9: u"doqquz",
35
+ }
36
+
37
+ DECIMALS = {
38
+ 1: u"on",
39
+ 2: u"iyirmi",
40
+ 3: u"otuz",
41
+ 4: u"qırx",
42
+ 5: u"əlli",
43
+ 6: u"altmış",
44
+ 7: u"yetmiş",
45
+ 8: u"səksən",
46
+ 9: u"doxsan",
47
+ }
48
+
49
+ POWERS_OF_TEN = {
50
+ 2: u"yüz",
51
+ 3: u"min",
52
+ 6: u"milyon",
53
+ 9: u"milyard",
54
+ 12: u"trilyon",
55
+ 15: u"katrilyon",
56
+ 18: u"kentilyon",
57
+ 21: u"sekstilyon",
58
+ 24: u"septilyon",
59
+ 27: u"oktilyon",
60
+ 30: u"nonilyon",
61
+ 33: u"desilyon",
62
+ 36: u"undesilyon",
63
+ 39: u"dodesilyon",
64
+ 42: u"tredesilyon",
65
+ 45: u"katordesilyon",
66
+ 48: u"kendesilyon",
67
+ 51: u"seksdesilyon",
68
+ 54: u"septendesilyon",
69
+ 57: u"oktodesilyon",
70
+ 60: u"novemdesilyon",
71
+ 63: u"vigintilyon",
72
+ }
73
+
74
+ VOWELS = u"aıoueəiöü"
75
+ VOWEL_TO_CARDINAL_SUFFIX_MAP = {
76
+ **dict.fromkeys(["a", "ı"], "ıncı"),
77
+ **dict.fromkeys(["e", "ə", "i"], "inci"),
78
+ **dict.fromkeys(["o", "u"], "uncu"),
79
+ **dict.fromkeys(["ö", "ü"], "üncü"),
80
+ }
81
+
82
+ VOWEL_TO_CARDINAL_NUM_SUFFIX_MAP = {
83
+ **dict.fromkeys(["a", "ı"], "cı"),
84
+ **dict.fromkeys(["e", "ə", "i"], "ci"),
85
+ **dict.fromkeys(["o", "u"], "cu"),
86
+ **dict.fromkeys(["ö", "ü"], "cü"),
87
+ }
88
+
89
+ CURRENCY_INTEGRAL = ('manat', 'manat')
90
+ CURRENCY_FRACTION = ('qəpik', 'qəpik')
91
+ CURRENCY_FORMS = {
92
+ 'AZN': (CURRENCY_INTEGRAL, CURRENCY_FRACTION),
93
+ 'EUR': (('avro', 'avro'), ('sent', 'sent')),
94
+ 'USD': (('dollar', 'dollar'), ('sent', 'sent')),
95
+ }
96
+
97
+ def setup(self):
98
+ super().setup()
99
+
100
+ self.negword = u"mənfi"
101
+ self.pointword = u"nöqtə"
102
+
103
+ def to_cardinal(self, value):
104
+ value_str = str(value)
105
+ parts = value_str.split(".")
106
+ integral_part = parts[0]
107
+ fraction_part = parts[1] if len(parts) > 1 else ""
108
+
109
+ if integral_part.startswith("-"):
110
+ integral_part = integral_part[1:] # ignore minus sign here
111
+
112
+ integral_part_in_words = self.int_to_word(integral_part)
113
+ fraction_part_in_words = "" if not fraction_part else self.int_to_word(
114
+ fraction_part, leading_zeros=True)
115
+
116
+ value_in_words = integral_part_in_words
117
+ if fraction_part:
118
+ value_in_words = " ".join(
119
+ [
120
+ integral_part_in_words,
121
+ self.pointword,
122
+ fraction_part_in_words
123
+ ]
124
+ )
125
+
126
+ if value < 0:
127
+ value_in_words = " ".join([self.negword, value_in_words])
128
+
129
+ return value_in_words
130
+
131
+ def to_ordinal(self, value):
132
+ assert int(value) == value
133
+
134
+ cardinal = self.to_cardinal(value)
135
+ last_vowel = self._last_vowel(cardinal)
136
+ assert last_vowel is not None
137
+ suffix = self.VOWEL_TO_CARDINAL_SUFFIX_MAP[last_vowel]
138
+
139
+ if cardinal.endswith(tuple(self.VOWELS)):
140
+ cardinal = cardinal[:-1]
141
+
142
+ ordinal = "".join([cardinal, suffix])
143
+
144
+ return ordinal
145
+
146
+ def to_ordinal_num(self, value):
147
+ assert int(value) == value
148
+
149
+ cardinal = self.to_cardinal(value)
150
+ last_vowel = self._last_vowel(cardinal)
151
+ assert last_vowel is not None
152
+ suffix = self.VOWEL_TO_CARDINAL_NUM_SUFFIX_MAP[last_vowel]
153
+ ordinal_num = "-".join([str(value), suffix])
154
+
155
+ return ordinal_num
156
+
157
+ def to_year(self, value):
158
+ assert int(value) == value
159
+
160
+ year = self.to_cardinal(abs(value))
161
+ if value < 0:
162
+ year = " ".join(["e.ə.", year])
163
+
164
+ return year
165
+
166
+ def pluralize(self, n, forms):
167
+ form = 0 if n == 1 else 1
168
+ return forms[form]
169
+
170
+ def int_to_word(self, num_str, leading_zeros=False):
171
+ words = []
172
+ reversed_str = list(reversed(num_str))
173
+
174
+ for index, digit in enumerate(reversed_str):
175
+ digit_int = int(digit)
176
+ # calculate remainder after dividing index by 3
177
+ # because number is parsed by three digit chunks
178
+ remainder_to_3 = index % 3
179
+ if remainder_to_3 == 0:
180
+ if index > 0:
181
+ if set(reversed_str[index:index + 3]) != {'0'}:
182
+ words.insert(0, self.POWERS_OF_TEN[index])
183
+ if digit_int > 0:
184
+ # we say "min" not "bir min"
185
+ if not (digit_int == 1 and index == 3):
186
+ words.insert(0, self.DIGITS[digit_int])
187
+ elif remainder_to_3 == 1:
188
+ if digit_int != 0:
189
+ words.insert(0, self.DECIMALS[digit_int])
190
+ else: # remainder is 2
191
+ if digit_int > 0:
192
+ words.insert(0, self.POWERS_OF_TEN[2]) # "yüz"
193
+ if digit_int > 1:
194
+ words.insert(0, self.DIGITS[digit_int])
195
+
196
+ if num_str == '0':
197
+ words.append(self.DIGITS[0])
198
+
199
+ if leading_zeros:
200
+ zeros_count = len(num_str) - len(str(int(num_str)))
201
+ words[:0] = zeros_count * [self.DIGITS[0]]
202
+
203
+ return " ".join(words)
204
+
205
+ def _last_vowel(self, value):
206
+ for char in value[::-1]:
207
+ if char in self.VOWELS:
208
+ return char
num2words2/lang_BA.py ADDED
@@ -0,0 +1,119 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
3
+ # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
4
+
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ # MA 02110-1301 USA
17
+
18
+ from __future__ import unicode_literals
19
+
20
+ from .base import Num2Word_Base
21
+
22
+
23
+ # Bashkir language support
24
+ class Num2Word_BA(Num2Word_Base):
25
+ CURRENCY_FORMS = {
26
+ 'RUB': (('һум', 'һум'), ('тин', 'тин')),
27
+ 'USD': (('доллар', 'доллар'), ('цент', 'цент')),
28
+ 'EUR': (('евро', 'евро'), ('цент', 'цент')),
29
+ }
30
+
31
+ def setup(self):
32
+ self.negword = "минус "
33
+ self.pointword = "өтөр"
34
+
35
+ def to_cardinal(self, number):
36
+ """Convert a number to its word representation in Bashkir."""
37
+ n = str(number).strip()
38
+
39
+ if n.startswith('-'):
40
+ n = n[1:]
41
+ ret = self.negword
42
+ else:
43
+ ret = ""
44
+
45
+ if '.' in n:
46
+ left, right = n.split('.', 1)
47
+ ret += self._int_to_word(int(left)) + " " + self.pointword + " "
48
+ ret += " ".join(self._int_to_word(int(d)) for d in right)
49
+ return ret
50
+ else:
51
+ return ret + self._int_to_word(int(n))
52
+
53
+ def _int_to_word(self, number):
54
+ """Convert an integer to its word representation in Bashkir."""
55
+ if number == 0:
56
+ return "нуль"
57
+
58
+ ones = ["", "бер", "ике", "өс", "дүрт", "биш", "алты", "ете", "һигеҙ", "туғыҙ"]
59
+ tens = ["", "", "егерме", "утыҙ", "ҡырҡ", "илле", "алтмыш", "етмеш", "һикһән", "туҡһан"]
60
+ teens = ["ун", "ун бер", "ун ике", "ун өс", "ун дүрт", "ун биш", "ун алты", "ун ете", "ун һигеҙ", "ун туғыҙ"]
61
+
62
+ if number < 10:
63
+ return ones[number]
64
+ elif number < 20:
65
+ return teens[number - 10]
66
+ elif number < 100:
67
+ return tens[number // 10] + (" " + ones[number % 10] if number % 10 else "")
68
+ elif number < 1000:
69
+ return ones[number // 100] + " йөҙ" + (" " + self._int_to_word(number % 100) if number % 100 else "")
70
+ elif number < 1000000:
71
+ return self._int_to_word(number // 1000) + " мең" + (" " + self._int_to_word(number % 1000) if number % 1000 else "")
72
+ elif number < 1000000000:
73
+ return self._int_to_word(number // 1000000) + " миллион" + (" " + self._int_to_word(number % 1000000) if number % 1000000 else "")
74
+ else:
75
+ return self._int_to_word(number // 1000000000) + " миллиард" + (" " + self._int_to_word(number % 1000000000) if number % 1000000000 else "")
76
+
77
+ def to_ordinal(self, number):
78
+ """Convert to ordinal."""
79
+ cardinal = self.to_cardinal(number)
80
+ return cardinal + "-се"
81
+
82
+ def to_ordinal_num(self, number):
83
+ """Convert to abbreviated ordinal."""
84
+ return str(number) + "-се"
85
+
86
+ def to_year(self, val, longval=True):
87
+ """Convert to year."""
88
+ return self.to_cardinal(val) + " йыл"
89
+
90
+ def to_currency(self, val, currency='RUB', cents=True, separator=' һәм ', adjective=False):
91
+ """Convert to currency."""
92
+ try:
93
+ left, right, is_negative = self.parse_currency(val)
94
+ except AttributeError:
95
+ is_negative = False
96
+ if val < 0:
97
+ is_negative = True
98
+ val = abs(val)
99
+
100
+ left, right = self._split_currency(val)
101
+
102
+ cr1, cr2 = self.CURRENCY_FORMS.get(currency, self.CURRENCY_FORMS['RUB'])
103
+
104
+ left_str = self._int_to_word(int(left))
105
+ cents_str = self._int_to_word(int(right)) if cents and right else ""
106
+
107
+ result = left_str + " " + cr1[0]
108
+
109
+ if cents_str:
110
+ result += separator + cents_str + " " + cr2[0]
111
+
112
+ return self.negword + result if is_negative else result
113
+
114
+ def _split_currency(self, n):
115
+ """Split currency into whole and fraction parts."""
116
+ parts = str(n).split('.')
117
+ left = int(parts[0]) if parts[0] else 0
118
+ right = int(parts[1][:2].ljust(2, '0')) if len(parts) > 1 and parts[1] else 0
119
+ return left, right
num2words2/lang_BE.py ADDED
@@ -0,0 +1,356 @@
1
+ # Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
2
+ # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
3
+ # Copyright (c) 2022, Sergei Ruzki. All Rights Reserved.
4
+
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ # MA 02110-1301 USA
17
+
18
+ from __future__ import unicode_literals
19
+
20
+ from .base import Num2Word_Base
21
+ from .utils import get_digits, splitbyx
22
+
23
+ ZERO = "нуль"
24
+
25
+ ONES_FEMININE = {
26
+ 1: "адна",
27
+ 2: "дзве",
28
+ 3: "тры",
29
+ 4: "чатыры",
30
+ 5: "пяць",
31
+ 6: "шэсць",
32
+ 7: "сем",
33
+ 8: "восем",
34
+ 9: "дзевяць",
35
+ }
36
+
37
+ ONES = {
38
+ "f": {
39
+ 1: "адна",
40
+ 2: "дзве",
41
+ 3: "тры",
42
+ 4: "чатыры",
43
+ 5: "пяць",
44
+ 6: "шэсць",
45
+ 7: "сем",
46
+ 8: "восем",
47
+ 9: "дзевяць",
48
+ },
49
+ "m": {
50
+ 1: "адзін",
51
+ 2: "два",
52
+ 3: "тры",
53
+ 4: "чатыры",
54
+ 5: "пяць",
55
+ 6: "шэсць",
56
+ 7: "сем",
57
+ 8: "восем",
58
+ 9: "дзевяць",
59
+ },
60
+ "n": {
61
+ 1: "адно",
62
+ 2: "два",
63
+ 3: "тры",
64
+ 4: "чатыры",
65
+ 5: "пяць",
66
+ 6: "шэсць",
67
+ 7: "сем",
68
+ 8: "восем",
69
+ 9: "дзевяць",
70
+ },
71
+ }
72
+
73
+ TENS = {
74
+ 0: "дзесяць",
75
+ 1: "адзінаццаць",
76
+ 2: "дванаццаць",
77
+ 3: "трынаццаць",
78
+ 4: "чатырнаццаць",
79
+ 5: "пятнаццаць",
80
+ 6: "шаснаццаць",
81
+ 7: "сямнаццаць",
82
+ 8: "васямнаццаць",
83
+ 9: "дзевятнаццаць",
84
+ }
85
+
86
+ TWENTIES = {
87
+ 2: "дваццаць",
88
+ 3: "трыццаць",
89
+ 4: "сорак",
90
+ 5: "пяцьдзясят",
91
+ 6: "шэсцьдзясят",
92
+ 7: "семдзесят",
93
+ 8: "восемдзесят",
94
+ 9: "дзевяноста",
95
+ }
96
+
97
+ TWENTIES_ORD = (
98
+ ("дваццаць", "дваццаці"),
99
+ ("трыццаць", "трыццаці"),
100
+ ("сорак", "сарака"),
101
+ ("пяцьдзясят", "пяцідзясяці"),
102
+ ("шэсцьдзясят", "шaсцідзясяці"),
103
+ ("семдзесят", "сямідзесяці"),
104
+ ("восемдзесят", "васьмідзесяці"),
105
+ ("дзевяноста", "дзевяноста"),
106
+ )
107
+
108
+ HUNDREDS = {
109
+ 1: "сто",
110
+ 2: "дзвесце",
111
+ 3: "трыста",
112
+ 4: "чатырыста",
113
+ 5: "пяцьсот",
114
+ 6: "шэсцьсот",
115
+ 7: "семсот",
116
+ 8: "восемсот",
117
+ 9: "дзевяцьсот",
118
+ }
119
+
120
+ THOUSANDS = {
121
+ 1: ("тысяча", "тысячы", "тысяч"), # 10^3
122
+ 2: ("мільён", "мільёны", "мільёнаў"), # 10^6
123
+ 3: ("мільярд", "мільярды", "мільярдаў"), # 10^9
124
+ 4: ("трыльён", "трыльёны", "трыльёнаў"), # 10^12
125
+ 5: ("квадрыльён", "квадрыльёны", "квадрыльёнаў"), # 10^15
126
+ 6: ("квінтыльён", "квінтыльёны", "квінтыльёнаў"), # 10^18
127
+ 7: ("секстыльён", "секстыльёны", "секстыльёнаў"), # 10^21
128
+ 8: ("сэптыльён", "сэптыльёны", "сэптыльёнаў"), # 10^24
129
+ 9: ("актыльён", "актыльёны", "актыльёнаў"), # 10^27
130
+ 10: ("нанільён", "нанільёны", "нанільёнаў"), # 10^30
131
+ }
132
+
133
+
134
+ class Num2Word_BE(Num2Word_Base):
135
+ CURRENCY_FORMS = {
136
+ "RUB": (
137
+ ("расійскі рубель", "расійскія рублі", "расійскіх рублёў"),
138
+ ("капейка", "капейкі", "капеек"),
139
+ ),
140
+ "EUR": (("еўра", "еўра", "еўра"), ("цэнт", "цэнты", "цэнтаў")),
141
+ "USD": (("долар", "долары", "долараў"), ("цэнт", "цэнты", "цэнтаў")),
142
+ "UAH": (
143
+ ("грыўна", "грыўны", "грыўнаў"),
144
+ ("капейка", "капейкі", "капеек"),
145
+ ),
146
+ "KZT": (("тэнге", "тэнге", "тэнге"), ("тыйін", "тыйіны", "тыйінаў")),
147
+ "BYN": (
148
+ ("беларускі рубель", "беларускія рублі", "беларускіх рублёў"),
149
+ ("капейка", "капейкі", "капеек"),
150
+ ),
151
+ "UZS": (("сум", "сумы", "сумаў"), ("тыйін", "тыйіны", "тыйінаў")),
152
+ "PLN": (("злоты", "злотых", "злотых"), ("грош", "грошы", "грошаў")),
153
+ }
154
+
155
+ def setup(self):
156
+ self.negword = "мінус"
157
+ self.pointword = "коска"
158
+ self.ords = {
159
+ "нуль": "нулявы",
160
+ "адзін": "першы",
161
+ "два": "другі",
162
+ "тры": "трэці",
163
+ "чатыры": "чацвёрты",
164
+ "пяць": "пяты",
165
+ "шэсць": "шосты",
166
+ "сем": "сёмы",
167
+ "восем": "восьмы",
168
+ "дзевяць": "дзявяты",
169
+ "сто": "соты",
170
+ "тысяча": "тысячны",
171
+ }
172
+
173
+ self.ords_adjective = {
174
+ "адзін": "адна",
175
+ "адна": "адна",
176
+ "дзве": "двух",
177
+ "тры": "трох",
178
+ "чатыры": "чатырох",
179
+ "пяць": "пяці",
180
+ "шэсць": "шасці",
181
+ "сем": "сямі",
182
+ "восем": "васьмі",
183
+ "дзевяць": "дзевяцi",
184
+ "сто": "ста",
185
+ }
186
+
187
+ def to_cardinal(self, number, gender="m"):
188
+ n = str(number).replace(",", ".")
189
+ if "." in n:
190
+ is_negative = n.startswith('-')
191
+ abs_n = n[1:] if is_negative else n
192
+ left, right = abs_n.split(".")
193
+ if set(right) == {"0"}:
194
+ leading_zero_count = 0
195
+ else:
196
+ leading_zero_count = len(right) - len(right.lstrip("0"))
197
+
198
+ decimal_part = (ZERO + " ") * leading_zero_count + self._int2word(
199
+ int(right), gender
200
+ )
201
+ result = "{} {} {}".format(
202
+ self._int2word(int(left), gender), self.pointword, decimal_part
203
+ )
204
+ if is_negative:
205
+ result = self.negword + " " + result
206
+ return result
207
+ else:
208
+ return self._int2word(int(n), gender)
209
+
210
+ def pluralize(self, n, forms):
211
+ if n % 100 < 10 or n % 100 > 20:
212
+ if n % 10 == 1:
213
+ form = 0
214
+ elif 5 > n % 10 > 1:
215
+ form = 1
216
+ else:
217
+ form = 2
218
+ else:
219
+ form = 2
220
+ return forms[form]
221
+
222
+ def to_ordinal(self, number, gender="m"):
223
+ self.verify_ordinal(number)
224
+ if isinstance(gender, bool) and gender:
225
+ gender = "f"
226
+ outwords = self.to_cardinal(number, gender).split(" ")
227
+ lastword = outwords[-1].lower()
228
+ try:
229
+ if len(outwords) > 1:
230
+ if outwords[-2] in self.ords_adjective:
231
+ outwords[-2] = self.ords_adjective.get(
232
+ outwords[-2], outwords[-2]
233
+ )
234
+ elif outwords[-2] == "дзесяць":
235
+ outwords[-2] = outwords[-2][:-1] + "і"
236
+ if len(outwords) == 3:
237
+ if outwords[-3] in ["адзін", "адна"]:
238
+ outwords[-3] = ""
239
+ lastword = self.ords[lastword]
240
+ except KeyError:
241
+ if lastword[:-3] in self.ords_adjective:
242
+ lastword = (
243
+ self.ords_adjective.get(lastword[:-3], lastword) + "соты"
244
+ )
245
+ elif lastword[-7:] == "дзесяць":
246
+ lastword = "дзясяты"
247
+ elif lastword[-9:] == "семдзесят":
248
+ lastword = "сямідзясяты"
249
+ elif lastword[-1] == "ь" or lastword[-2] == "ц":
250
+ lastword = lastword[:-2] + "ты"
251
+ elif lastword[-1] == "к":
252
+ lastword = lastword.replace("о", "а") + "авы"
253
+
254
+ elif lastword[-2] == "ч" or lastword[-1] == "ч":
255
+ if lastword[-2] == "ч":
256
+ lastword = lastword[:-1] + "ны"
257
+ if lastword[-1] == "ч":
258
+ lastword = lastword + "ны"
259
+
260
+ elif lastword[-1] == "н" or lastword[-2] == "н":
261
+ lastword = lastword[: lastword.rfind("н") + 1] + "ны"
262
+ elif lastword[-3:] == "наў":
263
+ lastword = lastword[: lastword.rfind("н") + 1] + "ны"
264
+ elif lastword[-1] == "д" or lastword[-2] == "д":
265
+ lastword = lastword[: lastword.rfind("д") + 1] + "ны"
266
+
267
+ if gender == "f":
268
+ if lastword[-2:] in [
269
+ "ці",
270
+ ]:
271
+ lastword = lastword[:-2] + "цяя"
272
+ else:
273
+ lastword = lastword[:-1] + "ая"
274
+
275
+ if gender == "n":
276
+ if lastword[-2:] in ["ці", "ца"]:
277
+ lastword = lastword[:-2] + "цяе"
278
+ else:
279
+ lastword = lastword[:-1] + "ае"
280
+
281
+ outwords[-1] = self.title(lastword)
282
+ if len(outwords) == 2 and "адна" in outwords[-2]:
283
+ outwords[-2] = outwords[-1]
284
+ del outwords[-1]
285
+
286
+ if len(outwords) > 1 and (
287
+ (any(x[0] in outwords[-1] for x in THOUSANDS.values()))
288
+ or "тысяч" in outwords[-1]
289
+ ):
290
+ new_outwords = []
291
+ for _w in outwords:
292
+ replacement = next(
293
+ (x for x in TWENTIES_ORD if x[0] in _w), None
294
+ )
295
+ if replacement:
296
+ _w = _w.replace(replacement[0], replacement[1])
297
+ new_outwords.append(_w)
298
+ outwords = ["".join(new_outwords)]
299
+
300
+ return " ".join(outwords).strip()
301
+
302
+ def _money_verbose(self, number, currency):
303
+ gender = "m"
304
+ if currency == "UAH":
305
+ gender = "f"
306
+
307
+ return self._int2word(number, gender)
308
+
309
+ def _cents_verbose(self, number, currency):
310
+ if currency in ("UAH", "RUB", "BYN"):
311
+ gender = "f"
312
+ else:
313
+ gender = "m"
314
+
315
+ return self._int2word(number, gender)
316
+
317
+ def _int2word(self, n, gender="m"):
318
+ if n < 0:
319
+ return " ".join([self.negword, self._int2word(abs(n), gender)])
320
+
321
+ if n == 0:
322
+ return ZERO
323
+
324
+ words = []
325
+ chunks = list(splitbyx(str(n), 3))
326
+ i = len(chunks)
327
+ for x in chunks:
328
+ i -= 1
329
+
330
+ if x == 0:
331
+ continue
332
+
333
+ n1, n2, n3 = get_digits(x)
334
+
335
+ if n3 > 0:
336
+ words.append(HUNDREDS[n3])
337
+
338
+ if n2 > 1:
339
+ words.append(TWENTIES[n2])
340
+
341
+ if n2 == 1:
342
+ words.append(TENS[n1])
343
+ elif n1 > 0:
344
+ if i == 0:
345
+ ones = ONES[gender]
346
+ elif i == 1:
347
+ ones = ONES["f"] # Thousands are feminine
348
+ else:
349
+ ones = ONES["m"]
350
+
351
+ words.append(ones[n1])
352
+
353
+ if i > 0:
354
+ words.append(self.pluralize(x, THOUSANDS[i]))
355
+
356
+ return " ".join(words)