n2words 1.23.1 → 2.0.0

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 (322) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +317 -59
  3. package/dist/ArabicConverter.js +3 -0
  4. package/dist/ArabicConverter.js.map +1 -0
  5. package/dist/AzerbaijaniConverter.js +3 -0
  6. package/dist/AzerbaijaniConverter.js.map +1 -0
  7. package/dist/BanglaConverter.js +3 -0
  8. package/dist/BanglaConverter.js.map +1 -0
  9. package/dist/BiblicalHebrewConverter.js +3 -0
  10. package/dist/BiblicalHebrewConverter.js.map +1 -0
  11. package/dist/CroatianConverter.js +3 -0
  12. package/dist/CroatianConverter.js.map +1 -0
  13. package/dist/CzechConverter.js +3 -0
  14. package/dist/CzechConverter.js.map +1 -0
  15. package/dist/DanishConverter.js +3 -0
  16. package/dist/DanishConverter.js.map +1 -0
  17. package/dist/DutchConverter.js +3 -0
  18. package/dist/DutchConverter.js.map +1 -0
  19. package/dist/EnglishConverter.js +3 -0
  20. package/dist/EnglishConverter.js.map +1 -0
  21. package/dist/FilipinoConverter.js +3 -0
  22. package/dist/FilipinoConverter.js.map +1 -0
  23. package/dist/FrenchBelgiumConverter.js +3 -0
  24. package/dist/FrenchBelgiumConverter.js.map +1 -0
  25. package/dist/FrenchConverter.js +3 -0
  26. package/dist/FrenchConverter.js.map +1 -0
  27. package/dist/GermanConverter.js +3 -0
  28. package/dist/GermanConverter.js.map +1 -0
  29. package/dist/GreekConverter.js +3 -0
  30. package/dist/GreekConverter.js.map +1 -0
  31. package/dist/GujaratiConverter.js +3 -0
  32. package/dist/GujaratiConverter.js.map +1 -0
  33. package/dist/HebrewConverter.js +3 -0
  34. package/dist/HebrewConverter.js.map +1 -0
  35. package/dist/HindiConverter.js +3 -0
  36. package/dist/HindiConverter.js.map +1 -0
  37. package/dist/HungarianConverter.js +3 -0
  38. package/dist/HungarianConverter.js.map +1 -0
  39. package/dist/IndonesianConverter.js +3 -0
  40. package/dist/IndonesianConverter.js.map +1 -0
  41. package/dist/ItalianConverter.js +3 -0
  42. package/dist/ItalianConverter.js.map +1 -0
  43. package/dist/JapaneseConverter.js +3 -0
  44. package/dist/JapaneseConverter.js.map +1 -0
  45. package/dist/KannadaConverter.js +3 -0
  46. package/dist/KannadaConverter.js.map +1 -0
  47. package/dist/KoreanConverter.js +3 -0
  48. package/dist/KoreanConverter.js.map +1 -0
  49. package/dist/LatvianConverter.js +3 -0
  50. package/dist/LatvianConverter.js.map +1 -0
  51. package/dist/LithuanianConverter.js +3 -0
  52. package/dist/LithuanianConverter.js.map +1 -0
  53. package/dist/MalayConverter.js +3 -0
  54. package/dist/MalayConverter.js.map +1 -0
  55. package/dist/MarathiConverter.js +3 -0
  56. package/dist/MarathiConverter.js.map +1 -0
  57. package/dist/NorwegianBokmalConverter.js +3 -0
  58. package/dist/NorwegianBokmalConverter.js.map +1 -0
  59. package/dist/PersianConverter.js +3 -0
  60. package/dist/PersianConverter.js.map +1 -0
  61. package/dist/PolishConverter.js +3 -0
  62. package/dist/PolishConverter.js.map +1 -0
  63. package/dist/PortugueseConverter.js +3 -0
  64. package/dist/PortugueseConverter.js.map +1 -0
  65. package/dist/PunjabiConverter.js +3 -0
  66. package/dist/PunjabiConverter.js.map +1 -0
  67. package/dist/RomanianConverter.js +3 -0
  68. package/dist/RomanianConverter.js.map +1 -0
  69. package/dist/RussianConverter.js +3 -0
  70. package/dist/RussianConverter.js.map +1 -0
  71. package/dist/SerbianCyrillicConverter.js +3 -0
  72. package/dist/SerbianCyrillicConverter.js.map +1 -0
  73. package/dist/SerbianLatinConverter.js +3 -0
  74. package/dist/SerbianLatinConverter.js.map +1 -0
  75. package/dist/SimplifiedChineseConverter.js +3 -0
  76. package/dist/SimplifiedChineseConverter.js.map +1 -0
  77. package/dist/SpanishConverter.js +3 -0
  78. package/dist/SpanishConverter.js.map +1 -0
  79. package/dist/SwahiliConverter.js +3 -0
  80. package/dist/SwahiliConverter.js.map +1 -0
  81. package/dist/SwedishConverter.js +3 -0
  82. package/dist/SwedishConverter.js.map +1 -0
  83. package/dist/TamilConverter.js +3 -0
  84. package/dist/TamilConverter.js.map +1 -0
  85. package/dist/TeluguConverter.js +3 -0
  86. package/dist/TeluguConverter.js.map +1 -0
  87. package/dist/ThaiConverter.js +3 -0
  88. package/dist/ThaiConverter.js.map +1 -0
  89. package/dist/TraditionalChineseConverter.js +3 -0
  90. package/dist/TraditionalChineseConverter.js.map +1 -0
  91. package/dist/TurkishConverter.js +3 -0
  92. package/dist/TurkishConverter.js.map +1 -0
  93. package/dist/UkrainianConverter.js +3 -0
  94. package/dist/UkrainianConverter.js.map +1 -0
  95. package/dist/UrduConverter.js +3 -0
  96. package/dist/UrduConverter.js.map +1 -0
  97. package/dist/VietnameseConverter.js +3 -0
  98. package/dist/VietnameseConverter.js.map +1 -0
  99. package/dist/n2words.js +3 -2
  100. package/dist/n2words.js.map +1 -1
  101. package/lib/classes/abstract-language.d.ts +158 -34
  102. package/lib/classes/abstract-language.js +223 -115
  103. package/lib/classes/greedy-scale-language.d.ts +109 -0
  104. package/lib/classes/greedy-scale-language.js +201 -0
  105. package/lib/classes/slavic-language.d.ts +148 -0
  106. package/lib/classes/slavic-language.js +281 -0
  107. package/lib/classes/south-asian-language.d.ts +70 -0
  108. package/lib/classes/south-asian-language.js +154 -0
  109. package/lib/classes/turkic-language.d.ts +26 -0
  110. package/lib/classes/turkic-language.js +59 -0
  111. package/lib/languages/ar.d.ts +30 -0
  112. package/lib/languages/ar.js +159 -0
  113. package/lib/languages/az.d.ts +12 -0
  114. package/lib/languages/az.js +42 -0
  115. package/lib/languages/bn.d.ts +11 -0
  116. package/lib/languages/bn.js +131 -0
  117. package/lib/languages/cs.d.ts +88 -0
  118. package/lib/languages/cs.js +143 -0
  119. package/lib/languages/da.d.ts +15 -0
  120. package/lib/languages/da.js +120 -0
  121. package/lib/languages/de.d.ts +14 -0
  122. package/lib/languages/de.js +101 -0
  123. package/lib/languages/el.d.ts +14 -0
  124. package/lib/languages/el.js +90 -0
  125. package/lib/languages/en.d.ts +16 -0
  126. package/lib/languages/en.js +86 -0
  127. package/lib/languages/es.d.ts +15 -0
  128. package/lib/languages/es.js +121 -0
  129. package/lib/languages/fa.d.ts +47 -0
  130. package/lib/languages/fa.js +144 -0
  131. package/lib/languages/fil.d.ts +16 -0
  132. package/lib/languages/fil.js +121 -0
  133. package/lib/languages/fr-BE.d.ts +11 -0
  134. package/lib/languages/fr-BE.js +25 -0
  135. package/lib/languages/fr.d.ts +15 -0
  136. package/lib/languages/fr.js +106 -0
  137. package/lib/languages/gu.d.ts +11 -0
  138. package/lib/languages/gu.js +132 -0
  139. package/lib/languages/hbo.d.ts +113 -0
  140. package/lib/languages/hbo.js +251 -0
  141. package/lib/languages/he.d.ts +80 -0
  142. package/lib/languages/he.js +206 -0
  143. package/lib/languages/hi.d.ts +11 -0
  144. package/lib/languages/hi.js +131 -0
  145. package/lib/languages/hr.d.ts +80 -0
  146. package/lib/languages/hr.js +113 -0
  147. package/lib/languages/hu.d.ts +22 -0
  148. package/lib/languages/hu.js +137 -0
  149. package/lib/languages/id.d.ts +37 -0
  150. package/lib/languages/id.js +159 -0
  151. package/lib/languages/it.d.ts +37 -0
  152. package/lib/languages/it.js +132 -0
  153. package/lib/languages/ja.d.ts +17 -0
  154. package/lib/languages/ja.js +137 -0
  155. package/lib/languages/kn.d.ts +11 -0
  156. package/lib/languages/kn.js +42 -0
  157. package/lib/languages/ko.d.ts +14 -0
  158. package/lib/languages/ko.js +55 -0
  159. package/lib/{i18n/pl.d.ts → languages/lt.d.ts} +18 -15
  160. package/lib/languages/lt.js +136 -0
  161. package/lib/{i18n/lt.d.ts → languages/lv.d.ts} +16 -14
  162. package/lib/languages/lv.js +130 -0
  163. package/lib/languages/mr.d.ts +11 -0
  164. package/lib/languages/mr.js +132 -0
  165. package/lib/languages/ms.d.ts +31 -0
  166. package/lib/languages/ms.js +150 -0
  167. package/lib/languages/nb.d.ts +12 -0
  168. package/lib/languages/nb.js +100 -0
  169. package/lib/languages/nl.d.ts +16 -0
  170. package/lib/languages/nl.js +155 -0
  171. package/lib/languages/pa.d.ts +11 -0
  172. package/lib/languages/pa.js +131 -0
  173. package/lib/{i18n/uk.d.ts → languages/pl.d.ts} +16 -14
  174. package/lib/languages/pl.js +110 -0
  175. package/lib/languages/pt.d.ts +29 -0
  176. package/lib/languages/pt.js +112 -0
  177. package/lib/languages/ro.d.ts +158 -0
  178. package/lib/languages/ro.js +273 -0
  179. package/lib/languages/ru.d.ts +85 -0
  180. package/lib/languages/ru.js +96 -0
  181. package/lib/languages/sr-Cyrl.d.ts +80 -0
  182. package/lib/languages/sr-Cyrl.js +113 -0
  183. package/lib/{i18n/cz.d.ts → languages/sr-Latn.d.ts} +26 -14
  184. package/lib/languages/sr-Latn.js +113 -0
  185. package/lib/languages/sv.d.ts +14 -0
  186. package/lib/languages/sv.js +90 -0
  187. package/lib/languages/sw.d.ts +39 -0
  188. package/lib/languages/sw.js +126 -0
  189. package/lib/languages/ta.d.ts +20 -0
  190. package/lib/languages/ta.js +226 -0
  191. package/lib/languages/te.d.ts +22 -0
  192. package/lib/languages/te.js +219 -0
  193. package/lib/languages/th.d.ts +17 -0
  194. package/lib/languages/th.js +117 -0
  195. package/lib/languages/tr.d.ts +12 -0
  196. package/lib/languages/tr.js +56 -0
  197. package/lib/languages/uk.d.ts +85 -0
  198. package/lib/{i18n → languages}/uk.js +33 -32
  199. package/lib/languages/ur.d.ts +11 -0
  200. package/lib/languages/ur.js +131 -0
  201. package/lib/{i18n → languages}/vi.d.ts +15 -13
  202. package/lib/languages/vi.js +147 -0
  203. package/lib/languages/zh-Hans.d.ts +21 -0
  204. package/lib/languages/zh-Hans.js +111 -0
  205. package/lib/languages/zh-Hant.d.ts +21 -0
  206. package/lib/languages/zh-Hant.js +111 -0
  207. package/lib/n2words.d.ts +207 -7
  208. package/lib/n2words.js +535 -81
  209. package/package.json +126 -79
  210. package/dist/ar.js +0 -2
  211. package/dist/ar.js.map +0 -1
  212. package/dist/az.js +0 -2
  213. package/dist/az.js.map +0 -1
  214. package/dist/cz.js +0 -2
  215. package/dist/cz.js.map +0 -1
  216. package/dist/de.js +0 -2
  217. package/dist/de.js.map +0 -1
  218. package/dist/dk.js +0 -2
  219. package/dist/dk.js.map +0 -1
  220. package/dist/en.js +0 -2
  221. package/dist/en.js.map +0 -1
  222. package/dist/es.js +0 -2
  223. package/dist/es.js.map +0 -1
  224. package/dist/fa.js +0 -2
  225. package/dist/fa.js.map +0 -1
  226. package/dist/fr-BE.js +0 -2
  227. package/dist/fr-BE.js.map +0 -1
  228. package/dist/fr.js +0 -2
  229. package/dist/fr.js.map +0 -1
  230. package/dist/he.js +0 -2
  231. package/dist/he.js.map +0 -1
  232. package/dist/hr.js +0 -2
  233. package/dist/hr.js.map +0 -1
  234. package/dist/hu.js +0 -2
  235. package/dist/hu.js.map +0 -1
  236. package/dist/id.js +0 -2
  237. package/dist/id.js.map +0 -1
  238. package/dist/it.js +0 -2
  239. package/dist/it.js.map +0 -1
  240. package/dist/ko.js +0 -2
  241. package/dist/ko.js.map +0 -1
  242. package/dist/lt.js +0 -2
  243. package/dist/lt.js.map +0 -1
  244. package/dist/lv.js +0 -2
  245. package/dist/lv.js.map +0 -1
  246. package/dist/n2words.d.ts +0 -2
  247. package/dist/nl.js +0 -2
  248. package/dist/nl.js.map +0 -1
  249. package/dist/no.js +0 -2
  250. package/dist/no.js.map +0 -1
  251. package/dist/pl.js +0 -2
  252. package/dist/pl.js.map +0 -1
  253. package/dist/pt.js +0 -2
  254. package/dist/pt.js.map +0 -1
  255. package/dist/ro.js +0 -2
  256. package/dist/ro.js.map +0 -1
  257. package/dist/ru.js +0 -2
  258. package/dist/ru.js.map +0 -1
  259. package/dist/sr.js +0 -2
  260. package/dist/sr.js.map +0 -1
  261. package/dist/tr.js +0 -2
  262. package/dist/tr.js.map +0 -1
  263. package/dist/uk.js +0 -2
  264. package/dist/uk.js.map +0 -1
  265. package/dist/vi.js +0 -2
  266. package/dist/vi.js.map +0 -1
  267. package/dist/zh.js +0 -2
  268. package/dist/zh.js.map +0 -1
  269. package/lib/classes/base-language.d.ts +0 -58
  270. package/lib/classes/base-language.js +0 -172
  271. package/lib/i18n/ar.d.ts +0 -41
  272. package/lib/i18n/ar.js +0 -209
  273. package/lib/i18n/az.d.ts +0 -15
  274. package/lib/i18n/az.js +0 -66
  275. package/lib/i18n/cz.js +0 -135
  276. package/lib/i18n/de.d.ts +0 -17
  277. package/lib/i18n/de.js +0 -103
  278. package/lib/i18n/dk.d.ts +0 -14
  279. package/lib/i18n/dk.js +0 -110
  280. package/lib/i18n/en.d.ts +0 -22
  281. package/lib/i18n/en.js +0 -86
  282. package/lib/i18n/es.d.ts +0 -16
  283. package/lib/i18n/es.js +0 -110
  284. package/lib/i18n/fa.d.ts +0 -54
  285. package/lib/i18n/fa.js +0 -106
  286. package/lib/i18n/fr-BE.d.ts +0 -11
  287. package/lib/i18n/fr-BE.js +0 -20
  288. package/lib/i18n/fr.d.ts +0 -15
  289. package/lib/i18n/fr.js +0 -99
  290. package/lib/i18n/he.d.ts +0 -61
  291. package/lib/i18n/he.js +0 -132
  292. package/lib/i18n/hr.d.ts +0 -68
  293. package/lib/i18n/hr.js +0 -129
  294. package/lib/i18n/hu.d.ts +0 -17
  295. package/lib/i18n/hu.js +0 -135
  296. package/lib/i18n/id.d.ts +0 -43
  297. package/lib/i18n/id.js +0 -156
  298. package/lib/i18n/it.d.ts +0 -29
  299. package/lib/i18n/it.js +0 -137
  300. package/lib/i18n/ko.d.ts +0 -15
  301. package/lib/i18n/ko.js +0 -56
  302. package/lib/i18n/lt.js +0 -138
  303. package/lib/i18n/lv.d.ts +0 -57
  304. package/lib/i18n/lv.js +0 -120
  305. package/lib/i18n/nl.d.ts +0 -20
  306. package/lib/i18n/nl.js +0 -125
  307. package/lib/i18n/no.d.ts +0 -15
  308. package/lib/i18n/no.js +0 -77
  309. package/lib/i18n/pl.js +0 -126
  310. package/lib/i18n/pt.d.ts +0 -26
  311. package/lib/i18n/pt.js +0 -118
  312. package/lib/i18n/ro.d.ts +0 -109
  313. package/lib/i18n/ro.js +0 -360
  314. package/lib/i18n/ru.d.ts +0 -30
  315. package/lib/i18n/ru.js +0 -198
  316. package/lib/i18n/sr.d.ts +0 -56
  317. package/lib/i18n/sr.js +0 -127
  318. package/lib/i18n/tr.d.ts +0 -15
  319. package/lib/i18n/tr.js +0 -64
  320. package/lib/i18n/vi.js +0 -151
  321. package/lib/i18n/zh.d.ts +0 -18
  322. package/lib/i18n/zh.js +0 -78
@@ -0,0 +1,159 @@
1
+ import { AbstractLanguage } from '../classes/abstract-language.js'
2
+
3
+ /**
4
+ * Arabic language converter.
5
+ *
6
+ * Supports:
7
+ * - Gender agreement (masculine/feminine forms)
8
+ * - Complex pluralization (singular/dual/plural)
9
+ * - Traditional Arabic number naming conventions
10
+ * - Right-to-left text orientation
11
+ */
12
+ export class Arabic extends AbstractLanguage {
13
+ negativeWord = 'ناقص'
14
+ decimalSeparatorWord = 'فاصلة'
15
+ zeroWord = 'صفر'
16
+
17
+ tensWords = ['عشرون', 'ثلاثون', 'أربعون', 'خمسون', 'ستون', 'سبعون', 'ثمانون', 'تسعون']
18
+ hundredsWords = ['', 'مائة', 'مئتان', 'ثلاثمائة', 'أربعمائة', 'خمسمائة', 'ستمائة', 'سبعمائة', 'ثمانمائة', 'تسعمائة']
19
+
20
+ // Magnitude words with three forms: singular, appended (tanween), plural
21
+ scaleWords = ['مائة', 'ألف', 'مليون', 'مليار', 'تريليون', 'كوادريليون', 'كوينتليون', 'سكستيليون']
22
+ scaleAppendedWords = ['', 'ألفاً', 'مليوناً', 'ملياراً', 'تريليوناً', 'كوادريليوناً', 'كوينتليوناً', 'سكستيليوناً']
23
+ scalePluralWords = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات']
24
+
25
+ // Dual forms (Arabic has singular, dual, plural)
26
+ dualWords = ['مئتان', 'ألفان', 'مليونان', 'ملياران', 'تريليونان', 'كوادريليونان', 'كوينتليونان', 'سكستيليونان']
27
+ dualAppendedWords = ['مئتا', 'ألفا', 'مليونا', 'مليارا', 'تريليونا', 'كوادريليونا', 'كوينتليونا', 'سكستيليونا']
28
+
29
+ // Gender-specific number words (1-19)
30
+ ones = {
31
+ masculine: [
32
+ 'واحد', 'اثنان', 'ثلاثة', 'أربعة', 'خمسة', 'ستة', 'سبعة', 'ثمانية', 'تسعة', 'عشرة',
33
+ 'أحد عشر', 'اثنا عشر', 'ثلاثة عشر', 'أربعة عشر', 'خمسة عشر', 'ستة عشر', 'سبعة عشر', 'ثمانية عشر', 'تسعة عشر'
34
+ ],
35
+ feminine: [
36
+ 'واحدة', 'اثنتان', 'ثلاث', 'أربع', 'خمس', 'ست', 'سبع', 'ثمان', 'تسع', 'عشر',
37
+ 'إحدى عشرة', 'اثنتا عشرة', 'ثلاث عشرة', 'أربع عشرة', 'خمس عشرة', 'ست عشرة', 'سبع عشرة', 'ثماني عشرة', 'تسع عشرة'
38
+ ]
39
+ }
40
+
41
+ constructor (options = {}) {
42
+ super()
43
+
44
+ this.setOptions({
45
+ gender: 'masculine'
46
+ }, options)
47
+
48
+ // Allow custom negativeWord via options
49
+ if (options.negativeWord !== undefined) {
50
+ this.negativeWord = options.negativeWord
51
+ }
52
+ }
53
+
54
+ /** Selects masculine or feminine number forms based on options. */
55
+ get selectedOnes () {
56
+ return this.ones[this.options.gender === 'feminine' ? 'feminine' : 'masculine']
57
+ }
58
+
59
+ /** Converts a 3-digit segment (0-999) to Arabic words with gender/plural rules. */
60
+ segmentToWords (groupNumber, groupLevel, fullNumber) {
61
+ const tens = groupNumber % 100
62
+ const hundredsRaw = groupNumber / 100
63
+ const hundreds = Math.trunc(hundredsRaw)
64
+ let returnValue = ''
65
+
66
+ // Process hundreds
67
+ if (hundreds > 0) {
68
+ if (tens === 0 && hundreds === 2) {
69
+ returnValue = this.dualWords[0]
70
+ } else {
71
+ const hundredsWord = this.hundredsWords[hundreds]
72
+ if (hundredsWord) {
73
+ returnValue = hundredsWord
74
+ if (tens !== 0) {
75
+ returnValue += ' و'
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ // Process tens and ones
82
+ if (tens > 0) {
83
+ if (tens < 20) { // 1 -> 19
84
+ if (tens === 2 && hundreds === 0 && groupLevel > 0) {
85
+ // Cache expensive log10 calculation
86
+ const numValue = Number(fullNumber)
87
+ const pow = Math.trunc(Math.log10(numValue))
88
+ if (pow % 3 === 0 && fullNumber === BigInt(2 * Math.pow(10, pow))) {
89
+ returnValue = groupNumber === 2 ? this.dualWords[groupLevel] : this.dualAppendedWords[groupLevel]
90
+ } else {
91
+ returnValue = this.dualWords[groupLevel]
92
+ }
93
+ } else if (tens === 1 && groupLevel > 0) {
94
+ returnValue += this.scaleWords[groupLevel]
95
+ } else {
96
+ returnValue += this.selectedOnes[tens - 1]
97
+ }
98
+ } else { // 20 -> 99
99
+ const ones = tens % 10
100
+ const tensIndex = Math.trunc(tens / 10) - 2
101
+
102
+ if (ones > 0) {
103
+ returnValue += this.selectedOnes[ones - 1]
104
+ returnValue += ' و'
105
+ }
106
+ returnValue += this.tensWords[tensIndex]
107
+ }
108
+ }
109
+
110
+ return returnValue
111
+ }
112
+
113
+ /** Converts integer part to Arabic words by processing 3-digit groups. */
114
+ integerToWords (integerPart) {
115
+ if (integerPart === 0n) {
116
+ return this.zeroWord
117
+ }
118
+ let temp = integerPart
119
+ let group = 0
120
+ let result = ''
121
+
122
+ // Process each group of 3 digits (right to left)
123
+ while (temp > 0n) {
124
+ const numberToProcess = Number(temp % 1000n)
125
+ temp = temp / 1000n
126
+
127
+ if (numberToProcess > 0) {
128
+ const groupDescription = this.segmentToWords(numberToProcess, group, integerPart)
129
+
130
+ if (groupDescription) {
131
+ // Add group name for thousands, millions, etc.
132
+ if (group > 0) {
133
+ if (result) {
134
+ result = ' و' + result
135
+ }
136
+
137
+ if (numberToProcess > 2) {
138
+ const remainder = numberToProcess % 100
139
+ if (remainder === 1) {
140
+ result = this.scaleWords[group] + ' ' + result
141
+ } else if (numberToProcess >= 3 && numberToProcess <= 10) {
142
+ result = this.scalePluralWords[group] + ' ' + result
143
+ } else {
144
+ result = (result ? this.scaleAppendedWords[group] : this.scaleWords[group]) + ' ' + result
145
+ }
146
+ }
147
+ }
148
+
149
+ // Add group description (prepend for RTL)
150
+ result = groupDescription + ' ' + result
151
+ }
152
+ }
153
+
154
+ group++
155
+ }
156
+
157
+ return result.replace(/\s+/g, ' ').trim()
158
+ }
159
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Azerbaijani language converter.
3
+ *
4
+ * Supports:
5
+ * - Implicit "bir" (one) omission before hundreds and thousands
6
+ * - Turkic language number patterns
7
+ * - Large numbers up to quintillion
8
+ */
9
+ export class Azerbaijani extends TurkicLanguage {
10
+ scaleWords: (string | bigint)[][];
11
+ }
12
+ import { TurkicLanguage } from '../classes/turkic-language.js';
@@ -0,0 +1,42 @@
1
+ import { TurkicLanguage } from '../classes/turkic-language.js'
2
+
3
+ /**
4
+ * Azerbaijani language converter.
5
+ *
6
+ * Supports:
7
+ * - Implicit "bir" (one) omission before hundreds and thousands
8
+ * - Turkic language number patterns
9
+ * - Large numbers up to quintillion
10
+ */
11
+ export class Azerbaijani extends TurkicLanguage {
12
+ negativeWord = 'mənfi'
13
+ decimalSeparatorWord = 'nöqtə'
14
+ zeroWord = 'sıfır'
15
+
16
+ scaleWords = [[1_000_000_000_000_000_000n, 'kentilyon'],
17
+ [1_000_000_000_000_000n, 'katrilyon'],
18
+ [1_000_000_000_000n, 'trilyon'],
19
+ [1_000_000_000n, 'milyar'],
20
+ [1_000_000n, 'milyon'],
21
+ [1000n, 'min'],
22
+ [100n, 'yüz'],
23
+ [90n, 'doxsan'],
24
+ [80n, 'səksən'],
25
+ [70n, 'yetmiş'],
26
+ [60n, 'altmış'],
27
+ [50n, 'əlli'],
28
+ [40n, 'qırx'],
29
+ [30n, 'otuz'],
30
+ [20n, 'iyirmi'],
31
+ [10n, 'on'],
32
+ [9n, 'doqquz'],
33
+ [8n, 'səkkiz'],
34
+ [7n, 'yeddi'],
35
+ [6n, 'altı'],
36
+ [5n, 'beş'],
37
+ [4n, 'dörd'],
38
+ [3n, 'üç'],
39
+ [2n, 'iki'],
40
+ [1n, 'bir'],
41
+ [0n, 'sıfır']]
42
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Bangla language converter.
3
+ *
4
+ * Supports:
5
+ * - Indian numbering system (হাজার, লাখ, কোটি)
6
+ * - Bangla script (Bengali)
7
+ * - Complete word forms for 0-99
8
+ */
9
+ export class Bangla extends SouthAsianLanguage {
10
+ }
11
+ import { SouthAsianLanguage } from '../classes/south-asian-language.js';
@@ -0,0 +1,131 @@
1
+ import { SouthAsianLanguage } from '../classes/south-asian-language.js'
2
+
3
+ /**
4
+ * Bangla language converter.
5
+ *
6
+ * Supports:
7
+ * - Indian numbering system (হাজার, লাখ, কোটি)
8
+ * - Bangla script (Bengali)
9
+ * - Complete word forms for 0-99
10
+ */
11
+ export class Bangla extends SouthAsianLanguage {
12
+ negativeWord = 'মাইনাস'
13
+ decimalSeparatorWord = 'দশমিক'
14
+ zeroWord = 'শূন্য'
15
+ hundredWord = 'শত'
16
+
17
+ belowHundredWords = [
18
+ 'শূন্য',
19
+ 'এক',
20
+ 'দুই',
21
+ 'তিন',
22
+ 'চার',
23
+ 'পাঁচ',
24
+ 'ছয়',
25
+ 'সাত',
26
+ 'আট',
27
+ 'নয়',
28
+ 'দশ',
29
+ 'এগারো',
30
+ 'বারো',
31
+ 'তেরো',
32
+ 'চৌদ্দ',
33
+ 'পনেরো',
34
+ 'ষোল',
35
+ 'সতেরো',
36
+ 'আঠারো',
37
+ 'উনিশ',
38
+ 'বিশ',
39
+ 'একুশ',
40
+ 'বাইশ',
41
+ 'তেইশ',
42
+ 'চব্বিশ',
43
+ 'পঁচিশ',
44
+ 'ছাব্বিশ',
45
+ 'সাতাশ',
46
+ 'আঠাশ',
47
+ 'উনত্রিশ',
48
+ 'ত্রিশ',
49
+ 'একত্রিশ',
50
+ 'বত্রিশ',
51
+ 'তেত্রিশ',
52
+ 'চৌত্রিশ',
53
+ 'পঁয়ত্রিশ',
54
+ 'ছত্রিশ',
55
+ 'সাঁইত্রিশ',
56
+ 'আটত্রিশ',
57
+ 'উনচল্লিশ',
58
+ 'চল্লিশ',
59
+ 'একচল্লিশ',
60
+ 'বেয়াল্লিশ',
61
+ 'তেতাল্লিশ',
62
+ 'চুয়াল্লিশ',
63
+ 'পঁয়তাল্লিশ',
64
+ 'ছেচল্লিশ',
65
+ 'সাতচল্লিশ',
66
+ 'আটচল্লিশ',
67
+ 'উনপঞ্চাশ',
68
+ 'পঞ্চাশ',
69
+ 'একান্ন',
70
+ 'বাহান্ন',
71
+ 'তিপ্পান্ন',
72
+ 'চুয়ান্ন',
73
+ 'পঞ্চান্ন',
74
+ 'ছাপ্পান্ন',
75
+ 'সাতান্ন',
76
+ 'আটান্ন',
77
+ 'উনষাট',
78
+ 'ষাট',
79
+ 'একষট্টি',
80
+ 'বাষট্টি',
81
+ 'তেষট্টি',
82
+ 'চৌষট্টি',
83
+ 'পঁয়ষট্টি',
84
+ 'ছেষট্টি',
85
+ 'সাতষট্টি',
86
+ 'আটষট্টি',
87
+ 'ঊনসত্তর',
88
+ 'সত্তর',
89
+ 'একাত্তর',
90
+ 'বাহাত্তর',
91
+ 'তেহাত্তর',
92
+ 'চুয়াত্তর',
93
+ 'পঁচাত্তর',
94
+ 'ছিয়াত্তর',
95
+ 'সাতাত্তর',
96
+ 'আটাত্তর',
97
+ 'উনআশি',
98
+ 'আশি',
99
+ 'একাশি',
100
+ 'বিরাশি',
101
+ 'তিরাশি',
102
+ 'চুরাশি',
103
+ 'পঁচাশি',
104
+ 'ছিয়াশি',
105
+ 'সাতাশি',
106
+ 'আটাশি',
107
+ 'উননব্বই',
108
+ 'নব্বই',
109
+ 'একানব্বই',
110
+ 'বিরানব্বই',
111
+ 'তিরানব্বই',
112
+ 'চুরানব্বই',
113
+ 'পঁচানব্বই',
114
+ 'ছিয়ানব্বই',
115
+ 'সাতানব্বই',
116
+ 'আটানব্বই',
117
+ 'নিরানব্বই'
118
+ ]
119
+
120
+ scaleWords = [
121
+ '',
122
+ 'হাজার',
123
+ 'লাখ',
124
+ 'কোটি',
125
+ 'আরব',
126
+ 'খরব',
127
+ 'নীল',
128
+ 'পদ্ম',
129
+ 'শঙ্খ'
130
+ ]
131
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Czech language converter.
3
+ *
4
+ * Supports:
5
+ * - Three-form pluralization (one/few/many)
6
+ * - Dynamic decimal separator (celá/celé/celých)
7
+ * - Gender agreement in number words
8
+ */
9
+ export class Czech extends SlavicLanguage {
10
+ constructor(options?: {});
11
+ onesWords: {
12
+ 1: string;
13
+ 2: string;
14
+ 3: string;
15
+ 4: string;
16
+ 5: string;
17
+ 6: string;
18
+ 7: string;
19
+ 8: string;
20
+ 9: string;
21
+ };
22
+ onesFeminineWords: {
23
+ 1: string;
24
+ 2: string;
25
+ 3: string;
26
+ 4: string;
27
+ 5: string;
28
+ 6: string;
29
+ 7: string;
30
+ 8: string;
31
+ 9: string;
32
+ };
33
+ teensWords: {
34
+ 0: string;
35
+ 1: string;
36
+ 2: string;
37
+ 3: string;
38
+ 4: string;
39
+ 5: string;
40
+ 6: string;
41
+ 7: string;
42
+ 8: string;
43
+ 9: string;
44
+ };
45
+ twentiesWords: {
46
+ 2: string;
47
+ 3: string;
48
+ 4: string;
49
+ 5: string;
50
+ 6: string;
51
+ 7: string;
52
+ 8: string;
53
+ 9: string;
54
+ };
55
+ hundredsWords: {
56
+ 1: string;
57
+ 2: string;
58
+ 3: string;
59
+ 4: string;
60
+ 5: string;
61
+ 6: string;
62
+ 7: string;
63
+ 8: string;
64
+ 9: string;
65
+ };
66
+ pluralForms: {
67
+ 1: string[];
68
+ 2: string[];
69
+ 3: string[];
70
+ 4: string[];
71
+ 5: string[];
72
+ 6: string[];
73
+ 7: string[];
74
+ 8: string[];
75
+ 9: string[];
76
+ 10: string[];
77
+ };
78
+ /** Returns decimal separator word based on integer part (celá/celé/celých). */
79
+ get decimalSeparatorWord(): "celá" | "celé" | "celých";
80
+ /**
81
+ * Override toWords to cache integer part before decimal separator is accessed.
82
+ */
83
+ toWords(isNegative: any, integerPart: any, decimalPart: any): string;
84
+ /** Selects Czech plural form: 1 = singular, 2-4 = few, else = many. */
85
+ pluralize(n: any, forms: any): any;
86
+ #private;
87
+ }
88
+ import { SlavicLanguage } from '../classes/slavic-language.js';
@@ -0,0 +1,143 @@
1
+ import { SlavicLanguage } from '../classes/slavic-language.js'
2
+
3
+ /**
4
+ * Czech language converter.
5
+ *
6
+ * Supports:
7
+ * - Three-form pluralization (one/few/many)
8
+ * - Dynamic decimal separator (celá/celé/celých)
9
+ * - Gender agreement in number words
10
+ */
11
+ export class Czech extends SlavicLanguage {
12
+ negativeWord = 'mínus'
13
+ zeroWord = 'nula'
14
+
15
+ onesWords = {
16
+ 1: 'jedna',
17
+ 2: 'dva',
18
+ 3: 'tři',
19
+ 4: 'čtyři',
20
+ 5: 'pět',
21
+ 6: 'šest',
22
+ 7: 'sedm',
23
+ 8: 'osm',
24
+ 9: 'devět'
25
+ }
26
+
27
+ onesFeminineWords = {
28
+ 1: 'jedna',
29
+ 2: 'dvě',
30
+ 3: 'tři',
31
+ 4: 'čtyři',
32
+ 5: 'pět',
33
+ 6: 'šest',
34
+ 7: 'sedm',
35
+ 8: 'osm',
36
+ 9: 'devět'
37
+ }
38
+
39
+ teensWords = {
40
+ 0: 'deset',
41
+ 1: 'jedenáct',
42
+ 2: 'dvanáct',
43
+ 3: 'třináct',
44
+ 4: 'čtrnáct',
45
+ 5: 'patnáct',
46
+ 6: 'šestnáct',
47
+ 7: 'sedmnáct',
48
+ 8: 'osmnáct',
49
+ 9: 'devatenáct'
50
+ }
51
+
52
+ twentiesWords = {
53
+ 2: 'dvacet',
54
+ 3: 'třicet',
55
+ 4: 'čtyřicet',
56
+ 5: 'padesát',
57
+ 6: 'šedesát',
58
+ 7: 'sedmdesát',
59
+ 8: 'osmdesát',
60
+ 9: 'devadesát'
61
+ }
62
+
63
+ hundredsWords = {
64
+ 1: 'sto',
65
+ 2: 'dvě stě',
66
+ 3: 'tři sta',
67
+ 4: 'čtyři sta',
68
+ 5: 'pět set',
69
+ 6: 'šest set',
70
+ 7: 'sedm set',
71
+ 8: 'osm set',
72
+ 9: 'devět set'
73
+ }
74
+
75
+ pluralForms = {
76
+ 1: ['tisíc', 'tisíce', 'tisíc'], // 10^ 3
77
+ 2: ['milion', 'miliony', 'milionů'], // 10^ 6
78
+ 3: ['miliarda', 'miliardy', 'miliard'], // 10^ 9
79
+ 4: ['bilion', 'biliony', 'bilionů'], // 10^ 12
80
+ 5: ['biliarda', 'biliardy', 'biliard'], // 10^ 15
81
+ 6: ['trilion', 'triliony', 'trilionů'], // 10^ 18
82
+ 7: ['triliarda', 'triliardy', 'triliard'], // 10^ 21
83
+ 8: ['kvadrilion', 'kvadriliony', 'kvadrilionů'], // 10^ 24
84
+ 9: ['kvadriliarda', 'kvadriliardy', 'kvadriliard'], // 10^ 27
85
+ 10: ['quintillion', 'quintilliony', 'quintillionů'] // 10^ 30
86
+ }
87
+
88
+ /**
89
+ * Czech omits "one" before scale words.
90
+ * e.g., 1000 is "tisíc" not "jedna tisíc"
91
+ */
92
+ omitOneBeforeScale = true
93
+
94
+ /**
95
+ * Cached integer part for decimal separator word selection.
96
+ * Set by toWords() before calling super.toWords().
97
+ * @private
98
+ */
99
+ #integerPart = 0n
100
+
101
+ /** Returns decimal separator word based on integer part (celá/celé/celých). */
102
+ get decimalSeparatorWord () {
103
+ if (this.#integerPart === 0n || this.#integerPart === 1n) {
104
+ return 'celá'
105
+ } else if (this.#integerPart >= 2n && this.#integerPart <= 4n) {
106
+ return 'celé'
107
+ } else {
108
+ return 'celých'
109
+ }
110
+ }
111
+
112
+ constructor (options = {}) {
113
+ super(options)
114
+
115
+ // Remove the inherited decimalSeparatorWord property so our getter works
116
+ delete this.decimalSeparatorWord
117
+ }
118
+
119
+ /**
120
+ * Override toWords to cache integer part before decimal separator is accessed.
121
+ */
122
+ toWords (isNegative, integerPart, decimalPart) {
123
+ this.#integerPart = integerPart
124
+ return super.toWords(isNegative, integerPart, decimalPart)
125
+ }
126
+
127
+ /** Selects Czech plural form: 1 = singular, 2-4 = few, else = many. */
128
+ pluralize (n, forms) {
129
+ if (n === 1n) {
130
+ return forms[0]
131
+ }
132
+
133
+ // Check if n is in the "few" form range (2-4, 22-24, 32-34, etc., excluding teens)
134
+ const lastDigit = n % 10n
135
+ const lastTwoDigits = n % 100n
136
+
137
+ if (lastDigit > 1n && lastDigit < 5n && (lastTwoDigits < 10n || lastTwoDigits > 20n)) {
138
+ return forms[1]
139
+ }
140
+
141
+ return forms[2]
142
+ }
143
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Danish language converter.
3
+ *
4
+ * Supports:
5
+ * - Vigesimal (base-20) number system
6
+ * - Units-before-tens ordering (e.g., "tre-og-tyve" = 23)
7
+ * - Optional ordinal numbers via ordFlag option
8
+ */
9
+ export class Danish extends GreedyScaleLanguage {
10
+ constructor(options?: {});
11
+ scaleWords: (string | bigint)[][];
12
+ /** Combines two word-sets with Danish vigesimal and reversal rules. */
13
+ combineWordSets(preceding: any, following: any): any;
14
+ }
15
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';