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
@@ -1,61 +1,300 @@
1
- import { French } from './fr.js'
2
-
3
1
  /**
4
- * @typedef {Object} BelgianFrenchOptions
5
- * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds.
6
- */
7
-
8
- /**
9
- * Belgian French language converter.
2
+ * French (Belgium) language converter - Functional Implementation
10
3
  *
11
- * Extends the French converter with Belgian French regional variant:
12
- * - Uses "septante" (70) instead of "soixante-dix"
13
- * - Uses "nonante" (90) instead of "quatre-vingt-dix"
14
- * - Maintains standard French "quatre-vingts" for 80
15
- * - More regular and logical number system than standard French
4
+ * Self-contained converter with precomputed lookup tables.
16
5
  *
17
- * Features:
18
- * - Regional number word variations (septante, nonante)
19
- * - Simplified tens naming (no complex arithmetic)
20
- * - Inherits all other French grammar rules from FR class
21
- * - Same pluralization and hyphenation patterns as standard French
6
+ * Belgian French differences from standard French:
7
+ * - septante (70) instead of soixante-dix
8
+ * - nonante (90) instead of quatre-vingt-dix
9
+ * - Keeps quatre-vingts (80) like standard French
10
+ * - Uses "septante et un" (71), "nonante et un" (91)
22
11
  */
23
- export class BelgianFrench extends French {
24
- /**
25
- * Initializes the Belgian French converter.
26
- *
27
- * @param {BelgianFrenchOptions} [options={}] Configuration options.
28
- */
29
- constructor (options = {}) {
30
- super(options)
31
- // Fill the empty placeholder slots with Belgian variants
32
- // First empty slot (index 10) is for 90n (between 100n and 80n)
33
- // Second empty slot (index 12) is for 70n (between 80n and 60n)
34
- this.scaleWordPairs = this.scaleWordPairs.map((pair, index) => {
35
- if (Array.isArray(pair) && pair.length === 0) {
36
- // Check next pair to determine which slot this is
37
- const nextPair = this.scaleWordPairs[index + 1]
38
- if (nextPair && nextPair[0] === 80n) {
39
- return [90n, 'nonante']
40
- } else if (nextPair && nextPair[0] === 60n) {
41
- return [70n, 'septante']
12
+
13
+ import { parseNumericValue } from '../utils/parse-numeric.js'
14
+ import { validateOptions } from '../utils/validate-options.js'
15
+
16
+ // ============================================================================
17
+ // Vocabulary
18
+ // ============================================================================
19
+
20
+ const ONES = ['', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf']
21
+ const TEENS = ['dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf']
22
+ const TENS = ['', '', 'vingt', 'trente', 'quarante', 'cinquante', 'soixante', 'septante', 'quatre-vingt', 'nonante']
23
+
24
+ // Scale words (long scale with -ard forms)
25
+ const SCALES = ['million', 'billion', 'trillion', 'quadrillion']
26
+ const SCALES_ARD = ['milliard', 'billiard', 'trilliard', 'quadrilliard']
27
+
28
+ const THOUSAND = 'mille'
29
+ const HUNDRED = 'cent'
30
+ const ZERO = 'zéro'
31
+ const NEGATIVE = 'moins'
32
+ const DECIMAL_SEP = 'virgule'
33
+
34
+ // ============================================================================
35
+ // Precomputed Lookup Tables
36
+ // ============================================================================
37
+
38
+ function buildSegment (n) {
39
+ if (n === 0) return { word: '', endsWithCents: false, endsWithVingts: false }
40
+
41
+ const tensOnes = n % 100
42
+ const hundreds = Math.floor(n / 100)
43
+
44
+ const parts = []
45
+ let endsWithCents = false
46
+ let endsWithVingts = false
47
+
48
+ // Hundreds
49
+ if (hundreds > 0) {
50
+ if (hundreds === 1) {
51
+ parts.push(HUNDRED)
52
+ } else {
53
+ if (tensOnes === 0) {
54
+ parts.push(ONES[hundreds] + ' ' + HUNDRED + 's')
55
+ endsWithCents = true
56
+ } else {
57
+ parts.push(ONES[hundreds] + ' ' + HUNDRED)
58
+ }
59
+ }
60
+ }
61
+
62
+ // Tens and ones - Belgian pattern
63
+ if (tensOnes === 0) {
64
+ // Just hundreds
65
+ } else if (tensOnes < 10) {
66
+ parts.push(ONES[tensOnes])
67
+ } else if (tensOnes < 17) {
68
+ parts.push(TEENS[tensOnes - 10])
69
+ } else if (tensOnes < 20) {
70
+ parts.push(TEENS[tensOnes - 10])
71
+ } else if (tensOnes < 70) {
72
+ // 20-69: standard pattern
73
+ const t = Math.floor(tensOnes / 10)
74
+ const o = tensOnes % 10
75
+ if (o === 0) {
76
+ parts.push(TENS[t])
77
+ } else if (o === 1) {
78
+ parts.push(TENS[t] + ' et ' + ONES[1])
79
+ } else {
80
+ parts.push(TENS[t] + '-' + ONES[o])
81
+ }
82
+ } else if (tensOnes < 80) {
83
+ // 70-79: septante pattern (Belgian)
84
+ const o = tensOnes % 10
85
+ if (o === 0) {
86
+ parts.push('septante')
87
+ } else if (o === 1) {
88
+ parts.push('septante et ' + ONES[1])
89
+ } else {
90
+ parts.push('septante-' + ONES[o])
91
+ }
92
+ } else if (tensOnes === 80) {
93
+ // 80: quatre-vingts (same as standard)
94
+ parts.push('quatre-vingts')
95
+ endsWithVingts = true
96
+ } else if (tensOnes < 90) {
97
+ // 81-89: quatre-vingt-X (same as standard)
98
+ const remainder = tensOnes - 80
99
+ parts.push('quatre-vingt-' + ONES[remainder])
100
+ } else {
101
+ // 90-99: nonante pattern (Belgian)
102
+ const o = tensOnes % 10
103
+ if (o === 0) {
104
+ parts.push('nonante')
105
+ } else if (o === 1) {
106
+ parts.push('nonante et ' + ONES[1])
107
+ } else {
108
+ parts.push('nonante-' + ONES[o])
109
+ }
110
+ }
111
+
112
+ return { word: parts.join(' '), endsWithCents, endsWithVingts }
113
+ }
114
+
115
+ // Precompute all 1000 segment words
116
+ const SEGMENTS = new Array(1000)
117
+ const SEGMENTS_ENDS_CENTS = new Array(1000)
118
+ const SEGMENTS_ENDS_VINGTS = new Array(1000)
119
+
120
+ for (let i = 0; i < 1000; i++) {
121
+ const result = buildSegment(i)
122
+ SEGMENTS[i] = result.word
123
+ SEGMENTS_ENDS_CENTS[i] = result.endsWithCents
124
+ SEGMENTS_ENDS_VINGTS[i] = result.endsWithVingts
125
+ }
126
+
127
+ // ============================================================================
128
+ // Helper Functions
129
+ // ============================================================================
130
+
131
+ function getScaleWord (scaleIndex, segment) {
132
+ if (scaleIndex === 1) return THOUSAND
133
+
134
+ if (scaleIndex % 2 === 0) {
135
+ const arrayIndex = (scaleIndex / 2) - 1
136
+ const baseWord = SCALES[arrayIndex]
137
+ if (!baseWord) return ''
138
+ return segment > 1n ? baseWord + 's' : baseWord
139
+ } else {
140
+ const arrayIndex = ((scaleIndex - 1) / 2) - 1
141
+ const ardWord = SCALES_ARD[arrayIndex]
142
+ if (!ardWord) return THOUSAND
143
+ return segment > 1n ? ardWord + 's' : ardWord
144
+ }
145
+ }
146
+
147
+ // ============================================================================
148
+ // Conversion Functions
149
+ // ============================================================================
150
+
151
+ function integerToWords (n, withHyphen = false) {
152
+ if (n === 0n) return ZERO
153
+
154
+ if (n < 1000n) {
155
+ const word = SEGMENTS[Number(n)]
156
+ return withHyphen ? word.replace(/ /g, '-') : word
157
+ }
158
+
159
+ if (n < 1_000_000n) {
160
+ const thousands = Number(n / 1000n)
161
+ const remainder = Number(n % 1000n)
162
+
163
+ let result
164
+ if (thousands === 1) {
165
+ result = THOUSAND
166
+ } else {
167
+ let thousandsWord = SEGMENTS[thousands]
168
+ if (SEGMENTS_ENDS_CENTS[thousands] || SEGMENTS_ENDS_VINGTS[thousands]) {
169
+ thousandsWord = thousandsWord.slice(0, -1)
170
+ }
171
+ result = thousandsWord + (withHyphen ? '-' : ' ') + THOUSAND
172
+ }
173
+
174
+ if (remainder > 0) {
175
+ result += (withHyphen ? '-' : ' ') + SEGMENTS[remainder]
176
+ }
177
+
178
+ if (withHyphen) {
179
+ result = result.replace(/ /g, '-')
180
+ }
181
+
182
+ return result
183
+ }
184
+
185
+ return buildLargeNumberWords(n, withHyphen)
186
+ }
187
+
188
+ function buildLargeNumberWords (n, withHyphen) {
189
+ const numStr = n.toString()
190
+ const len = numStr.length
191
+
192
+ const segments = []
193
+ const segmentSize = 3
194
+
195
+ const remainderLen = len % segmentSize
196
+ let pos = 0
197
+ if (remainderLen > 0) {
198
+ segments.push(Number(numStr.slice(0, remainderLen)))
199
+ pos = remainderLen
200
+ }
201
+ while (pos < len) {
202
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
203
+ pos += segmentSize
204
+ }
205
+
206
+ const parts = []
207
+ let scaleIndex = segments.length - 1
208
+
209
+ for (let i = 0; i < segments.length; i++) {
210
+ const segment = segments[i]
211
+
212
+ if (segment !== 0) {
213
+ const scaleWord = scaleIndex > 0 ? getScaleWord(scaleIndex, BigInt(segment)) : ''
214
+
215
+ if (scaleIndex === 0) {
216
+ parts.push(SEGMENTS[segment])
217
+ } else if (scaleIndex === 1) {
218
+ if (segment === 1) {
219
+ parts.push(THOUSAND)
220
+ } else {
221
+ let segWords = SEGMENTS[segment]
222
+ if (SEGMENTS_ENDS_CENTS[segment] || SEGMENTS_ENDS_VINGTS[segment]) {
223
+ segWords = segWords.slice(0, -1)
224
+ }
225
+ parts.push(segWords)
226
+ parts.push(scaleWord)
42
227
  }
228
+ } else {
229
+ parts.push(SEGMENTS[segment])
230
+ parts.push(scaleWord)
43
231
  }
44
- return pair
45
- })
232
+ }
233
+
234
+ scaleIndex--
235
+ }
236
+
237
+ const sep = withHyphen ? '-' : ' '
238
+ let result = parts.join(sep)
239
+
240
+ if (withHyphen) {
241
+ result = result.replace(/ /g, '-')
46
242
  }
243
+
244
+ return result
245
+ }
246
+
247
+ function decimalPartToWords (decimalPart, withHyphen) {
248
+ let result = ''
249
+ const sep = withHyphen ? '-' : ' '
250
+
251
+ let i = 0
252
+ while (i < decimalPart.length && decimalPart[i] === '0') {
253
+ if (result) result += sep
254
+ result += ZERO
255
+ i++
256
+ }
257
+
258
+ const remainder = decimalPart.slice(i)
259
+ if (remainder) {
260
+ if (result) result += sep
261
+ result += integerToWords(BigInt(remainder), withHyphen)
262
+ }
263
+
264
+ return result
47
265
  }
48
266
 
49
267
  /**
50
- * Converts a number to Belgian French cardinal (written) form.
268
+ * Converts a numeric value to Belgian French words.
51
269
  *
52
- * @param {number|string|bigint} value The number to convert.
53
- * @param {Object} [options={}] Configuration options.
54
- * @param {boolean} [options.withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds.
55
- * @returns {string} The number expressed in Belgian French words.
56
- * @throws {TypeError} If value is NaN or invalid type.
57
- * @throws {Error} If value is an invalid number string.
270
+ * @param {number | string | bigint} value - The numeric value to convert
271
+ * @param {Object} [options] - Optional configuration
272
+ * @param {boolean} [options.withHyphenSeparator=false] - Use hyphens between words
273
+ * @returns {string} The number in Belgian French words
58
274
  */
59
- export default function convertToWords (value, options = {}) {
60
- return new BelgianFrench(options).convertToWords(value)
275
+ function toWords (value, options) {
276
+ options = validateOptions(options)
277
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
278
+ const withHyphen = options.withHyphenSeparator || false
279
+
280
+ let result = ''
281
+ const sep = withHyphen ? '-' : ' '
282
+
283
+ if (isNegative) {
284
+ result = NEGATIVE + sep
285
+ }
286
+
287
+ result += integerToWords(integerPart, withHyphen)
288
+
289
+ if (decimalPart) {
290
+ result += sep + DECIMAL_SEP + sep + decimalPartToWords(decimalPart, withHyphen)
291
+ }
292
+
293
+ return result
61
294
  }
295
+
296
+ // ============================================================================
297
+ // Exports
298
+ // ============================================================================
299
+
300
+ export { toWords }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Converts a numeric value to French words.
3
+ *
4
+ * This is the main public API. It accepts any valid numeric input
5
+ * (number, string, or bigint) and handles parsing internally.
6
+ *
7
+ * @param {number | string | bigint} value - The numeric value to convert
8
+ * @param {Object} [options] - Optional configuration
9
+ * @param {boolean} [options.withHyphenSeparator=false] - Use hyphens between all words
10
+ * @returns {string} The number in French words
11
+ * @throws {TypeError} If value is not a valid numeric type
12
+ * @throws {Error} If value is not a valid number format
13
+ *
14
+ * @example
15
+ * toWords(21) // 'vingt et un'
16
+ * toWords(80) // 'quatre-vingts'
17
+ * toWords(1000000) // 'un million'
18
+ */
19
+ export function toWords(value: number | string | bigint, options?: {
20
+ withHyphenSeparator?: boolean | undefined;
21
+ }): string;