From 467ba6bf0b4aac52c55fe75451f505cef617743e Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Wed, 1 Feb 2023 10:20:15 +0100 Subject: [PATCH] feat(@lion/ui): localize side effect free internally --- .../components/calendar/src/LionCalendar.js | 5 ++- .../form-core/src/validate/ValidateMixin.js | 10 ++++-- .../src/validate/validators/DateValidators.js | 2 +- .../test-suites/FormatMixin.suite.js | 2 +- .../ValidateMixinFeedbackPart.suite.js | 10 +++--- .../test/validate/DateValidators.test.js | 2 +- .../input-amount/src/LionInputAmount.js | 4 +-- .../components/input-amount/src/formatters.js | 6 +++- .../ui/components/input-amount/src/parsers.js | 2 +- .../input-date/src/LionInputDate.js | 2 +- .../src/LionInputDatepicker.js | 2 +- .../input-email/src/LionInputEmail.js | 2 +- .../input-iban/src/LionInputIban.js | 2 +- .../components/input-iban/src/validators.js | 22 ++++++++----- .../input-range/src/LionInputRange.js | 2 +- .../src/LionInputTelDropdown.js | 11 ++++--- .../components/input-tel/src/LionInputTel.js | 6 ++-- .../test-suites/LionInputTel.suite.js | 5 +-- .../components/localize/src/LocalizeMixin.js | 33 ++++++++++++++----- .../localize/src/date/formatDate.js | 7 ++-- .../components/localize/src/date/parseDate.js | 6 ++-- .../localize/src/number/formatNumber.js | 9 ++--- .../localize/src/number/getCurrencyName.js | 5 +-- .../number/utils/emptyStringWhenNumberNan.js | 5 +-- .../localize/src/utils/getLocale.js | 11 ++----- .../localize/test-helpers/localizeTearDown.js | 9 ++--- .../localize/types/LocalizeMixinTypes.ts | 9 ++++- .../pagination/src/LionPagination.js | 2 +- .../src/LionProgressIndicator.js | 5 +-- .../src/loadDefaultFeedbackMessages.js | 4 +-- ...oadDefaultFeedbackMessagesNoSideEffects.js | 10 +++--- 31 files changed, 129 insertions(+), 83 deletions(-) diff --git a/packages/ui/components/calendar/src/LionCalendar.js b/packages/ui/components/calendar/src/LionCalendar.js index 400fd58af..637abf418 100644 --- a/packages/ui/components/calendar/src/LionCalendar.js +++ b/packages/ui/components/calendar/src/LionCalendar.js @@ -3,10 +3,9 @@ import { html, LitElement } from 'lit'; import { getMonthNames, getWeekdayNames, - localize, LocalizeMixin, normalizeDateTime, -} from '@lion/ui/localize.js'; +} from '@lion/ui/localize-no-side-effects.js'; import { calendarStyle } from './calendarStyle.js'; import { createDay } from './utils/createDay.js'; @@ -862,6 +861,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) { * @private */ __getLocale() { - return this.locale || localize.locale; + return this.locale || this._localizeManager.locale; } } diff --git a/packages/ui/components/form-core/src/validate/ValidateMixin.js b/packages/ui/components/form-core/src/validate/ValidateMixin.js index 5aa62305c..f61d219dc 100644 --- a/packages/ui/components/form-core/src/validate/ValidateMixin.js +++ b/packages/ui/components/form-core/src/validate/ValidateMixin.js @@ -3,7 +3,7 @@ import { SlotMixin, DisabledMixin } from '@lion/ui/core.js'; import { ScopedElementsMixin } from '@open-wc/scoped-elements'; import { dedupeMixin } from '@open-wc/dedupe-mixin'; // TODO: make form-core independent from localize -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { AsyncQueue } from '../utils/AsyncQueue.js'; import { pascalCase } from '../utils/pascalCase.js'; import { SyncUpdatableMixin } from '../utils/SyncUpdatableMixin.js'; @@ -262,12 +262,16 @@ export const ValidateMixinImplementation = superclass => connectedCallback() { super.connectedCallback(); - localize.addEventListener('localeChanged', this._updateFeedbackComponent); + + const localizeManager = getLocalizeManager(); + localizeManager.addEventListener('localeChanged', this._updateFeedbackComponent); } disconnectedCallback() { super.disconnectedCallback(); - localize.removeEventListener('localeChanged', this._updateFeedbackComponent); + + const localizeManager = getLocalizeManager(); + localizeManager.removeEventListener('localeChanged', this._updateFeedbackComponent); } /** diff --git a/packages/ui/components/form-core/src/validate/validators/DateValidators.js b/packages/ui/components/form-core/src/validate/validators/DateValidators.js index 25a4b34b0..46fa374e5 100644 --- a/packages/ui/components/form-core/src/validate/validators/DateValidators.js +++ b/packages/ui/components/form-core/src/validate/validators/DateValidators.js @@ -1,6 +1,6 @@ /* eslint-disable max-classes-per-file */ // TODO: move to input-datepicker? -import { normalizeDateTime } from '@lion/ui/localize.js'; +import { normalizeDateTime } from '@lion/ui/localize-no-side-effects.js'; import { Validator } from '../Validator.js'; /** diff --git a/packages/ui/components/form-core/test-suites/FormatMixin.suite.js b/packages/ui/components/form-core/test-suites/FormatMixin.suite.js index e0b4dfafc..751a59e4f 100644 --- a/packages/ui/components/form-core/test-suites/FormatMixin.suite.js +++ b/packages/ui/components/form-core/test-suites/FormatMixin.suite.js @@ -1,5 +1,5 @@ import { LitElement } from 'lit'; -import { parseDate } from '@lion/ui/localize.js'; +import { parseDate } from '@lion/ui/localize-no-side-effects.js'; import { aTimeout, defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import sinon from 'sinon'; import { Unparseable, Validator, FormatMixin } from '@lion/ui/form-core.js'; diff --git a/packages/ui/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js b/packages/ui/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js index 7dc8f6567..e2ef9e0e2 100644 --- a/packages/ui/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +++ b/packages/ui/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js @@ -1,5 +1,5 @@ import { LitElement } from 'lit'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { localizeTearDown } from '@lion/ui/localize-test-helpers.js'; import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import { getFormControlMembers, AlwaysInvalid } from '@lion/ui/form-core-test-helpers.js'; @@ -18,6 +18,8 @@ import { */ export function runValidateMixinFeedbackPart() { + const localizeManager = getLocalizeManager(); + describe('Validity Feedback', () => { beforeEach(() => { localizeTearDown(); @@ -65,7 +67,7 @@ export function runValidateMixinFeedbackPart() { AlwaysInvalid.getMessage = async () => 'Message for AlwaysInvalid'; MinLength.getMessage = async () => - localize.locale === 'de-DE' ? 'Nachricht für MinLength' : 'Message for MinLength'; + localizeManager.locale === 'de-DE' ? 'Nachricht für MinLength' : 'Message for MinLength'; ContainsLowercaseA.getMessage = async () => 'Message for ContainsLowercaseA'; ContainsCat.getMessage = async () => 'Message for ContainsCat'; @@ -341,8 +343,8 @@ export function runValidateMixinFeedbackPart() { expect(_feedbackNode.feedbackData?.length).to.equal(1); expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength'); - localize.locale = 'de-DE'; - await localize.loadingComplete; + localizeManager.locale = 'de-DE'; + await localizeManager.loadingComplete; await el.feedbackComplete; expect(_feedbackNode.feedbackData?.[0].message).to.equal('Nachricht für MinLength'); }); diff --git a/packages/ui/components/form-core/test/validate/DateValidators.test.js b/packages/ui/components/form-core/test/validate/DateValidators.test.js index c5dead565..3b9cea61d 100644 --- a/packages/ui/components/form-core/test/validate/DateValidators.test.js +++ b/packages/ui/components/form-core/test/validate/DateValidators.test.js @@ -1,6 +1,6 @@ import { expect } from '@open-wc/testing'; -import { normalizeDateTime } from '@lion/ui/localize.js'; +import { normalizeDateTime } from '@lion/ui/localize-no-side-effects.js'; import { IsDate, MinDate, MaxDate, MinMaxDate, IsDateDisabled } from '@lion/ui/form-core.js'; describe('Date Validation', () => { diff --git a/packages/ui/components/input-amount/src/LionInputAmount.js b/packages/ui/components/input-amount/src/LionInputAmount.js index 3d4b85406..df4b9a350 100644 --- a/packages/ui/components/input-amount/src/LionInputAmount.js +++ b/packages/ui/components/input-amount/src/LionInputAmount.js @@ -1,6 +1,6 @@ import { css } from 'lit'; import { LionInput } from '@lion/ui/input.js'; -import { getCurrencyName, localize, LocalizeMixin } from '@lion/ui/localize.js'; +import { getCurrencyName, LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; import { IsNumber } from '@lion/ui/form-core.js'; import { formatAmount, formatCurrencyLabel } from './formatters.js'; import { parseAmount } from './parsers.js'; @@ -201,7 +201,7 @@ export class LionInputAmount extends LocalizeMixin(LionInput) { } get __currencyLabel() { - return this.currency ? formatCurrencyLabel(this.currency, localize.locale) : ''; + return this.currency ? formatCurrencyLabel(this.currency, this._localizeManager.locale) : ''; } __reformat() { diff --git a/packages/ui/components/input-amount/src/formatters.js b/packages/ui/components/input-amount/src/formatters.js index 8bb08d54a..9efed3286 100644 --- a/packages/ui/components/input-amount/src/formatters.js +++ b/packages/ui/components/input-amount/src/formatters.js @@ -1,4 +1,8 @@ -import { formatNumber, getFractionDigits, normalizeCurrencyLabel } from '@lion/ui/localize.js'; +import { + formatNumber, + getFractionDigits, + normalizeCurrencyLabel, +} from '@lion/ui/localize-no-side-effects.js'; /** * @typedef {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} FormatOptions diff --git a/packages/ui/components/input-amount/src/parsers.js b/packages/ui/components/input-amount/src/parsers.js index 45c6653f2..be422f2c2 100644 --- a/packages/ui/components/input-amount/src/parsers.js +++ b/packages/ui/components/input-amount/src/parsers.js @@ -1,4 +1,4 @@ -import { parseNumber, getFractionDigits } from '@lion/ui/localize.js'; +import { parseNumber, getFractionDigits } from '@lion/ui/localize-no-side-effects.js'; /** * @typedef {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} FormatOptions diff --git a/packages/ui/components/input-date/src/LionInputDate.js b/packages/ui/components/input-date/src/LionInputDate.js index ee1ac6cc5..7ef8edb85 100644 --- a/packages/ui/components/input-date/src/LionInputDate.js +++ b/packages/ui/components/input-date/src/LionInputDate.js @@ -1,6 +1,6 @@ import { IsDate } from '@lion/ui/form-core.js'; import { LionInput } from '@lion/ui/input.js'; -import { formatDate, LocalizeMixin, parseDate } from '@lion/ui/localize.js'; +import { formatDate, LocalizeMixin, parseDate } from '@lion/ui/localize-no-side-effects.js'; /** * @param {Date|number} date diff --git a/packages/ui/components/input-datepicker/src/LionInputDatepicker.js b/packages/ui/components/input-datepicker/src/LionInputDatepicker.js index d160426b7..fa7ba82d3 100644 --- a/packages/ui/components/input-datepicker/src/LionInputDatepicker.js +++ b/packages/ui/components/input-datepicker/src/LionInputDatepicker.js @@ -10,7 +10,7 @@ import { withModalDialogConfig, ArrowMixin, } from '@lion/ui/overlays.js'; -import { LocalizeMixin } from '@lion/ui/localize.js'; +import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; import { localizeNamespaceLoader } from './localizeNamespaceLoader.js'; /** diff --git a/packages/ui/components/input-email/src/LionInputEmail.js b/packages/ui/components/input-email/src/LionInputEmail.js index 089c1402c..5f7f5812f 100644 --- a/packages/ui/components/input-email/src/LionInputEmail.js +++ b/packages/ui/components/input-email/src/LionInputEmail.js @@ -1,6 +1,6 @@ import { IsEmail } from '@lion/ui/form-core.js'; import { LionInput } from '@lion/ui/input.js'; -import { LocalizeMixin } from '@lion/ui/localize.js'; +import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; /** * LionInputEmail: extension of lion-input diff --git a/packages/ui/components/input-iban/src/LionInputIban.js b/packages/ui/components/input-iban/src/LionInputIban.js index 9a98bd4e3..f2457dd70 100644 --- a/packages/ui/components/input-iban/src/LionInputIban.js +++ b/packages/ui/components/input-iban/src/LionInputIban.js @@ -1,4 +1,4 @@ -import { LocalizeMixin } from '@lion/ui/localize.js'; +import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; import { LionInput } from '@lion/ui/input.js'; import { formatIBAN } from './formatters.js'; import { parseIBAN } from './parsers.js'; diff --git a/packages/ui/components/input-iban/src/validators.js b/packages/ui/components/input-iban/src/validators.js index ed9f3a7aa..9aa229304 100644 --- a/packages/ui/components/input-iban/src/validators.js +++ b/packages/ui/components/input-iban/src/validators.js @@ -1,15 +1,16 @@ /* eslint-disable max-classes-per-file, import/no-extraneous-dependencies */ -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { Unparseable, Validator } from '@lion/ui/form-core.js'; import { isValidIBAN } from 'ibantools'; let loaded = false; const loadTranslations = async () => { + const localizeManager = getLocalizeManager(); if (loaded) { return; } - await localize.loadNamespace( + await localizeManager.loadNamespace( { 'lion-validate+iban': /** @param {string} locale */ locale => { switch (locale) { @@ -86,7 +87,7 @@ const loadTranslations = async () => { } }, }, - { locale: localize.locale }, + { locale: localizeManager.locale }, ); loaded = true; }; @@ -113,8 +114,9 @@ export class IsIBAN extends Validator { * @returns {Promise} */ static async getMessage(data) { + const localizeManager = getLocalizeManager(); await loadTranslations(); - return localize.msg('lion-validate+iban:error.IsIBAN', data); + return localizeManager.msg('lion-validate+iban:error.IsIBAN', data); } } @@ -156,11 +158,13 @@ export class IsCountryIBAN extends IsIBAN { * @returns {Promise} */ static async getMessage(data) { + const localizeManager = getLocalizeManager(); + await loadTranslations(); // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback return data?.modelValue instanceof Unparseable - ? localize.msg('lion-validate+iban:error.IsIBAN', data) - : localize.msg('lion-validate+iban:error.IsCountryIBAN', data); + ? localizeManager.msg('lion-validate+iban:error.IsIBAN', data) + : localizeManager.msg('lion-validate+iban:error.IsCountryIBAN', data); } } @@ -203,6 +207,8 @@ export class IsNotCountryIBAN extends IsIBAN { * @returns {Promise} */ static async getMessage(data) { + const localizeManager = getLocalizeManager(); + await loadTranslations(); const _data = { ...data, @@ -211,7 +217,7 @@ export class IsNotCountryIBAN extends IsIBAN { }; // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback return data?.modelValue instanceof Unparseable - ? localize.msg('lion-validate+iban:error.IsIBAN', _data) - : localize.msg('lion-validate+iban:error.IsNotCountryIBAN', _data); + ? localizeManager.msg('lion-validate+iban:error.IsIBAN', _data) + : localizeManager.msg('lion-validate+iban:error.IsNotCountryIBAN', _data); } } diff --git a/packages/ui/components/input-range/src/LionInputRange.js b/packages/ui/components/input-range/src/LionInputRange.js index 195992283..93de10ff9 100644 --- a/packages/ui/components/input-range/src/LionInputRange.js +++ b/packages/ui/components/input-range/src/LionInputRange.js @@ -2,7 +2,7 @@ import { css, html } from 'lit'; import { ScopedStylesController } from '@lion/ui/core.js'; import { LionInput } from '@lion/ui/input.js'; -import { formatNumber } from '@lion/ui/localize.js'; +import { formatNumber } from '@lion/ui/localize-no-side-effects.js'; /** * @typedef {import('lit').CSSResult} CSSResult diff --git a/packages/ui/components/input-tel-dropdown/src/LionInputTelDropdown.js b/packages/ui/components/input-tel-dropdown/src/LionInputTelDropdown.js index a525b03d6..75248a038 100644 --- a/packages/ui/components/input-tel-dropdown/src/LionInputTelDropdown.js +++ b/packages/ui/components/input-tel-dropdown/src/LionInputTelDropdown.js @@ -2,7 +2,7 @@ import { html, css } from 'lit'; import { ref, createRef } from 'lit/directives/ref.js'; import { LionInputTel } from '@lion/ui/input-tel.js'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { getFlagSymbol } from './getFlagSymbol.js'; /** @@ -80,6 +80,7 @@ export class LionInputTelDropdown extends LionInputTel { * @type {TemplateDataForDropdownInputTel} */ get _templateDataDropdown() { + const localizeManager = getLocalizeManager(); const refs = { dropdown: { ref: this.refs.dropdown, @@ -91,10 +92,12 @@ export class LionInputTelDropdown extends LionInputTel { 'model-value-changed': this._onDropdownValueChange, }, labels: { - selectCountry: localize.msg('lion-input-tel:selectCountry'), - allCountries: this._allCountriesLabel || localize.msg('lion-input-tel:allCountries'), + selectCountry: localizeManager.msg('lion-input-tel:selectCountry'), + allCountries: + this._allCountriesLabel || localizeManager.msg('lion-input-tel:allCountries'), preferredCountries: - this._preferredCountriesLabel || localize.msg('lion-input-tel:suggestedCountries'), + this._preferredCountriesLabel || + localizeManager.msg('lion-input-tel:suggestedCountries'), }, }, }; diff --git a/packages/ui/components/input-tel/src/LionInputTel.js b/packages/ui/components/input-tel/src/LionInputTel.js index d2d376984..699f60241 100644 --- a/packages/ui/components/input-tel/src/LionInputTel.js +++ b/packages/ui/components/input-tel/src/LionInputTel.js @@ -1,5 +1,5 @@ import { Unparseable } from '@lion/ui/form-core.js'; -import { LocalizeMixin, localize } from '@lion/ui/localize.js'; +import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; import { LionInput } from '@lion/ui/input.js'; import { PhoneUtilManager } from './PhoneUtilManager.js'; @@ -125,7 +125,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) { // @ts-expect-error // eslint-disable-next-line class-methods-use-this get fieldName() { - return localize.msg('lion-input-tel:phoneNumber'); + return this._localizeManager.msg('lion-input-tel:phoneNumber'); } /** @@ -227,7 +227,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) { onLocaleUpdated() { super.onLocaleUpdated(); - const localeSplitted = localize.locale.split('-'); + const localeSplitted = this._localizeManager.locale.split('-'); /** * @protected * @type {RegionCode} diff --git a/packages/ui/components/input-tel/test-suites/LionInputTel.suite.js b/packages/ui/components/input-tel/test-suites/LionInputTel.suite.js index 848e6584c..391c1d6c1 100644 --- a/packages/ui/components/input-tel/test-suites/LionInputTel.suite.js +++ b/packages/ui/components/input-tel/test-suites/LionInputTel.suite.js @@ -9,7 +9,7 @@ import { } from '@open-wc/testing'; import sinon from 'sinon'; import { mimicUserInput } from '@lion/ui/form-core-test-helpers.js'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { Unparseable } from '@lion/ui/form-core.js'; import { LionInputTel, PhoneNumber, PhoneUtilManager } from '@lion/ui/input-tel.js'; import { mockPhoneUtilManager, restorePhoneUtilManager } from '@lion/ui/input-tel-test-helpers.js'; @@ -23,7 +23,8 @@ const fixture = /** @type {(arg: string | TemplateResult) => Promise LionInputTel} */ (_fixtureSync); const getRegionCodeBasedOnLocale = () => { - const localeSplitted = localize.locale.split('-'); + const localizeManager = getLocalizeManager(); + const localeSplitted = localizeManager.locale.split('-'); return /** @type {RegionCode} */ (localeSplitted[localeSplitted.length - 1]).toUpperCase(); }; diff --git a/packages/ui/components/localize/src/LocalizeMixin.js b/packages/ui/components/localize/src/LocalizeMixin.js index 85922f70f..240f3bba0 100644 --- a/packages/ui/components/localize/src/LocalizeMixin.js +++ b/packages/ui/components/localize/src/LocalizeMixin.js @@ -1,7 +1,7 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin'; import { nothing } from 'lit'; import { until } from 'lit/directives/until.js'; -import { localize } from './singleton.js'; +import { getLocalizeManager } from './getLocalizeManager.js'; /** * @typedef {import('lit/directive.js').DirectiveResult} DirectiveResult @@ -34,6 +34,8 @@ const LocalizeMixinImplementation = superclass => constructor() { super(); + this._localizeManager = getLocalizeManager(); + /** @private */ this.__boundLocalizeOnLocaleChanged = /** @param {...Object} args */ @@ -74,14 +76,23 @@ const LocalizeMixinImplementation = superclass => if (this.localizeNamespacesLoaded) { this.localizeNamespacesLoaded.then(() => this.onLocaleReady()); } - localize.addEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging); - localize.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged); + this._localizeManager.addEventListener( + '__localeChanging', + this.__boundLocalizeOnLocaleChanging, + ); + this._localizeManager.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged); } disconnectedCallback() { super.disconnectedCallback(); - localize.removeEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging); - localize.removeEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged); + this._localizeManager.removeEventListener( + '__localeChanging', + this.__boundLocalizeOnLocaleChanging, + ); + this._localizeManager.removeEventListener( + 'localeChanged', + this.__boundLocalizeOnLocaleChanged, + ); } /** @@ -93,7 +104,7 @@ const LocalizeMixinImplementation = superclass => */ msgLit(keys, variables, options) { if (this.__localizeMessageSync) { - return localize.msg(keys, variables, options); + return this._localizeManager.msg(keys, variables, options); } if (!this.localizeNamespacesLoaded) { @@ -101,7 +112,9 @@ const LocalizeMixinImplementation = superclass => } return until( - this.localizeNamespacesLoaded.then(() => localize.msg(keys, variables, options)), + this.localizeNamespacesLoaded.then(() => + this._localizeManager.msg(keys, variables, options), + ), nothing, ); } @@ -125,12 +138,14 @@ const LocalizeMixinImplementation = superclass => /** @private */ __localizeStartLoadingNamespaces() { - this.localizeNamespacesLoaded = localize.loadNamespaces(this.__getUniqueNamespaces()); + this.localizeNamespacesLoaded = this._localizeManager.loadNamespaces( + this.__getUniqueNamespaces(), + ); } /** * Start loading namespaces on the event that is sent immediately - * when localize.locale changes --> 'localeChanging' + * when this._localizeManager.locale changes --> 'localeChanging' * @private */ __localizeOnLocaleChanging() { diff --git a/packages/ui/components/localize/src/date/formatDate.js b/packages/ui/components/localize/src/date/formatDate.js index c71fed45b..bbcff8e4c 100644 --- a/packages/ui/components/localize/src/date/formatDate.js +++ b/packages/ui/components/localize/src/date/formatDate.js @@ -1,5 +1,5 @@ import { getLocale } from '../utils/getLocale.js'; -import { localize } from '../singleton.js'; +import { getLocalizeManager } from '../getLocalizeManager.js'; import { normalizeIntlDate } from './utils/normalizeIntlDate.js'; /** @typedef {import('../../types/LocalizeMixinTypes.js').DatePostProcessor} DatePostProcessor */ @@ -12,6 +12,7 @@ import { normalizeIntlDate } from './utils/normalizeIntlDate.js'; * @returns {string} */ export function formatDate(date, options) { + const localizeManager = getLocalizeManager(); if (!(date instanceof Date)) { return ''; } @@ -36,8 +37,8 @@ export function formatDate(date, options) { formattedDate = ''; } - if (localize.formatDateOptions.postProcessors.size > 0) { - Array.from(localize.formatDateOptions.postProcessors).forEach(([locale, fn]) => { + if (localizeManager.formatDateOptions.postProcessors.size > 0) { + Array.from(localizeManager.formatDateOptions.postProcessors).forEach(([locale, fn]) => { if (locale === computedLocale) { formattedDate = fn(formattedDate); } diff --git a/packages/ui/components/localize/src/date/parseDate.js b/packages/ui/components/localize/src/date/parseDate.js index 76c084e5e..fb3a31dee 100644 --- a/packages/ui/components/localize/src/date/parseDate.js +++ b/packages/ui/components/localize/src/date/parseDate.js @@ -1,5 +1,5 @@ import { getDateFormatBasedOnLocale } from './getDateFormatBasedOnLocale.js'; -import { localize } from '../singleton.js'; +import { getLocalizeManager } from '../getLocalizeManager.js'; import { addLeadingZero } from './utils/addLeadingZero.js'; /** @@ -29,10 +29,12 @@ const memoizedGetDateFormatBasedOnLocale = memoize(getDateFormatBasedOnLocale); * @returns {Date | undefined} */ export function parseDate(dateString) { + const localizeManager = getLocalizeManager(); + const stringToParse = addLeadingZero(dateString); let parsedString; - switch (memoizedGetDateFormatBasedOnLocale(localize.locale)) { + switch (memoizedGetDateFormatBasedOnLocale(localizeManager.locale)) { case 'day-month-year': parsedString = `${stringToParse.slice(6, 10)}/${stringToParse.slice( 3, diff --git a/packages/ui/components/localize/src/number/formatNumber.js b/packages/ui/components/localize/src/number/formatNumber.js index 46545041d..1c7ee984e 100644 --- a/packages/ui/components/localize/src/number/formatNumber.js +++ b/packages/ui/components/localize/src/number/formatNumber.js @@ -1,6 +1,6 @@ /** @typedef {import('../../types/LocalizeMixinTypes.js').NumberPostProcessor} NumberPostProcessor */ -import { localize } from '../singleton.js'; +import { getLocalizeManager } from '../getLocalizeManager.js'; import { getLocale } from '../utils/getLocale.js'; import { formatNumberToParts } from './formatNumberToParts.js'; @@ -14,12 +14,13 @@ import { formatNumberToParts } from './formatNumberToParts.js'; * @returns {string} */ export function formatNumber(number, options = /** @type {FormatOptions} */ ({})) { + const localizeManager = getLocalizeManager(); if (number === undefined || number === null) return ''; const formattedToParts = formatNumberToParts(number, options); // If number is not a number if ( formattedToParts === options.returnIfNaN || - formattedToParts === localize.formatNumberOptions.returnIfNaN + formattedToParts === localizeManager.formatNumberOptions.returnIfNaN ) { return /** @type {string} */ (formattedToParts); } @@ -33,8 +34,8 @@ export function formatNumber(number, options = /** @type {FormatOptions} */ ({}) const computedLocale = getLocale(options && options.locale); - if (localize.formatNumberOptions.postProcessors.size > 0) { - Array.from(localize.formatNumberOptions.postProcessors).forEach(([locale, fn]) => { + if (localizeManager.formatNumberOptions.postProcessors.size > 0) { + Array.from(localizeManager.formatNumberOptions.postProcessors).forEach(([locale, fn]) => { if (locale === computedLocale) { printNumberOfParts = fn(printNumberOfParts); } diff --git a/packages/ui/components/localize/src/number/getCurrencyName.js b/packages/ui/components/localize/src/number/getCurrencyName.js index 3fa0a7d50..87e0b4769 100644 --- a/packages/ui/components/localize/src/number/getCurrencyName.js +++ b/packages/ui/components/localize/src/number/getCurrencyName.js @@ -1,4 +1,4 @@ -import { localize } from '../singleton.js'; +import { getLocalizeManager } from '../getLocalizeManager.js'; import { formatNumberToParts } from './formatNumberToParts.js'; import { forceCurrencyNameForPHPEnGB } from './utils/normalize-get-currency-name/forceCurrencyNameForPHPEnGB.js'; @@ -11,6 +11,7 @@ import { forceCurrencyNameForPHPEnGB } from './utils/normalize-get-currency-name * @returns {string} currency name like 'US dollar' */ export function getCurrencyName(currencyIso, options) { + const localizeManager = getLocalizeManager(); const parts = /** @type {FormatNumberPart[]} */ ( formatNumberToParts(1, { ...options, @@ -23,7 +24,7 @@ export function getCurrencyName(currencyIso, options) { .filter(p => p.type === 'currency') .map(o => o.value) .join(' '); - const locale = options?.locale || localize.locale; + const locale = options?.locale || localizeManager.locale; if (currencyIso === 'PHP' && locale === 'en-GB') { currencyName = forceCurrencyNameForPHPEnGB(currencyName); } diff --git a/packages/ui/components/localize/src/number/utils/emptyStringWhenNumberNan.js b/packages/ui/components/localize/src/number/utils/emptyStringWhenNumberNan.js index 598c35a07..fad1a986a 100644 --- a/packages/ui/components/localize/src/number/utils/emptyStringWhenNumberNan.js +++ b/packages/ui/components/localize/src/number/utils/emptyStringWhenNumberNan.js @@ -1,4 +1,4 @@ -import { localize } from '../../singleton.js'; +import { getLocalizeManager } from '../../getLocalizeManager.js'; /** * When number is NaN we should return an empty string or returnIfNaN param @@ -7,5 +7,6 @@ import { localize } from '../../singleton.js'; * @returns {string} */ export function emptyStringWhenNumberNan(returnIfNaN) { - return returnIfNaN || localize.formatNumberOptions.returnIfNaN; + const localizeManager = getLocalizeManager(); + return returnIfNaN || localizeManager.formatNumberOptions.returnIfNaN; } diff --git a/packages/ui/components/localize/src/utils/getLocale.js b/packages/ui/components/localize/src/utils/getLocale.js index 737b46e69..90d06711d 100644 --- a/packages/ui/components/localize/src/utils/getLocale.js +++ b/packages/ui/components/localize/src/utils/getLocale.js @@ -1,4 +1,4 @@ -import { localize } from '../singleton.js'; +import { getLocalizeManager } from '../getLocalizeManager.js'; /** * Gets the locale to use @@ -7,11 +7,6 @@ import { localize } from '../singleton.js'; * @returns {string} */ export function getLocale(locale) { - if (locale) { - return locale; - } - if (localize && localize.locale) { - return localize.locale; - } - return 'en-GB'; + const localizeManager = getLocalizeManager(); + return locale || localizeManager?.locale || 'en-GB'; } diff --git a/packages/ui/components/localize/test-helpers/localizeTearDown.js b/packages/ui/components/localize/test-helpers/localizeTearDown.js index 573bffbf8..43e7b7a6b 100644 --- a/packages/ui/components/localize/test-helpers/localizeTearDown.js +++ b/packages/ui/components/localize/test-helpers/localizeTearDown.js @@ -1,11 +1,12 @@ -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; export const localizeTearDown = () => { + const localizeManager = getLocalizeManager(); // makes sure that between tests the localization is reset to default state // @ts-ignore - localize._teardownHtmlLangAttributeObserver(); + localizeManager._teardownHtmlLangAttributeObserver(); document.documentElement.lang = 'en-GB'; // @ts-ignore - localize._setupHtmlLangAttributeObserver(); - localize.reset(); + localizeManager._setupHtmlLangAttributeObserver(); + localizeManager.reset(); }; diff --git a/packages/ui/components/localize/types/LocalizeMixinTypes.ts b/packages/ui/components/localize/types/LocalizeMixinTypes.ts index a9102f683..a7904800b 100644 --- a/packages/ui/components/localize/types/LocalizeMixinTypes.ts +++ b/packages/ui/components/localize/types/LocalizeMixinTypes.ts @@ -1,6 +1,7 @@ import { Constructor } from '@open-wc/dedupe-mixin'; import { LitElement } from 'lit'; import { DirectiveResult } from 'lit/directive.js'; +import { LocalizeManager } from '../src/LocalizeManager.js'; export interface FormatNumberPart { type: string; @@ -76,7 +77,13 @@ export declare class LocalizeMixinHost { public onLocaleUpdated(): void; public connectedCallback(): void; public disconnectedCallback(): void; - public msgLit(keys: string | string[], variables?: msgVariables, options?: msgOptions): string | DirectiveResult; + public msgLit( + keys: string | string[], + variables?: msgVariables, + options?: msgOptions, + ): string | DirectiveResult; + + protected _localizeManager: LocalizeManager; private __boundLocalizeOnLocaleChanged(...args: Object[]): void; private __boundLocalizeOnLocaleChanging(...args: Object[]): void; diff --git a/packages/ui/components/pagination/src/LionPagination.js b/packages/ui/components/pagination/src/LionPagination.js index b51c10253..b20f9d989 100644 --- a/packages/ui/components/pagination/src/LionPagination.js +++ b/packages/ui/components/pagination/src/LionPagination.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-extraneous-dependencies */ import { LitElement, html, css } from 'lit'; -import { LocalizeMixin } from '@lion/ui/localize.js'; +import { LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; /** * @typedef {import('lit').TemplateResult} TemplateResult diff --git a/packages/ui/components/progress-indicator/src/LionProgressIndicator.js b/packages/ui/components/progress-indicator/src/LionProgressIndicator.js index e801be7be..99f610936 100644 --- a/packages/ui/components/progress-indicator/src/LionProgressIndicator.js +++ b/packages/ui/components/progress-indicator/src/LionProgressIndicator.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-extraneous-dependencies */ import { LitElement, nothing } from 'lit'; -import { localize, LocalizeMixin } from '@lion/ui/localize.js'; +import { getLocalizeManager, LocalizeMixin } from '@lion/ui/localize-no-side-effects.js'; /** * @typedef {import('lit').TemplateResult} TemplateResult @@ -195,10 +195,11 @@ export class LionProgressIndicator extends LocalizeMixin(LitElement) { } _setDefaultLabel() { + const localizeManager = getLocalizeManager(); if (this._ariaLabelledby) { this.removeAttribute('aria-label'); } else if (!this._ariaLabel) { - this.setAttribute('aria-label', localize.msg('lion-progress-indicator:loading')); + this.setAttribute('aria-label', localizeManager.msg('lion-progress-indicator:loading')); this.__hasDefaultLabelSet = true; } } diff --git a/packages/ui/components/validate-messages/src/loadDefaultFeedbackMessages.js b/packages/ui/components/validate-messages/src/loadDefaultFeedbackMessages.js index 873336d8f..2a78beacb 100644 --- a/packages/ui/components/validate-messages/src/loadDefaultFeedbackMessages.js +++ b/packages/ui/components/validate-messages/src/loadDefaultFeedbackMessages.js @@ -1,5 +1,5 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { loadDefaultFeedbackMessagesNoSideEffects } from './loadDefaultFeedbackMessagesNoSideEffects.js'; /** @@ -7,5 +7,5 @@ import { loadDefaultFeedbackMessagesNoSideEffects } from './loadDefaultFeedbackM */ export function loadDefaultFeedbackMessages() { - return loadDefaultFeedbackMessagesNoSideEffects({ localize }); + return loadDefaultFeedbackMessagesNoSideEffects({ localize: getLocalizeManager() }); } diff --git a/packages/ui/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js b/packages/ui/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js index 19d97755c..9d3462721 100644 --- a/packages/ui/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js +++ b/packages/ui/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.js @@ -1,6 +1,6 @@ /* eslint-disable no-unused-vars, no-param-reassign */ import { expect } from '@open-wc/testing'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { Required } from '@lion/ui/form-core.js'; import { loadDefaultFeedbackMessagesNoSideEffects } from '@lion/ui/validate-messages-no-side-effects.js'; @@ -20,6 +20,8 @@ function getProtectedMembers(validatorEl) { } describe('loadDefaultFeedbackMessagesNoSideEffects', () => { + const localizeManager = getLocalizeManager(); + it('will set default feedback message for Required', async () => { const el = new Required(); const { getMessage } = getProtectedMembers(el); @@ -27,18 +29,18 @@ describe('loadDefaultFeedbackMessagesNoSideEffects', () => { 'Please configure an error message for "Required" by overriding "static async getMessage()"', ); - loadDefaultFeedbackMessagesNoSideEffects({ localize }); + loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager }); expect(await getMessage({ fieldName: 'password' })).to.equal('Please enter a(n) password.'); }); it('will await loading of translations when switching locale', async () => { const el = new Required(); const { getMessage } = getProtectedMembers(el); - loadDefaultFeedbackMessagesNoSideEffects({ localize }); + loadDefaultFeedbackMessagesNoSideEffects({ localize: localizeManager }); expect(await getMessage({ fieldName: 'password' })).to.equal('Please enter a(n) password.'); expect(await getMessage({ fieldName: 'user name' })).to.equal('Please enter a(n) user name.'); - localize.locale = 'de-DE'; + localizeManager.locale = 'de-DE'; expect(await getMessage({ fieldName: 'Password' })).to.equal( 'Password muss ausgefüllt werden.', );