n2words 1.23.1 → 2.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 (322) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +317 -59
  3. package/dist/ArabicConverter.js +3 -0
  4. package/dist/ArabicConverter.js.map +1 -0
  5. package/dist/AzerbaijaniConverter.js +3 -0
  6. package/dist/AzerbaijaniConverter.js.map +1 -0
  7. package/dist/BanglaConverter.js +3 -0
  8. package/dist/BanglaConverter.js.map +1 -0
  9. package/dist/BiblicalHebrewConverter.js +3 -0
  10. package/dist/BiblicalHebrewConverter.js.map +1 -0
  11. package/dist/CroatianConverter.js +3 -0
  12. package/dist/CroatianConverter.js.map +1 -0
  13. package/dist/CzechConverter.js +3 -0
  14. package/dist/CzechConverter.js.map +1 -0
  15. package/dist/DanishConverter.js +3 -0
  16. package/dist/DanishConverter.js.map +1 -0
  17. package/dist/DutchConverter.js +3 -0
  18. package/dist/DutchConverter.js.map +1 -0
  19. package/dist/EnglishConverter.js +3 -0
  20. package/dist/EnglishConverter.js.map +1 -0
  21. package/dist/FilipinoConverter.js +3 -0
  22. package/dist/FilipinoConverter.js.map +1 -0
  23. package/dist/FrenchBelgiumConverter.js +3 -0
  24. package/dist/FrenchBelgiumConverter.js.map +1 -0
  25. package/dist/FrenchConverter.js +3 -0
  26. package/dist/FrenchConverter.js.map +1 -0
  27. package/dist/GermanConverter.js +3 -0
  28. package/dist/GermanConverter.js.map +1 -0
  29. package/dist/GreekConverter.js +3 -0
  30. package/dist/GreekConverter.js.map +1 -0
  31. package/dist/GujaratiConverter.js +3 -0
  32. package/dist/GujaratiConverter.js.map +1 -0
  33. package/dist/HebrewConverter.js +3 -0
  34. package/dist/HebrewConverter.js.map +1 -0
  35. package/dist/HindiConverter.js +3 -0
  36. package/dist/HindiConverter.js.map +1 -0
  37. package/dist/HungarianConverter.js +3 -0
  38. package/dist/HungarianConverter.js.map +1 -0
  39. package/dist/IndonesianConverter.js +3 -0
  40. package/dist/IndonesianConverter.js.map +1 -0
  41. package/dist/ItalianConverter.js +3 -0
  42. package/dist/ItalianConverter.js.map +1 -0
  43. package/dist/JapaneseConverter.js +3 -0
  44. package/dist/JapaneseConverter.js.map +1 -0
  45. package/dist/KannadaConverter.js +3 -0
  46. package/dist/KannadaConverter.js.map +1 -0
  47. package/dist/KoreanConverter.js +3 -0
  48. package/dist/KoreanConverter.js.map +1 -0
  49. package/dist/LatvianConverter.js +3 -0
  50. package/dist/LatvianConverter.js.map +1 -0
  51. package/dist/LithuanianConverter.js +3 -0
  52. package/dist/LithuanianConverter.js.map +1 -0
  53. package/dist/MalayConverter.js +3 -0
  54. package/dist/MalayConverter.js.map +1 -0
  55. package/dist/MarathiConverter.js +3 -0
  56. package/dist/MarathiConverter.js.map +1 -0
  57. package/dist/NorwegianBokmalConverter.js +3 -0
  58. package/dist/NorwegianBokmalConverter.js.map +1 -0
  59. package/dist/PersianConverter.js +3 -0
  60. package/dist/PersianConverter.js.map +1 -0
  61. package/dist/PolishConverter.js +3 -0
  62. package/dist/PolishConverter.js.map +1 -0
  63. package/dist/PortugueseConverter.js +3 -0
  64. package/dist/PortugueseConverter.js.map +1 -0
  65. package/dist/PunjabiConverter.js +3 -0
  66. package/dist/PunjabiConverter.js.map +1 -0
  67. package/dist/RomanianConverter.js +3 -0
  68. package/dist/RomanianConverter.js.map +1 -0
  69. package/dist/RussianConverter.js +3 -0
  70. package/dist/RussianConverter.js.map +1 -0
  71. package/dist/SerbianCyrillicConverter.js +3 -0
  72. package/dist/SerbianCyrillicConverter.js.map +1 -0
  73. package/dist/SerbianLatinConverter.js +3 -0
  74. package/dist/SerbianLatinConverter.js.map +1 -0
  75. package/dist/SimplifiedChineseConverter.js +3 -0
  76. package/dist/SimplifiedChineseConverter.js.map +1 -0
  77. package/dist/SpanishConverter.js +3 -0
  78. package/dist/SpanishConverter.js.map +1 -0
  79. package/dist/SwahiliConverter.js +3 -0
  80. package/dist/SwahiliConverter.js.map +1 -0
  81. package/dist/SwedishConverter.js +3 -0
  82. package/dist/SwedishConverter.js.map +1 -0
  83. package/dist/TamilConverter.js +3 -0
  84. package/dist/TamilConverter.js.map +1 -0
  85. package/dist/TeluguConverter.js +3 -0
  86. package/dist/TeluguConverter.js.map +1 -0
  87. package/dist/ThaiConverter.js +3 -0
  88. package/dist/ThaiConverter.js.map +1 -0
  89. package/dist/TraditionalChineseConverter.js +3 -0
  90. package/dist/TraditionalChineseConverter.js.map +1 -0
  91. package/dist/TurkishConverter.js +3 -0
  92. package/dist/TurkishConverter.js.map +1 -0
  93. package/dist/UkrainianConverter.js +3 -0
  94. package/dist/UkrainianConverter.js.map +1 -0
  95. package/dist/UrduConverter.js +3 -0
  96. package/dist/UrduConverter.js.map +1 -0
  97. package/dist/VietnameseConverter.js +3 -0
  98. package/dist/VietnameseConverter.js.map +1 -0
  99. package/dist/n2words.js +3 -2
  100. package/dist/n2words.js.map +1 -1
  101. package/lib/classes/abstract-language.d.ts +158 -34
  102. package/lib/classes/abstract-language.js +223 -115
  103. package/lib/classes/greedy-scale-language.d.ts +109 -0
  104. package/lib/classes/greedy-scale-language.js +201 -0
  105. package/lib/classes/slavic-language.d.ts +148 -0
  106. package/lib/classes/slavic-language.js +281 -0
  107. package/lib/classes/south-asian-language.d.ts +70 -0
  108. package/lib/classes/south-asian-language.js +154 -0
  109. package/lib/classes/turkic-language.d.ts +26 -0
  110. package/lib/classes/turkic-language.js +59 -0
  111. package/lib/languages/ar.d.ts +30 -0
  112. package/lib/languages/ar.js +159 -0
  113. package/lib/languages/az.d.ts +12 -0
  114. package/lib/languages/az.js +42 -0
  115. package/lib/languages/bn.d.ts +11 -0
  116. package/lib/languages/bn.js +131 -0
  117. package/lib/languages/cs.d.ts +88 -0
  118. package/lib/languages/cs.js +143 -0
  119. package/lib/languages/da.d.ts +15 -0
  120. package/lib/languages/da.js +120 -0
  121. package/lib/languages/de.d.ts +14 -0
  122. package/lib/languages/de.js +101 -0
  123. package/lib/languages/el.d.ts +14 -0
  124. package/lib/languages/el.js +90 -0
  125. package/lib/languages/en.d.ts +16 -0
  126. package/lib/languages/en.js +86 -0
  127. package/lib/languages/es.d.ts +15 -0
  128. package/lib/languages/es.js +121 -0
  129. package/lib/languages/fa.d.ts +47 -0
  130. package/lib/languages/fa.js +144 -0
  131. package/lib/languages/fil.d.ts +16 -0
  132. package/lib/languages/fil.js +121 -0
  133. package/lib/languages/fr-BE.d.ts +11 -0
  134. package/lib/languages/fr-BE.js +25 -0
  135. package/lib/languages/fr.d.ts +15 -0
  136. package/lib/languages/fr.js +106 -0
  137. package/lib/languages/gu.d.ts +11 -0
  138. package/lib/languages/gu.js +132 -0
  139. package/lib/languages/hbo.d.ts +113 -0
  140. package/lib/languages/hbo.js +251 -0
  141. package/lib/languages/he.d.ts +80 -0
  142. package/lib/languages/he.js +206 -0
  143. package/lib/languages/hi.d.ts +11 -0
  144. package/lib/languages/hi.js +131 -0
  145. package/lib/languages/hr.d.ts +80 -0
  146. package/lib/languages/hr.js +113 -0
  147. package/lib/languages/hu.d.ts +22 -0
  148. package/lib/languages/hu.js +137 -0
  149. package/lib/languages/id.d.ts +37 -0
  150. package/lib/languages/id.js +159 -0
  151. package/lib/languages/it.d.ts +37 -0
  152. package/lib/languages/it.js +132 -0
  153. package/lib/languages/ja.d.ts +17 -0
  154. package/lib/languages/ja.js +137 -0
  155. package/lib/languages/kn.d.ts +11 -0
  156. package/lib/languages/kn.js +42 -0
  157. package/lib/languages/ko.d.ts +14 -0
  158. package/lib/languages/ko.js +55 -0
  159. package/lib/{i18n/pl.d.ts → languages/lt.d.ts} +18 -15
  160. package/lib/languages/lt.js +136 -0
  161. package/lib/{i18n/lt.d.ts → languages/lv.d.ts} +16 -14
  162. package/lib/languages/lv.js +130 -0
  163. package/lib/languages/mr.d.ts +11 -0
  164. package/lib/languages/mr.js +132 -0
  165. package/lib/languages/ms.d.ts +31 -0
  166. package/lib/languages/ms.js +150 -0
  167. package/lib/languages/nb.d.ts +12 -0
  168. package/lib/languages/nb.js +100 -0
  169. package/lib/languages/nl.d.ts +16 -0
  170. package/lib/languages/nl.js +155 -0
  171. package/lib/languages/pa.d.ts +11 -0
  172. package/lib/languages/pa.js +131 -0
  173. package/lib/{i18n/uk.d.ts → languages/pl.d.ts} +16 -14
  174. package/lib/languages/pl.js +110 -0
  175. package/lib/languages/pt.d.ts +29 -0
  176. package/lib/languages/pt.js +112 -0
  177. package/lib/languages/ro.d.ts +158 -0
  178. package/lib/languages/ro.js +273 -0
  179. package/lib/languages/ru.d.ts +85 -0
  180. package/lib/languages/ru.js +96 -0
  181. package/lib/languages/sr-Cyrl.d.ts +80 -0
  182. package/lib/languages/sr-Cyrl.js +113 -0
  183. package/lib/{i18n/cz.d.ts → languages/sr-Latn.d.ts} +26 -14
  184. package/lib/languages/sr-Latn.js +113 -0
  185. package/lib/languages/sv.d.ts +14 -0
  186. package/lib/languages/sv.js +90 -0
  187. package/lib/languages/sw.d.ts +39 -0
  188. package/lib/languages/sw.js +126 -0
  189. package/lib/languages/ta.d.ts +20 -0
  190. package/lib/languages/ta.js +226 -0
  191. package/lib/languages/te.d.ts +22 -0
  192. package/lib/languages/te.js +219 -0
  193. package/lib/languages/th.d.ts +17 -0
  194. package/lib/languages/th.js +117 -0
  195. package/lib/languages/tr.d.ts +12 -0
  196. package/lib/languages/tr.js +56 -0
  197. package/lib/languages/uk.d.ts +85 -0
  198. package/lib/{i18n → languages}/uk.js +33 -32
  199. package/lib/languages/ur.d.ts +11 -0
  200. package/lib/languages/ur.js +131 -0
  201. package/lib/{i18n → languages}/vi.d.ts +15 -13
  202. package/lib/languages/vi.js +147 -0
  203. package/lib/languages/zh-Hans.d.ts +21 -0
  204. package/lib/languages/zh-Hans.js +111 -0
  205. package/lib/languages/zh-Hant.d.ts +21 -0
  206. package/lib/languages/zh-Hant.js +111 -0
  207. package/lib/n2words.d.ts +207 -7
  208. package/lib/n2words.js +535 -81
  209. package/package.json +126 -79
  210. package/dist/ar.js +0 -2
  211. package/dist/ar.js.map +0 -1
  212. package/dist/az.js +0 -2
  213. package/dist/az.js.map +0 -1
  214. package/dist/cz.js +0 -2
  215. package/dist/cz.js.map +0 -1
  216. package/dist/de.js +0 -2
  217. package/dist/de.js.map +0 -1
  218. package/dist/dk.js +0 -2
  219. package/dist/dk.js.map +0 -1
  220. package/dist/en.js +0 -2
  221. package/dist/en.js.map +0 -1
  222. package/dist/es.js +0 -2
  223. package/dist/es.js.map +0 -1
  224. package/dist/fa.js +0 -2
  225. package/dist/fa.js.map +0 -1
  226. package/dist/fr-BE.js +0 -2
  227. package/dist/fr-BE.js.map +0 -1
  228. package/dist/fr.js +0 -2
  229. package/dist/fr.js.map +0 -1
  230. package/dist/he.js +0 -2
  231. package/dist/he.js.map +0 -1
  232. package/dist/hr.js +0 -2
  233. package/dist/hr.js.map +0 -1
  234. package/dist/hu.js +0 -2
  235. package/dist/hu.js.map +0 -1
  236. package/dist/id.js +0 -2
  237. package/dist/id.js.map +0 -1
  238. package/dist/it.js +0 -2
  239. package/dist/it.js.map +0 -1
  240. package/dist/ko.js +0 -2
  241. package/dist/ko.js.map +0 -1
  242. package/dist/lt.js +0 -2
  243. package/dist/lt.js.map +0 -1
  244. package/dist/lv.js +0 -2
  245. package/dist/lv.js.map +0 -1
  246. package/dist/n2words.d.ts +0 -2
  247. package/dist/nl.js +0 -2
  248. package/dist/nl.js.map +0 -1
  249. package/dist/no.js +0 -2
  250. package/dist/no.js.map +0 -1
  251. package/dist/pl.js +0 -2
  252. package/dist/pl.js.map +0 -1
  253. package/dist/pt.js +0 -2
  254. package/dist/pt.js.map +0 -1
  255. package/dist/ro.js +0 -2
  256. package/dist/ro.js.map +0 -1
  257. package/dist/ru.js +0 -2
  258. package/dist/ru.js.map +0 -1
  259. package/dist/sr.js +0 -2
  260. package/dist/sr.js.map +0 -1
  261. package/dist/tr.js +0 -2
  262. package/dist/tr.js.map +0 -1
  263. package/dist/uk.js +0 -2
  264. package/dist/uk.js.map +0 -1
  265. package/dist/vi.js +0 -2
  266. package/dist/vi.js.map +0 -1
  267. package/dist/zh.js +0 -2
  268. package/dist/zh.js.map +0 -1
  269. package/lib/classes/base-language.d.ts +0 -58
  270. package/lib/classes/base-language.js +0 -172
  271. package/lib/i18n/ar.d.ts +0 -41
  272. package/lib/i18n/ar.js +0 -209
  273. package/lib/i18n/az.d.ts +0 -15
  274. package/lib/i18n/az.js +0 -66
  275. package/lib/i18n/cz.js +0 -135
  276. package/lib/i18n/de.d.ts +0 -17
  277. package/lib/i18n/de.js +0 -103
  278. package/lib/i18n/dk.d.ts +0 -14
  279. package/lib/i18n/dk.js +0 -110
  280. package/lib/i18n/en.d.ts +0 -22
  281. package/lib/i18n/en.js +0 -86
  282. package/lib/i18n/es.d.ts +0 -16
  283. package/lib/i18n/es.js +0 -110
  284. package/lib/i18n/fa.d.ts +0 -54
  285. package/lib/i18n/fa.js +0 -106
  286. package/lib/i18n/fr-BE.d.ts +0 -11
  287. package/lib/i18n/fr-BE.js +0 -20
  288. package/lib/i18n/fr.d.ts +0 -15
  289. package/lib/i18n/fr.js +0 -99
  290. package/lib/i18n/he.d.ts +0 -61
  291. package/lib/i18n/he.js +0 -132
  292. package/lib/i18n/hr.d.ts +0 -68
  293. package/lib/i18n/hr.js +0 -129
  294. package/lib/i18n/hu.d.ts +0 -17
  295. package/lib/i18n/hu.js +0 -135
  296. package/lib/i18n/id.d.ts +0 -43
  297. package/lib/i18n/id.js +0 -156
  298. package/lib/i18n/it.d.ts +0 -29
  299. package/lib/i18n/it.js +0 -137
  300. package/lib/i18n/ko.d.ts +0 -15
  301. package/lib/i18n/ko.js +0 -56
  302. package/lib/i18n/lt.js +0 -138
  303. package/lib/i18n/lv.d.ts +0 -57
  304. package/lib/i18n/lv.js +0 -120
  305. package/lib/i18n/nl.d.ts +0 -20
  306. package/lib/i18n/nl.js +0 -125
  307. package/lib/i18n/no.d.ts +0 -15
  308. package/lib/i18n/no.js +0 -77
  309. package/lib/i18n/pl.js +0 -126
  310. package/lib/i18n/pt.d.ts +0 -26
  311. package/lib/i18n/pt.js +0 -118
  312. package/lib/i18n/ro.d.ts +0 -109
  313. package/lib/i18n/ro.js +0 -360
  314. package/lib/i18n/ru.d.ts +0 -30
  315. package/lib/i18n/ru.js +0 -198
  316. package/lib/i18n/sr.d.ts +0 -56
  317. package/lib/i18n/sr.js +0 -127
  318. package/lib/i18n/tr.d.ts +0 -15
  319. package/lib/i18n/tr.js +0 -64
  320. package/lib/i18n/vi.js +0 -151
  321. package/lib/i18n/zh.d.ts +0 -18
  322. package/lib/i18n/zh.js +0 -78
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018-2024 Wael TELLAT
3
+ Copyright (c) 2018-2025 Wael TELLAT
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,94 +1,352 @@
1
1
  # n2words
2
2
 
3
- [![CI](https://github.com/forzagreen/n2words/actions/workflows/test.yml/badge.svg)](https://github.com/forzagreen/n2words/actions/workflows/test.yml)
4
- [![Coverage Status](https://coveralls.io/repos/github/forzagreen/n2words/badge.svg?branch=main)](https://coveralls.io/github/forzagreen/n2words?branch=main)
5
- [![npm](https://img.shields.io/npm/v/n2words.svg)](https://npmjs.com/package/n2words)
6
- [![npm](https://img.shields.io/npm/dw/n2words)](https://npmjs.com/package/n2words)
7
- [![jsDelivr](https://data.jsdelivr.com/v1/package/npm/n2words/badge)](https://www.jsdelivr.com/package/npm/n2words)
3
+ [![CI](https://github.com/forzagreen/n2words/actions/workflows/ci.yml/badge.svg)](https://github.com/forzagreen/n2words/actions/workflows/ci.yml)
4
+ [![Coverage](https://img.shields.io/coveralls/github/forzagreen/n2words)](https://coveralls.io/github/forzagreen/n2words)
5
+ [![npm version](https://img.shields.io/npm/v/n2words)](https://npmjs.com/package/n2words)
6
+ [![npm provenance](https://img.shields.io/badge/npm-provenance-blue)](https://www.npmjs.com/package/n2words)
7
+ [![Bundle size](https://img.shields.io/bundlephobia/minzip/n2words)](https://bundlephobia.com/package/n2words)
8
+ [![npm downloads](https://img.shields.io/npm/dw/n2words)](https://npmjs.com/package/n2words)
9
+ [![jsDelivr](https://img.shields.io/jsdelivr/npm/hm/n2words)](https://www.jsdelivr.com/package/npm/n2words)
8
10
 
9
- __n2words__ converts numerical numbers into written ones, supports [28 languages](https://github.com/forzagreen/n2words#supported-languages), and has zero dependencies.
11
+ **Convert numbers to words in 48 languages with zero dependencies.**
10
12
 
11
- ## Example
13
+ ## Why n2words?
12
14
 
13
- ```js
14
- n2words(123) // 'one hundred and twenty-three'
15
- n2words(-1.5) // 'minus one point five'
15
+ - **Maximum Language Coverage** — 48 languages including European, Asian, Middle Eastern, and regional variants
16
+ - **Zero Dependencies** Pure JavaScript with no external runtime dependencies
17
+ - **Universal Compatibility** — Works in Node.js, browsers (via CDN), and all modern bundlers
18
+ - **Type-Safe** — Full TypeScript support with generated `.d.ts` declarations
19
+ - **Production Ready** — Comprehensive test coverage (unit, integration, browser, type checking)
20
+ - **BigInt Support** — Handle arbitrarily large numbers without precision loss
21
+ - **Flexible Input** — Accepts `number`, `bigint`, or `string` inputs
22
+ - **Tree-Shakable** — Import only the languages you need (~2-5 KB gzipped per language)
23
+ - **Browser Tested** — Verified in Chromium, Firefox, and WebKit via automated tests
16
24
 
17
- n2words(123, {lang: 'fr'}) // 'cent vingt-trois'
18
- n2words(123, {lang: 'es'}) // 'ciento veintitrés'
19
- n2words(123, {lang: 'ar'}) // 'مائة وثلاثة وعشرون'
20
- ```
25
+ ## Contents
21
26
 
22
- See the [Wiki](https://github.com/forzagreen/n2words/wiki) for examples and advanced usage like [importing only specific languages](https://github.com/forzagreen/n2words/wiki/Importing-only-specific-languages).
27
+ - [Quick Start](#quick-start)
28
+ - [Usage](#usage) — ESM, CommonJS, Browser (UMD)
29
+ - [Type Safety](#type-safety) — TypeScript support
30
+ - [Supported Languages](#supported-languages-48) — 48 languages with options
31
+ - [Browser Compatibility](#browser-compatibility) — Chrome 67+, Firefox 68+, Safari 14+, Edge 79+
32
+ - [Performance & Bundle Size](#performance--bundle-size) — Tree-shaking and benchmarks
33
+ - [Examples](#examples) — Basic, gender agreement, language-specific features
34
+ - [Documentation](#documentation) — Guides and API reference
35
+ - [Contributing](#contributing) — How to contribute
36
+ - [License](#license)
23
37
 
24
- ## Install
38
+ ## Quick Start
25
39
 
26
- ```sh
40
+ ```bash
27
41
  npm install n2words
28
42
  ```
29
43
 
44
+ ```js
45
+ import { EnglishConverter, SpanishConverter, ArabicConverter } from 'n2words'
46
+
47
+ EnglishConverter(123) // 'one hundred and twenty-three'
48
+ SpanishConverter(123) // 'ciento veintitrés'
49
+ ArabicConverter(1, { gender: 'feminine' }) // 'واحدة' (with options)
50
+ ```
51
+
30
52
  ## Usage
31
53
 
32
- ### ESM
54
+ **ESM (Node.js, modern bundlers):**
33
55
 
34
56
  ```js
35
- import n2words from 'n2words'
57
+ import { EnglishConverter } from 'n2words'
36
58
  ```
37
59
 
38
- ### CommonJS ([dynamic import](https://nodejs.org/api/esm.html#import-expressions))
60
+ **CommonJS (Node.js):**
61
+
62
+ n2words is an ES module. For CommonJS environments, use dynamic import with Promises:
39
63
 
40
64
  ```js
41
- import('n2words').then(({default: n2words}) => {
42
- n2words(100)
65
+ // Promise-based
66
+ import('n2words').then(({ EnglishConverter }) => {
67
+ console.log(EnglishConverter(42)) // 'forty-two'
43
68
  })
69
+
70
+ // Or use async function
71
+ async function convertNumber(num) {
72
+ const { EnglishConverter } = await import('n2words')
73
+ return EnglishConverter(num)
74
+ }
44
75
  ```
45
76
 
46
- ### Browser
77
+ **Browser (UMD via CDN):**
47
78
 
48
79
  ```html
49
- <script src="./n2words.js"></script>
80
+ <!-- All languages (~23KB gzipped) -->
81
+ <script src="https://cdn.jsdelivr.net/npm/n2words/dist/n2words.js"></script>
82
+ <script>
83
+ n2words.EnglishConverter(42) // 'forty-two'
84
+ </script>
85
+
86
+ <!-- Individual languages (~2KB gzipped each) - load only what you need -->
87
+ <script src="https://cdn.jsdelivr.net/npm/n2words/dist/EnglishConverter.js"></script>
88
+ <script src="https://cdn.jsdelivr.net/npm/n2words/dist/SpanishConverter.js"></script>
50
89
  <script>
51
- n2words(100)
90
+ n2words.EnglishConverter(42) // 'forty-two'
91
+ n2words.SpanishConverter(123) // 'ciento veintitrés'
52
92
  </script>
53
93
  ```
54
94
 
55
- n2words is also available on [jsDelivr](https://www.jsdelivr.com/package/npm/n2words).
56
-
57
- ## Supported Languages
58
-
59
- - `en` (English, default)
60
- - `ar` (Arabic)
61
- - `az` (Azerbaijani)
62
- - `cz` (Czech)
63
- - `dk` (Danish)
64
- - `de` (German)
65
- - `es` (Spanish)
66
- - `fr` (French)
67
- - `fr-BE` (French (Belgium))
68
- - `fa` (Farsi)
69
- - `he` (Hebrew)
70
- - `hr` (Croatian)
71
- - `hu` (Hungarian)
72
- - `id` (Indonesian)
73
- - `it` (Italian)
74
- - `ko` (Korean)
75
- - `lt` (Lithuanian)
76
- - `lv` (Latvian)
77
- - `nl` (Dutch)
78
- - `no` (Norwegian)
79
- - `pl` (Polish)
80
- - `pt` (Portuguese)
81
- - `ru` (Russian)
82
- - `sr` (Serbian)
83
- - `tr` (Turkish)
84
- - `uk` (Ukrainian)
85
- - `vi` (Vietnamese)
86
- - `zh` (Chinese)
95
+ ## Type Safety
96
+
97
+ Full TypeScript support via JSDoc annotations and generated type definitions - works in both JavaScript and TypeScript projects with IntelliSense and type checking:
98
+
99
+ ```typescript
100
+ import { EnglishConverter, ArabicConverter, SimplifiedChineseConverter } from 'n2words'
101
+ import type { NumericValue, ArabicOptions } from 'n2words'
102
+
103
+ // All converters accept: number | bigint | string
104
+ EnglishConverter(42) // number → 'forty-two'
105
+ EnglishConverter('123') // string → 'one hundred and twenty-three'
106
+ EnglishConverter(100n) // BigInt → 'one hundred'
107
+
108
+ // Language-specific options with type checking
109
+ ArabicConverter(1, { gender: 'feminine' }) // ✓ 'واحدة' (feminine form)
110
+ ArabicConverter(1, { invalid: true }) // ✗ TypeScript error: invalid property
111
+
112
+ SimplifiedChineseConverter(123, { formal: false }) // ✓ '一百二十三' (common style)
113
+ SimplifiedChineseConverter(123, { formal: 'yes' }) // ✗ TypeScript error: wrong type
114
+ ```
115
+
116
+ **Type Definitions:**
117
+
118
+ n2words includes TypeScript declaration files (`.d.ts`) generated from JSDoc annotations:
119
+
120
+ - **Source**: JSDoc annotations in JavaScript source files
121
+ - **Generated**: TypeScript declarations built via `tsc` during package preparation
122
+ - **Included**: Published to npm with the package (no separate `@types` package needed)
123
+ - **Validated**: Comprehensive type tests ensure correctness
124
+
125
+ **Exported Types:**
126
+
127
+ - `NumericValue` - Accepted input types: `number | bigint | string`
128
+ - Language-specific option types (e.g., `ArabicOptions`, `SimplifiedChineseOptions`, `DutchOptions`, etc.)
129
+
130
+ ## Supported Languages (48)
131
+
132
+ Language codes follow [IETF BCP 47](https://tools.ietf.org/html/bcp47) standards.
133
+
134
+ | Code | Language | Options | Code | Language | Options |
135
+ | --------- | ------------------- | ------- | --------- | ------------------- | ------- |
136
+ | `ar` | Arabic | ✓ | `az` | Azerbaijani | |
137
+ | `bn` | Bengali | | `cs` | Czech | ✓ |
138
+ | `da` | Danish | ✓ | `de` | German | |
139
+ | `el` | Greek | | `en` | English | |
140
+ | `es` | Spanish | ✓ | `fa` | Persian | |
141
+ | `fil` | Filipino | | `fr` | French | ✓ |
142
+ | `fr-BE` | Belgian French | ✓ | `gu` | Gujarati | |
143
+ | `hbo` | Biblical Hebrew | ✓ | `he` | Modern Hebrew | ✓ |
144
+ | `hi` | Hindi | | `hr` | Croatian | ✓ |
145
+ | `hu` | Hungarian | | `id` | Indonesian | |
146
+ | `it` | Italian | | `ja` | Japanese | |
147
+ | `kn` | Kannada | | `ko` | Korean | |
148
+ | `lt` | Lithuanian | ✓ | `lv` | Latvian | ✓ |
149
+ | `mr` | Marathi | | `ms` | Malay | |
150
+ | `nb` | Norwegian Bokmål | | `nl` | Dutch | ✓ |
151
+ | `pa` | Punjabi | | `pl` | Polish | ✓ |
152
+ | `pt` | Portuguese | | `ro` | Romanian | ✓ |
153
+ | `ru` | Russian | ✓ | `sr-Cyrl` | Serbian Cyrillic | ✓ |
154
+ | `sr-Latn` | Serbian Latin | ✓ | `sv` | Swedish | |
155
+ | `sw` | Swahili | | `ta` | Tamil | |
156
+ | `te` | Telugu | | `th` | Thai | |
157
+ | `tr` | Turkish | ✓ | `uk` | Ukrainian | ✓ |
158
+ | `ur` | Urdu | | `vi` | Vietnamese | |
159
+ | `zh-Hans` | Chinese Simplified | ✓ | `zh-Hant` | Chinese Traditional | ✓ |
160
+
161
+ ### Language Options
162
+
163
+ 21 languages support additional options. Common options include:
164
+
165
+ **`gender`** (`'masculine'` | `'feminine'`) - 13 languages
166
+ Arabic, Biblical Hebrew, Croatian, Czech, Latvian, Lithuanian, Polish, Romanian, Russian, Serbian (both scripts), Spanish, Ukrainian
167
+
168
+ **`formal`** (`boolean`) - 2 languages
169
+ Simplified Chinese, Traditional Chinese - Toggle between formal/financial and common numerals
170
+
171
+ **Other options:**
172
+
173
+ - Dutch: `includeOptionalAnd`, `accentOne`, `noHundredPairing`
174
+ - French/French Belgium: `withHyphenSeparator`
175
+ - Hebrew (Modern & Biblical): `andWord`
176
+ - Turkish: `dropSpaces`
177
+ - Danish: `ordFlag` (ordinal numbers)
178
+ - Arabic: `negativeWord` (custom negative word)
179
+
180
+ [See complete options reference →](docs/ARCHITECTURE.md#language-specific-options)
181
+
182
+ ## Browser Compatibility
183
+
184
+ **Minimum Requirements** (due to BigInt):
185
+
186
+ - **Node.js**: 20 or above
187
+ - **Browsers**: Chrome 67+, Firefox 68+, Safari 14+, Edge 79+ (desktop + mobile)
188
+ - **Global Coverage**: ~86% of all users worldwide
189
+
190
+ **Note**: BigInt is a hard requirement and cannot be polyfilled. Older browsers are not supported.
191
+
192
+ **Build options:**
193
+
194
+ - **Browser CDN**: Use `dist/n2words.js` (pre-built UMD, tested in real browsers)
195
+ - **Node.js/Bundlers**: Use `lib/` source (ES modules, tree-shakable)
196
+
197
+ [See detailed compatibility guide →](COMPATIBILITY.md)
198
+
199
+ ## Performance & Bundle Size
200
+
201
+ ### Bundle Size Comparison
202
+
203
+ | Import Strategy | Bundle Size (Minified) | Gzipped | Languages Included |
204
+ | ---------------------------- | ---------------------- | -------- | ------------------ |
205
+ | All languages (UMD) | ~92 KB | ~23 KB | All 48 |
206
+ | Single language (UMD) | ~4-6 KB | ~2 KB | 1 |
207
+ | Tree-shaken (ESM, 1 lang) | ~4-5 KB | ~2 KB | 1 |
208
+ | Tree-shaken (ESM, 3 langs) | ~12-15 KB | ~4-5 KB | 3 |
209
+ | Tree-shaken (ESM, 10 langs) | ~40-50 KB | ~12-15 KB| 10 |
210
+
211
+ ### Performance Characteristics
212
+
213
+ - **Fast**: Sub-millisecond conversion for most numbers
214
+ - **Efficient**: Zero dependencies, minimal memory footprint
215
+ - **BigInt support**: Handles arbitrarily large numbers without precision loss
216
+ - **Memory-efficient**: ~2 KB overhead per language when tree-shaken
217
+
218
+ **Tree-shaking example:**
219
+
220
+ ```js
221
+ // Import only what you need - bundler only includes used languages
222
+ import { EnglishConverter, SpanishConverter } from 'n2words'
223
+ // Final bundle: ~4-5 KB gzipped (only English + Spanish + core)
224
+ ```
225
+
226
+ **Run benchmarks:**
227
+
228
+ ```bash
229
+ npm run bench:perf # Performance benchmarks (ops/sec)
230
+ npm run bench:memory # Memory usage benchmarks
231
+ ```
232
+
233
+ ## Examples
234
+
235
+ ### Basic Conversions
236
+
237
+ ```js
238
+ import { EnglishConverter } from 'n2words'
239
+
240
+ // Basic numbers
241
+ EnglishConverter(0) // 'zero'
242
+ EnglishConverter(42) // 'forty-two'
243
+ EnglishConverter(1000000) // 'one million'
244
+
245
+ // Decimals & negatives
246
+ EnglishConverter(3.14) // 'three point one four'
247
+ EnglishConverter(-42) // 'minus forty-two'
248
+
249
+ // Large numbers & BigInt
250
+ EnglishConverter(1234567890) // 'one billion two hundred and thirty-four million five hundred and sixty-seven thousand eight hundred and ninety'
251
+ EnglishConverter(123456789012345n) // Works with arbitrarily large integers
252
+ ```
253
+
254
+ ### Gender Agreement
255
+
256
+ ```js
257
+ import { SpanishConverter, ArabicConverter, RussianConverter } from 'n2words'
258
+
259
+ // Spanish: masculine vs feminine
260
+ SpanishConverter(1) // 'uno' (masculine, default)
261
+ SpanishConverter(1, { gender: 'feminine' }) // 'una'
262
+ SpanishConverter(21) // 'veintiuno' (masculine)
263
+ SpanishConverter(21, { gender: 'feminine' }) // 'veintiuna'
264
+
265
+ // Arabic: rich gender system
266
+ ArabicConverter(1) // 'واحد' (masculine, default)
267
+ ArabicConverter(1, { gender: 'feminine' }) // 'واحدة'
268
+
269
+ // Russian: gender for numerals
270
+ RussianConverter(1) // 'один' (masculine, default)
271
+ RussianConverter(1, { gender: 'feminine' }) // 'одна'
272
+ ```
273
+
274
+ ### Language-Specific Features
275
+
276
+ ```js
277
+ import {
278
+ SimplifiedChineseConverter,
279
+ TraditionalChineseConverter,
280
+ JapaneseConverter,
281
+ DutchConverter,
282
+ FrenchConverter
283
+ } from 'n2words'
284
+
285
+ // Chinese: formal (financial) vs common numerals
286
+ SimplifiedChineseConverter(123) // '壹佰贰拾叁' (formal, default)
287
+ SimplifiedChineseConverter(123, { formal: false }) // '一百二十三' (common)
288
+
289
+ TraditionalChineseConverter(456) // '肆佰伍拾陸' (formal, default)
290
+ TraditionalChineseConverter(456, { formal: false }) // '四百五十六' (common)
291
+
292
+ // Japanese: digit-by-digit decimals
293
+ JapaneseConverter(3.14) // '三点一四'
294
+
295
+ // Dutch: flexible formatting
296
+ DutchConverter(123) // 'honderddrieëntwintig' (default compound)
297
+ DutchConverter(101, { includeOptionalAnd: true }) // 'honderdeneen' (with optional "en")
298
+ DutchConverter(1) // 'één' (accented, default)
299
+ DutchConverter(1, { accentOne: false }) // 'een' (unaccented)
300
+
301
+ // French: selective hyphens vs all hyphens
302
+ FrenchConverter(123) // 'cent vingt-trois' (default)
303
+ FrenchConverter(123, { withHyphenSeparator: true }) // 'cent-vingt-trois' (all hyphens)
304
+ ```
305
+
306
+ ### Input Flexibility
307
+
308
+ ```js
309
+ import { EnglishConverter } from 'n2words'
310
+
311
+ // Multiple input types
312
+ EnglishConverter(42) // number → 'forty-two'
313
+ EnglishConverter('42') // string → 'forty-two'
314
+ EnglishConverter(42n) // BigInt → 'forty-two'
315
+
316
+ // Decimal strings
317
+ EnglishConverter('3.14') // 'three point one four'
318
+ EnglishConverter('.5') // 'zero point five'
319
+
320
+ // Negative strings
321
+ EnglishConverter('-42') // 'minus forty-two'
322
+
323
+ // Large BigInts (no precision loss)
324
+ EnglishConverter(999999999999999999999999n) // Accurate conversion
325
+ ```
326
+
327
+ ## Documentation
328
+
329
+ - **[Compatibility Guide](COMPATIBILITY.md)** - Browser and Node.js compatibility
330
+ - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute and add languages
331
+ - **[Architecture Guide](docs/ARCHITECTURE.md)** - Implementation patterns and options reference
332
+ - **[Code of Conduct](CODE_OF_CONDUCT.md)** - Community standards
87
333
 
88
334
  ## Contributing
89
335
 
90
- __This library is in active development.__ We want to improve the design and process for language contributors and add more languages. Bug reports and feature requests are also beneficial!
336
+ We welcome contributions! Add a new language or improve existing ones:
337
+
338
+ ```bash
339
+ npm run lang:add <code> # Scaffold a new language (BCP 47 code)
340
+ npm run lang:validate -- <code> # Validate implementation
341
+ npm test # Run full test suite
342
+ ```
343
+
344
+ Also welcome: bug reports, feature requests, documentation improvements, and language enhancements.
345
+
346
+ Please read our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
347
+
348
+ **[See full contributing guide →](CONTRIBUTING.md)**
91
349
 
92
350
  ## License
93
351
 
94
- [MIT](https://github.com/forzagreen/n2words/blob/main/LICENSE)
352
+ [MIT](./LICENSE) © Wael TELLAT, Tyler Vigario & contributors
@@ -0,0 +1,3 @@
1
+ /*! n2words/ArabicConverter v2.0.0 | MIT License | github.com/forzagreen/n2words */
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).n2words=e.n2words||{})}(this,function(e){"use strict";class t{#e={};negativeWord="";decimalSeparatorWord="";zeroWord="";wordSeparator=" ";usePerDigitDecimals=!1;get options(){return this.#e}toWords(e,t,r){const s=[];return e&&s.push(this.negativeWord),s.push(this.integerToWords(t)),r&&(s.push(this.decimalSeparatorWord),s.push(...this.decimalDigitsToWords(r))),s.join(this.wordSeparator)}integerToWords(e){throw new Error("integerToWords() must be implemented by subclass")}setOptions(e={},t={}){this.#e={...e,...t}}decimalIntegerToWords(e){return this.integerToWords(e)}decimalDigitsToWords(e){const t=[];let r=0;for(;r<e.length&&"0"===e[r];)t.push(this.zeroWord),r++;const s=e.slice(r);if(!s)return t;if(this.usePerDigitDecimals)for(const e of s)t.push(this.decimalIntegerToWords(BigInt(e)));else t.push(this.decimalIntegerToWords(BigInt(s)));return t}}function r(e){const[t,r]=e.toLowerCase().split("e"),s=parseInt(r,10),n=t.indexOf("."),i=-1===n?t:t.slice(0,n)+t.slice(n+1),o=(-1===n?t.length:n)+s;return o>=i.length?i+"0".repeat(o-i.length):o<=0?"0."+"0".repeat(-o)+i:i.slice(0,o)+"."+i.slice(o)}const s=(n=class extends t{negativeWord="ناقص";decimalSeparatorWord="فاصلة";zeroWord="صفر";tensWords=["عشرون","ثلاثون","أربعون","خمسون","ستون","سبعون","ثمانون","تسعون"];hundredsWords=["","مائة","مئتان","ثلاثمائة","أربعمائة","خمسمائة","ستمائة","سبعمائة","ثمانمائة","تسعمائة"];scaleWords=["مائة","ألف","مليون","مليار","تريليون","كوادريليون","كوينتليون","سكستيليون"];scaleAppendedWords=["","ألفاً","مليوناً","ملياراً","تريليوناً","كوادريليوناً","كوينتليوناً","سكستيليوناً"];scalePluralWords=["","آلاف","ملايين","مليارات","تريليونات","كوادريليونات","كوينتليونات","سكستيليونات"];dualWords=["مئتان","ألفان","مليونان","ملياران","تريليونان","كوادريليونان","كوينتليونان","سكستيليونان"];dualAppendedWords=["مئتا","ألفا","مليونا","مليارا","تريليونا","كوادريليونا","كوينتليونا","سكستيليونا"];ones={masculine:["واحد","اثنان","ثلاثة","أربعة","خمسة","ستة","سبعة","ثمانية","تسعة","عشرة","أحد عشر","اثنا عشر","ثلاثة عشر","أربعة عشر","خمسة عشر","ستة عشر","سبعة عشر","ثمانية عشر","تسعة عشر"],feminine:["واحدة","اثنتان","ثلاث","أربع","خمس","ست","سبع","ثمان","تسع","عشر","إحدى عشرة","اثنتا عشرة","ثلاث عشرة","أربع عشرة","خمس عشرة","ست عشرة","سبع عشرة","ثماني عشرة","تسع عشرة"]};constructor(e={}){super(),this.setOptions({gender:"masculine"},e),void 0!==e.negativeWord&&(this.negativeWord=e.negativeWord)}get selectedOnes(){return this.ones["feminine"===this.options.gender?"feminine":"masculine"]}segmentToWords(e,t,r){const s=e%100,n=e/100,i=Math.trunc(n);let o="";if(i>0)if(0===s&&2===i)o=this.dualWords[0];else{const e=this.hundredsWords[i];e&&(o=e,0!==s&&(o+=" و"))}if(s>0)if(s<20)if(2===s&&0===i&&t>0){const s=Number(r),n=Math.trunc(Math.log10(s));o=n%3==0&&r===BigInt(2*Math.pow(10,n))?2===e?this.dualWords[t]:this.dualAppendedWords[t]:this.dualWords[t]}else o+=1===s&&t>0?this.scaleWords[t]:this.selectedOnes[s-1];else{const e=s%10,t=Math.trunc(s/10)-2;e>0&&(o+=this.selectedOnes[e-1],o+=" و"),o+=this.tensWords[t]}return o}integerToWords(e){if(0n===e)return this.zeroWord;let t=e,r=0,s="";for(;t>0n;){const n=Number(t%1000n);if(t/=1000n,n>0){const t=this.segmentToWords(n,r,e);t&&(r>0&&(s&&(s=" و"+s),n>2)&&(s=1==n%100?this.scaleWords[r]+" "+s:n>=3&&n<=10?this.scalePluralWords[r]+" "+s:(s?this.scaleAppendedWords[r]:this.scaleWords[r])+" "+s),s=t+" "+s)}r++}return s.replace(/\s+/g," ").trim()}},function(e,t){if(void 0!==t&&!function(e){if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(t))throw new TypeError("options must be a plain object if provided");const{isNegative:s,integerPart:i,decimalPart:o}=function(e){const t=typeof e;if("bigint"===t)return e<0n?{isNegative:!0,integerPart:-e}:{isNegative:!1,integerPart:e};if("number"!==t&&"string"!==t)throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`);const s="number"===t?function(e){if(!Number.isFinite(e))throw new Error("Number must be finite (NaN and Infinity are not supported)");const t=e.toString();return t.includes("e")||t.includes("E")?r(t):t}(e):function(e){const t=e.trim();if(0===t.length)throw new Error(`Invalid number format: "${e}"`);if(Number.isNaN(Number(t)))throw new Error(`Invalid number format: "${e}"`);return t.includes("e")||t.includes("E")?r(t):t}(e);return function(e){const t="-"===e[0];t&&(e=e.slice(1));const r=e.indexOf(".");if(-1===r)return{isNegative:t,integerPart:BigInt(e)};const s=e.slice(0,r)||"0",n=e.slice(r+1);return{isNegative:t,integerPart:BigInt(s),decimalPart:n}}(s)}(e);return new n(t).toWords(s,i,o)});var n;e.ArabicConverter=s});
3
+ //# sourceMappingURL=ArabicConverter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArabicConverter.js","sources":["../lib/classes/abstract-language.js","../lib/n2words.js","../lib/languages/ar.js"],"sourcesContent":["/**\n * Abstract base class for language converters.\n *\n * This class provides the framework for converting numbers to words in any language.\n * It handles the common conversion flow while delegating language-specific logic to subclasses.\n *\n * ## Responsibilities\n *\n * - Receives pre-validated and normalized input from the public API (n2words.js)\n * - Handles negative number prefixing via `negativeWord`\n * - Converts decimals via `decimalDigitsToWords()`, preserving leading zeros\n * - Delegates integer conversion to `integerToWords()` (implemented by subclasses)\n *\n * ## Required Subclass Implementation\n *\n * Subclasses MUST provide:\n * - `integerToWords(integerPart)` - Core conversion logic (abstract method)\n * - `negativeWord` - Word preceding negative numbers (e.g., \"minus\"))\n * - `zeroWord` - Word for the digit 0 (e.g., \"zero\")\n * - `decimalSeparatorWord` - Word between whole and decimal parts (e.g., \"point\")\n *\n * ## Optional Overrides\n *\n * Subclasses MAY override:\n * - `wordSeparator` - Character(s) between words (default: space, empty for CJK languages)\n * - `usePerDigitDecimals` - Enable per-digit decimal mode (default: false)\n * - `decimalIntegerToWords()` - Custom decimal conversion (e.g., Romanian masculine forms)\n * - `decimalDigitsToWords()` - Complete decimal conversion override\n * - `toWords()` - Override to capture integerPart for context-dependent rules (e.g., Czech)\n *\n * ## Input Contract\n *\n * Input validation and normalization happen at the public API boundary (n2words.js).\n * This class assumes it receives clean, pre-processed data via `toWords()`.\n *\n * @abstract\n */\nexport class AbstractLanguage {\n // ============================================================================\n // Private Fields\n // ============================================================================\n\n /**\n * Private storage for options.\n * @type {Object}\n */\n #options = {}\n\n // ============================================================================\n // Required Properties (subclasses must define)\n // ============================================================================\n\n /**\n * Word that precedes negative numbers (e.g., \"minus\", \"negative\", \"moins\").\n * @type {string}\n */\n negativeWord = ''\n\n /**\n * Word that separates integer and decimal parts (e.g., \"point\", \"virgule\", \"comma\").\n * @type {string}\n */\n decimalSeparatorWord = ''\n\n /**\n * Word representation for the digit 0 (e.g., \"zero\", \"zéro\", \"null\").\n * Used for zero values and leading zeros in decimals.\n * @type {string}\n */\n zeroWord = ''\n\n // ============================================================================\n // Optional Properties (subclasses may override)\n // ============================================================================\n\n /**\n * Character(s) used to separate words in the output.\n *\n * Defaults to a single space. Set to empty string for languages without\n * word separators (e.g., Japanese, Thai, Chinese).\n *\n * @type {string}\n */\n wordSeparator = ' '\n\n /**\n * Whether to convert decimal digits individually rather than grouped.\n *\n * - `false` (default): Leading zeros preserved, remaining digits grouped as a number\n * - Example: \"05\" → [\"zero\", \"five\"], \"14\" → [\"fourteen\"]\n * - Used by: English, Spanish, French, German, etc.\n *\n * - `true`: Each digit converted separately\n * - Example: \"05\" → [\"zero\", \"five\"], \"14\" → [\"one\", \"four\"]\n * - Used by: Japanese, Thai, Tamil, Telugu, Greek, Hebrew, Filipino\n *\n * @type {boolean}\n */\n usePerDigitDecimals = false\n\n // ============================================================================\n // Public Accessors\n // ============================================================================\n\n /**\n * Read-only access to options set via `setOptions()`.\n * @type {Object}\n */\n get options () {\n return this.#options\n }\n\n // ============================================================================\n // Public Methods\n // ============================================================================\n\n /**\n * Converts pre-normalized numeric components to words.\n *\n * This is the main entry point called by the public API (makeConverter in n2words.js).\n * It assembles the final word representation from the provided components.\n *\n * **Caller contract (enforced by makeConverter):**\n * - `integerPart` is a non-negative BigInt (>= 0n)\n * - `decimalPart` is a string of digits only (no sign, no decimal point)\n * - `isNegative` reflects the original input sign\n *\n * **Conversion flow:**\n * 1. Prepend negative word if applicable\n * 2. Convert integer part via `integerToWords()`\n * 3. If decimals present: append separator and decimal words\n * 4. Join all parts with `wordSeparator`\n *\n * Subclasses needing access to the integer part during decimal conversion\n * (e.g., for context-dependent separator words) should override this\n * method to cache the value before calling super.toWords().\n *\n * @public\n * @param {boolean} isNegative Whether the original number was negative\n * @param {bigint} integerPart The integer part (always non-negative)\n * @param {string} [decimalPart] - Decimal digits if present (e.g., \"14\" for 3.14)\n * @returns {string} The localized cardinal string\n */\n toWords (isNegative, integerPart, decimalPart) {\n const words = []\n\n if (isNegative) words.push(this.negativeWord)\n\n words.push(this.integerToWords(integerPart))\n\n if (decimalPart) {\n words.push(this.decimalSeparatorWord)\n words.push(...this.decimalDigitsToWords(decimalPart))\n }\n\n return words.join(this.wordSeparator)\n }\n\n // ============================================================================\n // Abstract Methods (subclasses must implement)\n // ============================================================================\n\n /**\n * Converts a BigInt integer part to its cardinal word representation.\n *\n * This is the core template method that subclasses MUST implement to provide\n * language-specific number conversion logic.\n *\n * @abstract\n * @param {bigint} integerPart The integer part to convert (always >= 0n)\n * @returns {string} The cardinal representation in the target language\n * @throws {Error} If not implemented by subclass\n */\n integerToWords (integerPart) {\n throw new Error('integerToWords() must be implemented by subclass')\n }\n\n // ============================================================================\n // Protected Methods (subclasses may override or call)\n // ============================================================================\n\n /**\n * Sets options by merging language defaults with user-provided options.\n *\n * Merges defaults first, then user options (later keys override earlier ones).\n * Stores the result in the private `#options` field, accessible via the\n * read-only `options` getter.\n *\n * @protected\n * @param {Object} [defaults={}] - Default option values for the language\n * @param {Object} [userOptions={}] - Runtime options supplied by the caller\n *\n * @example\n * constructor(options = {}) {\n * super()\n * this.setOptions({ gender: 'masculine' }, options)\n * }\n */\n setOptions (defaults = {}, userOptions = {}) {\n this.#options = {\n ...defaults,\n ...userOptions\n }\n }\n\n /**\n * Converts an integer to words in decimal context.\n *\n * By default, delegates to `integerToWords()`. Override this method\n * when decimal conversion requires different behavior than integer conversion.\n *\n * Called with:\n * - Single digits (0-9) when `usePerDigitDecimals = true`\n * - Grouped numbers when `usePerDigitDecimals = false`\n *\n * **Use cases for overriding:**\n * - Romanian: Decimals always use masculine forms regardless of gender option\n * - Languages with different plural/gender rules for decimal vs integer parts\n *\n * @protected\n * @param {bigint} integerPart The integer to convert (single digit or grouped)\n * @returns {string} The word representation for use in decimal context\n */\n decimalIntegerToWords (integerPart) {\n return this.integerToWords(integerPart)\n }\n\n /**\n * Converts decimal fractional digits into an array of words.\n *\n * Leading zeros are always preserved individually. The remaining digits\n * are converted based on `usePerDigitDecimals`:\n *\n * - `false` (default): Remaining digits grouped as a single number\n * - \"05\" → [\"zero\", \"five\"], \"14\" → [\"fourteen\"]\n *\n * - `true`: Each remaining digit converted separately\n * - \"05\" → [\"zero\", \"five\"], \"14\" → [\"one\", \"four\"]\n *\n * @protected\n * @param {string} decimalPart Decimal digits as string (e.g., \"05\" for 3.05)\n * @returns {string[]} Array of word tokens for the fractional part\n */\n decimalDigitsToWords (decimalPart) {\n const words = []\n\n // Always preserve leading zeros individually\n let i = 0\n while (i < decimalPart.length && decimalPart[i] === '0') {\n words.push(this.zeroWord)\n i++\n }\n\n const remainder = decimalPart.slice(i)\n if (!remainder) return words\n\n // Convert remainder: per-digit or as single number\n if (this.usePerDigitDecimals) {\n for (const char of remainder) {\n words.push(this.decimalIntegerToWords(BigInt(char)))\n }\n } else {\n words.push(this.decimalIntegerToWords(BigInt(remainder)))\n }\n\n return words\n }\n}\n","/**\n * n2words - Convert numbers to words in multiple languages\n *\n * This file is the main entry point for the n2words library.\n * It exports converter functions for all supported languages.\n *\n * ## For Contributors\n *\n * When adding a new language, this file must be updated in THREE sections:\n * 1. Language Imports - Add import statement (alphabetically sorted)\n * 2. Language Converters - Create converter with makeConverter() (alphabetically sorted)\n * 3. Exports - Add to export list (alphabetically sorted)\n *\n * Use the scaffolding tool to automate this process:\n * npm run lang:add <language-code>\n *\n * ## Public API Structure\n *\n * Each language exports a converter function:\n * - Name: `{LanguageName}Converter` (e.g., EnglishConverter, SpanishConverter)\n * - Signature: `(value: NumericValue, options?: Options) => string`\n * - Input: number, bigint, or string (numeric strings only)\n * - Output: Words representing the number in the target language\n *\n * Languages without options use signature: `(value: NumericValue) => string`\n * Languages with options define a typedef (e.g., ArabicOptions) and use: `(value: NumericValue, options?: ArabicOptions) => string`\n *\n * @module n2words\n */\n\n// ============================================================================\n// Language Imports\n// ============================================================================\n\nimport { Arabic } from './languages/ar.js'\nimport { Azerbaijani } from './languages/az.js'\nimport { Bangla } from './languages/bn.js'\nimport { Czech } from './languages/cs.js'\nimport { Danish } from './languages/da.js'\nimport { German } from './languages/de.js'\nimport { Greek } from './languages/el.js'\nimport { English } from './languages/en.js'\nimport { Spanish } from './languages/es.js'\nimport { Persian } from './languages/fa.js'\nimport { Filipino } from './languages/fil.js'\nimport { French } from './languages/fr.js'\nimport { FrenchBelgium } from './languages/fr-BE.js'\nimport { Gujarati } from './languages/gu.js'\nimport { Hebrew } from './languages/he.js'\nimport { BiblicalHebrew } from './languages/hbo.js'\nimport { Hindi } from './languages/hi.js'\nimport { Croatian } from './languages/hr.js'\nimport { Hungarian } from './languages/hu.js'\nimport { Indonesian } from './languages/id.js'\nimport { Italian } from './languages/it.js'\nimport { Japanese } from './languages/ja.js'\nimport { Kannada } from './languages/kn.js'\nimport { Korean } from './languages/ko.js'\nimport { Lithuanian } from './languages/lt.js'\nimport { Latvian } from './languages/lv.js'\nimport { Marathi } from './languages/mr.js'\nimport { Malay } from './languages/ms.js'\nimport { Dutch } from './languages/nl.js'\nimport { NorwegianBokmal } from './languages/nb.js'\nimport { Punjabi } from './languages/pa.js'\nimport { Polish } from './languages/pl.js'\nimport { Portuguese } from './languages/pt.js'\nimport { Romanian } from './languages/ro.js'\nimport { Russian } from './languages/ru.js'\nimport { SerbianCyrillic } from './languages/sr-Cyrl.js'\nimport { SerbianLatin } from './languages/sr-Latn.js'\nimport { Swedish } from './languages/sv.js'\nimport { Swahili } from './languages/sw.js'\nimport { Tamil } from './languages/ta.js'\nimport { Telugu } from './languages/te.js'\nimport { Thai } from './languages/th.js'\nimport { Turkish } from './languages/tr.js'\nimport { Ukrainian } from './languages/uk.js'\nimport { Urdu } from './languages/ur.js'\nimport { Vietnamese } from './languages/vi.js'\nimport { SimplifiedChinese } from './languages/zh-Hans.js'\nimport { TraditionalChinese } from './languages/zh-Hant.js'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n//\n// This section defines TypeScript-compatible JSDoc types for:\n// - NumericValue: The input types accepted by all converters\n// - {Language}Options: Optional configuration for languages that support it\n//\n// Keep options typedefs alphabetically sorted for maintainability.\n// ============================================================================\n\n/**\n * Numeric value that can be converted to words.\n * Accepts number, bigint, or numeric string representations.\n * @typedef {number | bigint | string} NumericValue\n */\n\n/**\n * @typedef {Object} ArabicOptions\n * @property {string} [negativeWord] Word for negative numbers\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} BiblicalHebrewOptions\n * @property {string} [andWord='ו'] Conjunction character (typically 'ו' for and)\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} CroatianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} CzechOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} DanishOptions\n * @property {boolean} [ordFlag=false] Enable ordinal number conversion\n */\n\n/**\n * @typedef {Object} DutchOptions\n * @property {boolean} [includeOptionalAnd=false] Include optional \"en\" separator\n * @property {boolean} [noHundredPairing=false] Disable hundred-pairing (e.g., \"twelve hundred\" becomes \"one thousand two hundred\")\n * @property {boolean} [accentOne=true] Use accented \"één\" for one\n */\n\n/**\n * @typedef {Object} FrenchOptions\n * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds\n */\n\n/**\n * @typedef {Object} FrenchBelgiumOptions\n * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds\n */\n\n/**\n * @typedef {Object} HebrewOptions\n * @property {string} [andWord='ו'] Conjunction character (typically 'ו' for and)\n */\n\n/**\n * @typedef {Object} LatvianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} LithuanianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} PolishOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} RomanianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} RussianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} SerbianCyrillicOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} SerbianLatinOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} SimplifiedChineseOptions\n * @property {boolean} [formal=true] Use formal/financial numerals (壹贰叁) vs. common numerals (一二三)\n */\n\n/**\n * @typedef {Object} SpanishOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n/**\n * @typedef {Object} TraditionalChineseOptions\n * @property {boolean} [formal=true] Use formal/financial numerals (壹貳參) vs. common numerals (一二三)\n */\n\n/**\n * @typedef {Object} TurkishOptions\n * @property {boolean} [dropSpaces=false] Remove spaces between words if true\n */\n\n/**\n * @typedef {Object} UkrainianOptions\n * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms\n */\n\n// ============================================================================\n// Converter Factory\n// ============================================================================\n//\n// makeConverter() is a factory function that creates converter functions from\n// language classes. It provides a consistent functional API for all languages:\n//\n// const result = EnglishConverter(42) // \"forty-two\"\n// const result = ArabicConverter(1, {gender: 'feminine'}) // \"واحدة\"\n//\n// This design:\n// - Hides class instantiation details from public API\n// - Ensures each conversion uses a fresh instance\n// - Maintains immutability (no shared state between conversions)\n// ============================================================================\n\n/**\n * Creates a converter function for a language class.\n *\n * This factory handles all input validation and normalization at the public API\n * boundary, then delegates to the language class with pre-processed data.\n *\n * @template {Object} [TOptions={}]\n * @param {new (options?: TOptions) => { toWords: (isNegative: boolean, integerPart: bigint, decimalPart?: string) => string }} LanguageClass - Language class constructor\n * @returns {(value: NumericValue, options?: TOptions) => string} Converter function\n */\nfunction makeConverter (LanguageClass) {\n /**\n * @param {NumericValue} value\n * @param {TOptions} [options]\n * @returns {string}\n */\n return function convertToWords (value, options) {\n if (options !== undefined && !isPlainObject(options)) {\n throw new TypeError('options must be a plain object if provided')\n }\n\n const { isNegative, integerPart, decimalPart } = parseNumericValue(value)\n return new LanguageClass(options).toWords(isNegative, integerPart, decimalPart)\n }\n}\n\n// ============================================================================\n// Input Parsing Utilities\n// ============================================================================\n\n/**\n * @typedef {Object} ParsedNumericValue\n * @property {boolean} isNegative - Whether the value is negative\n * @property {bigint} integerPart - The absolute integer part\n * @property {string} [decimalPart] - The decimal digits (without the point)\n */\n\n/**\n * Parses and validates a numeric value into its components.\n * Handles number, string, and bigint inputs uniformly.\n *\n * @param {NumericValue} value The value to parse\n * @returns {ParsedNumericValue} The parsed components\n * @throws {TypeError} If value is not a valid numeric type\n * @throws {Error} If value is not a valid number format\n */\nfunction parseNumericValue (value) {\n const type = typeof value\n\n // BigInt: simplest case - no decimals, no scientific notation\n if (type === 'bigint') {\n return value < 0n\n ? { isNegative: true, integerPart: -value }\n : { isNegative: false, integerPart: value }\n }\n\n // Reject invalid types early\n if (type !== 'number' && type !== 'string') {\n throw new TypeError(\n `Invalid value type: expected number, string, or bigint, received ${type}`\n )\n }\n\n // Convert to normalized string\n const str = type === 'number'\n ? numberToString(value)\n : stringToNormalizedForm(value)\n\n return parseNumericString(str)\n}\n\n/**\n * Converts a JavaScript number to a decimal string.\n * Handles special cases: Infinity, NaN, and scientific notation.\n *\n * @param {number} value The number to convert\n * @returns {string} Decimal string representation\n * @throws {Error} If value is not finite\n */\nfunction numberToString (value) {\n if (!Number.isFinite(value)) {\n throw new Error('Number must be finite (NaN and Infinity are not supported)')\n }\n\n const str = value.toString()\n\n // Expand scientific notation (used for values >= 1e21 or < 1e-6)\n if (str.includes('e') || str.includes('E')) {\n return expandScientificNotation(str)\n }\n\n return str\n}\n\n/**\n * Validates and normalizes a string numeric input.\n *\n * @param {string} value The string to validate\n * @returns {string} Trimmed and validated string\n * @throws {Error} If string is empty or not a valid number format\n */\nfunction stringToNormalizedForm (value) {\n const trimmed = value.trim()\n\n if (trimmed.length === 0) {\n throw new Error(`Invalid number format: \"${value}\"`)\n }\n\n // Validate by attempting conversion (handles edge cases like \"1e21\", \"-.5\", etc.)\n if (Number.isNaN(Number(trimmed))) {\n throw new Error(`Invalid number format: \"${value}\"`)\n }\n\n // Expand scientific notation if present\n if (trimmed.includes('e') || trimmed.includes('E')) {\n return expandScientificNotation(trimmed)\n }\n\n return trimmed\n}\n\n/**\n * Parses a normalized numeric string into its components.\n *\n * @param {string} str A normalized decimal string (no scientific notation)\n * @returns {ParsedNumericValue} The parsed components\n */\nfunction parseNumericString (str) {\n // Extract sign\n const isNegative = str[0] === '-'\n if (isNegative) {\n str = str.slice(1)\n }\n\n // Split into integer and decimal parts\n const dotIndex = str.indexOf('.')\n if (dotIndex === -1) {\n return { isNegative, integerPart: BigInt(str) }\n }\n\n const integerStr = str.slice(0, dotIndex) || '0'\n const decimalPart = str.slice(dotIndex + 1)\n\n return { isNegative, integerPart: BigInt(integerStr), decimalPart }\n}\n\n/**\n * Expands scientific notation to decimal form.\n * JavaScript uses scientific notation for values >= 1e21 or < 1e-6.\n *\n * @param {string} str String possibly in scientific notation (e.g., \"1e+21\")\n * @returns {string} Decimal form (e.g., \"1000000000000000000000\")\n */\nfunction expandScientificNotation (str) {\n const [mantissa, expStr] = str.toLowerCase().split('e')\n const exp = parseInt(expStr, 10)\n\n // Extract digits and determine original decimal position\n const dotIndex = mantissa.indexOf('.')\n const digits = dotIndex === -1\n ? mantissa\n : mantissa.slice(0, dotIndex) + mantissa.slice(dotIndex + 1)\n const integerLength = dotIndex === -1 ? mantissa.length : dotIndex\n\n // Calculate new decimal position after applying exponent\n const newDotPosition = integerLength + exp\n\n if (newDotPosition >= digits.length) {\n // Pure integer: pad with trailing zeros\n return digits + '0'.repeat(newDotPosition - digits.length)\n }\n\n if (newDotPosition <= 0) {\n // Pure decimal: pad with leading zeros after decimal point\n return '0.' + '0'.repeat(-newDotPosition) + digits\n }\n\n // Mixed: insert decimal point at new position\n return digits.slice(0, newDotPosition) + '.' + digits.slice(newDotPosition)\n}\n\n/**\n * Checks if a value is a plain object (not null, array, or other object types).\n *\n * @param {*} value Value to check\n * @returns {boolean} True if value is a plain object\n */\nfunction isPlainObject (value) {\n if (value === null || typeof value !== 'object') return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n// ============================================================================\n// Language Converters\n// ============================================================================\n//\n// Each converter is created using makeConverter() with explicit type annotations.\n//\n// Pattern for languages WITHOUT options:\n// const LanguageConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Language))\n//\n// Pattern for languages WITH options:\n// const LanguageConverter = /** @type {(value: NumericValue, options?: LanguageOptions) => string} */ (makeConverter(Language))\n//\n// IMPORTANT: Keep converters alphabetically sorted by converter name.\n// ============================================================================\n\nconst ArabicConverter = /** @type {(value: NumericValue, options?: ArabicOptions) => string} */ (makeConverter(Arabic))\nconst AzerbaijaniConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Azerbaijani))\nconst BanglaConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Bangla))\nconst BiblicalHebrewConverter = /** @type {(value: NumericValue, options?: BiblicalHebrewOptions) => string} */ (makeConverter(BiblicalHebrew))\nconst CroatianConverter = /** @type {(value: NumericValue, options?: CroatianOptions) => string} */ (makeConverter(Croatian))\nconst CzechConverter = /** @type {(value: NumericValue, options?: CzechOptions) => string} */ (makeConverter(Czech))\nconst DanishConverter = /** @type {(value: NumericValue, options?: DanishOptions) => string} */ (makeConverter(Danish))\nconst DutchConverter = /** @type {(value: NumericValue, options?: DutchOptions) => string} */ (makeConverter(Dutch))\nconst EnglishConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(English))\nconst FilipinoConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Filipino))\nconst FrenchConverter = /** @type {(value: NumericValue, options?: FrenchOptions) => string} */ (makeConverter(French))\nconst FrenchBelgiumConverter = /** @type {(value: NumericValue, options?: FrenchBelgiumOptions) => string} */ (makeConverter(FrenchBelgium))\nconst GermanConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(German))\nconst GreekConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Greek))\nconst GujaratiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Gujarati))\nconst HebrewConverter = /** @type {(value: NumericValue, options?: HebrewOptions) => string} */ (makeConverter(Hebrew))\nconst HindiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Hindi))\nconst HungarianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Hungarian))\nconst IndonesianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Indonesian))\nconst ItalianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Italian))\nconst JapaneseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Japanese))\nconst KannadaConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Kannada))\nconst KoreanConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Korean))\nconst LatvianConverter = /** @type {(value: NumericValue, options?: LatvianOptions) => string} */ (makeConverter(Latvian))\nconst LithuanianConverter = /** @type {(value: NumericValue, options?: LithuanianOptions) => string} */ (makeConverter(Lithuanian))\nconst MalayConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Malay))\nconst MarathiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Marathi))\nconst NorwegianBokmalConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(NorwegianBokmal))\nconst PersianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Persian))\nconst PolishConverter = /** @type {(value: NumericValue, options?: PolishOptions) => string} */ (makeConverter(Polish))\nconst PortugueseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Portuguese))\nconst PunjabiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Punjabi))\nconst RomanianConverter = /** @type {(value: NumericValue, options?: RomanianOptions) => string} */ (makeConverter(Romanian))\nconst RussianConverter = /** @type {(value: NumericValue, options?: RussianOptions) => string} */ (makeConverter(Russian))\nconst SerbianCyrillicConverter = /** @type {(value: NumericValue, options?: SerbianCyrillicOptions) => string} */ (makeConverter(SerbianCyrillic))\nconst SerbianLatinConverter = /** @type {(value: NumericValue, options?: SerbianLatinOptions) => string} */ (makeConverter(SerbianLatin))\nconst SimplifiedChineseConverter = /** @type {(value: NumericValue, options?: SimplifiedChineseOptions) => string} */ (makeConverter(SimplifiedChinese))\nconst SpanishConverter = /** @type {(value: NumericValue, options?: SpanishOptions) => string} */ (makeConverter(Spanish))\nconst SwahiliConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Swahili))\nconst SwedishConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Swedish))\nconst TamilConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Tamil))\nconst TeluguConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Telugu))\nconst ThaiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Thai))\nconst TraditionalChineseConverter = /** @type {(value: NumericValue, options?: TraditionalChineseOptions) => string} */ (makeConverter(TraditionalChinese))\nconst TurkishConverter = /** @type {(value: NumericValue, options?: TurkishOptions) => string} */ (makeConverter(Turkish))\nconst UkrainianConverter = /** @type {(value: NumericValue, options?: UkrainianOptions) => string} */ (makeConverter(Ukrainian))\nconst UrduConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Urdu))\nconst VietnameseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Vietnamese))\n\n// ============================================================================\n// Exports\n// ============================================================================\n//\n// All converter functions are exported for public use.\n//\n// IMPORTANT: Keep exports alphabetically sorted for maintainability.\n// ============================================================================\n\nexport {\n ArabicConverter,\n AzerbaijaniConverter,\n BanglaConverter,\n BiblicalHebrewConverter,\n CroatianConverter,\n CzechConverter,\n DanishConverter,\n DutchConverter,\n EnglishConverter,\n FilipinoConverter,\n FrenchConverter,\n FrenchBelgiumConverter,\n GermanConverter,\n GreekConverter,\n GujaratiConverter,\n HebrewConverter,\n HindiConverter,\n HungarianConverter,\n IndonesianConverter,\n ItalianConverter,\n JapaneseConverter,\n KannadaConverter,\n KoreanConverter,\n LatvianConverter,\n LithuanianConverter,\n MalayConverter,\n MarathiConverter,\n NorwegianBokmalConverter,\n PersianConverter,\n PolishConverter,\n PortugueseConverter,\n PunjabiConverter,\n RomanianConverter,\n RussianConverter,\n SerbianCyrillicConverter,\n SerbianLatinConverter,\n SimplifiedChineseConverter,\n SpanishConverter,\n SwahiliConverter,\n SwedishConverter,\n TamilConverter,\n TeluguConverter,\n ThaiConverter,\n TraditionalChineseConverter,\n TurkishConverter,\n UkrainianConverter,\n UrduConverter,\n VietnameseConverter\n}\n","import { AbstractLanguage } from '../classes/abstract-language.js'\n\n/**\n * Arabic language converter.\n *\n * Supports:\n * - Gender agreement (masculine/feminine forms)\n * - Complex pluralization (singular/dual/plural)\n * - Traditional Arabic number naming conventions\n * - Right-to-left text orientation\n */\nexport class Arabic extends AbstractLanguage {\n negativeWord = 'ناقص'\n decimalSeparatorWord = 'فاصلة'\n zeroWord = 'صفر'\n\n tensWords = ['عشرون', 'ثلاثون', 'أربعون', 'خمسون', 'ستون', 'سبعون', 'ثمانون', 'تسعون']\n hundredsWords = ['', 'مائة', 'مئتان', 'ثلاثمائة', 'أربعمائة', 'خمسمائة', 'ستمائة', 'سبعمائة', 'ثمانمائة', 'تسعمائة']\n\n // Magnitude words with three forms: singular, appended (tanween), plural\n scaleWords = ['مائة', 'ألف', 'مليون', 'مليار', 'تريليون', 'كوادريليون', 'كوينتليون', 'سكستيليون']\n scaleAppendedWords = ['', 'ألفاً', 'مليوناً', 'ملياراً', 'تريليوناً', 'كوادريليوناً', 'كوينتليوناً', 'سكستيليوناً']\n scalePluralWords = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات']\n\n // Dual forms (Arabic has singular, dual, plural)\n dualWords = ['مئتان', 'ألفان', 'مليونان', 'ملياران', 'تريليونان', 'كوادريليونان', 'كوينتليونان', 'سكستيليونان']\n dualAppendedWords = ['مئتا', 'ألفا', 'مليونا', 'مليارا', 'تريليونا', 'كوادريليونا', 'كوينتليونا', 'سكستيليونا']\n\n // Gender-specific number words (1-19)\n ones = {\n masculine: [\n 'واحد', 'اثنان', 'ثلاثة', 'أربعة', 'خمسة', 'ستة', 'سبعة', 'ثمانية', 'تسعة', 'عشرة',\n 'أحد عشر', 'اثنا عشر', 'ثلاثة عشر', 'أربعة عشر', 'خمسة عشر', 'ستة عشر', 'سبعة عشر', 'ثمانية عشر', 'تسعة عشر'\n ],\n feminine: [\n 'واحدة', 'اثنتان', 'ثلاث', 'أربع', 'خمس', 'ست', 'سبع', 'ثمان', 'تسع', 'عشر',\n 'إحدى عشرة', 'اثنتا عشرة', 'ثلاث عشرة', 'أربع عشرة', 'خمس عشرة', 'ست عشرة', 'سبع عشرة', 'ثماني عشرة', 'تسع عشرة'\n ]\n }\n\n constructor (options = {}) {\n super()\n\n this.setOptions({\n gender: 'masculine'\n }, options)\n\n // Allow custom negativeWord via options\n if (options.negativeWord !== undefined) {\n this.negativeWord = options.negativeWord\n }\n }\n\n /** Selects masculine or feminine number forms based on options. */\n get selectedOnes () {\n return this.ones[this.options.gender === 'feminine' ? 'feminine' : 'masculine']\n }\n\n /** Converts a 3-digit segment (0-999) to Arabic words with gender/plural rules. */\n segmentToWords (groupNumber, groupLevel, fullNumber) {\n const tens = groupNumber % 100\n const hundredsRaw = groupNumber / 100\n const hundreds = Math.trunc(hundredsRaw)\n let returnValue = ''\n\n // Process hundreds\n if (hundreds > 0) {\n if (tens === 0 && hundreds === 2) {\n returnValue = this.dualWords[0]\n } else {\n const hundredsWord = this.hundredsWords[hundreds]\n if (hundredsWord) {\n returnValue = hundredsWord\n if (tens !== 0) {\n returnValue += ' و'\n }\n }\n }\n }\n\n // Process tens and ones\n if (tens > 0) {\n if (tens < 20) { // 1 -> 19\n if (tens === 2 && hundreds === 0 && groupLevel > 0) {\n // Cache expensive log10 calculation\n const numValue = Number(fullNumber)\n const pow = Math.trunc(Math.log10(numValue))\n if (pow % 3 === 0 && fullNumber === BigInt(2 * Math.pow(10, pow))) {\n returnValue = groupNumber === 2 ? this.dualWords[groupLevel] : this.dualAppendedWords[groupLevel]\n } else {\n returnValue = this.dualWords[groupLevel]\n }\n } else if (tens === 1 && groupLevel > 0) {\n returnValue += this.scaleWords[groupLevel]\n } else {\n returnValue += this.selectedOnes[tens - 1]\n }\n } else { // 20 -> 99\n const ones = tens % 10\n const tensIndex = Math.trunc(tens / 10) - 2\n\n if (ones > 0) {\n returnValue += this.selectedOnes[ones - 1]\n returnValue += ' و'\n }\n returnValue += this.tensWords[tensIndex]\n }\n }\n\n return returnValue\n }\n\n /** Converts integer part to Arabic words by processing 3-digit groups. */\n integerToWords (integerPart) {\n if (integerPart === 0n) {\n return this.zeroWord\n }\n let temp = integerPart\n let group = 0\n let result = ''\n\n // Process each group of 3 digits (right to left)\n while (temp > 0n) {\n const numberToProcess = Number(temp % 1000n)\n temp = temp / 1000n\n\n if (numberToProcess > 0) {\n const groupDescription = this.segmentToWords(numberToProcess, group, integerPart)\n\n if (groupDescription) {\n // Add group name for thousands, millions, etc.\n if (group > 0) {\n if (result) {\n result = ' و' + result\n }\n\n if (numberToProcess > 2) {\n const remainder = numberToProcess % 100\n if (remainder === 1) {\n result = this.scaleWords[group] + ' ' + result\n } else if (numberToProcess >= 3 && numberToProcess <= 10) {\n result = this.scalePluralWords[group] + ' ' + result\n } else {\n result = (result ? this.scaleAppendedWords[group] : this.scaleWords[group]) + ' ' + result\n }\n }\n }\n\n // Add group description (prepend for RTL)\n result = groupDescription + ' ' + result\n }\n }\n\n group++\n }\n\n return result.replace(/\\s+/g, ' ').trim()\n }\n}\n"],"names":["AbstractLanguage","options","negativeWord","decimalSeparatorWord","zeroWord","wordSeparator","usePerDigitDecimals","this","toWords","isNegative","integerPart","decimalPart","words","push","integerToWords","decimalDigitsToWords","join","Error","setOptions","defaults","userOptions","decimalIntegerToWords","i","length","remainder","slice","char","BigInt","expandScientificNotation","str","mantissa","expStr","toLowerCase","split","exp","parseInt","dotIndex","indexOf","digits","newDotPosition","repeat","ArabicConverter","LanguageClass","tensWords","hundredsWords","scaleWords","scaleAppendedWords","scalePluralWords","dualWords","dualAppendedWords","ones","masculine","feminine","constructor","super","gender","undefined","selectedOnes","segmentToWords","groupNumber","groupLevel","fullNumber","tens","hundredsRaw","hundreds","Math","trunc","returnValue","hundredsWord","numValue","Number","pow","log10","tensIndex","temp","group","result","numberToProcess","groupDescription","replace","trim","value","proto","Object","getPrototypeOf","prototype","isPlainObject","TypeError","type","isFinite","toString","includes","numberToString","trimmed","isNaN","stringToNormalizedForm","integerStr","parseNumericString","parseNumericValue"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /*! n2words/AzerbaijaniConverter v2.0.0 | MIT License | github.com/forzagreen/n2words */
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).n2words=e.n2words||{})}(this,function(e){"use strict";class t{#e={};negativeWord="";decimalSeparatorWord="";zeroWord="";wordSeparator=" ";usePerDigitDecimals=!1;get options(){return this.#e}toWords(e,t,n){const r=[];return e&&r.push(this.negativeWord),r.push(this.integerToWords(t)),n&&(r.push(this.decimalSeparatorWord),r.push(...this.decimalDigitsToWords(n))),r.join(this.wordSeparator)}integerToWords(e){throw new Error("integerToWords() must be implemented by subclass")}setOptions(e={},t={}){this.#e={...e,...t}}decimalIntegerToWords(e){return this.integerToWords(e)}decimalDigitsToWords(e){const t=[];let n=0;for(;n<e.length&&"0"===e[n];)t.push(this.zeroWord),n++;const r=e.slice(n);if(!r)return t;if(this.usePerDigitDecimals)for(const e of r)t.push(this.decimalIntegerToWords(BigInt(e)));else t.push(this.decimalIntegerToWords(BigInt(r)));return t}}class n extends t{scaleWords;wordForScale(e){const t=this.scaleWords.find(t=>t[0]===e);return t?.[1]}decomposeInteger(e){const t=[];let n=e;do{const e=this.scaleWords.find(e=>n>=e[0]);if(!e)break;const r=0n===n?1n:n/e[0];1n===r?t.push({[this.wordForScale(1n)]:1n}):t.push(this.decomposeInteger(r)),t.push({[e[1]]:e[0]}),n=0n===n?0n:n%e[0]}while(n>0n);return t}reduceWordSets(e){for(;e.length>1;){const[t,n,...r]=e;if(!Array.isArray(t)&&!Array.isArray(n)){const i=this.combineWordSets(t,n);e=r.length>0?[i,r]:[i];continue}const i=e.map(e=>Array.isArray(e)?1===e.length?e[0]:this.reduceWordSets(e):e);e=i}return e[0]}combineWordSets(e,t){throw new Error("combineWordSets() must be implemented by subclass")}finalizeWords(e){return e.trimEnd()}integerToWords(e){const t=this.decomposeInteger(e),n=this.reduceWordSets(t),r=Object.keys(n)[0];return this.finalizeWords(r)}}class r extends n{combineWordSets(e,t){const[[n,r]]=Object.entries(e),[[i,o]]=Object.entries(t);if(1n===r&&(o<=100n||1000n===o))return t;const s=o>r?r*o:r+o;return{[`${n}${this.wordSeparator}${i}`]:s}}}function i(e){const[t,n]=e.toLowerCase().split("e"),r=parseInt(n,10),i=t.indexOf("."),o=-1===i?t:t.slice(0,i)+t.slice(i+1),s=(-1===i?t.length:i)+r;return s>=o.length?o+"0".repeat(s-o.length):s<=0?"0."+"0".repeat(-s)+o:o.slice(0,s)+"."+o.slice(s)}const o=(s=class extends r{negativeWord="mənfi";decimalSeparatorWord="nöqtə";zeroWord="sıfır";scaleWords=[[1000000000000000000n,"kentilyon"],[1000000000000000n,"katrilyon"],[1000000000000n,"trilyon"],[1000000000n,"milyar"],[1000000n,"milyon"],[1000n,"min"],[100n,"yüz"],[90n,"doxsan"],[80n,"səksən"],[70n,"yetmiş"],[60n,"altmış"],[50n,"əlli"],[40n,"qırx"],[30n,"otuz"],[20n,"iyirmi"],[10n,"on"],[9n,"doqquz"],[8n,"səkkiz"],[7n,"yeddi"],[6n,"altı"],[5n,"beş"],[4n,"dörd"],[3n,"üç"],[2n,"iki"],[1n,"bir"],[0n,"sıfır"]]},function(e,t){if(void 0!==t&&!function(e){if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(t))throw new TypeError("options must be a plain object if provided");const{isNegative:n,integerPart:r,decimalPart:o}=function(e){const t=typeof e;if("bigint"===t)return e<0n?{isNegative:!0,integerPart:-e}:{isNegative:!1,integerPart:e};if("number"!==t&&"string"!==t)throw new TypeError(`Invalid value type: expected number, string, or bigint, received ${t}`);const n="number"===t?function(e){if(!Number.isFinite(e))throw new Error("Number must be finite (NaN and Infinity are not supported)");const t=e.toString();return t.includes("e")||t.includes("E")?i(t):t}(e):function(e){const t=e.trim();if(0===t.length)throw new Error(`Invalid number format: "${e}"`);if(Number.isNaN(Number(t)))throw new Error(`Invalid number format: "${e}"`);return t.includes("e")||t.includes("E")?i(t):t}(e);return function(e){const t="-"===e[0];t&&(e=e.slice(1));const n=e.indexOf(".");if(-1===n)return{isNegative:t,integerPart:BigInt(e)};const r=e.slice(0,n)||"0",i=e.slice(n+1);return{isNegative:t,integerPart:BigInt(r),decimalPart:i}}(n)}(e);return new s(t).toWords(n,r,o)});var s;e.AzerbaijaniConverter=o});
3
+ //# sourceMappingURL=AzerbaijaniConverter.js.map