@automattic/number-formatters 1.0.0-alpha.1 → 1.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 +19 -0
- package/dist/cjs/constants.cjs +5 -0
- package/dist/cjs/create-number-formatters.cjs +103 -0
- package/dist/cjs/get-cached-formatter.cjs +36 -0
- package/dist/cjs/index.cjs +10 -0
- package/dist/cjs/number-format-currency/currencies.cjs +488 -0
- package/dist/cjs/number-format-currency/index.cjs +322 -0
- package/dist/cjs/number-format.cjs +59 -0
- package/dist/cjs/types.cjs +2 -0
- package/dist/{create-number-formatters.js → esm/create-number-formatters.js} +3 -3
- package/dist/{get-cached-formatter.js → esm/get-cached-formatter.js} +1 -1
- package/dist/{index.js → esm/index.js} +1 -2
- package/dist/{number-format-currency → esm/number-format-currency}/index.js +3 -3
- package/dist/{number-format.js → esm/number-format.js} +1 -1
- package/dist/{create-number-formatters.d.ts → types/create-number-formatters.d.ts} +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/{number-format-currency → types/number-format-currency}/currencies.d.ts +1 -1
- package/dist/{number-format-currency → types/number-format-currency}/index.d.ts +1 -1
- package/dist/{number-format.d.ts → types/number-format.d.ts} +1 -1
- package/package.json +14 -9
- package/src/create-number-formatters.ts +4 -4
- package/src/get-cached-formatter.ts +1 -1
- package/src/index.ts +2 -2
- package/src/number-format-currency/currencies.ts +1 -1
- package/src/number-format-currency/index.ts +4 -4
- package/src/number-format.ts +2 -2
- package/dist/index.d.ts +0 -4
- /package/dist/{constants.js → esm/constants.js} +0 -0
- /package/dist/{number-format-currency → esm/number-format-currency}/currencies.js +0 -0
- /package/dist/{types.js → esm/types.js} +0 -0
- /package/dist/{constants.d.ts → types/constants.d.ts} +0 -0
- /package/dist/{get-cached-formatter.d.ts → types/get-cached-formatter.d.ts} +0 -0
- /package/dist/{types.d.ts → types/types.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
|
|
7
|
+
## [1.0.0] - 2025-04-29
|
|
8
|
+
### Changed
|
|
9
|
+
- Internal updates.
|
|
10
|
+
|
|
11
|
+
## [1.0.0] - 2025-04-29
|
|
12
|
+
### Changed
|
|
13
|
+
- Build CJS and ESM versions with TypeScript [#43106]
|
|
14
|
+
|
|
15
|
+
## [1.0.0-alpha.2] - 2025-04-10
|
|
16
|
+
### Changed
|
|
17
|
+
- Adjust relative imports in TypeScript sources to use correct extensions after enabling TypeScript's new `rewriteRelativeImportExtensions` option. The built JS should be unaffected, so this is not a breaking change. [#42990]
|
|
18
|
+
- Convert build to common-js [#42982]
|
|
19
|
+
|
|
20
|
+
## [1.0.0-alpha.1] - 2025-04-10
|
|
21
|
+
### Changed
|
|
22
|
+
- Internal updates.
|
|
23
|
+
|
|
7
24
|
## [1.0.0-alpha.1] - 2025-04-07
|
|
8
25
|
### Added
|
|
9
26
|
- initial release [#42639]
|
|
@@ -20,4 +37,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
20
37
|
- Initial release
|
|
21
38
|
- Basic number formatting functionality
|
|
22
39
|
|
|
40
|
+
[1.0.0]: https://github.com/Automattic/number-formatters/compare/1.0.0-alpha.2...1.0.0
|
|
41
|
+
[1.0.0-alpha.2]: https://github.com/Automattic/number-formatters/compare/1.0.0-alpha.1...1.0.0-alpha.2
|
|
23
42
|
[1.0.0-alpha.1]: https://github.com/Automattic/number-formatters/compare/0.1.0...1.0.0-alpha.1
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const date_1 = require("@wordpress/date");
|
|
4
|
+
const constants_ts_1 = require("./constants.cjs");
|
|
5
|
+
const index_ts_1 = require("./number-format-currency/index.cjs");
|
|
6
|
+
const number_format_ts_1 = require("./number-format.cjs");
|
|
7
|
+
/**
|
|
8
|
+
* Creates a NumberFormatters instance that provides number and currency formatting functionality with locale awareness
|
|
9
|
+
* @return {NumberFormatters} A NumberFormatters instance
|
|
10
|
+
*/
|
|
11
|
+
function createNumberFormatters() {
|
|
12
|
+
let localeState;
|
|
13
|
+
let geoLocationState;
|
|
14
|
+
const setLocale = (locale) => {
|
|
15
|
+
/**
|
|
16
|
+
* The `Intl.NumberFormat` constructor fails only when there is a variant, divided by `_`.
|
|
17
|
+
* These suffixes should be removed. Values like `de-at` or `es-mx`
|
|
18
|
+
* should all be valid inputs for the constructor.
|
|
19
|
+
*/
|
|
20
|
+
localeState = locale;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Returns the locale defined on the module instance (through `setLocale`)
|
|
24
|
+
* or the "fallback locale" if no locale has been set.
|
|
25
|
+
*
|
|
26
|
+
* The "fallback locale" is defined as:
|
|
27
|
+
* - the current WP user locale, if available through `@wordpress/date` settings (assuming this runs in a WordPress context)
|
|
28
|
+
* - or the browser locale, if available through `window.navigator.language`
|
|
29
|
+
* - or the fallback locale constant (`FALLBACK_LOCALE`)
|
|
30
|
+
*
|
|
31
|
+
* @return {string} The locale to use for formatting.
|
|
32
|
+
*/
|
|
33
|
+
const getBrowserSafeLocale = () => {
|
|
34
|
+
const { l10n: { locale: localeFromUserSettings }, } = (0, date_1.getSettings)();
|
|
35
|
+
return (localeState ??
|
|
36
|
+
(localeFromUserSettings || global?.window?.navigator?.language) ??
|
|
37
|
+
constants_ts_1.FALLBACK_LOCALE).split('_')[0];
|
|
38
|
+
};
|
|
39
|
+
const setGeoLocation = (geoLocation) => {
|
|
40
|
+
geoLocationState = geoLocation;
|
|
41
|
+
};
|
|
42
|
+
const formatNumber = (number, { decimals = 0, forceLatin = true, numberFormatOptions = {} } = {}) => {
|
|
43
|
+
try {
|
|
44
|
+
const formatter = (0, number_format_ts_1.numberFormat)({
|
|
45
|
+
browserSafeLocale: getBrowserSafeLocale(),
|
|
46
|
+
decimals,
|
|
47
|
+
forceLatin,
|
|
48
|
+
numberFormatOptions,
|
|
49
|
+
});
|
|
50
|
+
return formatter.format(number);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return String(number);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const formatNumberCompact = (number, { decimals = 0, forceLatin = true, numberFormatOptions = {} } = {}) => {
|
|
57
|
+
try {
|
|
58
|
+
const formatter = (0, number_format_ts_1.numberFormatCompact)({
|
|
59
|
+
browserSafeLocale: getBrowserSafeLocale(),
|
|
60
|
+
decimals,
|
|
61
|
+
forceLatin,
|
|
62
|
+
numberFormatOptions,
|
|
63
|
+
});
|
|
64
|
+
return formatter.format(number);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return String(number);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const formatCurrency = (number, currency, { stripZeros = false, isSmallestUnit = false, signForPositive = false, forceLatin = true } = {}) => {
|
|
71
|
+
return (0, index_ts_1.numberFormatCurrency)({
|
|
72
|
+
number,
|
|
73
|
+
currency,
|
|
74
|
+
browserSafeLocale: getBrowserSafeLocale(),
|
|
75
|
+
stripZeros,
|
|
76
|
+
isSmallestUnit,
|
|
77
|
+
signForPositive,
|
|
78
|
+
geoLocation: geoLocationState,
|
|
79
|
+
forceLatin,
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
const getCurrencyObject = (number, currency, { stripZeros = false, isSmallestUnit = false, signForPositive = false, forceLatin = true } = {}) => {
|
|
83
|
+
return (0, index_ts_1.getCurrencyObject)({
|
|
84
|
+
number,
|
|
85
|
+
currency,
|
|
86
|
+
browserSafeLocale: getBrowserSafeLocale(),
|
|
87
|
+
stripZeros,
|
|
88
|
+
isSmallestUnit,
|
|
89
|
+
signForPositive,
|
|
90
|
+
geoLocation: geoLocationState,
|
|
91
|
+
forceLatin,
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
setLocale,
|
|
96
|
+
setGeoLocation,
|
|
97
|
+
formatNumber,
|
|
98
|
+
formatNumberCompact,
|
|
99
|
+
formatCurrency,
|
|
100
|
+
getCurrencyObject,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
exports.default = createNumberFormatters;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCachedFormatter = getCachedFormatter;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
6
|
+
const constants_ts_1 = require("./constants.cjs");
|
|
7
|
+
const debug = (0, debug_1.default)('number-formatters:get-cached-formatter');
|
|
8
|
+
const formatterCache = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Get a cached formatter for a given locale and options.
|
|
11
|
+
* @param params - The parameters for the formatter.
|
|
12
|
+
* @param params.locale - The locale to format the number in.
|
|
13
|
+
* @param params.options - Intl.NumberFormatOptions to pass to the formatter.
|
|
14
|
+
* @param params.fallbackLocale - The locale to fallback to if the locale is not supported.
|
|
15
|
+
* @param params.retries - The number of retries to attempt if the formatter is not created.
|
|
16
|
+
* @return {Intl.NumberFormat} A cached formatter for the given locale and options.
|
|
17
|
+
*/
|
|
18
|
+
function getCachedFormatter({ locale, fallbackLocale = constants_ts_1.FALLBACK_LOCALE, options, retries = 1, }) {
|
|
19
|
+
const cacheKey = JSON.stringify([locale, options]);
|
|
20
|
+
try {
|
|
21
|
+
return (formatterCache.get(cacheKey) ??
|
|
22
|
+
formatterCache.set(cacheKey, new Intl.NumberFormat(locale, options)).get(cacheKey));
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
// If the locale is invalid, creating the NumberFormat will throw.
|
|
26
|
+
debug(`Intl.NumberFormat was called with a non-existent locale "${locale}"; falling back to ${fallbackLocale}`);
|
|
27
|
+
if (retries) {
|
|
28
|
+
return getCachedFormatter({
|
|
29
|
+
locale: fallbackLocale,
|
|
30
|
+
options,
|
|
31
|
+
retries: retries - 1,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNumberFormatters = exports.getCurrencyObject = exports.formatCurrency = exports.formatNumberCompact = exports.formatNumber = exports.setGeoLocation = exports.setLocale = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const create_number_formatters_ts_1 = tslib_1.__importDefault(require("./create-number-formatters.cjs"));
|
|
6
|
+
exports.createNumberFormatters = create_number_formatters_ts_1.default;
|
|
7
|
+
const defaultFormatter = (0, create_number_formatters_ts_1.default)();
|
|
8
|
+
exports.setLocale = defaultFormatter.setLocale, exports.setGeoLocation = defaultFormatter.setGeoLocation, exports.formatNumber = defaultFormatter.formatNumber, exports.formatNumberCompact = defaultFormatter.formatNumberCompact, exports.formatCurrency = defaultFormatter.formatCurrency, exports.getCurrencyObject = defaultFormatter.getCurrencyObject;
|
|
9
|
+
// We can optionally export the formatters individually if we want to use them in a more granular way.
|
|
10
|
+
// export { numberFormat, numberFormatCompact, numberFormatCurrency, getCurrencyObject };
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultCurrencyOverrides = void 0;
|
|
4
|
+
exports.defaultCurrencyOverrides = {
|
|
5
|
+
AED: {
|
|
6
|
+
symbol: 'د.إ.',
|
|
7
|
+
},
|
|
8
|
+
AFN: {
|
|
9
|
+
symbol: '؋',
|
|
10
|
+
},
|
|
11
|
+
ALL: {
|
|
12
|
+
symbol: 'Lek',
|
|
13
|
+
},
|
|
14
|
+
AMD: {
|
|
15
|
+
symbol: '֏',
|
|
16
|
+
},
|
|
17
|
+
ANG: {
|
|
18
|
+
symbol: 'ƒ',
|
|
19
|
+
},
|
|
20
|
+
AOA: {
|
|
21
|
+
symbol: 'Kz',
|
|
22
|
+
},
|
|
23
|
+
ARS: {
|
|
24
|
+
symbol: '$',
|
|
25
|
+
},
|
|
26
|
+
AUD: {
|
|
27
|
+
symbol: 'A$',
|
|
28
|
+
},
|
|
29
|
+
AWG: {
|
|
30
|
+
symbol: 'ƒ',
|
|
31
|
+
},
|
|
32
|
+
AZN: {
|
|
33
|
+
symbol: '₼',
|
|
34
|
+
},
|
|
35
|
+
BAM: {
|
|
36
|
+
symbol: 'КМ',
|
|
37
|
+
},
|
|
38
|
+
BBD: {
|
|
39
|
+
symbol: 'Bds$',
|
|
40
|
+
},
|
|
41
|
+
BDT: {
|
|
42
|
+
symbol: '৳',
|
|
43
|
+
},
|
|
44
|
+
BGN: {
|
|
45
|
+
symbol: 'лв.',
|
|
46
|
+
},
|
|
47
|
+
BHD: {
|
|
48
|
+
symbol: 'د.ب.',
|
|
49
|
+
},
|
|
50
|
+
BIF: {
|
|
51
|
+
symbol: 'FBu',
|
|
52
|
+
},
|
|
53
|
+
BMD: {
|
|
54
|
+
symbol: '$',
|
|
55
|
+
},
|
|
56
|
+
BND: {
|
|
57
|
+
symbol: '$',
|
|
58
|
+
},
|
|
59
|
+
BOB: {
|
|
60
|
+
symbol: 'Bs',
|
|
61
|
+
},
|
|
62
|
+
BRL: {
|
|
63
|
+
symbol: 'R$',
|
|
64
|
+
},
|
|
65
|
+
BSD: {
|
|
66
|
+
symbol: '$',
|
|
67
|
+
},
|
|
68
|
+
BTC: {
|
|
69
|
+
symbol: 'Ƀ',
|
|
70
|
+
},
|
|
71
|
+
BTN: {
|
|
72
|
+
symbol: 'Nu.',
|
|
73
|
+
},
|
|
74
|
+
BWP: {
|
|
75
|
+
symbol: 'P',
|
|
76
|
+
},
|
|
77
|
+
BYR: {
|
|
78
|
+
symbol: 'р.',
|
|
79
|
+
},
|
|
80
|
+
BZD: {
|
|
81
|
+
symbol: 'BZ$',
|
|
82
|
+
},
|
|
83
|
+
CAD: {
|
|
84
|
+
symbol: 'C$',
|
|
85
|
+
},
|
|
86
|
+
CDF: {
|
|
87
|
+
symbol: 'FC',
|
|
88
|
+
},
|
|
89
|
+
CHF: {
|
|
90
|
+
symbol: 'CHF',
|
|
91
|
+
},
|
|
92
|
+
CLP: {
|
|
93
|
+
symbol: '$',
|
|
94
|
+
},
|
|
95
|
+
CNY: {
|
|
96
|
+
symbol: '¥',
|
|
97
|
+
},
|
|
98
|
+
COP: {
|
|
99
|
+
symbol: '$',
|
|
100
|
+
},
|
|
101
|
+
CRC: {
|
|
102
|
+
symbol: '₡',
|
|
103
|
+
},
|
|
104
|
+
CUC: {
|
|
105
|
+
symbol: 'CUC',
|
|
106
|
+
},
|
|
107
|
+
CUP: {
|
|
108
|
+
symbol: '$MN',
|
|
109
|
+
},
|
|
110
|
+
CVE: {
|
|
111
|
+
symbol: '$',
|
|
112
|
+
},
|
|
113
|
+
CZK: {
|
|
114
|
+
symbol: 'Kč',
|
|
115
|
+
},
|
|
116
|
+
DJF: {
|
|
117
|
+
symbol: 'Fdj',
|
|
118
|
+
},
|
|
119
|
+
DKK: {
|
|
120
|
+
symbol: 'kr.',
|
|
121
|
+
},
|
|
122
|
+
DOP: {
|
|
123
|
+
symbol: 'RD$',
|
|
124
|
+
},
|
|
125
|
+
DZD: {
|
|
126
|
+
symbol: 'د.ج.',
|
|
127
|
+
},
|
|
128
|
+
EGP: {
|
|
129
|
+
symbol: 'ج.م.',
|
|
130
|
+
},
|
|
131
|
+
ERN: {
|
|
132
|
+
symbol: 'Nfk',
|
|
133
|
+
},
|
|
134
|
+
ETB: {
|
|
135
|
+
symbol: 'ETB',
|
|
136
|
+
},
|
|
137
|
+
EUR: {
|
|
138
|
+
symbol: '€',
|
|
139
|
+
},
|
|
140
|
+
FJD: {
|
|
141
|
+
symbol: 'FJ$',
|
|
142
|
+
},
|
|
143
|
+
FKP: {
|
|
144
|
+
symbol: '£',
|
|
145
|
+
},
|
|
146
|
+
GBP: {
|
|
147
|
+
symbol: '£',
|
|
148
|
+
},
|
|
149
|
+
GEL: {
|
|
150
|
+
symbol: 'Lari',
|
|
151
|
+
},
|
|
152
|
+
GHS: {
|
|
153
|
+
symbol: '₵',
|
|
154
|
+
},
|
|
155
|
+
GIP: {
|
|
156
|
+
symbol: '£',
|
|
157
|
+
},
|
|
158
|
+
GMD: {
|
|
159
|
+
symbol: 'D',
|
|
160
|
+
},
|
|
161
|
+
GNF: {
|
|
162
|
+
symbol: 'FG',
|
|
163
|
+
},
|
|
164
|
+
GTQ: {
|
|
165
|
+
symbol: 'Q',
|
|
166
|
+
},
|
|
167
|
+
GYD: {
|
|
168
|
+
symbol: 'G$',
|
|
169
|
+
},
|
|
170
|
+
HKD: {
|
|
171
|
+
symbol: 'HK$',
|
|
172
|
+
},
|
|
173
|
+
HNL: {
|
|
174
|
+
symbol: 'L.',
|
|
175
|
+
},
|
|
176
|
+
HRK: {
|
|
177
|
+
symbol: 'kn',
|
|
178
|
+
},
|
|
179
|
+
HTG: {
|
|
180
|
+
symbol: 'G',
|
|
181
|
+
},
|
|
182
|
+
HUF: {
|
|
183
|
+
symbol: 'Ft',
|
|
184
|
+
},
|
|
185
|
+
IDR: {
|
|
186
|
+
symbol: 'Rp',
|
|
187
|
+
},
|
|
188
|
+
ILS: {
|
|
189
|
+
symbol: '₪',
|
|
190
|
+
},
|
|
191
|
+
INR: {
|
|
192
|
+
symbol: '₹',
|
|
193
|
+
},
|
|
194
|
+
IQD: {
|
|
195
|
+
symbol: 'د.ع.',
|
|
196
|
+
},
|
|
197
|
+
IRR: {
|
|
198
|
+
symbol: '﷼',
|
|
199
|
+
},
|
|
200
|
+
ISK: {
|
|
201
|
+
symbol: 'kr.',
|
|
202
|
+
},
|
|
203
|
+
JMD: {
|
|
204
|
+
symbol: 'J$',
|
|
205
|
+
},
|
|
206
|
+
JOD: {
|
|
207
|
+
symbol: 'د.ا.',
|
|
208
|
+
},
|
|
209
|
+
JPY: {
|
|
210
|
+
symbol: '¥',
|
|
211
|
+
},
|
|
212
|
+
KES: {
|
|
213
|
+
symbol: 'S',
|
|
214
|
+
},
|
|
215
|
+
KGS: {
|
|
216
|
+
symbol: 'сом',
|
|
217
|
+
},
|
|
218
|
+
KHR: {
|
|
219
|
+
symbol: '៛',
|
|
220
|
+
},
|
|
221
|
+
KMF: {
|
|
222
|
+
symbol: 'CF',
|
|
223
|
+
},
|
|
224
|
+
KPW: {
|
|
225
|
+
symbol: '₩',
|
|
226
|
+
},
|
|
227
|
+
KRW: {
|
|
228
|
+
symbol: '₩',
|
|
229
|
+
},
|
|
230
|
+
KWD: {
|
|
231
|
+
symbol: 'د.ك.',
|
|
232
|
+
},
|
|
233
|
+
KYD: {
|
|
234
|
+
symbol: '$',
|
|
235
|
+
},
|
|
236
|
+
KZT: {
|
|
237
|
+
symbol: '₸',
|
|
238
|
+
},
|
|
239
|
+
LAK: {
|
|
240
|
+
symbol: '₭',
|
|
241
|
+
},
|
|
242
|
+
LBP: {
|
|
243
|
+
symbol: 'ل.ل.',
|
|
244
|
+
},
|
|
245
|
+
LKR: {
|
|
246
|
+
symbol: '₨',
|
|
247
|
+
},
|
|
248
|
+
LRD: {
|
|
249
|
+
symbol: 'L$',
|
|
250
|
+
},
|
|
251
|
+
LSL: {
|
|
252
|
+
symbol: 'M',
|
|
253
|
+
},
|
|
254
|
+
LYD: {
|
|
255
|
+
symbol: 'د.ل.',
|
|
256
|
+
},
|
|
257
|
+
MAD: {
|
|
258
|
+
symbol: 'د.م.',
|
|
259
|
+
},
|
|
260
|
+
MDL: {
|
|
261
|
+
symbol: 'lei',
|
|
262
|
+
},
|
|
263
|
+
MGA: {
|
|
264
|
+
symbol: 'Ar',
|
|
265
|
+
},
|
|
266
|
+
MKD: {
|
|
267
|
+
symbol: 'ден.',
|
|
268
|
+
},
|
|
269
|
+
MMK: {
|
|
270
|
+
symbol: 'K',
|
|
271
|
+
},
|
|
272
|
+
MNT: {
|
|
273
|
+
symbol: '₮',
|
|
274
|
+
},
|
|
275
|
+
MOP: {
|
|
276
|
+
symbol: 'MOP$',
|
|
277
|
+
},
|
|
278
|
+
MRO: {
|
|
279
|
+
symbol: 'UM',
|
|
280
|
+
},
|
|
281
|
+
MTL: {
|
|
282
|
+
symbol: '₤',
|
|
283
|
+
},
|
|
284
|
+
MUR: {
|
|
285
|
+
symbol: '₨',
|
|
286
|
+
},
|
|
287
|
+
MVR: {
|
|
288
|
+
symbol: 'MVR',
|
|
289
|
+
},
|
|
290
|
+
MWK: {
|
|
291
|
+
symbol: 'MK',
|
|
292
|
+
},
|
|
293
|
+
MXN: {
|
|
294
|
+
symbol: 'MX$',
|
|
295
|
+
},
|
|
296
|
+
MYR: {
|
|
297
|
+
symbol: 'RM',
|
|
298
|
+
},
|
|
299
|
+
MZN: {
|
|
300
|
+
symbol: 'MT',
|
|
301
|
+
},
|
|
302
|
+
NAD: {
|
|
303
|
+
symbol: 'N$',
|
|
304
|
+
},
|
|
305
|
+
NGN: {
|
|
306
|
+
symbol: '₦',
|
|
307
|
+
},
|
|
308
|
+
NIO: {
|
|
309
|
+
symbol: 'C$',
|
|
310
|
+
},
|
|
311
|
+
NOK: {
|
|
312
|
+
symbol: 'kr',
|
|
313
|
+
},
|
|
314
|
+
NPR: {
|
|
315
|
+
symbol: '₨',
|
|
316
|
+
},
|
|
317
|
+
NZD: {
|
|
318
|
+
symbol: 'NZ$',
|
|
319
|
+
},
|
|
320
|
+
OMR: {
|
|
321
|
+
symbol: '﷼',
|
|
322
|
+
},
|
|
323
|
+
PAB: {
|
|
324
|
+
symbol: 'B/.',
|
|
325
|
+
},
|
|
326
|
+
PEN: {
|
|
327
|
+
symbol: 'S/.',
|
|
328
|
+
},
|
|
329
|
+
PGK: {
|
|
330
|
+
symbol: 'K',
|
|
331
|
+
},
|
|
332
|
+
PHP: {
|
|
333
|
+
symbol: '₱',
|
|
334
|
+
},
|
|
335
|
+
PKR: {
|
|
336
|
+
symbol: '₨',
|
|
337
|
+
},
|
|
338
|
+
PLN: {
|
|
339
|
+
symbol: 'zł',
|
|
340
|
+
},
|
|
341
|
+
PYG: {
|
|
342
|
+
symbol: '₲',
|
|
343
|
+
},
|
|
344
|
+
QAR: {
|
|
345
|
+
symbol: '﷼',
|
|
346
|
+
},
|
|
347
|
+
RON: {
|
|
348
|
+
symbol: 'lei',
|
|
349
|
+
},
|
|
350
|
+
RSD: {
|
|
351
|
+
symbol: 'Дин.',
|
|
352
|
+
},
|
|
353
|
+
RUB: {
|
|
354
|
+
symbol: '₽',
|
|
355
|
+
},
|
|
356
|
+
RWF: {
|
|
357
|
+
symbol: 'RWF',
|
|
358
|
+
},
|
|
359
|
+
SAR: {
|
|
360
|
+
symbol: '﷼',
|
|
361
|
+
},
|
|
362
|
+
SBD: {
|
|
363
|
+
symbol: 'S$',
|
|
364
|
+
},
|
|
365
|
+
SCR: {
|
|
366
|
+
symbol: '₨',
|
|
367
|
+
},
|
|
368
|
+
SDD: {
|
|
369
|
+
symbol: 'LSd',
|
|
370
|
+
},
|
|
371
|
+
SDG: {
|
|
372
|
+
symbol: '£',
|
|
373
|
+
},
|
|
374
|
+
SEK: {
|
|
375
|
+
symbol: 'kr',
|
|
376
|
+
},
|
|
377
|
+
SGD: {
|
|
378
|
+
symbol: 'S$',
|
|
379
|
+
},
|
|
380
|
+
SHP: {
|
|
381
|
+
symbol: '£',
|
|
382
|
+
},
|
|
383
|
+
SLL: {
|
|
384
|
+
symbol: 'Le',
|
|
385
|
+
},
|
|
386
|
+
SOS: {
|
|
387
|
+
symbol: 'S',
|
|
388
|
+
},
|
|
389
|
+
SRD: {
|
|
390
|
+
symbol: '$',
|
|
391
|
+
},
|
|
392
|
+
STD: {
|
|
393
|
+
symbol: 'Db',
|
|
394
|
+
},
|
|
395
|
+
SVC: {
|
|
396
|
+
symbol: '₡',
|
|
397
|
+
},
|
|
398
|
+
SYP: {
|
|
399
|
+
symbol: '£',
|
|
400
|
+
},
|
|
401
|
+
SZL: {
|
|
402
|
+
symbol: 'E',
|
|
403
|
+
},
|
|
404
|
+
THB: {
|
|
405
|
+
symbol: '฿',
|
|
406
|
+
},
|
|
407
|
+
TJS: {
|
|
408
|
+
symbol: 'TJS',
|
|
409
|
+
},
|
|
410
|
+
TMT: {
|
|
411
|
+
symbol: 'm',
|
|
412
|
+
},
|
|
413
|
+
TND: {
|
|
414
|
+
symbol: 'د.ت.',
|
|
415
|
+
},
|
|
416
|
+
TOP: {
|
|
417
|
+
symbol: 'T$',
|
|
418
|
+
},
|
|
419
|
+
TRY: {
|
|
420
|
+
symbol: 'TL',
|
|
421
|
+
},
|
|
422
|
+
TTD: {
|
|
423
|
+
symbol: 'TT$',
|
|
424
|
+
},
|
|
425
|
+
TVD: {
|
|
426
|
+
symbol: '$T',
|
|
427
|
+
},
|
|
428
|
+
TWD: {
|
|
429
|
+
symbol: 'NT$',
|
|
430
|
+
},
|
|
431
|
+
TZS: {
|
|
432
|
+
symbol: 'TSh',
|
|
433
|
+
},
|
|
434
|
+
UAH: {
|
|
435
|
+
symbol: '₴',
|
|
436
|
+
},
|
|
437
|
+
UGX: {
|
|
438
|
+
symbol: 'USh',
|
|
439
|
+
},
|
|
440
|
+
USD: {
|
|
441
|
+
// No override. Do what the locale thinks is best.
|
|
442
|
+
},
|
|
443
|
+
UYU: {
|
|
444
|
+
symbol: '$U',
|
|
445
|
+
},
|
|
446
|
+
UZS: {
|
|
447
|
+
symbol: 'сўм',
|
|
448
|
+
},
|
|
449
|
+
VEB: {
|
|
450
|
+
symbol: 'Bs.',
|
|
451
|
+
},
|
|
452
|
+
VEF: {
|
|
453
|
+
symbol: 'Bs. F.',
|
|
454
|
+
},
|
|
455
|
+
VND: {
|
|
456
|
+
symbol: '₫',
|
|
457
|
+
},
|
|
458
|
+
VUV: {
|
|
459
|
+
symbol: 'VT',
|
|
460
|
+
},
|
|
461
|
+
WST: {
|
|
462
|
+
symbol: 'WS$',
|
|
463
|
+
},
|
|
464
|
+
XAF: {
|
|
465
|
+
symbol: 'F',
|
|
466
|
+
},
|
|
467
|
+
XCD: {
|
|
468
|
+
symbol: '$',
|
|
469
|
+
},
|
|
470
|
+
XOF: {
|
|
471
|
+
symbol: 'F',
|
|
472
|
+
},
|
|
473
|
+
XPF: {
|
|
474
|
+
symbol: 'F',
|
|
475
|
+
},
|
|
476
|
+
YER: {
|
|
477
|
+
symbol: '﷼',
|
|
478
|
+
},
|
|
479
|
+
ZAR: {
|
|
480
|
+
symbol: 'R',
|
|
481
|
+
},
|
|
482
|
+
ZMW: {
|
|
483
|
+
symbol: 'ZK',
|
|
484
|
+
},
|
|
485
|
+
WON: {
|
|
486
|
+
symbol: '₩',
|
|
487
|
+
},
|
|
488
|
+
};
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCurrencyObject = exports.numberFormatCurrency = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
6
|
+
const constants_ts_1 = require("../constants.cjs");
|
|
7
|
+
const get_cached_formatter_ts_1 = require("../get-cached-formatter.cjs");
|
|
8
|
+
const currencies_ts_1 = require("./currencies.cjs");
|
|
9
|
+
const debug = (0, debug_1.default)('number-formatters:number-format-currency');
|
|
10
|
+
/**
|
|
11
|
+
* Retrieves the currency override for a given currency.
|
|
12
|
+
* If the currency is USD and the user is not in the US, it will return `US$`.
|
|
13
|
+
* @param currency - The currency to get the override for.
|
|
14
|
+
* @param geoLocation - The geo location of the user.
|
|
15
|
+
* @return {CurrencyOverride | undefined} The currency override.
|
|
16
|
+
*/
|
|
17
|
+
function getCurrencyOverride(currency, geoLocation) {
|
|
18
|
+
if (currency === 'USD' && geoLocation && geoLocation !== '' && geoLocation !== 'US') {
|
|
19
|
+
return { symbol: 'US$' };
|
|
20
|
+
}
|
|
21
|
+
return currencies_ts_1.defaultCurrencyOverrides[currency];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns a valid currency code based on a shortlist of currency codes.
|
|
25
|
+
* Only currencies from the shortlist are allowed. Everything else will fall back to `FALLBACK_CURRENCY`.
|
|
26
|
+
* @param currency - The currency to get the valid currency for.
|
|
27
|
+
* @param geoLocation - The geo location of the user.
|
|
28
|
+
* @return {string} The valid currency.
|
|
29
|
+
*/
|
|
30
|
+
function getValidCurrency(currency, geoLocation) {
|
|
31
|
+
if (!getCurrencyOverride(currency, geoLocation)) {
|
|
32
|
+
debug(`getValidCurrency was called with a non-existent currency "${currency}"; falling back to ${constants_ts_1.FALLBACK_CURRENCY}`);
|
|
33
|
+
return constants_ts_1.FALLBACK_CURRENCY;
|
|
34
|
+
}
|
|
35
|
+
return currency;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns a currency formatter for a given currency.
|
|
39
|
+
* @param params - The parameters for the currency formatter.
|
|
40
|
+
* @param params.number - The number to format.
|
|
41
|
+
* @param params.currency - The currency to format.
|
|
42
|
+
* @param params.browserSafeLocale - The browser safe locale.
|
|
43
|
+
* @param params.forceLatin - Whether to force the latin locale.
|
|
44
|
+
* @param params.stripZeros - Whether to strip zeros.
|
|
45
|
+
* @param params.signForPositive - Whether to show the sign for positive numbers.
|
|
46
|
+
* @return {Intl.NumberFormat} The currency formatter.
|
|
47
|
+
*/
|
|
48
|
+
function getCurrencyFormatter({ number, currency, browserSafeLocale, forceLatin = true, stripZeros, signForPositive, }) {
|
|
49
|
+
/**
|
|
50
|
+
* `numberingSystem` is an option to `Intl.NumberFormat` and is available
|
|
51
|
+
* in all major browsers according to
|
|
52
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
|
|
53
|
+
* but is not part of the TypeScript types in `es2020`:
|
|
54
|
+
*
|
|
55
|
+
* https://github.com/microsoft/TypeScript/blob/cfd472f7aa5a2010a3115263bf457b30c5b489f3/src/lib/es2020.intl.d.ts#L272
|
|
56
|
+
*
|
|
57
|
+
* However, it is part of the TypeScript types in `es5`:
|
|
58
|
+
*
|
|
59
|
+
* https://github.com/microsoft/TypeScript/blob/cfd472f7aa5a2010a3115263bf457b30c5b489f3/src/lib/es5.d.ts#L4310
|
|
60
|
+
*
|
|
61
|
+
* Apparently calypso uses `es2020` so we cannot use that option here right
|
|
62
|
+
* now. Instead, we will use the unicode extension to the locale, documented
|
|
63
|
+
* here:
|
|
64
|
+
*
|
|
65
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem#adding_a_numbering_system_via_the_locale_string
|
|
66
|
+
*/
|
|
67
|
+
const locale = `${browserSafeLocale}${forceLatin ? '-u-nu-latn' : ''}`;
|
|
68
|
+
const numberFormatOptions = {
|
|
69
|
+
style: 'currency',
|
|
70
|
+
currency,
|
|
71
|
+
...(stripZeros &&
|
|
72
|
+
Number.isInteger(number) && {
|
|
73
|
+
/**
|
|
74
|
+
* There's an option called `trailingZeroDisplay` but it does not yet work
|
|
75
|
+
* in FF so we have to strip zeros manually.
|
|
76
|
+
*/
|
|
77
|
+
maximumFractionDigits: 0,
|
|
78
|
+
minimumFractionDigits: 0,
|
|
79
|
+
}),
|
|
80
|
+
...(signForPositive && { signDisplay: 'exceptZero' }),
|
|
81
|
+
};
|
|
82
|
+
return (0, get_cached_formatter_ts_1.getCachedFormatter)({
|
|
83
|
+
locale,
|
|
84
|
+
options: numberFormatOptions,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Returns the precision for a given locale and currency.
|
|
89
|
+
* @param browserSafeLocale - The browser safe locale.
|
|
90
|
+
* @param currency - The currency to get the precision for.
|
|
91
|
+
* @param forceLatin - Whether to force the latin locale.
|
|
92
|
+
* @return {number | undefined} The precision.
|
|
93
|
+
*/
|
|
94
|
+
function getPrecisionForLocaleAndCurrency(browserSafeLocale, currency, forceLatin) {
|
|
95
|
+
const formatter = getCurrencyFormatter({ number: 0, currency, browserSafeLocale, forceLatin });
|
|
96
|
+
/**
|
|
97
|
+
* For regular numbers, the default is 3 if neither `minimumFractionDigits` or `maximumFractionDigits` are set,
|
|
98
|
+
* otherwise the greatest betweem `minimumFractionDigits` and 3.
|
|
99
|
+
*
|
|
100
|
+
* For currencies, the default is dependent on the currency.
|
|
101
|
+
*
|
|
102
|
+
* This may also result in undefined, for several reasons:
|
|
103
|
+
* see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#significantdigitsfractiondigits_default_values
|
|
104
|
+
*/
|
|
105
|
+
return formatter.resolvedOptions().maximumFractionDigits;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Scales a number to a specified precision and rounds it to that precision.
|
|
109
|
+
* It ensures that all currency values are consistently rounded to the desired precision,
|
|
110
|
+
* avoiding issues with floating-point arithmetic.
|
|
111
|
+
* @param number - The number to scale.
|
|
112
|
+
* @param currencyPrecision - The precision to scale the number to.
|
|
113
|
+
* @return {number} The scaled number.
|
|
114
|
+
*/
|
|
115
|
+
function scaleNumberForPrecision(number, currencyPrecision) {
|
|
116
|
+
const scale = Math.pow(10, currencyPrecision);
|
|
117
|
+
return Math.round(number * scale) / scale;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Prepares a number for formatting.
|
|
121
|
+
* @param number - The number to prepare.
|
|
122
|
+
* @param currencyPrecision - The precision to prepare the number for.
|
|
123
|
+
* @param isSmallestUnit - Whether the number is the smallest unit of a currency.
|
|
124
|
+
* @return {number} The prepared number.
|
|
125
|
+
*/
|
|
126
|
+
function prepareNumberForFormatting(number,
|
|
127
|
+
// currencyPrecision here must be the precision of the currency, regardless
|
|
128
|
+
// of what precision is requested for display!
|
|
129
|
+
currencyPrecision, isSmallestUnit) {
|
|
130
|
+
if (isNaN(number)) {
|
|
131
|
+
debug('formatCurrency was called with NaN');
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
if (isSmallestUnit) {
|
|
135
|
+
if (!Number.isInteger(number)) {
|
|
136
|
+
debug('formatCurrency was called with isSmallestUnit and a float which will be rounded', number);
|
|
137
|
+
}
|
|
138
|
+
const smallestUnitDivisor = 10 ** currencyPrecision;
|
|
139
|
+
return scaleNumberForPrecision(Math.round(number) / smallestUnitDivisor, currencyPrecision);
|
|
140
|
+
}
|
|
141
|
+
return scaleNumberForPrecision(number, currencyPrecision);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Formats money with a given currency code.
|
|
145
|
+
*
|
|
146
|
+
* The currency will define the properties to use for this formatting, but
|
|
147
|
+
* those properties can be overridden using the options. Be careful when doing
|
|
148
|
+
* this.
|
|
149
|
+
*
|
|
150
|
+
* For currencies that include decimals, this will always return the amount
|
|
151
|
+
* with decimals included, even if those decimals are zeros. To exclude the
|
|
152
|
+
* zeros, use the `stripZeros` option. For example, the function will normally
|
|
153
|
+
* format `10.00` in `USD` as `$10.00` but when this option is true, it will
|
|
154
|
+
* return `$10` instead.
|
|
155
|
+
*
|
|
156
|
+
* Since rounding errors are common in floating point math, sometimes a price
|
|
157
|
+
* is provided as an integer in the smallest unit of a currency (eg: cents in
|
|
158
|
+
* USD or yen in JPY). Set the `isSmallestUnit` to change the function to
|
|
159
|
+
* operate on integer numbers instead. If this option is not set or false, the
|
|
160
|
+
* function will format the amount `1025` in `USD` as `$1,025.00`, but when the
|
|
161
|
+
* option is true, it will return `$10.25` instead.
|
|
162
|
+
*
|
|
163
|
+
* If the number is NaN, it will be treated as 0.
|
|
164
|
+
*
|
|
165
|
+
* If the currency code is not known, this will assume a default currency
|
|
166
|
+
* similar to USD.
|
|
167
|
+
*
|
|
168
|
+
* If `isSmallestUnit` is set and the number is not an integer, it will be
|
|
169
|
+
* rounded to an integer.
|
|
170
|
+
*
|
|
171
|
+
* @param params - The parameters for the currency formatter.
|
|
172
|
+
* @param params.number - The number to format.
|
|
173
|
+
* @param params.browserSafeLocale - The browser safe locale.
|
|
174
|
+
* @param params.currency - The currency to format.
|
|
175
|
+
* @param params.stripZeros - Whether to strip zeros.
|
|
176
|
+
* @param params.isSmallestUnit - Whether the number is the smallest unit of a currency.
|
|
177
|
+
* @param params.signForPositive - Whether to show the sign for positive numbers.
|
|
178
|
+
* @param params.geoLocation - The geo location of the user.
|
|
179
|
+
* @param params.forceLatin - Whether to force the latin locale.
|
|
180
|
+
* @return {string} A formatted string.
|
|
181
|
+
*/
|
|
182
|
+
const numberFormatCurrency = ({ number, browserSafeLocale, currency, stripZeros, isSmallestUnit, signForPositive, geoLocation, forceLatin, }) => {
|
|
183
|
+
const validCurrency = getValidCurrency(currency, geoLocation);
|
|
184
|
+
const currencyOverride = getCurrencyOverride(validCurrency, geoLocation);
|
|
185
|
+
const currencyPrecision = getPrecisionForLocaleAndCurrency(browserSafeLocale, validCurrency, forceLatin);
|
|
186
|
+
if (isSmallestUnit && typeof currencyPrecision === 'undefined') {
|
|
187
|
+
throw new Error(`Could not determine currency precision for ${validCurrency} in ${browserSafeLocale}`);
|
|
188
|
+
}
|
|
189
|
+
const numberAsFloat = prepareNumberForFormatting(number, currencyPrecision ?? 0, isSmallestUnit);
|
|
190
|
+
const formatter = getCurrencyFormatter({
|
|
191
|
+
number: numberAsFloat,
|
|
192
|
+
currency: validCurrency,
|
|
193
|
+
browserSafeLocale,
|
|
194
|
+
forceLatin,
|
|
195
|
+
stripZeros,
|
|
196
|
+
signForPositive,
|
|
197
|
+
});
|
|
198
|
+
const parts = formatter.formatToParts(numberAsFloat);
|
|
199
|
+
return parts.reduce((formatted, part) => {
|
|
200
|
+
switch (part.type) {
|
|
201
|
+
case 'currency':
|
|
202
|
+
if (currencyOverride?.symbol) {
|
|
203
|
+
return formatted + currencyOverride.symbol;
|
|
204
|
+
}
|
|
205
|
+
return formatted + part.value;
|
|
206
|
+
default:
|
|
207
|
+
return formatted + part.value;
|
|
208
|
+
}
|
|
209
|
+
}, '');
|
|
210
|
+
};
|
|
211
|
+
exports.numberFormatCurrency = numberFormatCurrency;
|
|
212
|
+
/**
|
|
213
|
+
* Returns a formatted price object which can be used to manually render a
|
|
214
|
+
* formatted currency (eg: if you wanted to render the currency symbol in a
|
|
215
|
+
* different font size).
|
|
216
|
+
*
|
|
217
|
+
* The currency will define the properties to use for this formatting, but
|
|
218
|
+
* those properties can be overridden using the options. Be careful when doing
|
|
219
|
+
* this.
|
|
220
|
+
*
|
|
221
|
+
* For currencies that include decimals, this will always return the amount
|
|
222
|
+
* with decimals included, even if those decimals are zeros. To exclude the
|
|
223
|
+
* zeros, use the `stripZeros` option. For example, the function will normally
|
|
224
|
+
* format `10.00` in `USD` as `$10.00` but when this option is true, it will
|
|
225
|
+
* return `$10` instead.
|
|
226
|
+
*
|
|
227
|
+
* Since rounding errors are common in floating point math, sometimes a price
|
|
228
|
+
* is provided as an integer in the smallest unit of a currency (eg: cents in
|
|
229
|
+
* USD or yen in JPY). Set the `isSmallestUnit` to change the function to
|
|
230
|
+
* operate on integer numbers instead. If this option is not set or false, the
|
|
231
|
+
* function will format the amount `1025` in `USD` as `$1,025.00`, but when the
|
|
232
|
+
* option is true, it will return `$10.25` instead.
|
|
233
|
+
*
|
|
234
|
+
* Note that the `integer` return value of this function is not a number, but a
|
|
235
|
+
* locale-formatted string which may include symbols like spaces, commas, or
|
|
236
|
+
* periods as group separators. Similarly, the `fraction` property is a string
|
|
237
|
+
* that contains the decimal separator.
|
|
238
|
+
*
|
|
239
|
+
* If the number is NaN, it will be treated as 0.
|
|
240
|
+
*
|
|
241
|
+
* If the currency code is not known, this will assume a default currency
|
|
242
|
+
* similar to USD.
|
|
243
|
+
*
|
|
244
|
+
* If `isSmallestUnit` is set and the number is not an integer, it will be
|
|
245
|
+
* rounded to an integer.
|
|
246
|
+
*
|
|
247
|
+
* @param params - The parameters for the currency formatter.
|
|
248
|
+
* @param params.number - The number to format.
|
|
249
|
+
* @param params.browserSafeLocale - The browser safe locale.
|
|
250
|
+
* @param params.currency - The currency to format.
|
|
251
|
+
* @param params.stripZeros - Whether to strip zeros.
|
|
252
|
+
* @param params.isSmallestUnit - Whether the number is the smallest unit of a currency.
|
|
253
|
+
* @param params.signForPositive - Whether to show the sign for positive numbers.
|
|
254
|
+
* @param params.geoLocation - The geo location of the user.
|
|
255
|
+
* @param params.forceLatin - Whether to force the latin locale.
|
|
256
|
+
* @return {CurrencyObject} A formatted string e.g. { symbol:'$', integer: '$99', fraction: '.99', sign: '-' }
|
|
257
|
+
*/
|
|
258
|
+
const getCurrencyObject = ({ number, browserSafeLocale, currency, stripZeros, isSmallestUnit, signForPositive, geoLocation, forceLatin, }) => {
|
|
259
|
+
const validCurrency = getValidCurrency(currency, geoLocation);
|
|
260
|
+
const currencyOverride = getCurrencyOverride(validCurrency, geoLocation);
|
|
261
|
+
const currencyPrecision = getPrecisionForLocaleAndCurrency(browserSafeLocale, validCurrency, forceLatin);
|
|
262
|
+
const numberAsFloat = prepareNumberForFormatting(number, currencyPrecision ?? 0, isSmallestUnit);
|
|
263
|
+
const formatter = getCurrencyFormatter({
|
|
264
|
+
number: numberAsFloat,
|
|
265
|
+
currency: validCurrency,
|
|
266
|
+
browserSafeLocale,
|
|
267
|
+
forceLatin,
|
|
268
|
+
stripZeros,
|
|
269
|
+
signForPositive,
|
|
270
|
+
});
|
|
271
|
+
const parts = formatter.formatToParts(numberAsFloat);
|
|
272
|
+
let sign = '';
|
|
273
|
+
let symbol = '$';
|
|
274
|
+
let symbolPosition = 'before';
|
|
275
|
+
let hasAmountBeenSet = false;
|
|
276
|
+
let hasDecimalBeenSet = false;
|
|
277
|
+
let integer = '';
|
|
278
|
+
let fraction = '';
|
|
279
|
+
parts.forEach(part => {
|
|
280
|
+
switch (part.type) {
|
|
281
|
+
case 'currency':
|
|
282
|
+
symbol = currencyOverride?.symbol ?? part.value;
|
|
283
|
+
if (hasAmountBeenSet) {
|
|
284
|
+
symbolPosition = 'after';
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
case 'group':
|
|
288
|
+
integer += part.value;
|
|
289
|
+
hasAmountBeenSet = true;
|
|
290
|
+
return;
|
|
291
|
+
case 'decimal':
|
|
292
|
+
fraction += part.value;
|
|
293
|
+
hasAmountBeenSet = true;
|
|
294
|
+
hasDecimalBeenSet = true;
|
|
295
|
+
return;
|
|
296
|
+
case 'integer':
|
|
297
|
+
integer += part.value;
|
|
298
|
+
hasAmountBeenSet = true;
|
|
299
|
+
return;
|
|
300
|
+
case 'fraction':
|
|
301
|
+
fraction += part.value;
|
|
302
|
+
hasAmountBeenSet = true;
|
|
303
|
+
hasDecimalBeenSet = true;
|
|
304
|
+
return;
|
|
305
|
+
case 'minusSign':
|
|
306
|
+
sign = '-';
|
|
307
|
+
return;
|
|
308
|
+
case 'plusSign':
|
|
309
|
+
sign = '+';
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
const hasNonZeroFraction = !Number.isInteger(numberAsFloat) && hasDecimalBeenSet;
|
|
313
|
+
return {
|
|
314
|
+
sign,
|
|
315
|
+
symbol,
|
|
316
|
+
symbolPosition,
|
|
317
|
+
integer,
|
|
318
|
+
fraction,
|
|
319
|
+
hasNonZeroFraction,
|
|
320
|
+
};
|
|
321
|
+
};
|
|
322
|
+
exports.getCurrencyObject = getCurrencyObject;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.numberFormatCompact = exports.numberFormat = void 0;
|
|
4
|
+
const get_cached_formatter_ts_1 = require("./get-cached-formatter.cjs");
|
|
5
|
+
/**
|
|
6
|
+
* Formats numbers using locale settings and/or passed options.
|
|
7
|
+
* @param params - The parameters for the number formatter.
|
|
8
|
+
* @param params.browserSafeLocale - The browser safe locale.
|
|
9
|
+
* @param params.decimals - The number of decimal places to use.
|
|
10
|
+
* @param params.forceLatin - Whether to force the latin locale.
|
|
11
|
+
* @param params.numberFormatOptions - The options for the number formatter.
|
|
12
|
+
* @return {Intl.NumberFormat} The number formatter.
|
|
13
|
+
*/
|
|
14
|
+
const numberFormat = ({ browserSafeLocale, decimals = 0, forceLatin = true, numberFormatOptions = {}, }) => {
|
|
15
|
+
/**
|
|
16
|
+
* `numberingSystem` is an option to `Intl.NumberFormat` and is available
|
|
17
|
+
* in all major browsers according to
|
|
18
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
|
|
19
|
+
* but is not part of the TypeScript types in `es2020`:
|
|
20
|
+
*
|
|
21
|
+
* https://github.com/microsoft/TypeScript/blob/cfd472f7aa5a2010a3115263bf457b30c5b489f3/src/lib/es2020.intl.d.ts#L272
|
|
22
|
+
*
|
|
23
|
+
* However, it is part of the TypeScript types in `es5`:
|
|
24
|
+
*
|
|
25
|
+
* https://github.com/microsoft/TypeScript/blob/cfd472f7aa5a2010a3115263bf457b30c5b489f3/src/lib/es5.d.ts#L4310
|
|
26
|
+
*
|
|
27
|
+
* Apparently calypso uses `es2020` so we cannot use that option here right
|
|
28
|
+
* now. Instead, we will use the unicode extension to the locale, documented
|
|
29
|
+
* here:
|
|
30
|
+
*
|
|
31
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem#adding_a_numbering_system_via_the_locale_string
|
|
32
|
+
*/
|
|
33
|
+
const locale = `${browserSafeLocale}${forceLatin ? '-u-nu-latn' : ''}`;
|
|
34
|
+
const options = {
|
|
35
|
+
minimumFractionDigits: decimals, // minimumFractionDigits default is 0
|
|
36
|
+
maximumFractionDigits: decimals, // maximumFractionDigits default is the greater between minimumFractionDigits and 3
|
|
37
|
+
...numberFormatOptions,
|
|
38
|
+
};
|
|
39
|
+
return (0, get_cached_formatter_ts_1.getCachedFormatter)({ locale, options });
|
|
40
|
+
};
|
|
41
|
+
exports.numberFormat = numberFormat;
|
|
42
|
+
/**
|
|
43
|
+
* Convenience method for formatting numbers in a compact notation e.g. 1K, 1M, etc.
|
|
44
|
+
* Basically sets `notation: 'compact'` and `maximumFractionDigits: 1` in the options.
|
|
45
|
+
* Everything is overridable by passing the `numberFormatOptions` option.
|
|
46
|
+
* If you want more digits, pass `maximumFractionDigits: 2`.
|
|
47
|
+
* @param params - The parameters for the number formatter.
|
|
48
|
+
* @param params.numberFormatOptions - The options for the number formatter.
|
|
49
|
+
* @return {Intl.NumberFormat} The number formatter.
|
|
50
|
+
*/
|
|
51
|
+
const numberFormatCompact = ({ numberFormatOptions = {}, ...params }) => numberFormat({
|
|
52
|
+
...params,
|
|
53
|
+
numberFormatOptions: {
|
|
54
|
+
notation: 'compact',
|
|
55
|
+
maximumFractionDigits: 1,
|
|
56
|
+
...numberFormatOptions,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
exports.numberFormatCompact = numberFormatCompact;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getSettings } from '@wordpress/date';
|
|
2
|
-
import { FALLBACK_LOCALE } from
|
|
3
|
-
import { numberFormatCurrency, getCurrencyObject as getCurrencyObjectFromCurrencyFormatter, } from
|
|
4
|
-
import { numberFormat, numberFormatCompact } from
|
|
2
|
+
import { FALLBACK_LOCALE } from "./constants.js";
|
|
3
|
+
import { numberFormatCurrency, getCurrencyObject as getCurrencyObjectFromCurrencyFormatter, } from "./number-format-currency/index.js";
|
|
4
|
+
import { numberFormat, numberFormatCompact } from "./number-format.js";
|
|
5
5
|
/**
|
|
6
6
|
* Creates a NumberFormatters instance that provides number and currency formatting functionality with locale awareness
|
|
7
7
|
* @return {NumberFormatters} A NumberFormatters instance
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import createNumberFormatters from
|
|
1
|
+
import createNumberFormatters from "./create-number-formatters.js";
|
|
2
2
|
const defaultFormatter = createNumberFormatters();
|
|
3
3
|
export const { setLocale, setGeoLocation, formatNumber, formatNumberCompact, formatCurrency, getCurrencyObject, } = defaultFormatter;
|
|
4
4
|
export { createNumberFormatters };
|
|
5
|
-
export * from './types.js';
|
|
6
5
|
// We can optionally export the formatters individually if we want to use them in a more granular way.
|
|
7
6
|
// export { numberFormat, numberFormatCompact, numberFormatCurrency, getCurrencyObject };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import debugFactory from 'debug';
|
|
2
|
-
import { FALLBACK_CURRENCY } from
|
|
3
|
-
import { getCachedFormatter } from
|
|
4
|
-
import { defaultCurrencyOverrides } from
|
|
2
|
+
import { FALLBACK_CURRENCY } from "../constants.js";
|
|
3
|
+
import { getCachedFormatter } from "../get-cached-formatter.js";
|
|
4
|
+
import { defaultCurrencyOverrides } from "./currencies.js";
|
|
5
5
|
const debug = debugFactory('number-formatters:number-format-currency');
|
|
6
6
|
/**
|
|
7
7
|
* Retrieves the currency override for a given currency.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import createNumberFormatters from './create-number-formatters.ts';
|
|
2
|
+
export declare const setLocale: (locale: string) => void, setGeoLocation: (geoLocation: string) => void, formatNumber: import("./types.ts").FormatNumber, formatNumberCompact: import("./types.ts").FormatNumber, formatCurrency: import("./types.ts").FormatCurrency, getCurrencyObject: import("./types.ts").GetCurrencyObject;
|
|
3
|
+
export { createNumberFormatters };
|
|
4
|
+
export type * from './types.ts';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { CurrencyOverride } from '../types.
|
|
1
|
+
import type { CurrencyOverride } from '../types.ts';
|
|
2
2
|
export declare const defaultCurrencyOverrides: Record<string, CurrencyOverride>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/number-formatters",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Number formatting utilities",
|
|
5
5
|
"author": "Automattic",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -14,30 +14,35 @@
|
|
|
14
14
|
"url": "https://github.com/Automattic/jetpack/labels/[JS Package] Number Formatters"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@
|
|
18
|
-
"
|
|
19
|
-
"
|
|
17
|
+
"@wordpress/date": "^5.19.0",
|
|
18
|
+
"debug": "^4.4.0",
|
|
19
|
+
"tslib": "^2.5.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@babel/core": "7.26.10",
|
|
23
23
|
"@babel/preset-react": "7.26.3",
|
|
24
24
|
"@jest/globals": "29.4.3",
|
|
25
|
+
"@knighted/duel": "2.1.4",
|
|
25
26
|
"@types/jest": "29.5.14",
|
|
26
27
|
"jest": "29.7.0",
|
|
27
28
|
"jest-environment-jsdom": "29.7.0",
|
|
28
29
|
"typescript": "5.8.2"
|
|
29
30
|
},
|
|
30
31
|
"type": "module",
|
|
32
|
+
"main": "./dist/cjs/index.cjs",
|
|
33
|
+
"module": "./dist/esm/index.js",
|
|
34
|
+
"types": "./dist/types/index.d.ts",
|
|
31
35
|
"exports": {
|
|
32
36
|
".": {
|
|
33
|
-
"types": "./dist/index.d.ts",
|
|
34
|
-
"
|
|
37
|
+
"types": "./dist/types/index.d.ts",
|
|
38
|
+
"import": "./dist/esm/index.js",
|
|
39
|
+
"require": "./dist/cjs/index.cjs"
|
|
35
40
|
}
|
|
36
41
|
},
|
|
37
42
|
"scripts": {
|
|
38
|
-
"build": "pnpm run clean && pnpm run
|
|
39
|
-
"
|
|
40
|
-
"
|
|
43
|
+
"build": "pnpm run clean && pnpm run build:ts",
|
|
44
|
+
"build:ts": "duel --dirs",
|
|
45
|
+
"clean": "rm -rf dist",
|
|
41
46
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
42
47
|
"test-coverage": "pnpm run test --coverage",
|
|
43
48
|
"typecheck": "tsc --noEmit"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getSettings } from '@wordpress/date';
|
|
2
|
-
import { FALLBACK_LOCALE } from './constants.
|
|
2
|
+
import { FALLBACK_LOCALE } from './constants.ts';
|
|
3
3
|
import {
|
|
4
4
|
numberFormatCurrency,
|
|
5
5
|
getCurrencyObject as getCurrencyObjectFromCurrencyFormatter,
|
|
6
|
-
} from './number-format-currency/index.
|
|
7
|
-
import { numberFormat, numberFormatCompact } from './number-format.
|
|
8
|
-
import type { CurrencyObject, FormatCurrency, FormatNumber, GetCurrencyObject } from './types.
|
|
6
|
+
} from './number-format-currency/index.ts';
|
|
7
|
+
import { numberFormat, numberFormatCompact } from './number-format.ts';
|
|
8
|
+
import type { CurrencyObject, FormatCurrency, FormatNumber, GetCurrencyObject } from './types.ts';
|
|
9
9
|
|
|
10
10
|
// Since global is used inside createNumberFormatters, we need to declare it for TS
|
|
11
11
|
declare const global: typeof globalThis;
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import createNumberFormatters from './create-number-formatters.
|
|
1
|
+
import createNumberFormatters from './create-number-formatters.ts';
|
|
2
2
|
|
|
3
3
|
const defaultFormatter = createNumberFormatters();
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ export const {
|
|
|
13
13
|
|
|
14
14
|
export { createNumberFormatters };
|
|
15
15
|
|
|
16
|
-
export * from './types.
|
|
16
|
+
export type * from './types.ts';
|
|
17
17
|
|
|
18
18
|
// We can optionally export the formatters individually if we want to use them in a more granular way.
|
|
19
19
|
// export { numberFormat, numberFormatCompact, numberFormatCurrency, getCurrencyObject };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import debugFactory from 'debug';
|
|
2
|
-
import { FALLBACK_CURRENCY } from '../constants.
|
|
3
|
-
import { getCachedFormatter } from '../get-cached-formatter.
|
|
4
|
-
import { defaultCurrencyOverrides } from './currencies.
|
|
5
|
-
import type { CurrencyOverride, CurrencyObject, NumberFormatCurrencyParams } from '../types.
|
|
2
|
+
import { FALLBACK_CURRENCY } from '../constants.ts';
|
|
3
|
+
import { getCachedFormatter } from '../get-cached-formatter.ts';
|
|
4
|
+
import { defaultCurrencyOverrides } from './currencies.ts';
|
|
5
|
+
import type { CurrencyOverride, CurrencyObject, NumberFormatCurrencyParams } from '../types.ts';
|
|
6
6
|
|
|
7
7
|
const debug = debugFactory( 'number-formatters:number-format-currency' );
|
|
8
8
|
|
package/src/number-format.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getCachedFormatter } from './get-cached-formatter.
|
|
2
|
-
import type { NumberFormatParams } from './types.
|
|
1
|
+
import { getCachedFormatter } from './get-cached-formatter.ts';
|
|
2
|
+
import type { NumberFormatParams } from './types.ts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Formats numbers using locale settings and/or passed options.
|
package/dist/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import createNumberFormatters from './create-number-formatters.js';
|
|
2
|
-
export declare const setLocale: (locale: string) => void, setGeoLocation: (geoLocation: string) => void, formatNumber: import("./types.js").FormatNumber, formatNumberCompact: import("./types.js").FormatNumber, formatCurrency: import("./types.js").FormatCurrency, getCurrencyObject: import("./types.js").GetCurrencyObject;
|
|
3
|
-
export { createNumberFormatters };
|
|
4
|
-
export * from './types.js';
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|