n2words 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +86 -188
  3. package/dist/languages/am-Latn.js +3 -0
  4. package/dist/languages/am-Latn.js.map +1 -0
  5. package/dist/languages/am.js +3 -0
  6. package/dist/languages/am.js.map +1 -0
  7. package/dist/languages/ar.js +3 -0
  8. package/dist/languages/ar.js.map +1 -0
  9. package/dist/languages/az.js +3 -0
  10. package/dist/languages/az.js.map +1 -0
  11. package/dist/languages/bn.js +3 -0
  12. package/dist/languages/bn.js.map +1 -0
  13. package/dist/languages/cs.js +3 -0
  14. package/dist/languages/cs.js.map +1 -0
  15. package/dist/languages/da.js +3 -0
  16. package/dist/languages/da.js.map +1 -0
  17. package/dist/languages/de.js +3 -0
  18. package/dist/languages/de.js.map +1 -0
  19. package/dist/languages/el.js +3 -0
  20. package/dist/languages/el.js.map +1 -0
  21. package/dist/languages/en.js +3 -0
  22. package/dist/languages/en.js.map +1 -0
  23. package/dist/languages/es.js +3 -0
  24. package/dist/languages/es.js.map +1 -0
  25. package/dist/languages/fa.js +3 -0
  26. package/dist/languages/fa.js.map +1 -0
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -0
  30. package/dist/languages/fil.js.map +1 -0
  31. package/dist/languages/fr-BE.js +3 -0
  32. package/dist/languages/fr-BE.js.map +1 -0
  33. package/dist/languages/fr.js +3 -0
  34. package/dist/languages/fr.js.map +1 -0
  35. package/dist/languages/gu.js +3 -0
  36. package/dist/languages/gu.js.map +1 -0
  37. package/dist/languages/ha.js +3 -0
  38. package/dist/languages/ha.js.map +1 -0
  39. package/dist/languages/hbo.js +3 -0
  40. package/dist/languages/hbo.js.map +1 -0
  41. package/dist/languages/he.js +3 -0
  42. package/dist/languages/he.js.map +1 -0
  43. package/dist/languages/hi.js +3 -0
  44. package/dist/languages/hi.js.map +1 -0
  45. package/dist/languages/hr.js +3 -0
  46. package/dist/languages/hr.js.map +1 -0
  47. package/dist/languages/hu.js +3 -0
  48. package/dist/languages/hu.js.map +1 -0
  49. package/dist/languages/id.js +3 -0
  50. package/dist/languages/id.js.map +1 -0
  51. package/dist/languages/it.js +3 -0
  52. package/dist/languages/it.js.map +1 -0
  53. package/dist/languages/ja.js +3 -0
  54. package/dist/languages/ja.js.map +1 -0
  55. package/dist/languages/ka.js +3 -0
  56. package/dist/languages/ka.js.map +1 -0
  57. package/dist/languages/kn.js +3 -0
  58. package/dist/languages/kn.js.map +1 -0
  59. package/dist/languages/ko.js +3 -0
  60. package/dist/languages/ko.js.map +1 -0
  61. package/dist/languages/lt.js +3 -0
  62. package/dist/languages/lt.js.map +1 -0
  63. package/dist/languages/lv.js +3 -0
  64. package/dist/languages/lv.js.map +1 -0
  65. package/dist/languages/mr.js +3 -0
  66. package/dist/languages/mr.js.map +1 -0
  67. package/dist/languages/ms.js +3 -0
  68. package/dist/languages/ms.js.map +1 -0
  69. package/dist/languages/nb.js +3 -0
  70. package/dist/languages/nb.js.map +1 -0
  71. package/dist/languages/nl.js +3 -0
  72. package/dist/languages/nl.js.map +1 -0
  73. package/dist/languages/pa.js +3 -0
  74. package/dist/languages/pa.js.map +1 -0
  75. package/dist/languages/pl.js +3 -0
  76. package/dist/languages/pl.js.map +1 -0
  77. package/dist/languages/pt.js +3 -0
  78. package/dist/languages/pt.js.map +1 -0
  79. package/dist/languages/ro.js +3 -0
  80. package/dist/languages/ro.js.map +1 -0
  81. package/dist/languages/ru.js +3 -0
  82. package/dist/languages/ru.js.map +1 -0
  83. package/dist/languages/sr-Cyrl.js +3 -0
  84. package/dist/languages/sr-Cyrl.js.map +1 -0
  85. package/dist/languages/sr-Latn.js +3 -0
  86. package/dist/languages/sr-Latn.js.map +1 -0
  87. package/dist/languages/sv.js +3 -0
  88. package/dist/languages/sv.js.map +1 -0
  89. package/dist/languages/sw.js +3 -0
  90. package/dist/languages/sw.js.map +1 -0
  91. package/dist/languages/ta.js +3 -0
  92. package/dist/languages/ta.js.map +1 -0
  93. package/dist/languages/te.js +3 -0
  94. package/dist/languages/te.js.map +1 -0
  95. package/dist/languages/th.js +3 -0
  96. package/dist/languages/th.js.map +1 -0
  97. package/dist/languages/tr.js +3 -0
  98. package/dist/languages/tr.js.map +1 -0
  99. package/dist/languages/uk.js +3 -0
  100. package/dist/languages/uk.js.map +1 -0
  101. package/dist/languages/ur.js +3 -0
  102. package/dist/languages/ur.js.map +1 -0
  103. package/dist/languages/vi.js +3 -0
  104. package/dist/languages/vi.js.map +1 -0
  105. package/dist/languages/yo.js +3 -0
  106. package/dist/languages/yo.js.map +1 -0
  107. package/dist/languages/zh-Hans.js +3 -0
  108. package/dist/languages/zh-Hans.js.map +1 -0
  109. package/dist/languages/zh-Hant.js +3 -0
  110. package/dist/languages/zh-Hant.js.map +1 -0
  111. package/dist/n2words.js +2 -2
  112. package/dist/n2words.js.map +1 -1
  113. package/lib/languages/am-Latn.d.ts +7 -0
  114. package/lib/languages/am-Latn.js +159 -0
  115. package/lib/languages/am.d.ts +7 -0
  116. package/lib/languages/am.js +159 -0
  117. package/lib/languages/ar.d.ts +14 -27
  118. package/lib/languages/ar.js +175 -129
  119. package/lib/languages/az.d.ts +4 -9
  120. package/lib/languages/az.js +166 -37
  121. package/lib/languages/bn.d.ts +4 -8
  122. package/lib/languages/bn.js +159 -124
  123. package/lib/languages/cs.d.ts +15 -85
  124. package/lib/languages/cs.js +293 -114
  125. package/lib/languages/da.d.ts +11 -12
  126. package/lib/languages/da.js +269 -101
  127. package/lib/languages/de.d.ts +14 -11
  128. package/lib/languages/de.js +305 -86
  129. package/lib/languages/el.d.ts +11 -11
  130. package/lib/languages/el.js +224 -78
  131. package/lib/languages/en.d.ts +14 -13
  132. package/lib/languages/en.js +228 -72
  133. package/lib/languages/es.d.ts +18 -12
  134. package/lib/languages/es.js +297 -103
  135. package/lib/languages/fa.d.ts +4 -44
  136. package/lib/languages/fa.js +112 -122
  137. package/lib/languages/fi.d.ts +14 -0
  138. package/lib/languages/fi.js +238 -0
  139. package/lib/languages/fil.d.ts +4 -13
  140. package/lib/languages/fil.js +196 -106
  141. package/lib/languages/fr-BE.d.ts +8 -8
  142. package/lib/languages/fr-BE.js +285 -19
  143. package/lib/languages/fr.d.ts +18 -12
  144. package/lib/languages/fr.js +339 -89
  145. package/lib/languages/gu.d.ts +4 -8
  146. package/lib/languages/gu.js +143 -125
  147. package/lib/languages/ha.d.ts +7 -0
  148. package/lib/languages/ha.js +225 -0
  149. package/lib/languages/hbo.d.ts +10 -110
  150. package/lib/languages/hbo.js +245 -214
  151. package/lib/languages/he.d.ts +10 -77
  152. package/lib/languages/he.js +231 -172
  153. package/lib/languages/hi.d.ts +4 -8
  154. package/lib/languages/hi.js +163 -124
  155. package/lib/languages/hr.d.ts +8 -77
  156. package/lib/languages/hr.js +200 -89
  157. package/lib/languages/hu.d.ts +4 -19
  158. package/lib/languages/hu.js +198 -119
  159. package/lib/languages/id.d.ts +4 -34
  160. package/lib/languages/id.js +166 -129
  161. package/lib/languages/it.d.ts +16 -34
  162. package/lib/languages/it.js +307 -97
  163. package/lib/languages/ja.d.ts +14 -14
  164. package/lib/languages/ja.js +221 -111
  165. package/lib/languages/ka.d.ts +17 -0
  166. package/lib/languages/ka.js +291 -0
  167. package/lib/languages/kn.d.ts +4 -8
  168. package/lib/languages/kn.js +143 -35
  169. package/lib/languages/ko.d.ts +11 -11
  170. package/lib/languages/ko.js +250 -49
  171. package/lib/languages/lt.d.ts +15 -67
  172. package/lib/languages/lt.js +287 -122
  173. package/lib/languages/lv.d.ts +15 -67
  174. package/lib/languages/lv.js +288 -106
  175. package/lib/languages/mr.d.ts +4 -8
  176. package/lib/languages/mr.js +143 -125
  177. package/lib/languages/ms.d.ts +4 -28
  178. package/lib/languages/ms.js +166 -116
  179. package/lib/languages/nb.d.ts +11 -9
  180. package/lib/languages/nb.js +272 -87
  181. package/lib/languages/nl.d.ts +23 -13
  182. package/lib/languages/nl.js +299 -133
  183. package/lib/languages/pa.d.ts +4 -8
  184. package/lib/languages/pa.js +151 -124
  185. package/lib/languages/pl.d.ts +19 -77
  186. package/lib/languages/pl.js +294 -87
  187. package/lib/languages/pt.d.ts +14 -26
  188. package/lib/languages/pt.js +272 -92
  189. package/lib/languages/ro.d.ts +15 -155
  190. package/lib/languages/ro.js +219 -235
  191. package/lib/languages/ru.d.ts +8 -82
  192. package/lib/languages/ru.js +239 -90
  193. package/lib/languages/sr-Cyrl.d.ts +8 -77
  194. package/lib/languages/sr-Cyrl.js +197 -89
  195. package/lib/languages/sr-Latn.d.ts +8 -77
  196. package/lib/languages/sr-Latn.js +197 -89
  197. package/lib/languages/sv.d.ts +11 -11
  198. package/lib/languages/sv.js +278 -74
  199. package/lib/languages/sw.d.ts +4 -36
  200. package/lib/languages/sw.js +133 -106
  201. package/lib/languages/ta.d.ts +4 -17
  202. package/lib/languages/ta.js +143 -202
  203. package/lib/languages/te.d.ts +4 -19
  204. package/lib/languages/te.js +133 -196
  205. package/lib/languages/th.d.ts +4 -14
  206. package/lib/languages/th.js +135 -91
  207. package/lib/languages/tr.d.ts +15 -9
  208. package/lib/languages/tr.js +245 -49
  209. package/lib/languages/uk.d.ts +8 -82
  210. package/lib/languages/uk.js +206 -78
  211. package/lib/languages/ur.d.ts +4 -8
  212. package/lib/languages/ur.js +151 -124
  213. package/lib/languages/vi.d.ts +14 -69
  214. package/lib/languages/vi.js +278 -129
  215. package/lib/languages/yo.d.ts +7 -0
  216. package/lib/languages/yo.js +303 -0
  217. package/lib/languages/zh-Hans.d.ts +8 -18
  218. package/lib/languages/zh-Hans.js +163 -92
  219. package/lib/languages/zh-Hant.d.ts +8 -18
  220. package/lib/languages/zh-Hant.js +181 -90
  221. package/lib/n2words.d.ts +55 -209
  222. package/lib/n2words.js +115 -530
  223. package/lib/utils/is-plain-object.d.ts +13 -0
  224. package/lib/utils/is-plain-object.js +17 -0
  225. package/lib/utils/parse-numeric.d.ts +17 -0
  226. package/lib/utils/parse-numeric.js +108 -0
  227. package/lib/utils/validate-options.d.ts +8 -0
  228. package/lib/utils/validate-options.js +16 -0
  229. package/package.json +26 -14
  230. package/dist/ArabicConverter.js +0 -3
  231. package/dist/ArabicConverter.js.map +0 -1
  232. package/dist/AzerbaijaniConverter.js +0 -3
  233. package/dist/AzerbaijaniConverter.js.map +0 -1
  234. package/dist/BanglaConverter.js +0 -3
  235. package/dist/BanglaConverter.js.map +0 -1
  236. package/dist/BiblicalHebrewConverter.js +0 -3
  237. package/dist/BiblicalHebrewConverter.js.map +0 -1
  238. package/dist/CroatianConverter.js +0 -3
  239. package/dist/CroatianConverter.js.map +0 -1
  240. package/dist/CzechConverter.js +0 -3
  241. package/dist/CzechConverter.js.map +0 -1
  242. package/dist/DanishConverter.js +0 -3
  243. package/dist/DanishConverter.js.map +0 -1
  244. package/dist/DutchConverter.js +0 -3
  245. package/dist/DutchConverter.js.map +0 -1
  246. package/dist/EnglishConverter.js +0 -3
  247. package/dist/EnglishConverter.js.map +0 -1
  248. package/dist/FilipinoConverter.js +0 -3
  249. package/dist/FilipinoConverter.js.map +0 -1
  250. package/dist/FrenchBelgiumConverter.js +0 -3
  251. package/dist/FrenchBelgiumConverter.js.map +0 -1
  252. package/dist/FrenchConverter.js +0 -3
  253. package/dist/FrenchConverter.js.map +0 -1
  254. package/dist/GermanConverter.js +0 -3
  255. package/dist/GermanConverter.js.map +0 -1
  256. package/dist/GreekConverter.js +0 -3
  257. package/dist/GreekConverter.js.map +0 -1
  258. package/dist/GujaratiConverter.js +0 -3
  259. package/dist/GujaratiConverter.js.map +0 -1
  260. package/dist/HebrewConverter.js +0 -3
  261. package/dist/HebrewConverter.js.map +0 -1
  262. package/dist/HindiConverter.js +0 -3
  263. package/dist/HindiConverter.js.map +0 -1
  264. package/dist/HungarianConverter.js +0 -3
  265. package/dist/HungarianConverter.js.map +0 -1
  266. package/dist/IndonesianConverter.js +0 -3
  267. package/dist/IndonesianConverter.js.map +0 -1
  268. package/dist/ItalianConverter.js +0 -3
  269. package/dist/ItalianConverter.js.map +0 -1
  270. package/dist/JapaneseConverter.js +0 -3
  271. package/dist/JapaneseConverter.js.map +0 -1
  272. package/dist/KannadaConverter.js +0 -3
  273. package/dist/KannadaConverter.js.map +0 -1
  274. package/dist/KoreanConverter.js +0 -3
  275. package/dist/KoreanConverter.js.map +0 -1
  276. package/dist/LatvianConverter.js +0 -3
  277. package/dist/LatvianConverter.js.map +0 -1
  278. package/dist/LithuanianConverter.js +0 -3
  279. package/dist/LithuanianConverter.js.map +0 -1
  280. package/dist/MalayConverter.js +0 -3
  281. package/dist/MalayConverter.js.map +0 -1
  282. package/dist/MarathiConverter.js +0 -3
  283. package/dist/MarathiConverter.js.map +0 -1
  284. package/dist/NorwegianBokmalConverter.js +0 -3
  285. package/dist/NorwegianBokmalConverter.js.map +0 -1
  286. package/dist/PersianConverter.js +0 -3
  287. package/dist/PersianConverter.js.map +0 -1
  288. package/dist/PolishConverter.js +0 -3
  289. package/dist/PolishConverter.js.map +0 -1
  290. package/dist/PortugueseConverter.js +0 -3
  291. package/dist/PortugueseConverter.js.map +0 -1
  292. package/dist/PunjabiConverter.js +0 -3
  293. package/dist/PunjabiConverter.js.map +0 -1
  294. package/dist/RomanianConverter.js +0 -3
  295. package/dist/RomanianConverter.js.map +0 -1
  296. package/dist/RussianConverter.js +0 -3
  297. package/dist/RussianConverter.js.map +0 -1
  298. package/dist/SerbianCyrillicConverter.js +0 -3
  299. package/dist/SerbianCyrillicConverter.js.map +0 -1
  300. package/dist/SerbianLatinConverter.js +0 -3
  301. package/dist/SerbianLatinConverter.js.map +0 -1
  302. package/dist/SimplifiedChineseConverter.js +0 -3
  303. package/dist/SimplifiedChineseConverter.js.map +0 -1
  304. package/dist/SpanishConverter.js +0 -3
  305. package/dist/SpanishConverter.js.map +0 -1
  306. package/dist/SwahiliConverter.js +0 -3
  307. package/dist/SwahiliConverter.js.map +0 -1
  308. package/dist/SwedishConverter.js +0 -3
  309. package/dist/SwedishConverter.js.map +0 -1
  310. package/dist/TamilConverter.js +0 -3
  311. package/dist/TamilConverter.js.map +0 -1
  312. package/dist/TeluguConverter.js +0 -3
  313. package/dist/TeluguConverter.js.map +0 -1
  314. package/dist/ThaiConverter.js +0 -3
  315. package/dist/ThaiConverter.js.map +0 -1
  316. package/dist/TraditionalChineseConverter.js +0 -3
  317. package/dist/TraditionalChineseConverter.js.map +0 -1
  318. package/dist/TurkishConverter.js +0 -3
  319. package/dist/TurkishConverter.js.map +0 -1
  320. package/dist/UkrainianConverter.js +0 -3
  321. package/dist/UkrainianConverter.js.map +0 -1
  322. package/dist/UrduConverter.js +0 -3
  323. package/dist/UrduConverter.js.map +0 -1
  324. package/dist/VietnameseConverter.js +0 -3
  325. package/dist/VietnameseConverter.js.map +0 -1
  326. package/lib/classes/abstract-language.d.ts +0 -178
  327. package/lib/classes/abstract-language.js +0 -268
  328. package/lib/classes/greedy-scale-language.d.ts +0 -109
  329. package/lib/classes/greedy-scale-language.js +0 -201
  330. package/lib/classes/slavic-language.d.ts +0 -148
  331. package/lib/classes/slavic-language.js +0 -281
  332. package/lib/classes/south-asian-language.d.ts +0 -70
  333. package/lib/classes/south-asian-language.js +0 -154
  334. package/lib/classes/turkic-language.d.ts +0 -26
  335. package/lib/classes/turkic-language.js +0 -59
@@ -1,111 +1,202 @@
1
- import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
2
-
3
1
  /**
4
- * Traditional Chinese language converter.
2
+ * Traditional Chinese language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter for Traditional Chinese.
5
5
  *
6
- * Supports:
7
- * - Traditional Chinese characters (繁體中文)
6
+ * Key features:
7
+ * - Myriad-based (萬, 億) grouping - 4 digits
8
+ * - Formal (financial) vs common numerals
9
+ * - Zero insertion for skipped positions
8
10
  * - No word separators (concatenated format)
9
- * - Optional formal (financial) vs common numerals
11
+ *
12
+ * Differences from Simplified:
13
+ * - Different character forms (e.g., 負/负, 點/点, 億/亿, 萬/万)
14
+ * - Some formal numerals differ (參/叁, 貳/贰, 陸/陆)
10
15
  */
11
- export class TraditionalChinese extends GreedyScaleLanguage {
12
- negativeWord = ''
13
- decimalSeparatorWord = ''
14
- zeroWord = '零'
15
- wordSeparator = ''
16
-
17
- constructor (options = {}) {
18
- super()
19
-
20
- this.setOptions({
21
- formal: true
22
- }, options)
23
-
24
- if (this.options.formal) {
25
- this.scaleWords = [
26
- [1_000_000_000_000n, ''],
27
- [100_000_000n, ''],
28
- [10_000n, ''],
29
- [1000n, '仟'],
30
- [100n, '佰'],
31
- [10n, '拾'],
32
- [9n, ''],
33
- [8n, ''],
34
- [7n, '柒'],
35
- [6n, ''],
36
- [5n, ''],
37
- [4n, ''],
38
- [3n, '參'],
39
- [2n, '貳'],
40
- [1n, '壹'],
41
- [0n, '零']
42
- ]
43
- } else {
44
- this.scaleWords = [
45
- [1_000_000_000_000n, '萬'],
46
- [100_000_000n, '億'],
47
- [10_000n, '萬'],
48
- [1000n, '千'],
49
- [100n, '百'],
50
- [10n, '十'],
51
- [9n, '九'],
52
- [8n, '八'],
53
- [7n, ''],
54
- [6n, '六'],
55
- [5n, '五'],
56
- [4n, '四'],
57
- [3n, '三'],
58
- [2n, '二'],
59
- [1n, '一'],
60
- [0n, '零']
61
- ]
16
+
17
+ import { parseNumericValue } from '../utils/parse-numeric.js'
18
+ import { validateOptions } from '../utils/validate-options.js'
19
+
20
+ // ============================================================================
21
+ // Vocabulary
22
+ // ============================================================================
23
+
24
+ // Common (everyday) numerals - Traditional forms
25
+ const ONES_COMMON = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
26
+ const TEN_COMMON = '十'
27
+ const HUNDRED_COMMON = '百'
28
+ const THOUSAND_COMMON = '千'
29
+
30
+ // Formal (financial) numerals - Traditional forms
31
+ const ONES_FORMAL = ['零', '', '貳', '參', '肆', '伍', '陸', '柒', '捌', '玖']
32
+ const TEN_FORMAL = ''
33
+ const HUNDRED_FORMAL = ''
34
+ const THOUSAND_FORMAL = '仟'
35
+
36
+ // Scale words - Traditional forms
37
+ const WAN_WORD = '' // 10,000
38
+ const YI_WORD = '' // 100,000,000
39
+
40
+ const ZERO = ''
41
+ const NEGATIVE = ''
42
+ const DECIMAL_SEP = ''
43
+
44
+ // ============================================================================
45
+ // Conversion Functions
46
+ // ============================================================================
47
+
48
+ function integerToWords (n, formal = true) {
49
+ if (n === 0n) return ZERO
50
+
51
+ const ones = formal ? ONES_FORMAL : ONES_COMMON
52
+ const ten = formal ? TEN_FORMAL : TEN_COMMON
53
+ const hundred = formal ? HUNDRED_FORMAL : HUNDRED_COMMON
54
+ const thousand = formal ? THOUSAND_FORMAL : THOUSAND_COMMON
55
+
56
+ // Convert number below 萬 (10,000)
57
+ function convertBelowWan (value) {
58
+ if (value === 0n) return ''
59
+
60
+ const parts = []
61
+ let needsZero = false
62
+
63
+ // Thousands (千)
64
+ const thousandsVal = value / 1000n
65
+ const thousandsRemainder = value % 1000n
66
+ if (thousandsVal > 0n) {
67
+ parts.push(ones[Number(thousandsVal)] + thousand)
68
+ needsZero = thousandsRemainder > 0n && thousandsRemainder < 100n
62
69
  }
63
- }
64
70
 
65
- /** Combines two word-sets with Traditional Chinese grammar rules and zero insertion. */
66
- combineWordSets (preceding, following) {
67
- const precedingWord = Object.keys(preceding)[0]
68
- const precedingValue = Object.values(preceding)[0]
69
- const followingWord = Object.keys(following)[0]
70
- const followingValue = Object.values(following)[0]
71
+ // Hundreds (百)
72
+ const hundredsVal = thousandsRemainder / 100n
73
+ const hundredsRemainder = thousandsRemainder % 100n
74
+ if (hundredsVal > 0n) {
75
+ if (needsZero) {
76
+ parts.push(ZERO)
77
+ needsZero = false
78
+ }
79
+ parts.push(ones[Number(hundredsVal)] + hundred)
80
+ needsZero = hundredsRemainder > 0n && hundredsRemainder < 10n
81
+ } else if (thousandsVal > 0n && hundredsRemainder > 0n) {
82
+ needsZero = true
83
+ }
71
84
 
72
- // Implicit one: omit 1 before single digits (< 10)
73
- if (precedingValue === 1n && followingValue < 10n) {
74
- return following
85
+ // Tens ()
86
+ const tensVal = hundredsRemainder / 10n
87
+ const onesVal = hundredsRemainder % 10n
88
+ if (tensVal > 0n) {
89
+ if (needsZero) {
90
+ parts.push(ZERO)
91
+ needsZero = false
92
+ }
93
+ parts.push(ones[Number(tensVal)] + ten)
94
+ } else if ((hundredsVal > 0n || thousandsVal > 0n) && onesVal > 0n) {
95
+ needsZero = true
75
96
  }
76
97
 
77
- // Multiply when following > preceding (scale words like 千, 萬, 億)
78
- if (followingValue > precedingValue) {
79
- return { [`${precedingWord}${followingWord}`]: precedingValue * followingValue }
98
+ // Ones
99
+ if (onesVal > 0n) {
100
+ if (needsZero) {
101
+ parts.push(ZERO)
102
+ }
103
+ parts.push(ones[Number(onesVal)])
80
104
  }
81
105
 
82
- // Insert "零" (zero) when position skip levels (e.g., 1003 = 千零三)
83
- // zeroDigit() checks if gap exists between preceding and following magnitude
84
- if (this.zeroDigit(precedingValue) > this.digit(followingValue)) {
85
- return { [`${precedingWord}${this.zeroWord}${followingWord}`]: precedingValue + followingValue }
106
+ return parts.join('')
107
+ }
108
+
109
+ // Convert number below (100 million)
110
+ function convertBelowYi (value) {
111
+ if (value === 0n) return ''
112
+
113
+ const parts = []
114
+
115
+ if (value >= 10_000n) {
116
+ const wanValue = value / 10_000n
117
+ const wanRemainder = value % 10_000n
118
+
119
+ parts.push(convertBelowWan(wanValue) + WAN_WORD)
120
+
121
+ if (wanRemainder > 0n) {
122
+ const wanEndsWithZero = wanValue % 10n === 0n
123
+ const remainderMissesThousands = wanRemainder < 1000n
124
+ const needsZero = wanEndsWithZero || remainderMissesThousands
125
+ if (needsZero) {
126
+ parts.push(ZERO)
127
+ }
128
+ parts.push(convertBelowWan(wanRemainder))
129
+ }
130
+ } else {
131
+ parts.push(convertBelowWan(value))
86
132
  }
87
133
 
88
- // Default: concatenate without zero insertion
89
- return { [`${precedingWord}${followingWord}`]: precedingValue + followingValue }
134
+ return parts.join('')
90
135
  }
91
136
 
92
- /** Returns the number of digits in a number. */
93
- digit (number_) {
94
- return number_.toString().length
137
+ // Main conversion
138
+ const parts = []
139
+
140
+ if (n >= 100_000_000n) {
141
+ const yiValue = n / 100_000_000n
142
+ const yiRemainder = n % 100_000_000n
143
+
144
+ const yiWords = convertBelowYi(yiValue)
145
+ parts.push(yiWords + YI_WORD)
146
+
147
+ if (yiRemainder > 0n) {
148
+ const needsZero = yiRemainder < 10_000_000n
149
+ if (needsZero) {
150
+ parts.push(ZERO)
151
+ }
152
+ parts.push(convertBelowYi(yiRemainder))
153
+ }
154
+ } else {
155
+ parts.push(convertBelowYi(n))
95
156
  }
96
157
 
97
- /** Counts the number of zero digits in a number. */
98
- zeroDigit (number_) {
99
- return [...number_.toString()].filter(c => c === '0').length
158
+ return parts.join('')
159
+ }
160
+
161
+ function decimalDigitsToWords (decimalString, formal = true) {
162
+ const ones = formal ? ONES_FORMAL : ONES_COMMON
163
+ const words = []
164
+ for (const char of decimalString) {
165
+ words.push(ones[Number(char)])
100
166
  }
167
+ return words
168
+ }
101
169
 
102
- /** Converts decimal digits to words by reading each digit individually. */
103
- decimalDigitsToWords (decimalString) {
104
- const words = []
105
- for (let i = 0; i < decimalString.length; i++) {
106
- const digitValue = BigInt(decimalString[i])
107
- words.push(this.integerToWords(digitValue))
108
- }
109
- return words
170
+ /**
171
+ * Converts a numeric value to Traditional Chinese words.
172
+ *
173
+ * @param {number | string | bigint} value - The numeric value to convert
174
+ * @param {Object} [options] - Optional configuration
175
+ * @param {boolean} [options.formal=true] - Use formal/financial numerals
176
+ * @returns {string} The number in Traditional Chinese words
177
+ */
178
+ function toWords (value, options) {
179
+ options = validateOptions(options)
180
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
181
+ const formal = options.formal !== false // Default to true
182
+
183
+ let result = ''
184
+
185
+ if (isNegative) {
186
+ result = NEGATIVE
110
187
  }
188
+
189
+ result += integerToWords(integerPart, formal)
190
+
191
+ if (decimalPart) {
192
+ result += DECIMAL_SEP + decimalDigitsToWords(decimalPart, formal).join('')
193
+ }
194
+
195
+ return result
111
196
  }
197
+
198
+ // ============================================================================
199
+ // Exports
200
+ // ============================================================================
201
+
202
+ export { toWords }
package/lib/n2words.d.ts CHANGED
@@ -1,209 +1,55 @@
1
- /**
2
- * Numeric value that can be converted to words.
3
- * Accepts number, bigint, or numeric string representations.
4
- */
5
- export type NumericValue = number | bigint | string;
6
- export type ArabicOptions = {
7
- /**
8
- * Word for negative numbers
9
- */
10
- negativeWord?: string | undefined;
11
- /**
12
- * Grammatical gender for number forms
13
- */
14
- gender?: "feminine" | "masculine" | undefined;
15
- };
16
- export type BiblicalHebrewOptions = {
17
- /**
18
- * Conjunction character (typically 'ו' for and)
19
- */
20
- andWord?: string | undefined;
21
- /**
22
- * Grammatical gender for number forms
23
- */
24
- gender?: "feminine" | "masculine" | undefined;
25
- };
26
- export type CroatianOptions = {
27
- /**
28
- * Grammatical gender for number forms
29
- */
30
- gender?: "feminine" | "masculine" | undefined;
31
- };
32
- export type CzechOptions = {
33
- /**
34
- * Grammatical gender for number forms
35
- */
36
- gender?: "feminine" | "masculine" | undefined;
37
- };
38
- export type DanishOptions = {
39
- /**
40
- * Enable ordinal number conversion
41
- */
42
- ordFlag?: boolean | undefined;
43
- };
44
- export type DutchOptions = {
45
- /**
46
- * Include optional "en" separator
47
- */
48
- includeOptionalAnd?: boolean | undefined;
49
- /**
50
- * Disable hundred-pairing (e.g., "twelve hundred" becomes "one thousand two hundred")
51
- */
52
- noHundredPairing?: boolean | undefined;
53
- /**
54
- * Use accented "één" for one
55
- */
56
- accentOne?: boolean | undefined;
57
- };
58
- export type FrenchOptions = {
59
- /**
60
- * Use hyphens (true) instead of spaces (false) in compounds
61
- */
62
- withHyphenSeparator?: boolean | undefined;
63
- };
64
- export type FrenchBelgiumOptions = {
65
- /**
66
- * Use hyphens (true) instead of spaces (false) in compounds
67
- */
68
- withHyphenSeparator?: boolean | undefined;
69
- };
70
- export type HebrewOptions = {
71
- /**
72
- * Conjunction character (typically 'ו' for and)
73
- */
74
- andWord?: string | undefined;
75
- };
76
- export type LatvianOptions = {
77
- /**
78
- * Grammatical gender for number forms
79
- */
80
- gender?: "feminine" | "masculine" | undefined;
81
- };
82
- export type LithuanianOptions = {
83
- /**
84
- * Grammatical gender for number forms
85
- */
86
- gender?: "feminine" | "masculine" | undefined;
87
- };
88
- export type PolishOptions = {
89
- /**
90
- * Grammatical gender for number forms
91
- */
92
- gender?: "feminine" | "masculine" | undefined;
93
- };
94
- export type RomanianOptions = {
95
- /**
96
- * Grammatical gender for number forms
97
- */
98
- gender?: "feminine" | "masculine" | undefined;
99
- };
100
- export type RussianOptions = {
101
- /**
102
- * Grammatical gender for number forms
103
- */
104
- gender?: "feminine" | "masculine" | undefined;
105
- };
106
- export type SerbianCyrillicOptions = {
107
- /**
108
- * Grammatical gender for number forms
109
- */
110
- gender?: "feminine" | "masculine" | undefined;
111
- };
112
- export type SerbianLatinOptions = {
113
- /**
114
- * Grammatical gender for number forms
115
- */
116
- gender?: "feminine" | "masculine" | undefined;
117
- };
118
- export type SimplifiedChineseOptions = {
119
- /**
120
- * Use formal/financial numerals (壹贰叁) vs. common numerals (一二三)
121
- */
122
- formal?: boolean | undefined;
123
- };
124
- export type SpanishOptions = {
125
- /**
126
- * Grammatical gender for number forms
127
- */
128
- gender?: "feminine" | "masculine" | undefined;
129
- };
130
- export type TraditionalChineseOptions = {
131
- /**
132
- * Use formal/financial numerals (壹貳參) vs. common numerals (一二三)
133
- */
134
- formal?: boolean | undefined;
135
- };
136
- export type TurkishOptions = {
137
- /**
138
- * Remove spaces between words if true
139
- */
140
- dropSpaces?: boolean | undefined;
141
- };
142
- export type UkrainianOptions = {
143
- /**
144
- * Grammatical gender for number forms
145
- */
146
- gender?: "feminine" | "masculine" | undefined;
147
- };
148
- export type ParsedNumericValue = {
149
- /**
150
- * - Whether the value is negative
151
- */
152
- isNegative: boolean;
153
- /**
154
- * - The absolute integer part
155
- */
156
- integerPart: bigint;
157
- /**
158
- * - The decimal digits (without the point)
159
- */
160
- decimalPart?: string | undefined;
161
- };
162
- export const ArabicConverter: (value: NumericValue, options?: ArabicOptions) => string;
163
- export const AzerbaijaniConverter: (value: NumericValue) => string;
164
- export const BanglaConverter: (value: NumericValue) => string;
165
- export const BiblicalHebrewConverter: (value: NumericValue, options?: BiblicalHebrewOptions) => string;
166
- export const CroatianConverter: (value: NumericValue, options?: CroatianOptions) => string;
167
- export const CzechConverter: (value: NumericValue, options?: CzechOptions) => string;
168
- export const DanishConverter: (value: NumericValue, options?: DanishOptions) => string;
169
- export const DutchConverter: (value: NumericValue, options?: DutchOptions) => string;
170
- export const EnglishConverter: (value: NumericValue) => string;
171
- export const FilipinoConverter: (value: NumericValue) => string;
172
- export const FrenchConverter: (value: NumericValue, options?: FrenchOptions) => string;
173
- export const FrenchBelgiumConverter: (value: NumericValue, options?: FrenchBelgiumOptions) => string;
174
- export const GermanConverter: (value: NumericValue) => string;
175
- export const GreekConverter: (value: NumericValue) => string;
176
- export const GujaratiConverter: (value: NumericValue) => string;
177
- export const HebrewConverter: (value: NumericValue, options?: HebrewOptions) => string;
178
- export const HindiConverter: (value: NumericValue) => string;
179
- export const HungarianConverter: (value: NumericValue) => string;
180
- export const IndonesianConverter: (value: NumericValue) => string;
181
- export const ItalianConverter: (value: NumericValue) => string;
182
- export const JapaneseConverter: (value: NumericValue) => string;
183
- export const KannadaConverter: (value: NumericValue) => string;
184
- export const KoreanConverter: (value: NumericValue) => string;
185
- export const LatvianConverter: (value: NumericValue, options?: LatvianOptions) => string;
186
- export const LithuanianConverter: (value: NumericValue, options?: LithuanianOptions) => string;
187
- export const MalayConverter: (value: NumericValue) => string;
188
- export const MarathiConverter: (value: NumericValue) => string;
189
- export const NorwegianBokmalConverter: (value: NumericValue) => string;
190
- export const PersianConverter: (value: NumericValue) => string;
191
- export const PolishConverter: (value: NumericValue, options?: PolishOptions) => string;
192
- export const PortugueseConverter: (value: NumericValue) => string;
193
- export const PunjabiConverter: (value: NumericValue) => string;
194
- export const RomanianConverter: (value: NumericValue, options?: RomanianOptions) => string;
195
- export const RussianConverter: (value: NumericValue, options?: RussianOptions) => string;
196
- export const SerbianCyrillicConverter: (value: NumericValue, options?: SerbianCyrillicOptions) => string;
197
- export const SerbianLatinConverter: (value: NumericValue, options?: SerbianLatinOptions) => string;
198
- export const SimplifiedChineseConverter: (value: NumericValue, options?: SimplifiedChineseOptions) => string;
199
- export const SpanishConverter: (value: NumericValue, options?: SpanishOptions) => string;
200
- export const SwahiliConverter: (value: NumericValue) => string;
201
- export const SwedishConverter: (value: NumericValue) => string;
202
- export const TamilConverter: (value: NumericValue) => string;
203
- export const TeluguConverter: (value: NumericValue) => string;
204
- export const ThaiConverter: (value: NumericValue) => string;
205
- export const TraditionalChineseConverter: (value: NumericValue, options?: TraditionalChineseOptions) => string;
206
- export const TurkishConverter: (value: NumericValue, options?: TurkishOptions) => string;
207
- export const UkrainianConverter: (value: NumericValue, options?: UkrainianOptions) => string;
208
- export const UrduConverter: (value: NumericValue) => string;
209
- export const VietnameseConverter: (value: NumericValue) => string;
1
+ import { toWords as am } from './languages/am.js';
2
+ import { toWords as amLatn } from './languages/am-Latn.js';
3
+ import { toWords as ar } from './languages/ar.js';
4
+ import { toWords as az } from './languages/az.js';
5
+ import { toWords as bn } from './languages/bn.js';
6
+ import { toWords as cs } from './languages/cs.js';
7
+ import { toWords as da } from './languages/da.js';
8
+ import { toWords as de } from './languages/de.js';
9
+ import { toWords as el } from './languages/el.js';
10
+ import { toWords as en } from './languages/en.js';
11
+ import { toWords as es } from './languages/es.js';
12
+ import { toWords as fa } from './languages/fa.js';
13
+ import { toWords as fi } from './languages/fi.js';
14
+ import { toWords as fil } from './languages/fil.js';
15
+ import { toWords as fr } from './languages/fr.js';
16
+ import { toWords as frBE } from './languages/fr-BE.js';
17
+ import { toWords as gu } from './languages/gu.js';
18
+ import { toWords as ha } from './languages/ha.js';
19
+ import { toWords as hbo } from './languages/hbo.js';
20
+ import { toWords as he } from './languages/he.js';
21
+ import { toWords as hi } from './languages/hi.js';
22
+ import { toWords as hr } from './languages/hr.js';
23
+ import { toWords as hu } from './languages/hu.js';
24
+ import { toWords as id } from './languages/id.js';
25
+ import { toWords as it } from './languages/it.js';
26
+ import { toWords as ja } from './languages/ja.js';
27
+ import { toWords as ka } from './languages/ka.js';
28
+ import { toWords as kn } from './languages/kn.js';
29
+ import { toWords as ko } from './languages/ko.js';
30
+ import { toWords as lt } from './languages/lt.js';
31
+ import { toWords as lv } from './languages/lv.js';
32
+ import { toWords as mr } from './languages/mr.js';
33
+ import { toWords as ms } from './languages/ms.js';
34
+ import { toWords as nb } from './languages/nb.js';
35
+ import { toWords as nl } from './languages/nl.js';
36
+ import { toWords as pa } from './languages/pa.js';
37
+ import { toWords as pl } from './languages/pl.js';
38
+ import { toWords as pt } from './languages/pt.js';
39
+ import { toWords as ro } from './languages/ro.js';
40
+ import { toWords as ru } from './languages/ru.js';
41
+ import { toWords as srCyrl } from './languages/sr-Cyrl.js';
42
+ import { toWords as srLatn } from './languages/sr-Latn.js';
43
+ import { toWords as sv } from './languages/sv.js';
44
+ import { toWords as sw } from './languages/sw.js';
45
+ import { toWords as ta } from './languages/ta.js';
46
+ import { toWords as te } from './languages/te.js';
47
+ import { toWords as th } from './languages/th.js';
48
+ import { toWords as tr } from './languages/tr.js';
49
+ import { toWords as uk } from './languages/uk.js';
50
+ import { toWords as ur } from './languages/ur.js';
51
+ import { toWords as vi } from './languages/vi.js';
52
+ import { toWords as yo } from './languages/yo.js';
53
+ import { toWords as zhHans } from './languages/zh-Hans.js';
54
+ import { toWords as zhHant } from './languages/zh-Hant.js';
55
+ export { am, amLatn, ar, az, bn, cs, da, de, el, en, es, fa, fi, fil, fr, frBE, gu, ha, hbo, he, hi, hr, hu, id, it, ja, ka, kn, ko, lt, lv, mr, ms, nb, nl, pa, pl, pt, ro, ru, srCyrl, srLatn, sv, sw, ta, te, th, tr, uk, ur, vi, yo, zhHans, zhHant };