n2words 1.24.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 (280) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +183 -156
  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 -2
  8. package/dist/languages/ar.js.map +1 -1
  9. package/dist/languages/az.js +3 -2
  10. package/dist/languages/az.js.map +1 -1
  11. package/dist/languages/bn.js +3 -2
  12. package/dist/languages/bn.js.map +1 -1
  13. package/dist/languages/cs.js +3 -2
  14. package/dist/languages/cs.js.map +1 -1
  15. package/dist/languages/da.js +3 -2
  16. package/dist/languages/da.js.map +1 -1
  17. package/dist/languages/de.js +3 -2
  18. package/dist/languages/de.js.map +1 -1
  19. package/dist/languages/el.js +3 -2
  20. package/dist/languages/el.js.map +1 -1
  21. package/dist/languages/en.js +3 -2
  22. package/dist/languages/en.js.map +1 -1
  23. package/dist/languages/es.js +3 -2
  24. package/dist/languages/es.js.map +1 -1
  25. package/dist/languages/fa.js +3 -2
  26. package/dist/languages/fa.js.map +1 -1
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -2
  30. package/dist/languages/fil.js.map +1 -1
  31. package/dist/languages/fr-BE.js +3 -2
  32. package/dist/languages/fr-BE.js.map +1 -1
  33. package/dist/languages/fr.js +3 -2
  34. package/dist/languages/fr.js.map +1 -1
  35. package/dist/languages/gu.js +3 -2
  36. package/dist/languages/gu.js.map +1 -1
  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 -2
  42. package/dist/languages/he.js.map +1 -1
  43. package/dist/languages/hi.js +3 -2
  44. package/dist/languages/hi.js.map +1 -1
  45. package/dist/languages/hr.js +3 -2
  46. package/dist/languages/hr.js.map +1 -1
  47. package/dist/languages/hu.js +3 -2
  48. package/dist/languages/hu.js.map +1 -1
  49. package/dist/languages/id.js +3 -2
  50. package/dist/languages/id.js.map +1 -1
  51. package/dist/languages/it.js +3 -2
  52. package/dist/languages/it.js.map +1 -1
  53. package/dist/languages/ja.js +3 -2
  54. package/dist/languages/ja.js.map +1 -1
  55. package/dist/languages/kn.js +3 -2
  56. package/dist/languages/kn.js.map +1 -1
  57. package/dist/languages/ko.js +3 -2
  58. package/dist/languages/ko.js.map +1 -1
  59. package/dist/languages/lt.js +3 -2
  60. package/dist/languages/lt.js.map +1 -1
  61. package/dist/languages/lv.js +3 -2
  62. package/dist/languages/lv.js.map +1 -1
  63. package/dist/languages/mr.js +3 -2
  64. package/dist/languages/mr.js.map +1 -1
  65. package/dist/languages/ms.js +3 -2
  66. package/dist/languages/ms.js.map +1 -1
  67. package/dist/languages/nb.js +3 -2
  68. package/dist/languages/nb.js.map +1 -1
  69. package/dist/languages/nl.js +3 -2
  70. package/dist/languages/nl.js.map +1 -1
  71. package/dist/languages/pa.js +3 -0
  72. package/dist/languages/pa.js.map +1 -0
  73. package/dist/languages/pl.js +3 -2
  74. package/dist/languages/pl.js.map +1 -1
  75. package/dist/languages/pt.js +3 -2
  76. package/dist/languages/pt.js.map +1 -1
  77. package/dist/languages/ro.js +3 -2
  78. package/dist/languages/ro.js.map +1 -1
  79. package/dist/languages/ru.js +3 -2
  80. package/dist/languages/ru.js.map +1 -1
  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 -2
  84. package/dist/languages/sr-Latn.js.map +1 -1
  85. package/dist/languages/sv.js +3 -2
  86. package/dist/languages/sv.js.map +1 -1
  87. package/dist/languages/sw.js +3 -2
  88. package/dist/languages/sw.js.map +1 -1
  89. package/dist/languages/ta.js +3 -2
  90. package/dist/languages/ta.js.map +1 -1
  91. package/dist/languages/te.js +3 -2
  92. package/dist/languages/te.js.map +1 -1
  93. package/dist/languages/th.js +3 -2
  94. package/dist/languages/th.js.map +1 -1
  95. package/dist/languages/tr.js +3 -2
  96. package/dist/languages/tr.js.map +1 -1
  97. package/dist/languages/uk.js +3 -2
  98. package/dist/languages/uk.js.map +1 -1
  99. package/dist/languages/ur.js +3 -2
  100. package/dist/languages/ur.js.map +1 -1
  101. package/dist/languages/vi.js +3 -2
  102. package/dist/languages/vi.js.map +1 -1
  103. package/dist/languages/zh-Hans.js +3 -2
  104. package/dist/languages/zh-Hans.js.map +1 -1
  105. package/dist/languages/zh-Hant.js +3 -0
  106. package/dist/languages/zh-Hant.js.map +1 -0
  107. package/dist/n2words.js +3 -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 +17 -0
  114. package/lib/languages/ar.js +171 -209
  115. package/lib/languages/az.d.ts +7 -0
  116. package/lib/languages/az.js +167 -49
  117. package/lib/languages/bn.d.ts +7 -0
  118. package/lib/languages/bn.js +142 -123
  119. package/lib/languages/cs.d.ts +18 -0
  120. package/lib/languages/cs.js +303 -176
  121. package/lib/languages/da.d.ts +14 -0
  122. package/lib/languages/da.js +267 -139
  123. package/lib/languages/de.d.ts +17 -0
  124. package/lib/languages/de.js +310 -113
  125. package/lib/languages/el.d.ts +14 -0
  126. package/lib/languages/el.js +225 -98
  127. package/lib/languages/en.d.ts +17 -0
  128. package/lib/languages/en.js +235 -102
  129. package/lib/languages/es.d.ts +21 -0
  130. package/lib/languages/es.js +307 -125
  131. package/lib/languages/fa.d.ts +7 -0
  132. package/lib/languages/fa.js +115 -108
  133. package/lib/languages/fi.d.ts +14 -0
  134. package/lib/languages/fi.js +245 -0
  135. package/lib/languages/fil.d.ts +7 -0
  136. package/lib/languages/fil.js +199 -139
  137. package/lib/languages/fr-BE.d.ts +11 -0
  138. package/lib/languages/fr-BE.js +287 -48
  139. package/lib/languages/fr.d.ts +21 -0
  140. package/lib/languages/fr.js +343 -119
  141. package/lib/languages/gu.d.ts +7 -0
  142. package/lib/languages/gu.js +125 -144
  143. package/lib/languages/ha.d.ts +7 -0
  144. package/lib/languages/ha.js +230 -0
  145. package/lib/languages/hbo.d.ts +13 -0
  146. package/lib/languages/hbo.js +300 -0
  147. package/lib/languages/he.d.ts +13 -0
  148. package/lib/languages/he.js +230 -283
  149. package/lib/languages/hi.d.ts +7 -0
  150. package/lib/languages/hi.js +142 -123
  151. package/lib/languages/hr.d.ts +11 -0
  152. package/lib/languages/hr.js +190 -129
  153. package/lib/languages/hu.d.ts +7 -0
  154. package/lib/languages/hu.js +194 -133
  155. package/lib/languages/id.d.ts +7 -0
  156. package/lib/languages/id.js +167 -140
  157. package/lib/languages/it.d.ts +19 -0
  158. package/lib/languages/it.js +337 -108
  159. package/lib/languages/ja.d.ts +17 -0
  160. package/lib/languages/ja.js +224 -155
  161. package/lib/languages/kn.d.ts +7 -0
  162. package/lib/languages/kn.js +128 -62
  163. package/lib/languages/ko.d.ts +14 -0
  164. package/lib/languages/ko.js +250 -70
  165. package/lib/languages/lt.d.ts +18 -0
  166. package/lib/languages/lt.js +287 -148
  167. package/lib/languages/lv.d.ts +18 -0
  168. package/lib/languages/lv.js +291 -123
  169. package/lib/languages/mr.d.ts +7 -0
  170. package/lib/languages/mr.js +125 -144
  171. package/lib/languages/ms.d.ts +7 -0
  172. package/lib/languages/ms.js +171 -112
  173. package/lib/languages/nb.d.ts +14 -0
  174. package/lib/languages/nb.js +275 -100
  175. package/lib/languages/nl.d.ts +26 -0
  176. package/lib/languages/nl.js +307 -174
  177. package/lib/languages/pa.d.ts +7 -0
  178. package/lib/languages/pa.js +163 -0
  179. package/lib/languages/pl.d.ts +22 -0
  180. package/lib/languages/pl.js +299 -158
  181. package/lib/languages/pt.d.ts +17 -0
  182. package/lib/languages/pt.js +279 -120
  183. package/lib/languages/ro.d.ts +18 -0
  184. package/lib/languages/ro.js +214 -337
  185. package/lib/languages/ru.d.ts +11 -0
  186. package/lib/languages/ru.js +219 -95
  187. package/lib/languages/sr-Cyrl.d.ts +11 -0
  188. package/lib/languages/sr-Cyrl.js +215 -0
  189. package/lib/languages/sr-Latn.d.ts +11 -0
  190. package/lib/languages/sr-Latn.js +190 -132
  191. package/lib/languages/sv.d.ts +14 -0
  192. package/lib/languages/sv.js +280 -103
  193. package/lib/languages/sw.d.ts +7 -0
  194. package/lib/languages/sw.js +135 -103
  195. package/lib/languages/ta.d.ts +7 -0
  196. package/lib/languages/ta.js +133 -205
  197. package/lib/languages/te.d.ts +7 -0
  198. package/lib/languages/te.js +148 -213
  199. package/lib/languages/th.d.ts +7 -0
  200. package/lib/languages/th.js +139 -101
  201. package/lib/languages/tr.d.ts +18 -0
  202. package/lib/languages/tr.js +246 -66
  203. package/lib/languages/uk.d.ts +11 -0
  204. package/lib/languages/uk.js +197 -101
  205. package/lib/languages/ur.d.ts +7 -0
  206. package/lib/languages/ur.js +160 -123
  207. package/lib/languages/vi.d.ts +17 -0
  208. package/lib/languages/vi.js +287 -164
  209. package/lib/languages/zh-Hans.d.ts +11 -0
  210. package/lib/languages/zh-Hans.js +159 -142
  211. package/lib/languages/zh-Hant.d.ts +11 -0
  212. package/lib/languages/zh-Hant.js +202 -0
  213. package/lib/n2words.d.ts +53 -0
  214. package/lib/n2words.js +91 -227
  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 +118 -67
  222. package/dist/languages/pa-Guru.js +0 -2
  223. package/dist/languages/pa-Guru.js.map +0 -1
  224. package/lib/classes/abstract-language.js +0 -261
  225. package/lib/classes/greedy-scale-language.js +0 -195
  226. package/lib/classes/slavic-language.js +0 -251
  227. package/lib/classes/south-asian-language.js +0 -161
  228. package/lib/classes/turkic-language.js +0 -63
  229. package/lib/languages/pa-Guru.js +0 -126
  230. package/typings/classes/abstract-language.d.ts +0 -144
  231. package/typings/classes/greedy-scale-language.d.ts +0 -148
  232. package/typings/classes/slavic-language.d.ts +0 -145
  233. package/typings/classes/south-asian-language.d.ts +0 -101
  234. package/typings/classes/turkic-language.d.ts +0 -42
  235. package/typings/languages/ar.d.ts +0 -93
  236. package/typings/languages/az.d.ts +0 -25
  237. package/typings/languages/bn.d.ts +0 -1
  238. package/typings/languages/cs.d.ts +0 -120
  239. package/typings/languages/da.d.ts +0 -53
  240. package/typings/languages/de.d.ts +0 -26
  241. package/typings/languages/el.d.ts +0 -11
  242. package/typings/languages/en.d.ts +0 -30
  243. package/typings/languages/es.d.ts +0 -43
  244. package/typings/languages/fa.d.ts +0 -81
  245. package/typings/languages/fil.d.ts +0 -12
  246. package/typings/languages/fr-BE.d.ts +0 -41
  247. package/typings/languages/fr.d.ts +0 -43
  248. package/typings/languages/gu.d.ts +0 -12
  249. package/typings/languages/he.d.ts +0 -197
  250. package/typings/languages/hi.d.ts +0 -1
  251. package/typings/languages/hr.d.ts +0 -110
  252. package/typings/languages/hu.d.ts +0 -37
  253. package/typings/languages/id.d.ts +0 -69
  254. package/typings/languages/it.d.ts +0 -51
  255. package/typings/languages/ja.d.ts +0 -58
  256. package/typings/languages/kn.d.ts +0 -11
  257. package/typings/languages/ko.d.ts +0 -25
  258. package/typings/languages/lt.d.ts +0 -110
  259. package/typings/languages/lv.d.ts +0 -99
  260. package/typings/languages/mr.d.ts +0 -12
  261. package/typings/languages/ms.d.ts +0 -37
  262. package/typings/languages/nb.d.ts +0 -27
  263. package/typings/languages/nl.d.ts +0 -65
  264. package/typings/languages/pa-Guru.d.ts +0 -1
  265. package/typings/languages/pl.d.ts +0 -116
  266. package/typings/languages/pt.d.ts +0 -39
  267. package/typings/languages/ro.d.ts +0 -229
  268. package/typings/languages/ru.d.ts +0 -108
  269. package/typings/languages/sr-Latn.d.ts +0 -98
  270. package/typings/languages/sv.d.ts +0 -30
  271. package/typings/languages/sw.d.ts +0 -1
  272. package/typings/languages/ta.d.ts +0 -1
  273. package/typings/languages/te.d.ts +0 -1
  274. package/typings/languages/th.d.ts +0 -1
  275. package/typings/languages/tr.d.ts +0 -46
  276. package/typings/languages/uk.d.ts +0 -117
  277. package/typings/languages/ur.d.ts +0 -1
  278. package/typings/languages/vi.d.ts +0 -116
  279. package/typings/languages/zh-Hans.d.ts +0 -57
  280. package/typings/n2words.d.ts +0 -177
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Converts a numeric value to Amharic (Latin script) words.
3
+ *
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Amharic Latin words
6
+ */
7
+ export function toWords(value: number | string | bigint): string;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Amharic Latin language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter with precomputed lookup tables.
5
+ * Latin/ASCII romanization of Amharic numerals.
6
+ *
7
+ * Key features:
8
+ * - Romanized numerals (and, hulet, sost)
9
+ * - Teens formed with "asra" prefix
10
+ * - Keeps "one" before hundred: "and meto" (100)
11
+ * - Short scale naming
12
+ * - Per-digit decimal reading
13
+ */
14
+
15
+ import { parseNumericValue } from '../utils/parse-numeric.js'
16
+
17
+ // ============================================================================
18
+ // Vocabulary
19
+ // ============================================================================
20
+
21
+ const ONES = ['', 'and', 'hulet', 'sost', 'arat', 'amist', 'siddist', 'sebat', 'siment', 'zeteny']
22
+ const TEENS = ['asir', 'asra and', 'asra hulet', 'asra sost', 'asra arat', 'asra amist', 'asra siddist', 'asra sebat', 'asra siment', 'asra zeteny']
23
+ const TENS = ['', '', 'haya', 'selasa', 'arba', 'hamsa', 'silsa', 'seba', 'semanya', 'zetena']
24
+
25
+ const HUNDRED = 'meto'
26
+ const THOUSAND = 'shi'
27
+
28
+ const ZERO = 'zero'
29
+ const NEGATIVE = 'asitegna'
30
+ const DECIMAL_SEP = 'netib'
31
+
32
+ // Short scale
33
+ const SCALE_WORDS = ['', THOUSAND, 'miliyon', 'billiyon']
34
+
35
+ // ============================================================================
36
+ // Precomputed Lookup Table
37
+ // ============================================================================
38
+
39
+ function buildSegment (n) {
40
+ if (n === 0) return ''
41
+
42
+ const ones = n % 10
43
+ const tensDigit = Math.floor(n / 10) % 10
44
+ const hundredsDigit = Math.floor(n / 100)
45
+
46
+ const parts = []
47
+
48
+ // Amharic keeps "one" before hundred: "and meto" (100)
49
+ if (hundredsDigit > 0) {
50
+ parts.push(ONES[hundredsDigit] + ' ' + HUNDRED)
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)
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 {
116
+ parts.push(SEGMENTS[segment] + ' ' + scaleWord)
117
+ }
118
+ }
119
+
120
+ scaleIndex--
121
+ }
122
+
123
+ return parts.join(' ')
124
+ }
125
+
126
+ function decimalPartToWords (decimalPart) {
127
+ // Per-digit decimal reading
128
+ const digits = []
129
+ for (const char of decimalPart) {
130
+ const d = parseInt(char, 10)
131
+ digits.push(d === 0 ? ZERO : ONES[d])
132
+ }
133
+ return digits.join(' ')
134
+ }
135
+
136
+ /**
137
+ * Converts a numeric value to Amharic (Latin script) words.
138
+ *
139
+ * @param {number | string | bigint} value - The numeric value to convert
140
+ * @returns {string} The number in Amharic Latin words
141
+ */
142
+ function toWords (value) {
143
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
144
+
145
+ let result = ''
146
+
147
+ if (isNegative) {
148
+ result = NEGATIVE + ' '
149
+ }
150
+
151
+ result += integerToWords(integerPart)
152
+
153
+ if (decimalPart) {
154
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
155
+ }
156
+
157
+ return result
158
+ }
159
+
160
+ // ============================================================================
161
+ // Exports
162
+ // ============================================================================
163
+
164
+ export { toWords }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Converts a numeric value to Amharic words.
3
+ *
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Amharic words
6
+ */
7
+ export function toWords(value: number | string | bigint): string;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Amharic language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter with precomputed lookup tables.
5
+ * Native Ge'ez script (ግዕዝ) output.
6
+ *
7
+ * Key features:
8
+ * - Ge'ez/Ethiopic script numerals
9
+ * - Teens formed with "አስራ" prefix
10
+ * - Keeps "one" before hundred: "አንድ መቶ" (100)
11
+ * - Short scale naming
12
+ * - Per-digit decimal reading
13
+ */
14
+
15
+ import { parseNumericValue } from '../utils/parse-numeric.js'
16
+
17
+ // ============================================================================
18
+ // Vocabulary
19
+ // ============================================================================
20
+
21
+ const ONES = ['', 'አንድ', 'ሁለት', 'ሶስት', 'አራት', 'አምስት', 'ስድስት', 'ሰባት', 'ስምንት', 'ዘጠኝ']
22
+ const TEENS = ['አስር', 'አስራ አንድ', 'አስራ ሁለት', 'አስራ ሶስት', 'አስራ አራት', 'አስራ አምስት', 'አስራ ስድስት', 'አስራ ሰባት', 'አስራ ስምንት', 'አስራ ዘጠኝ']
23
+ const TENS = ['', '', 'ሃያ', 'ሰላሳ', 'አርባ', 'ሃምሳ', 'ስልሳ', 'ሰባ', 'ሰማንያ', 'ዘጠና']
24
+
25
+ const HUNDRED = 'መቶ'
26
+ const THOUSAND = 'ሺ'
27
+
28
+ const ZERO = 'ዜሮ'
29
+ const NEGATIVE = 'አሉታዊ'
30
+ const DECIMAL_SEP = 'ነጥብ'
31
+
32
+ // Short scale
33
+ const SCALE_WORDS = ['', THOUSAND, 'ሚሊዮን', 'ቢሊዮን']
34
+
35
+ // ============================================================================
36
+ // Precomputed Lookup Table
37
+ // ============================================================================
38
+
39
+ function buildSegment (n) {
40
+ if (n === 0) return ''
41
+
42
+ const ones = n % 10
43
+ const tensDigit = Math.floor(n / 10) % 10
44
+ const hundredsDigit = Math.floor(n / 100)
45
+
46
+ const parts = []
47
+
48
+ // Amharic keeps "one" before hundred: "አንድ መቶ" (100)
49
+ if (hundredsDigit > 0) {
50
+ parts.push(ONES[hundredsDigit] + ' ' + HUNDRED)
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)
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 {
116
+ parts.push(SEGMENTS[segment] + ' ' + scaleWord)
117
+ }
118
+ }
119
+
120
+ scaleIndex--
121
+ }
122
+
123
+ return parts.join(' ')
124
+ }
125
+
126
+ function decimalPartToWords (decimalPart) {
127
+ // Per-digit decimal reading
128
+ const digits = []
129
+ for (const char of decimalPart) {
130
+ const d = parseInt(char, 10)
131
+ digits.push(d === 0 ? ZERO : ONES[d])
132
+ }
133
+ return digits.join(' ')
134
+ }
135
+
136
+ /**
137
+ * Converts a numeric value to Amharic words.
138
+ *
139
+ * @param {number | string | bigint} value - The numeric value to convert
140
+ * @returns {string} The number in Amharic words
141
+ */
142
+ function toWords (value) {
143
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
144
+
145
+ let result = ''
146
+
147
+ if (isNegative) {
148
+ result = NEGATIVE + ' '
149
+ }
150
+
151
+ result += integerToWords(integerPart)
152
+
153
+ if (decimalPart) {
154
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
155
+ }
156
+
157
+ return result
158
+ }
159
+
160
+ // ============================================================================
161
+ // Exports
162
+ // ============================================================================
163
+
164
+ export { toWords }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Converts a numeric value to Arabic words.
3
+ *
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @param {Object} [options] - Optional configuration
6
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
7
+ * @param {string} [options.negativeWord] - Custom word for negative numbers
8
+ * @returns {string} The number in Arabic words
9
+ *
10
+ * @example
11
+ * toWords(1) // 'واحد'
12
+ * toWords(1, {gender: 'feminine'}) // 'واحدة'
13
+ */
14
+ export function toWords(value: number | string | bigint, options?: {
15
+ gender?: "masculine" | "feminine" | undefined;
16
+ negativeWord?: string | undefined;
17
+ }): string;