feat(@lion/ui): localize side effect free internally

This commit is contained in:
Thijs Louisse 2023-02-01 10:20:15 +01:00 committed by Thijs Louisse
parent 6712934782
commit 467ba6bf0b
31 changed files with 129 additions and 83 deletions

View file

@ -3,10 +3,9 @@ import { html, LitElement } from 'lit';
import { import {
getMonthNames, getMonthNames,
getWeekdayNames, getWeekdayNames,
localize,
LocalizeMixin, LocalizeMixin,
normalizeDateTime, normalizeDateTime,
} from '@lion/ui/localize.js'; } from '@lion/ui/localize-no-side-effects.js';
import { calendarStyle } from './calendarStyle.js'; import { calendarStyle } from './calendarStyle.js';
import { createDay } from './utils/createDay.js'; import { createDay } from './utils/createDay.js';
@ -862,6 +861,6 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
* @private * @private
*/ */
__getLocale() { __getLocale() {
return this.locale || localize.locale; return this.locale || this._localizeManager.locale;
} }
} }

View file

@ -3,7 +3,7 @@ import { SlotMixin, DisabledMixin } from '@lion/ui/core.js';
import { ScopedElementsMixin } from '@open-wc/scoped-elements'; import { ScopedElementsMixin } from '@open-wc/scoped-elements';
import { dedupeMixin } from '@open-wc/dedupe-mixin'; import { dedupeMixin } from '@open-wc/dedupe-mixin';
// TODO: make form-core independent from localize // 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 { AsyncQueue } from '../utils/AsyncQueue.js';
import { pascalCase } from '../utils/pascalCase.js'; import { pascalCase } from '../utils/pascalCase.js';
import { SyncUpdatableMixin } from '../utils/SyncUpdatableMixin.js'; import { SyncUpdatableMixin } from '../utils/SyncUpdatableMixin.js';
@ -262,12 +262,16 @@ export const ValidateMixinImplementation = superclass =>
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
localize.addEventListener('localeChanged', this._updateFeedbackComponent);
const localizeManager = getLocalizeManager();
localizeManager.addEventListener('localeChanged', this._updateFeedbackComponent);
} }
disconnectedCallback() { disconnectedCallback() {
super.disconnectedCallback(); super.disconnectedCallback();
localize.removeEventListener('localeChanged', this._updateFeedbackComponent);
const localizeManager = getLocalizeManager();
localizeManager.removeEventListener('localeChanged', this._updateFeedbackComponent);
} }
/** /**

View file

@ -1,6 +1,6 @@
/* eslint-disable max-classes-per-file */ /* eslint-disable max-classes-per-file */
// TODO: move to input-datepicker? // 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'; import { Validator } from '../Validator.js';
/** /**

View file

@ -1,5 +1,5 @@
import { LitElement } from 'lit'; 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 { aTimeout, defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
import sinon from 'sinon'; import sinon from 'sinon';
import { Unparseable, Validator, FormatMixin } from '@lion/ui/form-core.js'; import { Unparseable, Validator, FormatMixin } from '@lion/ui/form-core.js';

View file

@ -1,5 +1,5 @@
import { LitElement } from 'lit'; 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 { localizeTearDown } from '@lion/ui/localize-test-helpers.js';
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
import { getFormControlMembers, AlwaysInvalid } from '@lion/ui/form-core-test-helpers.js'; import { getFormControlMembers, AlwaysInvalid } from '@lion/ui/form-core-test-helpers.js';
@ -18,6 +18,8 @@ import {
*/ */
export function runValidateMixinFeedbackPart() { export function runValidateMixinFeedbackPart() {
const localizeManager = getLocalizeManager();
describe('Validity Feedback', () => { describe('Validity Feedback', () => {
beforeEach(() => { beforeEach(() => {
localizeTearDown(); localizeTearDown();
@ -65,7 +67,7 @@ export function runValidateMixinFeedbackPart() {
AlwaysInvalid.getMessage = async () => 'Message for AlwaysInvalid'; AlwaysInvalid.getMessage = async () => 'Message for AlwaysInvalid';
MinLength.getMessage = async () => 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'; ContainsLowercaseA.getMessage = async () => 'Message for ContainsLowercaseA';
ContainsCat.getMessage = async () => 'Message for ContainsCat'; ContainsCat.getMessage = async () => 'Message for ContainsCat';
@ -341,8 +343,8 @@ export function runValidateMixinFeedbackPart() {
expect(_feedbackNode.feedbackData?.length).to.equal(1); expect(_feedbackNode.feedbackData?.length).to.equal(1);
expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength'); expect(_feedbackNode.feedbackData?.[0].message).to.equal('Message for MinLength');
localize.locale = 'de-DE'; localizeManager.locale = 'de-DE';
await localize.loadingComplete; await localizeManager.loadingComplete;
await el.feedbackComplete; await el.feedbackComplete;
expect(_feedbackNode.feedbackData?.[0].message).to.equal('Nachricht für MinLength'); expect(_feedbackNode.feedbackData?.[0].message).to.equal('Nachricht für MinLength');
}); });

View file

@ -1,6 +1,6 @@
import { expect } from '@open-wc/testing'; 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'; import { IsDate, MinDate, MaxDate, MinMaxDate, IsDateDisabled } from '@lion/ui/form-core.js';
describe('Date Validation', () => { describe('Date Validation', () => {

View file

@ -1,6 +1,6 @@
import { css } from 'lit'; import { css } from 'lit';
import { LionInput } from '@lion/ui/input.js'; 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 { IsNumber } from '@lion/ui/form-core.js';
import { formatAmount, formatCurrencyLabel } from './formatters.js'; import { formatAmount, formatCurrencyLabel } from './formatters.js';
import { parseAmount } from './parsers.js'; import { parseAmount } from './parsers.js';
@ -201,7 +201,7 @@ export class LionInputAmount extends LocalizeMixin(LionInput) {
} }
get __currencyLabel() { get __currencyLabel() {
return this.currency ? formatCurrencyLabel(this.currency, localize.locale) : ''; return this.currency ? formatCurrencyLabel(this.currency, this._localizeManager.locale) : '';
} }
__reformat() { __reformat() {

View file

@ -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 * @typedef {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} FormatOptions

View file

@ -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 * @typedef {import('../../localize/types/LocalizeMixinTypes.js').FormatNumberOptions} FormatOptions

View file

@ -1,6 +1,6 @@
import { IsDate } from '@lion/ui/form-core.js'; import { IsDate } from '@lion/ui/form-core.js';
import { LionInput } from '@lion/ui/input.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 * @param {Date|number} date

View file

@ -10,7 +10,7 @@ import {
withModalDialogConfig, withModalDialogConfig,
ArrowMixin, ArrowMixin,
} from '@lion/ui/overlays.js'; } 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'; import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
/** /**

View file

@ -1,6 +1,6 @@
import { IsEmail } from '@lion/ui/form-core.js'; import { IsEmail } from '@lion/ui/form-core.js';
import { LionInput } from '@lion/ui/input.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 * LionInputEmail: extension of lion-input

View file

@ -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 { LionInput } from '@lion/ui/input.js';
import { formatIBAN } from './formatters.js'; import { formatIBAN } from './formatters.js';
import { parseIBAN } from './parsers.js'; import { parseIBAN } from './parsers.js';

View file

@ -1,15 +1,16 @@
/* eslint-disable max-classes-per-file, import/no-extraneous-dependencies */ /* 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 { Unparseable, Validator } from '@lion/ui/form-core.js';
import { isValidIBAN } from 'ibantools'; import { isValidIBAN } from 'ibantools';
let loaded = false; let loaded = false;
const loadTranslations = async () => { const loadTranslations = async () => {
const localizeManager = getLocalizeManager();
if (loaded) { if (loaded) {
return; return;
} }
await localize.loadNamespace( await localizeManager.loadNamespace(
{ {
'lion-validate+iban': /** @param {string} locale */ locale => { 'lion-validate+iban': /** @param {string} locale */ locale => {
switch (locale) { switch (locale) {
@ -86,7 +87,7 @@ const loadTranslations = async () => {
} }
}, },
}, },
{ locale: localize.locale }, { locale: localizeManager.locale },
); );
loaded = true; loaded = true;
}; };
@ -113,8 +114,9 @@ export class IsIBAN extends Validator {
* @returns {Promise<string|Element>} * @returns {Promise<string|Element>}
*/ */
static async getMessage(data) { static async getMessage(data) {
const localizeManager = getLocalizeManager();
await loadTranslations(); 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<string|Element>} * @returns {Promise<string|Element>}
*/ */
static async getMessage(data) { static async getMessage(data) {
const localizeManager = getLocalizeManager();
await loadTranslations(); await loadTranslations();
// If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback
return data?.modelValue instanceof Unparseable return data?.modelValue instanceof Unparseable
? localize.msg('lion-validate+iban:error.IsIBAN', data) ? localizeManager.msg('lion-validate+iban:error.IsIBAN', data)
: localize.msg('lion-validate+iban:error.IsCountryIBAN', data); : localizeManager.msg('lion-validate+iban:error.IsCountryIBAN', data);
} }
} }
@ -203,6 +207,8 @@ export class IsNotCountryIBAN extends IsIBAN {
* @returns {Promise<string|Element>} * @returns {Promise<string|Element>}
*/ */
static async getMessage(data) { static async getMessage(data) {
const localizeManager = getLocalizeManager();
await loadTranslations(); await loadTranslations();
const _data = { const _data = {
...data, ...data,
@ -211,7 +217,7 @@ export class IsNotCountryIBAN extends IsIBAN {
}; };
// If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback // If modelValue is Unparseable, the IsIBAN message is the more appropriate feedback
return data?.modelValue instanceof Unparseable return data?.modelValue instanceof Unparseable
? localize.msg('lion-validate+iban:error.IsIBAN', _data) ? localizeManager.msg('lion-validate+iban:error.IsIBAN', _data)
: localize.msg('lion-validate+iban:error.IsNotCountryIBAN', _data); : localizeManager.msg('lion-validate+iban:error.IsNotCountryIBAN', _data);
} }
} }

View file

@ -2,7 +2,7 @@
import { css, html } from 'lit'; import { css, html } from 'lit';
import { ScopedStylesController } from '@lion/ui/core.js'; import { ScopedStylesController } from '@lion/ui/core.js';
import { LionInput } from '@lion/ui/input.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 * @typedef {import('lit').CSSResult} CSSResult

View file

@ -2,7 +2,7 @@ import { html, css } from 'lit';
import { ref, createRef } from 'lit/directives/ref.js'; import { ref, createRef } from 'lit/directives/ref.js';
import { LionInputTel } from '@lion/ui/input-tel.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'; import { getFlagSymbol } from './getFlagSymbol.js';
/** /**
@ -80,6 +80,7 @@ export class LionInputTelDropdown extends LionInputTel {
* @type {TemplateDataForDropdownInputTel} * @type {TemplateDataForDropdownInputTel}
*/ */
get _templateDataDropdown() { get _templateDataDropdown() {
const localizeManager = getLocalizeManager();
const refs = { const refs = {
dropdown: { dropdown: {
ref: this.refs.dropdown, ref: this.refs.dropdown,
@ -91,10 +92,12 @@ export class LionInputTelDropdown extends LionInputTel {
'model-value-changed': this._onDropdownValueChange, 'model-value-changed': this._onDropdownValueChange,
}, },
labels: { labels: {
selectCountry: localize.msg('lion-input-tel:selectCountry'), selectCountry: localizeManager.msg('lion-input-tel:selectCountry'),
allCountries: this._allCountriesLabel || localize.msg('lion-input-tel:allCountries'), allCountries:
this._allCountriesLabel || localizeManager.msg('lion-input-tel:allCountries'),
preferredCountries: preferredCountries:
this._preferredCountriesLabel || localize.msg('lion-input-tel:suggestedCountries'), this._preferredCountriesLabel ||
localizeManager.msg('lion-input-tel:suggestedCountries'),
}, },
}, },
}; };

View file

@ -1,5 +1,5 @@
import { Unparseable } from '@lion/ui/form-core.js'; 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 { LionInput } from '@lion/ui/input.js';
import { PhoneUtilManager } from './PhoneUtilManager.js'; import { PhoneUtilManager } from './PhoneUtilManager.js';
@ -125,7 +125,7 @@ export class LionInputTel extends LocalizeMixin(LionInput) {
// @ts-expect-error // @ts-expect-error
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
get fieldName() { 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() { onLocaleUpdated() {
super.onLocaleUpdated(); super.onLocaleUpdated();
const localeSplitted = localize.locale.split('-'); const localeSplitted = this._localizeManager.locale.split('-');
/** /**
* @protected * @protected
* @type {RegionCode} * @type {RegionCode}

View file

@ -9,7 +9,7 @@ import {
} from '@open-wc/testing'; } from '@open-wc/testing';
import sinon from 'sinon'; import sinon from 'sinon';
import { mimicUserInput } from '@lion/ui/form-core-test-helpers.js'; 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 { Unparseable } from '@lion/ui/form-core.js';
import { LionInputTel, PhoneNumber, PhoneUtilManager } from '@lion/ui/input-tel.js'; import { LionInputTel, PhoneNumber, PhoneUtilManager } from '@lion/ui/input-tel.js';
import { mockPhoneUtilManager, restorePhoneUtilManager } from '@lion/ui/input-tel-test-helpers.js'; import { mockPhoneUtilManager, restorePhoneUtilManager } from '@lion/ui/input-tel-test-helpers.js';
@ -23,7 +23,8 @@ const fixture = /** @type {(arg: string | TemplateResult) => Promise<LionInputTe
const fixtureSync = /** @type {(arg: string | TemplateResult) => LionInputTel} */ (_fixtureSync); const fixtureSync = /** @type {(arg: string | TemplateResult) => LionInputTel} */ (_fixtureSync);
const getRegionCodeBasedOnLocale = () => { const getRegionCodeBasedOnLocale = () => {
const localeSplitted = localize.locale.split('-'); const localizeManager = getLocalizeManager();
const localeSplitted = localizeManager.locale.split('-');
return /** @type {RegionCode} */ (localeSplitted[localeSplitted.length - 1]).toUpperCase(); return /** @type {RegionCode} */ (localeSplitted[localeSplitted.length - 1]).toUpperCase();
}; };

View file

@ -1,7 +1,7 @@
import { dedupeMixin } from '@open-wc/dedupe-mixin'; import { dedupeMixin } from '@open-wc/dedupe-mixin';
import { nothing } from 'lit'; import { nothing } from 'lit';
import { until } from 'lit/directives/until.js'; import { until } from 'lit/directives/until.js';
import { localize } from './singleton.js'; import { getLocalizeManager } from './getLocalizeManager.js';
/** /**
* @typedef {import('lit/directive.js').DirectiveResult} DirectiveResult * @typedef {import('lit/directive.js').DirectiveResult} DirectiveResult
@ -34,6 +34,8 @@ const LocalizeMixinImplementation = superclass =>
constructor() { constructor() {
super(); super();
this._localizeManager = getLocalizeManager();
/** @private */ /** @private */
this.__boundLocalizeOnLocaleChanged = this.__boundLocalizeOnLocaleChanged =
/** @param {...Object} args */ /** @param {...Object} args */
@ -74,14 +76,23 @@ const LocalizeMixinImplementation = superclass =>
if (this.localizeNamespacesLoaded) { if (this.localizeNamespacesLoaded) {
this.localizeNamespacesLoaded.then(() => this.onLocaleReady()); this.localizeNamespacesLoaded.then(() => this.onLocaleReady());
} }
localize.addEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging); this._localizeManager.addEventListener(
localize.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged); '__localeChanging',
this.__boundLocalizeOnLocaleChanging,
);
this._localizeManager.addEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged);
} }
disconnectedCallback() { disconnectedCallback() {
super.disconnectedCallback(); super.disconnectedCallback();
localize.removeEventListener('__localeChanging', this.__boundLocalizeOnLocaleChanging); this._localizeManager.removeEventListener(
localize.removeEventListener('localeChanged', this.__boundLocalizeOnLocaleChanged); '__localeChanging',
this.__boundLocalizeOnLocaleChanging,
);
this._localizeManager.removeEventListener(
'localeChanged',
this.__boundLocalizeOnLocaleChanged,
);
} }
/** /**
@ -93,7 +104,7 @@ const LocalizeMixinImplementation = superclass =>
*/ */
msgLit(keys, variables, options) { msgLit(keys, variables, options) {
if (this.__localizeMessageSync) { if (this.__localizeMessageSync) {
return localize.msg(keys, variables, options); return this._localizeManager.msg(keys, variables, options);
} }
if (!this.localizeNamespacesLoaded) { if (!this.localizeNamespacesLoaded) {
@ -101,7 +112,9 @@ const LocalizeMixinImplementation = superclass =>
} }
return until( return until(
this.localizeNamespacesLoaded.then(() => localize.msg(keys, variables, options)), this.localizeNamespacesLoaded.then(() =>
this._localizeManager.msg(keys, variables, options),
),
nothing, nothing,
); );
} }
@ -125,12 +138,14 @@ const LocalizeMixinImplementation = superclass =>
/** @private */ /** @private */
__localizeStartLoadingNamespaces() { __localizeStartLoadingNamespaces() {
this.localizeNamespacesLoaded = localize.loadNamespaces(this.__getUniqueNamespaces()); this.localizeNamespacesLoaded = this._localizeManager.loadNamespaces(
this.__getUniqueNamespaces(),
);
} }
/** /**
* Start loading namespaces on the event that is sent immediately * Start loading namespaces on the event that is sent immediately
* when localize.locale changes --> 'localeChanging' * when this._localizeManager.locale changes --> 'localeChanging'
* @private * @private
*/ */
__localizeOnLocaleChanging() { __localizeOnLocaleChanging() {

View file

@ -1,5 +1,5 @@
import { getLocale } from '../utils/getLocale.js'; import { getLocale } from '../utils/getLocale.js';
import { localize } from '../singleton.js'; import { getLocalizeManager } from '../getLocalizeManager.js';
import { normalizeIntlDate } from './utils/normalizeIntlDate.js'; import { normalizeIntlDate } from './utils/normalizeIntlDate.js';
/** @typedef {import('../../types/LocalizeMixinTypes.js').DatePostProcessor} DatePostProcessor */ /** @typedef {import('../../types/LocalizeMixinTypes.js').DatePostProcessor} DatePostProcessor */
@ -12,6 +12,7 @@ import { normalizeIntlDate } from './utils/normalizeIntlDate.js';
* @returns {string} * @returns {string}
*/ */
export function formatDate(date, options) { export function formatDate(date, options) {
const localizeManager = getLocalizeManager();
if (!(date instanceof Date)) { if (!(date instanceof Date)) {
return ''; return '';
} }
@ -36,8 +37,8 @@ export function formatDate(date, options) {
formattedDate = ''; formattedDate = '';
} }
if (localize.formatDateOptions.postProcessors.size > 0) { if (localizeManager.formatDateOptions.postProcessors.size > 0) {
Array.from(localize.formatDateOptions.postProcessors).forEach(([locale, fn]) => { Array.from(localizeManager.formatDateOptions.postProcessors).forEach(([locale, fn]) => {
if (locale === computedLocale) { if (locale === computedLocale) {
formattedDate = fn(formattedDate); formattedDate = fn(formattedDate);
} }

View file

@ -1,5 +1,5 @@
import { getDateFormatBasedOnLocale } from './getDateFormatBasedOnLocale.js'; import { getDateFormatBasedOnLocale } from './getDateFormatBasedOnLocale.js';
import { localize } from '../singleton.js'; import { getLocalizeManager } from '../getLocalizeManager.js';
import { addLeadingZero } from './utils/addLeadingZero.js'; import { addLeadingZero } from './utils/addLeadingZero.js';
/** /**
@ -29,10 +29,12 @@ const memoizedGetDateFormatBasedOnLocale = memoize(getDateFormatBasedOnLocale);
* @returns {Date | undefined} * @returns {Date | undefined}
*/ */
export function parseDate(dateString) { export function parseDate(dateString) {
const localizeManager = getLocalizeManager();
const stringToParse = addLeadingZero(dateString); const stringToParse = addLeadingZero(dateString);
let parsedString; let parsedString;
switch (memoizedGetDateFormatBasedOnLocale(localize.locale)) { switch (memoizedGetDateFormatBasedOnLocale(localizeManager.locale)) {
case 'day-month-year': case 'day-month-year':
parsedString = `${stringToParse.slice(6, 10)}/${stringToParse.slice( parsedString = `${stringToParse.slice(6, 10)}/${stringToParse.slice(
3, 3,

View file

@ -1,6 +1,6 @@
/** @typedef {import('../../types/LocalizeMixinTypes.js').NumberPostProcessor} NumberPostProcessor */ /** @typedef {import('../../types/LocalizeMixinTypes.js').NumberPostProcessor} NumberPostProcessor */
import { localize } from '../singleton.js'; import { getLocalizeManager } from '../getLocalizeManager.js';
import { getLocale } from '../utils/getLocale.js'; import { getLocale } from '../utils/getLocale.js';
import { formatNumberToParts } from './formatNumberToParts.js'; import { formatNumberToParts } from './formatNumberToParts.js';
@ -14,12 +14,13 @@ import { formatNumberToParts } from './formatNumberToParts.js';
* @returns {string} * @returns {string}
*/ */
export function formatNumber(number, options = /** @type {FormatOptions} */ ({})) { export function formatNumber(number, options = /** @type {FormatOptions} */ ({})) {
const localizeManager = getLocalizeManager();
if (number === undefined || number === null) return ''; if (number === undefined || number === null) return '';
const formattedToParts = formatNumberToParts(number, options); const formattedToParts = formatNumberToParts(number, options);
// If number is not a number // If number is not a number
if ( if (
formattedToParts === options.returnIfNaN || formattedToParts === options.returnIfNaN ||
formattedToParts === localize.formatNumberOptions.returnIfNaN formattedToParts === localizeManager.formatNumberOptions.returnIfNaN
) { ) {
return /** @type {string} */ (formattedToParts); return /** @type {string} */ (formattedToParts);
} }
@ -33,8 +34,8 @@ export function formatNumber(number, options = /** @type {FormatOptions} */ ({})
const computedLocale = getLocale(options && options.locale); const computedLocale = getLocale(options && options.locale);
if (localize.formatNumberOptions.postProcessors.size > 0) { if (localizeManager.formatNumberOptions.postProcessors.size > 0) {
Array.from(localize.formatNumberOptions.postProcessors).forEach(([locale, fn]) => { Array.from(localizeManager.formatNumberOptions.postProcessors).forEach(([locale, fn]) => {
if (locale === computedLocale) { if (locale === computedLocale) {
printNumberOfParts = fn(printNumberOfParts); printNumberOfParts = fn(printNumberOfParts);
} }

View file

@ -1,4 +1,4 @@
import { localize } from '../singleton.js'; import { getLocalizeManager } from '../getLocalizeManager.js';
import { formatNumberToParts } from './formatNumberToParts.js'; import { formatNumberToParts } from './formatNumberToParts.js';
import { forceCurrencyNameForPHPEnGB } from './utils/normalize-get-currency-name/forceCurrencyNameForPHPEnGB.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' * @returns {string} currency name like 'US dollar'
*/ */
export function getCurrencyName(currencyIso, options) { export function getCurrencyName(currencyIso, options) {
const localizeManager = getLocalizeManager();
const parts = /** @type {FormatNumberPart[]} */ ( const parts = /** @type {FormatNumberPart[]} */ (
formatNumberToParts(1, { formatNumberToParts(1, {
...options, ...options,
@ -23,7 +24,7 @@ export function getCurrencyName(currencyIso, options) {
.filter(p => p.type === 'currency') .filter(p => p.type === 'currency')
.map(o => o.value) .map(o => o.value)
.join(' '); .join(' ');
const locale = options?.locale || localize.locale; const locale = options?.locale || localizeManager.locale;
if (currencyIso === 'PHP' && locale === 'en-GB') { if (currencyIso === 'PHP' && locale === 'en-GB') {
currencyName = forceCurrencyNameForPHPEnGB(currencyName); currencyName = forceCurrencyNameForPHPEnGB(currencyName);
} }

View file

@ -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 * When number is NaN we should return an empty string or returnIfNaN param
@ -7,5 +7,6 @@ import { localize } from '../../singleton.js';
* @returns {string} * @returns {string}
*/ */
export function emptyStringWhenNumberNan(returnIfNaN) { export function emptyStringWhenNumberNan(returnIfNaN) {
return returnIfNaN || localize.formatNumberOptions.returnIfNaN; const localizeManager = getLocalizeManager();
return returnIfNaN || localizeManager.formatNumberOptions.returnIfNaN;
} }

View file

@ -1,4 +1,4 @@
import { localize } from '../singleton.js'; import { getLocalizeManager } from '../getLocalizeManager.js';
/** /**
* Gets the locale to use * Gets the locale to use
@ -7,11 +7,6 @@ import { localize } from '../singleton.js';
* @returns {string} * @returns {string}
*/ */
export function getLocale(locale) { export function getLocale(locale) {
if (locale) { const localizeManager = getLocalizeManager();
return locale; return locale || localizeManager?.locale || 'en-GB';
}
if (localize && localize.locale) {
return localize.locale;
}
return 'en-GB';
} }

View file

@ -1,11 +1,12 @@
import { localize } from '@lion/ui/localize.js'; import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js';
export const localizeTearDown = () => { export const localizeTearDown = () => {
const localizeManager = getLocalizeManager();
// makes sure that between tests the localization is reset to default state // makes sure that between tests the localization is reset to default state
// @ts-ignore // @ts-ignore
localize._teardownHtmlLangAttributeObserver(); localizeManager._teardownHtmlLangAttributeObserver();
document.documentElement.lang = 'en-GB'; document.documentElement.lang = 'en-GB';
// @ts-ignore // @ts-ignore
localize._setupHtmlLangAttributeObserver(); localizeManager._setupHtmlLangAttributeObserver();
localize.reset(); localizeManager.reset();
}; };

View file

@ -1,6 +1,7 @@
import { Constructor } from '@open-wc/dedupe-mixin'; import { Constructor } from '@open-wc/dedupe-mixin';
import { LitElement } from 'lit'; import { LitElement } from 'lit';
import { DirectiveResult } from 'lit/directive.js'; import { DirectiveResult } from 'lit/directive.js';
import { LocalizeManager } from '../src/LocalizeManager.js';
export interface FormatNumberPart { export interface FormatNumberPart {
type: string; type: string;
@ -76,7 +77,13 @@ export declare class LocalizeMixinHost {
public onLocaleUpdated(): void; public onLocaleUpdated(): void;
public connectedCallback(): void; public connectedCallback(): void;
public disconnectedCallback(): 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 __boundLocalizeOnLocaleChanged(...args: Object[]): void;
private __boundLocalizeOnLocaleChanging(...args: Object[]): void; private __boundLocalizeOnLocaleChanging(...args: Object[]): void;

View file

@ -1,6 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import { LitElement, html, css } from 'lit'; 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 * @typedef {import('lit').TemplateResult} TemplateResult

View file

@ -1,6 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import { LitElement, nothing } from 'lit'; 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 * @typedef {import('lit').TemplateResult} TemplateResult
@ -195,10 +195,11 @@ export class LionProgressIndicator extends LocalizeMixin(LitElement) {
} }
_setDefaultLabel() { _setDefaultLabel() {
const localizeManager = getLocalizeManager();
if (this._ariaLabelledby) { if (this._ariaLabelledby) {
this.removeAttribute('aria-label'); this.removeAttribute('aria-label');
} else if (!this._ariaLabel) { } 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; this.__hasDefaultLabelSet = true;
} }
} }

View file

@ -1,5 +1,5 @@
/* eslint-disable import/no-extraneous-dependencies */ /* 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'; import { loadDefaultFeedbackMessagesNoSideEffects } from './loadDefaultFeedbackMessagesNoSideEffects.js';
/** /**
@ -7,5 +7,5 @@ import { loadDefaultFeedbackMessagesNoSideEffects } from './loadDefaultFeedbackM
*/ */
export function loadDefaultFeedbackMessages() { export function loadDefaultFeedbackMessages() {
return loadDefaultFeedbackMessagesNoSideEffects({ localize }); return loadDefaultFeedbackMessagesNoSideEffects({ localize: getLocalizeManager() });
} }

View file

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars, no-param-reassign */ /* eslint-disable no-unused-vars, no-param-reassign */
import { expect } from '@open-wc/testing'; 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 { Required } from '@lion/ui/form-core.js';
import { loadDefaultFeedbackMessagesNoSideEffects } from '@lion/ui/validate-messages-no-side-effects.js'; import { loadDefaultFeedbackMessagesNoSideEffects } from '@lion/ui/validate-messages-no-side-effects.js';
@ -20,6 +20,8 @@ function getProtectedMembers(validatorEl) {
} }
describe('loadDefaultFeedbackMessagesNoSideEffects', () => { describe('loadDefaultFeedbackMessagesNoSideEffects', () => {
const localizeManager = getLocalizeManager();
it('will set default feedback message for Required', async () => { it('will set default feedback message for Required', async () => {
const el = new Required(); const el = new Required();
const { getMessage } = getProtectedMembers(el); const { getMessage } = getProtectedMembers(el);
@ -27,18 +29,18 @@ describe('loadDefaultFeedbackMessagesNoSideEffects', () => {
'Please configure an error message for "Required" by overriding "static async getMessage()"', '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.'); expect(await getMessage({ fieldName: 'password' })).to.equal('Please enter a(n) password.');
}); });
it('will await loading of translations when switching locale', async () => { it('will await loading of translations when switching locale', async () => {
const el = new Required(); const el = new Required();
const { getMessage } = getProtectedMembers(el); 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: 'password' })).to.equal('Please enter a(n) password.');
expect(await getMessage({ fieldName: 'user name' })).to.equal('Please enter a(n) user name.'); 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( expect(await getMessage({ fieldName: 'Password' })).to.equal(
'Password muss ausgefüllt werden.', 'Password muss ausgefüllt werden.',
); );