n2words 2.0.0 → 3.1.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 (335) hide show
  1. package/CHANGELOG.md +64 -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/ka.js +3 -0
  56. package/dist/languages/ka.js.map +1 -0
  57. package/dist/languages/kn.js +3 -0
  58. package/dist/languages/kn.js.map +1 -0
  59. package/dist/languages/ko.js +3 -0
  60. package/dist/languages/ko.js.map +1 -0
  61. package/dist/languages/lt.js +3 -0
  62. package/dist/languages/lt.js.map +1 -0
  63. package/dist/languages/lv.js +3 -0
  64. package/dist/languages/lv.js.map +1 -0
  65. package/dist/languages/mr.js +3 -0
  66. package/dist/languages/mr.js.map +1 -0
  67. package/dist/languages/ms.js +3 -0
  68. package/dist/languages/ms.js.map +1 -0
  69. package/dist/languages/nb.js +3 -0
  70. package/dist/languages/nb.js.map +1 -0
  71. package/dist/languages/nl.js +3 -0
  72. package/dist/languages/nl.js.map +1 -0
  73. package/dist/languages/pa.js +3 -0
  74. package/dist/languages/pa.js.map +1 -0
  75. package/dist/languages/pl.js +3 -0
  76. package/dist/languages/pl.js.map +1 -0
  77. package/dist/languages/pt.js +3 -0
  78. package/dist/languages/pt.js.map +1 -0
  79. package/dist/languages/ro.js +3 -0
  80. package/dist/languages/ro.js.map +1 -0
  81. package/dist/languages/ru.js +3 -0
  82. package/dist/languages/ru.js.map +1 -0
  83. package/dist/languages/sr-Cyrl.js +3 -0
  84. package/dist/languages/sr-Cyrl.js.map +1 -0
  85. package/dist/languages/sr-Latn.js +3 -0
  86. package/dist/languages/sr-Latn.js.map +1 -0
  87. package/dist/languages/sv.js +3 -0
  88. package/dist/languages/sv.js.map +1 -0
  89. package/dist/languages/sw.js +3 -0
  90. package/dist/languages/sw.js.map +1 -0
  91. package/dist/languages/ta.js +3 -0
  92. package/dist/languages/ta.js.map +1 -0
  93. package/dist/languages/te.js +3 -0
  94. package/dist/languages/te.js.map +1 -0
  95. package/dist/languages/th.js +3 -0
  96. package/dist/languages/th.js.map +1 -0
  97. package/dist/languages/tr.js +3 -0
  98. package/dist/languages/tr.js.map +1 -0
  99. package/dist/languages/uk.js +3 -0
  100. package/dist/languages/uk.js.map +1 -0
  101. package/dist/languages/ur.js +3 -0
  102. package/dist/languages/ur.js.map +1 -0
  103. package/dist/languages/vi.js +3 -0
  104. package/dist/languages/vi.js.map +1 -0
  105. package/dist/languages/yo.js +3 -0
  106. package/dist/languages/yo.js.map +1 -0
  107. package/dist/languages/zh-Hans.js +3 -0
  108. package/dist/languages/zh-Hans.js.map +1 -0
  109. package/dist/languages/zh-Hant.js +3 -0
  110. package/dist/languages/zh-Hant.js.map +1 -0
  111. package/dist/n2words.js +2 -2
  112. package/dist/n2words.js.map +1 -1
  113. package/lib/languages/am-Latn.d.ts +7 -0
  114. package/lib/languages/am-Latn.js +159 -0
  115. package/lib/languages/am.d.ts +7 -0
  116. package/lib/languages/am.js +159 -0
  117. package/lib/languages/ar.d.ts +14 -27
  118. package/lib/languages/ar.js +175 -129
  119. package/lib/languages/az.d.ts +4 -9
  120. package/lib/languages/az.js +166 -37
  121. package/lib/languages/bn.d.ts +4 -8
  122. package/lib/languages/bn.js +159 -124
  123. package/lib/languages/cs.d.ts +15 -85
  124. package/lib/languages/cs.js +293 -114
  125. package/lib/languages/da.d.ts +11 -12
  126. package/lib/languages/da.js +269 -101
  127. package/lib/languages/de.d.ts +14 -11
  128. package/lib/languages/de.js +305 -86
  129. package/lib/languages/el.d.ts +11 -11
  130. package/lib/languages/el.js +224 -78
  131. package/lib/languages/en.d.ts +14 -13
  132. package/lib/languages/en.js +228 -72
  133. package/lib/languages/es.d.ts +18 -12
  134. package/lib/languages/es.js +297 -103
  135. package/lib/languages/fa.d.ts +4 -44
  136. package/lib/languages/fa.js +112 -122
  137. package/lib/languages/fi.d.ts +14 -0
  138. package/lib/languages/fi.js +238 -0
  139. package/lib/languages/fil.d.ts +4 -13
  140. package/lib/languages/fil.js +196 -106
  141. package/lib/languages/fr-BE.d.ts +8 -8
  142. package/lib/languages/fr-BE.js +285 -19
  143. package/lib/languages/fr.d.ts +18 -12
  144. package/lib/languages/fr.js +339 -89
  145. package/lib/languages/gu.d.ts +4 -8
  146. package/lib/languages/gu.js +143 -125
  147. package/lib/languages/ha.d.ts +7 -0
  148. package/lib/languages/ha.js +225 -0
  149. package/lib/languages/hbo.d.ts +10 -110
  150. package/lib/languages/hbo.js +245 -214
  151. package/lib/languages/he.d.ts +10 -77
  152. package/lib/languages/he.js +231 -172
  153. package/lib/languages/hi.d.ts +4 -8
  154. package/lib/languages/hi.js +163 -124
  155. package/lib/languages/hr.d.ts +8 -77
  156. package/lib/languages/hr.js +200 -89
  157. package/lib/languages/hu.d.ts +4 -19
  158. package/lib/languages/hu.js +198 -119
  159. package/lib/languages/id.d.ts +4 -34
  160. package/lib/languages/id.js +166 -129
  161. package/lib/languages/it.d.ts +16 -34
  162. package/lib/languages/it.js +307 -97
  163. package/lib/languages/ja.d.ts +14 -14
  164. package/lib/languages/ja.js +221 -111
  165. package/lib/languages/ka.d.ts +17 -0
  166. package/lib/languages/ka.js +291 -0
  167. package/lib/languages/kn.d.ts +4 -8
  168. package/lib/languages/kn.js +143 -35
  169. package/lib/languages/ko.d.ts +11 -11
  170. package/lib/languages/ko.js +250 -49
  171. package/lib/languages/lt.d.ts +15 -67
  172. package/lib/languages/lt.js +287 -122
  173. package/lib/languages/lv.d.ts +15 -67
  174. package/lib/languages/lv.js +288 -106
  175. package/lib/languages/mr.d.ts +4 -8
  176. package/lib/languages/mr.js +143 -125
  177. package/lib/languages/ms.d.ts +4 -28
  178. package/lib/languages/ms.js +166 -116
  179. package/lib/languages/nb.d.ts +11 -9
  180. package/lib/languages/nb.js +272 -87
  181. package/lib/languages/nl.d.ts +23 -13
  182. package/lib/languages/nl.js +299 -133
  183. package/lib/languages/pa.d.ts +4 -8
  184. package/lib/languages/pa.js +151 -124
  185. package/lib/languages/pl.d.ts +19 -77
  186. package/lib/languages/pl.js +294 -87
  187. package/lib/languages/pt.d.ts +14 -26
  188. package/lib/languages/pt.js +272 -92
  189. package/lib/languages/ro.d.ts +15 -155
  190. package/lib/languages/ro.js +219 -235
  191. package/lib/languages/ru.d.ts +8 -82
  192. package/lib/languages/ru.js +239 -90
  193. package/lib/languages/sr-Cyrl.d.ts +8 -77
  194. package/lib/languages/sr-Cyrl.js +197 -89
  195. package/lib/languages/sr-Latn.d.ts +8 -77
  196. package/lib/languages/sr-Latn.js +197 -89
  197. package/lib/languages/sv.d.ts +11 -11
  198. package/lib/languages/sv.js +278 -74
  199. package/lib/languages/sw.d.ts +4 -36
  200. package/lib/languages/sw.js +133 -106
  201. package/lib/languages/ta.d.ts +4 -17
  202. package/lib/languages/ta.js +143 -202
  203. package/lib/languages/te.d.ts +4 -19
  204. package/lib/languages/te.js +133 -196
  205. package/lib/languages/th.d.ts +4 -14
  206. package/lib/languages/th.js +135 -91
  207. package/lib/languages/tr.d.ts +15 -9
  208. package/lib/languages/tr.js +245 -49
  209. package/lib/languages/uk.d.ts +8 -82
  210. package/lib/languages/uk.js +206 -78
  211. package/lib/languages/ur.d.ts +4 -8
  212. package/lib/languages/ur.js +151 -124
  213. package/lib/languages/vi.d.ts +14 -69
  214. package/lib/languages/vi.js +278 -129
  215. package/lib/languages/yo.d.ts +7 -0
  216. package/lib/languages/yo.js +303 -0
  217. package/lib/languages/zh-Hans.d.ts +8 -18
  218. package/lib/languages/zh-Hans.js +163 -92
  219. package/lib/languages/zh-Hant.d.ts +8 -18
  220. package/lib/languages/zh-Hant.js +181 -90
  221. package/lib/n2words.d.ts +55 -209
  222. package/lib/n2words.js +115 -530
  223. package/lib/utils/is-plain-object.d.ts +13 -0
  224. package/lib/utils/is-plain-object.js +17 -0
  225. package/lib/utils/parse-numeric.d.ts +17 -0
  226. package/lib/utils/parse-numeric.js +108 -0
  227. package/lib/utils/validate-options.d.ts +8 -0
  228. package/lib/utils/validate-options.js +16 -0
  229. package/package.json +26 -14
  230. package/dist/ArabicConverter.js +0 -3
  231. package/dist/ArabicConverter.js.map +0 -1
  232. package/dist/AzerbaijaniConverter.js +0 -3
  233. package/dist/AzerbaijaniConverter.js.map +0 -1
  234. package/dist/BanglaConverter.js +0 -3
  235. package/dist/BanglaConverter.js.map +0 -1
  236. package/dist/BiblicalHebrewConverter.js +0 -3
  237. package/dist/BiblicalHebrewConverter.js.map +0 -1
  238. package/dist/CroatianConverter.js +0 -3
  239. package/dist/CroatianConverter.js.map +0 -1
  240. package/dist/CzechConverter.js +0 -3
  241. package/dist/CzechConverter.js.map +0 -1
  242. package/dist/DanishConverter.js +0 -3
  243. package/dist/DanishConverter.js.map +0 -1
  244. package/dist/DutchConverter.js +0 -3
  245. package/dist/DutchConverter.js.map +0 -1
  246. package/dist/EnglishConverter.js +0 -3
  247. package/dist/EnglishConverter.js.map +0 -1
  248. package/dist/FilipinoConverter.js +0 -3
  249. package/dist/FilipinoConverter.js.map +0 -1
  250. package/dist/FrenchBelgiumConverter.js +0 -3
  251. package/dist/FrenchBelgiumConverter.js.map +0 -1
  252. package/dist/FrenchConverter.js +0 -3
  253. package/dist/FrenchConverter.js.map +0 -1
  254. package/dist/GermanConverter.js +0 -3
  255. package/dist/GermanConverter.js.map +0 -1
  256. package/dist/GreekConverter.js +0 -3
  257. package/dist/GreekConverter.js.map +0 -1
  258. package/dist/GujaratiConverter.js +0 -3
  259. package/dist/GujaratiConverter.js.map +0 -1
  260. package/dist/HebrewConverter.js +0 -3
  261. package/dist/HebrewConverter.js.map +0 -1
  262. package/dist/HindiConverter.js +0 -3
  263. package/dist/HindiConverter.js.map +0 -1
  264. package/dist/HungarianConverter.js +0 -3
  265. package/dist/HungarianConverter.js.map +0 -1
  266. package/dist/IndonesianConverter.js +0 -3
  267. package/dist/IndonesianConverter.js.map +0 -1
  268. package/dist/ItalianConverter.js +0 -3
  269. package/dist/ItalianConverter.js.map +0 -1
  270. package/dist/JapaneseConverter.js +0 -3
  271. package/dist/JapaneseConverter.js.map +0 -1
  272. package/dist/KannadaConverter.js +0 -3
  273. package/dist/KannadaConverter.js.map +0 -1
  274. package/dist/KoreanConverter.js +0 -3
  275. package/dist/KoreanConverter.js.map +0 -1
  276. package/dist/LatvianConverter.js +0 -3
  277. package/dist/LatvianConverter.js.map +0 -1
  278. package/dist/LithuanianConverter.js +0 -3
  279. package/dist/LithuanianConverter.js.map +0 -1
  280. package/dist/MalayConverter.js +0 -3
  281. package/dist/MalayConverter.js.map +0 -1
  282. package/dist/MarathiConverter.js +0 -3
  283. package/dist/MarathiConverter.js.map +0 -1
  284. package/dist/NorwegianBokmalConverter.js +0 -3
  285. package/dist/NorwegianBokmalConverter.js.map +0 -1
  286. package/dist/PersianConverter.js +0 -3
  287. package/dist/PersianConverter.js.map +0 -1
  288. package/dist/PolishConverter.js +0 -3
  289. package/dist/PolishConverter.js.map +0 -1
  290. package/dist/PortugueseConverter.js +0 -3
  291. package/dist/PortugueseConverter.js.map +0 -1
  292. package/dist/PunjabiConverter.js +0 -3
  293. package/dist/PunjabiConverter.js.map +0 -1
  294. package/dist/RomanianConverter.js +0 -3
  295. package/dist/RomanianConverter.js.map +0 -1
  296. package/dist/RussianConverter.js +0 -3
  297. package/dist/RussianConverter.js.map +0 -1
  298. package/dist/SerbianCyrillicConverter.js +0 -3
  299. package/dist/SerbianCyrillicConverter.js.map +0 -1
  300. package/dist/SerbianLatinConverter.js +0 -3
  301. package/dist/SerbianLatinConverter.js.map +0 -1
  302. package/dist/SimplifiedChineseConverter.js +0 -3
  303. package/dist/SimplifiedChineseConverter.js.map +0 -1
  304. package/dist/SpanishConverter.js +0 -3
  305. package/dist/SpanishConverter.js.map +0 -1
  306. package/dist/SwahiliConverter.js +0 -3
  307. package/dist/SwahiliConverter.js.map +0 -1
  308. package/dist/SwedishConverter.js +0 -3
  309. package/dist/SwedishConverter.js.map +0 -1
  310. package/dist/TamilConverter.js +0 -3
  311. package/dist/TamilConverter.js.map +0 -1
  312. package/dist/TeluguConverter.js +0 -3
  313. package/dist/TeluguConverter.js.map +0 -1
  314. package/dist/ThaiConverter.js +0 -3
  315. package/dist/ThaiConverter.js.map +0 -1
  316. package/dist/TraditionalChineseConverter.js +0 -3
  317. package/dist/TraditionalChineseConverter.js.map +0 -1
  318. package/dist/TurkishConverter.js +0 -3
  319. package/dist/TurkishConverter.js.map +0 -1
  320. package/dist/UkrainianConverter.js +0 -3
  321. package/dist/UkrainianConverter.js.map +0 -1
  322. package/dist/UrduConverter.js +0 -3
  323. package/dist/UrduConverter.js.map +0 -1
  324. package/dist/VietnameseConverter.js +0 -3
  325. package/dist/VietnameseConverter.js.map +0 -1
  326. package/lib/classes/abstract-language.d.ts +0 -178
  327. package/lib/classes/abstract-language.js +0 -268
  328. package/lib/classes/greedy-scale-language.d.ts +0 -109
  329. package/lib/classes/greedy-scale-language.js +0 -201
  330. package/lib/classes/slavic-language.d.ts +0 -148
  331. package/lib/classes/slavic-language.js +0 -281
  332. package/lib/classes/south-asian-language.d.ts +0 -70
  333. package/lib/classes/south-asian-language.js +0 -154
  334. package/lib/classes/turkic-language.d.ts +0 -26
  335. 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,171 @@
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 module with its own input validation, ready for subpath exports.
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
+ // ============================================================================
68
+ // Conversion Functions
69
+ // ============================================================================
70
+
71
+ function integerToWords (n) {
72
+ if (n === 0n) return ZERO
73
+
74
+ if (n < 1000n) {
75
+ return buildSegment(Number(n))
76
+ }
77
+
78
+ return buildLargeNumberWords(n)
42
79
  }
80
+
81
+ function buildLargeNumberWords (n) {
82
+ const numStr = n.toString()
83
+ const len = numStr.length
84
+
85
+ const segments = []
86
+ const segmentSize = 3
87
+
88
+ const remainderLen = len % segmentSize
89
+ let pos = 0
90
+ if (remainderLen > 0) {
91
+ segments.push(Number(numStr.slice(0, remainderLen)))
92
+ pos = remainderLen
93
+ }
94
+ while (pos < len) {
95
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
96
+ pos += segmentSize
97
+ }
98
+
99
+ const parts = []
100
+ let scaleIndex = segments.length - 1
101
+
102
+ for (let i = 0; i < segments.length; i++) {
103
+ const segment = segments[i]
104
+
105
+ if (segment !== 0) {
106
+ const scaleWord = SCALE_WORDS[scaleIndex] || ''
107
+
108
+ if (scaleIndex === 0) {
109
+ parts.push(buildSegment(segment))
110
+ } else if (scaleIndex === 1 && segment === 1) {
111
+ // Omit "bir" before thousand
112
+ parts.push(scaleWord)
113
+ } else {
114
+ parts.push(buildSegment(segment) + ' ' + scaleWord)
115
+ }
116
+ }
117
+
118
+ scaleIndex--
119
+ }
120
+
121
+ return parts.join(' ')
122
+ }
123
+
124
+ function decimalPartToWords (decimalPart) {
125
+ let result = ''
126
+ let i = 0
127
+
128
+ while (i < decimalPart.length && decimalPart[i] === '0') {
129
+ if (result) result += ' '
130
+ result += ZERO
131
+ i++
132
+ }
133
+
134
+ const remainder = decimalPart.slice(i)
135
+ if (remainder) {
136
+ if (result) result += ' '
137
+ result += integerToWords(BigInt(remainder))
138
+ }
139
+
140
+ return result
141
+ }
142
+
143
+ /**
144
+ * Converts a numeric value to Azerbaijani words.
145
+ *
146
+ * @param {number | string | bigint} value - The numeric value to convert
147
+ * @returns {string} The number in Azerbaijani words
148
+ */
149
+ function toWords (value) {
150
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
151
+
152
+ let result = ''
153
+
154
+ if (isNegative) {
155
+ result = NEGATIVE + ' '
156
+ }
157
+
158
+ result += integerToWords(integerPart)
159
+
160
+ if (decimalPart) {
161
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
162
+ }
163
+
164
+ return result
165
+ }
166
+
167
+ // ============================================================================
168
+ // Exports
169
+ // ============================================================================
170
+
171
+ 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;