n2words 1.24.0 → 3.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.
- package/CHANGELOG.md +49 -0
- package/README.md +183 -156
- package/dist/languages/am-Latn.js +3 -0
- package/dist/languages/am-Latn.js.map +1 -0
- package/dist/languages/am.js +3 -0
- package/dist/languages/am.js.map +1 -0
- package/dist/languages/ar.js +3 -2
- package/dist/languages/ar.js.map +1 -1
- package/dist/languages/az.js +3 -2
- package/dist/languages/az.js.map +1 -1
- package/dist/languages/bn.js +3 -2
- package/dist/languages/bn.js.map +1 -1
- package/dist/languages/cs.js +3 -2
- package/dist/languages/cs.js.map +1 -1
- package/dist/languages/da.js +3 -2
- package/dist/languages/da.js.map +1 -1
- package/dist/languages/de.js +3 -2
- package/dist/languages/de.js.map +1 -1
- package/dist/languages/el.js +3 -2
- package/dist/languages/el.js.map +1 -1
- package/dist/languages/en.js +3 -2
- package/dist/languages/en.js.map +1 -1
- package/dist/languages/es.js +3 -2
- package/dist/languages/es.js.map +1 -1
- package/dist/languages/fa.js +3 -2
- package/dist/languages/fa.js.map +1 -1
- package/dist/languages/fi.js +3 -0
- package/dist/languages/fi.js.map +1 -0
- package/dist/languages/fil.js +3 -2
- package/dist/languages/fil.js.map +1 -1
- package/dist/languages/fr-BE.js +3 -2
- package/dist/languages/fr-BE.js.map +1 -1
- package/dist/languages/fr.js +3 -2
- package/dist/languages/fr.js.map +1 -1
- package/dist/languages/gu.js +3 -2
- package/dist/languages/gu.js.map +1 -1
- package/dist/languages/ha.js +3 -0
- package/dist/languages/ha.js.map +1 -0
- package/dist/languages/hbo.js +3 -0
- package/dist/languages/hbo.js.map +1 -0
- package/dist/languages/he.js +3 -2
- package/dist/languages/he.js.map +1 -1
- package/dist/languages/hi.js +3 -2
- package/dist/languages/hi.js.map +1 -1
- package/dist/languages/hr.js +3 -2
- package/dist/languages/hr.js.map +1 -1
- package/dist/languages/hu.js +3 -2
- package/dist/languages/hu.js.map +1 -1
- package/dist/languages/id.js +3 -2
- package/dist/languages/id.js.map +1 -1
- package/dist/languages/it.js +3 -2
- package/dist/languages/it.js.map +1 -1
- package/dist/languages/ja.js +3 -2
- package/dist/languages/ja.js.map +1 -1
- package/dist/languages/kn.js +3 -2
- package/dist/languages/kn.js.map +1 -1
- package/dist/languages/ko.js +3 -2
- package/dist/languages/ko.js.map +1 -1
- package/dist/languages/lt.js +3 -2
- package/dist/languages/lt.js.map +1 -1
- package/dist/languages/lv.js +3 -2
- package/dist/languages/lv.js.map +1 -1
- package/dist/languages/mr.js +3 -2
- package/dist/languages/mr.js.map +1 -1
- package/dist/languages/ms.js +3 -2
- package/dist/languages/ms.js.map +1 -1
- package/dist/languages/nb.js +3 -2
- package/dist/languages/nb.js.map +1 -1
- package/dist/languages/nl.js +3 -2
- package/dist/languages/nl.js.map +1 -1
- package/dist/languages/pa.js +3 -0
- package/dist/languages/pa.js.map +1 -0
- package/dist/languages/pl.js +3 -2
- package/dist/languages/pl.js.map +1 -1
- package/dist/languages/pt.js +3 -2
- package/dist/languages/pt.js.map +1 -1
- package/dist/languages/ro.js +3 -2
- package/dist/languages/ro.js.map +1 -1
- package/dist/languages/ru.js +3 -2
- package/dist/languages/ru.js.map +1 -1
- package/dist/languages/sr-Cyrl.js +3 -0
- package/dist/languages/sr-Cyrl.js.map +1 -0
- package/dist/languages/sr-Latn.js +3 -2
- package/dist/languages/sr-Latn.js.map +1 -1
- package/dist/languages/sv.js +3 -2
- package/dist/languages/sv.js.map +1 -1
- package/dist/languages/sw.js +3 -2
- package/dist/languages/sw.js.map +1 -1
- package/dist/languages/ta.js +3 -2
- package/dist/languages/ta.js.map +1 -1
- package/dist/languages/te.js +3 -2
- package/dist/languages/te.js.map +1 -1
- package/dist/languages/th.js +3 -2
- package/dist/languages/th.js.map +1 -1
- package/dist/languages/tr.js +3 -2
- package/dist/languages/tr.js.map +1 -1
- package/dist/languages/uk.js +3 -2
- package/dist/languages/uk.js.map +1 -1
- package/dist/languages/ur.js +3 -2
- package/dist/languages/ur.js.map +1 -1
- package/dist/languages/vi.js +3 -2
- package/dist/languages/vi.js.map +1 -1
- package/dist/languages/zh-Hans.js +3 -2
- package/dist/languages/zh-Hans.js.map +1 -1
- package/dist/languages/zh-Hant.js +3 -0
- package/dist/languages/zh-Hant.js.map +1 -0
- package/dist/n2words.js +3 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.d.ts +7 -0
- package/lib/languages/am-Latn.js +164 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +164 -0
- package/lib/languages/ar.d.ts +17 -0
- package/lib/languages/ar.js +171 -209
- package/lib/languages/az.d.ts +7 -0
- package/lib/languages/az.js +167 -49
- package/lib/languages/bn.d.ts +7 -0
- package/lib/languages/bn.js +142 -123
- package/lib/languages/cs.d.ts +18 -0
- package/lib/languages/cs.js +303 -176
- package/lib/languages/da.d.ts +14 -0
- package/lib/languages/da.js +267 -139
- package/lib/languages/de.d.ts +17 -0
- package/lib/languages/de.js +310 -113
- package/lib/languages/el.d.ts +14 -0
- package/lib/languages/el.js +225 -98
- package/lib/languages/en.d.ts +17 -0
- package/lib/languages/en.js +235 -102
- package/lib/languages/es.d.ts +21 -0
- package/lib/languages/es.js +307 -125
- package/lib/languages/fa.d.ts +7 -0
- package/lib/languages/fa.js +115 -108
- package/lib/languages/fi.d.ts +14 -0
- package/lib/languages/fi.js +245 -0
- package/lib/languages/fil.d.ts +7 -0
- package/lib/languages/fil.js +199 -139
- package/lib/languages/fr-BE.d.ts +11 -0
- package/lib/languages/fr-BE.js +287 -48
- package/lib/languages/fr.d.ts +21 -0
- package/lib/languages/fr.js +343 -119
- package/lib/languages/gu.d.ts +7 -0
- package/lib/languages/gu.js +125 -144
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +230 -0
- package/lib/languages/hbo.d.ts +13 -0
- package/lib/languages/hbo.js +300 -0
- package/lib/languages/he.d.ts +13 -0
- package/lib/languages/he.js +230 -283
- package/lib/languages/hi.d.ts +7 -0
- package/lib/languages/hi.js +142 -123
- package/lib/languages/hr.d.ts +11 -0
- package/lib/languages/hr.js +190 -129
- package/lib/languages/hu.d.ts +7 -0
- package/lib/languages/hu.js +194 -133
- package/lib/languages/id.d.ts +7 -0
- package/lib/languages/id.js +167 -140
- package/lib/languages/it.d.ts +19 -0
- package/lib/languages/it.js +337 -108
- package/lib/languages/ja.d.ts +17 -0
- package/lib/languages/ja.js +224 -155
- package/lib/languages/kn.d.ts +7 -0
- package/lib/languages/kn.js +128 -62
- package/lib/languages/ko.d.ts +14 -0
- package/lib/languages/ko.js +250 -70
- package/lib/languages/lt.d.ts +18 -0
- package/lib/languages/lt.js +287 -148
- package/lib/languages/lv.d.ts +18 -0
- package/lib/languages/lv.js +291 -123
- package/lib/languages/mr.d.ts +7 -0
- package/lib/languages/mr.js +125 -144
- package/lib/languages/ms.d.ts +7 -0
- package/lib/languages/ms.js +171 -112
- package/lib/languages/nb.d.ts +14 -0
- package/lib/languages/nb.js +275 -100
- package/lib/languages/nl.d.ts +26 -0
- package/lib/languages/nl.js +307 -174
- package/lib/languages/pa.d.ts +7 -0
- package/lib/languages/pa.js +163 -0
- package/lib/languages/pl.d.ts +22 -0
- package/lib/languages/pl.js +299 -158
- package/lib/languages/pt.d.ts +17 -0
- package/lib/languages/pt.js +279 -120
- package/lib/languages/ro.d.ts +18 -0
- package/lib/languages/ro.js +214 -337
- package/lib/languages/ru.d.ts +11 -0
- package/lib/languages/ru.js +219 -95
- package/lib/languages/sr-Cyrl.d.ts +11 -0
- package/lib/languages/sr-Cyrl.js +215 -0
- package/lib/languages/sr-Latn.d.ts +11 -0
- package/lib/languages/sr-Latn.js +190 -132
- package/lib/languages/sv.d.ts +14 -0
- package/lib/languages/sv.js +280 -103
- package/lib/languages/sw.d.ts +7 -0
- package/lib/languages/sw.js +135 -103
- package/lib/languages/ta.d.ts +7 -0
- package/lib/languages/ta.js +133 -205
- package/lib/languages/te.d.ts +7 -0
- package/lib/languages/te.js +148 -213
- package/lib/languages/th.d.ts +7 -0
- package/lib/languages/th.js +139 -101
- package/lib/languages/tr.d.ts +18 -0
- package/lib/languages/tr.js +246 -66
- package/lib/languages/uk.d.ts +11 -0
- package/lib/languages/uk.js +197 -101
- package/lib/languages/ur.d.ts +7 -0
- package/lib/languages/ur.js +160 -123
- package/lib/languages/vi.d.ts +17 -0
- package/lib/languages/vi.js +287 -164
- package/lib/languages/zh-Hans.d.ts +11 -0
- package/lib/languages/zh-Hans.js +159 -142
- package/lib/languages/zh-Hant.d.ts +11 -0
- package/lib/languages/zh-Hant.js +202 -0
- package/lib/n2words.d.ts +53 -0
- package/lib/n2words.js +91 -227
- package/lib/utils/is-plain-object.d.ts +13 -0
- package/lib/utils/is-plain-object.js +17 -0
- package/lib/utils/parse-numeric.d.ts +17 -0
- package/lib/utils/parse-numeric.js +108 -0
- package/lib/utils/validate-options.d.ts +8 -0
- package/lib/utils/validate-options.js +16 -0
- package/package.json +118 -67
- package/dist/languages/pa-Guru.js +0 -2
- package/dist/languages/pa-Guru.js.map +0 -1
- package/lib/classes/abstract-language.js +0 -261
- package/lib/classes/greedy-scale-language.js +0 -195
- package/lib/classes/slavic-language.js +0 -251
- package/lib/classes/south-asian-language.js +0 -161
- package/lib/classes/turkic-language.js +0 -63
- package/lib/languages/pa-Guru.js +0 -126
- package/typings/classes/abstract-language.d.ts +0 -144
- package/typings/classes/greedy-scale-language.d.ts +0 -148
- package/typings/classes/slavic-language.d.ts +0 -145
- package/typings/classes/south-asian-language.d.ts +0 -101
- package/typings/classes/turkic-language.d.ts +0 -42
- package/typings/languages/ar.d.ts +0 -93
- package/typings/languages/az.d.ts +0 -25
- package/typings/languages/bn.d.ts +0 -1
- package/typings/languages/cs.d.ts +0 -120
- package/typings/languages/da.d.ts +0 -53
- package/typings/languages/de.d.ts +0 -26
- package/typings/languages/el.d.ts +0 -11
- package/typings/languages/en.d.ts +0 -30
- package/typings/languages/es.d.ts +0 -43
- package/typings/languages/fa.d.ts +0 -81
- package/typings/languages/fil.d.ts +0 -12
- package/typings/languages/fr-BE.d.ts +0 -41
- package/typings/languages/fr.d.ts +0 -43
- package/typings/languages/gu.d.ts +0 -12
- package/typings/languages/he.d.ts +0 -197
- package/typings/languages/hi.d.ts +0 -1
- package/typings/languages/hr.d.ts +0 -110
- package/typings/languages/hu.d.ts +0 -37
- package/typings/languages/id.d.ts +0 -69
- package/typings/languages/it.d.ts +0 -51
- package/typings/languages/ja.d.ts +0 -58
- package/typings/languages/kn.d.ts +0 -11
- package/typings/languages/ko.d.ts +0 -25
- package/typings/languages/lt.d.ts +0 -110
- package/typings/languages/lv.d.ts +0 -99
- package/typings/languages/mr.d.ts +0 -12
- package/typings/languages/ms.d.ts +0 -37
- package/typings/languages/nb.d.ts +0 -27
- package/typings/languages/nl.d.ts +0 -65
- package/typings/languages/pa-Guru.d.ts +0 -1
- package/typings/languages/pl.d.ts +0 -116
- package/typings/languages/pt.d.ts +0 -39
- package/typings/languages/ro.d.ts +0 -229
- package/typings/languages/ru.d.ts +0 -108
- package/typings/languages/sr-Latn.d.ts +0 -98
- package/typings/languages/sv.d.ts +0 -30
- package/typings/languages/sw.d.ts +0 -1
- package/typings/languages/ta.d.ts +0 -1
- package/typings/languages/te.d.ts +0 -1
- package/typings/languages/th.d.ts +0 -1
- package/typings/languages/tr.d.ts +0 -46
- package/typings/languages/uk.d.ts +0 -117
- package/typings/languages/ur.d.ts +0 -1
- package/typings/languages/vi.d.ts +0 -116
- package/typings/languages/zh-Hans.d.ts +0 -57
- package/typings/n2words.d.ts +0 -177
package/lib/languages/zh-Hans.js
CHANGED
|
@@ -1,165 +1,182 @@
|
|
|
1
|
-
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Simplified Chinese language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter for Simplified Chinese.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Myriad-based (万, 亿) grouping - 4 digits
|
|
8
|
+
* - Formal (financial) vs common numerals
|
|
9
|
+
* - Zero insertion for skipped positions
|
|
10
|
+
* - No word separators (concatenated format)
|
|
6
11
|
*/
|
|
7
12
|
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Vocabulary
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
// Common (everyday) numerals
|
|
21
|
+
const ONES_COMMON = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
|
|
22
|
+
const TEN_COMMON = '十'
|
|
23
|
+
const HUNDRED_COMMON = '百'
|
|
24
|
+
const THOUSAND_COMMON = '千'
|
|
25
|
+
|
|
26
|
+
// Formal (financial) numerals - harder to alter/forge
|
|
27
|
+
const ONES_FORMAL = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
|
28
|
+
const TEN_FORMAL = '拾'
|
|
29
|
+
const HUNDRED_FORMAL = '佰'
|
|
30
|
+
const THOUSAND_FORMAL = '仟'
|
|
31
|
+
|
|
32
|
+
// Scale words
|
|
33
|
+
const WAN_WORD = '万' // 10,000
|
|
34
|
+
const YI_WORD = '亿' // 100,000,000
|
|
35
|
+
|
|
36
|
+
const ZERO = '零'
|
|
37
|
+
const NEGATIVE = '负'
|
|
38
|
+
const DECIMAL_SEP = '点'
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Conversion Functions
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
8
44
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
45
|
+
* Convert number below 万 (10,000) to words using direct string concatenation.
|
|
16
46
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
decimalSeparatorWord = '点'
|
|
20
|
-
zeroWord = '零'
|
|
21
|
-
wordSeparator = ''
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Initializes the Chinese converter.
|
|
25
|
-
*
|
|
26
|
-
* @param {ChineseOptions} [options={}] Configuration options.
|
|
27
|
-
*/
|
|
28
|
-
constructor ({ formal = true } = {}) {
|
|
29
|
-
super()
|
|
30
|
-
|
|
31
|
-
this.formal = formal
|
|
32
|
-
|
|
33
|
-
if (this.formal) {
|
|
34
|
-
this.scaleWordPairs = [
|
|
35
|
-
[1_000_000_000_000n, '万'],
|
|
36
|
-
[100_000_000n, '亿'],
|
|
37
|
-
[10_000n, '万'],
|
|
38
|
-
[1000n, '仟'],
|
|
39
|
-
[100n, '佰'],
|
|
40
|
-
[10n, '拾'],
|
|
41
|
-
[9n, '玖'],
|
|
42
|
-
[8n, '捌'],
|
|
43
|
-
[7n, '柒'],
|
|
44
|
-
[6n, '陆'],
|
|
45
|
-
[5n, '伍'],
|
|
46
|
-
[4n, '肆'],
|
|
47
|
-
[3n, '叁'],
|
|
48
|
-
[2n, '贰'],
|
|
49
|
-
[1n, '壹'],
|
|
50
|
-
[0n, '零']
|
|
51
|
-
]
|
|
52
|
-
} else {
|
|
53
|
-
this.scaleWordPairs = [
|
|
54
|
-
[1_000_000_000_000n, '万'],
|
|
55
|
-
[100_000_000n, '亿'],
|
|
56
|
-
[10_000n, '万'],
|
|
57
|
-
[1000n, '千'],
|
|
58
|
-
[100n, '百'],
|
|
59
|
-
[10n, '十'],
|
|
60
|
-
[9n, '九'],
|
|
61
|
-
[8n, '八'],
|
|
62
|
-
[7n, '七'],
|
|
63
|
-
[6n, '六'],
|
|
64
|
-
[5n, '五'],
|
|
65
|
-
[4n, '四'],
|
|
66
|
-
[3n, '三'],
|
|
67
|
-
[2n, '二'],
|
|
68
|
-
[1n, '一'],
|
|
69
|
-
[0n, '零']
|
|
70
|
-
]
|
|
71
|
-
}
|
|
72
|
-
}
|
|
47
|
+
function convertBelowWan (value, ones, ten, hundred, thousand) {
|
|
48
|
+
if (value === 0n) return ''
|
|
73
49
|
|
|
74
|
-
|
|
75
|
-
|
|
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]
|
|
92
|
-
|
|
93
|
-
// Implicit one: omit 1 before single digits (< 10)
|
|
94
|
-
if (leftNumber === 1n && rightNumber < 10n) {
|
|
95
|
-
return rightPair
|
|
96
|
-
}
|
|
50
|
+
let result = ''
|
|
51
|
+
let needsZero = false
|
|
97
52
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
53
|
+
// Thousands (千)
|
|
54
|
+
const thousandsVal = value / 1000n
|
|
55
|
+
const thousandsRemainder = value % 1000n
|
|
56
|
+
if (thousandsVal > 0n) {
|
|
57
|
+
result = ones[Number(thousandsVal)] + thousand
|
|
58
|
+
needsZero = thousandsRemainder > 0n && thousandsRemainder < 100n
|
|
59
|
+
}
|
|
102
60
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
61
|
+
// Hundreds (百)
|
|
62
|
+
const hundredsVal = thousandsRemainder / 100n
|
|
63
|
+
const hundredsRemainder = thousandsRemainder % 100n
|
|
64
|
+
if (hundredsVal > 0n) {
|
|
65
|
+
if (needsZero) result += ZERO
|
|
66
|
+
result += ones[Number(hundredsVal)] + hundred
|
|
67
|
+
needsZero = hundredsRemainder > 0n && hundredsRemainder < 10n
|
|
68
|
+
} else if (thousandsVal > 0n && hundredsRemainder > 0n) {
|
|
69
|
+
needsZero = true
|
|
70
|
+
}
|
|
108
71
|
|
|
109
|
-
|
|
110
|
-
|
|
72
|
+
// Tens (十)
|
|
73
|
+
const tensVal = hundredsRemainder / 10n
|
|
74
|
+
const onesVal = hundredsRemainder % 10n
|
|
75
|
+
if (tensVal > 0n) {
|
|
76
|
+
if (needsZero) result += ZERO
|
|
77
|
+
result += ones[Number(tensVal)] + ten
|
|
78
|
+
needsZero = false
|
|
79
|
+
} else if ((hundredsVal > 0n || thousandsVal > 0n) && onesVal > 0n) {
|
|
80
|
+
needsZero = true
|
|
111
81
|
}
|
|
112
82
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* @returns {number} The count of digits.
|
|
118
|
-
*/
|
|
119
|
-
digit (number_) {
|
|
120
|
-
return number_.toString().length
|
|
83
|
+
// Ones
|
|
84
|
+
if (onesVal > 0n) {
|
|
85
|
+
if (needsZero) result += ZERO
|
|
86
|
+
result += ones[Number(onesVal)]
|
|
121
87
|
}
|
|
122
88
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
89
|
+
return result
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convert number below 亿 (100 million) to words.
|
|
94
|
+
*/
|
|
95
|
+
function convertBelowYi (value, ones, ten, hundred, thousand) {
|
|
96
|
+
if (value === 0n) return ''
|
|
97
|
+
|
|
98
|
+
if (value >= 10_000n) {
|
|
99
|
+
const wanValue = value / 10_000n
|
|
100
|
+
const wanRemainder = value % 10_000n
|
|
101
|
+
|
|
102
|
+
let result = convertBelowWan(wanValue, ones, ten, hundred, thousand) + WAN_WORD
|
|
103
|
+
|
|
104
|
+
if (wanRemainder > 0n) {
|
|
105
|
+
const needsZero = (wanValue % 10n === 0n) || (wanRemainder < 1000n)
|
|
106
|
+
if (needsZero) result += ZERO
|
|
107
|
+
result += convertBelowWan(wanRemainder, ones, ten, hundred, thousand)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return result
|
|
131
111
|
}
|
|
132
112
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
113
|
+
return convertBelowWan(value, ones, ten, hundred, thousand)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function integerToWords (n, formal = true) {
|
|
117
|
+
if (n === 0n) return ZERO
|
|
118
|
+
|
|
119
|
+
const ones = formal ? ONES_FORMAL : ONES_COMMON
|
|
120
|
+
const ten = formal ? TEN_FORMAL : TEN_COMMON
|
|
121
|
+
const hundred = formal ? HUNDRED_FORMAL : HUNDRED_COMMON
|
|
122
|
+
const thousand = formal ? THOUSAND_FORMAL : THOUSAND_COMMON
|
|
123
|
+
|
|
124
|
+
// Handle numbers >= 亿 (100 million)
|
|
125
|
+
if (n >= 100_000_000n) {
|
|
126
|
+
const yiValue = n / 100_000_000n
|
|
127
|
+
const yiRemainder = n % 100_000_000n
|
|
128
|
+
|
|
129
|
+
let result = convertBelowYi(yiValue, ones, ten, hundred, thousand) + YI_WORD
|
|
130
|
+
|
|
131
|
+
if (yiRemainder > 0n) {
|
|
132
|
+
if (yiRemainder < 10_000_000n) result += ZERO
|
|
133
|
+
result += convertBelowYi(yiRemainder, ones, ten, hundred, thousand)
|
|
145
134
|
}
|
|
146
|
-
|
|
135
|
+
|
|
136
|
+
return result
|
|
147
137
|
}
|
|
138
|
+
|
|
139
|
+
return convertBelowYi(n, ones, ten, hundred, thousand)
|
|
148
140
|
}
|
|
149
141
|
|
|
150
142
|
/**
|
|
151
|
-
*
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
143
|
+
* Convert decimal digits to words using direct concatenation.
|
|
144
|
+
*/
|
|
145
|
+
function decimalDigitsToWords (decimalString, ones) {
|
|
146
|
+
let result = ''
|
|
147
|
+
for (let i = 0; i < decimalString.length; i++) {
|
|
148
|
+
result += ones[Number(decimalString[i])]
|
|
149
|
+
}
|
|
150
|
+
return result
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Converts a numeric value to Simplified Chinese words.
|
|
158
155
|
*
|
|
159
|
-
* @
|
|
160
|
-
*
|
|
161
|
-
*
|
|
156
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
157
|
+
* @param {Object} [options] - Optional configuration
|
|
158
|
+
* @param {boolean} [options.formal=true] - Use formal/financial numerals
|
|
159
|
+
* @returns {string} The number in Simplified Chinese words
|
|
162
160
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
function toWords (value, options) {
|
|
162
|
+
options = validateOptions(options)
|
|
163
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
164
|
+
const formal = options.formal !== false // Default to true
|
|
165
|
+
|
|
166
|
+
let result = isNegative ? NEGATIVE : ''
|
|
167
|
+
|
|
168
|
+
result += integerToWords(integerPart, formal)
|
|
169
|
+
|
|
170
|
+
if (decimalPart) {
|
|
171
|
+
const ones = formal ? ONES_FORMAL : ONES_COMMON
|
|
172
|
+
result += DECIMAL_SEP + decimalDigitsToWords(decimalPart, ones)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return result
|
|
165
176
|
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Exports
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
export { toWords }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a numeric value to Traditional Chinese words.
|
|
3
|
+
*
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @param {Object} [options] - Optional configuration
|
|
6
|
+
* @param {boolean} [options.formal=true] - Use formal/financial numerals
|
|
7
|
+
* @returns {string} The number in Traditional Chinese words
|
|
8
|
+
*/
|
|
9
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
10
|
+
formal?: boolean | undefined;
|
|
11
|
+
}): string;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traditional Chinese language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter for Traditional Chinese.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Myriad-based (萬, 億) grouping - 4 digits
|
|
8
|
+
* - Formal (financial) vs common numerals
|
|
9
|
+
* - Zero insertion for skipped positions
|
|
10
|
+
* - No word separators (concatenated format)
|
|
11
|
+
*
|
|
12
|
+
* Differences from Simplified:
|
|
13
|
+
* - Different character forms (e.g., 負/负, 點/点, 億/亿, 萬/万)
|
|
14
|
+
* - Some formal numerals differ (參/叁, 貳/贰, 陸/陆)
|
|
15
|
+
*/
|
|
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
|
|
69
|
+
}
|
|
70
|
+
|
|
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
|
+
}
|
|
84
|
+
|
|
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
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Ones
|
|
99
|
+
if (onesVal > 0n) {
|
|
100
|
+
if (needsZero) {
|
|
101
|
+
parts.push(ZERO)
|
|
102
|
+
}
|
|
103
|
+
parts.push(ones[Number(onesVal)])
|
|
104
|
+
}
|
|
105
|
+
|
|
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))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return parts.join('')
|
|
135
|
+
}
|
|
136
|
+
|
|
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))
|
|
156
|
+
}
|
|
157
|
+
|
|
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)])
|
|
166
|
+
}
|
|
167
|
+
return words
|
|
168
|
+
}
|
|
169
|
+
|
|
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
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
result += integerToWords(integerPart, formal)
|
|
190
|
+
|
|
191
|
+
if (decimalPart) {
|
|
192
|
+
result += DECIMAL_SEP + decimalDigitsToWords(decimalPart, formal).join('')
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return result
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ============================================================================
|
|
199
|
+
// Exports
|
|
200
|
+
// ============================================================================
|
|
201
|
+
|
|
202
|
+
export { toWords }
|
package/lib/n2words.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
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 kn } from './languages/kn.js';
|
|
28
|
+
import { toWords as ko } from './languages/ko.js';
|
|
29
|
+
import { toWords as lt } from './languages/lt.js';
|
|
30
|
+
import { toWords as lv } from './languages/lv.js';
|
|
31
|
+
import { toWords as mr } from './languages/mr.js';
|
|
32
|
+
import { toWords as ms } from './languages/ms.js';
|
|
33
|
+
import { toWords as nb } from './languages/nb.js';
|
|
34
|
+
import { toWords as nl } from './languages/nl.js';
|
|
35
|
+
import { toWords as pa } from './languages/pa.js';
|
|
36
|
+
import { toWords as pl } from './languages/pl.js';
|
|
37
|
+
import { toWords as pt } from './languages/pt.js';
|
|
38
|
+
import { toWords as ro } from './languages/ro.js';
|
|
39
|
+
import { toWords as ru } from './languages/ru.js';
|
|
40
|
+
import { toWords as srCyrl } from './languages/sr-Cyrl.js';
|
|
41
|
+
import { toWords as srLatn } from './languages/sr-Latn.js';
|
|
42
|
+
import { toWords as sv } from './languages/sv.js';
|
|
43
|
+
import { toWords as sw } from './languages/sw.js';
|
|
44
|
+
import { toWords as ta } from './languages/ta.js';
|
|
45
|
+
import { toWords as te } from './languages/te.js';
|
|
46
|
+
import { toWords as th } from './languages/th.js';
|
|
47
|
+
import { toWords as tr } from './languages/tr.js';
|
|
48
|
+
import { toWords as uk } from './languages/uk.js';
|
|
49
|
+
import { toWords as ur } from './languages/ur.js';
|
|
50
|
+
import { toWords as vi } from './languages/vi.js';
|
|
51
|
+
import { toWords as zhHans } from './languages/zh-Hans.js';
|
|
52
|
+
import { toWords as zhHant } from './languages/zh-Hant.js';
|
|
53
|
+
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, kn, ko, lt, lv, mr, ms, nb, nl, pa, pl, pt, ro, ru, srCyrl, srLatn, sv, sw, ta, te, th, tr, uk, ur, vi, zhHans, zhHant };
|