n2words 1.24.0 → 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 (349) hide show
  1. package/README.md +285 -156
  2. package/dist/ArabicConverter.js +3 -0
  3. package/dist/ArabicConverter.js.map +1 -0
  4. package/dist/AzerbaijaniConverter.js +3 -0
  5. package/dist/AzerbaijaniConverter.js.map +1 -0
  6. package/dist/BanglaConverter.js +3 -0
  7. package/dist/BanglaConverter.js.map +1 -0
  8. package/dist/BiblicalHebrewConverter.js +3 -0
  9. package/dist/BiblicalHebrewConverter.js.map +1 -0
  10. package/dist/CroatianConverter.js +3 -0
  11. package/dist/CroatianConverter.js.map +1 -0
  12. package/dist/CzechConverter.js +3 -0
  13. package/dist/CzechConverter.js.map +1 -0
  14. package/dist/DanishConverter.js +3 -0
  15. package/dist/DanishConverter.js.map +1 -0
  16. package/dist/DutchConverter.js +3 -0
  17. package/dist/DutchConverter.js.map +1 -0
  18. package/dist/EnglishConverter.js +3 -0
  19. package/dist/EnglishConverter.js.map +1 -0
  20. package/dist/FilipinoConverter.js +3 -0
  21. package/dist/FilipinoConverter.js.map +1 -0
  22. package/dist/FrenchBelgiumConverter.js +3 -0
  23. package/dist/FrenchBelgiumConverter.js.map +1 -0
  24. package/dist/FrenchConverter.js +3 -0
  25. package/dist/FrenchConverter.js.map +1 -0
  26. package/dist/GermanConverter.js +3 -0
  27. package/dist/GermanConverter.js.map +1 -0
  28. package/dist/GreekConverter.js +3 -0
  29. package/dist/GreekConverter.js.map +1 -0
  30. package/dist/GujaratiConverter.js +3 -0
  31. package/dist/GujaratiConverter.js.map +1 -0
  32. package/dist/HebrewConverter.js +3 -0
  33. package/dist/HebrewConverter.js.map +1 -0
  34. package/dist/HindiConverter.js +3 -0
  35. package/dist/HindiConverter.js.map +1 -0
  36. package/dist/HungarianConverter.js +3 -0
  37. package/dist/HungarianConverter.js.map +1 -0
  38. package/dist/IndonesianConverter.js +3 -0
  39. package/dist/IndonesianConverter.js.map +1 -0
  40. package/dist/ItalianConverter.js +3 -0
  41. package/dist/ItalianConverter.js.map +1 -0
  42. package/dist/JapaneseConverter.js +3 -0
  43. package/dist/JapaneseConverter.js.map +1 -0
  44. package/dist/KannadaConverter.js +3 -0
  45. package/dist/KannadaConverter.js.map +1 -0
  46. package/dist/KoreanConverter.js +3 -0
  47. package/dist/KoreanConverter.js.map +1 -0
  48. package/dist/LatvianConverter.js +3 -0
  49. package/dist/LatvianConverter.js.map +1 -0
  50. package/dist/LithuanianConverter.js +3 -0
  51. package/dist/LithuanianConverter.js.map +1 -0
  52. package/dist/MalayConverter.js +3 -0
  53. package/dist/MalayConverter.js.map +1 -0
  54. package/dist/MarathiConverter.js +3 -0
  55. package/dist/MarathiConverter.js.map +1 -0
  56. package/dist/NorwegianBokmalConverter.js +3 -0
  57. package/dist/NorwegianBokmalConverter.js.map +1 -0
  58. package/dist/PersianConverter.js +3 -0
  59. package/dist/PersianConverter.js.map +1 -0
  60. package/dist/PolishConverter.js +3 -0
  61. package/dist/PolishConverter.js.map +1 -0
  62. package/dist/PortugueseConverter.js +3 -0
  63. package/dist/PortugueseConverter.js.map +1 -0
  64. package/dist/PunjabiConverter.js +3 -0
  65. package/dist/PunjabiConverter.js.map +1 -0
  66. package/dist/RomanianConverter.js +3 -0
  67. package/dist/RomanianConverter.js.map +1 -0
  68. package/dist/RussianConverter.js +3 -0
  69. package/dist/RussianConverter.js.map +1 -0
  70. package/dist/SerbianCyrillicConverter.js +3 -0
  71. package/dist/SerbianCyrillicConverter.js.map +1 -0
  72. package/dist/SerbianLatinConverter.js +3 -0
  73. package/dist/SerbianLatinConverter.js.map +1 -0
  74. package/dist/SimplifiedChineseConverter.js +3 -0
  75. package/dist/SimplifiedChineseConverter.js.map +1 -0
  76. package/dist/SpanishConverter.js +3 -0
  77. package/dist/SpanishConverter.js.map +1 -0
  78. package/dist/SwahiliConverter.js +3 -0
  79. package/dist/SwahiliConverter.js.map +1 -0
  80. package/dist/SwedishConverter.js +3 -0
  81. package/dist/SwedishConverter.js.map +1 -0
  82. package/dist/TamilConverter.js +3 -0
  83. package/dist/TamilConverter.js.map +1 -0
  84. package/dist/TeluguConverter.js +3 -0
  85. package/dist/TeluguConverter.js.map +1 -0
  86. package/dist/ThaiConverter.js +3 -0
  87. package/dist/ThaiConverter.js.map +1 -0
  88. package/dist/TraditionalChineseConverter.js +3 -0
  89. package/dist/TraditionalChineseConverter.js.map +1 -0
  90. package/dist/TurkishConverter.js +3 -0
  91. package/dist/TurkishConverter.js.map +1 -0
  92. package/dist/UkrainianConverter.js +3 -0
  93. package/dist/UkrainianConverter.js.map +1 -0
  94. package/dist/UrduConverter.js +3 -0
  95. package/dist/UrduConverter.js.map +1 -0
  96. package/dist/VietnameseConverter.js +3 -0
  97. package/dist/VietnameseConverter.js.map +1 -0
  98. package/dist/n2words.js +3 -2
  99. package/dist/n2words.js.map +1 -1
  100. package/lib/classes/abstract-language.d.ts +178 -0
  101. package/lib/classes/abstract-language.js +192 -185
  102. package/lib/classes/greedy-scale-language.d.ts +109 -0
  103. package/lib/classes/greedy-scale-language.js +96 -90
  104. package/lib/classes/slavic-language.d.ts +148 -0
  105. package/lib/classes/slavic-language.js +136 -106
  106. package/lib/classes/south-asian-language.d.ts +70 -0
  107. package/lib/classes/south-asian-language.js +58 -65
  108. package/lib/classes/turkic-language.d.ts +26 -0
  109. package/lib/classes/turkic-language.js +22 -26
  110. package/lib/languages/ar.d.ts +30 -0
  111. package/lib/languages/ar.js +49 -133
  112. package/lib/languages/az.d.ts +12 -0
  113. package/lib/languages/az.js +7 -23
  114. package/lib/languages/bn.d.ts +11 -0
  115. package/lib/languages/bn.js +12 -7
  116. package/lib/languages/cs.d.ts +88 -0
  117. package/lib/languages/cs.js +44 -113
  118. package/lib/languages/da.d.ts +15 -0
  119. package/lib/languages/da.js +40 -87
  120. package/lib/languages/de.d.ts +14 -0
  121. package/lib/languages/de.js +34 -68
  122. package/lib/languages/el.d.ts +14 -0
  123. package/lib/languages/el.js +22 -48
  124. package/lib/languages/en.d.ts +16 -0
  125. package/lib/languages/en.js +22 -59
  126. package/lib/languages/es.d.ts +15 -0
  127. package/lib/languages/es.js +49 -81
  128. package/lib/languages/fa.d.ts +47 -0
  129. package/lib/languages/fa.js +90 -73
  130. package/lib/languages/fil.d.ts +16 -0
  131. package/lib/languages/fil.js +35 -76
  132. package/lib/languages/fr-BE.d.ts +11 -0
  133. package/lib/languages/fr-BE.js +15 -51
  134. package/lib/languages/fr.d.ts +15 -0
  135. package/lib/languages/fr.js +33 -72
  136. package/lib/languages/gu.d.ts +11 -0
  137. package/lib/languages/gu.js +10 -34
  138. package/lib/languages/hbo.d.ts +113 -0
  139. package/lib/languages/hbo.js +251 -0
  140. package/lib/languages/he.d.ts +80 -0
  141. package/lib/languages/he.js +41 -164
  142. package/lib/languages/hi.d.ts +11 -0
  143. package/lib/languages/hi.js +12 -7
  144. package/lib/languages/hr.d.ts +80 -0
  145. package/lib/languages/hr.js +51 -95
  146. package/lib/languages/hu.d.ts +22 -0
  147. package/lib/languages/hu.js +35 -53
  148. package/lib/languages/id.d.ts +37 -0
  149. package/lib/languages/id.js +29 -44
  150. package/lib/languages/it.d.ts +37 -0
  151. package/lib/languages/it.js +36 -52
  152. package/lib/languages/ja.d.ts +17 -0
  153. package/lib/languages/ja.js +22 -75
  154. package/lib/languages/kn.d.ts +11 -0
  155. package/lib/languages/kn.js +10 -39
  156. package/lib/languages/ko.d.ts +14 -0
  157. package/lib/languages/ko.js +17 -45
  158. package/lib/languages/lt.d.ts +70 -0
  159. package/lib/languages/lt.js +28 -63
  160. package/lib/languages/lv.d.ts +70 -0
  161. package/lib/languages/lv.js +35 -58
  162. package/lib/languages/mr.d.ts +11 -0
  163. package/lib/languages/mr.js +10 -34
  164. package/lib/languages/ms.d.ts +31 -0
  165. package/lib/languages/ms.js +24 -20
  166. package/lib/languages/nb.d.ts +12 -0
  167. package/lib/languages/nb.js +36 -56
  168. package/lib/languages/nl.d.ts +16 -0
  169. package/lib/languages/nl.js +58 -109
  170. package/lib/languages/pa.d.ts +11 -0
  171. package/lib/languages/{pa-Guru.js → pa.js} +12 -7
  172. package/lib/languages/pl.d.ts +80 -0
  173. package/lib/languages/pl.js +26 -105
  174. package/lib/languages/pt.d.ts +29 -0
  175. package/lib/languages/pt.js +29 -64
  176. package/lib/languages/ro.d.ts +158 -0
  177. package/lib/languages/ro.js +60 -167
  178. package/lib/languages/ru.d.ts +85 -0
  179. package/lib/languages/ru.js +17 -37
  180. package/lib/languages/sr-Cyrl.d.ts +80 -0
  181. package/lib/languages/sr-Cyrl.js +113 -0
  182. package/lib/languages/sr-Latn.d.ts +80 -0
  183. package/lib/languages/sr-Latn.js +54 -98
  184. package/lib/languages/sv.d.ts +14 -0
  185. package/lib/languages/sv.js +26 -63
  186. package/lib/languages/sw.d.ts +39 -0
  187. package/lib/languages/sw.js +26 -21
  188. package/lib/languages/ta.d.ts +20 -0
  189. package/lib/languages/ta.js +26 -26
  190. package/lib/languages/te.d.ts +22 -0
  191. package/lib/languages/te.js +28 -38
  192. package/lib/languages/th.d.ts +17 -0
  193. package/lib/languages/th.js +25 -31
  194. package/lib/languages/tr.d.ts +12 -0
  195. package/lib/languages/tr.js +11 -38
  196. package/lib/languages/uk.d.ts +85 -0
  197. package/lib/languages/uk.js +18 -44
  198. package/lib/languages/ur.d.ts +11 -0
  199. package/lib/languages/ur.js +12 -7
  200. package/lib/languages/vi.d.ts +72 -0
  201. package/lib/languages/vi.js +25 -71
  202. package/lib/languages/zh-Hans.d.ts +21 -0
  203. package/lib/languages/zh-Hans.js +33 -87
  204. package/lib/languages/zh-Hant.d.ts +21 -0
  205. package/lib/languages/zh-Hant.js +111 -0
  206. package/lib/n2words.d.ts +209 -0
  207. package/lib/n2words.js +474 -191
  208. package/package.json +106 -67
  209. package/dist/languages/ar.js +0 -2
  210. package/dist/languages/ar.js.map +0 -1
  211. package/dist/languages/az.js +0 -2
  212. package/dist/languages/az.js.map +0 -1
  213. package/dist/languages/bn.js +0 -2
  214. package/dist/languages/bn.js.map +0 -1
  215. package/dist/languages/cs.js +0 -2
  216. package/dist/languages/cs.js.map +0 -1
  217. package/dist/languages/da.js +0 -2
  218. package/dist/languages/da.js.map +0 -1
  219. package/dist/languages/de.js +0 -2
  220. package/dist/languages/de.js.map +0 -1
  221. package/dist/languages/el.js +0 -2
  222. package/dist/languages/el.js.map +0 -1
  223. package/dist/languages/en.js +0 -2
  224. package/dist/languages/en.js.map +0 -1
  225. package/dist/languages/es.js +0 -2
  226. package/dist/languages/es.js.map +0 -1
  227. package/dist/languages/fa.js +0 -2
  228. package/dist/languages/fa.js.map +0 -1
  229. package/dist/languages/fil.js +0 -2
  230. package/dist/languages/fil.js.map +0 -1
  231. package/dist/languages/fr-BE.js +0 -2
  232. package/dist/languages/fr-BE.js.map +0 -1
  233. package/dist/languages/fr.js +0 -2
  234. package/dist/languages/fr.js.map +0 -1
  235. package/dist/languages/gu.js +0 -2
  236. package/dist/languages/gu.js.map +0 -1
  237. package/dist/languages/he.js +0 -2
  238. package/dist/languages/he.js.map +0 -1
  239. package/dist/languages/hi.js +0 -2
  240. package/dist/languages/hi.js.map +0 -1
  241. package/dist/languages/hr.js +0 -2
  242. package/dist/languages/hr.js.map +0 -1
  243. package/dist/languages/hu.js +0 -2
  244. package/dist/languages/hu.js.map +0 -1
  245. package/dist/languages/id.js +0 -2
  246. package/dist/languages/id.js.map +0 -1
  247. package/dist/languages/it.js +0 -2
  248. package/dist/languages/it.js.map +0 -1
  249. package/dist/languages/ja.js +0 -2
  250. package/dist/languages/ja.js.map +0 -1
  251. package/dist/languages/kn.js +0 -2
  252. package/dist/languages/kn.js.map +0 -1
  253. package/dist/languages/ko.js +0 -2
  254. package/dist/languages/ko.js.map +0 -1
  255. package/dist/languages/lt.js +0 -2
  256. package/dist/languages/lt.js.map +0 -1
  257. package/dist/languages/lv.js +0 -2
  258. package/dist/languages/lv.js.map +0 -1
  259. package/dist/languages/mr.js +0 -2
  260. package/dist/languages/mr.js.map +0 -1
  261. package/dist/languages/ms.js +0 -2
  262. package/dist/languages/ms.js.map +0 -1
  263. package/dist/languages/nb.js +0 -2
  264. package/dist/languages/nb.js.map +0 -1
  265. package/dist/languages/nl.js +0 -2
  266. package/dist/languages/nl.js.map +0 -1
  267. package/dist/languages/pa-Guru.js +0 -2
  268. package/dist/languages/pa-Guru.js.map +0 -1
  269. package/dist/languages/pl.js +0 -2
  270. package/dist/languages/pl.js.map +0 -1
  271. package/dist/languages/pt.js +0 -2
  272. package/dist/languages/pt.js.map +0 -1
  273. package/dist/languages/ro.js +0 -2
  274. package/dist/languages/ro.js.map +0 -1
  275. package/dist/languages/ru.js +0 -2
  276. package/dist/languages/ru.js.map +0 -1
  277. package/dist/languages/sr-Latn.js +0 -2
  278. package/dist/languages/sr-Latn.js.map +0 -1
  279. package/dist/languages/sv.js +0 -2
  280. package/dist/languages/sv.js.map +0 -1
  281. package/dist/languages/sw.js +0 -2
  282. package/dist/languages/sw.js.map +0 -1
  283. package/dist/languages/ta.js +0 -2
  284. package/dist/languages/ta.js.map +0 -1
  285. package/dist/languages/te.js +0 -2
  286. package/dist/languages/te.js.map +0 -1
  287. package/dist/languages/th.js +0 -2
  288. package/dist/languages/th.js.map +0 -1
  289. package/dist/languages/tr.js +0 -2
  290. package/dist/languages/tr.js.map +0 -1
  291. package/dist/languages/uk.js +0 -2
  292. package/dist/languages/uk.js.map +0 -1
  293. package/dist/languages/ur.js +0 -2
  294. package/dist/languages/ur.js.map +0 -1
  295. package/dist/languages/vi.js +0 -2
  296. package/dist/languages/vi.js.map +0 -1
  297. package/dist/languages/zh-Hans.js +0 -2
  298. package/dist/languages/zh-Hans.js.map +0 -1
  299. package/typings/classes/abstract-language.d.ts +0 -144
  300. package/typings/classes/greedy-scale-language.d.ts +0 -148
  301. package/typings/classes/slavic-language.d.ts +0 -145
  302. package/typings/classes/south-asian-language.d.ts +0 -101
  303. package/typings/classes/turkic-language.d.ts +0 -42
  304. package/typings/languages/ar.d.ts +0 -93
  305. package/typings/languages/az.d.ts +0 -25
  306. package/typings/languages/bn.d.ts +0 -1
  307. package/typings/languages/cs.d.ts +0 -120
  308. package/typings/languages/da.d.ts +0 -53
  309. package/typings/languages/de.d.ts +0 -26
  310. package/typings/languages/el.d.ts +0 -11
  311. package/typings/languages/en.d.ts +0 -30
  312. package/typings/languages/es.d.ts +0 -43
  313. package/typings/languages/fa.d.ts +0 -81
  314. package/typings/languages/fil.d.ts +0 -12
  315. package/typings/languages/fr-BE.d.ts +0 -41
  316. package/typings/languages/fr.d.ts +0 -43
  317. package/typings/languages/gu.d.ts +0 -12
  318. package/typings/languages/he.d.ts +0 -197
  319. package/typings/languages/hi.d.ts +0 -1
  320. package/typings/languages/hr.d.ts +0 -110
  321. package/typings/languages/hu.d.ts +0 -37
  322. package/typings/languages/id.d.ts +0 -69
  323. package/typings/languages/it.d.ts +0 -51
  324. package/typings/languages/ja.d.ts +0 -58
  325. package/typings/languages/kn.d.ts +0 -11
  326. package/typings/languages/ko.d.ts +0 -25
  327. package/typings/languages/lt.d.ts +0 -110
  328. package/typings/languages/lv.d.ts +0 -99
  329. package/typings/languages/mr.d.ts +0 -12
  330. package/typings/languages/ms.d.ts +0 -37
  331. package/typings/languages/nb.d.ts +0 -27
  332. package/typings/languages/nl.d.ts +0 -65
  333. package/typings/languages/pa-Guru.d.ts +0 -1
  334. package/typings/languages/pl.d.ts +0 -116
  335. package/typings/languages/pt.d.ts +0 -39
  336. package/typings/languages/ro.d.ts +0 -229
  337. package/typings/languages/ru.d.ts +0 -108
  338. package/typings/languages/sr-Latn.d.ts +0 -98
  339. package/typings/languages/sv.d.ts +0 -30
  340. package/typings/languages/sw.d.ts +0 -1
  341. package/typings/languages/ta.d.ts +0 -1
  342. package/typings/languages/te.d.ts +0 -1
  343. package/typings/languages/th.d.ts +0 -1
  344. package/typings/languages/tr.d.ts +0 -46
  345. package/typings/languages/uk.d.ts +0 -117
  346. package/typings/languages/ur.d.ts +0 -1
  347. package/typings/languages/vi.d.ts +0 -116
  348. package/typings/languages/zh-Hans.d.ts +0 -57
  349. package/typings/n2words.d.ts +0 -177
@@ -1,37 +1,19 @@
1
- import AbstractLanguage from '../classes/abstract-language.js'
1
+ import { AbstractLanguage } from '../classes/abstract-language.js'
2
2
 
3
3
  /**
4
4
  * Vietnamese language converter.
5
5
  *
6
- * Converts numbers to Vietnamese words following Vietnamese number naming:
7
- * - Base-10 grouping system (trăm = hundred, nghìn = thousand, triệu = million, tỷ = billion)
8
- * - Special pronunciation rules for 5 and 15 (lăm instead of năm)
9
- * - Special pronunciation for final 1 in compound numbers (mốt instead of một)
10
- * - "Lẻ" (odd/extra) used when tens place is zero but units exist
11
- *
12
- * Key Features:
13
- * - Base number mapping for 0-19 (with special forms)
14
- * - Tens mapping (hai mươi, ba mươi, etc.)
15
- * - Group-based algorithm:
16
- * 1. Split number into groups of 3 digits
17
- * 2. For each group, build words using special pronunciation rules:
18
- * - "Mốt" instead of "một" for final 1 (e.g., 21 → hai mươi mốt)
19
- * - "Lăm" instead of "năm" for 15 and mid-group 5 (e.g., 15, 105)
20
- * - "Lẻ" prefix when tens=0 but units>0 (e.g., 101 → một trăm lẻ một)
21
- * 3. Append magnitude word (nghìn/triệu/tỷ)
22
- * 4. Join all groups with spaces
23
- * - Support for large numbers up to vigintillions
24
- *
25
- * Features:
26
- * - Natural Vietnamese number flow
27
- * - Proper handling of special cases (mốt, lăm)
28
- * - Contextual pronunciation adjustments
6
+ * Supports:
7
+ * - Special pronunciation rules (lăm for 5, mốt for final 1)
8
+ * - "Lẻ" (odd/extra) when tens place is zero
9
+ * - Vietnamese diacritical marks
29
10
  */
30
11
  export class Vietnamese extends AbstractLanguage {
31
12
  negativeWord = 'âm'
32
13
  decimalSeparatorWord = 'phẩy'
33
14
  zeroWord = 'không'
34
- base = {
15
+
16
+ belowTwentyWords = {
35
17
  0: 'không',
36
18
  1: 'một',
37
19
  2: 'hai',
@@ -54,7 +36,7 @@ export class Vietnamese extends AbstractLanguage {
54
36
  19: 'mười chín'
55
37
  }
56
38
 
57
- tens = {
39
+ twentiesWords = {
58
40
  20: 'hai mươi',
59
41
  30: 'ba mươi',
60
42
  40: 'bốn mươi',
@@ -65,7 +47,7 @@ export class Vietnamese extends AbstractLanguage {
65
47
  90: 'chín mươi'
66
48
  }
67
49
 
68
- thousands = {
50
+ scaleWords = {
69
51
  1: 'nghìn', // 10^1
70
52
  2: 'triệu', // 10^2
71
53
  3: 'tỷ', // 10^3
@@ -88,20 +70,15 @@ export class Vietnamese extends AbstractLanguage {
88
70
  20: 'Vigintillion'
89
71
  }
90
72
 
91
- /**
92
- * Convert numbers less than 100 to Vietnamese words.
93
- *
94
- * @param {number} number The number to convert (0-99).
95
- * @returns {string} The Vietnamese representation.
96
- */
73
+ /** Convert numbers less than 100 to Vietnamese words. */
97
74
  convertLess100 (number) {
98
75
  const unitsPart = number % 10
99
76
  const tensPart = number - unitsPart
100
- const tensPartText = this.tens[tensPart]
77
+ const tensPartText = this.twentiesWords[tensPart]
101
78
  if (unitsPart === 0) {
102
79
  return tensPartText
103
80
  }
104
- const unitsPartText = this.base[unitsPart]
81
+ const unitsPartText = this.belowTwentyWords[unitsPart]
105
82
  let suffix = unitsPartText
106
83
  if (unitsPart === 1) {
107
84
  suffix = 'mốt'
@@ -112,18 +89,13 @@ export class Vietnamese extends AbstractLanguage {
112
89
  return tensPartText + ' ' + suffix
113
90
  }
114
91
 
115
- /**
116
- * Convert numbers less than 1000 to Vietnamese words.
117
- *
118
- * @param {number} number The number to convert (0-999).
119
- * @returns {string} The Vietnamese representation.
120
- */
92
+ /** Convert numbers less than 1000 to Vietnamese words. */
121
93
  convertLess1000 (number) {
122
94
  const words = []
123
95
  const tensUnitsPart = number % 100
124
96
  const hundredsPart = number - tensUnitsPart
125
97
  if (hundredsPart > 0) {
126
- words.push(this.base[hundredsPart / 100], 'trăm')
98
+ words.push(this.belowTwentyWords[hundredsPart / 100], 'trăm')
127
99
  }
128
100
  if (tensUnitsPart > 0 && tensUnitsPart < 10) {
129
101
  if (words.length > 0) {
@@ -132,21 +104,16 @@ export class Vietnamese extends AbstractLanguage {
132
104
  if (tensUnitsPart === 5) {
133
105
  words.push('năm')
134
106
  } else {
135
- words.push(this.base[tensUnitsPart])
107
+ words.push(this.belowTwentyWords[tensUnitsPart])
136
108
  }
137
109
  }
138
110
  if (tensUnitsPart >= 10) {
139
- words.push(this.convertWholePart(tensUnitsPart))
111
+ words.push(this.integerToWords(tensUnitsPart))
140
112
  }
141
113
  return words.join(' ')
142
114
  }
143
115
 
144
- /**
145
- * Convert numbers greater than 1000 to Vietnamese words.
146
- *
147
- * @param {bigint} number The number to convert (>= 1000).
148
- * @returns {string} The Vietnamese representation.
149
- */
116
+ /** Convert numbers greater than 1000 to Vietnamese words. */
150
117
  convertMore1000 (number) {
151
118
  const words = []
152
119
  let division = number / 1000n
@@ -156,38 +123,25 @@ export class Vietnamese extends AbstractLanguage {
156
123
  power = power + 1
157
124
  }
158
125
  const r = number - (division * BigInt(Math.pow(1000, power)))
159
- words.push(this.convertWholePart(division), this.thousands[power])
126
+ words.push(this.integerToWords(division), this.scaleWords[power])
160
127
  if (r > 0n) {
161
128
  if (r <= 99n) {
162
129
  words.push('lẻ')
163
130
  }
164
- words.push(this.convertWholePart(r))
131
+ words.push(this.integerToWords(r))
165
132
  }
166
133
  return words.join(' ')
167
134
  }
168
135
 
169
- convertWholePart (number) {
170
- if (number < 20n) {
171
- return this.base[Number(number)]
136
+ integerToWords (integerPart) {
137
+ if (integerPart < 20n) {
138
+ return this.belowTwentyWords[Number(integerPart)]
172
139
  } else {
173
- if (number < 100n) {
174
- return this.convertLess100(Number(number))
140
+ if (integerPart < 100n) {
141
+ return this.convertLess100(Number(integerPart))
175
142
  } else {
176
- return (number < 1000n ? this.convertLess1000(Number(number)) : this.convertMore1000(number))
143
+ return (integerPart < 1000n ? this.convertLess1000(Number(integerPart)) : this.convertMore1000(integerPart))
177
144
  }
178
145
  }
179
146
  }
180
147
  }
181
-
182
- /**
183
- * Converts a number to Vietnamese cardinal (written) form.
184
- *
185
- * @param {number|string|bigint} value The number to convert.
186
- * @param {Object} [options={}] Configuration options.
187
- * @returns {string} The number expressed in Vietnamese words.
188
- * @throws {TypeError} If value is NaN or invalid type.
189
- * @throws {Error} If value is an invalid number string.
190
- */
191
- export default function convertToWords (value, options = {}) {
192
- return new Vietnamese(options).convertToWords(value)
193
- }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Simplified Chinese language converter.
3
+ *
4
+ * Supports:
5
+ * - Simplified Chinese characters (简体中文)
6
+ * - No word separators (concatenated format)
7
+ * - Optional formal (financial) vs common numerals
8
+ */
9
+ export class SimplifiedChinese extends GreedyScaleLanguage {
10
+ constructor(options?: {});
11
+ scaleWords: (string | bigint)[][];
12
+ /** Combines two word-sets according to Chinese grammar rules. */
13
+ combineWordSets(preceding: any, following: any): any;
14
+ /** Returns the number of digits in a number. */
15
+ digit(number_: any): any;
16
+ /** Counts the number of zero digits in a number. */
17
+ zeroDigit(number_: any): number;
18
+ /** Converts decimal digits to words by reading each digit individually. */
19
+ decimalDigitsToWords(decimalString: any): string[];
20
+ }
21
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
@@ -1,37 +1,28 @@
1
- import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
1
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
2
2
 
3
3
  /**
4
- * @typedef {Object} ChineseOptions
5
- * @property {boolean} [formal=true] Use formal/financial numerals (壹贰叁) vs. common numerals (一二三).
6
- */
7
-
8
- /**
9
- * Chinese language converter.
4
+ * Simplified Chinese language converter.
10
5
  *
11
- * Features:
12
- * - Concatenated number-word format (no spaces)
13
- * - Implicit zero insertion for positional values
14
- * - Decimal digits pronounced individually
15
- * - Supports both formal (financial) and common (everyday) styles
6
+ * Supports:
7
+ * - Simplified Chinese characters (简体中文)
8
+ * - No word separators (concatenated format)
9
+ * - Optional formal (financial) vs common numerals
16
10
  */
17
- export class Chinese extends GreedyScaleLanguage {
11
+ export class SimplifiedChinese extends GreedyScaleLanguage {
18
12
  negativeWord = '负'
19
13
  decimalSeparatorWord = '点'
20
14
  zeroWord = '零'
21
15
  wordSeparator = ''
22
16
 
23
- /**
24
- * Initializes the Chinese converter.
25
- *
26
- * @param {ChineseOptions} [options={}] Configuration options.
27
- */
28
- constructor ({ formal = true } = {}) {
17
+ constructor (options = {}) {
29
18
  super()
30
19
 
31
- this.formal = formal
20
+ this.setOptions({
21
+ formal: true
22
+ }, options)
32
23
 
33
- if (this.formal) {
34
- this.scaleWordPairs = [
24
+ if (this.options.formal) {
25
+ this.scaleWords = [
35
26
  [1_000_000_000_000n, '万'],
36
27
  [100_000_000n, '亿'],
37
28
  [10_000n, '万'],
@@ -50,7 +41,7 @@ export class Chinese extends GreedyScaleLanguage {
50
41
  [0n, '零']
51
42
  ]
52
43
  } else {
53
- this.scaleWordPairs = [
44
+ this.scaleWords = [
54
45
  [1_000_000_000_000n, '万'],
55
46
  [100_000_000n, '亿'],
56
47
  [10_000n, '万'],
@@ -71,95 +62,50 @@ export class Chinese extends GreedyScaleLanguage {
71
62
  }
72
63
  }
73
64
 
74
- /**
75
- * Merges two adjacent word-number pairs according to Chinese grammar rules.
76
- *
77
- * Chinese-specific rules:
78
- * - Omits '一' (or '壹' in formal style) before single digits (< 10)
79
- * - Concatenates without space
80
- * - Inserts '零' (zero) when positional values skip magnitude levels
81
- * - Multiplies when right > left, adds otherwise
82
- *
83
- * @param {Object} leftPair The left operand as `{ word: number }`.
84
- * @param {Object} rightPair The right operand as `{ word: number }`.
85
- * @returns {Object} Merged pair with combined word and resulting number.
86
- */
87
- mergeScales (leftPair, rightPair) {
88
- const leftWord = Object.keys(leftPair)[0]
89
- const leftNumber = Object.values(leftPair)[0]
90
- const rightWord = Object.keys(rightPair)[0]
91
- const rightNumber = Object.values(rightPair)[0]
65
+ /** Combines two word-sets according to Chinese grammar rules. */
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]
92
71
 
93
72
  // Implicit one: omit 1 before single digits (< 10)
94
- if (leftNumber === 1n && rightNumber < 10n) {
95
- return rightPair
73
+ if (precedingValue === 1n && followingValue < 10n) {
74
+ return following
96
75
  }
97
76
 
98
- // Multiply when right > left (scale words like 千, 万, 亿)
99
- if (rightNumber > leftNumber) {
100
- return { [`${leftWord}${rightWord}`]: leftNumber * rightNumber }
77
+ // Multiply when following > preceding (scale words like 仁, 万, 亿)
78
+ if (followingValue > precedingValue) {
79
+ return { [`${precedingWord}${followingWord}`]: precedingValue * followingValue }
101
80
  }
102
81
 
103
82
  // Insert "零" (zero) when position skip levels (e.g., 1003 = 千零三)
104
- // zeroDigit() checks if gap exists between left and right magnitude
105
- if (this.zeroDigit(leftNumber) > this.digit(rightNumber)) {
106
- return { [`${leftWord}${this.zeroWord}${rightWord}`]: leftNumber + rightNumber }
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 }
107
86
  }
108
87
 
109
88
  // Default: concatenate without zero insertion
110
- return { [`${leftWord}${rightWord}`]: leftNumber + rightNumber }
89
+ return { [`${precedingWord}${followingWord}`]: precedingValue + followingValue }
111
90
  }
112
91
 
113
- /**
114
- * Get the number of digits in a number.
115
- *
116
- * @param {bigint|number} number_ The number to count digits for.
117
- * @returns {number} The count of digits.
118
- */
92
+ /** Returns the number of digits in a number. */
119
93
  digit (number_) {
120
94
  return number_.toString().length
121
95
  }
122
96
 
123
- /**
124
- * Count the number of zeros in a number.
125
- *
126
- * @param {bigint|number} number_ The number to count zeros in.
127
- * @returns {number} The count of zero digits.
128
- */
97
+ /** Counts the number of zero digits in a number. */
129
98
  zeroDigit (number_) {
130
99
  return [...number_.toString()].filter(c => c === '0').length
131
100
  }
132
101
 
133
- /**
134
- * Convert decimal digits to words by reading each digit individually.
135
- * Overrides the default grouped behavior from AbstractLanguage.
136
- *
137
- * @param {string} decimalString The decimal digits as a string.
138
- * @returns {Array<string>} Array of individual digit words.
139
- */
102
+ /** Converts decimal digits to words by reading each digit individually. */
140
103
  decimalDigitsToWords (decimalString) {
141
104
  const words = []
142
105
  for (let i = 0; i < decimalString.length; i++) {
143
106
  const digitValue = BigInt(decimalString[i])
144
- words.push(this.convertWholePart(digitValue))
107
+ words.push(this.integerToWords(digitValue))
145
108
  }
146
109
  return words
147
110
  }
148
111
  }
149
-
150
- /**
151
- * Converts a number to Chinese cardinal (written) form.
152
- *
153
- * @param {number|string|bigint} value The number to convert.
154
- * @param {ChineseOptions} [options] Conversion options.
155
- * @returns {string} The number expressed in Chinese words.
156
- * @throws {TypeError} If value is NaN or invalid type.
157
- * @throws {Error} If value is an invalid number string.
158
- *
159
- * @example
160
- * convertToWords(42); // '肆拾贰' (formal style)
161
- * convertToWords(42, { formal: false }); // '四十二' (common style)
162
- */
163
- export default function convertToWords (value, options = {}) {
164
- return new Chinese(options).convertToWords(value)
165
- }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Traditional Chinese language converter.
3
+ *
4
+ * Supports:
5
+ * - Traditional Chinese characters (繁體中文)
6
+ * - No word separators (concatenated format)
7
+ * - Optional formal (financial) vs common numerals
8
+ */
9
+ export class TraditionalChinese extends GreedyScaleLanguage {
10
+ constructor(options?: {});
11
+ scaleWords: (string | bigint)[][];
12
+ /** Combines two word-sets with Traditional Chinese grammar rules and zero insertion. */
13
+ combineWordSets(preceding: any, following: any): any;
14
+ /** Returns the number of digits in a number. */
15
+ digit(number_: any): any;
16
+ /** Counts the number of zero digits in a number. */
17
+ zeroDigit(number_: any): number;
18
+ /** Converts decimal digits to words by reading each digit individually. */
19
+ decimalDigitsToWords(decimalString: any): string[];
20
+ }
21
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
@@ -0,0 +1,111 @@
1
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
2
+
3
+ /**
4
+ * Traditional Chinese language converter.
5
+ *
6
+ * Supports:
7
+ * - Traditional Chinese characters (繁體中文)
8
+ * - No word separators (concatenated format)
9
+ * - Optional formal (financial) vs common numerals
10
+ */
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
+ ]
62
+ }
63
+ }
64
+
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
+
72
+ // Implicit one: omit 1 before single digits (< 10)
73
+ if (precedingValue === 1n && followingValue < 10n) {
74
+ return following
75
+ }
76
+
77
+ // Multiply when following > preceding (scale words like 千, 萬, 億)
78
+ if (followingValue > precedingValue) {
79
+ return { [`${precedingWord}${followingWord}`]: precedingValue * followingValue }
80
+ }
81
+
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 }
86
+ }
87
+
88
+ // Default: concatenate without zero insertion
89
+ return { [`${precedingWord}${followingWord}`]: precedingValue + followingValue }
90
+ }
91
+
92
+ /** Returns the number of digits in a number. */
93
+ digit (number_) {
94
+ return number_.toString().length
95
+ }
96
+
97
+ /** Counts the number of zero digits in a number. */
98
+ zeroDigit (number_) {
99
+ return [...number_.toString()].filter(c => c === '0').length
100
+ }
101
+
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
110
+ }
111
+ }