@lion/localize
Advanced tools
Comparing version 0.25.0 to 0.26.0
@@ -12,3 +12,3 @@ # Systems >> Localize >> Overview ||10 | ||
Further examples and a more in depth description can be found at the [Use Cases Page](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/use-cases.md). | ||
Further examples and a more in depth description can be found at the [Use Cases Page](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/use-cases.md). | ||
@@ -19,5 +19,5 @@ ## Content | ||
| ---------------------------------------- | --------------------------------------------- | | ||
| [Translate Text](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/text.md) | Load and translate text in multiple languages | | ||
| [Format Numbers](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/numbers.md) | Format numbers in multiple languages | | ||
| [Format Dates](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/dates.md) | Format dates in multiple languages | | ||
| [Translate Text](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/text.md) | Load and translate text in multiple languages | | ||
| [Format Numbers](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/numbers.md) | Format numbers in multiple languages | | ||
| [Format Dates](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/dates.md) | Format dates in multiple languages | | ||
@@ -24,0 +24,0 @@ ## Installation |
@@ -15,4 +15,5 @@ export { formatDate } from "./src/date/formatDate.js"; | ||
export { getGroupSeparator } from "./src/number/getGroupSeparator.js"; | ||
export { getSeparatorsFromNumber } from "./src/number/getSeparatorsFromNumber.js"; | ||
export { normalizeCurrencyLabel } from "./src/number/normalizeCurrencyLabel.js"; | ||
export { parseNumber } from "./src/number/parseNumber.js"; | ||
export { localize, setLocalize } from "./src/localize.js"; |
@@ -16,3 +16,4 @@ export { formatDate } from './src/date/formatDate.js'; | ||
export { getGroupSeparator } from './src/number/getGroupSeparator.js'; | ||
export { getSeparatorsFromNumber } from './src/number/getSeparatorsFromNumber.js'; | ||
export { normalizeCurrencyLabel } from './src/number/normalizeCurrencyLabel.js'; | ||
export { parseNumber } from './src/number/parseNumber.js'; |
{ | ||
"name": "@lion/localize", | ||
"version": "0.25.0", | ||
"version": "0.26.0", | ||
"description": "The localization system helps to manage localization data split into locales and automate its loading", | ||
@@ -38,3 +38,3 @@ "license": "MIT", | ||
"@bundled-es-modules/message-format": "6.0.4", | ||
"@lion/core": "^0.23.0", | ||
"@lion/core": "^0.24.0", | ||
"singleton-manager": "^1.5.0" | ||
@@ -41,0 +41,0 @@ }, |
@@ -12,3 +12,3 @@ # Systems >> Localize >> Overview ||10 | ||
Further examples and a more in depth description can be found at the [Use Cases Page](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/use-cases.md). | ||
Further examples and a more in depth description can be found at the [Use Cases Page](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/use-cases.md). | ||
@@ -19,5 +19,5 @@ ## Content | ||
| ---------------------------------------- | --------------------------------------------- | | ||
| [Translate Text](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/text.md) | Load and translate text in multiple languages | | ||
| [Format Numbers](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/numbers.md) | Format numbers in multiple languages | | ||
| [Format Dates](https://github.com/ing-bank/lion/blob/9ebc79431bfdcacfd0d9c9b6457c1a99686a6a47/docs/fundamentals/systems/localize/dates.md) | Format dates in multiple languages | | ||
| [Translate Text](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/text.md) | Load and translate text in multiple languages | | ||
| [Format Numbers](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/numbers.md) | Format numbers in multiple languages | | ||
| [Format Dates](https://github.com/ing-bank/lion/blob/650657231a4ec83592d45cd69836d28436635340/docs/fundamentals/systems/localize/dates.md) | Format dates in multiple languages | | ||
@@ -24,0 +24,0 @@ ## Installation |
import { emptyStringWhenNumberNan } from './utils/emptyStringWhenNumberNan.js'; | ||
import { getSeparatorsFromNumber } from './getSeparatorsFromNumber.js'; | ||
import { getDecimalSeparator } from './getDecimalSeparator.js'; | ||
@@ -51,6 +52,12 @@ import { getGroupSeparator } from './getGroupSeparator.js'; | ||
const formattedNumber = Intl.NumberFormat(computedLocale, options).format(parsedNumber); | ||
const regexCurrency = /[.,\s0-9]/; | ||
const { decimalSeparator, groupSeparator } = getSeparatorsFromNumber( | ||
parsedNumber, | ||
formattedNumber, | ||
options, | ||
); | ||
// eslint-disable-next-line no-irregular-whitespace | ||
const regexCurrency = /[.,\s0-9 _ ]/; | ||
const regexMinusSign = /[-]/; // U+002D, Hyphen-Minus, - | ||
const regexNum = /[0-9]/; | ||
const regexSeparator = /[.,]/; | ||
const regexSpace = /[\s]/; | ||
@@ -60,2 +67,11 @@ let currency = ''; | ||
let fraction = false; | ||
let isGroup = false; | ||
const group = getGroupSeparator(computedLocale, options); | ||
const decimal = getDecimalSeparator(computedLocale, options); | ||
if (decimalSeparator && groupSeparator && group === decimal) { | ||
throw new Error(`Decimal and group (thousand) separator are the same character: '${group}'. | ||
This can happen due to both props being specified as the same, or one of the props being the same as the other one from default locale. | ||
Please specify .groupSeparator / .decimalSeparator on the formatOptions object to be different.`); | ||
} | ||
for (let i = 0; i < formattedNumber.length; i += 1) { | ||
@@ -81,4 +97,8 @@ // detect minusSign | ||
// detect dot and comma separators | ||
if (regexSeparator.test(formattedNumber[i])) { | ||
// group sep must be lead by / followed by a number | ||
if ( | ||
formattedNumber[i] === groupSeparator && | ||
formattedNumber[i - 1].match(regexNum) && | ||
formattedNumber[i + 1].match(regexNum) | ||
) { | ||
// Write number grouping | ||
@@ -89,13 +109,20 @@ if (numberPart) { | ||
} | ||
const decimal = getDecimalSeparator(computedLocale); | ||
if (formattedNumber[i] === decimal) { | ||
formattedParts.push({ type: 'decimal', value: formattedNumber[i] }); | ||
fraction = true; | ||
} else { | ||
formattedParts.push({ type: 'group', value: formattedNumber[i] }); | ||
formattedParts.push({ type: 'group', value: group }); | ||
isGroup = true; | ||
} | ||
if (formattedNumber[i] === decimalSeparator) { | ||
// Write number grouping | ||
if (numberPart) { | ||
formattedParts.push({ type: 'integer', value: numberPart }); | ||
numberPart = ''; | ||
} | ||
formattedParts.push({ type: 'decimal', value: decimal }); | ||
fraction = true; | ||
} | ||
// detect literals (empty spaces) or space group separator | ||
if (regexSpace.test(formattedNumber[i])) { | ||
const group = getGroupSeparator(computedLocale); | ||
const hasNumberPart = !!numberPart; | ||
@@ -113,6 +140,8 @@ // Write number grouping | ||
formattedParts.push({ type: 'group', value: formattedNumber[i] }); | ||
} else { | ||
// if we already pushed it as a group separator, don't add it as a literal on top.. | ||
} else if (!isGroup) { | ||
formattedParts.push({ type: 'literal', value: formattedNumber[i] }); | ||
} | ||
} | ||
isGroup = false; | ||
// Numbers after the decimal sign are fractions, write the last | ||
@@ -119,0 +148,0 @@ // fractions at the end of the number |
@@ -5,4 +5,5 @@ /** | ||
* @param {string} [locale] To override the browser locale | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] | ||
* @returns {string} The separator | ||
*/ | ||
export function getDecimalSeparator(locale?: string | undefined): string; | ||
export function getDecimalSeparator(locale?: string | undefined, options?: import("../../types/LocalizeMixinTypes").FormatNumberOptions | undefined): string; |
@@ -7,5 +7,9 @@ import { getLocale } from '../utils/getLocale.js'; | ||
* @param {string} [locale] To override the browser locale | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] | ||
* @returns {string} The separator | ||
*/ | ||
export function getDecimalSeparator(locale) { | ||
export function getDecimalSeparator(locale, options) { | ||
if (options && options.decimalSeparator) { | ||
return options.decimalSeparator; | ||
} | ||
const computedLocale = getLocale(locale); | ||
@@ -12,0 +16,0 @@ const formattedNumber = Intl.NumberFormat(computedLocale, { |
@@ -5,4 +5,5 @@ /** | ||
* @param {string} [locale] To override the browser locale | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] | ||
* @returns {string} | ||
*/ | ||
export function getGroupSeparator(locale?: string | undefined): string; | ||
export function getGroupSeparator(locale?: string | undefined, options?: import("../../types/LocalizeMixinTypes").FormatNumberOptions | undefined): string; |
@@ -8,5 +8,9 @@ import { getLocale } from '../utils/getLocale.js'; | ||
* @param {string} [locale] To override the browser locale | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] | ||
* @returns {string} | ||
*/ | ||
export function getGroupSeparator(locale) { | ||
export function getGroupSeparator(locale, options) { | ||
if (options && options.groupSeparator) { | ||
return options.groupSeparator; | ||
} | ||
const computedLocale = getLocale(locale); | ||
@@ -13,0 +17,0 @@ const formattedNumber = Intl.NumberFormat(computedLocale, { |
@@ -18,4 +18,4 @@ /** | ||
* @param {string} value Number to be parsed | ||
* @param {object} [options] Locale Options | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] Locale Options | ||
*/ | ||
export function parseNumber(value: string, options?: object | undefined): number | undefined; | ||
export function parseNumber(value: string, options?: import("../../types/LocalizeMixinTypes").FormatNumberOptions | undefined): number | undefined; |
@@ -67,8 +67,7 @@ import { getDecimalSeparator } from './getDecimalSeparator.js'; | ||
* @param {string} value Number to be parsed | ||
* @param {Object} options Locale Options | ||
* @param {string} [options.locale] | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} options Locale Options | ||
*/ | ||
function parseWithLocale(value, options) { | ||
const locale = options && options.locale ? options.locale : undefined; | ||
const separator = getDecimalSeparator(locale); | ||
const separator = getDecimalSeparator(locale, options); | ||
const regexNumberAndLocaleSeparator = new RegExp(`[0-9${separator}-]`, 'g'); | ||
@@ -99,3 +98,3 @@ let numberAndLocaleSeparator = value.match(regexNumberAndLocaleSeparator)?.join(''); | ||
.replace(/(,|\.)([^,|.]*)$/g, '_decSep_$2') | ||
.replace(/(,|\.| )/g, '') // 2. remove all thousand separators | ||
.replace(/(,|\.| )/g, '') // 2. remove all group separators | ||
.replace(/_decSep_/, '.'); // 3. restore decimal separator | ||
@@ -124,3 +123,3 @@ return parseFloat(numberString); | ||
* @param {string} value Number to be parsed | ||
* @param {object} [options] Locale Options | ||
* @param {import('../../types/LocalizeMixinTypes').FormatNumberOptions} [options] Locale Options | ||
*/ | ||
@@ -127,0 +126,0 @@ export function parseNumber(value, options) { |
@@ -182,4 +182,62 @@ import { expect } from '@open-wc/testing'; | ||
).to.equal('112.345.678,00'); | ||
expect( | ||
formatNumber(112345678, { | ||
style: 'decimal', | ||
minimumFractionDigits: 2, | ||
maximumFractionDigits: 2, | ||
groupSeparator: ' ', | ||
decimalSeparator: '.', | ||
}), | ||
).to.equal('112 345 678.00'); | ||
}); | ||
it('throws when decimal and group separator are the same value, only when problematic', () => { | ||
localize.locale = 'nl-NL'; | ||
const fn = () => | ||
formatNumber(112345678, { | ||
style: 'decimal', | ||
minimumFractionDigits: 2, | ||
maximumFractionDigits: 2, | ||
decimalSeparator: '.', // same as group separator for nl-NL | ||
}); | ||
expect(fn).to.throw(`Decimal and group (thousand) separator are the same character: '.'. | ||
This can happen due to both props being specified as the same, or one of the props being the same as the other one from default locale. | ||
Please specify .groupSeparator / .decimalSeparator on the formatOptions object to be different.`); | ||
const fn2 = () => | ||
formatNumber(112345678, { | ||
style: 'decimal', | ||
minimumFractionDigits: 2, | ||
maximumFractionDigits: 2, | ||
groupSeparator: ',', | ||
decimalSeparator: ',', | ||
}); | ||
expect(fn2).to.throw(`Decimal and group (thousand) separator are the same character: ','. | ||
This can happen due to both props being specified as the same, or one of the props being the same as the other one from default locale. | ||
Please specify .groupSeparator / .decimalSeparator on the formatOptions object to be different.`); | ||
// this one doesn't end up with decimals, so not a problem | ||
const fn3 = () => | ||
formatNumber(112345678, { | ||
groupSeparator: ',', | ||
decimalSeparator: ',', | ||
}); | ||
expect(fn3).to.not.throw(); | ||
// this one doesn't end up with group separators (<1000), so not a problem | ||
const fn4 = () => | ||
formatNumber(112.345678, { | ||
style: 'decimal', | ||
minimumFractionDigits: 2, | ||
maximumFractionDigits: 2, | ||
groupSeparator: ',', | ||
decimalSeparator: ',', | ||
}); | ||
expect(fn4).to.not.throw(); | ||
}); | ||
it('formats 2-digit decimals correctly', () => { | ||
@@ -186,0 +244,0 @@ localize.locale = 'nl-NL'; |
@@ -11,2 +11,7 @@ import { expect } from '@open-wc/testing'; | ||
}); | ||
it('will return the decimalSeparator from options if passed', () => { | ||
expect(getDecimalSeparator('nl-NL')).to.equal(','); | ||
expect(getDecimalSeparator('nl-NL', { decimalSeparator: '.' })).to.equal('.'); | ||
}); | ||
}); |
@@ -22,3 +22,2 @@ import { Constructor } from '@open-wc/dedupe-mixin'; | ||
returnIfNaN?: string; | ||
decimalSeparator?: string; | ||
mode?: 'pasted' | 'auto'; | ||
@@ -39,3 +38,7 @@ | ||
returnIfNaN?: string; | ||
decimalSeparator?: string; | ||
// https://en.wikipedia.org/wiki/Decimal_separator#Current_standards | ||
decimalSeparator?: ',' | '.'; | ||
// https://en.wikipedia.org/wiki/Decimal_separator#Digit_grouping | ||
// note the half space in there as well | ||
groupSeparator?: ',' | '.' | ' ' | '_' | ' ' | "'"; | ||
mode?: 'pasted' | 'auto'; | ||
@@ -42,0 +45,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
255220
144
5773
+ Added@lion/core@0.24.0(transitive)
- Removed@lion/core@0.23.1(transitive)
Updated@lion/core@^0.24.0