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_SN.py ADDED
@@ -0,0 +1,447 @@
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
+ """
19
+ Module for converting numbers to words in Shona (chiShona).
20
+ Shona is a Bantu language spoken in Zimbabwe and Mozambique.
21
+ """
22
+
23
+ from __future__ import unicode_literals
24
+
25
+ from .base import Num2Word_Base
26
+
27
+
28
+ class Num2Word_SN(Num2Word_Base):
29
+ """Convert numbers to Shona words."""
30
+
31
+ CURRENCY_FORMS = {
32
+ 'USD': (
33
+ ('dhora', 'madhora'), ('sendi', 'masendi')
34
+ ),
35
+ 'ZWL': (
36
+ ('dhora', 'madhora'), ('sendi', 'masendi')
37
+ ),
38
+ 'ZAR': (
39
+ ('randi', 'marandi'), ('sendi', 'masendi')
40
+ ),
41
+ }
42
+
43
+ def __init__(self):
44
+ # Basic numbers 0-10
45
+ self.ones = {
46
+ 0: 'zero',
47
+ 1: 'motsi',
48
+ 2: 'piri',
49
+ 3: 'tatu',
50
+ 4: 'china',
51
+ 5: 'shanu',
52
+ 6: 'tanhatu',
53
+ 7: 'nomwe',
54
+ 8: 'sere',
55
+ 9: 'pfumbamwe',
56
+ 10: 'gumi'
57
+ }
58
+
59
+ # Forms used after "ne" (and)
60
+ self.ones_after_ne = {
61
+ 0: 'zero',
62
+ 1: 'imwe',
63
+ 2: 'piri',
64
+ 3: 'tatu',
65
+ 4: 'china',
66
+ 5: 'shanu',
67
+ 6: 'nhatu',
68
+ 7: 'nomwe',
69
+ 8: 'sere',
70
+ 9: 'pfumbamwe',
71
+ 10: 'gumi'
72
+ }
73
+
74
+ # Numbers for tens when used in compound forms
75
+ self.tens_forms = {
76
+ 2: 'maviri',
77
+ 3: 'matatu',
78
+ 4: 'mana',
79
+ 5: 'mashanu',
80
+ 6: 'matanhatu',
81
+ 7: 'manomwe',
82
+ 8: 'masere',
83
+ 9: 'mapfumbamwe'
84
+ }
85
+
86
+ # Ordinal numbers
87
+ self.ordinals = {
88
+ 1: 'wekutanga',
89
+ 2: 'wechipiri',
90
+ 3: 'wechitatu',
91
+ 4: 'wechina',
92
+ 5: 'wechishanu',
93
+ 6: 'wechitanhatu',
94
+ 7: 'wechinomwe',
95
+ 8: 'wechisere',
96
+ 9: 'wechipfumbamwe',
97
+ 10: 'wegumi'
98
+ }
99
+
100
+ # Large number scales
101
+ self.scale = {
102
+ 100: 'zana',
103
+ 1000: 'churu',
104
+ 1000000: 'miriyoni',
105
+ 1000000000: 'bhiriyoni',
106
+ 1000000000000: 'tiriyoni'
107
+ }
108
+
109
+ super(Num2Word_SN, self).__init__()
110
+
111
+ def setup(self):
112
+ super(Num2Word_SN, self).setup()
113
+ self.negword = "minus"
114
+ self.pointword = "poindi"
115
+
116
+ def _int_to_sn_word(self, number):
117
+ """Convert an integer to Shona words."""
118
+
119
+ if number == 0:
120
+ return self.ones[0]
121
+
122
+ if number < 0:
123
+ return self.negword + " " + self._int_to_sn_word(-number)
124
+
125
+ if number <= 10:
126
+ return self.ones[number]
127
+
128
+ # Numbers 11-19
129
+ if number < 20:
130
+ return "gumi ne" + self.ones_after_ne[number - 10]
131
+
132
+ # Numbers 20-99
133
+ if number < 100:
134
+ tens, units = divmod(number, 10)
135
+ if units == 0:
136
+ return "makumi " + self.tens_forms[tens]
137
+ else:
138
+ return ("makumi " + self.tens_forms[tens] + " ne" +
139
+ self.ones_after_ne[units])
140
+
141
+ # Numbers 100-999
142
+ if number < 1000:
143
+ hundreds, remainder = divmod(number, 100)
144
+ if hundreds == 1:
145
+ if remainder == 0:
146
+ return "zana"
147
+ else:
148
+ # Use ones_after_ne for single digits
149
+ if remainder < 10:
150
+ return "zana ne" + self.ones_after_ne[remainder]
151
+ else:
152
+ return "zana ne" + self._int_to_sn_word(remainder)
153
+ else:
154
+ if remainder == 0:
155
+ return "mazana " + self.tens_forms[hundreds]
156
+ else:
157
+ return ("mazana " + self.tens_forms[hundreds] + " ne" +
158
+ self._int_to_sn_word(remainder))
159
+
160
+ # Numbers 1000-9999
161
+ if number < 10000:
162
+ thousands, remainder = divmod(number, 1000)
163
+ if thousands == 1:
164
+ if remainder == 0:
165
+ return "churu"
166
+ else:
167
+ # Use ones_after_ne for single digits
168
+ if remainder < 10:
169
+ return "churu ne" + self.ones_after_ne[remainder]
170
+ else:
171
+ return "churu ne" + self._int_to_sn_word(remainder)
172
+ else:
173
+ if remainder == 0:
174
+ if thousands < 10:
175
+ return ("zvuru zvi" +
176
+ self._get_thousands_form(thousands))
177
+
178
+ else:
179
+ return "zvuru " + self._int_to_sn_word(thousands)
180
+ else:
181
+ if thousands < 10:
182
+ return ("zvuru zvi" +
183
+ self._get_thousands_form(thousands) +
184
+ " ne" + self._int_to_sn_word(remainder))
185
+ else:
186
+ return ("zvuru " + self._int_to_sn_word(thousands) +
187
+ " ne" + self._int_to_sn_word(remainder))
188
+
189
+ # Numbers 10000-99999
190
+ if number < 100000:
191
+ ten_thousands, remainder = divmod(number, 1000)
192
+ if remainder == 0:
193
+ return "zvuru " + self._int_to_sn_word(ten_thousands)
194
+ else:
195
+ # Use ones_after_ne for single digit remainders
196
+ if remainder < 10:
197
+ return ("zvuru " + self._int_to_sn_word(ten_thousands) +
198
+ " ne" + self.ones_after_ne[remainder])
199
+ else:
200
+ return ("zvuru " + self._int_to_sn_word(ten_thousands) +
201
+ " ne" + self._int_to_sn_word(remainder))
202
+
203
+ # Numbers 100000-999999
204
+ if number < 1000000:
205
+ hundred_thousands, remainder = divmod(number, 1000)
206
+ if remainder == 0:
207
+ return "zvuru " + self._int_to_sn_word(hundred_thousands)
208
+ else:
209
+ return ("zvuru " + self._int_to_sn_word(hundred_thousands) +
210
+ " ne" + self._int_to_sn_word(remainder))
211
+
212
+ # Millions
213
+ if number < 1000000000:
214
+ millions, remainder = divmod(number, 1000000)
215
+ if millions == 1:
216
+ if remainder == 0:
217
+ return "miriyoni"
218
+ else:
219
+ # Use ones_after_ne for single digits
220
+ if remainder < 10:
221
+ return "miriyoni ne" + self.ones_after_ne[remainder]
222
+ else:
223
+ return "miriyoni ne" + self._int_to_sn_word(remainder)
224
+ else:
225
+ if remainder == 0:
226
+ if millions == 2:
227
+ return "miriyoni mbiri"
228
+ elif millions < 10:
229
+ base = (self.ones[millions] if millions in self.ones
230
+ else self._int_to_sn_word(millions))
231
+ return "miriyoni " + base
232
+
233
+ else:
234
+ return "miriyoni " + self._int_to_sn_word(millions)
235
+ else:
236
+ if millions == 2:
237
+ return ("miriyoni mbiri ne" +
238
+ self._int_to_sn_word(remainder))
239
+ elif millions < 10:
240
+ base = (self.ones[millions] if millions in self.ones
241
+ else self._int_to_sn_word(millions))
242
+ return ("miriyoni " + base + " ne" +
243
+ self._int_to_sn_word(remainder))
244
+ else:
245
+ return ("miriyoni " + self._int_to_sn_word(millions) +
246
+ " ne" + self._int_to_sn_word(remainder))
247
+
248
+ # Billions
249
+ if number < 1000000000000:
250
+ billions, remainder = divmod(number, 1000000000)
251
+ if billions == 1:
252
+ if remainder == 0:
253
+ return "bhiriyoni"
254
+ else:
255
+ return "bhiriyoni ne" + self._int_to_sn_word(remainder)
256
+ else:
257
+ base = ("mbiri" if billions == 2
258
+ else self.ones[billions] if billions < 10
259
+ else self._int_to_sn_word(billions))
260
+ if remainder == 0:
261
+ return "bhiriyoni " + base
262
+ else:
263
+ return ("bhiriyoni " + base + " ne" +
264
+ self._int_to_sn_word(remainder))
265
+
266
+ # Trillions
267
+ trillions, remainder = divmod(number, 1000000000000)
268
+ if trillions == 1:
269
+ if remainder == 0:
270
+ return "tiriyoni"
271
+ else:
272
+ return "tiriyoni ne" + self._int_to_sn_word(remainder)
273
+ else:
274
+ base = ("mbiri" if trillions == 2
275
+ else self.ones[trillions] if trillions < 10
276
+ else self._int_to_sn_word(trillions))
277
+ if remainder == 0:
278
+ return "tiriyoni " + base
279
+ else:
280
+ return ("tiriyoni " + base + " ne" +
281
+ self._int_to_sn_word(remainder))
282
+
283
+ def _get_thousands_form(self, number):
284
+ """Get the special form for thousands (zvuru zvi...)"""
285
+ thousands_forms = {
286
+ 2: 'viri',
287
+ 3: 'tatu',
288
+ 4: 'na',
289
+ 5: 'shanu',
290
+ 6: 'tanhatu',
291
+ 7: 'nomwe',
292
+ 8: 'sere',
293
+ 9: 'pfumbamwe'
294
+ }
295
+ return thousands_forms.get(number, self.ones[number])
296
+
297
+ def to_cardinal(self, number):
298
+ """Convert a number to its cardinal representation."""
299
+ try:
300
+ if isinstance(number, str):
301
+ number = int(number)
302
+
303
+ # Handle floats
304
+ if isinstance(number, float):
305
+ return self.to_cardinal_float(number)
306
+
307
+ return self._int_to_sn_word(number)
308
+
309
+ except Exception:
310
+ return self._int_to_sn_word(int(number))
311
+
312
+ def to_cardinal_float(self, number):
313
+ """Convert a float to its cardinal representation."""
314
+ sign = ""
315
+ if number < 0:
316
+ sign = self.negword + " "
317
+ number = abs(number)
318
+
319
+ integer_part = int(number)
320
+ decimal_part = str(number).split('.')[1] if '.' in str(number) else ''
321
+
322
+ result = self._int_to_sn_word(integer_part)
323
+
324
+ if decimal_part:
325
+ result += " " + self.pointword
326
+ for digit in decimal_part:
327
+ result += " " + self.ones[int(digit)]
328
+
329
+ if sign:
330
+ return sign + result
331
+ return result
332
+
333
+ def to_ordinal(self, number):
334
+ """Convert a number to its ordinal representation."""
335
+ # For simple ordinals (1-10), use the direct mapping
336
+ if number in self.ordinals:
337
+ return self.ordinals[number]
338
+
339
+ # For larger numbers, add "we" prefix to the cardinal
340
+ cardinal = self._int_to_sn_word(number)
341
+
342
+ # Handle special cases for ordinals
343
+ if cardinal.startswith("gumi"):
344
+ return "we" + cardinal
345
+ elif cardinal.startswith("makumi"):
346
+ return "we" + cardinal # Just add "we" prefix
347
+ elif cardinal.startswith("zana"):
348
+ return "we" + cardinal
349
+ elif cardinal.startswith("mazana"):
350
+ return "we" + cardinal[2:] # Remove "ma" prefix
351
+ elif cardinal.startswith("churu"):
352
+ return "we" + cardinal
353
+ elif cardinal.startswith("zvuru"):
354
+ return "we" + cardinal[2:] # Remove "zv" prefix
355
+ else:
356
+ return "we" + cardinal
357
+
358
+ def to_ordinal_num(self, number):
359
+ """Convert a number to its abbreviated ordinal form."""
360
+ # Shona doesn't typically use abbreviated ordinals like "1st", "2nd"
361
+ # Return the number with a suffix indicator
362
+ return str(number) + "."
363
+
364
+ def to_currency(self, n, currency='USD', cents=True, separator='ne'):
365
+ """Convert a number to a currency representation."""
366
+ result = []
367
+ value = self.float_to_value(n)
368
+
369
+ # Check if value has fractional cents
370
+ from decimal import Decimal
371
+ decimal_val = Decimal(str(n))
372
+ has_fractional_cents = (decimal_val * 100) % 1 != 0
373
+
374
+ if value < 0:
375
+ result.append(self.negword)
376
+ value = abs(value)
377
+
378
+ integer_part, decimal_part = self._split_currency(value, has_fractional_cents)
379
+
380
+ # Get currency forms
381
+ if currency not in self.CURRENCY_FORMS:
382
+ raise NotImplementedError(
383
+ f"Currency {currency} not implemented for Shona")
384
+
385
+ currency_forms = self.CURRENCY_FORMS[currency]
386
+ major_singular, major_plural = currency_forms[0]
387
+ minor_singular, minor_plural = currency_forms[1]
388
+
389
+ # Major currency unit
390
+ if integer_part == 1:
391
+ result.append(major_singular + " rimwe")
392
+ else:
393
+ # Use cardinal form but with "ma" prefix and appropriate forms
394
+ cardinal = self._int_to_sn_word(integer_part)
395
+ # Special handling for smaller numbers
396
+ if integer_part == 2:
397
+ result.append("ma" + major_singular + " maviri")
398
+ elif integer_part < 10 and integer_part in self.ones:
399
+ # Use tens_forms for consistency
400
+ if integer_part in self.tens_forms:
401
+ result.append("ma" + major_singular + " " +
402
+ self.tens_forms[integer_part])
403
+ else:
404
+ result.append("ma" + major_singular + " " + cardinal)
405
+ else:
406
+ result.append("ma" + major_singular + " " + cardinal)
407
+
408
+ # Minor currency unit (cents)
409
+ if cents and decimal_part:
410
+ # Handle fractional cents
411
+ from decimal import Decimal
412
+ if isinstance(decimal_part, Decimal):
413
+ # Convert fractional cents (e.g., 65.3 cents)
414
+ result.append(separator + minor_singular + " " +
415
+ self.to_cardinal_float(float(decimal_part)))
416
+ elif decimal_part == 1:
417
+ result.append(separator + minor_singular + " rimwe")
418
+ else:
419
+ # For cents, use minor_singular without "ma" prefix
420
+ result.append(separator + minor_singular + " " +
421
+ self._int_to_sn_word(decimal_part))
422
+
423
+ return " ".join(result)
424
+
425
+ def _split_currency(self, value, has_fractional_cents=False):
426
+ """Split a currency value into integer and decimal parts."""
427
+ if has_fractional_cents:
428
+ # Keep precision for fractional cents
429
+ from decimal import Decimal
430
+ decimal_val = Decimal(str(value))
431
+ integer_part = int(decimal_val)
432
+ decimal_part = decimal_val * 100 - (integer_part * 100)
433
+ else:
434
+ integer_part = int(value)
435
+ decimal_part = int(round((value - integer_part) * 100))
436
+ return integer_part, decimal_part
437
+
438
+ def to_year(self, number):
439
+ """Convert a number to a year representation."""
440
+ # In Shona, years are typically expressed as regular cardinal numbers
441
+ return self._int_to_sn_word(number)
442
+
443
+ def float_to_value(self, n):
444
+ """Convert string or float to float value."""
445
+ if isinstance(n, str):
446
+ return float(n)
447
+ return n
num2words2/lang_SO.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
+ # Somali language support
24
+ class Num2Word_SO(Num2Word_Base):
25
+ CURRENCY_FORMS = {
26
+ 'SOS': (('shilin', 'shilin'), ('sent', 'sent')),
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 = ['', 'kow', 'laba', 'saddex', 'afar', 'shan', 'lix', 'toddoba', 'siddeed', 'sagaal']
35
+ self.tens = ['', 'toban', 'labaatan', 'soddon', 'afartan', 'konton', 'lixdan', 'toddobaatan', 'siddeetan', 'sagaashan']
36
+ self.hundred = "boqol"
37
+ self.thousand = "kun"
38
+ self.million = "milyan"
39
+
40
+ def to_cardinal(self, number):
41
+ """Convert a number to its word representation in Somali."""
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 Somali."""
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 Somali."""
101
+ cardinal = self.to_cardinal(number)
102
+ # Language-specific ordinal suffix
103
+ return cardinal + "-aad"
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 Somali."""
111
+ return self.to_cardinal(val)
112
+
113
+ def to_currency(self, val, currency='SOS', cents=True, separator=' ', adjective=False):
114
+ """Convert to currency in Somali."""
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()