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.
- num2words2/README.md +69 -0
- num2words2/__init__.py +196 -0
- num2words2/_version.py +3 -0
- num2words2/base.py +377 -0
- num2words2/compat.py +29 -0
- num2words2/currency.py +60 -0
- num2words2/lang_AF.py +202 -0
- num2words2/lang_AM.py +193 -0
- num2words2/lang_AR.py +435 -0
- num2words2/lang_AS.py +119 -0
- num2words2/lang_AZ.py +208 -0
- num2words2/lang_BA.py +119 -0
- num2words2/lang_BE.py +356 -0
- num2words2/lang_BG.py +393 -0
- num2words2/lang_BN.py +242 -0
- num2words2/lang_BO.py +122 -0
- num2words2/lang_BR.py +135 -0
- num2words2/lang_BS.py +189 -0
- num2words2/lang_CA.py +476 -0
- num2words2/lang_CE.py +546 -0
- num2words2/lang_CS.py +260 -0
- num2words2/lang_CY.py +574 -0
- num2words2/lang_DA.py +170 -0
- num2words2/lang_DE.py +180 -0
- num2words2/lang_EL.py +338 -0
- num2words2/lang_EN.py +118 -0
- num2words2/lang_EN_IN.py +26 -0
- num2words2/lang_EN_NG.py +45 -0
- num2words2/lang_EO.py +130 -0
- num2words2/lang_ES.py +399 -0
- num2words2/lang_ES_CO.py +37 -0
- num2words2/lang_ES_CR.py +38 -0
- num2words2/lang_ES_GT.py +37 -0
- num2words2/lang_ES_NI.py +35 -0
- num2words2/lang_ES_VE.py +43 -0
- num2words2/lang_ET.py +393 -0
- num2words2/lang_EU.py +158 -0
- num2words2/lang_EUR.py +104 -0
- num2words2/lang_FA.py +187 -0
- num2words2/lang_FI.py +759 -0
- num2words2/lang_FO.py +136 -0
- num2words2/lang_FR.py +133 -0
- num2words2/lang_FR_BE.py +49 -0
- num2words2/lang_FR_CH.py +48 -0
- num2words2/lang_FR_DZ.py +35 -0
- num2words2/lang_GL.py +135 -0
- num2words2/lang_GU.py +172 -0
- num2words2/lang_HA.py +293 -0
- num2words2/lang_HAW.py +144 -0
- num2words2/lang_HE.py +314 -0
- num2words2/lang_HI.py +243 -0
- num2words2/lang_HR.py +304 -0
- num2words2/lang_HT.py +136 -0
- num2words2/lang_HU.py +189 -0
- num2words2/lang_HY.py +364 -0
- num2words2/lang_ID.py +242 -0
- num2words2/lang_IS.py +208 -0
- num2words2/lang_IT.py +265 -0
- num2words2/lang_JA.py +615 -0
- num2words2/lang_JW.py +136 -0
- num2words2/lang_KA.py +169 -0
- num2words2/lang_KK.py +136 -0
- num2words2/lang_KM.py +173 -0
- num2words2/lang_KN.py +182 -0
- num2words2/lang_KO.py +175 -0
- num2words2/lang_KZ.py +161 -0
- num2words2/lang_LA.py +135 -0
- num2words2/lang_LB.py +135 -0
- num2words2/lang_LN.py +136 -0
- num2words2/lang_LO.py +149 -0
- num2words2/lang_LT.py +283 -0
- num2words2/lang_LV.py +266 -0
- num2words2/lang_MG.py +143 -0
- num2words2/lang_MI.py +151 -0
- num2words2/lang_MK.py +136 -0
- num2words2/lang_ML.py +159 -0
- num2words2/lang_MN.py +319 -0
- num2words2/lang_MR.py +187 -0
- num2words2/lang_MS.py +293 -0
- num2words2/lang_MT.py +159 -0
- num2words2/lang_MY.py +152 -0
- num2words2/lang_NE.py +157 -0
- num2words2/lang_NL.py +204 -0
- num2words2/lang_NN.py +136 -0
- num2words2/lang_NO.py +143 -0
- num2words2/lang_OC.py +135 -0
- num2words2/lang_PA.py +159 -0
- num2words2/lang_PL.py +336 -0
- num2words2/lang_PS.py +136 -0
- num2words2/lang_PT.py +280 -0
- num2words2/lang_PT_BR.py +224 -0
- num2words2/lang_RO.py +183 -0
- num2words2/lang_RU.py +570 -0
- num2words2/lang_SA.py +136 -0
- num2words2/lang_SD.py +136 -0
- num2words2/lang_SI.py +152 -0
- num2words2/lang_SK.py +250 -0
- num2words2/lang_SL.py +306 -0
- num2words2/lang_SN.py +447 -0
- num2words2/lang_SO.py +136 -0
- num2words2/lang_SQ.py +252 -0
- num2words2/lang_SR.py +254 -0
- num2words2/lang_SU.py +136 -0
- num2words2/lang_SV.py +169 -0
- num2words2/lang_SW.py +219 -0
- num2words2/lang_TA.py +303 -0
- num2words2/lang_TE.py +169 -0
- num2words2/lang_TET.py +285 -0
- num2words2/lang_TG.py +149 -0
- num2words2/lang_TH.py +214 -0
- num2words2/lang_TK.py +136 -0
- num2words2/lang_TL.py +145 -0
- num2words2/lang_TR.py +882 -0
- num2words2/lang_TT.py +136 -0
- num2words2/lang_UK.py +1101 -0
- num2words2/lang_UR.py +168 -0
- num2words2/lang_UZ.py +136 -0
- num2words2/lang_VI.py +143 -0
- num2words2/lang_WO.py +136 -0
- num2words2/lang_YI.py +135 -0
- num2words2/lang_YO.py +136 -0
- num2words2/lang_ZH.py +296 -0
- num2words2/lang_ZH_CN.py +85 -0
- num2words2/lang_ZH_HK.py +48 -0
- num2words2/lang_ZH_TW.py +198 -0
- num2words2/utils.py +35 -0
- num2words2-0.1.0.dev1.data/scripts/num2words2 +98 -0
- num2words2-0.1.0.dev1.dist-info/METADATA +244 -0
- num2words2-0.1.0.dev1.dist-info/RECORD +133 -0
- num2words2-0.1.0.dev1.dist-info/WHEEL +5 -0
- num2words2-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- num2words2-0.1.0.dev1.dist-info/licenses/COPYING +145 -0
- 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)
|