Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

@lion/localize

Package Overview
Dependencies
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lion/localize - npm Package Compare versions

Comparing version
0.20.2
to
0.21.0
+20
src/number/parseNumber.d.ts
/**
* Parses a number string and returns the best possible javascript number.
* For edge cases it may use locale to give the best possible assumption.
*
* It has 3 "methods" of returning numbers
* - 'unparseable': becomes just numbers
* - 'withLocale': result depends on given or global locale
* - 'heuristic': result depends on considering separators
*
* @example
* parseNumber('1.234.567'); // method: unparseable => 1234567
* parseNumber('1.234'); // method: withLocale => depending on locale 1234 or 1.234
* parseNumber('1.234,56'); // method: heuristic => 1234.56
* parseNumber('1 234.56'); // method: heuristic => 1234.56
* parseNumber('1,234.56'); // method: heuristic => 1234.56
*
* @param {string} value Number to be parsed
* @param {object} [options] Locale Options
*/
export function parseNumber(value: string, options?: object | undefined): number | undefined;
import { getDecimalSeparator } from './getDecimalSeparator.js';
/**
* @param {string} value to evaluate
* @return {boolean} true if value equal . or ,
*/
function isDecimalSeparator(value) {
return value === '.' || value === ',';
}
/**
* Determines the best possible parsing mode.
*
* - If there is only one separator (withLocale)
* - 1,23 => xxx1.23 (heuristic)
* - else parse mode depends mostly on the last 4 chars
* - 1234 => xxx1234 (heuristic)
* - [space]123 => xxx123 (heuristic)
* - ,123 => unclear
* - if 1.000,123 (we find a different separator) => 1000.123 (heuristic)
* - if 1,000,123 (we find only same separators) => 1000123 (unparseable)
* - if 100,123 (we find no more separators) => unclear
* - if en => 100123 (withLocale)
* - if nl => 100.123 (withLocale)
*
* See also {@link parseAmount}
*
* @example
* getParseMode('1.234') => 'withLocale'
*
* @param {string} value Clean number (only [0-9 ,.]) to be parsed
* @return {string} unparseable|withLocale|heuristic
*/
function getParseMode(value, { mode = 'auto' } = {}) {
const separators = value.match(/[., ]/g);
if (mode === 'auto' && separators && separators.length === 1) {
return 'withLocale';
}
if (value.length > 4) {
const charAtLastSeparatorPosition = value[value.length - 4];
if (isDecimalSeparator(charAtLastSeparatorPosition)) {
const firstPart = value.substring(0, value.length - 4);
const otherSeparators = firstPart.match(/[., ]/g);
if (otherSeparators) {
const lastSeparator = charAtLastSeparatorPosition;
return otherSeparators.indexOf(lastSeparator) === -1 ? 'heuristic' : 'unparseable';
}
return 'withLocale';
}
}
return 'heuristic';
}
/**
* Parses numbers by considering the locale.
* Useful for numbers with an ending pair of 3 number chars as in this case you can not be
* certain if it is a group or comma separator. e.g. 1.234; 1,234; 1234.567;
* Taking into consideration the locale we make the best possible assumption.
*
* @example
* parseWithLocale('1.234', { locale: 'en-GB' }) => 1.234
* parseWithLocale('1,234', { locale: 'en-GB' }) => 1234
*
* @param {string} value Number to be parsed
* @param {Object} options Locale Options
* @param {string} [options.locale]
*/
function parseWithLocale(value, options) {
const locale = options && options.locale ? options.locale : undefined;
const separator = getDecimalSeparator(locale);
const regexNumberAndLocaleSeparator = new RegExp(`[0-9${separator}-]`, 'g');
let numberAndLocaleSeparator = value.match(regexNumberAndLocaleSeparator)?.join('');
if (separator === ',') {
numberAndLocaleSeparator = numberAndLocaleSeparator?.replace(',', '.');
}
if (!numberAndLocaleSeparator) {
return NaN;
}
return parseFloat(numberAndLocaleSeparator);
}
/**
* Parses numbers by considering all separators.
* It only keeps the last separator and uses it as decimal separator.
*
* Warning: This function works only with numbers that can be heuristically parsed.
*
* @param {string} value Number that can be heuristically parsed
* @return {number} parsed javascript number
*/
function parseHeuristic(value) {
if (value.match(/[0-9., ]/g)) {
// 1. put placeholder at decimal separator
const numberString = value
.replace(/(,|\.)([^,|.]*)$/g, '_decSep_$2')
.replace(/(,|\.| )/g, '') // 2. remove all thousand separators
.replace(/_decSep_/, '.'); // 3. restore decimal separator
return parseFloat(numberString);
}
return 0;
}
/**
* Parses a number string and returns the best possible javascript number.
* For edge cases it may use locale to give the best possible assumption.
*
* It has 3 "methods" of returning numbers
* - 'unparseable': becomes just numbers
* - 'withLocale': result depends on given or global locale
* - 'heuristic': result depends on considering separators
*
* @example
* parseNumber('1.234.567'); // method: unparseable => 1234567
* parseNumber('1.234'); // method: withLocale => depending on locale 1234 or 1.234
* parseNumber('1.234,56'); // method: heuristic => 1234.56
* parseNumber('1 234.56'); // method: heuristic => 1234.56
* parseNumber('1,234.56'); // method: heuristic => 1234.56
*
* @param {string} value Number to be parsed
* @param {object} [options] Locale Options
*/
export function parseNumber(value, options) {
const containsNumbers = value.match(/\d/g);
if (!containsNumbers) {
return undefined;
}
const matchedInput = value.match(/[0-9,.\- ]/g);
if (!matchedInput) {
return undefined;
}
const cleanedInput = matchedInput.join('');
const parseMode = getParseMode(cleanedInput, options);
switch (parseMode) {
case 'unparseable': {
const cleanedInputMatchStr = cleanedInput.match(/[0-9]/g)?.join('');
if (!cleanedInputMatchStr) {
return NaN;
}
return parseFloat(cleanedInputMatchStr);
}
case 'withLocale':
return parseWithLocale(cleanedInput, options || {});
case 'heuristic':
return parseHeuristic(cleanedInput);
default:
return 0;
}
}
import { expect } from '@open-wc/testing';
import { localize } from '@lion/localize';
import { parseNumber } from '../../src/number/parseNumber.js';
describe('parseNumber()', () => {
it('parses integers', () => {
expect(parseNumber('1')).to.equal(1);
expect(parseNumber('12')).to.equal(12);
expect(parseNumber('123')).to.equal(123);
expect(parseNumber('1234')).to.equal(1234);
expect(parseNumber('12345')).to.equal(12345);
expect(parseNumber('123456')).to.equal(123456);
expect(parseNumber('1234567')).to.equal(1234567);
expect(parseNumber('12345678')).to.equal(12345678);
expect(parseNumber('123456789')).to.equal(123456789);
});
it('detects separators heuristically when there are 2 different ones e.g. 1,234.5', () => {
expect(parseNumber('1,234.5')).to.equal(1234.5);
expect(parseNumber('1.234,5')).to.equal(1234.5);
expect(parseNumber('1 234.5')).to.equal(1234.5);
expect(parseNumber('1 234,5')).to.equal(1234.5);
expect(parseNumber('1,234.56')).to.equal(1234.56);
expect(parseNumber('1.234,56')).to.equal(1234.56);
expect(parseNumber('1 234.56')).to.equal(1234.56);
expect(parseNumber('1 234,56')).to.equal(1234.56);
expect(parseNumber('1,234.567')).to.equal(1234.567);
expect(parseNumber('1.234,567')).to.equal(1234.567);
expect(parseNumber('1 234.567')).to.equal(1234.567);
expect(parseNumber('1 234,567')).to.equal(1234.567);
expect(parseNumber('1,234.5678')).to.equal(1234.5678);
expect(parseNumber('1.234,5678')).to.equal(1234.5678);
expect(parseNumber('1 234.5678')).to.equal(1234.5678);
expect(parseNumber('1 234,5678')).to.equal(1234.5678);
expect(parseNumber('1,234.56789')).to.equal(1234.56789);
expect(parseNumber('1.234,56789')).to.equal(1234.56789);
expect(parseNumber('1 234.56789')).to.equal(1234.56789);
expect(parseNumber('1 234,56789')).to.equal(1234.56789);
});
it('detects separators heuristically when there is only one and "pasted" mode used e.g. 123456,78', () => {
expect(parseNumber('1.', { mode: 'pasted' })).to.equal(1);
expect(parseNumber('1,', { mode: 'pasted' })).to.equal(1);
expect(parseNumber('1 ', { mode: 'pasted' })).to.equal(1);
expect(parseNumber('1.2', { mode: 'pasted' })).to.equal(1.2);
expect(parseNumber('1,2', { mode: 'pasted' })).to.equal(1.2);
expect(parseNumber('1 2', { mode: 'pasted' })).to.equal(12);
expect(parseNumber('1.23', { mode: 'pasted' })).to.equal(1.23);
expect(parseNumber('1,23', { mode: 'pasted' })).to.equal(1.23);
expect(parseNumber('1 23', { mode: 'pasted' })).to.equal(123);
expect(parseNumber('1 234', { mode: 'pasted' })).to.equal(1234);
expect(parseNumber('1.2345', { mode: 'pasted' })).to.equal(1.2345);
expect(parseNumber('1,2345', { mode: 'pasted' })).to.equal(1.2345);
expect(parseNumber('1 2345', { mode: 'pasted' })).to.equal(12345);
expect(parseNumber('1.23456', { mode: 'pasted' })).to.equal(1.23456);
expect(parseNumber('1,23456', { mode: 'pasted' })).to.equal(1.23456);
expect(parseNumber('1 23456', { mode: 'pasted' })).to.equal(123456);
expect(parseNumber('1.234567', { mode: 'pasted' })).to.equal(1.234567);
expect(parseNumber('1,234567', { mode: 'pasted' })).to.equal(1.234567);
expect(parseNumber('1 234567', { mode: 'pasted' })).to.equal(1234567);
expect(parseNumber('123456,78', { mode: 'pasted' })).to.equal(123456.78);
expect(parseNumber('123456.78', { mode: 'pasted' })).to.equal(123456.78);
});
it('detects separators heuristically when there are 2 same ones e.g. 1.234.56', () => {
expect(parseNumber('1.234.5')).to.equal(1234.5);
expect(parseNumber('1,234,5')).to.equal(1234.5);
expect(parseNumber('1.234.56')).to.equal(1234.56);
expect(parseNumber('1,234,56')).to.equal(1234.56);
expect(parseNumber('1 234 56')).to.equal(123456);
expect(parseNumber('1.234.5678')).to.equal(1234.5678);
expect(parseNumber('1,234,5678')).to.equal(1234.5678);
expect(parseNumber('1.234.56789')).to.equal(1234.56789);
expect(parseNumber('1,234,56789')).to.equal(1234.56789);
});
it('uses locale to parse amount if there is only one separator e.g. 1.234', () => {
localize.locale = 'en-GB';
expect(parseNumber('12.34')).to.equal(12.34);
expect(parseNumber('12,34')).to.equal(1234);
expect(parseNumber('1.234')).to.equal(1.234);
expect(parseNumber('1,234')).to.equal(1234);
localize.locale = 'nl-NL';
expect(parseNumber('12.34')).to.equal(1234);
expect(parseNumber('12,34')).to.equal(12.34);
expect(parseNumber('1.234')).to.equal(1234);
expect(parseNumber('1,234')).to.equal(1.234);
});
it('returns numbers only if it can not be interpreted e.g. 1.234.567', () => {
// impossible to interpret unambiguously even with locale knowledge
expect(parseNumber('1.234.567')).to.equal(1234567);
expect(parseNumber('1,234,567')).to.equal(1234567);
});
it('keeps only last separator for "broken" numbers like 1.23,4', () => {
expect(parseNumber('1.23,4')).to.equal(123.4);
expect(parseNumber('1,23.4')).to.equal(123.4);
expect(parseNumber('1 23,4')).to.equal(123.4);
expect(parseNumber('1 23.4')).to.equal(123.4);
});
it('parses negative numbers', () => {
expect(parseNumber('-0')).to.equal(0);
expect(parseNumber('-1')).to.equal(-1);
expect(parseNumber('-1234')).to.equal(-1234);
expect(parseNumber('-1.234,5')).to.equal(-1234.5);
expect(parseNumber('-1,234.5')).to.equal(-1234.5);
expect(parseNumber('-1.234,5678')).to.equal(-1234.5678);
expect(parseNumber('-1,234.5678')).to.equal(-1234.5678);
});
it('ignores all non-number symbols (including currency)', () => {
expect(parseNumber('€ 1,234.56')).to.equal(1234.56);
expect(parseNumber('€ -1,234.56')).to.equal(-1234.56);
expect(parseNumber('-€ 1,234.56')).to.equal(-1234.56);
expect(parseNumber('1,234.56 €')).to.equal(1234.56);
expect(parseNumber('-1,234.56 €')).to.equal(-1234.56);
expect(parseNumber('EUR 1,234.56')).to.equal(1234.56);
expect(parseNumber('EUR -1,234.56')).to.equal(-1234.56);
expect(parseNumber('-EUR 1,234.56')).to.equal(-1234.56);
expect(parseNumber('1,234.56 EUR')).to.equal(1234.56);
expect(parseNumber('-1,234.56 EUR')).to.equal(-1234.56);
expect(parseNumber('Number is 1,234.56')).to.equal(1234.56);
});
it('ignores non-number characters and returns undefined', () => {
expect(parseNumber('A')).to.equal(undefined);
expect(parseNumber('EUR')).to.equal(undefined);
expect(parseNumber('EU R')).to.equal(undefined);
});
it('returns undefined when value is empty string', () => {
expect(parseNumber('')).to.equal(undefined);
});
it('with locale set and length is more than four', () => {
expect(
parseNumber('6,000', {
locale: 'en-GB',
}),
).to.equal(6000);
expect(
parseNumber('6.000', {
locale: 'es-ES',
}),
).to.equal(6000);
});
});
+14
-0
# Change Log
## 0.21.0
### Minor Changes
- 9648d418: added a parseNumber function
- 8a766644: Make ValidateMixin feedback message wait for localize loadingComplete, to ensure getting the right fieldName if this refers to a localized label.
- c544af4e: BREAKING: Fires localeChanged event (and as a result, invokes onLocaleChanged / onLocaleUpdated) after localize loading has completed. This means if the user switches the locale to a locale which has not loaded yet, it will load it first before sending the event. This will allow users to immediately call localize.msg and get the right output, without having to await localize.loadingComplete themselves. This is slightly breaking with regards to timing and might break tests in extensions. In that case, you probably need a `await localize.loadingComplete` statement in front of the failing assertion.
### Patch Changes
- 9b9d82fc: Fix onLocaleChanged method missing param types
- Updated dependencies [8c06302e]
- @lion/core@0.18.2
## 0.20.2

@@ -4,0 +18,0 @@

+1
-1

@@ -101,3 +101,3 @@ # Systems >> Localize >> Features ||50

localize.loadNamespace({
'my-hello-component': locale => {
'my-hello-component': async locale => {
// resolves to a module with the module.default `{ greeting: 'Hallo {name}!' }`

@@ -104,0 +104,0 @@ return import(`./translations/${locale}.js`);

@@ -12,3 +12,3 @@ # Systems >> Localize >> Overview ||10

Further examples and a more in depth description can be found at the [Features Page](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/features.md).
Further examples and a more in depth description can be found at the [Features Page](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/features.md).

@@ -19,5 +19,5 @@ ## Content

| ---------------------------------------- | --------------------------------------------- |
| [Translate Text](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/text.md) | Load and translate text in multiple languages |
| [Format Numbers](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/numbers.md) | Format numbers in multiple languages |
| [Format Dates](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/dates.md) | Format dates in multiple languages |
| [Translate Text](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/text.md) | Load and translate text in multiple languages |
| [Format Numbers](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/numbers.md) | Format numbers in multiple languages |
| [Format Dates](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/dates.md) | Format dates in multiple languages |

@@ -24,0 +24,0 @@ ## Installation

@@ -7,2 +7,4 @@ export { formatDate } from "./src/date/formatDate.js";

export { parseDate } from "./src/date/parseDate.js";
export { LocalizeManager } from "./src/LocalizeManager.js";
export { LocalizeMixin } from "./src/LocalizeMixin.js";
export { formatNumber } from "./src/number/formatNumber.js";

@@ -14,5 +16,4 @@ export { formatNumberToParts } from "./src/number/formatNumberToParts.js";

export { getGroupSeparator } from "./src/number/getGroupSeparator.js";
export { LocalizeManager } from "./src/LocalizeManager.js";
export { LocalizeMixin } from "./src/LocalizeMixin.js";
export { normalizeCurrencyLabel } from "./src/number/normalizeCurrencyLabel.js";
export { parseNumber } from "./src/number/parseNumber.js";
export { localize, setLocalize } from "./src/localize.js";

@@ -7,2 +7,5 @@ export { formatDate } from './src/date/formatDate.js';

export { parseDate } from './src/date/parseDate.js';
export { localize, setLocalize } from './src/localize.js';
export { LocalizeManager } from './src/LocalizeManager.js';
export { LocalizeMixin } from './src/LocalizeMixin.js';
export { formatNumber } from './src/number/formatNumber.js';

@@ -14,5 +17,3 @@ export { formatNumberToParts } from './src/number/formatNumberToParts.js';

export { getGroupSeparator } from './src/number/getGroupSeparator.js';
export { localize, setLocalize } from './src/localize.js';
export { LocalizeManager } from './src/LocalizeManager.js';
export { LocalizeMixin } from './src/LocalizeMixin.js';
export { normalizeCurrencyLabel } from './src/number/normalizeCurrencyLabel.js';
export { parseNumber } from './src/number/parseNumber.js';
{
"name": "@lion/localize",
"version": "0.20.2",
"version": "0.21.0",
"description": "The localization system helps to manage localization data split into locales and automate its loading",

@@ -37,3 +37,3 @@ "license": "MIT",

"@bundled-es-modules/message-format": "6.0.4",
"@lion/core": "0.18.1",
"@lion/core": "0.18.2",
"singleton-manager": "1.4.2"

@@ -40,0 +40,0 @@ },

@@ -12,3 +12,3 @@ # Systems >> Localize >> Overview ||10

Further examples and a more in depth description can be found at the [Features Page](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/features.md).
Further examples and a more in depth description can be found at the [Features Page](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/features.md).

@@ -19,5 +19,5 @@ ## Content

| ---------------------------------------- | --------------------------------------------- |
| [Translate Text](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/text.md) | Load and translate text in multiple languages |
| [Format Numbers](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/numbers.md) | Format numbers in multiple languages |
| [Format Dates](https://github.com/ing-bank/lion/blob/0895af24d06146a1ccf9c3904ca18b8a9131efd6/docs/docs/systems/localize/dates.md) | Format dates in multiple languages |
| [Translate Text](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/text.md) | Load and translate text in multiple languages |
| [Format Numbers](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/numbers.md) | Format numbers in multiple languages |
| [Format Dates](https://github.com/ing-bank/lion/blob/e03f8d2cc31563d46f910074d562ad68a2e41dfd/docs/docs/systems/localize/dates.md) | Format dates in multiple languages |

@@ -24,0 +24,0 @@ ## Installation

@@ -36,3 +36,3 @@ /**

/**
* @type {Object.<string, Object.<string, Promise.<Object>>>}
* @type {Object.<string, Object.<string, Promise.<Object|void>>>}
* @private

@@ -101,5 +101,5 @@ */

/**
* @returns {Promise.<Object>}
* @returns {Promise.<Object|void>}
*/
get loadingComplete(): Promise<Object>;
get loadingComplete(): Promise<void | Object>;
reset(): void;

@@ -164,3 +164,3 @@ /**

*/
protected _getCachedNamespaceLoaderPromise(locale: string, namespace: string): Promise<Object> | null;
protected _getCachedNamespaceLoaderPromise(locale: string, namespace: string): Promise<void | Object> | null;
/**

@@ -196,6 +196,6 @@ * @param {string} locale

* @param {string} namespace
* @param {Promise.<Object>} promise
* @param {Promise.<Object|void>} promise
* @protected
*/
protected _cacheNamespaceLoaderPromise(locale: string, namespace: string, promise: Promise<Object>): void;
protected _cacheNamespaceLoaderPromise(locale: string, namespace: string, promise: Promise<Object | void>): void;
/**

@@ -239,6 +239,5 @@ * @param {string} namespace

* @param {string} oldLocale
* @returns {Promise.<Object>}
* @protected
*/
protected _loadAllMissing(newLocale: string, oldLocale: string): Promise<Object>;
protected _loadAllMissing(newLocale: string, oldLocale: string): void;
/**

@@ -245,0 +244,0 @@ * @param {string | string[]} keys

@@ -44,3 +44,3 @@ // @ts-expect-error [external]: no types for this package

/**
* @type {Object.<string, Object.<string, Promise.<Object>>>}
* @type {Object.<string, Object.<string, Promise.<Object|void>>>}
* @private

@@ -177,6 +177,9 @@ */

/**
* @returns {Promise.<Object>}
* @returns {Promise.<Object|void>}
*/
get loadingComplete() {
return Promise.all(Object.values(this.__namespaceLoaderPromisesCache[this.locale]));
if (typeof this.__namespaceLoaderPromisesCache[this.locale] === 'object') {
return Promise.all(Object.values(this.__namespaceLoaderPromisesCache[this.locale]));
}
return Promise.resolve();
}

@@ -421,3 +424,3 @@

* @param {string} namespace
* @param {Promise.<Object>} promise
* @param {Promise.<Object|void>} promise
* @protected

@@ -493,2 +496,4 @@ */

_onLocaleChanged(newLocale, oldLocale) {
// Event firing immediately, does not wait for loading the translations
this.dispatchEvent(new CustomEvent('__localeChanging'));
if (newLocale === oldLocale) {

@@ -499,4 +504,8 @@ return;

this._loadAllMissing(newLocale, oldLocale);
this.loadingComplete.then(() => {
this.dispatchEvent(new CustomEvent('localeChanged', { detail: { newLocale, oldLocale } }));
});
} else {
this.dispatchEvent(new CustomEvent('localeChanged', { detail: { newLocale, oldLocale } }));
}
this.dispatchEvent(new CustomEvent('localeChanged', { detail: { newLocale, oldLocale } }));
}

@@ -507,3 +516,2 @@

* @param {string} oldLocale
* @returns {Promise.<Object>}
* @protected

@@ -514,15 +522,10 @@ */

const newLocaleNamespaces = this.__storage[newLocale] || {};
/** @type {Promise<Object|void>[]} */
const promises = [];
Object.keys(oldLocaleNamespaces).forEach(namespace => {
const newNamespaceData = newLocaleNamespaces[namespace];
if (!newNamespaceData) {
promises.push(
this.loadNamespace(namespace, {
locale: newLocale,
}),
);
this.loadNamespace(namespace, {
locale: newLocale,
});
}
});
return Promise.all(promises);
}

@@ -529,0 +532,0 @@

@@ -14,3 +14,2 @@ import { dedupeMixin, until, nothing } from '@lion/core';

const LocalizeMixinImplementation = superclass =>
// eslint-disable-next-line
class LocalizeMixin extends superclass {

@@ -42,2 +41,8 @@ /**

this.__boundLocalizeOnLocaleChanging =
/** @param {...Object} args */
() => {
this.__localizeOnLocaleChanging();
};
// should be loaded in advance

@@ -67,18 +72,14 @@ /** @private */

connectedCallback() {
if (super.connectedCallback) {
super.connectedCallback();
}
super.connectedCallback();
if (this.localizeNamespacesLoaded) {
this.localizeNamespacesLoaded.then(() => this.onLocaleReady());
}
this.__localizeAddLocaleChangedListener();
localize.addEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging);
localize.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged);
}
disconnectedCallback() {
if (super.disconnectedCallback) {
super.disconnectedCallback();
}
this.__localizeRemoveLocaleChangedListener();
super.disconnectedCallback();
localize.removeEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging);
localize.removeEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged);
}

@@ -88,3 +89,3 @@

* @param {string | string[]} keys
* @param {Object.<string,?>} variables
* @param {Object.<string,?>} [variables]
* @param {Object} [options]

@@ -131,12 +132,11 @@ * @param {string} [options.locale]

/** @private */
__localizeAddLocaleChangedListener() {
localize.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged);
/**
* Start loading namespaces on the event that is sent immediately
* when localize.locale changes --> 'localeChanging'
* @private
*/
__localizeOnLocaleChanging() {
this.__localizeStartLoadingNamespaces();
}
/** @private */
__localizeRemoveLocaleChangedListener() {
localize.removeEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged);
}
/**

@@ -160,3 +160,2 @@ * @param {CustomEvent} event

onLocaleChanged(newLocale, oldLocale) {
this.__localizeStartLoadingNamespaces();
this.onLocaleUpdated();

@@ -163,0 +162,0 @@ this.requestUpdate();

@@ -24,3 +24,3 @@ /**

setupFakeImport(`./${namespace}/${locale}.js`, {
default: {},
default: { foo: `bar-${locale}` },
});

@@ -27,0 +27,0 @@ });

@@ -32,3 +32,2 @@ import { isDirectiveResult, LitElement } from '@lion/core';

const tagString = defineCE(
// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -101,3 +100,2 @@ static get localizeNamespaces() {

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -118,3 +116,3 @@ static get localizeNamespaces() {

await localize.loadingComplete;
await el.localizeNamespacesLoaded;
expect(onLocaleReadySpy.callCount).to.equal(0);

@@ -124,3 +122,3 @@

await localize.loadingComplete;
await el.localizeNamespacesLoaded;
expect(onLocaleReadySpy.callCount).to.equal(1);

@@ -135,3 +133,2 @@ });

// @ts-ignore
class MyOtherElement extends LocalizeMixin(LitElement) {

@@ -151,18 +148,60 @@ static get localizeNamespaces() {

await localize.loadingComplete;
await el.localizeNamespacesLoaded;
localize.locale = 'nl-NL';
await localize.loadingComplete;
await el.localizeNamespacesLoaded;
expect(onLocaleChangedSpy.callCount).to.equal(0);
// Appending to DOM will result in onLocaleChanged to be invoked
wrapper.appendChild(el);
// Changing locale will result in onLocaleChanged to be invoked
localize.locale = 'ru-RU';
await localize.loadingComplete;
expect(onLocaleChangedSpy.callCount).to.equal(1);
// FIXME: Expected 0 arguments, but got 2. ts(2554) --> not sure why this sinon type is not working
// @ts-ignore
await el.localizeNamespacesLoaded;
expect(onLocaleChangedSpy.callCount).to.equal(2);
expect(onLocaleChangedSpy.calledWithExactly('ru-RU', 'nl-NL')).to.be.true;
});
it('dispatches "localeChanged" after loader promises have resolved, allowing to call .msg() immediately', async () => {
const myElementNs = {
/** @param {string} locale */
'my-element': locale => fakeImport(`./my-element/${locale}.js`),
};
class MyOtherElement extends LocalizeMixin(LitElement) {
static get localizeNamespaces() {
return [myElementNs, ...super.localizeNamespaces];
}
/**
* @param {string} newLocale
* @param {string} oldLocale
*/
onLocaleChanged(newLocale, oldLocale) {
super.onLocaleChanged(newLocale, oldLocale);
// Can call localize.msg immediately, without having to await localize.loadingComplete
// This is because localeChanged event is fired only after awaiting loading
// unless the user disables _autoLoadOnLocaleChange property
this.foo = localize.msg('my-element:foo');
}
}
const tagString = defineCE(MyOtherElement);
setupEmptyFakeImportsFor(['my-element'], ['en-GB', 'nl-NL', 'ru-RU']);
const el = /** @type {MyOtherElement} */ (document.createElement(tagString));
const wrapper = await fixture('<div></div>');
wrapper.appendChild(el);
localize.locale = 'nl-NL';
await el.localizeNamespacesLoaded;
expect(el.foo).to.equal('bar-nl-NL');
localize.locale = 'ru-RU';
await el.localizeNamespacesLoaded;
expect(el.foo).to.equal('bar-ru-RU');
});
it('calls "onLocaleUpdated()" after both "onLocaleReady()" and "onLocaleChanged()"', async () => {

@@ -174,3 +213,2 @@ const myElementNs = {

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -197,2 +235,3 @@ static get localizeNamespaces() {

localize.locale = 'nl-NL';
await el.localizeNamespacesLoaded;
expect(onLocaleUpdatedSpy.callCount).to.equal(2);

@@ -217,3 +256,2 @@ });

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -226,3 +264,2 @@ static get localizeNamespaces() {

super.onLocaleUpdated();
await this.localizeNamespacesLoaded;
this.label = localize.msg('my-element:label');

@@ -236,3 +273,2 @@ }

await el.localizeNamespacesLoaded;
await nextFrame(); // needed as both are added to the micro task que

@@ -252,3 +288,2 @@ expect(el.label).to.equal('one');

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -267,5 +302,8 @@ static get localizeNamespaces() {

el.connectedCallback();
localize.locale = 'nl-NL';
await el.localizeNamespacesLoaded;
localize.locale = 'nl-NL';
// await next frame for requestUpdate to be fired
await nextFrame();
expect(updateSpy.callCount).to.equal(1);

@@ -285,3 +323,2 @@ });

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -328,3 +365,2 @@ static get localizeNamespaces() {

// @ts-ignore
class MyElement extends LocalizeMixin(LitElement) {

@@ -356,3 +392,2 @@ static get localizeNamespaces() {

// @ts-ignore
class MyLocalizedClass extends LocalizeMixin(LitElement) {

@@ -398,3 +433,2 @@ static get localizeNamespaces() {

// @ts-ignore
class MyLocalizedClass extends LocalizeMixin(LitElement) {

@@ -410,4 +444,5 @@ static get localizeNamespaces() {

const tag = defineCE(MyLocalizedClass);
const el = /** @type {MyLocalizedClass} */ (await fixture(`<${tag}></${tag}>`));
const tagName = defineCE(MyLocalizedClass);
const tag = unsafeStatic(tagName);
const el = /** @type {MyLocalizedClass} */ (await fixture(html`<${tag}></${tag}>`));
await el.updateComplete;

@@ -421,2 +456,4 @@

expect(p.innerText).to.equal('Hi!');
await el.localizeNamespacesLoaded;
await nextFrame(); // needed because msgLit relies on until directive to re-render
await el.updateComplete;

@@ -438,3 +475,2 @@ expect(p.innerText).to.equal('Howdy!');

// @ts-ignore
class MyLocalizedClass extends LocalizeMixin(LitElement) {

@@ -441,0 +477,0 @@ static get waitForLocalizeNamespaces() {

@@ -63,3 +63,3 @@ import { Constructor } from '@open-wc/dedupe-mixin';

public localizeNamespacesLoaded(): Promise<Object>;
public localizeNamespacesLoaded: Promise<Object> | undefined;

@@ -72,3 +72,3 @@ /**

public onLocaleReady(): void;
public onLocaleChanged(): void;
public onLocaleChanged(newLocale: string, oldLocale: string): void;
public onLocaleUpdated(): void;

@@ -79,6 +79,9 @@ public connectedCallback(): void;

private __getUniqueNamespaces(): void;
private __localizeAddLocaleChangedListener(): void;
private __localizeRemoveLocaleChangedListener(): void;
private __boundLocalizeOnLocaleChanged(...args: Object[]): void;
private __boundLocalizeOnLocaleChanging(...args: Object[]): void;
private __getUniqueNamespaces(): string[];
private __localizeOnLocaleChanged(event: CustomEvent): void;
private __localizeMessageSync: boolean;
private __localizeStartLoadingNamespaces(): void;
private __localizeOnLocaleChanging(): void;
}

@@ -85,0 +88,0 @@