n2words 5.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 +128 -42
- package/README.md +6 -4
- 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 -2
- package/dist/pt-BR.umd.js +2 -2
- 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 +31 -22
- 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 +22 -11
- package/src/pt-BR.js +93 -53
- 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/ar-SA.d.ts
CHANGED
|
@@ -1,46 +1,72 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} CardinalOptions
|
|
6
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
7
|
+
* @property {string} [negativeWord] - Custom word for negative numbers
|
|
8
|
+
*/
|
|
9
|
+
/** @type {Required<CardinalOptions>} */
|
|
10
|
+
export const cardinalDefaults: Required<CardinalOptions>;
|
|
11
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
12
|
+
export const cardinalValues: {
|
|
13
|
+
gender: ReadonlyArray<Required<CardinalOptions>["gender"]>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} OrdinalOptions
|
|
17
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
18
|
+
*/
|
|
19
|
+
/** @type {Required<OrdinalOptions>} */
|
|
20
|
+
export const ordinalDefaults: Required<OrdinalOptions>;
|
|
21
|
+
/** @type {{ gender: ReadonlyArray<Required<OrdinalOptions>['gender']> }} */
|
|
22
|
+
export const ordinalValues: {
|
|
23
|
+
gender: ReadonlyArray<Required<OrdinalOptions>["gender"]>;
|
|
24
|
+
};
|
|
25
|
+
export type CardinalOptions = {
|
|
26
|
+
/**
|
|
27
|
+
* - Grammatical gender
|
|
28
|
+
*/
|
|
29
|
+
gender?: "feminine" | "masculine" | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* - Custom word for negative numbers
|
|
32
|
+
*/
|
|
33
|
+
negativeWord?: string | undefined;
|
|
34
|
+
};
|
|
35
|
+
export type OrdinalOptions = {
|
|
36
|
+
/**
|
|
37
|
+
* - Grammatical gender
|
|
38
|
+
*/
|
|
39
|
+
gender?: "feminine" | "masculine" | undefined;
|
|
40
|
+
};
|
|
1
41
|
/**
|
|
2
42
|
* Converts a numeric value to Arabic words.
|
|
3
|
-
*
|
|
4
43
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
-
* @param {
|
|
6
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
7
|
-
* @param {string} [options.negativeWord] - Custom word for negative numbers
|
|
44
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
8
45
|
* @returns {string} The number in Arabic words
|
|
9
|
-
*
|
|
10
46
|
* @example
|
|
11
47
|
* toCardinal(1) // 'واحد'
|
|
12
48
|
* toCardinal(1, {gender: 'feminine'}) // 'واحدة'
|
|
13
49
|
*/
|
|
14
|
-
export function toCardinal(value: number | string | bigint, options?:
|
|
15
|
-
gender?: "masculine" | "feminine" | undefined;
|
|
16
|
-
negativeWord?: string | undefined;
|
|
17
|
-
}): string;
|
|
50
|
+
export function toCardinal(value: number | string | bigint, options?: CardinalOptions): string;
|
|
18
51
|
/**
|
|
19
52
|
* Converts a numeric value to Arabic ordinal words.
|
|
20
|
-
*
|
|
21
53
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
54
|
+
* @param {OrdinalOptions} [options] - Optional configuration
|
|
24
55
|
* @returns {string} The number as ordinal words
|
|
25
56
|
* @throws {TypeError} If value is not a valid numeric type
|
|
26
57
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
27
|
-
*
|
|
28
58
|
* @example
|
|
29
59
|
* toOrdinal(1) // 'الأول'
|
|
30
60
|
* toOrdinal(1, {gender: 'feminine'}) // 'الأولى'
|
|
31
61
|
* toOrdinal(3) // 'الثالث'
|
|
32
62
|
*/
|
|
33
|
-
export function toOrdinal(value: number | string | bigint, options?:
|
|
34
|
-
gender?: "masculine" | "feminine" | undefined;
|
|
35
|
-
}): string;
|
|
63
|
+
export function toOrdinal(value: number | string | bigint, options?: OrdinalOptions): string;
|
|
36
64
|
/**
|
|
37
65
|
* Converts a numeric value to Arabic currency words (Saudi Riyal).
|
|
38
|
-
*
|
|
39
66
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
40
67
|
* @returns {string} The amount in Arabic currency words
|
|
41
68
|
* @throws {TypeError} If value is not a valid numeric type
|
|
42
69
|
* @throws {Error} If value is not a valid number format
|
|
43
|
-
*
|
|
44
70
|
* @example
|
|
45
71
|
* toCurrency(42.50) // 'اثنان وأربعون ريالاً وخمسون هللة'
|
|
46
72
|
* toCurrency(1) // 'ريال واحد'
|
package/src/ar-SA.js
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
16
16
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
17
17
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
18
|
-
import {
|
|
18
|
+
import { checkMax } from './utils/check-max.js'
|
|
19
|
+
import { western } from './utils/scale.js'
|
|
20
|
+
import { resolveOptions } from './utils/resolve-options.js'
|
|
19
21
|
|
|
20
22
|
// ============================================================================
|
|
21
23
|
// Vocabulary
|
|
@@ -26,6 +28,11 @@ const HUNDREDS = ['', 'مائة', 'مئتان', 'ثلاثمائة', 'أربعم
|
|
|
26
28
|
|
|
27
29
|
// Magnitude words with three forms: singular, appended (tanween), plural
|
|
28
30
|
const SCALE_WORDS = ['مائة', 'ألف', 'مليون', 'مليار', 'تريليون', 'كوادريليون', 'كوينتليون', 'سكستيليون']
|
|
31
|
+
|
|
32
|
+
// Supported magnitude ceiling (checked at the public entry points), derived from the scale table.
|
|
33
|
+
export const cardinalMax = western(SCALE_WORDS.length - 1)
|
|
34
|
+
export const ordinalMax = western(SCALE_WORDS.length - 1)
|
|
35
|
+
export const currencyMax = western(SCALE_WORDS.length - 1)
|
|
29
36
|
const SCALE_APPENDED = ['', 'ألفاً', 'مليوناً', 'ملياراً', 'تريليوناً', 'كوادريليوناً', 'كوينتليوناً', 'سكستيليوناً']
|
|
30
37
|
const SCALE_PLURAL = ['', 'آلاف', 'ملايين', 'مليارات', 'تريليونات', 'كوادريليونات', 'كوينتليونات', 'سكستيليونات']
|
|
31
38
|
|
|
@@ -76,8 +83,13 @@ const HALALA_PLURAL_11 = 'هللة'
|
|
|
76
83
|
* Convert a 3-digit group to words.
|
|
77
84
|
* Returns a clean string with no leading/trailing spaces.
|
|
78
85
|
* Arabic "و" (and) is attached to following word: "مائة وخمسة" not "مائة و خمسة"
|
|
86
|
+
* @param {number} groupNumber - The 3-digit group value (0-999)
|
|
87
|
+
* @param {number} groupLevel - The scale level of this group (0 = units, 1 = thousands, ...)
|
|
88
|
+
* @param {bigint} fullNumber - The full number being converted
|
|
89
|
+
* @param {string[]} ones - Gender-specific ones words (1-19)
|
|
90
|
+
* @returns {string} The group rendered as words
|
|
79
91
|
*/
|
|
80
|
-
function segmentToWords
|
|
92
|
+
function segmentToWords(groupNumber, groupLevel, fullNumber, ones) {
|
|
81
93
|
const tensValue = groupNumber % 100
|
|
82
94
|
const hundredsDigit = Math.trunc(groupNumber / 100)
|
|
83
95
|
let result = ''
|
|
@@ -86,7 +98,8 @@ function segmentToWords (groupNumber, groupLevel, fullNumber, ones) {
|
|
|
86
98
|
if (hundredsDigit > 0) {
|
|
87
99
|
if (tensValue === 0 && hundredsDigit === 2) {
|
|
88
100
|
result = DUAL[0]
|
|
89
|
-
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
90
103
|
const hundredsWord = HUNDREDS[hundredsDigit]
|
|
91
104
|
if (hundredsWord) {
|
|
92
105
|
result = hundredsWord
|
|
@@ -105,15 +118,19 @@ function segmentToWords (groupNumber, groupLevel, fullNumber, ones) {
|
|
|
105
118
|
const pow = Math.trunc(Math.log10(numValue))
|
|
106
119
|
if (pow % 3 === 0 && fullNumber === BigInt(2 * Math.pow(10, pow))) {
|
|
107
120
|
result += (groupNumber === 2 ? DUAL[groupLevel] : DUAL_APPENDED[groupLevel])
|
|
108
|
-
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
109
123
|
result += DUAL[groupLevel]
|
|
110
124
|
}
|
|
111
|
-
}
|
|
125
|
+
}
|
|
126
|
+
else if (tensValue === 1 && groupLevel > 0) {
|
|
112
127
|
result += SCALE_WORDS[groupLevel]
|
|
113
|
-
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
114
130
|
result += ones[tensValue - 1]
|
|
115
131
|
}
|
|
116
|
-
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
117
134
|
const onesDigit = tensValue % 10
|
|
118
135
|
const tensIndex = Math.trunc(tensValue / 10) - 2
|
|
119
136
|
|
|
@@ -127,7 +144,13 @@ function segmentToWords (groupNumber, groupLevel, fullNumber, ones) {
|
|
|
127
144
|
return result
|
|
128
145
|
}
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Convert a non-negative integer to Arabic words.
|
|
149
|
+
* @param {bigint} n - The non-negative integer to convert
|
|
150
|
+
* @param {string} gender - 'masculine' or 'feminine'
|
|
151
|
+
* @returns {string} The number rendered as words
|
|
152
|
+
*/
|
|
153
|
+
function integerToWords(n, gender) {
|
|
131
154
|
if (n === 0n) return ZERO
|
|
132
155
|
|
|
133
156
|
const ones = gender === 'feminine' ? ONES_FEM : ONES_MASC
|
|
@@ -151,9 +174,11 @@ function integerToWords (n, gender) {
|
|
|
151
174
|
const remainder = numberToProcess % 100
|
|
152
175
|
if (remainder === 1) {
|
|
153
176
|
groupText += ' ' + SCALE_WORDS[group]
|
|
154
|
-
}
|
|
177
|
+
}
|
|
178
|
+
else if (numberToProcess >= 3 && numberToProcess <= 10) {
|
|
155
179
|
groupText += ' ' + SCALE_PLURAL[group]
|
|
156
|
-
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
157
182
|
groupText += ' ' + (groups.length > 0 ? SCALE_APPENDED[group] : SCALE_WORDS[group])
|
|
158
183
|
}
|
|
159
184
|
}
|
|
@@ -177,7 +202,13 @@ function integerToWords (n, gender) {
|
|
|
177
202
|
return result
|
|
178
203
|
}
|
|
179
204
|
|
|
180
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Convert the fractional digits of a number to Arabic words.
|
|
207
|
+
* @param {string} decimalPart - The decimal digits (after the separator)
|
|
208
|
+
* @param {string} gender - 'masculine' or 'feminine'
|
|
209
|
+
* @returns {string} The decimal part rendered as words
|
|
210
|
+
*/
|
|
211
|
+
function decimalPartToWords(decimalPart, gender) {
|
|
181
212
|
const parts = []
|
|
182
213
|
let i = 0
|
|
183
214
|
|
|
@@ -194,28 +225,33 @@ function decimalPartToWords (decimalPart, gender) {
|
|
|
194
225
|
return parts.join(' ')
|
|
195
226
|
}
|
|
196
227
|
|
|
228
|
+
/**
|
|
229
|
+
* @typedef {object} CardinalOptions
|
|
230
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
231
|
+
* @property {string} [negativeWord] - Custom word for negative numbers
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
/** @type {Required<CardinalOptions>} */
|
|
235
|
+
export const cardinalDefaults = { gender: 'masculine', negativeWord: NEGATIVE }
|
|
236
|
+
|
|
237
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
238
|
+
export const cardinalValues = { gender: ['masculine', 'feminine'] }
|
|
239
|
+
|
|
197
240
|
/**
|
|
198
241
|
* Converts a numeric value to Arabic words.
|
|
199
|
-
*
|
|
200
242
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
201
|
-
* @param {
|
|
202
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
203
|
-
* @param {string} [options.negativeWord] - Custom word for negative numbers
|
|
243
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
204
244
|
* @returns {string} The number in Arabic words
|
|
205
|
-
*
|
|
206
245
|
* @example
|
|
207
246
|
* toCardinal(1) // 'واحد'
|
|
208
247
|
* toCardinal(1, {gender: 'feminine'}) // 'واحدة'
|
|
209
248
|
*/
|
|
210
|
-
function toCardinal
|
|
211
|
-
options = validateOptions(options)
|
|
249
|
+
function toCardinal(value, options) {
|
|
212
250
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
251
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
213
252
|
|
|
214
253
|
// Apply option defaults
|
|
215
|
-
const {
|
|
216
|
-
gender = 'masculine',
|
|
217
|
-
negativeWord = NEGATIVE
|
|
218
|
-
} = options
|
|
254
|
+
const { gender, negativeWord } = resolveOptions(options, cardinalDefaults, cardinalValues)
|
|
219
255
|
|
|
220
256
|
const parts = []
|
|
221
257
|
|
|
@@ -241,12 +277,11 @@ function toCardinal (value, options) {
|
|
|
241
277
|
* Gets the Arabic ordinal form for a number.
|
|
242
278
|
*
|
|
243
279
|
* Arabic ordinals 1-10 have special forms, beyond 10 use cardinal + position.
|
|
244
|
-
*
|
|
245
280
|
* @param {bigint} n - Positive integer to convert
|
|
246
281
|
* @param {string} gender - 'masculine' or 'feminine'
|
|
247
282
|
* @returns {string} Arabic ordinal words
|
|
248
283
|
*/
|
|
249
|
-
function integerToOrdinal
|
|
284
|
+
function integerToOrdinal(n, gender) {
|
|
250
285
|
const ordinals = gender === 'feminine' ? ORDINAL_FEM : ORDINAL_MASC
|
|
251
286
|
|
|
252
287
|
// Special ordinals for 1-10
|
|
@@ -259,25 +294,33 @@ function integerToOrdinal (n, gender) {
|
|
|
259
294
|
return 'ال' + cardinal
|
|
260
295
|
}
|
|
261
296
|
|
|
297
|
+
/**
|
|
298
|
+
* @typedef {object} OrdinalOptions
|
|
299
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
300
|
+
*/
|
|
301
|
+
|
|
302
|
+
/** @type {Required<OrdinalOptions>} */
|
|
303
|
+
export const ordinalDefaults = { gender: 'masculine' }
|
|
304
|
+
|
|
305
|
+
/** @type {{ gender: ReadonlyArray<Required<OrdinalOptions>['gender']> }} */
|
|
306
|
+
export const ordinalValues = { gender: ['masculine', 'feminine'] }
|
|
307
|
+
|
|
262
308
|
/**
|
|
263
309
|
* Converts a numeric value to Arabic ordinal words.
|
|
264
|
-
*
|
|
265
310
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
266
|
-
* @param {
|
|
267
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
311
|
+
* @param {OrdinalOptions} [options] - Optional configuration
|
|
268
312
|
* @returns {string} The number as ordinal words
|
|
269
313
|
* @throws {TypeError} If value is not a valid numeric type
|
|
270
314
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
271
|
-
*
|
|
272
315
|
* @example
|
|
273
316
|
* toOrdinal(1) // 'الأول'
|
|
274
317
|
* toOrdinal(1, {gender: 'feminine'}) // 'الأولى'
|
|
275
318
|
* toOrdinal(3) // 'الثالث'
|
|
276
319
|
*/
|
|
277
|
-
function toOrdinal
|
|
278
|
-
options = validateOptions(options)
|
|
320
|
+
function toOrdinal(value, options) {
|
|
279
321
|
const integerPart = parseOrdinalValue(value)
|
|
280
|
-
|
|
322
|
+
checkMax(integerPart, ordinalMax)
|
|
323
|
+
const { gender } = resolveOptions(options, ordinalDefaults, ordinalValues)
|
|
281
324
|
return integerToOrdinal(integerPart, gender)
|
|
282
325
|
}
|
|
283
326
|
|
|
@@ -293,15 +336,22 @@ function toOrdinal (value, options) {
|
|
|
293
336
|
* - 2: dual
|
|
294
337
|
* - 3-10: plural form 1
|
|
295
338
|
* - 11+: plural form 2 (different ending)
|
|
339
|
+
* @param {bigint} n - The riyal count
|
|
340
|
+
* @returns {string} The appropriate riyal word form
|
|
296
341
|
*/
|
|
297
|
-
function getRiyalForm
|
|
342
|
+
function getRiyalForm(n) {
|
|
298
343
|
if (n === 1n) return RIYAL_SINGULAR
|
|
299
344
|
if (n === 2n) return RIYAL_DUAL
|
|
300
345
|
if (n >= 3n && n <= 10n) return RIYAL_PLURAL_3_10
|
|
301
346
|
return RIYAL_PLURAL_11
|
|
302
347
|
}
|
|
303
348
|
|
|
304
|
-
|
|
349
|
+
/**
|
|
350
|
+
* Gets the appropriate halala word form based on number.
|
|
351
|
+
* @param {bigint} n - The halala count
|
|
352
|
+
* @returns {string} The appropriate halala word form
|
|
353
|
+
*/
|
|
354
|
+
function getHalalaForm(n) {
|
|
305
355
|
if (n === 1n) return HALALA_SINGULAR
|
|
306
356
|
if (n === 2n) return HALALA_DUAL
|
|
307
357
|
if (n >= 3n && n <= 10n) return HALALA_PLURAL_3_10
|
|
@@ -310,19 +360,18 @@ function getHalalaForm (n) {
|
|
|
310
360
|
|
|
311
361
|
/**
|
|
312
362
|
* Converts a numeric value to Arabic currency words (Saudi Riyal).
|
|
313
|
-
*
|
|
314
363
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
315
364
|
* @returns {string} The amount in Arabic currency words
|
|
316
365
|
* @throws {TypeError} If value is not a valid numeric type
|
|
317
366
|
* @throws {Error} If value is not a valid number format
|
|
318
|
-
*
|
|
319
367
|
* @example
|
|
320
368
|
* toCurrency(42.50) // 'اثنان وأربعون ريالاً وخمسون هللة'
|
|
321
369
|
* toCurrency(1) // 'ريال واحد'
|
|
322
370
|
* toCurrency(0.01) // 'هللة واحدة'
|
|
323
371
|
*/
|
|
324
|
-
function toCurrency
|
|
372
|
+
function toCurrency(value) {
|
|
325
373
|
const { isNegative, dollars: riyals, cents: halalas } = parseCurrencyValue(value)
|
|
374
|
+
checkMax(riyals, currencyMax)
|
|
326
375
|
|
|
327
376
|
// Build result
|
|
328
377
|
let result = ''
|
|
@@ -333,9 +382,11 @@ function toCurrency (value) {
|
|
|
333
382
|
// Special case for 1 and 2: currency word comes first
|
|
334
383
|
if (riyals === 1n) {
|
|
335
384
|
result += RIYAL_SINGULAR + ' ' + ONES_MASC[0]
|
|
336
|
-
}
|
|
385
|
+
}
|
|
386
|
+
else if (riyals === 2n) {
|
|
337
387
|
result += RIYAL_DUAL
|
|
338
|
-
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
339
390
|
const riyalWord = integerToWords(riyals, 'masculine')
|
|
340
391
|
result += riyalWord + ' ' + getRiyalForm(riyals)
|
|
341
392
|
}
|
|
@@ -349,9 +400,11 @@ function toCurrency (value) {
|
|
|
349
400
|
// Special case for 1 and 2: currency word comes first
|
|
350
401
|
if (halalas === 1n) {
|
|
351
402
|
result += HALALA_SINGULAR + ' ' + ONES_FEM[0]
|
|
352
|
-
}
|
|
403
|
+
}
|
|
404
|
+
else if (halalas === 2n) {
|
|
353
405
|
result += HALALA_DUAL
|
|
354
|
-
}
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
355
408
|
const halalaWord = integerToWords(halalas, 'feminine')
|
|
356
409
|
result += halalaWord + ' ' + getHalalaForm(halalas)
|
|
357
410
|
}
|
package/src/az-AZ.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
1
4
|
/**
|
|
2
5
|
* Converts a numeric value to Azerbaijani words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Azerbaijani words
|
|
6
8
|
*/
|
|
7
9
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
10
|
/**
|
|
9
11
|
* Converts a numeric value to Azerbaijani ordinal words.
|
|
10
|
-
*
|
|
11
12
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
12
13
|
* @returns {string} The number as ordinal words
|
|
13
14
|
* @throws {TypeError} If value is not a valid numeric type
|
|
14
15
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
15
|
-
*
|
|
16
16
|
* @example
|
|
17
17
|
* toOrdinal(1) // 'birinci'
|
|
18
18
|
* toOrdinal(2) // 'ikinci'
|
|
@@ -23,12 +23,10 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
23
23
|
* Converts a numeric value to Azerbaijani currency words (Manat).
|
|
24
24
|
*
|
|
25
25
|
* Uses manat and qəpik (100 qəpik = 1 manat).
|
|
26
|
-
*
|
|
27
26
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
28
27
|
* @returns {string} The amount in Azerbaijani currency words
|
|
29
28
|
* @throws {TypeError} If value is not a valid numeric type
|
|
30
29
|
* @throws {Error} If value is not a valid number format
|
|
31
|
-
*
|
|
32
30
|
* @example
|
|
33
31
|
* toCurrency(42) // 'qırx iki manat'
|
|
34
32
|
* toCurrency(1.50) // 'bir manat əlli qəpik'
|
package/src/az-AZ.js
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
13
13
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
14
14
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
15
|
+
import { checkMax } from './utils/check-max.js'
|
|
16
|
+
import { western } from './utils/scale.js'
|
|
15
17
|
|
|
16
18
|
// ============================================================================
|
|
17
19
|
// Vocabulary
|
|
@@ -31,12 +33,22 @@ const DECIMAL_SEP = 'nöqtə'
|
|
|
31
33
|
// Short scale
|
|
32
34
|
const SCALE_WORDS = ['', THOUSAND, 'milyon', 'milyar', 'trilyon', 'katrilyon', 'kentilyon']
|
|
33
35
|
|
|
36
|
+
// Supported magnitude ceiling (checked at the public entry points). SCALE_WORDS
|
|
37
|
+
// reaches index SCALE_WORDS.length-1 (kentilyon, 10^18), so values must stay
|
|
38
|
+
// below 10^(SCALE_WORDS.length * 3) = 10^21. Ordinal builds on the cardinal
|
|
39
|
+
// (integerToWords + suffix) and currency too, so all three share the ceiling —
|
|
40
|
+
// and the decimal is also spelled via integerToWords, so it's guarded as well.
|
|
41
|
+
export const cardinalMax = western(SCALE_WORDS.length - 1)
|
|
42
|
+
export const ordinalMax = western(SCALE_WORDS.length - 1)
|
|
43
|
+
export const currencyMax = western(SCALE_WORDS.length - 1)
|
|
44
|
+
|
|
34
45
|
// ============================================================================
|
|
35
46
|
// Ordinal Vocabulary
|
|
36
47
|
// ============================================================================
|
|
37
48
|
|
|
38
49
|
// Azerbaijani ordinals use -(i/ı/u/ü)nci/ncı/ncu/ncü suffix with vowel harmony
|
|
39
50
|
// Special forms for 1-10
|
|
51
|
+
/** @type {Record<number, string>} */
|
|
40
52
|
const ORDINAL_SPECIAL = {
|
|
41
53
|
1: 'birinci',
|
|
42
54
|
2: 'ikinci',
|
|
@@ -47,7 +59,7 @@ const ORDINAL_SPECIAL = {
|
|
|
47
59
|
7: 'yeddinci',
|
|
48
60
|
8: 'səkkizinci',
|
|
49
61
|
9: 'doqquzuncu',
|
|
50
|
-
10: 'onuncu'
|
|
62
|
+
10: 'onuncu',
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
// ============================================================================
|
|
@@ -61,7 +73,12 @@ const QEPIK = 'qəpik' // subunit (100 qəpik = 1 manat)
|
|
|
61
73
|
// Precomputed Lookup Table
|
|
62
74
|
// ============================================================================
|
|
63
75
|
|
|
64
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Builds the Azerbaijani words for a 3-digit segment (0-999).
|
|
78
|
+
* @param {number} n - The segment value
|
|
79
|
+
* @returns {string} The segment in words
|
|
80
|
+
*/
|
|
81
|
+
function buildSegment(n) {
|
|
65
82
|
if (n === 0) return ''
|
|
66
83
|
|
|
67
84
|
const ones = n % 10
|
|
@@ -73,14 +90,16 @@ function buildSegment (n) {
|
|
|
73
90
|
if (hundredsDigit > 0) {
|
|
74
91
|
if (hundredsDigit === 1) {
|
|
75
92
|
parts.push(HUNDRED)
|
|
76
|
-
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
77
95
|
parts.push(ONES[hundredsDigit] + ' ' + HUNDRED)
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
|
|
81
99
|
if (tensDigit === 1) {
|
|
82
100
|
parts.push(TEENS[ones])
|
|
83
|
-
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
84
103
|
if (tensDigit > 1) {
|
|
85
104
|
parts.push(TENS[tensDigit])
|
|
86
105
|
}
|
|
@@ -96,7 +115,12 @@ function buildSegment (n) {
|
|
|
96
115
|
// Conversion Functions
|
|
97
116
|
// ============================================================================
|
|
98
117
|
|
|
99
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Converts a non-negative integer to Azerbaijani words.
|
|
120
|
+
* @param {bigint} n - The integer value
|
|
121
|
+
* @returns {string} The integer in words
|
|
122
|
+
*/
|
|
123
|
+
function integerToWords(n) {
|
|
100
124
|
if (n === 0n) return ZERO
|
|
101
125
|
|
|
102
126
|
if (n < 1000n) {
|
|
@@ -106,7 +130,12 @@ function integerToWords (n) {
|
|
|
106
130
|
return buildLargeNumberWords(n)
|
|
107
131
|
}
|
|
108
132
|
|
|
109
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Builds Azerbaijani words for numbers >= 1000 using scale words.
|
|
135
|
+
* @param {bigint} n - The integer value
|
|
136
|
+
* @returns {string} The number in words
|
|
137
|
+
*/
|
|
138
|
+
function buildLargeNumberWords(n) {
|
|
110
139
|
const numStr = n.toString()
|
|
111
140
|
const len = numStr.length
|
|
112
141
|
|
|
@@ -135,10 +164,12 @@ function buildLargeNumberWords (n) {
|
|
|
135
164
|
|
|
136
165
|
if (scaleIndex === 0) {
|
|
137
166
|
parts.push(buildSegment(segment))
|
|
138
|
-
}
|
|
167
|
+
}
|
|
168
|
+
else if (scaleIndex === 1 && segment === 1) {
|
|
139
169
|
// Omit "bir" before thousand
|
|
140
170
|
parts.push(scaleWord)
|
|
141
|
-
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
142
173
|
parts.push(buildSegment(segment) + ' ' + scaleWord)
|
|
143
174
|
}
|
|
144
175
|
}
|
|
@@ -149,7 +180,12 @@ function buildLargeNumberWords (n) {
|
|
|
149
180
|
return parts.join(' ')
|
|
150
181
|
}
|
|
151
182
|
|
|
152
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Converts the decimal-part digit string to Azerbaijani words.
|
|
185
|
+
* @param {string} decimalPart - The decimal digits as a string
|
|
186
|
+
* @returns {string} The decimal part in words
|
|
187
|
+
*/
|
|
188
|
+
function decimalPartToWords(decimalPart) {
|
|
153
189
|
let result = ''
|
|
154
190
|
let i = 0
|
|
155
191
|
|
|
@@ -170,12 +206,14 @@ function decimalPartToWords (decimalPart) {
|
|
|
170
206
|
|
|
171
207
|
/**
|
|
172
208
|
* Converts a numeric value to Azerbaijani words.
|
|
173
|
-
*
|
|
174
209
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
175
210
|
* @returns {string} The number in Azerbaijani words
|
|
176
211
|
*/
|
|
177
|
-
function toCardinal
|
|
212
|
+
function toCardinal(value) {
|
|
178
213
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
214
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
215
|
+
// the scale builder, so both must clear the ceiling.
|
|
216
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
179
217
|
|
|
180
218
|
let result = ''
|
|
181
219
|
|
|
@@ -201,7 +239,7 @@ function toCardinal (value) {
|
|
|
201
239
|
* @param {string} word - The cardinal word
|
|
202
240
|
* @returns {string} The appropriate suffix
|
|
203
241
|
*/
|
|
204
|
-
function getOrdinalSuffix
|
|
242
|
+
function getOrdinalSuffix(word) {
|
|
205
243
|
// Azerbaijani vowel harmony: back vowels (a,ı,o,u) vs front vowels (ə,e,i,ö,ü)
|
|
206
244
|
const backVowels = 'aıou'
|
|
207
245
|
const frontVowels = 'əeiöü'
|
|
@@ -228,11 +266,10 @@ function getOrdinalSuffix (word) {
|
|
|
228
266
|
*
|
|
229
267
|
* Azerbaijani ordinals: birinci (1st), ikinci (2nd), üçüncü (3rd), etc.
|
|
230
268
|
* Uses vowel harmony for suffix selection.
|
|
231
|
-
*
|
|
232
269
|
* @param {bigint} n - Positive integer to convert
|
|
233
270
|
* @returns {string} Azerbaijani ordinal words
|
|
234
271
|
*/
|
|
235
|
-
function integerToOrdinal
|
|
272
|
+
function integerToOrdinal(n) {
|
|
236
273
|
// Special forms for 1-10
|
|
237
274
|
if (n >= 1n && n <= 10n) {
|
|
238
275
|
return ORDINAL_SPECIAL[Number(n)]
|
|
@@ -246,19 +283,21 @@ function integerToOrdinal (n) {
|
|
|
246
283
|
|
|
247
284
|
/**
|
|
248
285
|
* Converts a numeric value to Azerbaijani ordinal words.
|
|
249
|
-
*
|
|
250
286
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
251
287
|
* @returns {string} The number as ordinal words
|
|
252
288
|
* @throws {TypeError} If value is not a valid numeric type
|
|
253
289
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
254
|
-
*
|
|
255
290
|
* @example
|
|
256
291
|
* toOrdinal(1) // 'birinci'
|
|
257
292
|
* toOrdinal(2) // 'ikinci'
|
|
258
293
|
* toOrdinal(21) // 'iyirmibirinci'
|
|
259
294
|
*/
|
|
260
|
-
function toOrdinal
|
|
295
|
+
function toOrdinal(value) {
|
|
261
296
|
const integerPart = parseOrdinalValue(value)
|
|
297
|
+
// Ordinal builds on the cardinal (integerToWords + suffix), so it shares the
|
|
298
|
+
// ceiling — past it the cardinal's trailing-space artifact would be hidden by
|
|
299
|
+
// the space-stripping and emit a silently-wrong ordinal.
|
|
300
|
+
checkMax(integerPart, ordinalMax)
|
|
262
301
|
return integerToOrdinal(integerPart)
|
|
263
302
|
}
|
|
264
303
|
|
|
@@ -270,19 +309,18 @@ function toOrdinal (value) {
|
|
|
270
309
|
* Converts a numeric value to Azerbaijani currency words (Manat).
|
|
271
310
|
*
|
|
272
311
|
* Uses manat and qəpik (100 qəpik = 1 manat).
|
|
273
|
-
*
|
|
274
312
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
275
313
|
* @returns {string} The amount in Azerbaijani currency words
|
|
276
314
|
* @throws {TypeError} If value is not a valid numeric type
|
|
277
315
|
* @throws {Error} If value is not a valid number format
|
|
278
|
-
*
|
|
279
316
|
* @example
|
|
280
317
|
* toCurrency(42) // 'qırx iki manat'
|
|
281
318
|
* toCurrency(1.50) // 'bir manat əlli qəpik'
|
|
282
319
|
* toCurrency(-5) // 'mənfi beş manat'
|
|
283
320
|
*/
|
|
284
|
-
function toCurrency
|
|
321
|
+
function toCurrency(value) {
|
|
285
322
|
const { isNegative, dollars: manat, cents: qepik } = parseCurrencyValue(value)
|
|
323
|
+
checkMax(manat, currencyMax)
|
|
286
324
|
|
|
287
325
|
let result = ''
|
|
288
326
|
if (isNegative) {
|
package/src/bn-BD.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
1
4
|
/**
|
|
2
5
|
* Converts a numeric value to Bengali words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Bengali words
|
|
6
8
|
*/
|
|
7
9
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
10
|
/**
|
|
9
11
|
* Converts a numeric value to Bengali ordinal words.
|
|
10
|
-
*
|
|
11
12
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
12
13
|
* @returns {string} The number as ordinal words
|
|
13
14
|
* @throws {TypeError} If value is not a valid numeric type
|
|
14
15
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
15
|
-
*
|
|
16
16
|
* @example
|
|
17
17
|
* toOrdinal(1) // 'প্রথম'
|
|
18
18
|
* toOrdinal(2) // 'দ্বিতীয়'
|
|
@@ -22,12 +22,10 @@ export function toCardinal(value: number | string | bigint): string;
|
|
|
22
22
|
export function toOrdinal(value: number | string | bigint): string;
|
|
23
23
|
/**
|
|
24
24
|
* Converts a numeric value to Bengali currency words (Bangladeshi Taka).
|
|
25
|
-
*
|
|
26
25
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
27
26
|
* @returns {string} The amount in Bengali currency words
|
|
28
27
|
* @throws {TypeError} If value is not a valid numeric type
|
|
29
28
|
* @throws {Error} If value is not a valid number format
|
|
30
|
-
*
|
|
31
29
|
* @example
|
|
32
30
|
* toCurrency(42.50) // 'বেয়াল্লিশ টাকা পঞ্চাশ পয়সা'
|
|
33
31
|
* toCurrency(1) // 'এক টাকা'
|