n2words 4.0.0 → 5.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 (309) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +14 -12
  3. package/dist/am-ET.js +2 -2
  4. package/dist/am-ET.umd.js +2 -2
  5. package/dist/am-Latn-ET.js +2 -2
  6. package/dist/am-Latn-ET.umd.js +2 -2
  7. package/dist/ar-SA.js +2 -2
  8. package/dist/ar-SA.umd.js +2 -2
  9. package/dist/az-AZ.js +2 -2
  10. package/dist/az-AZ.umd.js +2 -2
  11. package/dist/bn-BD.js +2 -2
  12. package/dist/bn-BD.umd.js +2 -2
  13. package/dist/cs-CZ.js +2 -2
  14. package/dist/cs-CZ.umd.js +2 -2
  15. package/dist/da-DK.js +2 -2
  16. package/dist/da-DK.umd.js +2 -2
  17. package/dist/de-DE.js +2 -2
  18. package/dist/de-DE.umd.js +2 -2
  19. package/dist/el-GR.js +2 -2
  20. package/dist/el-GR.umd.js +2 -2
  21. package/dist/en-AU.js +2 -2
  22. package/dist/en-AU.umd.js +2 -2
  23. package/dist/en-BD.js +2 -2
  24. package/dist/en-BD.umd.js +2 -2
  25. package/dist/en-CA.js +2 -2
  26. package/dist/en-CA.umd.js +2 -2
  27. package/dist/en-GB.js +2 -2
  28. package/dist/en-GB.umd.js +2 -2
  29. package/dist/en-GH.js +2 -2
  30. package/dist/en-GH.umd.js +2 -2
  31. package/dist/en-IE.js +2 -2
  32. package/dist/en-IE.umd.js +2 -2
  33. package/dist/en-IN.js +2 -2
  34. package/dist/en-IN.umd.js +2 -2
  35. package/dist/en-KE.js +2 -2
  36. package/dist/en-KE.umd.js +2 -2
  37. package/dist/en-MY.js +2 -2
  38. package/dist/en-MY.umd.js +2 -2
  39. package/dist/en-NG.js +2 -2
  40. package/dist/en-NG.umd.js +2 -2
  41. package/dist/en-NZ.js +2 -2
  42. package/dist/en-NZ.umd.js +2 -2
  43. package/dist/en-PH.js +2 -2
  44. package/dist/en-PH.umd.js +2 -2
  45. package/dist/en-PK.js +2 -2
  46. package/dist/en-PK.umd.js +2 -2
  47. package/dist/en-SG.js +2 -2
  48. package/dist/en-SG.umd.js +2 -2
  49. package/dist/en-US.js +2 -2
  50. package/dist/en-US.umd.js +2 -2
  51. package/dist/en-ZA.js +2 -2
  52. package/dist/en-ZA.umd.js +2 -2
  53. package/dist/es-ES.js +2 -2
  54. package/dist/es-ES.umd.js +2 -2
  55. package/dist/es-MX.js +2 -2
  56. package/dist/es-MX.umd.js +2 -2
  57. package/dist/es-US.js +2 -2
  58. package/dist/es-US.umd.js +2 -2
  59. package/dist/fa-IR.js +2 -2
  60. package/dist/fa-IR.umd.js +2 -2
  61. package/dist/fi-FI.js +2 -2
  62. package/dist/fi-FI.umd.js +2 -2
  63. package/dist/fil-PH.js +2 -2
  64. package/dist/fil-PH.umd.js +2 -2
  65. package/dist/fr-BE.js +2 -2
  66. package/dist/fr-BE.umd.js +2 -2
  67. package/dist/fr-FR.js +2 -2
  68. package/dist/fr-FR.umd.js +2 -2
  69. package/dist/gu-IN.js +2 -2
  70. package/dist/gu-IN.umd.js +2 -2
  71. package/dist/ha-NG.js +2 -2
  72. package/dist/ha-NG.umd.js +2 -2
  73. package/dist/hbo-IL.js +2 -2
  74. package/dist/hbo-IL.umd.js +2 -2
  75. package/dist/he-IL.js +2 -2
  76. package/dist/he-IL.umd.js +2 -2
  77. package/dist/hi-IN.js +2 -2
  78. package/dist/hi-IN.umd.js +2 -2
  79. package/dist/hr-HR.js +2 -2
  80. package/dist/hr-HR.umd.js +2 -2
  81. package/dist/hu-HU.js +2 -2
  82. package/dist/hu-HU.umd.js +2 -2
  83. package/dist/id-ID.js +2 -2
  84. package/dist/id-ID.umd.js +2 -2
  85. package/dist/it-IT.js +2 -2
  86. package/dist/it-IT.umd.js +2 -2
  87. package/dist/ja-JP.js +2 -2
  88. package/dist/ja-JP.umd.js +2 -2
  89. package/dist/ka-GE.js +2 -2
  90. package/dist/ka-GE.umd.js +2 -2
  91. package/dist/kn-IN.js +2 -2
  92. package/dist/kn-IN.umd.js +2 -2
  93. package/dist/ko-KR.js +2 -2
  94. package/dist/ko-KR.umd.js +2 -2
  95. package/dist/lt-LT.js +2 -2
  96. package/dist/lt-LT.umd.js +2 -2
  97. package/dist/lv-LV.js +2 -2
  98. package/dist/lv-LV.umd.js +2 -2
  99. package/dist/mr-IN.js +2 -2
  100. package/dist/mr-IN.umd.js +2 -2
  101. package/dist/ms-MY.js +2 -2
  102. package/dist/ms-MY.umd.js +2 -2
  103. package/dist/nb-NO.js +2 -2
  104. package/dist/nb-NO.umd.js +2 -2
  105. package/dist/nl-NL.js +2 -2
  106. package/dist/nl-NL.umd.js +2 -2
  107. package/dist/pa-IN.js +2 -2
  108. package/dist/pa-IN.umd.js +2 -2
  109. package/dist/pl-PL.js +2 -2
  110. package/dist/pl-PL.umd.js +2 -2
  111. package/dist/pt-BR.js +2 -0
  112. package/dist/pt-BR.umd.js +2 -0
  113. package/dist/pt-PT.js +2 -2
  114. package/dist/pt-PT.umd.js +2 -2
  115. package/dist/ro-RO.js +2 -2
  116. package/dist/ro-RO.umd.js +2 -2
  117. package/dist/ru-RU.js +2 -2
  118. package/dist/ru-RU.umd.js +2 -2
  119. package/dist/sr-Cyrl-RS.js +2 -2
  120. package/dist/sr-Cyrl-RS.umd.js +2 -2
  121. package/dist/sr-Latn-RS.js +2 -2
  122. package/dist/sr-Latn-RS.umd.js +2 -2
  123. package/dist/sv-SE.js +2 -2
  124. package/dist/sv-SE.umd.js +2 -2
  125. package/dist/sw-KE.js +2 -2
  126. package/dist/sw-KE.umd.js +2 -2
  127. package/dist/ta-IN.js +2 -2
  128. package/dist/ta-IN.umd.js +2 -2
  129. package/dist/te-IN.js +2 -2
  130. package/dist/te-IN.umd.js +2 -2
  131. package/dist/th-TH.js +2 -2
  132. package/dist/th-TH.umd.js +2 -2
  133. package/dist/tr-TR.js +2 -2
  134. package/dist/tr-TR.umd.js +2 -2
  135. package/dist/uk-UA.js +2 -2
  136. package/dist/uk-UA.umd.js +2 -2
  137. package/dist/ur-PK.js +2 -2
  138. package/dist/ur-PK.umd.js +2 -2
  139. package/dist/vi-VN.js +2 -2
  140. package/dist/vi-VN.umd.js +2 -2
  141. package/dist/yo-NG.js +2 -2
  142. package/dist/yo-NG.umd.js +2 -2
  143. package/dist/zh-Hans-CN.js +2 -2
  144. package/dist/zh-Hans-CN.umd.js +2 -2
  145. package/dist/zh-Hant-TW.js +2 -2
  146. package/dist/zh-Hant-TW.umd.js +2 -2
  147. package/package.json +53 -36
  148. package/src/am-ET.d.ts +3 -5
  149. package/src/am-ET.js +41 -16
  150. package/src/am-Latn-ET.d.ts +3 -5
  151. package/src/am-Latn-ET.js +45 -16
  152. package/src/ar-SA.d.ts +44 -18
  153. package/src/ar-SA.js +93 -40
  154. package/src/az-AZ.d.ts +3 -5
  155. package/src/az-AZ.js +58 -20
  156. package/src/bn-BD.d.ts +3 -5
  157. package/src/bn-BD.js +32 -16
  158. package/src/cs-CZ.d.ts +3 -6
  159. package/src/cs-CZ.js +66 -42
  160. package/src/da-DK.d.ts +3 -6
  161. package/src/da-DK.js +53 -48
  162. package/src/de-DE.d.ts +17 -11
  163. package/src/de-DE.js +88 -57
  164. package/src/el-GR.d.ts +3 -6
  165. package/src/el-GR.js +45 -32
  166. package/src/en-AU.d.ts +17 -11
  167. package/src/en-AU.js +56 -41
  168. package/src/en-BD.d.ts +17 -11
  169. package/src/en-BD.js +60 -41
  170. package/src/en-CA.d.ts +36 -18
  171. package/src/en-CA.js +67 -46
  172. package/src/en-GB.d.ts +17 -11
  173. package/src/en-GB.js +56 -41
  174. package/src/en-GH.d.ts +32 -3
  175. package/src/en-GH.js +104 -26
  176. package/src/en-IE.d.ts +17 -11
  177. package/src/en-IE.js +56 -41
  178. package/src/en-IN.d.ts +17 -11
  179. package/src/en-IN.js +60 -41
  180. package/src/en-KE.d.ts +28 -3
  181. package/src/en-KE.js +93 -26
  182. package/src/en-MY.d.ts +26 -3
  183. package/src/en-MY.js +91 -26
  184. package/src/en-NG.d.ts +17 -11
  185. package/src/en-NG.js +56 -41
  186. package/src/en-NZ.d.ts +32 -3
  187. package/src/en-NZ.js +85 -31
  188. package/src/en-PH.d.ts +32 -3
  189. package/src/en-PH.js +97 -26
  190. package/src/en-PK.d.ts +17 -11
  191. package/src/en-PK.js +60 -41
  192. package/src/en-SG.d.ts +28 -3
  193. package/src/en-SG.js +93 -26
  194. package/src/en-US.d.ts +36 -18
  195. package/src/en-US.js +70 -47
  196. package/src/en-ZA.d.ts +17 -11
  197. package/src/en-ZA.js +56 -41
  198. package/src/es-ES.d.ts +53 -21
  199. package/src/es-ES.js +104 -56
  200. package/src/es-MX.d.ts +53 -21
  201. package/src/es-MX.js +104 -56
  202. package/src/es-US.d.ts +53 -21
  203. package/src/es-US.js +92 -51
  204. package/src/fa-IR.d.ts +3 -5
  205. package/src/fa-IR.js +28 -13
  206. package/src/fi-FI.d.ts +3 -6
  207. package/src/fi-FI.js +47 -29
  208. package/src/fil-PH.d.ts +3 -5
  209. package/src/fil-PH.js +61 -28
  210. package/src/fr-BE.d.ts +31 -15
  211. package/src/fr-BE.js +128 -57
  212. package/src/fr-FR.d.ts +31 -16
  213. package/src/fr-FR.js +97 -60
  214. package/src/gu-IN.d.ts +3 -5
  215. package/src/gu-IN.js +31 -16
  216. package/src/ha-NG.d.ts +3 -5
  217. package/src/ha-NG.js +55 -27
  218. package/src/hbo-IL.d.ts +26 -12
  219. package/src/hbo-IL.js +92 -51
  220. package/src/he-IL.d.ts +17 -10
  221. package/src/he-IL.js +92 -50
  222. package/src/hi-IN.d.ts +3 -5
  223. package/src/hi-IN.js +30 -17
  224. package/src/hr-HR.d.ts +21 -10
  225. package/src/hr-HR.js +89 -33
  226. package/src/hu-HU.d.ts +3 -5
  227. package/src/hu-HU.js +57 -23
  228. package/src/id-ID.d.ts +3 -5
  229. package/src/id-ID.js +56 -23
  230. package/src/it-IT.d.ts +17 -11
  231. package/src/it-IT.js +74 -43
  232. package/src/ja-JP.d.ts +3 -6
  233. package/src/ja-JP.js +39 -26
  234. package/src/ka-GE.d.ts +3 -6
  235. package/src/ka-GE.js +38 -26
  236. package/src/kn-IN.d.ts +3 -5
  237. package/src/kn-IN.js +31 -16
  238. package/src/ko-KR.d.ts +3 -6
  239. package/src/ko-KR.js +34 -26
  240. package/src/lt-LT.d.ts +21 -11
  241. package/src/lt-LT.js +64 -42
  242. package/src/lv-LV.d.ts +21 -11
  243. package/src/lv-LV.js +79 -51
  244. package/src/mr-IN.d.ts +3 -5
  245. package/src/mr-IN.js +31 -16
  246. package/src/ms-MY.d.ts +3 -5
  247. package/src/ms-MY.js +58 -24
  248. package/src/nb-NO.d.ts +3 -6
  249. package/src/nb-NO.js +54 -34
  250. package/src/nl-NL.d.ts +41 -20
  251. package/src/nl-NL.js +111 -69
  252. package/src/pa-IN.d.ts +3 -5
  253. package/src/pa-IN.js +32 -16
  254. package/src/pl-PL.d.ts +21 -11
  255. package/src/pl-PL.js +69 -45
  256. package/src/pt-BR.d.ts +42 -0
  257. package/src/pt-BR.js +574 -0
  258. package/src/pt-PT.d.ts +17 -11
  259. package/src/pt-PT.js +80 -48
  260. package/src/ro-RO.d.ts +21 -11
  261. package/src/ro-RO.js +77 -39
  262. package/src/ru-RU.d.ts +35 -15
  263. package/src/ru-RU.js +100 -38
  264. package/src/sr-Cyrl-RS.d.ts +35 -15
  265. package/src/sr-Cyrl-RS.js +100 -38
  266. package/src/sr-Latn-RS.d.ts +35 -15
  267. package/src/sr-Latn-RS.js +100 -38
  268. package/src/sv-SE.d.ts +3 -6
  269. package/src/sv-SE.js +53 -34
  270. package/src/sw-KE.d.ts +3 -5
  271. package/src/sw-KE.js +50 -20
  272. package/src/ta-IN.d.ts +3 -5
  273. package/src/ta-IN.js +29 -17
  274. package/src/te-IN.d.ts +3 -5
  275. package/src/te-IN.js +31 -16
  276. package/src/th-TH.d.ts +3 -5
  277. package/src/th-TH.js +42 -19
  278. package/src/tr-TR.d.ts +17 -11
  279. package/src/tr-TR.js +63 -37
  280. package/src/uk-UA.d.ts +21 -10
  281. package/src/uk-UA.js +89 -33
  282. package/src/ur-PK.d.ts +3 -5
  283. package/src/ur-PK.js +32 -16
  284. package/src/utils/check-max.d.ts +26 -0
  285. package/src/utils/check-max.js +33 -0
  286. package/src/utils/expand-scientific.d.ts +0 -4
  287. package/src/utils/expand-scientific.js +7 -9
  288. package/src/utils/is-plain-object.d.ts +3 -4
  289. package/src/utils/is-plain-object.js +3 -4
  290. package/src/utils/parse-cardinal.d.ts +1 -2
  291. package/src/utils/parse-cardinal.js +12 -9
  292. package/src/utils/parse-currency.d.ts +1 -2
  293. package/src/utils/parse-currency.js +9 -11
  294. package/src/utils/parse-ordinal.d.ts +0 -1
  295. package/src/utils/parse-ordinal.js +9 -10
  296. package/src/utils/resolve-options.d.ts +17 -0
  297. package/src/utils/resolve-options.js +56 -0
  298. package/src/utils/scale.d.ts +49 -0
  299. package/src/utils/scale.js +65 -0
  300. package/src/vi-VN.d.ts +3 -6
  301. package/src/vi-VN.js +41 -28
  302. package/src/yo-NG.d.ts +3 -5
  303. package/src/yo-NG.js +49 -33
  304. package/src/zh-Hans-CN.d.ts +45 -20
  305. package/src/zh-Hans-CN.js +84 -31
  306. package/src/zh-Hant-TW.d.ts +45 -20
  307. package/src/zh-Hant-TW.js +85 -34
  308. package/src/utils/validate-options.d.ts +0 -8
  309. package/src/utils/validate-options.js +0 -16
package/src/da-DK.js CHANGED
@@ -14,6 +14,8 @@
14
14
  import { parseCardinalValue } from './utils/parse-cardinal.js'
15
15
  import { parseCurrencyValue } from './utils/parse-currency.js'
16
16
  import { parseOrdinalValue } from './utils/parse-ordinal.js'
17
+ import { checkMax } from './utils/check-max.js'
18
+ import { western } from './utils/scale.js'
17
19
 
18
20
  // ============================================================================
19
21
  // Vocabulary (module-level constants)
@@ -38,12 +40,21 @@ const DECIMAL_SEP = 'komma'
38
40
  // Long scale: millioner, millarder, billioner, etc.
39
41
  const SCALES = ['millioner', 'millarder', 'billioner', 'billarder', 'trillioner', 'trillarder', 'quadrillioner', 'quadrillarder']
40
42
 
43
+ // Supported magnitude ceiling (checked at the public entry points). Segments
44
+ // are [units, thousands, then one per SCALES entry], so cardinals span at most
45
+ // SCALES.length + 2 groups of 3 digits — they must stay below 10^30. Ordinals
46
+ // and currency build on the cardinal, so they share the same ceiling.
47
+ export const cardinalMax = western(SCALES.length + 1)
48
+ export const ordinalMax = western(SCALES.length + 1)
49
+ export const currencyMax = western(SCALES.length + 1)
50
+
41
51
  // ============================================================================
42
52
  // Ordinal Vocabulary
43
53
  // ============================================================================
44
54
 
45
55
  // Danish ordinals: 1st-2nd special, others use -te/-nde suffix
46
56
  // "anden/andet" for 2nd (common/neuter), we use common form
57
+ /** @type {Record<number, string>} */
47
58
  const ORDINAL_SPECIAL = {
48
59
  1: 'første',
49
60
  2: 'anden',
@@ -56,7 +67,7 @@ const ORDINAL_SPECIAL = {
56
67
  9: 'niende',
57
68
  10: 'tiende',
58
69
  11: 'ellevte',
59
- 12: 'tolvte'
70
+ 12: 'tolvte',
60
71
  }
61
72
 
62
73
  // ============================================================================
@@ -73,8 +84,10 @@ const ORE = 'øre' // same singular and plural
73
84
 
74
85
  /**
75
86
  * Builds segment word for 0-999.
87
+ * @param {number} n - Integer in range 0-999
88
+ * @returns {string} Danish words for the segment
76
89
  */
77
- function buildSegment (n) {
90
+ function buildSegment(n) {
78
91
  if (n === 0) return ''
79
92
 
80
93
  const ones = n % 10
@@ -93,16 +106,20 @@ function buildSegment (n) {
93
106
 
94
107
  if (tensOnes === 0) {
95
108
  // Just hundreds
96
- } else if (tensOnes < 10) {
109
+ }
110
+ else if (tensOnes < 10) {
97
111
  // Single digit
98
112
  parts.push(ONES[ones])
99
- } else if (tensOnes < 20) {
113
+ }
114
+ else if (tensOnes < 20) {
100
115
  // Teens
101
116
  parts.push(TEENS[ones])
102
- } else if (ones === 0) {
117
+ }
118
+ else if (ones === 0) {
103
119
  // Even tens
104
120
  parts.push(TENS[tens])
105
- } else {
121
+ }
122
+ else {
106
123
  // Units-before-tens: "enogtyve", "treogfyrre"
107
124
  parts.push(ONES_VIGESIMAL[ones] + 'og' + TENS[tens])
108
125
  }
@@ -120,11 +137,10 @@ function buildSegment (n) {
120
137
 
121
138
  /**
122
139
  * Converts a non-negative integer to Danish words.
123
- *
124
140
  * @param {bigint} n - Non-negative integer to convert
125
141
  * @returns {string} Danish words
126
142
  */
127
- function integerToWords (n) {
143
+ function integerToWords(n) {
128
144
  if (n === 0n) return ZERO
129
145
 
130
146
  // Fast path: numbers < 1000 (direct lookup)
@@ -154,11 +170,10 @@ function integerToWords (n) {
154
170
 
155
171
  /**
156
172
  * Builds words for numbers >= 1,000,000.
157
- *
158
173
  * @param {bigint} n - Number >= 1,000,000
159
174
  * @returns {string} Danish words
160
175
  */
161
- function buildLargeNumberWords (n) {
176
+ function buildLargeNumberWords(n) {
162
177
  const numStr = n.toString()
163
178
  const len = numStr.length
164
179
 
@@ -178,6 +193,7 @@ function buildLargeNumberWords (n) {
178
193
  }
179
194
 
180
195
  // Convert segments to words with scale tracking
196
+ // Callers guard the magnitude (cardinalMax) before reaching here.
181
197
  // scaleIndex: 0 = units, 1 = thousands, 2 = millions, etc.
182
198
  const parts = []
183
199
  let scaleIndex = segments.length - 1
@@ -191,10 +207,12 @@ function buildLargeNumberWords (n) {
191
207
  if (scaleIndex === 0) {
192
208
  // Units segment
193
209
  parts.push({ word: segmentWord, type: 'units' })
194
- } else if (scaleIndex === 1) {
210
+ }
211
+ else if (scaleIndex === 1) {
195
212
  // Thousands - compound form
196
213
  parts.push({ word: segmentWord + THOUSAND, type: 'thousand' })
197
- } else {
214
+ }
215
+ else {
198
216
  // Millions+ - space-separated, use "en" for 1
199
217
  const scaleWord = SCALES[scaleIndex - 2]
200
218
  let numWord = segmentWord
@@ -217,50 +235,38 @@ function buildLargeNumberWords (n) {
217
235
  * Joins parts with Danish spacing rules.
218
236
  * - After thousands with remainder: "tusinde og"
219
237
  * - Millions are space-separated
220
- *
221
- * @param {Array} parts - Parts with type metadata
238
+ * @param {Array<{word: string, type: string}>} parts - Parts with type metadata
222
239
  * @returns {string} Joined string
223
240
  */
224
- function joinDanishParts (parts) {
241
+ function joinDanishParts(parts) {
225
242
  if (parts.length === 0) return ZERO
226
- if (parts.length === 1) return parts[0].word
227
243
 
228
- const result = []
244
+ const tokens = []
229
245
 
230
246
  for (let i = 0; i < parts.length; i++) {
231
247
  const part = parts[i]
232
248
  const nextPart = parts[i + 1]
233
249
 
234
250
  if (part.type === 'thousand' && nextPart && nextPart.type === 'units') {
235
- // Thousands followed by units: add "e og"
236
- result.push(part.word + 'e og ' + nextPart.word)
237
- i++ // Skip the units part
238
- } else if (part.type === 'million') {
239
- if (result.length > 0) {
240
- result.push(' ')
241
- }
242
- result.push(part.word)
243
- if (nextPart) {
244
- result.push(' ')
245
- }
246
- } else {
247
- if (result.length > 0 && !result[result.length - 1].endsWith(' ')) {
248
- result.push(' ')
249
- }
250
- result.push(part.word)
251
+ // Thousands directly followed by the units segment: compound "…tusinde og"
252
+ tokens.push(part.word + 'e og ' + nextPart.word)
253
+ i++ // consumed the units part
254
+ }
255
+ else {
256
+ tokens.push(part.word)
251
257
  }
252
258
  }
253
259
 
254
- return result.join('')
260
+ // Every remaining boundary (between scale groups) is a single space.
261
+ return tokens.join(' ')
255
262
  }
256
263
 
257
264
  /**
258
265
  * Converts decimal digits to Danish words.
259
- *
260
266
  * @param {string} decimalPart - Decimal digits (without the point)
261
267
  * @returns {string} Danish words for decimal part
262
268
  */
263
- function decimalPartToWords (decimalPart) {
269
+ function decimalPartToWords(decimalPart) {
264
270
  let result = ''
265
271
 
266
272
  // Handle leading zeros
@@ -283,19 +289,20 @@ function decimalPartToWords (decimalPart) {
283
289
 
284
290
  /**
285
291
  * Converts a numeric value to Danish words.
286
- *
287
292
  * @param {number | string | bigint} value - The numeric value to convert
288
293
  * @returns {string} The number in Danish words
289
294
  * @throws {TypeError} If value is not a valid numeric type
290
295
  * @throws {Error} If value is not a valid number format
291
- *
292
296
  * @example
293
297
  * toCardinal(21) // 'enogtyve'
294
298
  * toCardinal(1000) // 'ettusind'
295
299
  * toCardinal(1000000) // 'en millioner'
296
300
  */
297
- function toCardinal (value) {
301
+ function toCardinal(value) {
298
302
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
303
+ // Both the integer part and the decimal's significant digits are spelled via
304
+ // the scale builder, so both must clear the ceiling.
305
+ checkMax(integerPart, cardinalMax, decimalPart)
299
306
 
300
307
  let result = ''
301
308
 
@@ -321,11 +328,10 @@ function toCardinal (value) {
321
328
  *
322
329
  * Danish ordinals: første (1st), anden (2nd), tredje (3rd), etc.
323
330
  * 1-12 have special forms, others use cardinal + -de/-nde suffix.
324
- *
325
331
  * @param {bigint} n - Positive integer to convert
326
332
  * @returns {string} Danish ordinal words
327
333
  */
328
- function integerToOrdinal (n) {
334
+ function integerToOrdinal(n) {
329
335
  // Special forms for 1-12
330
336
  if (n >= 1n && n <= 12n) {
331
337
  return ORDINAL_SPECIAL[Number(n)]
@@ -338,19 +344,18 @@ function integerToOrdinal (n) {
338
344
 
339
345
  /**
340
346
  * Converts a numeric value to Danish ordinal words.
341
- *
342
347
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
343
348
  * @returns {string} The number as ordinal words
344
349
  * @throws {TypeError} If value is not a valid numeric type
345
350
  * @throws {RangeError} If value is negative, zero, or has a decimal part
346
- *
347
351
  * @example
348
352
  * toOrdinal(1) // 'første'
349
353
  * toOrdinal(2) // 'anden'
350
354
  * toOrdinal(21) // 'enogtyvede'
351
355
  */
352
- function toOrdinal (value) {
356
+ function toOrdinal(value) {
353
357
  const integerPart = parseOrdinalValue(value)
358
+ checkMax(integerPart, ordinalMax)
354
359
  return integerToOrdinal(integerPart)
355
360
  }
356
361
 
@@ -362,19 +367,18 @@ function toOrdinal (value) {
362
367
  * Converts a numeric value to Danish currency words (Danish Krone).
363
368
  *
364
369
  * Uses krone/kroner and øre (100 øre = 1 krone).
365
- *
366
370
  * @param {number | string | bigint} value - The currency amount to convert
367
371
  * @returns {string} The amount in Danish currency words
368
372
  * @throws {TypeError} If value is not a valid numeric type
369
373
  * @throws {Error} If value is not a valid number format
370
- *
371
374
  * @example
372
375
  * toCurrency(1) // 'en krone'
373
376
  * toCurrency(42) // 'toogfyrre kroner'
374
377
  * toCurrency(1.50) // 'en krone og halvtreds øre'
375
378
  */
376
- function toCurrency (value) {
379
+ function toCurrency(value) {
377
380
  const { isNegative, dollars: kroner, cents: ore } = parseCurrencyValue(value)
381
+ checkMax(kroner, currencyMax)
378
382
 
379
383
  let result = ''
380
384
  if (isNegative) {
@@ -385,7 +389,8 @@ function toCurrency (value) {
385
389
  if (kroner > 0n || ore === 0n) {
386
390
  if (kroner === 1n) {
387
391
  result += 'en ' + KRONE
388
- } else {
392
+ }
393
+ else {
389
394
  result += integerToWords(kroner) + ' ' + KRONER
390
395
  }
391
396
  }
package/src/de-DE.d.ts CHANGED
@@ -1,14 +1,27 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
4
+ /**
5
+ * @typedef {object} CurrencyOptions
6
+ * @property {boolean} [and] - Use "und" between euros and cents
7
+ */
8
+ /** @type {Required<CurrencyOptions>} */
9
+ export const currencyDefaults: Required<CurrencyOptions>;
10
+ export type CurrencyOptions = {
11
+ /**
12
+ * - Use "und" between euros and cents
13
+ */
14
+ and?: boolean | undefined;
15
+ };
1
16
  /**
2
17
  * Converts a numeric value to German words.
3
18
  *
4
19
  * This is the main public API. It accepts any valid numeric input
5
20
  * (number, string, or bigint) and handles parsing internally.
6
- *
7
21
  * @param {number | string | bigint} value - The numeric value to convert
8
22
  * @returns {string} The number in German words
9
23
  * @throws {TypeError} If value is not a valid numeric type
10
24
  * @throws {Error} If value is not a valid number format
11
- *
12
25
  * @example
13
26
  * toCardinal(21) // 'einundzwanzig'
14
27
  * toCardinal(1000) // 'eintausend'
@@ -20,12 +33,10 @@ export function toCardinal(value: number | string | bigint): string;
20
33
  *
21
34
  * German ordinals add -te for 1-19 and -ste for 20+.
22
35
  * Irregular forms: erste (1st), dritte (3rd), siebte (7th), achte (8th).
23
- *
24
36
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
25
37
  * @returns {string} The number as ordinal words
26
38
  * @throws {TypeError} If value is not a valid numeric type
27
39
  * @throws {RangeError} If value is negative, zero, or has a decimal part
28
- *
29
40
  * @example
30
41
  * toOrdinal(1) // 'erste'
31
42
  * toOrdinal(2) // 'zweite'
@@ -37,14 +48,11 @@ export function toCardinal(value: number | string | bigint): string;
37
48
  export function toOrdinal(value: number | string | bigint): string;
38
49
  /**
39
50
  * Converts a numeric value to German currency words (Euro).
40
- *
41
51
  * @param {number | string | bigint} value - The currency amount to convert
42
- * @param {Object} [options] - Optional configuration
43
- * @param {boolean} [options.and=true] - Use "und" between euros and cents
52
+ * @param {CurrencyOptions} [options] - Optional configuration
44
53
  * @returns {string} The amount in German currency words
45
54
  * @throws {TypeError} If value is not a valid numeric type
46
55
  * @throws {Error} If value is not a valid number format
47
- *
48
56
  * @example
49
57
  * toCurrency(42.50) // 'zweiundvierzig Euro und fünfzig Cent'
50
58
  * toCurrency(1) // 'ein Euro'
@@ -52,6 +60,4 @@ export function toOrdinal(value: number | string | bigint): string;
52
60
  * toCurrency(0.01) // 'ein Cent'
53
61
  * toCurrency(42.50, { and: false }) // 'zweiundvierzig Euro fünfzig Cent'
54
62
  */
55
- export function toCurrency(value: number | string | bigint, options?: {
56
- and?: boolean | undefined;
57
- }): string;
63
+ export function toCurrency(value: number | string | bigint, options?: CurrencyOptions): string;