n2words 4.0.0 → 5.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.
- package/CHANGELOG.md +53 -0
- package/README.md +14 -12
- package/dist/am-ET.js +2 -2
- package/dist/am-ET.umd.js +2 -2
- package/dist/am-Latn-ET.js +2 -2
- package/dist/am-Latn-ET.umd.js +2 -2
- package/dist/ar-SA.js +2 -2
- package/dist/ar-SA.umd.js +2 -2
- package/dist/az-AZ.js +2 -2
- package/dist/az-AZ.umd.js +2 -2
- package/dist/bn-BD.js +2 -2
- package/dist/bn-BD.umd.js +2 -2
- package/dist/cs-CZ.js +2 -2
- package/dist/cs-CZ.umd.js +2 -2
- package/dist/da-DK.js +2 -2
- package/dist/da-DK.umd.js +2 -2
- package/dist/de-DE.js +2 -2
- package/dist/de-DE.umd.js +2 -2
- package/dist/el-GR.js +2 -2
- package/dist/el-GR.umd.js +2 -2
- package/dist/en-AU.js +2 -2
- package/dist/en-AU.umd.js +2 -2
- package/dist/en-BD.js +2 -2
- package/dist/en-BD.umd.js +2 -2
- package/dist/en-CA.js +2 -2
- package/dist/en-CA.umd.js +2 -2
- package/dist/en-GB.js +2 -2
- package/dist/en-GB.umd.js +2 -2
- package/dist/en-GH.js +2 -2
- package/dist/en-GH.umd.js +2 -2
- package/dist/en-IE.js +2 -2
- package/dist/en-IE.umd.js +2 -2
- package/dist/en-IN.js +2 -2
- package/dist/en-IN.umd.js +2 -2
- package/dist/en-KE.js +2 -2
- package/dist/en-KE.umd.js +2 -2
- package/dist/en-MY.js +2 -2
- package/dist/en-MY.umd.js +2 -2
- package/dist/en-NG.js +2 -2
- package/dist/en-NG.umd.js +2 -2
- package/dist/en-NZ.js +2 -2
- package/dist/en-NZ.umd.js +2 -2
- package/dist/en-PH.js +2 -2
- package/dist/en-PH.umd.js +2 -2
- package/dist/en-PK.js +2 -2
- package/dist/en-PK.umd.js +2 -2
- package/dist/en-SG.js +2 -2
- package/dist/en-SG.umd.js +2 -2
- package/dist/en-US.js +2 -2
- package/dist/en-US.umd.js +2 -2
- package/dist/en-ZA.js +2 -2
- package/dist/en-ZA.umd.js +2 -2
- package/dist/es-ES.js +2 -2
- package/dist/es-ES.umd.js +2 -2
- package/dist/es-MX.js +2 -2
- package/dist/es-MX.umd.js +2 -2
- package/dist/es-US.js +2 -2
- package/dist/es-US.umd.js +2 -2
- package/dist/fa-IR.js +2 -2
- package/dist/fa-IR.umd.js +2 -2
- package/dist/fi-FI.js +2 -2
- package/dist/fi-FI.umd.js +2 -2
- package/dist/fil-PH.js +2 -2
- package/dist/fil-PH.umd.js +2 -2
- package/dist/fr-BE.js +2 -2
- package/dist/fr-BE.umd.js +2 -2
- package/dist/fr-FR.js +2 -2
- package/dist/fr-FR.umd.js +2 -2
- package/dist/gu-IN.js +2 -2
- package/dist/gu-IN.umd.js +2 -2
- package/dist/ha-NG.js +2 -2
- package/dist/ha-NG.umd.js +2 -2
- package/dist/hbo-IL.js +2 -2
- package/dist/hbo-IL.umd.js +2 -2
- package/dist/he-IL.js +2 -2
- package/dist/he-IL.umd.js +2 -2
- package/dist/hi-IN.js +2 -2
- package/dist/hi-IN.umd.js +2 -2
- package/dist/hr-HR.js +2 -2
- package/dist/hr-HR.umd.js +2 -2
- package/dist/hu-HU.js +2 -2
- package/dist/hu-HU.umd.js +2 -2
- package/dist/id-ID.js +2 -2
- package/dist/id-ID.umd.js +2 -2
- package/dist/it-IT.js +2 -2
- package/dist/it-IT.umd.js +2 -2
- package/dist/ja-JP.js +2 -2
- package/dist/ja-JP.umd.js +2 -2
- package/dist/ka-GE.js +2 -2
- package/dist/ka-GE.umd.js +2 -2
- package/dist/kn-IN.js +2 -2
- package/dist/kn-IN.umd.js +2 -2
- package/dist/ko-KR.js +2 -2
- package/dist/ko-KR.umd.js +2 -2
- package/dist/lt-LT.js +2 -2
- package/dist/lt-LT.umd.js +2 -2
- package/dist/lv-LV.js +2 -2
- package/dist/lv-LV.umd.js +2 -2
- package/dist/mr-IN.js +2 -2
- package/dist/mr-IN.umd.js +2 -2
- package/dist/ms-MY.js +2 -2
- package/dist/ms-MY.umd.js +2 -2
- package/dist/nb-NO.js +2 -2
- package/dist/nb-NO.umd.js +2 -2
- package/dist/nl-NL.js +2 -2
- package/dist/nl-NL.umd.js +2 -2
- package/dist/pa-IN.js +2 -2
- package/dist/pa-IN.umd.js +2 -2
- package/dist/pl-PL.js +2 -2
- package/dist/pl-PL.umd.js +2 -2
- package/dist/pt-BR.js +2 -0
- package/dist/pt-BR.umd.js +2 -0
- package/dist/pt-PT.js +2 -2
- package/dist/pt-PT.umd.js +2 -2
- package/dist/ro-RO.js +2 -2
- package/dist/ro-RO.umd.js +2 -2
- package/dist/ru-RU.js +2 -2
- package/dist/ru-RU.umd.js +2 -2
- package/dist/sr-Cyrl-RS.js +2 -2
- package/dist/sr-Cyrl-RS.umd.js +2 -2
- package/dist/sr-Latn-RS.js +2 -2
- package/dist/sr-Latn-RS.umd.js +2 -2
- package/dist/sv-SE.js +2 -2
- package/dist/sv-SE.umd.js +2 -2
- package/dist/sw-KE.js +2 -2
- package/dist/sw-KE.umd.js +2 -2
- package/dist/ta-IN.js +2 -2
- package/dist/ta-IN.umd.js +2 -2
- package/dist/te-IN.js +2 -2
- package/dist/te-IN.umd.js +2 -2
- package/dist/th-TH.js +2 -2
- package/dist/th-TH.umd.js +2 -2
- package/dist/tr-TR.js +2 -2
- package/dist/tr-TR.umd.js +2 -2
- package/dist/uk-UA.js +2 -2
- package/dist/uk-UA.umd.js +2 -2
- package/dist/ur-PK.js +2 -2
- package/dist/ur-PK.umd.js +2 -2
- package/dist/vi-VN.js +2 -2
- package/dist/vi-VN.umd.js +2 -2
- package/dist/yo-NG.js +2 -2
- package/dist/yo-NG.umd.js +2 -2
- package/dist/zh-Hans-CN.js +2 -2
- package/dist/zh-Hans-CN.umd.js +2 -2
- package/dist/zh-Hant-TW.js +2 -2
- package/dist/zh-Hant-TW.umd.js +2 -2
- package/package.json +53 -36
- package/src/am-ET.d.ts +3 -5
- package/src/am-ET.js +41 -16
- package/src/am-Latn-ET.d.ts +3 -5
- package/src/am-Latn-ET.js +45 -16
- package/src/ar-SA.d.ts +44 -18
- package/src/ar-SA.js +93 -40
- package/src/az-AZ.d.ts +3 -5
- package/src/az-AZ.js +58 -20
- package/src/bn-BD.d.ts +3 -5
- package/src/bn-BD.js +32 -16
- package/src/cs-CZ.d.ts +3 -6
- package/src/cs-CZ.js +66 -42
- package/src/da-DK.d.ts +3 -6
- package/src/da-DK.js +53 -48
- package/src/de-DE.d.ts +17 -11
- package/src/de-DE.js +88 -57
- package/src/el-GR.d.ts +3 -6
- package/src/el-GR.js +45 -32
- package/src/en-AU.d.ts +17 -11
- package/src/en-AU.js +56 -41
- package/src/en-BD.d.ts +17 -11
- package/src/en-BD.js +60 -41
- package/src/en-CA.d.ts +36 -18
- package/src/en-CA.js +67 -46
- package/src/en-GB.d.ts +17 -11
- package/src/en-GB.js +56 -41
- package/src/en-GH.d.ts +32 -3
- package/src/en-GH.js +104 -26
- package/src/en-IE.d.ts +17 -11
- package/src/en-IE.js +56 -41
- package/src/en-IN.d.ts +17 -11
- package/src/en-IN.js +60 -41
- package/src/en-KE.d.ts +28 -3
- package/src/en-KE.js +93 -26
- package/src/en-MY.d.ts +26 -3
- package/src/en-MY.js +91 -26
- package/src/en-NG.d.ts +17 -11
- package/src/en-NG.js +56 -41
- package/src/en-NZ.d.ts +32 -3
- package/src/en-NZ.js +85 -31
- package/src/en-PH.d.ts +32 -3
- package/src/en-PH.js +97 -26
- package/src/en-PK.d.ts +17 -11
- package/src/en-PK.js +60 -41
- package/src/en-SG.d.ts +28 -3
- package/src/en-SG.js +93 -26
- package/src/en-US.d.ts +36 -18
- package/src/en-US.js +70 -47
- package/src/en-ZA.d.ts +17 -11
- package/src/en-ZA.js +56 -41
- package/src/es-ES.d.ts +53 -21
- package/src/es-ES.js +104 -56
- package/src/es-MX.d.ts +53 -21
- package/src/es-MX.js +104 -56
- package/src/es-US.d.ts +53 -21
- package/src/es-US.js +92 -51
- package/src/fa-IR.d.ts +3 -5
- package/src/fa-IR.js +28 -13
- package/src/fi-FI.d.ts +3 -6
- package/src/fi-FI.js +47 -29
- package/src/fil-PH.d.ts +3 -5
- package/src/fil-PH.js +61 -28
- package/src/fr-BE.d.ts +31 -15
- package/src/fr-BE.js +128 -57
- package/src/fr-FR.d.ts +31 -16
- package/src/fr-FR.js +97 -60
- package/src/gu-IN.d.ts +3 -5
- package/src/gu-IN.js +31 -16
- package/src/ha-NG.d.ts +3 -5
- package/src/ha-NG.js +55 -27
- package/src/hbo-IL.d.ts +26 -12
- package/src/hbo-IL.js +92 -51
- package/src/he-IL.d.ts +17 -10
- package/src/he-IL.js +92 -50
- package/src/hi-IN.d.ts +3 -5
- package/src/hi-IN.js +30 -17
- package/src/hr-HR.d.ts +21 -10
- package/src/hr-HR.js +89 -33
- package/src/hu-HU.d.ts +3 -5
- package/src/hu-HU.js +57 -23
- package/src/id-ID.d.ts +3 -5
- package/src/id-ID.js +56 -23
- package/src/it-IT.d.ts +17 -11
- package/src/it-IT.js +74 -43
- package/src/ja-JP.d.ts +3 -6
- package/src/ja-JP.js +39 -26
- package/src/ka-GE.d.ts +3 -6
- package/src/ka-GE.js +38 -26
- package/src/kn-IN.d.ts +3 -5
- package/src/kn-IN.js +31 -16
- package/src/ko-KR.d.ts +3 -6
- package/src/ko-KR.js +34 -26
- package/src/lt-LT.d.ts +21 -11
- package/src/lt-LT.js +64 -42
- package/src/lv-LV.d.ts +21 -11
- package/src/lv-LV.js +79 -51
- package/src/mr-IN.d.ts +3 -5
- package/src/mr-IN.js +31 -16
- package/src/ms-MY.d.ts +3 -5
- package/src/ms-MY.js +58 -24
- package/src/nb-NO.d.ts +3 -6
- package/src/nb-NO.js +54 -34
- package/src/nl-NL.d.ts +41 -20
- package/src/nl-NL.js +111 -69
- package/src/pa-IN.d.ts +3 -5
- package/src/pa-IN.js +32 -16
- package/src/pl-PL.d.ts +21 -11
- package/src/pl-PL.js +69 -45
- package/src/pt-BR.d.ts +42 -0
- package/src/pt-BR.js +574 -0
- package/src/pt-PT.d.ts +17 -11
- package/src/pt-PT.js +80 -48
- package/src/ro-RO.d.ts +21 -11
- package/src/ro-RO.js +77 -39
- package/src/ru-RU.d.ts +35 -15
- package/src/ru-RU.js +100 -38
- package/src/sr-Cyrl-RS.d.ts +35 -15
- package/src/sr-Cyrl-RS.js +100 -38
- package/src/sr-Latn-RS.d.ts +35 -15
- package/src/sr-Latn-RS.js +100 -38
- package/src/sv-SE.d.ts +3 -6
- package/src/sv-SE.js +53 -34
- package/src/sw-KE.d.ts +3 -5
- package/src/sw-KE.js +50 -20
- package/src/ta-IN.d.ts +3 -5
- package/src/ta-IN.js +29 -17
- package/src/te-IN.d.ts +3 -5
- package/src/te-IN.js +31 -16
- package/src/th-TH.d.ts +3 -5
- package/src/th-TH.js +42 -19
- package/src/tr-TR.d.ts +17 -11
- package/src/tr-TR.js +63 -37
- package/src/uk-UA.d.ts +21 -10
- package/src/uk-UA.js +89 -33
- package/src/ur-PK.d.ts +3 -5
- package/src/ur-PK.js +32 -16
- package/src/utils/check-max.d.ts +26 -0
- package/src/utils/check-max.js +33 -0
- package/src/utils/expand-scientific.d.ts +0 -4
- package/src/utils/expand-scientific.js +7 -9
- package/src/utils/is-plain-object.d.ts +3 -4
- package/src/utils/is-plain-object.js +3 -4
- package/src/utils/parse-cardinal.d.ts +1 -2
- package/src/utils/parse-cardinal.js +12 -9
- package/src/utils/parse-currency.d.ts +1 -2
- package/src/utils/parse-currency.js +9 -11
- package/src/utils/parse-ordinal.d.ts +0 -1
- package/src/utils/parse-ordinal.js +9 -10
- package/src/utils/resolve-options.d.ts +17 -0
- package/src/utils/resolve-options.js +56 -0
- package/src/utils/scale.d.ts +49 -0
- package/src/utils/scale.js +65 -0
- package/src/vi-VN.d.ts +3 -6
- package/src/vi-VN.js +41 -28
- package/src/yo-NG.d.ts +3 -5
- package/src/yo-NG.js +49 -33
- package/src/zh-Hans-CN.d.ts +45 -20
- package/src/zh-Hans-CN.js +84 -31
- package/src/zh-Hant-TW.d.ts +45 -20
- package/src/zh-Hant-TW.js +85 -34
- package/src/utils/validate-options.d.ts +0 -8
- package/src/utils/validate-options.js +0 -16
package/src/en-CA.d.ts
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} CardinalOptions
|
|
6
|
+
* @property {boolean} [hundredPairing] - Use hundred-pairing for 1100-9999 (e.g., "fifteen hundred" instead of "one thousand five hundred")
|
|
7
|
+
* @property {boolean} [and] - Use "and" after hundreds and before final small numbers (default: true, Canadian/British style)
|
|
8
|
+
*/
|
|
9
|
+
/** @type {Required<CardinalOptions>} */
|
|
10
|
+
export const cardinalDefaults: Required<CardinalOptions>;
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} CurrencyOptions
|
|
13
|
+
* @property {boolean} [and] - Use "and" between dollars and cents (e.g., "one dollar and fifty cents")
|
|
14
|
+
*/
|
|
15
|
+
/** @type {Required<CurrencyOptions>} */
|
|
16
|
+
export const currencyDefaults: Required<CurrencyOptions>;
|
|
17
|
+
export type CardinalOptions = {
|
|
18
|
+
/**
|
|
19
|
+
* - Use hundred-pairing for 1100-9999 (e.g., "fifteen hundred" instead of "one thousand five hundred")
|
|
20
|
+
*/
|
|
21
|
+
hundredPairing?: boolean | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* - Use "and" after hundreds and before final small numbers (default: true, Canadian/British style)
|
|
24
|
+
*/
|
|
25
|
+
and?: boolean | undefined;
|
|
26
|
+
};
|
|
27
|
+
export type CurrencyOptions = {
|
|
28
|
+
/**
|
|
29
|
+
* - Use "and" between dollars and cents (e.g., "one dollar and fifty cents")
|
|
30
|
+
*/
|
|
31
|
+
and?: boolean | undefined;
|
|
32
|
+
};
|
|
1
33
|
/**
|
|
2
34
|
* Converts a numeric value to Canadian English words.
|
|
3
35
|
*
|
|
4
36
|
* This is the main public API. It accepts any valid numeric input
|
|
5
37
|
* (number, string, or bigint) and handles parsing internally.
|
|
6
|
-
*
|
|
7
38
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
8
|
-
* @param {
|
|
9
|
-
* @param {boolean} [options.hundredPairing=false] - Use hundred-pairing for 1100-9999 (e.g., "fifteen hundred" instead of "one thousand five hundred")
|
|
10
|
-
* @param {boolean} [options.and=true] - Use "and" after hundreds and before final small numbers (default: true, Canadian/British style)
|
|
39
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
11
40
|
* @returns {string} The number in Canadian English words
|
|
12
41
|
* @throws {TypeError} If value is not a valid numeric type
|
|
13
42
|
* @throws {Error} If value is not a valid number format
|
|
14
|
-
*
|
|
15
43
|
* @example
|
|
16
44
|
* toCardinal(42) // 'forty-two'
|
|
17
45
|
* toCardinal(101) // 'one hundred and one'
|
|
@@ -19,18 +47,13 @@
|
|
|
19
47
|
* toCardinal(1500) // 'one thousand five hundred'
|
|
20
48
|
* toCardinal(1500, { hundredPairing: true }) // 'fifteen hundred'
|
|
21
49
|
*/
|
|
22
|
-
export function toCardinal(value: number | string | bigint, options?:
|
|
23
|
-
hundredPairing?: boolean | undefined;
|
|
24
|
-
and?: boolean | undefined;
|
|
25
|
-
}): string;
|
|
50
|
+
export function toCardinal(value: number | string | bigint, options?: CardinalOptions): string;
|
|
26
51
|
/**
|
|
27
52
|
* Converts a numeric value to Canadian English ordinal words.
|
|
28
|
-
*
|
|
29
53
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
30
54
|
* @returns {string} The number as ordinal words (e.g., "first", "forty-second")
|
|
31
55
|
* @throws {TypeError} If value is not a valid numeric type
|
|
32
56
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
33
|
-
*
|
|
34
57
|
* @example
|
|
35
58
|
* toOrdinal(1) // 'first'
|
|
36
59
|
* toOrdinal(2) // 'second'
|
|
@@ -44,20 +67,15 @@ export function toCardinal(value: number | string | bigint, options?: {
|
|
|
44
67
|
export function toOrdinal(value: number | string | bigint): string;
|
|
45
68
|
/**
|
|
46
69
|
* Converts a numeric value to Canadian English currency words.
|
|
47
|
-
*
|
|
48
70
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
49
|
-
* @param {
|
|
50
|
-
* @param {boolean} [options.and=true] - Use "and" between dollars and cents (e.g., "one dollar and fifty cents")
|
|
71
|
+
* @param {CurrencyOptions} [options] - Optional configuration
|
|
51
72
|
* @returns {string} The amount in Canadian English currency words
|
|
52
73
|
* @throws {TypeError} If value is not a valid numeric type
|
|
53
74
|
* @throws {Error} If value is not a valid number format
|
|
54
|
-
*
|
|
55
75
|
* @example
|
|
56
76
|
* toCurrency(42.50) // 'forty-two dollars and fifty cents'
|
|
57
77
|
* toCurrency(1) // 'one dollar'
|
|
58
78
|
* toCurrency(0.99) // 'ninety-nine cents'
|
|
59
79
|
* toCurrency(42.50, { and: false }) // 'forty-two dollars fifty cents'
|
|
60
80
|
*/
|
|
61
|
-
export function toCurrency(value: number | string | bigint, options?:
|
|
62
|
-
and?: boolean | undefined;
|
|
63
|
-
}): string;
|
|
81
|
+
export function toCurrency(value: number | string | bigint, options?: CurrencyOptions): string;
|
package/src/en-CA.js
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
23
23
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
24
24
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
25
|
-
import {
|
|
25
|
+
import { checkMax } from './utils/check-max.js'
|
|
26
|
+
import { western } from './utils/scale.js'
|
|
27
|
+
import { resolveOptions } from './utils/resolve-options.js'
|
|
26
28
|
|
|
27
29
|
// ============================================================================
|
|
28
30
|
// VOCABULARY
|
|
@@ -37,8 +39,12 @@ const SCALES = [
|
|
|
37
39
|
'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion',
|
|
38
40
|
'decillion', 'undecillion', 'duodecillion', 'tredecillion', 'quattuordecillion',
|
|
39
41
|
'quindecillion', 'sexdecillion', 'septendecillion', 'octodecillion', 'novemdecillion',
|
|
40
|
-
'vigintillion'
|
|
42
|
+
'vigintillion',
|
|
41
43
|
]
|
|
44
|
+
|
|
45
|
+
export const cardinalMax = western(SCALES.length)
|
|
46
|
+
export const ordinalMax = western(SCALES.length)
|
|
47
|
+
export const currencyMax = western(SCALES.length)
|
|
42
48
|
const HUNDRED = 'hundred'
|
|
43
49
|
const ZERO = 'zero'
|
|
44
50
|
const NEGATIVE = 'minus'
|
|
@@ -64,12 +70,11 @@ const segmentResult = { word: '', hasHundred: false }
|
|
|
64
70
|
|
|
65
71
|
/**
|
|
66
72
|
* Builds words for a 0-999 segment.
|
|
67
|
-
*
|
|
68
73
|
* @param {number} n - Number 0-999
|
|
69
74
|
* @param {boolean} useAnd - Whether to use "and" after hundreds
|
|
70
|
-
* @returns {{ word: string, hasHundred: boolean }}
|
|
75
|
+
* @returns {{ word: string, hasHundred: boolean }} The segment words and whether a hundreds place is present
|
|
71
76
|
*/
|
|
72
|
-
function buildSegment
|
|
77
|
+
function buildSegment(n, useAnd) {
|
|
73
78
|
if (n === 0) {
|
|
74
79
|
segmentResult.word = ''
|
|
75
80
|
segmentResult.hasHundred = false
|
|
@@ -84,9 +89,11 @@ function buildSegment (n, useAnd) {
|
|
|
84
89
|
let tensOnes = ''
|
|
85
90
|
if (tens === 1) {
|
|
86
91
|
tensOnes = TEENS[ones]
|
|
87
|
-
}
|
|
92
|
+
}
|
|
93
|
+
else if (tens >= 2) {
|
|
88
94
|
tensOnes = ones > 0 ? TENS[tens] + '-' + ONES[ones] : TENS[tens]
|
|
89
|
-
}
|
|
95
|
+
}
|
|
96
|
+
else if (ones > 0) {
|
|
90
97
|
tensOnes = ONES[ones]
|
|
91
98
|
}
|
|
92
99
|
|
|
@@ -95,11 +102,13 @@ function buildSegment (n, useAnd) {
|
|
|
95
102
|
if (tensOnes) {
|
|
96
103
|
const connector = useAnd ? ' and ' : ' '
|
|
97
104
|
segmentResult.word = ONES[hundreds] + ' ' + HUNDRED + connector + tensOnes
|
|
98
|
-
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
99
107
|
segmentResult.word = ONES[hundreds] + ' ' + HUNDRED
|
|
100
108
|
}
|
|
101
109
|
segmentResult.hasHundred = true
|
|
102
|
-
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
103
112
|
segmentResult.word = tensOnes
|
|
104
113
|
segmentResult.hasHundred = false
|
|
105
114
|
}
|
|
@@ -113,13 +122,12 @@ function buildSegment (n, useAnd) {
|
|
|
113
122
|
|
|
114
123
|
/**
|
|
115
124
|
* Converts a non-negative integer to English words.
|
|
116
|
-
*
|
|
117
125
|
* @param {bigint} n - Non-negative integer to convert
|
|
118
126
|
* @param {boolean} hundredPairing - Use hundred-pairing for 1100-9999
|
|
119
127
|
* @param {boolean} useAnd - Use "and" after hundreds and before final segment
|
|
120
128
|
* @returns {string} English words
|
|
121
129
|
*/
|
|
122
|
-
function integerToWords
|
|
130
|
+
function integerToWords(n, hundredPairing, useAnd) {
|
|
123
131
|
if (n === 0n) return ZERO
|
|
124
132
|
|
|
125
133
|
// Fast path: numbers < 1000
|
|
@@ -175,12 +183,11 @@ function integerToWords (n, hundredPairing, useAnd) {
|
|
|
175
183
|
/**
|
|
176
184
|
* Builds words for numbers >= 1,000,000.
|
|
177
185
|
* Uses BigInt division for faster segment extraction.
|
|
178
|
-
*
|
|
179
186
|
* @param {bigint} n - Number >= 1,000,000
|
|
180
187
|
* @param {boolean} useAnd - Use "and" after hundreds and before final segment
|
|
181
188
|
* @returns {string} English words
|
|
182
189
|
*/
|
|
183
|
-
function buildLargeNumberWords
|
|
190
|
+
function buildLargeNumberWords(n, useAnd) {
|
|
184
191
|
// Extract segments using BigInt division
|
|
185
192
|
// Segments are stored least-significant first (index 0 = ones, 1 = thousands, etc.)
|
|
186
193
|
const segments = []
|
|
@@ -225,7 +232,8 @@ function buildLargeNumberWords (n, useAnd) {
|
|
|
225
232
|
if (i > 0) {
|
|
226
233
|
result += ' ' + SCALES[i - 1]
|
|
227
234
|
prevWasScale = true
|
|
228
|
-
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
229
237
|
prevWasScale = false
|
|
230
238
|
}
|
|
231
239
|
}
|
|
@@ -235,12 +243,11 @@ function buildLargeNumberWords (n, useAnd) {
|
|
|
235
243
|
|
|
236
244
|
/**
|
|
237
245
|
* Converts decimal digits to English words.
|
|
238
|
-
*
|
|
239
246
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
240
247
|
* @param {boolean} useAnd - Use "and" in number conversion
|
|
241
248
|
* @returns {string} English words for decimal part
|
|
242
249
|
*/
|
|
243
|
-
function decimalPartToWords
|
|
250
|
+
function decimalPartToWords(decimalPart, useAnd) {
|
|
244
251
|
let result = ''
|
|
245
252
|
|
|
246
253
|
// Handle leading zeros
|
|
@@ -261,20 +268,25 @@ function decimalPartToWords (decimalPart, useAnd) {
|
|
|
261
268
|
return result
|
|
262
269
|
}
|
|
263
270
|
|
|
271
|
+
/**
|
|
272
|
+
* @typedef {object} CardinalOptions
|
|
273
|
+
* @property {boolean} [hundredPairing] - Use hundred-pairing for 1100-9999 (e.g., "fifteen hundred" instead of "one thousand five hundred")
|
|
274
|
+
* @property {boolean} [and] - Use "and" after hundreds and before final small numbers (default: true, Canadian/British style)
|
|
275
|
+
*/
|
|
276
|
+
|
|
277
|
+
/** @type {Required<CardinalOptions>} */
|
|
278
|
+
export const cardinalDefaults = { hundredPairing: false, and: true }
|
|
279
|
+
|
|
264
280
|
/**
|
|
265
281
|
* Converts a numeric value to Canadian English words.
|
|
266
282
|
*
|
|
267
283
|
* This is the main public API. It accepts any valid numeric input
|
|
268
284
|
* (number, string, or bigint) and handles parsing internally.
|
|
269
|
-
*
|
|
270
285
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
271
|
-
* @param {
|
|
272
|
-
* @param {boolean} [options.hundredPairing=false] - Use hundred-pairing for 1100-9999 (e.g., "fifteen hundred" instead of "one thousand five hundred")
|
|
273
|
-
* @param {boolean} [options.and=true] - Use "and" after hundreds and before final small numbers (default: true, Canadian/British style)
|
|
286
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
274
287
|
* @returns {string} The number in Canadian English words
|
|
275
288
|
* @throws {TypeError} If value is not a valid numeric type
|
|
276
289
|
* @throws {Error} If value is not a valid number format
|
|
277
|
-
*
|
|
278
290
|
* @example
|
|
279
291
|
* toCardinal(42) // 'forty-two'
|
|
280
292
|
* toCardinal(101) // 'one hundred and one'
|
|
@@ -282,12 +294,14 @@ function decimalPartToWords (decimalPart, useAnd) {
|
|
|
282
294
|
* toCardinal(1500) // 'one thousand five hundred'
|
|
283
295
|
* toCardinal(1500, { hundredPairing: true }) // 'fifteen hundred'
|
|
284
296
|
*/
|
|
285
|
-
function toCardinal
|
|
286
|
-
options = validateOptions(options)
|
|
297
|
+
function toCardinal(value, options) {
|
|
287
298
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
299
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
300
|
+
// the scale builder, so both must clear the ceiling.
|
|
301
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
288
302
|
|
|
289
303
|
// Extract options with defaults (Canadian English uses "and" like British English)
|
|
290
|
-
const { hundredPairing
|
|
304
|
+
const { hundredPairing, and: useAnd } = resolveOptions(options, cardinalDefaults)
|
|
291
305
|
|
|
292
306
|
let result = ''
|
|
293
307
|
|
|
@@ -311,11 +325,10 @@ function toCardinal (value, options) {
|
|
|
311
325
|
/**
|
|
312
326
|
* Builds ordinal words for a 0-999 segment (final segment only).
|
|
313
327
|
* Returns ordinal form: "first", "twenty-third", "one hundred forty-fifth"
|
|
314
|
-
*
|
|
315
328
|
* @param {number} n - Number 0-999
|
|
316
329
|
* @returns {string} Ordinal words for this segment
|
|
317
330
|
*/
|
|
318
|
-
function buildOrdinalSegment
|
|
331
|
+
function buildOrdinalSegment(n) {
|
|
319
332
|
const ones = n % 10
|
|
320
333
|
const tens = Math.trunc(n / 10) % 10
|
|
321
334
|
const hundreds = Math.trunc(n / 100)
|
|
@@ -325,15 +338,18 @@ function buildOrdinalSegment (n) {
|
|
|
325
338
|
if (tens === 1) {
|
|
326
339
|
// Teens: 10-19 → "tenth" through "nineteenth"
|
|
327
340
|
tensOnesOrdinal = ORDINAL_TEENS[ones]
|
|
328
|
-
}
|
|
341
|
+
}
|
|
342
|
+
else if (tens >= 2) {
|
|
329
343
|
if (ones > 0) {
|
|
330
344
|
// Compound: "twenty-first", "thirty-second", etc.
|
|
331
345
|
tensOnesOrdinal = TENS[tens] + '-' + ORDINAL_ONES[ones]
|
|
332
|
-
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
333
348
|
// Round tens: "twentieth", "thirtieth", etc.
|
|
334
349
|
tensOnesOrdinal = ORDINAL_TENS[tens]
|
|
335
350
|
}
|
|
336
|
-
}
|
|
351
|
+
}
|
|
352
|
+
else if (ones > 0) {
|
|
337
353
|
// Single digit: "first", "second", etc.
|
|
338
354
|
tensOnesOrdinal = ORDINAL_ONES[ones]
|
|
339
355
|
}
|
|
@@ -343,7 +359,8 @@ function buildOrdinalSegment (n) {
|
|
|
343
359
|
if (tensOnesOrdinal) {
|
|
344
360
|
// "one hundred twenty-first"
|
|
345
361
|
return ONES[hundreds] + ' ' + HUNDRED + ' ' + tensOnesOrdinal
|
|
346
|
-
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
347
364
|
// "one hundredth", "two hundredth", etc.
|
|
348
365
|
return ONES[hundreds] + ' hundredth'
|
|
349
366
|
}
|
|
@@ -355,11 +372,10 @@ function buildOrdinalSegment (n) {
|
|
|
355
372
|
/**
|
|
356
373
|
* Converts a positive integer to ordinal words.
|
|
357
374
|
* Generates ordinals directly without string manipulation.
|
|
358
|
-
*
|
|
359
375
|
* @param {bigint} n - Positive integer to convert
|
|
360
376
|
* @returns {string} Ordinal English words
|
|
361
377
|
*/
|
|
362
|
-
function integerToOrdinal
|
|
378
|
+
function integerToOrdinal(n) {
|
|
363
379
|
// Fast path: numbers < 1000
|
|
364
380
|
if (n < 1000n) {
|
|
365
381
|
return buildOrdinalSegment(Number(n))
|
|
@@ -387,11 +403,10 @@ function integerToOrdinal (n) {
|
|
|
387
403
|
/**
|
|
388
404
|
* Builds ordinal words for numbers >= 1,000,000.
|
|
389
405
|
* All segments except the final one are cardinal; final segment is ordinal.
|
|
390
|
-
*
|
|
391
406
|
* @param {bigint} n - Number >= 1,000,000
|
|
392
407
|
* @returns {string} Ordinal English words
|
|
393
408
|
*/
|
|
394
|
-
function buildLargeOrdinal
|
|
409
|
+
function buildLargeOrdinal(n) {
|
|
395
410
|
// Extract segments (least-significant first)
|
|
396
411
|
const segments = []
|
|
397
412
|
let temp = n
|
|
@@ -425,11 +440,13 @@ function buildLargeOrdinal (n) {
|
|
|
425
440
|
if (i === 0) {
|
|
426
441
|
// Units position: use ordinal segment
|
|
427
442
|
result += buildOrdinalSegment(segment)
|
|
428
|
-
}
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
429
445
|
// Scale position with no remainder below: "one millionth"
|
|
430
446
|
result += buildSegment(segment, false).word + ' ' + SCALES[i - 1] + 'th'
|
|
431
447
|
}
|
|
432
|
-
}
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
433
450
|
// Non-final segments are cardinal
|
|
434
451
|
result += buildSegment(segment, false).word
|
|
435
452
|
if (i > 0) {
|
|
@@ -443,12 +460,10 @@ function buildLargeOrdinal (n) {
|
|
|
443
460
|
|
|
444
461
|
/**
|
|
445
462
|
* Converts a numeric value to Canadian English ordinal words.
|
|
446
|
-
*
|
|
447
463
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
448
464
|
* @returns {string} The number as ordinal words (e.g., "first", "forty-second")
|
|
449
465
|
* @throws {TypeError} If value is not a valid numeric type
|
|
450
466
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
451
|
-
*
|
|
452
467
|
* @example
|
|
453
468
|
* toOrdinal(1) // 'first'
|
|
454
469
|
* toOrdinal(2) // 'second'
|
|
@@ -459,8 +474,9 @@ function buildLargeOrdinal (n) {
|
|
|
459
474
|
* toOrdinal(101) // 'one hundred first'
|
|
460
475
|
* toOrdinal(1000) // 'one thousandth'
|
|
461
476
|
*/
|
|
462
|
-
function toOrdinal
|
|
477
|
+
function toOrdinal(value) {
|
|
463
478
|
const integerPart = parseOrdinalValue(value)
|
|
479
|
+
checkMax(integerPart, ordinalMax)
|
|
464
480
|
return integerToOrdinal(integerPart)
|
|
465
481
|
}
|
|
466
482
|
|
|
@@ -468,26 +484,31 @@ function toOrdinal (value) {
|
|
|
468
484
|
// CURRENCY: toCurrency(value, options?)
|
|
469
485
|
// ============================================================================
|
|
470
486
|
|
|
487
|
+
/**
|
|
488
|
+
* @typedef {object} CurrencyOptions
|
|
489
|
+
* @property {boolean} [and] - Use "and" between dollars and cents (e.g., "one dollar and fifty cents")
|
|
490
|
+
*/
|
|
491
|
+
|
|
492
|
+
/** @type {Required<CurrencyOptions>} */
|
|
493
|
+
export const currencyDefaults = { and: true }
|
|
494
|
+
|
|
471
495
|
/**
|
|
472
496
|
* Converts a numeric value to Canadian English currency words.
|
|
473
|
-
*
|
|
474
497
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
475
|
-
* @param {
|
|
476
|
-
* @param {boolean} [options.and=true] - Use "and" between dollars and cents (e.g., "one dollar and fifty cents")
|
|
498
|
+
* @param {CurrencyOptions} [options] - Optional configuration
|
|
477
499
|
* @returns {string} The amount in Canadian English currency words
|
|
478
500
|
* @throws {TypeError} If value is not a valid numeric type
|
|
479
501
|
* @throws {Error} If value is not a valid number format
|
|
480
|
-
*
|
|
481
502
|
* @example
|
|
482
503
|
* toCurrency(42.50) // 'forty-two dollars and fifty cents'
|
|
483
504
|
* toCurrency(1) // 'one dollar'
|
|
484
505
|
* toCurrency(0.99) // 'ninety-nine cents'
|
|
485
506
|
* toCurrency(42.50, { and: false }) // 'forty-two dollars fifty cents'
|
|
486
507
|
*/
|
|
487
|
-
function toCurrency
|
|
488
|
-
options = validateOptions(options)
|
|
508
|
+
function toCurrency(value, options) {
|
|
489
509
|
const { isNegative, dollars, cents } = parseCurrencyValue(value)
|
|
490
|
-
|
|
510
|
+
checkMax(dollars, currencyMax)
|
|
511
|
+
const { and: useAnd } = resolveOptions(options, currencyDefaults)
|
|
491
512
|
|
|
492
513
|
// Build result
|
|
493
514
|
let result = ''
|
package/src/en-GB.d.ts
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} CurrencyOptions
|
|
6
|
+
* @property {boolean} [and] - Use "and" between pounds and pence (e.g., "one pound and fifty pence")
|
|
7
|
+
*/
|
|
8
|
+
/** @type {Required<CurrencyOptions>} */
|
|
9
|
+
export const currencyDefaults: Required<CurrencyOptions>;
|
|
10
|
+
export type CurrencyOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* - Use "and" between pounds and pence (e.g., "one pound and fifty pence")
|
|
13
|
+
*/
|
|
14
|
+
and?: boolean | undefined;
|
|
15
|
+
};
|
|
1
16
|
/**
|
|
2
17
|
* Converts a numeric value to English words.
|
|
3
18
|
*
|
|
4
19
|
* This is the main public API. It accepts any valid numeric input
|
|
5
20
|
* (number, string, or bigint) and handles parsing internally.
|
|
6
|
-
*
|
|
7
21
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
8
22
|
* @returns {string} The number in English words
|
|
9
23
|
* @throws {TypeError} If value is not a valid numeric type
|
|
10
24
|
* @throws {Error} If value is not a valid number format
|
|
11
|
-
*
|
|
12
25
|
* @example
|
|
13
26
|
* toCardinal(42) // 'forty-two'
|
|
14
27
|
* toCardinal(-3.14) // 'minus three point fourteen'
|
|
@@ -17,12 +30,10 @@
|
|
|
17
30
|
export function toCardinal(value: number | string | bigint): string;
|
|
18
31
|
/**
|
|
19
32
|
* Converts a numeric value to British English ordinal words.
|
|
20
|
-
*
|
|
21
33
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
22
34
|
* @returns {string} The number as ordinal words (e.g., "first", "forty-second")
|
|
23
35
|
* @throws {TypeError} If value is not a valid numeric type
|
|
24
36
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
25
|
-
*
|
|
26
37
|
* @example
|
|
27
38
|
* toOrdinal(1) // 'first'
|
|
28
39
|
* toOrdinal(2) // 'second'
|
|
@@ -36,14 +47,11 @@ export function toCardinal(value: number | string | bigint): string;
|
|
|
36
47
|
export function toOrdinal(value: number | string | bigint): string;
|
|
37
48
|
/**
|
|
38
49
|
* Converts a numeric value to British English currency words.
|
|
39
|
-
*
|
|
40
50
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
41
|
-
* @param {
|
|
42
|
-
* @param {boolean} [options.and=true] - Use "and" between pounds and pence (e.g., "one pound and fifty pence")
|
|
51
|
+
* @param {CurrencyOptions} [options] - Optional configuration
|
|
43
52
|
* @returns {string} The amount in British English currency words
|
|
44
53
|
* @throws {TypeError} If value is not a valid numeric type
|
|
45
54
|
* @throws {Error} If value is not a valid number format
|
|
46
|
-
*
|
|
47
55
|
* @example
|
|
48
56
|
* toCurrency(42.50) // 'forty-two pounds and fifty pence'
|
|
49
57
|
* toCurrency(1) // 'one pound'
|
|
@@ -51,6 +59,4 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
51
59
|
* toCurrency(0.01) // 'one penny'
|
|
52
60
|
* toCurrency(42.50, { and: false }) // 'forty-two pounds fifty pence'
|
|
53
61
|
*/
|
|
54
|
-
export function toCurrency(value: number | string | bigint, options?:
|
|
55
|
-
and?: boolean | undefined;
|
|
56
|
-
}): string;
|
|
62
|
+
export function toCurrency(value: number | string | bigint, options?: CurrencyOptions): string;
|