n2words 5.0.0 → 5.1.1

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 +133 -40
  2. package/README.md +6 -4
  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 -2
  112. package/dist/pt-BR.umd.js +2 -2
  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 +33 -24
  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 +22 -11
  257. package/src/pt-BR.js +93 -53
  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 +106 -43
  266. package/src/sr-Latn-RS.d.ts +35 -15
  267. package/src/sr-Latn-RS.js +106 -43
  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
@@ -1,2 +1,2 @@
1
- /*! n2words/zh-Hans-CN v5.0.0 | MIT License | github.com/forzagreen/n2words */
2
- var n,e;n=this,e=function(n){"use strict";function e(n){let[e,r]=n.toLowerCase().split("e");const t=parseInt(r,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const o=e.indexOf("."),s=-1===o?e:e.slice(0,o)+e.slice(o+1),u=(-1===o?e.length:o)+t;return u>=s.length?i+s+"0".repeat(u-s.length):u<=0?i+"0."+"0".repeat(-u)+s:i+s.slice(0,u)+"."+s.slice(u)}function r(n){const r=n.toString();return t(r)?e(r):r}function t(n){return n.includes("e")||n.includes("E")}function i(n){const e="-"===n[0];e&&(n=n.slice(1));const r=n.indexOf(".");if(-1===r)return{isNegative:e,integerPart:BigInt(n)};const t=n.slice(0,r)||"0",i=n.slice(r+1);return{isNegative:e,integerPart:BigInt(t),decimalPart:i}}function o(n){let r=n.trim();if(0===r.length||Number.isNaN(Number(r)))throw new RangeError(`Invalid currency format: "${n}"`);t(r)&&(r=e(r));const i="-"===r[0];i&&(r=r.slice(1));const o=r.indexOf(".");if(-1===o)return{isNegative:i,dollars:BigInt(r),cents:0n};const s=r.slice(0,o)||"0",u=(r.slice(o+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(s),cents:BigInt(u)}}function s(n){if(void 0===n)return{};if(function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))return n;throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n)}const u=["零","一","二","三","四","五","六","七","八","九"],a=["零","壹","贰","叁","肆","伍","陆","柒","捌","玖"],c="零";function f(n,e,r,t,i){if(0n===n)return"";let o="",s=!1;const u=n/1000n,a=n%1000n;u>0n&&(o=e[Number(u)]+i,s=a>0n&&a<100n);const f=a/100n,l=a%100n;f>0n?(s&&(o+=c),o+=e[Number(f)]+t,s=l>0n&&l<10n):u>0n&&l>0n&&(s=!0);const g=l/10n,d=l%10n;return g>0n?(s&&(o+=c),o+=e[Number(g)]+r,s=!1):(f>0n||u>0n)&&d>0n&&(s=!0),d>0n&&(s&&(o+=c),o+=e[Number(d)]),o}function l(n,e,r,t,i){if(0n===n)return"";if(n>=10000n){const o=n/10000n,s=n%10000n;let u=f(o,e,r,t,i)+"万";return s>0n&&((o%10n==0n||s<1000n)&&(u+=c),u+=f(s,e,r,t,i)),u}return f(n,e,r,t,i)}function g(n,e=!0){if(0n===n)return c;const r=e?a:u,t=e?"拾":"十",i=e?"佰":"百",o=e?"仟":"千";if(n>=100000000n){const e=n%100000000n;let s=l(n/100000000n,r,t,i,o)+"亿";return e>0n&&(e<10000000n&&(s+=c),s+=l(e,r,t,i,o)),s}return l(n,r,t,i,o)}const d={zhHansCN:function(n,r){r=s(r);const i=function(n){const r=typeof n;if("bigint"===r){if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}if("number"===r){if(!Number.isFinite(n))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(n))throw new RangeError("Ordinals must be whole numbers");if(n<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(n)}if("string"===r)return function(n){const r=n.trim();if(0===r.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===r[0])throw new RangeError("Ordinals cannot be negative");if(r.includes("."))throw new RangeError("Ordinals must be whole numbers");if(t(r)){const n=e(r);if(n.includes("."))throw new RangeError("Ordinals must be whole numbers");const t=BigInt(n);if(t<=0n)throw new RangeError("Ordinals must be positive integers");return t}try{const n=BigInt(r);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(e){if(e instanceof RangeError)throw e;throw new RangeError(`Invalid ordinal format: "${n}"`)}}(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${r}`)}(n),{formal:o=!0}=r;return function(n,e){return"第"+g(n,e)}(i,o)}};n.currency={zhHansCN:function(n,e){e=s(e);const{isNegative:t,dollars:i,cents:f}=function(n){const e=typeof n;if("bigint"===e)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"===e){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:o(r(n))}if("string"===e)return o(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${e}`)}(n),{formal:l=!0}=e,d=l?a:u,b=l?"圆":"元",m=f/10n,w=f%10n;let N="";return t&&(N="负"),i>0n&&(N+=g(i,l)+b),m>0n?N+=d[Number(m)]+"角":i>0n&&w>0n&&(N+=c),w>0n?N+=d[Number(w)]+"分":(i>0n||m>0n)&&(N+="整"),0n===i&&0n===m&&0n===w&&(N+=c+b+"整"),N}},n.ordinal=d,n.zhHansCN=function(n,o){o=s(o);const{isNegative:c,integerPart:f,decimalPart:l}=function(n){const o=typeof n;if("bigint"===o)return n<0n?{isNegative:!0,integerPart:-n}:{isNegative:!1,integerPart:n};if("number"===o){if(!Number.isFinite(n))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(n)?n<0?{isNegative:!0,integerPart:BigInt(-n)}:{isNegative:!1,integerPart:BigInt(n)}:i(r(n))}if("string"===o)return i(function(n){const r=n.trim();if(0===r.length||Number.isNaN(Number(r)))throw new RangeError(`Invalid number format: "${n}"`);return t(r)?e(r):r}(n));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${o}`)}(n),{formal:d=!0}=o;let b=c?"负":"";return b+=g(f,d),l&&(b+="点"+function(n,e){let r="";for(let t=0;t<n.length;t++)r+=e[Number(n[t])];return r}(l,d?a:u)),b}},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).n2words=n.n2words||{});
1
+ /*! n2words/zh-Hans-CN v5.1.1 | MIT License | github.com/forzagreen/n2words */
2
+ var n,e;n=this,e=function(n){"use strict";function e(n){let[e,t]=n.toLowerCase().split("e");const r=parseInt(t,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const o=e.indexOf("."),s=-1===o?e:e.slice(0,o)+e.slice(o+1),u=(-1===o?e.length:o)+r;return u>=s.length?i+s+"0".repeat(u-s.length):u<=0?i+"0."+"0".repeat(-u)+s:i+s.slice(0,u)+"."+s.slice(u)}function t(n){const t=n.toString();return r(t)?e(t):t}function r(n){return n.includes("e")||n.includes("E")}function i(n){const e="-"===n[0];e&&(n=n.slice(1));const t=n.indexOf(".");if(-1===t)return{isNegative:e,integerPart:BigInt(n)};const r=n.slice(0,t)||"0",i=n.slice(t+1);return{isNegative:e,integerPart:BigInt(r),decimalPart:i}}function o(n){let t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid currency format: "${n}"`);r(t)&&(t=e(t));const i="-"===t[0];i&&(t=t.slice(1));const o=t.indexOf(".");if(-1===o)return{isNegative:i,dollars:BigInt(t),cents:0n};const s=t.slice(0,o)||"0",u=(t.slice(o+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(s),cents:BigInt(u)}}function s(n,e,t){if(null===e)return;if(n<e)return;const r=e.toString().length-1,i=e===10n**BigInt(r)?`10^${r} - 1`:""+(e-1n);throw new RangeError(`Number too large to convert: the largest supported value is ${i}`)}function u(n){return 10n**BigInt(n)}function f(n,e,t){const r={...e};if(void 0===n)return r;if(!function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n);const i=Object.keys(e);for(const[t,o]of Object.entries(n)){if(!Object.hasOwn(e,t))throw new TypeError(`Unknown option "${t}" — expected one of: ${i.join(", ")}`);if(void 0!==o){if(typeof o!=typeof r[t])throw new TypeError(`Option "${t}" must be a ${typeof r[t]}, got ${typeof o}`);r[t]=o}}return r}const c=["零","一","二","三","四","五","六","七","八","九"],a=["零","壹","贰","叁","肆","伍","陆","柒","捌","玖"],l=u(16),g=u(16),d=u(16),b="零";function m(n,e,t,r,i){if(0n===n)return"";let o="",s=!1;const u=n/1000n,f=n%1000n;u>0n&&(o=e[Number(u)]+i,s=f>0n&&f<100n);const c=f/100n,a=f%100n;c>0n?(s&&(o+=b),o+=e[Number(c)]+r,s=a>0n&&a<10n):u>0n&&a>0n&&(s=!0);const l=a/10n,g=a%10n;return l>0n?(s&&(o+=b),o+=e[Number(l)]+t,s=!1):(c>0n||u>0n)&&g>0n&&(s=!0),g>0n&&(s&&(o+=b),o+=e[Number(g)]),o}function p(n,e,t,r,i){if(0n===n)return"";if(n>=10000n){const o=n/10000n,s=n%10000n;let u=m(o,e,t,r,i)+"万";return s>0n&&((o%10n==0n||s<1000n)&&(u+=b),u+=m(s,e,t,r,i)),u}return m(n,e,t,r,i)}function w(n,e=!0){if(0n===n)return b;const t=e?a:c,r=e?"拾":"十",i=e?"佰":"百",o=e?"仟":"千";if(n>=100000000n){const e=n%100000000n;let s=p(n/100000000n,t,r,i,o)+"亿";return e>0n&&(e<10000000n&&(s+=b),s+=p(e,t,r,i,o)),s}return p(n,t,r,i,o)}const h={formal:!0},N={formal:!0},y={formal:!0},v={zhHansCN:function(n,t){const i=function(n){const t=typeof n;if("bigint"==typeof n){if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(n))throw new RangeError("Ordinals must be whole numbers");if(n<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(n)}if("string"==typeof n)return function(n){const t=n.trim();if(0===t.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===t[0])throw new RangeError("Ordinals cannot be negative");if(t.includes("."))throw new RangeError("Ordinals must be whole numbers");if(r(t)){const n=e(t);if(n.includes("."))throw new RangeError("Ordinals must be whole numbers");const r=BigInt(n);if(r<=0n)throw new RangeError("Ordinals must be positive integers");return r}try{const n=BigInt(t);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(e){if(e instanceof RangeError)throw e;throw new RangeError(`Invalid ordinal format: "${n}"`,{cause:e})}}(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`)}(n);s(i,g);const{formal:o}=f(t,N);return function(n,e){return"第"+w(n,e)}(i,o)}};n.currency={zhHansCN:function(n,e){const{isNegative:r,dollars:i,cents:u}=function(n){const e=typeof n;if("bigint"==typeof n)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:o(t(n))}if("string"==typeof n)return o(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${e}`)}(n);s(i,d);const{formal:l}=f(e,y),g=l?a:c,m=l?"圆":"元",p=u/10n,h=u%10n;let N="";return r&&(N="负"),i>0n&&(N+=w(i,l)+m),p>0n?N+=g[Number(p)]+"角":i>0n&&h>0n&&(N+=b),h>0n?N+=g[Number(h)]+"分":(i>0n||p>0n)&&(N+="整"),0n===i&&0n===p&&0n===h&&(N+=b+m+"整"),N}},n.ordinal=v,n.zhHansCN=function(n,o){const{isNegative:u,integerPart:g,decimalPart:d}=function(n){const o=typeof n;if("bigint"==typeof n)return n<0n?{isNegative:!0,integerPart:-n}:{isNegative:!1,integerPart:n};if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(n)?n<0?{isNegative:!0,integerPart:BigInt(-n)}:{isNegative:!1,integerPart:BigInt(n)}:i(t(n))}if("string"==typeof n)return i(function(n){const t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid number format: "${n}"`);return r(t)?e(t):t}(n));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${o}`)}(n);s(g,l);const{formal:b}=f(o,h);let m=u?"负":"";return m+=w(g,b),d&&(m+="点"+function(n,e){let t="";for(let r=0;r<n.length;r++)t+=e[Number(n[r])];return t}(d,b?a:c)),m}},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).n2words=n.n2words||{});
@@ -1,2 +1,2 @@
1
- /*! n2words/zh-Hant-TW v5.0.0 | MIT License | github.com/forzagreen/n2words */
2
- function n(n){let[e,r]=n.toLowerCase().split("e");const t=parseInt(r,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const s=e.indexOf("."),o=-1===s?e:e.slice(0,s)+e.slice(s+1),u=(-1===s?e.length:s)+t;return u>=o.length?i+o+"0".repeat(u-o.length):u<=0?i+"0."+"0".repeat(-u)+o:i+o.slice(0,u)+"."+o.slice(u)}function e(e){const t=e.toString();return r(t)?n(t):t}function r(n){return n.includes("e")||n.includes("E")}function t(n){const e="-"===n[0];e&&(n=n.slice(1));const r=n.indexOf(".");if(-1===r)return{isNegative:e,integerPart:BigInt(n)};const t=n.slice(0,r)||"0",i=n.slice(r+1);return{isNegative:e,integerPart:BigInt(t),decimalPart:i}}function i(e){let t=e.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid currency format: "${e}"`);r(t)&&(t=n(t));const i="-"===t[0];i&&(t=t.slice(1));const s=t.indexOf(".");if(-1===s)return{isNegative:i,dollars:BigInt(t),cents:0n};const o=t.slice(0,s)||"0",u=(t.slice(s+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(o),cents:BigInt(u)}}function s(n){if(void 0===n)return{};if(function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))return n;throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n)}const o=["零","一","二","三","四","五","六","七","八","九"],u=["零","壹","貳","參","肆","伍","陸","柒","捌","玖"],c="零";function a(n,e=!0){if(0n===n)return c;const r=e?u:o,t=e?"拾":"十",i=e?"佰":"百",s=e?"仟":"千";function a(n){if(0n===n)return"";const e=[];let o=!1;const u=n/1000n,a=n%1000n;u>0n&&(e.push(r[Number(u)]+s),o=a>0n&&a<100n);const f=a/100n,g=a%100n;f>0n?(o&&(e.push(c),o=!1),e.push(r[Number(f)]+i),o=g>0n&&g<10n):u>0n&&g>0n&&(o=!0);const l=g/10n,b=g%10n;return l>0n?(o&&(e.push(c),o=!1),e.push(r[Number(l)]+t)):(f>0n||u>0n)&&b>0n&&(o=!0),b>0n&&(o&&e.push(c),e.push(r[Number(b)])),e.join("")}function f(n){if(0n===n)return"";const e=[];if(n>=10000n){const r=n/10000n,t=n%10000n;e.push(a(r)+"萬"),t>0n&&((r%10n==0n||t<1000n)&&e.push(c),e.push(a(t)))}else e.push(a(n));return e.join("")}const g=[];if(n>=100000000n){const e=n%100000000n,r=f(n/100000000n);g.push(r+"億"),e>0n&&(e<10000000n&&g.push(c),g.push(f(e)))}else g.push(f(n));return g.join("")}function f(i,c){c=s(c);const{isNegative:f,integerPart:g,decimalPart:l}=function(i){const s=typeof i;if("bigint"===s)return i<0n?{isNegative:!0,integerPart:-i}:{isNegative:!1,integerPart:i};if("number"===s){if(!Number.isFinite(i))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(i)?i<0?{isNegative:!0,integerPart:BigInt(-i)}:{isNegative:!1,integerPart:BigInt(i)}:t(e(i))}if("string"===s)return t(function(e){const t=e.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid number format: "${e}"`);return r(t)?n(t):t}(i));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${s}`)}(i),{formal:b=!0}=c;let m="";return f&&(m="負"),m+=a(g,b),l&&(m+="點"+function(n,e=!0){const r=e?u:o,t=[];for(const e of n)t.push(r[Number(e)]);return t}(l,b).join("")),m}function g(e,t){t=s(t);const i=function(e){const t=typeof e;if("bigint"===t){if(e<=0n)throw new RangeError("Ordinals must be positive integers");return e}if("number"===t){if(!Number.isFinite(e))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(e))throw new RangeError("Ordinals must be whole numbers");if(e<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(e)}if("string"===t)return function(e){const t=e.trim();if(0===t.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===t[0])throw new RangeError("Ordinals cannot be negative");if(t.includes("."))throw new RangeError("Ordinals must be whole numbers");if(r(t)){const e=n(t);if(e.includes("."))throw new RangeError("Ordinals must be whole numbers");const r=BigInt(e);if(r<=0n)throw new RangeError("Ordinals must be positive integers");return r}try{const n=BigInt(t);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(n){if(n instanceof RangeError)throw n;throw new RangeError(`Invalid ordinal format: "${e}"`)}}(e);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`)}(e),{formal:o=!0}=t;return function(n,e=!0){return"第"+a(n,e)}(i,o)}function l(n,r){r=s(r);const{isNegative:t,dollars:f,cents:g}=function(n){const r=typeof n;if("bigint"===r)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"===r){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:i(e(n))}if("string"===r)return i(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${r}`)}(n),{formal:l=!0}=r,b=l?"圓":"元",m=g/10n,p=g%10n;let d="";return t&&(d="負"),(f>0n||0n===g)&&(d+=a(f,l),d+=b),m>0n&&(d+=(l?u:o)[Number(m)]+"角"),p>0n?(f>0n&&0n===m&&(d+=c),d+=(l?u:o)[Number(p)]+"分"):d+="整",d}export{f as toCardinal,l as toCurrency,g as toOrdinal};
1
+ /*! n2words/zh-Hant-TW v5.1.1 | MIT License | github.com/forzagreen/n2words */
2
+ function n(n){let[e,t]=n.toLowerCase().split("e");const r=parseInt(t,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const o=e.indexOf("."),s=-1===o?e:e.slice(0,o)+e.slice(o+1),u=(-1===o?e.length:o)+r;return u>=s.length?i+s+"0".repeat(u-s.length):u<=0?i+"0."+"0".repeat(-u)+s:i+s.slice(0,u)+"."+s.slice(u)}function e(e){const r=e.toString();return t(r)?n(r):r}function t(n){return n.includes("e")||n.includes("E")}function r(n){const e="-"===n[0];e&&(n=n.slice(1));const t=n.indexOf(".");if(-1===t)return{isNegative:e,integerPart:BigInt(n)};const r=n.slice(0,t)||"0",i=n.slice(t+1);return{isNegative:e,integerPart:BigInt(r),decimalPart:i}}function i(e){let r=e.trim();if(0===r.length||Number.isNaN(Number(r)))throw new RangeError(`Invalid currency format: "${e}"`);t(r)&&(r=n(r));const i="-"===r[0];i&&(r=r.slice(1));const o=r.indexOf(".");if(-1===o)return{isNegative:i,dollars:BigInt(r),cents:0n};const s=r.slice(0,o)||"0",u=(r.slice(o+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(s),cents:BigInt(u)}}function o(n,e,t){if(null===e)return;if(n<e)return;const r=e.toString().length-1,i=e===10n**BigInt(r)?`10^${r} - 1`:""+(e-1n);throw new RangeError(`Number too large to convert: the largest supported value is ${i}`)}function s(n){return 10n**BigInt(n)}function u(n,e,t){const r={...e};if(void 0===n)return r;if(!function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n);const i=Object.keys(e);for(const[t,o]of Object.entries(n)){if(!Object.hasOwn(e,t))throw new TypeError(`Unknown option "${t}" — expected one of: ${i.join(", ")}`);if(void 0!==o){if(typeof o!=typeof r[t])throw new TypeError(`Option "${t}" must be a ${typeof r[t]}, got ${typeof o}`);r[t]=o}}return r}const c=["零","一","二","三","四","五","六","七","八","九"],f=["零","壹","貳","參","肆","伍","陸","柒","捌","玖"],a=s(16),l=s(16),g=s(16),p="零";function b(n,e=!0){if(0n===n)return p;const t=e?f:c,r=e?"拾":"十",i=e?"佰":"百",o=e?"仟":"千";function s(n){if(0n===n)return"";const e=[];let s=!1;const u=n/1000n,c=n%1000n;u>0n&&(e.push(t[Number(u)]+o),s=c>0n&&c<100n);const f=c/100n,a=c%100n;f>0n?(s&&e.push(p),e.push(t[Number(f)]+i),s=a>0n&&a<10n):u>0n&&a>0n&&(s=!0);const l=a/10n,g=a%10n;return l>0n?(s&&(e.push(p),s=!1),e.push(t[Number(l)]+r)):(f>0n||u>0n)&&g>0n&&(s=!0),g>0n&&(s&&e.push(p),e.push(t[Number(g)])),e.join("")}function u(n){if(0n===n)return"";const e=[];if(n>=10000n){const t=n/10000n,r=n%10000n;e.push(s(t)+"萬"),r>0n&&((t%10n==0n||r<1000n)&&e.push(p),e.push(s(r)))}else e.push(s(n));return e.join("")}const a=[];if(n>=100000000n){const e=n%100000000n,t=u(n/100000000n);a.push(t+"億"),e>0n&&(e<10000000n&&a.push(p),a.push(u(e)))}else a.push(u(n));return a.join("")}const m={formal:!0};function h(i,s){const{isNegative:l,integerPart:g,decimalPart:p}=function(i){const o=typeof i;if("bigint"==typeof i)return i<0n?{isNegative:!0,integerPart:-i}:{isNegative:!1,integerPart:i};if("number"==typeof i){if(!Number.isFinite(i))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(i)?i<0?{isNegative:!0,integerPart:BigInt(-i)}:{isNegative:!1,integerPart:BigInt(i)}:r(e(i))}if("string"==typeof i)return r(function(e){const r=e.trim();if(0===r.length||Number.isNaN(Number(r)))throw new RangeError(`Invalid number format: "${e}"`);return t(r)?n(r):r}(i));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${o}`)}(i);o(g,a);const{formal:h}=u(s,m);let w="";return l&&(w="負"),w+=b(g,h),p&&(w+="點"+function(n,e=!0){const t=e?f:c,r=[];for(const e of n)r.push(t[Number(e)]);return r}(p,h).join("")),w}const w={formal:!0};function d(e,r){const i=function(e){const r=typeof e;if("bigint"==typeof e){if(e<=0n)throw new RangeError("Ordinals must be positive integers");return e}if("number"==typeof e){if(!Number.isFinite(e))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(e))throw new RangeError("Ordinals must be whole numbers");if(e<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(e)}if("string"==typeof e)return function(e){const r=e.trim();if(0===r.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===r[0])throw new RangeError("Ordinals cannot be negative");if(r.includes("."))throw new RangeError("Ordinals must be whole numbers");if(t(r)){const e=n(r);if(e.includes("."))throw new RangeError("Ordinals must be whole numbers");const t=BigInt(e);if(t<=0n)throw new RangeError("Ordinals must be positive integers");return t}try{const n=BigInt(r);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(n){if(n instanceof RangeError)throw n;throw new RangeError(`Invalid ordinal format: "${e}"`,{cause:n})}}(e);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${r}`)}(e);o(i,l);const{formal:s}=u(r,w);return function(n,e=!0){return"第"+b(n,e)}(i,s)}const N={formal:!0};function v(n,t){const{isNegative:r,dollars:s,cents:a}=function(n){const t=typeof n;if("bigint"==typeof n)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:i(e(n))}if("string"==typeof n)return i(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`)}(n);o(s,g);const{formal:l}=u(t,N),m=l?"圓":"元",h=a/10n,w=a%10n;let d="";return r&&(d="負"),(s>0n||0n===a)&&(d+=b(s,l),d+=m),h>0n&&(d+=(l?f:c)[Number(h)]+"角"),w>0n?(s>0n&&0n===h&&(d+=p),d+=(l?f:c)[Number(w)]+"分"):d+="整",d}export{m as cardinalDefaults,a as cardinalMax,N as currencyDefaults,g as currencyMax,w as ordinalDefaults,l as ordinalMax,h as toCardinal,v as toCurrency,d as toOrdinal};
@@ -1,2 +1,2 @@
1
- /*! n2words/zh-Hant-TW v5.0.0 | MIT License | github.com/forzagreen/n2words */
2
- var n,e;n=this,e=function(n){"use strict";function e(n){let[e,t]=n.toLowerCase().split("e");const r=parseInt(t,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const o=e.indexOf("."),s=-1===o?e:e.slice(0,o)+e.slice(o+1),u=(-1===o?e.length:o)+r;return u>=s.length?i+s+"0".repeat(u-s.length):u<=0?i+"0."+"0".repeat(-u)+s:i+s.slice(0,u)+"."+s.slice(u)}function t(n){const t=n.toString();return r(t)?e(t):t}function r(n){return n.includes("e")||n.includes("E")}function i(n){const e="-"===n[0];e&&(n=n.slice(1));const t=n.indexOf(".");if(-1===t)return{isNegative:e,integerPart:BigInt(n)};const r=n.slice(0,t)||"0",i=n.slice(t+1);return{isNegative:e,integerPart:BigInt(r),decimalPart:i}}function o(n){let t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid currency format: "${n}"`);r(t)&&(t=e(t));const i="-"===t[0];i&&(t=t.slice(1));const o=t.indexOf(".");if(-1===o)return{isNegative:i,dollars:BigInt(t),cents:0n};const s=t.slice(0,o)||"0",u=(t.slice(o+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(s),cents:BigInt(u)}}function s(n){if(void 0===n)return{};if(function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))return n;throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n)}const u=["零","一","二","三","四","五","六","七","八","九"],c=["零","壹","貳","參","肆","伍","陸","柒","捌","玖"],a="零";function f(n,e=!0){if(0n===n)return a;const t=e?c:u,r=e?"拾":"十",i=e?"佰":"百",o=e?"仟":"千";function s(n){if(0n===n)return"";const e=[];let s=!1;const u=n/1000n,c=n%1000n;u>0n&&(e.push(t[Number(u)]+o),s=c>0n&&c<100n);const f=c/100n,l=c%100n;f>0n?(s&&(e.push(a),s=!1),e.push(t[Number(f)]+i),s=l>0n&&l<10n):u>0n&&l>0n&&(s=!0);const g=l/10n,d=l%10n;return g>0n?(s&&(e.push(a),s=!1),e.push(t[Number(g)]+r)):(f>0n||u>0n)&&d>0n&&(s=!0),d>0n&&(s&&e.push(a),e.push(t[Number(d)])),e.join("")}function f(n){if(0n===n)return"";const e=[];if(n>=10000n){const t=n/10000n,r=n%10000n;e.push(s(t)+"萬"),r>0n&&((t%10n==0n||r<1000n)&&e.push(a),e.push(s(r)))}else e.push(s(n));return e.join("")}const l=[];if(n>=100000000n){const e=n%100000000n,t=f(n/100000000n);l.push(t+"億"),e>0n&&(e<10000000n&&l.push(a),l.push(f(e)))}else l.push(f(n));return l.join("")}const l={zhHantTW:function(n,t){t=s(t);const i=function(n){const t=typeof n;if("bigint"===t){if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}if("number"===t){if(!Number.isFinite(n))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(n))throw new RangeError("Ordinals must be whole numbers");if(n<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(n)}if("string"===t)return function(n){const t=n.trim();if(0===t.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===t[0])throw new RangeError("Ordinals cannot be negative");if(t.includes("."))throw new RangeError("Ordinals must be whole numbers");if(r(t)){const n=e(t);if(n.includes("."))throw new RangeError("Ordinals must be whole numbers");const r=BigInt(n);if(r<=0n)throw new RangeError("Ordinals must be positive integers");return r}try{const n=BigInt(t);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(e){if(e instanceof RangeError)throw e;throw new RangeError(`Invalid ordinal format: "${n}"`)}}(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`)}(n),{formal:o=!0}=t;return function(n,e=!0){return"第"+f(n,e)}(i,o)}};n.currency={zhHantTW:function(n,e){e=s(e);const{isNegative:r,dollars:i,cents:l}=function(n){const e=typeof n;if("bigint"===e)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"===e){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:o(t(n))}if("string"===e)return o(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${e}`)}(n),{formal:g=!0}=e,d=g?"圓":"元",b=l/10n,p=l%10n;let m="";return r&&(m="負"),(i>0n||0n===l)&&(m+=f(i,g),m+=d),b>0n&&(m+=(g?c:u)[Number(b)]+"角"),p>0n?(i>0n&&0n===b&&(m+=a),m+=(g?c:u)[Number(p)]+"分"):m+="整",m}},n.ordinal=l,n.zhHantTW=function(n,o){o=s(o);const{isNegative:a,integerPart:l,decimalPart:g}=function(n){const o=typeof n;if("bigint"===o)return n<0n?{isNegative:!0,integerPart:-n}:{isNegative:!1,integerPart:n};if("number"===o){if(!Number.isFinite(n))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(n)?n<0?{isNegative:!0,integerPart:BigInt(-n)}:{isNegative:!1,integerPart:BigInt(n)}:i(t(n))}if("string"===o)return i(function(n){const t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid number format: "${n}"`);return r(t)?e(t):t}(n));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${o}`)}(n),{formal:d=!0}=o;let b="";return a&&(b="負"),b+=f(l,d),g&&(b+="點"+function(n,e=!0){const t=e?c:u,r=[];for(const e of n)r.push(t[Number(e)]);return r}(g,d).join("")),b}},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).n2words=n.n2words||{});
1
+ /*! n2words/zh-Hant-TW v5.1.1 | MIT License | github.com/forzagreen/n2words */
2
+ var n,e;n=this,e=function(n){"use strict";function e(n){let[e,t]=n.toLowerCase().split("e");const r=parseInt(t,10);let i="";"-"===e[0]&&(i="-",e=e.slice(1));const o=e.indexOf("."),s=-1===o?e:e.slice(0,o)+e.slice(o+1),u=(-1===o?e.length:o)+r;return u>=s.length?i+s+"0".repeat(u-s.length):u<=0?i+"0."+"0".repeat(-u)+s:i+s.slice(0,u)+"."+s.slice(u)}function t(n){const t=n.toString();return r(t)?e(t):t}function r(n){return n.includes("e")||n.includes("E")}function i(n){const e="-"===n[0];e&&(n=n.slice(1));const t=n.indexOf(".");if(-1===t)return{isNegative:e,integerPart:BigInt(n)};const r=n.slice(0,t)||"0",i=n.slice(t+1);return{isNegative:e,integerPart:BigInt(r),decimalPart:i}}function o(n){let t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid currency format: "${n}"`);r(t)&&(t=e(t));const i="-"===t[0];i&&(t=t.slice(1));const o=t.indexOf(".");if(-1===o)return{isNegative:i,dollars:BigInt(t),cents:0n};const s=t.slice(0,o)||"0",u=(t.slice(o+1)+"00").slice(0,2);return{isNegative:i,dollars:BigInt(s),cents:BigInt(u)}}function s(n,e,t){if(null===e)return;if(n<e)return;const r=e.toString().length-1,i=e===10n**BigInt(r)?`10^${r} - 1`:""+(e-1n);throw new RangeError(`Number too large to convert: the largest supported value is ${i}`)}function u(n){return 10n**BigInt(n)}function c(n,e,t){const r={...e};if(void 0===n)return r;if(!function(n){if(null===n||"object"!=typeof n)return!1;const e=Object.getPrototypeOf(n);return null===e||e===Object.prototype}(n))throw new TypeError("Invalid options: expected plain object or undefined, got "+typeof n);const i=Object.keys(e);for(const[t,o]of Object.entries(n)){if(!Object.hasOwn(e,t))throw new TypeError(`Unknown option "${t}" — expected one of: ${i.join(", ")}`);if(void 0!==o){if(typeof o!=typeof r[t])throw new TypeError(`Option "${t}" must be a ${typeof r[t]}, got ${typeof o}`);r[t]=o}}return r}const f=["零","一","二","三","四","五","六","七","八","九"],a=["零","壹","貳","參","肆","伍","陸","柒","捌","玖"],l=u(16),g=u(16),p=u(16),d="零";function b(n,e=!0){if(0n===n)return d;const t=e?a:f,r=e?"拾":"十",i=e?"佰":"百",o=e?"仟":"千";function s(n){if(0n===n)return"";const e=[];let s=!1;const u=n/1000n,c=n%1000n;u>0n&&(e.push(t[Number(u)]+o),s=c>0n&&c<100n);const f=c/100n,a=c%100n;f>0n?(s&&e.push(d),e.push(t[Number(f)]+i),s=a>0n&&a<10n):u>0n&&a>0n&&(s=!0);const l=a/10n,g=a%10n;return l>0n?(s&&(e.push(d),s=!1),e.push(t[Number(l)]+r)):(f>0n||u>0n)&&g>0n&&(s=!0),g>0n&&(s&&e.push(d),e.push(t[Number(g)])),e.join("")}function u(n){if(0n===n)return"";const e=[];if(n>=10000n){const t=n/10000n,r=n%10000n;e.push(s(t)+"萬"),r>0n&&((t%10n==0n||r<1000n)&&e.push(d),e.push(s(r)))}else e.push(s(n));return e.join("")}const c=[];if(n>=100000000n){const e=n%100000000n,t=u(n/100000000n);c.push(t+"億"),e>0n&&(e<10000000n&&c.push(d),c.push(u(e)))}else c.push(u(n));return c.join("")}const m={formal:!0},h={formal:!0},w={formal:!0},y={zhHantTW:function(n,t){const i=function(n){const t=typeof n;if("bigint"==typeof n){if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Ordinals must be finite numbers");if(!Number.isInteger(n))throw new RangeError("Ordinals must be whole numbers");if(n<=0)throw new RangeError("Ordinals must be positive integers");return BigInt(n)}if("string"==typeof n)return function(n){const t=n.trim();if(0===t.length)throw new RangeError("Ordinals cannot be empty strings");if("-"===t[0])throw new RangeError("Ordinals cannot be negative");if(t.includes("."))throw new RangeError("Ordinals must be whole numbers");if(r(t)){const n=e(t);if(n.includes("."))throw new RangeError("Ordinals must be whole numbers");const r=BigInt(n);if(r<=0n)throw new RangeError("Ordinals must be positive integers");return r}try{const n=BigInt(t);if(n<=0n)throw new RangeError("Ordinals must be positive integers");return n}catch(e){if(e instanceof RangeError)throw e;throw new RangeError(`Invalid ordinal format: "${n}"`,{cause:e})}}(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`)}(n);s(i,g);const{formal:o}=c(t,h);return function(n,e=!0){return"第"+b(n,e)}(i,o)}};n.currency={zhHantTW:function(n,e){const{isNegative:r,dollars:i,cents:u}=function(n){const e=typeof n;if("bigint"==typeof n)return n<0n?{isNegative:!0,dollars:-n,cents:0n}:{isNegative:!1,dollars:n,cents:0n};if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Currency must be a finite number");return Number.isSafeInteger(n)?n<0?{isNegative:!0,dollars:BigInt(-n),cents:0n}:{isNegative:!1,dollars:BigInt(n),cents:0n}:o(t(n))}if("string"==typeof n)return o(n);throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${e}`)}(n);s(i,p);const{formal:l}=c(e,w),g=l?"圓":"元",m=u/10n,h=u%10n;let y="";return r&&(y="負"),(i>0n||0n===u)&&(y+=b(i,l),y+=g),m>0n&&(y+=(l?a:f)[Number(m)]+"角"),h>0n?(i>0n&&0n===m&&(y+=d),y+=(l?a:f)[Number(h)]+"分"):y+="整",y}},n.ordinal=y,n.zhHantTW=function(n,o){const{isNegative:u,integerPart:g,decimalPart:p}=function(n){const o=typeof n;if("bigint"==typeof n)return n<0n?{isNegative:!0,integerPart:-n}:{isNegative:!1,integerPart:n};if("number"==typeof n){if(!Number.isFinite(n))throw new RangeError("Number must be finite (NaN and Infinity are not supported)");return Number.isSafeInteger(n)?n<0?{isNegative:!0,integerPart:BigInt(-n)}:{isNegative:!1,integerPart:BigInt(n)}:i(t(n))}if("string"==typeof n)return i(function(n){const t=n.trim();if(0===t.length||Number.isNaN(Number(t)))throw new RangeError(`Invalid number format: "${n}"`);return r(t)?e(t):t}(n));throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${o}`)}(n);s(g,l);const{formal:d}=c(o,m);let h="";return u&&(h="負"),h+=b(g,d),p&&(h+="點"+function(n,e=!0){const t=e?a:f,r=[];for(const e of n)r.push(t[Number(e)]);return r}(p,d).join("")),h}},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).n2words=n.n2words||{});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n2words",
3
- "version": "5.0.0",
3
+ "version": "5.1.1",
4
4
  "description": "Convert numbers to words in 70+ languages with zero dependencies. Supports BigInt, decimals, and browser/Node.js environments.",
5
5
  "keywords": [
6
6
  "number-to-words",
@@ -75,15 +75,18 @@
75
75
  "clean:dist": "rimraf dist",
76
76
  "clean:types": "rimraf \"src/**/*.d.ts\" --glob",
77
77
  "coverage": "c8 node --run test:unit",
78
+ "coverage:check": "c8 check-coverage",
78
79
  "docs:languages": "node scripts/generate-languages-md.js",
79
80
  "lang:add": "node scripts/add-language.js",
80
81
  "lint": "node --run lint:js && node --run lint:md",
81
- "lint:fix": "standard --fix && markdownlint-cli2 --fix",
82
- "lint:js": "standard",
82
+ "lint:fix": "eslint --fix && markdownlint-cli2 --fix",
83
+ "lint:js": "eslint",
83
84
  "lint:md": "markdownlint-cli2",
85
+ "prepack": "node --run build",
84
86
  "prepare:husky": "husky",
85
87
  "test": "node --run test:unit && node --run build:types",
86
- "test:unit": "ava \"test/*.test.js\" \"test/utils/*.test.js\""
88
+ "test:unit": "ava \"test/*.test.js\" \"test/utils/*.test.js\"",
89
+ "typecheck": "tsc --project tsconfig.build.json --noEmit"
87
90
  },
88
91
  "ava": {
89
92
  "extensions": [
@@ -97,11 +100,6 @@
97
100
  "concurrency": 8,
98
101
  "workerThreads": false
99
102
  },
100
- "standard": {
101
- "ignore": [
102
- "!.vscode/"
103
- ]
104
- },
105
103
  "c8": {
106
104
  "all": true,
107
105
  "include": [
@@ -114,41 +112,52 @@
114
112
  "lcov",
115
113
  "text",
116
114
  "json-summary"
117
- ]
115
+ ],
116
+ "lines": 90,
117
+ "statements": 90,
118
+ "functions": 90,
119
+ "branches": 85
118
120
  },
119
121
  "lint-staged": {
120
122
  "*.{js,cjs,mjs}": [
121
- "standard --fix"
123
+ "eslint --fix"
122
124
  ],
123
125
  "*.md": [
124
126
  "markdownlint-cli2 --fix"
125
127
  ]
126
128
  },
127
129
  "devDependencies": {
128
- "@babel/core": "^7.29.0",
129
- "@babel/preset-env": "^7.29.5",
130
- "@commitlint/cli": "^21.0.1",
131
- "@commitlint/config-conventional": "^21.0.1",
132
- "@commitlint/format": "^21.0.1",
133
- "@rollup/plugin-babel": "^7.0.0",
134
- "@rollup/plugin-node-resolve": "^16.0.3",
130
+ "@commitlint/cli": "^21.1.0",
131
+ "@commitlint/config-conventional": "^21.1.0",
132
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.7.2",
133
+ "@eslint/js": "^10.0.1",
135
134
  "@rollup/plugin-terser": "^1.0.0",
136
135
  "@rollup/plugin-virtual": "^3.0.2",
136
+ "@stylistic/eslint-plugin": "^5.10.0",
137
+ "@types/node": "^26.0.1",
137
138
  "ava": "^8.0.1",
138
- "benchmark": "^2.1.4",
139
- "browserslist": "^4.28.2",
139
+ "browserslist": "^4.28.4",
140
140
  "c8": "^11.0.0",
141
141
  "chalk": "^5.6.2",
142
+ "eslint": "^10.5.0",
143
+ "eslint-plugin-ava": "^17.0.1",
144
+ "eslint-plugin-compat": "^7.0.2",
145
+ "eslint-plugin-es-x": "^9.7.0",
146
+ "eslint-plugin-import-x": "^4.17.0",
147
+ "eslint-plugin-jsdoc": "^63.0.8",
148
+ "eslint-plugin-n": "^18.2.1",
149
+ "fast-check": "^4.8.0",
150
+ "globals": "^17.7.0",
142
151
  "husky": "^9.1.7",
143
- "lint-staged": "^17.0.5",
152
+ "lint-staged": "^17.0.8",
144
153
  "markdownlint-cli2": "^0.22.1",
145
154
  "rimraf": "^6.1.3",
146
- "rollup": "^4.60.4",
147
- "standard": "^17.1.2",
155
+ "rollup": "^4.62.2",
156
+ "tinybench": "^6.0.2",
148
157
  "typescript": "^6.0.3"
149
158
  },
150
159
  "engines": {
151
- "node": ">=22"
160
+ "node": "^22 || ^24 || ^26"
152
161
  },
153
162
  "publishConfig": {
154
163
  "access": "public",
package/src/am-ET.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
1
4
  /**
2
5
  * Converts a numeric value to Amharic words.
3
- *
4
6
  * @param {number | string | bigint} value - The numeric value to convert
5
7
  * @returns {string} The number in Amharic words
6
8
  */
@@ -10,12 +12,10 @@ export function toCardinal(value: number | string | bigint): string;
10
12
  *
11
13
  * Amharic ordinals: add -ኛ suffix to cardinal.
12
14
  * Special case: 1 → አንደኛ
13
- *
14
15
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
15
16
  * @returns {string} The number as ordinal words
16
17
  * @throws {TypeError} If value is not a valid numeric type
17
18
  * @throws {RangeError} If value is negative, zero, or has a decimal part
18
- *
19
19
  * @example
20
20
  * toOrdinal(1) // 'አንደኛ'
21
21
  * toOrdinal(2) // 'ሁለትኛ'
@@ -25,12 +25,10 @@ export function toCardinal(value: number | string | bigint): string;
25
25
  export function toOrdinal(value: number | string | bigint): string;
26
26
  /**
27
27
  * Converts a numeric value to Amharic currency words (Ethiopian Birr).
28
- *
29
28
  * @param {number | string | bigint} value - The currency amount to convert
30
29
  * @returns {string} The amount in Amharic currency words
31
30
  * @throws {TypeError} If value is not a valid numeric type
32
31
  * @throws {Error} If value is not a valid number format
33
- *
34
32
  * @example
35
33
  * toCurrency(42.50) // 'አርባ ሁለት ብር ሃምሳ ሳንቲም'
36
34
  * toCurrency(1) // 'አንድ ብር'
package/src/am-ET.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
@@ -53,11 +55,23 @@ const SANTIM = 'ሳንቲም'
53
55
  // Short scale
54
56
  const SCALE_WORDS = ['', THOUSAND, 'ሚሊዮን', 'ቢሊዮን']
55
57
 
58
+ // Supported magnitude ceiling (checked at the public entry points). SCALE_WORDS
59
+ // reaches index SCALE_WORDS.length-1 (ቢሊዮን, 10^9), so values must stay below
60
+ // 10^(SCALE_WORDS.length * 3) = 10^12. Ordinal and currency build on the
61
+ // cardinal, so they share it. Decimals are read digit-by-digit (no ceiling).
62
+ export const cardinalMax = western(SCALE_WORDS.length - 1)
63
+ export const ordinalMax = western(SCALE_WORDS.length - 1)
64
+ export const currencyMax = western(SCALE_WORDS.length - 1)
65
+
56
66
  // ============================================================================
57
67
  // Precomputed Lookup Table
58
68
  // ============================================================================
59
69
 
60
- function buildSegment (n) {
70
+ /**
71
+ * @param {number} n The three-digit segment value (0-999) to convert.
72
+ * @returns {string} The segment in Amharic words.
73
+ */
74
+ function buildSegment(n) {
61
75
  if (n === 0) return ''
62
76
 
63
77
  const ones = n % 10
@@ -73,7 +87,8 @@ function buildSegment (n) {
73
87
 
74
88
  if (tensDigit === 1) {
75
89
  parts.push(TEENS[ones])
76
- } else {
90
+ }
91
+ else {
77
92
  if (tensDigit > 1) {
78
93
  parts.push(TENS[tensDigit])
79
94
  }
@@ -89,7 +104,11 @@ function buildSegment (n) {
89
104
  // Conversion Functions
90
105
  // ============================================================================
91
106
 
92
- function integerToWords (n) {
107
+ /**
108
+ * @param {bigint} n The non-negative integer to convert.
109
+ * @returns {string} The integer in Amharic words.
110
+ */
111
+ function integerToWords(n) {
93
112
  if (n === 0n) return ZERO
94
113
 
95
114
  if (n < 1000n) {
@@ -99,7 +118,11 @@ function integerToWords (n) {
99
118
  return buildLargeNumberWords(n)
100
119
  }
101
120
 
102
- function buildLargeNumberWords (n) {
121
+ /**
122
+ * @param {bigint} n The integer (>= 1000) to convert using scale words.
123
+ * @returns {string} The integer in Amharic words.
124
+ */
125
+ function buildLargeNumberWords(n) {
103
126
  const numStr = n.toString()
104
127
  const len = numStr.length
105
128
 
@@ -128,7 +151,8 @@ function buildLargeNumberWords (n) {
128
151
 
129
152
  if (scaleIndex === 0) {
130
153
  parts.push(buildSegment(segment))
131
- } else {
154
+ }
155
+ else {
132
156
  parts.push(buildSegment(segment) + ' ' + scaleWord)
133
157
  }
134
158
  }
@@ -139,7 +163,11 @@ function buildLargeNumberWords (n) {
139
163
  return parts.join(' ')
140
164
  }
141
165
 
142
- function decimalPartToWords (decimalPart) {
166
+ /**
167
+ * @param {string} decimalPart The digit string after the decimal point.
168
+ * @returns {string} The decimal digits read individually in Amharic words.
169
+ */
170
+ function decimalPartToWords(decimalPart) {
143
171
  // Per-digit decimal reading
144
172
  const digits = []
145
173
  for (const char of decimalPart) {
@@ -151,12 +179,12 @@ function decimalPartToWords (decimalPart) {
151
179
 
152
180
  /**
153
181
  * Converts a numeric value to Amharic words.
154
- *
155
182
  * @param {number | string | bigint} value - The numeric value to convert
156
183
  * @returns {string} The number in Amharic words
157
184
  */
158
- function toCardinal (value) {
185
+ function toCardinal(value) {
159
186
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
187
+ checkMax(integerPart, cardinalMax)
160
188
 
161
189
  let result = ''
162
190
 
@@ -182,11 +210,10 @@ function toCardinal (value) {
182
210
  *
183
211
  * In Amharic, ordinals are formed by adding -ኛ suffix to the cardinal.
184
212
  * Special case: 1 = አንደኛ (not አንድኛ)
185
- *
186
213
  * @param {bigint} n - Positive integer to convert
187
214
  * @returns {string} Amharic ordinal words
188
215
  */
189
- function integerToOrdinal (n) {
216
+ function integerToOrdinal(n) {
190
217
  // Special case: 1 → አንደኛ
191
218
  if (n === 1n) {
192
219
  return FIRST
@@ -202,20 +229,19 @@ function integerToOrdinal (n) {
202
229
  *
203
230
  * Amharic ordinals: add -ኛ suffix to cardinal.
204
231
  * Special case: 1 → አንደኛ
205
- *
206
232
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
207
233
  * @returns {string} The number as ordinal words
208
234
  * @throws {TypeError} If value is not a valid numeric type
209
235
  * @throws {RangeError} If value is negative, zero, or has a decimal part
210
- *
211
236
  * @example
212
237
  * toOrdinal(1) // 'አንደኛ'
213
238
  * toOrdinal(2) // 'ሁለትኛ'
214
239
  * toOrdinal(10) // 'አስርኛ'
215
240
  * toOrdinal(100) // 'አንድ መቶኛ'
216
241
  */
217
- function toOrdinal (value) {
242
+ function toOrdinal(value) {
218
243
  const integerPart = parseOrdinalValue(value)
244
+ checkMax(integerPart, ordinalMax)
219
245
  return integerToOrdinal(integerPart)
220
246
  }
221
247
 
@@ -225,20 +251,19 @@ function toOrdinal (value) {
225
251
 
226
252
  /**
227
253
  * Converts a numeric value to Amharic currency words (Ethiopian Birr).
228
- *
229
254
  * @param {number | string | bigint} value - The currency amount to convert
230
255
  * @returns {string} The amount in Amharic currency words
231
256
  * @throws {TypeError} If value is not a valid numeric type
232
257
  * @throws {Error} If value is not a valid number format
233
- *
234
258
  * @example
235
259
  * toCurrency(42.50) // 'አርባ ሁለት ብር ሃምሳ ሳንቲም'
236
260
  * toCurrency(1) // 'አንድ ብር'
237
261
  * toCurrency(0.99) // 'ዘጠና ዘጠኝ ሳንቲም'
238
262
  * toCurrency(0.01) // 'አንድ ሳንቲም'
239
263
  */
240
- function toCurrency (value) {
264
+ function toCurrency(value) {
241
265
  const { isNegative, dollars: birr, cents: santim } = parseCurrencyValue(value)
266
+ checkMax(birr, currencyMax)
242
267
 
243
268
  // Build result
244
269
  let result = ''
@@ -1,18 +1,18 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
1
4
  /**
2
5
  * Converts a numeric value to Amharic (Latin script) words.
3
- *
4
6
  * @param {number | string | bigint} value - The numeric value to convert
5
7
  * @returns {string} The number in Amharic Latin words
6
8
  */
7
9
  export function toCardinal(value: number | string | bigint): string;
8
10
  /**
9
11
  * Converts a numeric value to Amharic (Latin script) ordinal words.
10
- *
11
12
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
12
13
  * @returns {string} The number as ordinal words
13
14
  * @throws {TypeError} If value is not a valid numeric type
14
15
  * @throws {RangeError} If value is negative, zero, or has a decimal part
15
- *
16
16
  * @example
17
17
  * toOrdinal(1) // 'andenya'
18
18
  * toOrdinal(2) // 'huletnya'
@@ -21,12 +21,10 @@ export function toCardinal(value: number | string | bigint): string;
21
21
  export function toOrdinal(value: number | string | bigint): string;
22
22
  /**
23
23
  * Converts a numeric value to Amharic (Latin script) currency words (Ethiopian Birr).
24
- *
25
24
  * @param {number | string | bigint} value - The currency amount to convert
26
25
  * @returns {string} The amount in Amharic (Latin) currency words
27
26
  * @throws {TypeError} If value is not a valid numeric type
28
27
  * @throws {Error} If value is not a valid number format
29
- *
30
28
  * @example
31
29
  * toCurrency(42.50) // 'arba hulet birr hamsa santim'
32
30
  * toCurrency(1) // 'and birr'
package/src/am-Latn-ET.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
@@ -53,11 +55,24 @@ const SANTIM = 'santim'
53
55
  // Short scale
54
56
  const SCALE_WORDS = ['', THOUSAND, 'miliyon', 'billiyon']
55
57
 
58
+ // Supported magnitude ceiling (checked at the public entry points). SCALE_WORDS
59
+ // reaches index SCALE_WORDS.length-1 (billiyon, 10^9), so values must stay below
60
+ // 10^(SCALE_WORDS.length * 3) = 10^12. Ordinal and currency build on the
61
+ // cardinal, so they share it. Decimals are read digit-by-digit (no ceiling).
62
+ export const cardinalMax = western(SCALE_WORDS.length - 1)
63
+ export const ordinalMax = western(SCALE_WORDS.length - 1)
64
+ export const currencyMax = western(SCALE_WORDS.length - 1)
65
+
56
66
  // ============================================================================
57
67
  // Precomputed Lookup Table
58
68
  // ============================================================================
59
69
 
60
- function buildSegment (n) {
70
+ /**
71
+ * Builds the words for a 3-digit segment (0-999).
72
+ * @param {number} n - Segment value (0-999)
73
+ * @returns {string} The segment in Amharic (Latin) words
74
+ */
75
+ function buildSegment(n) {
61
76
  if (n === 0) return ''
62
77
 
63
78
  const ones = n % 10
@@ -73,7 +88,8 @@ function buildSegment (n) {
73
88
 
74
89
  if (tensDigit === 1) {
75
90
  parts.push(TEENS[ones])
76
- } else {
91
+ }
92
+ else {
77
93
  if (tensDigit > 1) {
78
94
  parts.push(TENS[tensDigit])
79
95
  }
@@ -89,7 +105,12 @@ function buildSegment (n) {
89
105
  // Conversion Functions
90
106
  // ============================================================================
91
107
 
92
- function integerToWords (n) {
108
+ /**
109
+ * Converts a non-negative integer to Amharic (Latin script) words.
110
+ * @param {bigint} n - Non-negative integer to convert
111
+ * @returns {string} The integer in Amharic (Latin) words
112
+ */
113
+ function integerToWords(n) {
93
114
  if (n === 0n) return ZERO
94
115
 
95
116
  if (n < 1000n) {
@@ -99,7 +120,12 @@ function integerToWords (n) {
99
120
  return buildLargeNumberWords(n)
100
121
  }
101
122
 
102
- function buildLargeNumberWords (n) {
123
+ /**
124
+ * Builds the words for a number of 1000 or greater using short-scale grouping.
125
+ * @param {bigint} n - Integer of 1000 or greater
126
+ * @returns {string} The number in Amharic (Latin) words
127
+ */
128
+ function buildLargeNumberWords(n) {
103
129
  const numStr = n.toString()
104
130
  const len = numStr.length
105
131
 
@@ -128,7 +154,8 @@ function buildLargeNumberWords (n) {
128
154
 
129
155
  if (scaleIndex === 0) {
130
156
  parts.push(buildSegment(segment))
131
- } else {
157
+ }
158
+ else {
132
159
  parts.push(buildSegment(segment) + ' ' + scaleWord)
133
160
  }
134
161
  }
@@ -139,7 +166,12 @@ function buildLargeNumberWords (n) {
139
166
  return parts.join(' ')
140
167
  }
141
168
 
142
- function decimalPartToWords (decimalPart) {
169
+ /**
170
+ * Reads the decimal part digit by digit.
171
+ * @param {string} decimalPart - The fractional digits as a string
172
+ * @returns {string} The decimal digits in Amharic (Latin) words
173
+ */
174
+ function decimalPartToWords(decimalPart) {
143
175
  // Per-digit decimal reading
144
176
  const digits = []
145
177
  for (const char of decimalPart) {
@@ -151,12 +183,12 @@ function decimalPartToWords (decimalPart) {
151
183
 
152
184
  /**
153
185
  * Converts a numeric value to Amharic (Latin script) words.
154
- *
155
186
  * @param {number | string | bigint} value - The numeric value to convert
156
187
  * @returns {string} The number in Amharic Latin words
157
188
  */
158
- function toCardinal (value) {
189
+ function toCardinal(value) {
159
190
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
191
+ checkMax(integerPart, cardinalMax)
160
192
 
161
193
  let result = ''
162
194
 
@@ -182,11 +214,10 @@ function toCardinal (value) {
182
214
  *
183
215
  * In Amharic, ordinals are formed by adding -nya suffix to the cardinal.
184
216
  * Special case: 1 = andenya
185
- *
186
217
  * @param {bigint} n - Positive integer to convert
187
218
  * @returns {string} Amharic (Latin) ordinal words
188
219
  */
189
- function integerToOrdinal (n) {
220
+ function integerToOrdinal(n) {
190
221
  // Special case: 1 → andenya
191
222
  if (n === 1n) {
192
223
  return FIRST
@@ -199,19 +230,18 @@ function integerToOrdinal (n) {
199
230
 
200
231
  /**
201
232
  * Converts a numeric value to Amharic (Latin script) ordinal words.
202
- *
203
233
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
204
234
  * @returns {string} The number as ordinal words
205
235
  * @throws {TypeError} If value is not a valid numeric type
206
236
  * @throws {RangeError} If value is negative, zero, or has a decimal part
207
- *
208
237
  * @example
209
238
  * toOrdinal(1) // 'andenya'
210
239
  * toOrdinal(2) // 'huletnya'
211
240
  * toOrdinal(10) // 'asirnya'
212
241
  */
213
- function toOrdinal (value) {
242
+ function toOrdinal(value) {
214
243
  const integerPart = parseOrdinalValue(value)
244
+ checkMax(integerPart, ordinalMax)
215
245
  return integerToOrdinal(integerPart)
216
246
  }
217
247
 
@@ -221,19 +251,18 @@ function toOrdinal (value) {
221
251
 
222
252
  /**
223
253
  * Converts a numeric value to Amharic (Latin script) currency words (Ethiopian Birr).
224
- *
225
254
  * @param {number | string | bigint} value - The currency amount to convert
226
255
  * @returns {string} The amount in Amharic (Latin) currency words
227
256
  * @throws {TypeError} If value is not a valid numeric type
228
257
  * @throws {Error} If value is not a valid number format
229
- *
230
258
  * @example
231
259
  * toCurrency(42.50) // 'arba hulet birr hamsa santim'
232
260
  * toCurrency(1) // 'and birr'
233
261
  * toCurrency(0.01) // 'and santim'
234
262
  */
235
- function toCurrency (value) {
263
+ function toCurrency(value) {
236
264
  const { isNegative, dollars: birr, cents: santim } = parseCurrencyValue(value)
265
+ checkMax(birr, currencyMax)
237
266
 
238
267
  // Build result
239
268
  let result = ''