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_CY.py ADDED
@@ -0,0 +1,574 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2023, Johannes Heinecke. All Rights Reserved.
3
+
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15
+ # MA 02110-1301 USA
16
+
17
+ from __future__ import unicode_literals
18
+
19
+ from .lang_EUR import Num2Word_EUR
20
+
21
+ # Welsh numerals differs to many other languages since the counted
22
+ # object does not follow the numeral but is inserted between
23
+ # e.g. "23 hours" is
24
+ # tri awr ar hugain
25
+ # 3 hour on twenty
26
+ # in addition to that some numeral trigger a mutation on the following word
27
+ # either another numeral or the counted object
28
+ # (https://en.wikipedia.org/wiki/Consonant_mutation#Welsh)
29
+ # e.g. "23 dogs" (aspirated mutation, c -> ch)
30
+ # tri chi ar hugain
31
+ # 3 dog on twenty
32
+ # but "22 dogs" (soft mutation, c -> g)
33
+ # dau gi ar hugain
34
+ # 2 dog on twenty
35
+ # and "24 dogs" (no mutation)
36
+ # pedwar ci ar hugain
37
+ # 4 dog on twenty
38
+ # (BTW, the counted word is always in singular when following a numeral)
39
+ # numerals are mutated as well
40
+ # e.g. "300"
41
+ # tri chant
42
+ # 3 hundred
43
+ # "200"
44
+ # dau gant
45
+ # 2 hundred
46
+ # "500"
47
+ # pump cant
48
+ # 5 hundreds
49
+ # the numerals for 2, 3 and 4 are different in function of gender (MASC, FEM)
50
+ # 2 cats
51
+ # dwy gath
52
+
53
+ # 2 dogs
54
+ # dau gi
55
+
56
+ # 2000
57
+ # dwy fil
58
+
59
+ # 3000
60
+ # tair mil
61
+
62
+ # to add the counted object in the correct position use
63
+ # num2words(17, lang="cy", counted="ci", gender="masc")
64
+ # num2words(17, lang="cy", counted="cath", gender="fem")
65
+ # if the number is > 99, use plural form of counted object
66
+ # num2words(117, lang="cy", counted="cathod", gender="fem")
67
+
68
+
69
+ # Globals
70
+ # -------
71
+
72
+ OBJ = "__OBJECT__"
73
+
74
+ CARDINAL_WORDS = {
75
+ # masc, fem, triggers mutation
76
+ 0: [("dim", None), (OBJ, None)],
77
+ 1: [("un", None), (OBJ, None)],
78
+ 2: [("dau", "SM"), (OBJ, None)],
79
+ 3: [("tri", "AM"), (OBJ, None)],
80
+ 4: [("pedwar", None), (OBJ, None)],
81
+ 5: [("pump", None), (OBJ, None)],
82
+ 6: [("chwech", "AM"), (OBJ, None)],
83
+ 7: [("saith", None), (OBJ, None)],
84
+ 8: [("wyth", None), (OBJ, None)],
85
+ 9: [("naw", None), (OBJ, None)],
86
+ 10: [("deg", None), (OBJ, None)],
87
+ 11: [("un", None), (OBJ, None), ("ar ddeg", None)],
88
+ 12: [("deuddeg", None), (OBJ, None)],
89
+ 13: [("tri", "AM"), (OBJ, None), ("ar ddeg", None)],
90
+ 14: [("pedwar", None), (OBJ, None), ("ar ddeg", None)],
91
+ 15: [("pymtheg", None), (OBJ, None)],
92
+ 16: [("un", None), (OBJ, None), ("ar bymtheg", None)],
93
+ 17: [("dau", "SM"), (OBJ, None), ("ar bymtheg", None)],
94
+ 18: [("deunaw", None), (OBJ, None)],
95
+ 19: [("pedwar", None), ("ar bymtheg", None)],
96
+ }
97
+
98
+ CARDINAL_WORDS_FEM = {
99
+ # masc, fem, triggers mutation
100
+ 0: [("dim", None), (OBJ, None)],
101
+ 1: [("un", None), (OBJ, None)],
102
+ 2: [("dwy", "SM"), (OBJ, None)],
103
+ 3: [("tair", None), (OBJ, None)],
104
+ 4: [("pedair", None), (OBJ, None)],
105
+ 5: [("pump", None), (OBJ, None)],
106
+ 6: [("chwech", "AM"), (OBJ, None)],
107
+ 7: [("saith", None), (OBJ, None)],
108
+ 8: [("wyth", None), (OBJ, None)],
109
+ 9: [("naw", None), (OBJ, None)],
110
+ 10: [("deg", None), (OBJ, None)],
111
+ 11: [("un", None), (OBJ, None), ("ar ddeg", None)],
112
+ 12: [("deuddeg", None), (OBJ, None)],
113
+ 13: [("tair", None), (OBJ, None), ("ar ddeg", None)],
114
+ 14: [("pedair", None), (OBJ, None), ("ar ddeg", None)],
115
+ 15: [("pymtheg", None), (OBJ, None)],
116
+ 16: [("un", None), (OBJ, None), ("ar bymtheg", None)],
117
+ 17: [("dwy", "SM"), (OBJ, None), ("ar bymtheg", None)],
118
+ 18: [("deunaw", None), (OBJ, None)],
119
+ 19: [("pedair", None), ("ar bymtheg", None)],
120
+ }
121
+
122
+ MILLION_WORDS = {
123
+ 3: ("mil", None),
124
+ 6: ("miliwn", None),
125
+ 9: ("biliwn", None),
126
+ 12: ("triliwn", None),
127
+ 15: ("cwadriliwn", None),
128
+ 18: ("cwintiliwn", None),
129
+ 21: ("secsttiliwn", None),
130
+ 24: ("septiliwn", None),
131
+ 27: ("octiliwn", None),
132
+ 30: ("noniliwn", None),
133
+ 33: ("dengiliwn", None),
134
+ }
135
+
136
+ ORDINAL_WORDS = {
137
+ 0: [("dimfed", None), (OBJ, None)],
138
+ 1: [(OBJ, None), ("cyntaf", None)],
139
+ 2: [("ail", "SM"), (OBJ, None)],
140
+ 3: [("trydydd", None), (OBJ, None)],
141
+ 4: [("pedwerydd", None), (OBJ, None)],
142
+ 5: [("pumed", None), (OBJ, None)],
143
+ 6: [("chweched", None), (OBJ, None)],
144
+ 7: [("saithfed", None), (OBJ, None)],
145
+ 8: [("wythfed", None), (OBJ, None)],
146
+ 9: [("nawfed", None), (OBJ, None)],
147
+ 10: [("degfed", None), (OBJ, None)],
148
+ 11: [("unfed", "SM"), (OBJ, None), ("ar ddeg", None)],
149
+ 12: [("deuddegfed", None), (OBJ, None)],
150
+ 13: [("trydydd", None), (OBJ, None), ("ar ddeg", None)],
151
+ 14: [("pedwerydd", None), (OBJ, None), ("ar ddeg", None)],
152
+ 15: [("pymthegfed", None), (OBJ, None)],
153
+ 16: [("unfed", None), (OBJ, None), ("ar bymtheg", None)],
154
+ 17: [("ail", "SM"), (OBJ, None), ("ar bymtheg", None)],
155
+ 18: [("deunawfed", None), (OBJ, None)],
156
+ 19: [("pedwerydd", None), (OBJ, None), ("ar bymtheg", None)],
157
+ }
158
+ ORDINAL_WORDS_FEM = {
159
+ 0: [("dimfed", None), (OBJ, None)],
160
+ 1: [(OBJ, None), ("gyntaf", None)],
161
+ 2: [("ail", "SM"), (OBJ, None)],
162
+ 3: [("trydedd", "SM"), (OBJ, None)],
163
+ 4: [("pedwaredd", "SM"), (OBJ, None)],
164
+ 5: [("pumed", None), (OBJ, None)],
165
+ 6: [("chweched", None), (OBJ, None)],
166
+ 7: [("saithfed", None), (OBJ, None)],
167
+ 8: [("wythfed", None), (OBJ, None)],
168
+ 9: [("nawfed", None), (OBJ, None)],
169
+ 10: [("degfed", None), (OBJ, None)],
170
+ 11: [("unfed", "SM"), (OBJ, None), ("ar ddeg", None)],
171
+ 12: [("deuddegfed", None), (OBJ, None)],
172
+ 13: [("trydedd", "SM"), (OBJ, None), ("ar ddeg", None)],
173
+ 14: [("pedwaredd", "SM"), (OBJ, None), ("ar ddeg", None)],
174
+ 15: [("pymthegfed", None), (OBJ, None)],
175
+ 16: [("unfed", None), (OBJ, None), ("ar bymtheg", None)],
176
+ 17: [("ail", "SM"), (OBJ, None), ("ar bymtheg", None)],
177
+ 18: [("deunawfed", None), (OBJ, None)],
178
+ 19: [("pedwaredd", None), (OBJ, None), ("ar bymtheg", None)],
179
+ }
180
+
181
+ # The script can extrapolate the missing numbers from the base forms.
182
+ STR_TENS = {
183
+ 1: [("ugain", None), (OBJ, None)],
184
+ 2: [("deugain", None), (OBJ, None)],
185
+ 3: [("trigain", None), (OBJ, None)],
186
+ 4: [("pedwar ugain", None), (OBJ, None)],
187
+ }
188
+
189
+ ORD_STR_TENS = {
190
+ 1: [("ugainfed", None), (OBJ, None)],
191
+ 2: [("deugainfed", None), (OBJ, None)],
192
+ 3: [("trigainfed", None), (OBJ, None)],
193
+ 4: [("pedwar ugainfed", None), (OBJ, None)],
194
+ }
195
+
196
+ STR_TENS_INFORMAL = {
197
+ 1: ("undeg", None),
198
+ 2: ("dauddeg", None),
199
+ 3: ("trideg", None),
200
+ 4: ("pedwardeg", None),
201
+ 5: ("pumdeg", None),
202
+ 6: ("chwedeg", None),
203
+ 7: ("saithdeg", None),
204
+ 8: ("wythdeg", None),
205
+ 9: ("nawdeg", None),
206
+ }
207
+
208
+
209
+ GENERIC_DOLLARS = ("dolar", "dolarau")
210
+ GENERIC_CENTS = ("ceiniog", "ceiniogau")
211
+
212
+ CURRENCIES_FEM = ["GBP"]
213
+
214
+
215
+ class Num2Word_CY(Num2Word_EUR):
216
+ CURRENCY_FORMS = {
217
+ # currency code: (sg, pl), (sg, pl)
218
+ # in Welsh a noun after a numeral is ALWAYS in the singular
219
+ "EUR": (("euro", "euros"), GENERIC_CENTS),
220
+ "USD": (GENERIC_DOLLARS, GENERIC_CENTS),
221
+ "GBP": (("punt", "punnoedd"), ("ceiniog", "ceiniogau")),
222
+ "CNY": (("yuan", "yuans"), ("ffen", "ffens")),
223
+ }
224
+
225
+ MINUS_PREFIX_WORD = "meinws "
226
+ FLOAT_INFIX_WORD = " pwynt "
227
+
228
+ # def setup(self):
229
+ # Num2Word_EU.setup(self)
230
+
231
+ def __init__(self):
232
+ pass
233
+
234
+ def float_to_words(self, float_number):
235
+ # Check if negative
236
+ is_negative = float_number < 0
237
+ abs_float = abs(float_number)
238
+
239
+ # if ordinal:
240
+ # prefix = self.to_ordinal(int(abs_float))
241
+ # else:
242
+ prefix = self.to_cardinal(int(abs_float))
243
+ float_part = str(abs_float).split(".")[1]
244
+ postfix = " ".join(
245
+ # Drops the trailing zero and comma
246
+ [self.to_cardinal(int(c)) for c in float_part]
247
+ )
248
+ result = prefix + Num2Word_CY.FLOAT_INFIX_WORD + postfix
249
+
250
+ if is_negative:
251
+ result = "meinws " + result
252
+ return result
253
+
254
+ def hundred_group(
255
+ self, number, informal=False, gender="masc", ordinal=False
256
+ ):
257
+ hundreds = number // 100
258
+ until100 = number % 100 # 0 - 99
259
+ # list group of number words and mutation info (for the following word)
260
+ result = (
261
+ []
262
+ )
263
+ if gender == "fem":
264
+ CW = CARDINAL_WORDS_FEM
265
+ else:
266
+ if ordinal:
267
+ CW = ORDINAL_WORDS
268
+ else:
269
+ CW = CARDINAL_WORDS
270
+
271
+ if hundreds > 0:
272
+ if hundreds > 1:
273
+ result.extend((CARDINAL_WORDS[hundreds]))
274
+ result.extend([("cant", None), (OBJ, None)])
275
+ if until100:
276
+ if until100 in [
277
+ 1,
278
+ 8,
279
+ 11,
280
+ 16,
281
+ 20,
282
+ 21,
283
+ 31,
284
+ 36,
285
+ 41,
286
+ 48,
287
+ 61,
288
+ 68,
289
+ 71,
290
+ 81,
291
+ 88,
292
+ 91,
293
+ ]:
294
+ result.append(("ac", None))
295
+ else:
296
+ result.append(("a", "AM"))
297
+ if until100:
298
+ # if informal:
299
+ # pass
300
+ if not ordinal and until100 >= 50 and until100 <= 59:
301
+ units = number % 10
302
+ if hundreds > 0:
303
+ if units == 0:
304
+ result.append(("hanner", None))
305
+ elif units == 1:
306
+ result.extend([("hanner ac un", None), (OBJ, None)])
307
+ else:
308
+ result.append(("hanner a", "AM"))
309
+ result.extend(CW[units])
310
+ else:
311
+ if units == 0:
312
+ result.extend([("hanner cant", None), (OBJ, None)])
313
+ elif units == 1:
314
+ result.extend(
315
+ [("hanner cant ac un", None), (OBJ, None)]
316
+ )
317
+ else:
318
+ result.append(("hanner cant a", "AM"))
319
+ result.extend(CW[units])
320
+ else:
321
+ if (number < 20 and number > 0) or (
322
+ number == 0 and hundreds == 0
323
+ ):
324
+ if gender == "fem":
325
+ result.extend(CARDINAL_WORDS_FEM[int(number)])
326
+ else:
327
+ result.extend(CARDINAL_WORDS[int(number)])
328
+
329
+ else:
330
+ tens = until100 // 20
331
+ units = number % 20
332
+ if ordinal and units == 0:
333
+ degau = ORD_STR_TENS.get(tens)
334
+ else:
335
+ degau = STR_TENS.get(tens)
336
+
337
+ if units != 0:
338
+ if tens > 1:
339
+ result.extend(CW[units])
340
+ if degau:
341
+ result.append(("a", "AM"))
342
+ result.extend(degau)
343
+ else:
344
+ result.extend(CW[units])
345
+ if degau:
346
+ result.append(("ar", "SM"))
347
+ result.extend(degau)
348
+ elif degau:
349
+ result.extend(degau)
350
+ return result
351
+
352
+ def to_ordinal(self, number, informal=False, gender="masc"):
353
+ if number < 20:
354
+ return makestring(ORDINAL_WORDS[number])
355
+ if number == 100:
356
+ return "canfed"
357
+ elif number > 100:
358
+ raise NotImplementedError("The given number is too large.")
359
+
360
+ return self.to_cardinal(
361
+ number, informal=False, gender=gender, ordinal=True
362
+ )
363
+
364
+ def to_cardinal(
365
+ self,
366
+ number,
367
+ informal=False,
368
+ gender="masc",
369
+ ordinal=False,
370
+ counted=None,
371
+ raw=False,
372
+ ):
373
+ # Handle floats first, including negative floats
374
+ if isinstance(number, float):
375
+ return self.float_to_words(number)
376
+
377
+ negative = False
378
+ if number < 0:
379
+ negative = True
380
+ number = -1 * number
381
+ if number == 0:
382
+ if raw:
383
+ return CARDINAL_WORDS[0]
384
+ else:
385
+ return makestring(CARDINAL_WORDS[0])
386
+ elif not number < 999 * 10**33:
387
+ raise NotImplementedError("The given number is too large.")
388
+
389
+ # split in groups of 10**3
390
+ # groups of three digits starting from right (units (1 - 999),
391
+ # thousands, millions, ...)
392
+ groups = (
393
+ []
394
+ )
395
+ lowestgroup = (
396
+ None # find the lowest group of 3 digits > 0 for the ordinals
397
+ )
398
+ for pot in [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]:
399
+ gr = (number % 10**pot) // 10 ** (pot - 3)
400
+ groups.append((gr, pot))
401
+ if gr and not lowestgroup:
402
+ lowestgroup = gr
403
+ # print("groups", groups)
404
+
405
+ result = []
406
+ if negative:
407
+ result.append(("meinws", None))
408
+
409
+ for gr, pot in reversed(groups):
410
+ if gr:
411
+ # print("AAAA", gr, pot, gender)
412
+ if pot == 6:
413
+ g = "fem" # mil (1000) is feminine
414
+ elif pot == 3:
415
+ g = gender # units depend on the following noun
416
+ else:
417
+ g = "masc" # millions etc are masculine
418
+ # "mil" is feminine
419
+ if gr > 1 or pot == 3:
420
+ words = self.hundred_group(
421
+ gr,
422
+ informal=informal,
423
+ gender=g,
424
+ ordinal=ordinal and (lowestgroup == gr),
425
+ )
426
+ result += words
427
+ # print(">>>> ", words)
428
+ if pot > 3:
429
+ result.append(MILLION_WORDS[pot - 3])
430
+ if raw:
431
+ # need to be able trigger correct mutation on currencies
432
+ return result
433
+ else:
434
+ if number < 100:
435
+ return makestring(result, counted=counted)
436
+ else:
437
+ if counted:
438
+ result.extend([("o", "SM"), (counted, None)])
439
+ return makestring(result)
440
+
441
+ def to_currency(
442
+ self, val, currency="GBP", cents=True, separator=",", adjective=False
443
+ ):
444
+ # Handle integers specially - no cents
445
+ if isinstance(val, int):
446
+ minus_str = "minws " if val < 0 else ""
447
+ money_str = self.to_cardinal(abs(val))
448
+ # Simple currency name without cents
449
+ if abs(val) == 1:
450
+ currency_str = "bunt"
451
+ else:
452
+ currency_str = "bunnoedd"
453
+ return u'%s%s %s' % (minus_str, money_str, currency_str)
454
+
455
+ # For floats, call parent implementation
456
+ return super().to_currency(val, currency=currency, cents=cents,
457
+ separator=separator, adjective=adjective)
458
+
459
+ def _money_verbose(self, number, currency):
460
+ # used in super().to_currency(), we need to add gender
461
+ # here for feminine currencies
462
+ # if currency in CURRENCIES_FEM: # always true in this context
463
+ if number > 100:
464
+ m = self.to_cardinal(number, gender="fem", raw=True)
465
+ # if currency in self.CURRENCY_FORMS:
466
+ c = self.CURRENCY_FORMS[currency][0][1]
467
+ m.append(("o", "SM"))
468
+ m.append((c, None))
469
+ # else:
470
+ # c = currency
471
+ # m.append((c, None))
472
+ return makestring(m)
473
+ else:
474
+ # if number > 1:
475
+ m = self.to_cardinal(number, gender="fem", raw=True)
476
+ # elif number == 0:
477
+ # m = self.to_cardinal(number, gender="fem", raw=True)
478
+ # else:
479
+ # m = [(OBJ, None)]
480
+ # if currency in self.CURRENCY_FORMS:
481
+ c = self.CURRENCY_FORMS[currency][0][0]
482
+ # else:
483
+ # c = currency
484
+ # print("eeeeeeeee", m)
485
+ # m.append((c, None))
486
+ # print("fffffffff", m)
487
+ return makestring(m, counted=c)
488
+ # else:
489
+ # return self.to_cardinal(number, raw=True)
490
+
491
+ def _cents_verbose(self, number, currency):
492
+ if number == 0:
493
+ return ""
494
+ # elif number > 100:
495
+ # m = self.to_cardinal(number, raw=True)
496
+ # # if currency in self.CURRENCY_FORMS:
497
+ # c = self.CURRENCY_FORMS[currency][0][1]
498
+ # m.append(("o", "SM"))
499
+ # m.append((c, None))
500
+ # # else:
501
+ # # c = currency
502
+ # # m.append((c, None))
503
+ # return makestring(m)
504
+ else:
505
+ if number > 1:
506
+ m = self.to_cardinal(number, raw=True)
507
+ else:
508
+ m = [(OBJ, None)]
509
+ # if currency in self.CURRENCY_FORMS:
510
+ c = self.CURRENCY_FORMS[currency][1][0]
511
+ # else:
512
+ # c = currency
513
+ return makestring(m, counted=c)
514
+
515
+
516
+ def makestring(result, counted=None):
517
+ # concatenate numberwords with correct mutation
518
+ out = []
519
+ lastmut = None
520
+ for w, mut in result:
521
+ if w == OBJ:
522
+ if not counted:
523
+ continue
524
+ else:
525
+ w = counted
526
+ counted = None # only first position
527
+ if lastmut:
528
+ out.append(mutate(w, lastmut))
529
+ else:
530
+ out.append(w)
531
+ lastmut = mut
532
+ return " ".join(out)
533
+
534
+
535
+ def mutate(word, mutation):
536
+ # print("uuu", word, mutation)
537
+ if mutation == "SM":
538
+ return softmutation(word)
539
+ elif mutation == "AM":
540
+ return aspiratedmutation(word)
541
+ # return word # does not occur
542
+
543
+
544
+ def softmutation(word):
545
+ # print("SM<<<<%s>" % word)
546
+ if word[0] == "p" and word[1] != "h":
547
+ return "b" + word[1:]
548
+ elif word[0] == "t" and word[1] != "h":
549
+ return "d" + word[1:]
550
+ elif word[0] == "c" and word[1] != "h":
551
+ return "g" + word[1:]
552
+ elif word[0] == "b" or word[0] == "m":
553
+ return "f" + word[1:]
554
+ elif word[0] == "d" and word[1] != "d":
555
+ return "d" + word
556
+ elif word.startswith("ll"):
557
+ return word[1:]
558
+ elif word.startswith("rh"):
559
+ return "r" + word[2:]
560
+ elif word == "ugain":
561
+ return "hugain"
562
+ else:
563
+ return word
564
+
565
+
566
+ def aspiratedmutation(word):
567
+ if word[0] == "p" and word[1] != "h":
568
+ return "ph" + word[1:]
569
+ elif word[0] == "t" and word[1] != "h":
570
+ return "th" + word[1:]
571
+ elif word[0] == "c" and word[1] != "h":
572
+ return "ch" + word[1:]
573
+ else:
574
+ return word