n2words 2.0.0 → 3.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 (327) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +86 -188
  3. package/dist/languages/am-Latn.js +3 -0
  4. package/dist/languages/am-Latn.js.map +1 -0
  5. package/dist/languages/am.js +3 -0
  6. package/dist/languages/am.js.map +1 -0
  7. package/dist/languages/ar.js +3 -0
  8. package/dist/languages/ar.js.map +1 -0
  9. package/dist/languages/az.js +3 -0
  10. package/dist/languages/az.js.map +1 -0
  11. package/dist/languages/bn.js +3 -0
  12. package/dist/languages/bn.js.map +1 -0
  13. package/dist/languages/cs.js +3 -0
  14. package/dist/languages/cs.js.map +1 -0
  15. package/dist/languages/da.js +3 -0
  16. package/dist/languages/da.js.map +1 -0
  17. package/dist/languages/de.js +3 -0
  18. package/dist/languages/de.js.map +1 -0
  19. package/dist/languages/el.js +3 -0
  20. package/dist/languages/el.js.map +1 -0
  21. package/dist/languages/en.js +3 -0
  22. package/dist/languages/en.js.map +1 -0
  23. package/dist/languages/es.js +3 -0
  24. package/dist/languages/es.js.map +1 -0
  25. package/dist/languages/fa.js +3 -0
  26. package/dist/languages/fa.js.map +1 -0
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -0
  30. package/dist/languages/fil.js.map +1 -0
  31. package/dist/languages/fr-BE.js +3 -0
  32. package/dist/languages/fr-BE.js.map +1 -0
  33. package/dist/languages/fr.js +3 -0
  34. package/dist/languages/fr.js.map +1 -0
  35. package/dist/languages/gu.js +3 -0
  36. package/dist/languages/gu.js.map +1 -0
  37. package/dist/languages/ha.js +3 -0
  38. package/dist/languages/ha.js.map +1 -0
  39. package/dist/languages/hbo.js +3 -0
  40. package/dist/languages/hbo.js.map +1 -0
  41. package/dist/languages/he.js +3 -0
  42. package/dist/languages/he.js.map +1 -0
  43. package/dist/languages/hi.js +3 -0
  44. package/dist/languages/hi.js.map +1 -0
  45. package/dist/languages/hr.js +3 -0
  46. package/dist/languages/hr.js.map +1 -0
  47. package/dist/languages/hu.js +3 -0
  48. package/dist/languages/hu.js.map +1 -0
  49. package/dist/languages/id.js +3 -0
  50. package/dist/languages/id.js.map +1 -0
  51. package/dist/languages/it.js +3 -0
  52. package/dist/languages/it.js.map +1 -0
  53. package/dist/languages/ja.js +3 -0
  54. package/dist/languages/ja.js.map +1 -0
  55. package/dist/languages/kn.js +3 -0
  56. package/dist/languages/kn.js.map +1 -0
  57. package/dist/languages/ko.js +3 -0
  58. package/dist/languages/ko.js.map +1 -0
  59. package/dist/languages/lt.js +3 -0
  60. package/dist/languages/lt.js.map +1 -0
  61. package/dist/languages/lv.js +3 -0
  62. package/dist/languages/lv.js.map +1 -0
  63. package/dist/languages/mr.js +3 -0
  64. package/dist/languages/mr.js.map +1 -0
  65. package/dist/languages/ms.js +3 -0
  66. package/dist/languages/ms.js.map +1 -0
  67. package/dist/languages/nb.js +3 -0
  68. package/dist/languages/nb.js.map +1 -0
  69. package/dist/languages/nl.js +3 -0
  70. package/dist/languages/nl.js.map +1 -0
  71. package/dist/languages/pa.js +3 -0
  72. package/dist/languages/pa.js.map +1 -0
  73. package/dist/languages/pl.js +3 -0
  74. package/dist/languages/pl.js.map +1 -0
  75. package/dist/languages/pt.js +3 -0
  76. package/dist/languages/pt.js.map +1 -0
  77. package/dist/languages/ro.js +3 -0
  78. package/dist/languages/ro.js.map +1 -0
  79. package/dist/languages/ru.js +3 -0
  80. package/dist/languages/ru.js.map +1 -0
  81. package/dist/languages/sr-Cyrl.js +3 -0
  82. package/dist/languages/sr-Cyrl.js.map +1 -0
  83. package/dist/languages/sr-Latn.js +3 -0
  84. package/dist/languages/sr-Latn.js.map +1 -0
  85. package/dist/languages/sv.js +3 -0
  86. package/dist/languages/sv.js.map +1 -0
  87. package/dist/languages/sw.js +3 -0
  88. package/dist/languages/sw.js.map +1 -0
  89. package/dist/languages/ta.js +3 -0
  90. package/dist/languages/ta.js.map +1 -0
  91. package/dist/languages/te.js +3 -0
  92. package/dist/languages/te.js.map +1 -0
  93. package/dist/languages/th.js +3 -0
  94. package/dist/languages/th.js.map +1 -0
  95. package/dist/languages/tr.js +3 -0
  96. package/dist/languages/tr.js.map +1 -0
  97. package/dist/languages/uk.js +3 -0
  98. package/dist/languages/uk.js.map +1 -0
  99. package/dist/languages/ur.js +3 -0
  100. package/dist/languages/ur.js.map +1 -0
  101. package/dist/languages/vi.js +3 -0
  102. package/dist/languages/vi.js.map +1 -0
  103. package/dist/languages/zh-Hans.js +3 -0
  104. package/dist/languages/zh-Hans.js.map +1 -0
  105. package/dist/languages/zh-Hant.js +3 -0
  106. package/dist/languages/zh-Hant.js.map +1 -0
  107. package/dist/n2words.js +2 -2
  108. package/dist/n2words.js.map +1 -1
  109. package/lib/languages/am-Latn.d.ts +7 -0
  110. package/lib/languages/am-Latn.js +164 -0
  111. package/lib/languages/am.d.ts +7 -0
  112. package/lib/languages/am.js +164 -0
  113. package/lib/languages/ar.d.ts +14 -27
  114. package/lib/languages/ar.js +175 -129
  115. package/lib/languages/az.d.ts +4 -9
  116. package/lib/languages/az.js +171 -37
  117. package/lib/languages/bn.d.ts +4 -8
  118. package/lib/languages/bn.js +138 -124
  119. package/lib/languages/cs.d.ts +15 -85
  120. package/lib/languages/cs.js +310 -114
  121. package/lib/languages/da.d.ts +11 -12
  122. package/lib/languages/da.js +276 -101
  123. package/lib/languages/de.d.ts +14 -11
  124. package/lib/languages/de.js +317 -86
  125. package/lib/languages/el.d.ts +11 -11
  126. package/lib/languages/el.js +231 -78
  127. package/lib/languages/en.d.ts +14 -13
  128. package/lib/languages/en.js +242 -72
  129. package/lib/languages/es.d.ts +18 -12
  130. package/lib/languages/es.js +317 -103
  131. package/lib/languages/fa.d.ts +4 -44
  132. package/lib/languages/fa.js +112 -122
  133. package/lib/languages/fi.d.ts +14 -0
  134. package/lib/languages/fi.js +245 -0
  135. package/lib/languages/fil.d.ts +4 -13
  136. package/lib/languages/fil.js +207 -106
  137. package/lib/languages/fr-BE.d.ts +8 -8
  138. package/lib/languages/fr-BE.js +294 -19
  139. package/lib/languages/fr.d.ts +18 -12
  140. package/lib/languages/fr.js +352 -89
  141. package/lib/languages/gu.d.ts +4 -8
  142. package/lib/languages/gu.js +130 -125
  143. package/lib/languages/ha.d.ts +7 -0
  144. package/lib/languages/ha.js +230 -0
  145. package/lib/languages/hbo.d.ts +10 -110
  146. package/lib/languages/hbo.js +263 -214
  147. package/lib/languages/he.d.ts +10 -77
  148. package/lib/languages/he.js +242 -172
  149. package/lib/languages/hi.d.ts +4 -8
  150. package/lib/languages/hi.js +138 -124
  151. package/lib/languages/hr.d.ts +8 -77
  152. package/lib/languages/hr.js +194 -89
  153. package/lib/languages/hu.d.ts +4 -19
  154. package/lib/languages/hu.js +198 -119
  155. package/lib/languages/id.d.ts +4 -34
  156. package/lib/languages/id.js +171 -129
  157. package/lib/languages/it.d.ts +16 -34
  158. package/lib/languages/it.js +339 -94
  159. package/lib/languages/ja.d.ts +14 -14
  160. package/lib/languages/ja.js +233 -111
  161. package/lib/languages/kn.d.ts +4 -8
  162. package/lib/languages/kn.js +130 -35
  163. package/lib/languages/ko.d.ts +11 -11
  164. package/lib/languages/ko.js +257 -49
  165. package/lib/languages/lt.d.ts +15 -67
  166. package/lib/languages/lt.js +296 -122
  167. package/lib/languages/lv.d.ts +15 -67
  168. package/lib/languages/lv.js +297 -106
  169. package/lib/languages/mr.d.ts +4 -8
  170. package/lib/languages/mr.js +130 -125
  171. package/lib/languages/ms.d.ts +4 -28
  172. package/lib/languages/ms.js +171 -116
  173. package/lib/languages/nb.d.ts +11 -9
  174. package/lib/languages/nb.js +282 -87
  175. package/lib/languages/nl.d.ts +23 -13
  176. package/lib/languages/nl.js +317 -133
  177. package/lib/languages/pa.d.ts +4 -8
  178. package/lib/languages/pa.js +156 -124
  179. package/lib/languages/pl.d.ts +19 -77
  180. package/lib/languages/pl.js +307 -87
  181. package/lib/languages/pt.d.ts +14 -26
  182. package/lib/languages/pt.js +286 -92
  183. package/lib/languages/ro.d.ts +15 -155
  184. package/lib/languages/ro.js +219 -235
  185. package/lib/languages/ru.d.ts +8 -82
  186. package/lib/languages/ru.js +222 -78
  187. package/lib/languages/sr-Cyrl.d.ts +8 -77
  188. package/lib/languages/sr-Cyrl.js +191 -89
  189. package/lib/languages/sr-Latn.d.ts +8 -77
  190. package/lib/languages/sr-Latn.js +191 -89
  191. package/lib/languages/sv.d.ts +11 -11
  192. package/lib/languages/sv.js +288 -74
  193. package/lib/languages/sw.d.ts +4 -36
  194. package/lib/languages/sw.js +133 -106
  195. package/lib/languages/ta.d.ts +4 -17
  196. package/lib/languages/ta.js +129 -201
  197. package/lib/languages/te.d.ts +4 -19
  198. package/lib/languages/te.js +141 -196
  199. package/lib/languages/th.d.ts +4 -14
  200. package/lib/languages/th.js +135 -91
  201. package/lib/languages/tr.d.ts +15 -9
  202. package/lib/languages/tr.js +256 -49
  203. package/lib/languages/uk.d.ts +8 -82
  204. package/lib/languages/uk.js +200 -78
  205. package/lib/languages/ur.d.ts +4 -8
  206. package/lib/languages/ur.js +156 -124
  207. package/lib/languages/vi.d.ts +14 -69
  208. package/lib/languages/vi.js +294 -125
  209. package/lib/languages/zh-Hans.d.ts +8 -18
  210. package/lib/languages/zh-Hans.js +163 -92
  211. package/lib/languages/zh-Hant.d.ts +8 -18
  212. package/lib/languages/zh-Hant.js +181 -90
  213. package/lib/n2words.d.ts +53 -209
  214. package/lib/n2words.js +111 -530
  215. package/lib/utils/is-plain-object.d.ts +13 -0
  216. package/lib/utils/is-plain-object.js +17 -0
  217. package/lib/utils/parse-numeric.d.ts +17 -0
  218. package/lib/utils/parse-numeric.js +108 -0
  219. package/lib/utils/validate-options.d.ts +8 -0
  220. package/lib/utils/validate-options.js +16 -0
  221. package/package.json +26 -14
  222. package/dist/ArabicConverter.js +0 -3
  223. package/dist/ArabicConverter.js.map +0 -1
  224. package/dist/AzerbaijaniConverter.js +0 -3
  225. package/dist/AzerbaijaniConverter.js.map +0 -1
  226. package/dist/BanglaConverter.js +0 -3
  227. package/dist/BanglaConverter.js.map +0 -1
  228. package/dist/BiblicalHebrewConverter.js +0 -3
  229. package/dist/BiblicalHebrewConverter.js.map +0 -1
  230. package/dist/CroatianConverter.js +0 -3
  231. package/dist/CroatianConverter.js.map +0 -1
  232. package/dist/CzechConverter.js +0 -3
  233. package/dist/CzechConverter.js.map +0 -1
  234. package/dist/DanishConverter.js +0 -3
  235. package/dist/DanishConverter.js.map +0 -1
  236. package/dist/DutchConverter.js +0 -3
  237. package/dist/DutchConverter.js.map +0 -1
  238. package/dist/EnglishConverter.js +0 -3
  239. package/dist/EnglishConverter.js.map +0 -1
  240. package/dist/FilipinoConverter.js +0 -3
  241. package/dist/FilipinoConverter.js.map +0 -1
  242. package/dist/FrenchBelgiumConverter.js +0 -3
  243. package/dist/FrenchBelgiumConverter.js.map +0 -1
  244. package/dist/FrenchConverter.js +0 -3
  245. package/dist/FrenchConverter.js.map +0 -1
  246. package/dist/GermanConverter.js +0 -3
  247. package/dist/GermanConverter.js.map +0 -1
  248. package/dist/GreekConverter.js +0 -3
  249. package/dist/GreekConverter.js.map +0 -1
  250. package/dist/GujaratiConverter.js +0 -3
  251. package/dist/GujaratiConverter.js.map +0 -1
  252. package/dist/HebrewConverter.js +0 -3
  253. package/dist/HebrewConverter.js.map +0 -1
  254. package/dist/HindiConverter.js +0 -3
  255. package/dist/HindiConverter.js.map +0 -1
  256. package/dist/HungarianConverter.js +0 -3
  257. package/dist/HungarianConverter.js.map +0 -1
  258. package/dist/IndonesianConverter.js +0 -3
  259. package/dist/IndonesianConverter.js.map +0 -1
  260. package/dist/ItalianConverter.js +0 -3
  261. package/dist/ItalianConverter.js.map +0 -1
  262. package/dist/JapaneseConverter.js +0 -3
  263. package/dist/JapaneseConverter.js.map +0 -1
  264. package/dist/KannadaConverter.js +0 -3
  265. package/dist/KannadaConverter.js.map +0 -1
  266. package/dist/KoreanConverter.js +0 -3
  267. package/dist/KoreanConverter.js.map +0 -1
  268. package/dist/LatvianConverter.js +0 -3
  269. package/dist/LatvianConverter.js.map +0 -1
  270. package/dist/LithuanianConverter.js +0 -3
  271. package/dist/LithuanianConverter.js.map +0 -1
  272. package/dist/MalayConverter.js +0 -3
  273. package/dist/MalayConverter.js.map +0 -1
  274. package/dist/MarathiConverter.js +0 -3
  275. package/dist/MarathiConverter.js.map +0 -1
  276. package/dist/NorwegianBokmalConverter.js +0 -3
  277. package/dist/NorwegianBokmalConverter.js.map +0 -1
  278. package/dist/PersianConverter.js +0 -3
  279. package/dist/PersianConverter.js.map +0 -1
  280. package/dist/PolishConverter.js +0 -3
  281. package/dist/PolishConverter.js.map +0 -1
  282. package/dist/PortugueseConverter.js +0 -3
  283. package/dist/PortugueseConverter.js.map +0 -1
  284. package/dist/PunjabiConverter.js +0 -3
  285. package/dist/PunjabiConverter.js.map +0 -1
  286. package/dist/RomanianConverter.js +0 -3
  287. package/dist/RomanianConverter.js.map +0 -1
  288. package/dist/RussianConverter.js +0 -3
  289. package/dist/RussianConverter.js.map +0 -1
  290. package/dist/SerbianCyrillicConverter.js +0 -3
  291. package/dist/SerbianCyrillicConverter.js.map +0 -1
  292. package/dist/SerbianLatinConverter.js +0 -3
  293. package/dist/SerbianLatinConverter.js.map +0 -1
  294. package/dist/SimplifiedChineseConverter.js +0 -3
  295. package/dist/SimplifiedChineseConverter.js.map +0 -1
  296. package/dist/SpanishConverter.js +0 -3
  297. package/dist/SpanishConverter.js.map +0 -1
  298. package/dist/SwahiliConverter.js +0 -3
  299. package/dist/SwahiliConverter.js.map +0 -1
  300. package/dist/SwedishConverter.js +0 -3
  301. package/dist/SwedishConverter.js.map +0 -1
  302. package/dist/TamilConverter.js +0 -3
  303. package/dist/TamilConverter.js.map +0 -1
  304. package/dist/TeluguConverter.js +0 -3
  305. package/dist/TeluguConverter.js.map +0 -1
  306. package/dist/ThaiConverter.js +0 -3
  307. package/dist/ThaiConverter.js.map +0 -1
  308. package/dist/TraditionalChineseConverter.js +0 -3
  309. package/dist/TraditionalChineseConverter.js.map +0 -1
  310. package/dist/TurkishConverter.js +0 -3
  311. package/dist/TurkishConverter.js.map +0 -1
  312. package/dist/UkrainianConverter.js +0 -3
  313. package/dist/UkrainianConverter.js.map +0 -1
  314. package/dist/UrduConverter.js +0 -3
  315. package/dist/UrduConverter.js.map +0 -1
  316. package/dist/VietnameseConverter.js +0 -3
  317. package/dist/VietnameseConverter.js.map +0 -1
  318. package/lib/classes/abstract-language.d.ts +0 -178
  319. package/lib/classes/abstract-language.js +0 -268
  320. package/lib/classes/greedy-scale-language.d.ts +0 -109
  321. package/lib/classes/greedy-scale-language.js +0 -201
  322. package/lib/classes/slavic-language.d.ts +0 -148
  323. package/lib/classes/slavic-language.js +0 -281
  324. package/lib/classes/south-asian-language.d.ts +0 -70
  325. package/lib/classes/south-asian-language.js +0 -154
  326. package/lib/classes/turkic-language.d.ts +0 -26
  327. package/lib/classes/turkic-language.js +0 -59
@@ -1,159 +1,205 @@
1
- import { AbstractLanguage } from '../classes/abstract-language.js'
2
-
3
1
  /**
4
- * Arabic language converter.
2
+ * Arabic language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter with gender agreement and complex pluralization.
5
5
  *
6
- * Supports:
6
+ * Key features:
7
7
  * - Gender agreement (masculine/feminine forms)
8
8
  * - Complex pluralization (singular/dual/plural)
9
9
  * - Traditional Arabic number naming conventions
10
- * - Right-to-left text orientation
10
+ * - "و" (and) conjunction between segments
11
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
12
 
41
- constructor (options = {}) {
42
- super()
13
+ import { parseNumericValue } from '../utils/parse-numeric.js'
14
+ import { validateOptions } from '../utils/validate-options.js'
43
15
 
44
- this.setOptions({
45
- gender: 'masculine'
46
- }, options)
16
+ // ============================================================================
17
+ // Vocabulary
18
+ // ============================================================================
47
19
 
48
- // Allow custom negativeWord via options
49
- if (options.negativeWord !== undefined) {
50
- this.negativeWord = options.negativeWord
51
- }
52
- }
20
+ const TENS = ['عشرون', 'ثلاثون', 'أربعون', 'خمسون', 'ستون', 'سبعون', 'ثمانون', 'تسعون']
21
+ const HUNDREDS = ['', 'مائة', 'مئتان', 'ثلاثمائة', 'أربعمائة', 'خمسمائة', 'ستمائة', 'سبعمائة', 'ثمانمائة', 'تسعمائة']
22
+
23
+ // Magnitude words with three forms: singular, appended (tanween), plural
24
+ const SCALE_WORDS = ['مائة', 'ألف', 'مليون', 'مليار', 'تريليون', 'كوادريليون', 'كوينتليون', 'سكستيليون']
25
+ const SCALE_APPENDED = ['', 'ألفاً', 'مليوناً', 'ملياراً', 'تريليوناً', 'كوادريليوناً', 'كوينتليوناً', 'سكستيليوناً']
26
+ const SCALE_PLURAL = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات']
27
+
28
+ // Dual forms
29
+ const DUAL = ['مئتان', 'ألفان', 'مليونان', 'ملياران', 'تريليونان', 'كوادريليونان', 'كوينتليونان', 'سكستيليونان']
30
+ const DUAL_APPENDED = ['مئتا', 'ألفا', 'مليونا', 'مليارا', 'تريليونا', 'كوادريليونا', 'كوينتليونا', 'سكستيليونا']
31
+
32
+ // Gender-specific forms (1-19)
33
+ const ONES_MASC = ['واحد', 'اثنان', 'ثلاثة', 'أربعة', 'خمسة', 'ستة', 'سبعة', 'ثمانية', 'تسعة', 'عشرة', 'أحد عشر', 'اثنا عشر', 'ثلاثة عشر', 'أربعة عشر', 'خمسة عشر', 'ستة عشر', 'سبعة عشر', 'ثمانية عشر', 'تسعة عشر']
34
+ const ONES_FEM = ['واحدة', 'اثنتان', 'ثلاث', 'أربع', 'خمس', 'ست', 'سبع', 'ثمان', 'تسع', 'عشر', 'إحدى عشرة', 'اثنتا عشرة', 'ثلاث عشرة', 'أربع عشرة', 'خمس عشرة', 'ست عشرة', 'سبع عشرة', 'ثماني عشرة', 'تسع عشرة']
53
35
 
54
- /** Selects masculine or feminine number forms based on options. */
55
- get selectedOnes () {
56
- return this.ones[this.options.gender === 'feminine' ? 'feminine' : 'masculine']
36
+ const ZERO = 'صفر'
37
+ const NEGATIVE = 'ناقص'
38
+ const DECIMAL_SEP = 'فاصلة'
39
+ const AND = 'و'
40
+
41
+ // ============================================================================
42
+ // Conversion Functions
43
+ // ============================================================================
44
+
45
+ /**
46
+ * Convert a 3-digit group to words.
47
+ * Returns a clean string with no leading/trailing spaces.
48
+ * Arabic "و" (and) is attached to following word: "مائة وخمسة" not "مائة و خمسة"
49
+ */
50
+ function segmentToWords (groupNumber, groupLevel, fullNumber, ones) {
51
+ const tensValue = groupNumber % 100
52
+ const hundredsDigit = Math.trunc(groupNumber / 100)
53
+ let result = ''
54
+
55
+ // Process hundreds
56
+ if (hundredsDigit > 0) {
57
+ if (tensValue === 0 && hundredsDigit === 2) {
58
+ result = DUAL[0]
59
+ } else {
60
+ const hundredsWord = HUNDREDS[hundredsDigit]
61
+ if (hundredsWord) {
62
+ result = hundredsWord
63
+ if (tensValue !== 0) {
64
+ result += ' ' + AND // "مائة و" - و attaches to next word
65
+ }
66
+ }
67
+ }
57
68
  }
58
69
 
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
- }
70
+ // Process tens and ones
71
+ if (tensValue > 0) {
72
+ if (tensValue < 20) {
73
+ if (tensValue === 2 && hundredsDigit === 0 && groupLevel > 0) {
74
+ const numValue = Number(fullNumber)
75
+ const pow = Math.trunc(Math.log10(numValue))
76
+ if (pow % 3 === 0 && fullNumber === BigInt(2 * Math.pow(10, pow))) {
77
+ result += (groupNumber === 2 ? DUAL[groupLevel] : DUAL_APPENDED[groupLevel])
78
+ } else {
79
+ result += DUAL[groupLevel]
77
80
  }
81
+ } else if (tensValue === 1 && groupLevel > 0) {
82
+ result += SCALE_WORDS[groupLevel]
83
+ } else {
84
+ result += ones[tensValue - 1]
78
85
  }
86
+ } else {
87
+ const onesDigit = tensValue % 10
88
+ const tensIndex = Math.trunc(tensValue / 10) - 2
89
+
90
+ if (onesDigit > 0) {
91
+ result += ones[onesDigit - 1] + ' ' + AND // "ستة و" attaches to tens
92
+ }
93
+ result += TENS[tensIndex]
79
94
  }
95
+ }
96
+
97
+ return result
98
+ }
99
+
100
+ function integerToWords (n, options) {
101
+ if (n === 0n) return ZERO
102
+
103
+ const gender = options.gender || 'masculine'
104
+ const ones = gender === 'feminine' ? ONES_FEM : ONES_MASC
105
+
106
+ let temp = n
107
+ let group = 0
108
+ const groups = []
109
+
110
+ while (temp > 0n) {
111
+ const numberToProcess = Number(temp % 1000n)
112
+ temp = temp / 1000n
113
+
114
+ if (numberToProcess > 0) {
115
+ const groupDescription = segmentToWords(numberToProcess, group, n, ones)
80
116
 
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]
117
+ if (groupDescription) {
118
+ let groupText = groupDescription
119
+
120
+ // Add scale word for groups > 0
121
+ if (group > 0 && numberToProcess > 2) {
122
+ const remainder = numberToProcess % 100
123
+ if (remainder === 1) {
124
+ groupText += ' ' + SCALE_WORDS[group]
125
+ } else if (numberToProcess >= 3 && numberToProcess <= 10) {
126
+ groupText += ' ' + SCALE_PLURAL[group]
90
127
  } else {
91
- returnValue = this.dualWords[groupLevel]
128
+ groupText += ' ' + (groups.length > 0 ? SCALE_APPENDED[group] : SCALE_WORDS[group])
92
129
  }
93
- } else if (tens === 1 && groupLevel > 0) {
94
- returnValue += this.scaleWords[groupLevel]
95
- } else {
96
- returnValue += this.selectedOnes[tens - 1]
97
130
  }
98
- } else { // 20 -> 99
99
- const ones = tens % 10
100
- const tensIndex = Math.trunc(tens / 10) - 2
101
131
 
102
- if (ones > 0) {
103
- returnValue += this.selectedOnes[ones - 1]
104
- returnValue += ' و'
105
- }
106
- returnValue += this.tensWords[tensIndex]
132
+ groups.unshift(groupText)
107
133
  }
108
134
  }
109
135
 
110
- return returnValue
136
+ group++
111
137
  }
112
138
 
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
- }
139
+ // Join groups with و (and) - space before و, attaches to next word
140
+ // Use simple join since segmentToWords returns clean strings
141
+ if (groups.length === 1) return groups[0]
148
142
 
149
- // Add group description (prepend for RTL)
150
- result = groupDescription + ' ' + result
151
- }
152
- }
143
+ // Build result: "group1 وgroup2 وgroup3"
144
+ let result = groups[0]
145
+ for (let i = 1; i < groups.length; i++) {
146
+ result += ' ' + AND + groups[i]
147
+ }
148
+ return result
149
+ }
153
150
 
154
- group++
155
- }
151
+ function decimalPartToWords (decimalPart, options) {
152
+ const parts = []
153
+ let i = 0
154
+
155
+ while (i < decimalPart.length && decimalPart[i] === '0') {
156
+ parts.push(ZERO)
157
+ i++
158
+ }
159
+
160
+ const remainder = decimalPart.slice(i)
161
+ if (remainder) {
162
+ parts.push(integerToWords(BigInt(remainder), options))
163
+ }
156
164
 
157
- return result.replace(/\s+/g, ' ').trim()
165
+ return parts.join(' ')
166
+ }
167
+
168
+ /**
169
+ * Converts a numeric value to Arabic words.
170
+ *
171
+ * @param {number | string | bigint} value - The numeric value to convert
172
+ * @param {Object} [options] - Optional configuration
173
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
174
+ * @param {string} [options.negativeWord] - Custom word for negative numbers
175
+ * @returns {string} The number in Arabic words
176
+ *
177
+ * @example
178
+ * toWords(1) // 'واحد'
179
+ * toWords(1, {gender: 'feminine'}) // 'واحدة'
180
+ */
181
+ function toWords (value, options) {
182
+ options = validateOptions(options)
183
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
184
+
185
+ const parts = []
186
+
187
+ if (isNegative) {
188
+ parts.push(options.negativeWord || NEGATIVE)
189
+ }
190
+
191
+ parts.push(integerToWords(integerPart, options))
192
+
193
+ if (decimalPart) {
194
+ parts.push(DECIMAL_SEP)
195
+ parts.push(decimalPartToWords(decimalPart, options))
158
196
  }
197
+
198
+ return parts.join(' ')
159
199
  }
200
+
201
+ // ============================================================================
202
+ // Exports
203
+ // ============================================================================
204
+
205
+ export { toWords }
@@ -1,12 +1,7 @@
1
1
  /**
2
- * Azerbaijani language converter.
2
+ * Converts a numeric value to Azerbaijani words.
3
3
  *
4
- * Supports:
5
- * - Implicit "bir" (one) omission before hundreds and thousands
6
- * - Turkic language number patterns
7
- * - Large numbers up to quintillion
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Azerbaijani words
8
6
  */
9
- export class Azerbaijani extends TurkicLanguage {
10
- scaleWords: (string | bigint)[][];
11
- }
12
- import { TurkicLanguage } from '../classes/turkic-language.js';
7
+ export function toWords(value: number | string | bigint): string;
@@ -1,42 +1,176 @@
1
- import { TurkicLanguage } from '../classes/turkic-language.js'
2
-
3
1
  /**
4
- * Azerbaijani language converter.
2
+ * Azerbaijani language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter with precomputed lookup tables.
5
5
  *
6
- * Supports:
6
+ * Key features:
7
+ * - Turkic language patterns
7
8
  * - Implicit "bir" (one) omission before hundreds and thousands
8
- * - Turkic language number patterns
9
- * - Large numbers up to quintillion
9
+ * - Short scale naming
10
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']]
11
+
12
+ import { parseNumericValue } from '../utils/parse-numeric.js'
13
+
14
+ // ============================================================================
15
+ // Vocabulary
16
+ // ============================================================================
17
+
18
+ const ONES = ['', 'bir', 'iki', 'üç', 'dörd', 'beş', 'altı', 'yeddi', 'səkkiz', 'doqquz']
19
+ const TEENS = ['on', 'on bir', 'on iki', 'on üç', 'on dörd', 'on beş', 'on altı', 'on yeddi', 'on səkkiz', 'on doqquz']
20
+ const TENS = ['', '', 'iyirmi', 'otuz', 'qırx', 'əlli', 'altmış', 'yetmiş', 'səksən', 'doxsan']
21
+
22
+ const HUNDRED = 'yüz'
23
+ const THOUSAND = 'min'
24
+
25
+ const ZERO = 'sıfır'
26
+ const NEGATIVE = 'mənfi'
27
+ const DECIMAL_SEP = 'nöqtə'
28
+
29
+ // Short scale
30
+ const SCALE_WORDS = ['', THOUSAND, 'milyon', 'milyar', 'trilyon', 'katrilyon', 'kentilyon']
31
+
32
+ // ============================================================================
33
+ // Precomputed Lookup Table
34
+ // ============================================================================
35
+
36
+ function buildSegment (n) {
37
+ if (n === 0) return ''
38
+
39
+ const ones = n % 10
40
+ const tensDigit = Math.floor(n / 10) % 10
41
+ const hundredsDigit = Math.floor(n / 100)
42
+
43
+ const parts = []
44
+
45
+ if (hundredsDigit > 0) {
46
+ if (hundredsDigit === 1) {
47
+ parts.push(HUNDRED)
48
+ } else {
49
+ parts.push(ONES[hundredsDigit] + ' ' + HUNDRED)
50
+ }
51
+ }
52
+
53
+ if (tensDigit === 1) {
54
+ parts.push(TEENS[ones])
55
+ } else {
56
+ if (tensDigit > 1) {
57
+ parts.push(TENS[tensDigit])
58
+ }
59
+ if (ones > 0) {
60
+ parts.push(ONES[ones])
61
+ }
62
+ }
63
+
64
+ return parts.join(' ')
65
+ }
66
+
67
+ const SEGMENTS = new Array(1000)
68
+ for (let i = 0; i < 1000; i++) {
69
+ SEGMENTS[i] = buildSegment(i)
70
+ }
71
+
72
+ // ============================================================================
73
+ // Conversion Functions
74
+ // ============================================================================
75
+
76
+ function integerToWords (n) {
77
+ if (n === 0n) return ZERO
78
+
79
+ if (n < 1000n) {
80
+ return SEGMENTS[Number(n)]
81
+ }
82
+
83
+ return buildLargeNumberWords(n)
42
84
  }
85
+
86
+ function buildLargeNumberWords (n) {
87
+ const numStr = n.toString()
88
+ const len = numStr.length
89
+
90
+ const segments = []
91
+ const segmentSize = 3
92
+
93
+ const remainderLen = len % segmentSize
94
+ let pos = 0
95
+ if (remainderLen > 0) {
96
+ segments.push(Number(numStr.slice(0, remainderLen)))
97
+ pos = remainderLen
98
+ }
99
+ while (pos < len) {
100
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
101
+ pos += segmentSize
102
+ }
103
+
104
+ const parts = []
105
+ let scaleIndex = segments.length - 1
106
+
107
+ for (let i = 0; i < segments.length; i++) {
108
+ const segment = segments[i]
109
+
110
+ if (segment !== 0) {
111
+ const scaleWord = SCALE_WORDS[scaleIndex] || ''
112
+
113
+ if (scaleIndex === 0) {
114
+ parts.push(SEGMENTS[segment])
115
+ } else if (scaleIndex === 1 && segment === 1) {
116
+ // Omit "bir" before thousand
117
+ parts.push(scaleWord)
118
+ } else {
119
+ parts.push(SEGMENTS[segment] + ' ' + scaleWord)
120
+ }
121
+ }
122
+
123
+ scaleIndex--
124
+ }
125
+
126
+ return parts.join(' ')
127
+ }
128
+
129
+ function decimalPartToWords (decimalPart) {
130
+ let result = ''
131
+ let i = 0
132
+
133
+ while (i < decimalPart.length && decimalPart[i] === '0') {
134
+ if (result) result += ' '
135
+ result += ZERO
136
+ i++
137
+ }
138
+
139
+ const remainder = decimalPart.slice(i)
140
+ if (remainder) {
141
+ if (result) result += ' '
142
+ result += integerToWords(BigInt(remainder))
143
+ }
144
+
145
+ return result
146
+ }
147
+
148
+ /**
149
+ * Converts a numeric value to Azerbaijani words.
150
+ *
151
+ * @param {number | string | bigint} value - The numeric value to convert
152
+ * @returns {string} The number in Azerbaijani words
153
+ */
154
+ function toWords (value) {
155
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
156
+
157
+ let result = ''
158
+
159
+ if (isNegative) {
160
+ result = NEGATIVE + ' '
161
+ }
162
+
163
+ result += integerToWords(integerPart)
164
+
165
+ if (decimalPart) {
166
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
167
+ }
168
+
169
+ return result
170
+ }
171
+
172
+ // ============================================================================
173
+ // Exports
174
+ // ============================================================================
175
+
176
+ export { toWords }
@@ -1,11 +1,7 @@
1
1
  /**
2
- * Bangla language converter.
2
+ * Converts a numeric value to Bengali words.
3
3
  *
4
- * Supports:
5
- * - Indian numbering system (হাজার, লাখ, কোটি)
6
- * - Bangla script (Bengali)
7
- * - Complete word forms for 0-99
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Bengali words
8
6
  */
9
- export class Bangla extends SouthAsianLanguage {
10
- }
11
- import { SouthAsianLanguage } from '../classes/south-asian-language.js';
7
+ export function toWords(value: number | string | bigint): string;