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_SQ.py ADDED
@@ -0,0 +1,252 @@
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_SQ(Num2Word_Base):
24
+ CURRENCY_FORMS = {
25
+ 'ALL': (('lek', 'lekë'), ('qindarkë', 'qindarkë')),
26
+ 'EUR': (('euro', 'euro'), ('cent', 'centë')),
27
+ 'USD': (('dollar', 'dollarë'), ('cent', 'centë')),
28
+ 'GBP': (('paund', 'paund'), ('peni', 'pence')),
29
+ 'CHF': (('frank zviceran', 'franka zvicer'), ('centim', 'centimë')),
30
+ 'JPY': (('jen', 'jenë'), ('sen', 'senë')),
31
+ 'RUB': (('rubël', 'rubla'), ('kopek', 'kopekë')),
32
+ }
33
+
34
+ def setup(self):
35
+ self.negword = "minus "
36
+ self.pointword = "presje"
37
+ self.exclude_title = ["e", "presje", "minus"]
38
+
39
+ self.high_numwords = ["trilion", "miliard", "milion"]
40
+
41
+ self.mid_numwords = [
42
+ (1000, "mijë"),
43
+ (100, "qind"),
44
+ (90, "nëntëdhjetë"),
45
+ (80, "tetëdhjetë"),
46
+ (70, "shtatëdhjetë"),
47
+ (60, "gjashtëdhjetë"),
48
+ (50, "pesëdhjetë"),
49
+ (40, "dyzet"),
50
+ (30, "tridhjetë"),
51
+ (20, "njëzet"),
52
+ ]
53
+
54
+ self.low_numwords = [
55
+ "nëntëmbëdhjetë", # 19
56
+ "tetëmbëdhjetë", # 18
57
+ "shtatëmbëdhjetë", # 17
58
+ "gjashtëmbëdhjetë", # 16
59
+ "pesëmbëdhjetë", # 15
60
+ "katërmbëdhjetë", # 14
61
+ "trembëdhjetë", # 13
62
+ "dymbëdhjetë", # 12
63
+ "njëmbëdhjetë", # 11
64
+ "dhjetë", # 10
65
+ "nëntë", # 9
66
+ "tetë", # 8
67
+ "shtatë", # 7
68
+ "gjashtë", # 6
69
+ "pesë", # 5
70
+ "katër", # 4
71
+ "tre", # 3
72
+ "dy", # 2
73
+ "një", # 1
74
+ "zero" # 0
75
+ ]
76
+
77
+ # Ordinal forms
78
+ self.ordinal_forms = {
79
+ 0: "i zeroi",
80
+ 1: "i pari",
81
+ 2: "i dyti",
82
+ 3: "i treti",
83
+ 4: "i katërti",
84
+ 5: "i pesti",
85
+ 6: "i gjashti",
86
+ 7: "i shtati",
87
+ 8: "i teti",
88
+ 9: "i nënti",
89
+ 10: "i dhjeti",
90
+ 20: "i njezeti",
91
+ 100: "i njëqindi",
92
+ 1000: "i një mijti",
93
+ }
94
+
95
+ def set_high_numwords(self, high):
96
+ max = 3 + 3 * len(high)
97
+ for word, n in zip(high, range(max, 3, -3)):
98
+ self.cards[10 ** n] = word
99
+
100
+ def merge(self, curr, next):
101
+ ctext, cnum, ntext, nnum = curr + next
102
+
103
+ if cnum == 1:
104
+ if nnum == 1000:
105
+ return ("një mijë", 1000)
106
+ if nnum == 100:
107
+ return ("njëqind", 100) # Combined as one word
108
+ if nnum < 100:
109
+ return next
110
+ ctext = "një"
111
+
112
+ if nnum > cnum:
113
+ if nnum >= 1000000:
114
+ return ("%s %s" % (ctext, ntext), cnum * nnum)
115
+ elif nnum >= 1000:
116
+ return ("%s %s" % (ctext, ntext), cnum * nnum)
117
+ elif nnum == 100:
118
+ return ("%s %s" % (ctext, ntext), cnum * nnum)
119
+
120
+ if nnum < cnum:
121
+ if cnum >= 1000:
122
+ # For thousands, always use "e" connector for smaller numbers
123
+ return ("%s e %s" % (ctext, ntext), cnum + nnum)
124
+ elif cnum >= 100:
125
+ # For hundreds, use "e" for anything smaller
126
+ return ("%s e %s" % (ctext, ntext), cnum + nnum)
127
+ else:
128
+ # For tens (20, 30, etc.), use "e" for units
129
+ if cnum >= 20 and nnum < 10:
130
+ return ("%s e %s" % (ctext, ntext), cnum + nnum)
131
+ return ("%s%s" % (ctext, ntext), cnum + nnum)
132
+
133
+ return ("%s %s" % (ctext, ntext), cnum + nnum)
134
+
135
+ def to_cardinal(self, value):
136
+ if value == 0:
137
+ return 'zero'
138
+
139
+ result = super(Num2Word_SQ, self).to_cardinal(value)
140
+ return result
141
+
142
+ def to_ordinal(self, value):
143
+ if value in self.ordinal_forms:
144
+ return self.ordinal_forms[value]
145
+
146
+ # For compound ordinals, use pattern "i + cardinal + suffix"
147
+ if value <= 10:
148
+ return self.ordinal_forms.get(value, "i " + self.to_cardinal(value))
149
+
150
+ elif value == 20:
151
+ return "i njezeti"
152
+ elif value == 100:
153
+ return "i njëqindi"
154
+ elif value == 1000:
155
+ return "i një mijti"
156
+ else:
157
+ # For other numbers, use pattern
158
+ cardinal = self.to_cardinal(value)
159
+ return "i " + cardinal
160
+
161
+ def to_ordinal_num(self, value):
162
+ self.verify_ordinal(value)
163
+
164
+ # Albanian ordinal suffixes based on ending
165
+ if value % 10 == 1 and value % 100 != 11:
166
+ suffix = "-shi"
167
+ elif value % 10 == 2 and value % 100 != 12:
168
+ suffix = "-ri"
169
+ elif value % 10 == 3 and value % 100 != 13:
170
+ suffix = "-ti"
171
+ else:
172
+ suffix = "-ti"
173
+
174
+ return str(value) + suffix
175
+
176
+ def pluralize(self, n, forms):
177
+ """Albanian plural rules"""
178
+ if not forms:
179
+ return ''
180
+
181
+ if len(forms) == 1:
182
+ return forms[0]
183
+
184
+ if len(forms) >= 2:
185
+ # In Albanian, use singular for 1, plural for everything else
186
+ if n == 1:
187
+ return forms[0]
188
+ else:
189
+ return forms[1]
190
+
191
+ return forms[0]
192
+
193
+ def to_currency(self, val, currency='ALL', cents=True, separator=',',
194
+ adjective=False):
195
+ """
196
+ Convert a value to Albanian currency format.
197
+ """
198
+ result = []
199
+ is_negative = val < 0
200
+ val = abs(val)
201
+
202
+ if currency in self.CURRENCY_FORMS:
203
+ # Check if value has fractional cents
204
+ from decimal import Decimal
205
+ decimal_val = Decimal(str(val))
206
+ has_fractional_cents = (decimal_val * 100) % 1 != 0
207
+
208
+ if isinstance(val, float):
209
+ # Handle decimal values
210
+ if has_fractional_cents:
211
+ # Keep precision for fractional cents
212
+ whole = int(decimal_val)
213
+ cents_value = decimal_val * 100 - (whole * 100)
214
+ else:
215
+ whole = int(val)
216
+ cents_value = int(round((val - whole) * 100))
217
+ else:
218
+ whole = int(val)
219
+ cents_value = 0
220
+
221
+ # Add the main currency
222
+ if whole > 0:
223
+ result.append(self.to_cardinal(whole))
224
+ result.append(self.pluralize(whole, self.CURRENCY_FORMS[currency][0]))
225
+
226
+ # Add cents if present and cents=True
227
+ if cents_value > 0 and cents:
228
+ if whole > 0:
229
+ # Join the main currency part first, then add separator
230
+ main_part = ' '.join(result)
231
+ result = [main_part + separator]
232
+ # Handle fractional cents
233
+ from decimal import Decimal
234
+ if isinstance(cents_value, Decimal):
235
+ # Convert fractional cents (e.g., 65.3 cents)
236
+ result.append(self.to_cardinal_float(float(cents_value)))
237
+ result.append(self.pluralize(int(cents_value), self.CURRENCY_FORMS[currency][1]))
238
+ else:
239
+ result.append(self.to_cardinal(cents_value))
240
+ result.append(self.pluralize(cents_value, self.CURRENCY_FORMS[currency][1]))
241
+
242
+ if is_negative:
243
+ result.insert(0, self.negword.strip())
244
+
245
+ return ' '.join(result)
246
+ else:
247
+ # Fallback for unknown currency
248
+ return self.to_cardinal(val)
249
+
250
+ def to_year(self, value, **kwargs):
251
+ """Convert number to year format (same as cardinal for Albanian)."""
252
+ return self.to_cardinal(value)
num2words2/lang_SR.py ADDED
@@ -0,0 +1,254 @@
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
+ from .currency import parse_currency_parts
22
+ from .utils import get_digits, splitbyx
23
+
24
+ ZERO = ('нула',)
25
+
26
+ ONES = {
27
+ 1: ('један', 'једна'),
28
+ 2: ('два', 'две'),
29
+ 3: ('три', 'три'),
30
+ 4: ('четири', 'четири'),
31
+ 5: ('пет', 'пет'),
32
+ 6: ('шест', 'шест'),
33
+ 7: ('седам', 'седам'),
34
+ 8: ('осам', 'осам'),
35
+ 9: ('девет', 'девет'),
36
+ }
37
+
38
+ TENS = {
39
+ 0: ('десет',),
40
+ 1: ('једанаест',),
41
+ 2: ('дванаест',),
42
+ 3: ('тринаест',),
43
+ 4: ('четрнаест',),
44
+ 5: ('петнаест',),
45
+ 6: ('шеснаест',),
46
+ 7: ('седамнаест',),
47
+ 8: ('осамнаест',),
48
+ 9: ('деветнаест',),
49
+ }
50
+
51
+ TWENTIES = {
52
+ 2: ('двадесет',),
53
+ 3: ('тридесет',),
54
+ 4: ('четрдесет',),
55
+ 5: ('педесет',),
56
+ 6: ('шездесет',),
57
+ 7: ('седамдесет',),
58
+ 8: ('осамдесет',),
59
+ 9: ('деведесет',),
60
+ }
61
+
62
+ HUNDREDS = {
63
+ 1: ('сто',),
64
+ 2: ('двеста',),
65
+ 3: ('триста',),
66
+ 4: ('четиристо',),
67
+ 5: ('петсто',),
68
+ 6: ('шесто',),
69
+ 7: ('седамсто',),
70
+ 8: ('осамсто',),
71
+ 9: ('деветсто',),
72
+ }
73
+
74
+ SCALE = {
75
+ 0: ('', '', '', False),
76
+ 1: ('хиљада', 'хиљаде', 'хиљада', True), # 10^3
77
+ 2: ('милион', 'милиона', 'милиона', False), # 10^6
78
+ 3: ('милијарда', 'милијарде', 'милијарди', True), # 10^9 - using long scale
79
+ 4: ('билион', 'билиона', 'билиона', False), # 10^12
80
+ 5: ('билијарда', 'билијарде', 'билијарди', True), # 10^15
81
+ 6: ('трилион', 'трилиона', 'трилиона', False), # 10^18
82
+ 7: ('трилијарда', 'трилијарде', 'трилијарди', True), # 10^21
83
+ 8: ('квадрилион', 'квадрилиона', 'квадрилиона', False), # 10^24
84
+ 9: ('квадрилијарда', 'квадрилијарде', 'квадрилијарди', True), # 10^27
85
+ 10: ('квинтилион', 'квинтилиона', 'квинтилиона', False), # 10^30
86
+ }
87
+
88
+
89
+ class Num2Word_SR(Num2Word_Base):
90
+ CURRENCY_FORMS = {
91
+ 'RUB': (
92
+ ('rublja', 'rublje', 'rublji', True),
93
+ ('kopejka', 'kopejke', 'kopejki', True)
94
+ ),
95
+ 'EUR': (
96
+ ('evro', 'evra', 'evra', False),
97
+ ('cent', 'centa', 'centi', False)
98
+ ),
99
+ 'RSD': (
100
+ ('dinar', 'dinara', 'dinara', False),
101
+ ('para', 'pare', 'para', True)
102
+ ),
103
+ }
104
+
105
+ def setup(self):
106
+ self.negword = "минус"
107
+ self.pointword = "запета"
108
+
109
+ def to_cardinal(self, number, feminine=False):
110
+ n = str(number).replace(',', '.')
111
+ if '.' in n:
112
+ is_negative = n.startswith('-')
113
+ abs_n = n[1:] if is_negative else n
114
+ left, right = abs_n.split('.')
115
+ leading_zero_count = len(right) - len(right.lstrip('0'))
116
+ decimal_part = ((ZERO[0] + ' ') * leading_zero_count +
117
+ self._int2word(int(right), feminine))
118
+ result = u'%s %s %s' % (
119
+ self._int2word(int(left), feminine),
120
+ self.pointword,
121
+ decimal_part
122
+ )
123
+ if is_negative:
124
+ result = self.negword + ' ' + result
125
+ return result
126
+ else:
127
+ return self._int2word(int(n), feminine)
128
+
129
+ def pluralize(self, number, forms):
130
+ if number % 100 < 10 or number % 100 > 20:
131
+ if number % 10 == 1:
132
+ form = 0
133
+ elif 1 < number % 10 < 5:
134
+ form = 1
135
+ else:
136
+ form = 2
137
+ else:
138
+ form = 2
139
+ return forms[form]
140
+
141
+ def to_ordinal(self, number):
142
+ """Convert to Serbian ordinal numbers (Cyrillic)."""
143
+ try:
144
+ num = int(number)
145
+ except (ValueError, TypeError):
146
+ return str(number)
147
+
148
+ # Serbian ordinals in Cyrillic
149
+ ordinals = {
150
+ 1: 'први',
151
+ 2: 'други',
152
+ 3: 'трећи',
153
+ 4: 'четврти',
154
+ 5: 'пети',
155
+ 6: 'шести',
156
+ 7: 'седми',
157
+ 8: 'осми',
158
+ 9: 'девети',
159
+ 10: 'десети',
160
+ 11: 'једанаести',
161
+ 12: 'дванаести',
162
+ 13: 'тринаести',
163
+ 14: 'четрнаести',
164
+ 15: 'петнаести',
165
+ 16: 'шеснаести',
166
+ 17: 'седамнаести',
167
+ 18: 'осамнаести',
168
+ 19: 'деветнаести',
169
+ 20: 'двадесети',
170
+ 30: 'тридесети',
171
+ 40: 'четрдесети',
172
+ 50: 'педесети',
173
+ 60: 'шездесети',
174
+ 70: 'седамдесети',
175
+ 80: 'осамдесети',
176
+ 90: 'деведесети',
177
+ 100: 'стоти',
178
+ 1000: 'хиљадити',
179
+ }
180
+
181
+ if num in ordinals:
182
+ return ordinals[num]
183
+
184
+ # For other numbers, add 'и' suffix to the cardinal
185
+ # This is a simplified implementation
186
+ cardinal = self.to_cardinal(num)
187
+ return cardinal + 'и'
188
+
189
+ def _cents_verbose(self, number, currency):
190
+ return self._int2word(
191
+ number,
192
+ self.CURRENCY_FORMS[currency][1][-1]
193
+ )
194
+
195
+ def _int2word(self, number, feminine=False):
196
+ if number < 0:
197
+ return ' '.join([self.negword, self._int2word(abs(number))])
198
+
199
+ if number == 0:
200
+ return ZERO[0]
201
+
202
+ words = []
203
+ chunks = list(splitbyx(str(number), 3))
204
+ chunk_len = len(chunks)
205
+ for chunk in chunks:
206
+ chunk_len -= 1
207
+ digit_right, digit_mid, digit_left = get_digits(chunk)
208
+
209
+ if digit_left > 0:
210
+ words.append(HUNDREDS[digit_left][0])
211
+
212
+ if digit_mid > 1:
213
+ words.append(TWENTIES[digit_mid][0])
214
+
215
+ if digit_mid == 1:
216
+ words.append(TENS[digit_right][0])
217
+ elif digit_right > 0:
218
+ # Skip 'један' for thousands (1000, 1001, etc.)
219
+ if not (chunk_len > 0 and chunk == 1):
220
+ is_feminine = feminine or SCALE[chunk_len][-1]
221
+ gender_idx = int(is_feminine)
222
+ words.append(
223
+ ONES[digit_right][gender_idx]
224
+ )
225
+
226
+ if chunk_len > 0 and chunk != 0:
227
+ words.append(self.pluralize(chunk, SCALE[chunk_len]))
228
+
229
+ return ' '.join(words)
230
+
231
+ def to_currency(self, val, currency='RSD', cents=True, separator=',',
232
+ adjective=False):
233
+ # Handle integers specially - no cents
234
+ if isinstance(val, int):
235
+ # Get major currency part only
236
+ left, right, is_negative = parse_currency_parts(val, is_int_with_cents=False)
237
+ words = []
238
+ if is_negative:
239
+ words.append('минус')
240
+ words.append(self.to_cardinal(left))
241
+
242
+ # Add currency name based on the number
243
+ if left % 10 == 1 and left % 100 != 11:
244
+ words.append('динар')
245
+ elif 2 <= left % 10 <= 4 and not (12 <= left % 100 <= 14):
246
+ words.append('динара')
247
+ else:
248
+ words.append('динара')
249
+
250
+ return ' '.join(words)
251
+
252
+ # For floats, use parent implementation
253
+ return super().to_currency(val, currency=currency, cents=cents,
254
+ separator=separator, adjective=adjective)
num2words2/lang_SU.py ADDED
@@ -0,0 +1,136 @@
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
+ # Sundanese language support
24
+ class Num2Word_SU(Num2Word_Base):
25
+ CURRENCY_FORMS = {
26
+ 'IDR': (('rupiah', 'rupiah'), ('sen', 'sen')),
27
+ 'USD': (('dollar', 'dollars'), ('cent', 'cents')),
28
+ 'EUR': (('euro', 'euros'), ('cent', 'cents'))
29
+ }
30
+
31
+ def setup(self):
32
+ self.negword = "minus "
33
+ self.pointword = "point"
34
+ self.ones = ['', 'hiji', 'dua', 'tilu', 'opat', 'lima', 'genep', 'tujuh', 'dalapan', 'salapan']
35
+ self.tens = ['', 'sapuluh', 'dua puluh', 'tilu puluh', 'opat puluh', 'lima puluh', 'genep puluh', 'tujuh puluh', 'dalapan puluh', 'salapan puluh']
36
+ self.hundred = "ratus"
37
+ self.thousand = "rebu"
38
+ self.million = "juta"
39
+
40
+ def to_cardinal(self, number):
41
+ """Convert a number to its word representation in Sundanese."""
42
+ n = str(number).strip()
43
+
44
+ if n.startswith('-'):
45
+ n = n[1:]
46
+ ret = self.negword
47
+ else:
48
+ ret = ""
49
+
50
+ if '.' in n:
51
+ left, right = n.split('.', 1)
52
+ ret += self._int_to_word(int(left)) + " " + self.pointword + " "
53
+ for digit in right:
54
+ ret += self._int_to_word(int(digit)) + " "
55
+ return ret.strip()
56
+ else:
57
+ return (ret + self._int_to_word(int(n))).strip()
58
+
59
+ def _int_to_word(self, number):
60
+ """Convert an integer to its word representation in Sundanese."""
61
+ if number == 0:
62
+ return self.ones[0] if self.ones[0] else "zero"
63
+
64
+ if number < 0:
65
+ return self.negword + self._int_to_word(abs(number))
66
+ elif number < 10:
67
+ return self.ones[number]
68
+ elif number < 100:
69
+ tens_val = number // 10
70
+ ones_val = number % 10
71
+ if ones_val == 0:
72
+ return self.tens[tens_val]
73
+ else:
74
+ return self.tens[tens_val] + " " + self.ones[ones_val]
75
+ elif number < 1000:
76
+ hundreds_val = number // 100
77
+ remainder = number % 100
78
+ result = self.ones[hundreds_val] + " " + self.hundred
79
+ if remainder:
80
+ result += " " + self._int_to_word(remainder)
81
+ return result
82
+ elif number < 1000000:
83
+ thousands_val = number // 1000
84
+ remainder = number % 1000
85
+ result = self._int_to_word(thousands_val) + " " + self.thousand
86
+ if remainder:
87
+ result += " " + self._int_to_word(remainder)
88
+ return result
89
+ elif number < 1000000000:
90
+ millions_val = number // 1000000
91
+ remainder = number % 1000000
92
+ result = self._int_to_word(millions_val) + " " + self.million
93
+ if remainder:
94
+ result += " " + self._int_to_word(remainder)
95
+ return result
96
+ else:
97
+ return str(number) # Fallback for very large numbers
98
+
99
+ def to_ordinal(self, number):
100
+ """Convert to ordinal in Sundanese."""
101
+ cardinal = self.to_cardinal(number)
102
+ # Language-specific ordinal suffix
103
+ return cardinal + "-na"
104
+
105
+ def to_ordinal_num(self, number):
106
+ """Convert to abbreviated ordinal."""
107
+ return str(number) + "."
108
+
109
+ def to_year(self, val, longval=True):
110
+ """Convert to year in Sundanese."""
111
+ return self.to_cardinal(val)
112
+
113
+ def to_currency(self, val, currency='IDR', cents=True, separator=' ', adjective=False):
114
+ """Convert to currency in Sundanese."""
115
+ is_negative = False
116
+ if val < 0:
117
+ is_negative = True
118
+ val = abs(val)
119
+
120
+ parts = str(val).split('.')
121
+ left = int(parts[0]) if parts[0] else 0
122
+ right = int(parts[1][:2].ljust(2, '0')) if len(parts) > 1 and parts[1] else 0
123
+
124
+ cr1, cr2 = self.CURRENCY_FORMS.get(currency, list(self.CURRENCY_FORMS.values())[0])
125
+
126
+ left_str = self._int_to_word(left)
127
+ result = left_str + " " + (cr1[1] if left != 1 else cr1[0])
128
+
129
+ if cents and right:
130
+ cents_str = self._int_to_word(right)
131
+ result += separator + cents_str + " " + (cr2[1] if right != 1 else cr2[0])
132
+
133
+ if is_negative:
134
+ result = self.negword + result
135
+
136
+ return result.strip()