@lion/ui 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/components/calendar/src/LionCalendar.js +6 -0
- package/components/core/src/DisabledWithTabIndexMixin.js +7 -0
- package/components/core/src/ScopedElementsMixin.js +58 -37
- package/components/core/test/ScopedElementsMixin.test.js +131 -0
- package/components/core/test/ssr-definitions/ScopedElementsHost.define.js +1 -0
- package/components/form/src/LionForm.js +3 -12
- package/components/form/test/lion-form.test.js +88 -1
- package/components/form-core/src/FormControlMixin.js +6 -0
- package/components/form-core/src/registration/FormRegisteringMixin.js +1 -1
- package/components/form-core/src/utils/SyncUpdatableMixin.js +7 -0
- package/components/form-core/src/validate/LionValidationFeedback.js +4 -2
- package/components/form-core/test/validate/lion-validation-feedback.test.js +12 -0
- package/components/form-core/types/registration/FormRegisteringMixinTypes.ts +1 -1
- package/components/icon/src/LionIcon.js +6 -0
- package/components/listbox/test-suites/ListboxMixin.suite.js +2 -2
- package/components/localize/src/LocalizeManager.js +259 -204
- package/components/overlays/src/OverlayController.js +1 -1
- package/components/overlays/src/OverlayMixin.js +7 -0
- package/components/progress-indicator/src/LionProgressIndicator.js +6 -0
- package/components/steps/src/LionStep.js +6 -0
- package/components/steps/src/LionSteps.js +6 -0
- package/components/tabs/src/LionTabs.js +6 -0
- package/components/tooltip/src/LionTooltip.js +6 -0
- package/custom-elements.json +792 -330
- package/dist-types/components/calendar/src/LionCalendar.d.ts +5 -0
- package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
- package/dist-types/components/core/src/DisabledWithTabIndexMixin.d.ts.map +1 -1
- package/dist-types/components/core/src/ScopedElementsMixin.d.ts +43 -6
- package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
- package/dist-types/components/core/test/ScopedElementsMixin.test.d.ts +2 -0
- package/dist-types/components/core/test/ScopedElementsMixin.test.d.ts.map +1 -0
- package/dist-types/components/core/test/ssr-definitions/ScopedElementsHost.define.d.ts +2 -0
- package/dist-types/components/core/test/ssr-definitions/ScopedElementsHost.define.d.ts.map +1 -0
- package/dist-types/components/form/src/LionForm.d.ts.map +1 -1
- package/dist-types/components/form/test/lion-form.test.d.ts.map +1 -1
- package/dist-types/components/form-core/src/FormControlMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/utils/SyncUpdatableMixin.d.ts.map +1 -1
- package/dist-types/components/form-core/src/validate/LionValidationFeedback.d.ts.map +1 -1
- package/dist-types/components/form-core/types/registration/FormRegisteringMixinTypes.d.ts +1 -1
- package/dist-types/components/form-integrations/test/helpers/helpers.d.ts +3 -3
- package/dist-types/components/form-integrations/test/helpers/helpers.d.ts.map +1 -1
- package/dist-types/components/icon/src/LionIcon.d.ts +5 -0
- package/dist-types/components/icon/src/LionIcon.d.ts.map +1 -1
- package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
- package/dist-types/components/input-file/src/LionInputFile.d.ts +1 -1
- package/dist-types/components/input-file/src/LionSelectedFileList.d.ts +1 -1
- package/dist-types/components/localize/src/LocalizeManager.d.ts +109 -112
- package/dist-types/components/localize/src/LocalizeManager.d.ts.map +1 -1
- package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
- package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts +5 -0
- package/dist-types/components/progress-indicator/src/LionProgressIndicator.d.ts.map +1 -1
- package/dist-types/components/select-rich/src/LionSelectRich.d.ts +1 -1
- package/dist-types/components/steps/src/LionStep.d.ts +5 -0
- package/dist-types/components/steps/src/LionStep.d.ts.map +1 -1
- package/dist-types/components/steps/src/LionSteps.d.ts +5 -0
- package/dist-types/components/steps/src/LionSteps.d.ts.map +1 -1
- package/dist-types/components/switch/src/LionSwitch.d.ts +1 -1
- package/dist-types/components/tabs/src/LionTabs.d.ts +5 -0
- package/dist-types/components/tabs/src/LionTabs.d.ts.map +1 -1
- package/dist-types/components/tooltip/src/LionTooltip.d.ts +5 -0
- package/dist-types/components/tooltip/src/LionTooltip.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/api-table.md +2 -2
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +1 -1
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/api-table.md +2 -2
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/api-table.md +2 -2
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/api-table.md +2 -2
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/api-table.md +2 -2
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/api-table.md +2 -2
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/api-table.md +2 -2
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/api-table.md +2 -2
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/api-table.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/api-table.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/api-table.md +2 -2
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/api-table.md +2 -2
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/api-table.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/api-table.md +2 -2
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/api-table.md +2 -2
- package/docs/components/select/use-cases.md +1 -1
- package/docs/components/select-rich/api-table.md +1 -1
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/switch/api-table.md +2 -2
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/textarea/api-table.md +2 -2
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/rationales/accessibility.md +1 -1
- package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/api-table.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +2 -2
- package/docs/fundamentals/systems/localize/api-table.md +38 -40
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/create-a-form.md +4 -4
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/package.json +1 -1
|
@@ -1,202 +1,182 @@
|
|
|
1
|
-
// @ts-
|
|
1
|
+
// @ts-expect-error
|
|
2
2
|
import MessageFormat from '@bundled-es-modules/message-format/MessageFormat.js';
|
|
3
|
+
import { isServer } from 'lit';
|
|
4
|
+
|
|
3
5
|
import isLocalizeESModule from './isLocalizeESModule.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
8
|
+
* @typedef {import('../types/LocalizeMixinTypes.js').NumberPostProcessor} NumberPostProcessor
|
|
9
|
+
* @typedef {import('../types/LocalizeMixinTypes.js').DatePostProcessor} DatePostProcessor
|
|
6
10
|
* @typedef {import('../types/LocalizeMixinTypes.js').NamespaceObject} NamespaceObject
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* We can't access `window.document.documentElement` on the server,
|
|
15
|
+
* so we write to and read from this object on the server.
|
|
16
|
+
* N.B.: for now, the goal is to make LocalizeManager not crash on the server, and let localization happen on the client.
|
|
17
|
+
* In the future, we might want to look into more advanced SSR of localized messages
|
|
18
|
+
*/
|
|
19
|
+
const documentElement = isServer
|
|
20
|
+
? { getAttribute: () => null, lang: '' }
|
|
21
|
+
: globalThis.document?.documentElement;
|
|
11
22
|
|
|
12
23
|
/**
|
|
13
24
|
* `LocalizeManager` manages your translations (includes loading)
|
|
14
25
|
*/
|
|
15
|
-
export class LocalizeManager {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/** @protected */
|
|
26
|
-
this._autoLoadOnLocaleChange = !!autoLoadOnLocaleChange;
|
|
27
|
-
/** @protected */
|
|
28
|
-
this._fallbackLocale = fallbackLocale;
|
|
29
|
-
/** @protected */
|
|
30
|
-
this._showKeyAsFallback = showKeyAsFallback;
|
|
31
|
-
|
|
32
|
-
/** @private */
|
|
33
|
-
this.__allowOverridesForExistingNamespaces = allowOverridesForExistingNamespaces;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @type {Object.<string, Object.<string, Object>>}
|
|
37
|
-
* @private
|
|
38
|
-
*/
|
|
39
|
-
this.__storage = {};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @type {Map.<RegExp|string, function>}
|
|
43
|
-
* @private
|
|
44
|
-
*/
|
|
45
|
-
this.__namespacePatternsMap = new Map();
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @type {Object.<string, function|null>}
|
|
49
|
-
* @private
|
|
50
|
-
*/
|
|
51
|
-
this.__namespaceLoadersCache = {};
|
|
26
|
+
export class LocalizeManager extends EventTarget {
|
|
27
|
+
/**
|
|
28
|
+
* The localize system uses (normalized) Intl for formatting numbers.
|
|
29
|
+
* It's possible to customize this output per locale
|
|
30
|
+
*/
|
|
31
|
+
formatNumberOptions = {
|
|
32
|
+
returnIfNaN: '',
|
|
33
|
+
/** @type {Map<string, NumberPostProcessor>} */
|
|
34
|
+
postProcessors: new Map(),
|
|
35
|
+
};
|
|
52
36
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The localize system uses (normalized) Intl for formatting dates.
|
|
39
|
+
* It's possible to customize this output per locale
|
|
40
|
+
*/
|
|
41
|
+
formatDateOptions = {
|
|
42
|
+
/** @type {Map<string, DatePostProcessor>} */
|
|
43
|
+
postProcessors: new Map(),
|
|
44
|
+
};
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Although it's common to configure the language via the html[lang] attribute,
|
|
48
|
+
* the lang attribute can be changed by 3rd party translation tools like Google Translate.
|
|
49
|
+
*
|
|
50
|
+
* ## Why is this a potential problem?
|
|
51
|
+
* The localize system reads from html[lang] for its original configuration. Let's say it's
|
|
52
|
+
* configured as "en-US" by the developer. This means all translation data are fetched for locale "en-US".
|
|
53
|
+
*
|
|
54
|
+
* Now the Google Translate plugin kicks in. It will automatically translate all English texts found into
|
|
55
|
+
* Chinese texts. Everything looks fine... But Google Translate also sets html[lang] to "zh-CN":
|
|
56
|
+
* our localize system responds by trying to fetch Chinese translation data.
|
|
57
|
+
* Two problems can occur here:
|
|
58
|
+
* - the Chinese translations don't exist
|
|
59
|
+
* - Google Translate expects to translate from English to Chinese... and now we suddenly serve Chinese text
|
|
60
|
+
* ourselves... not what we intended.
|
|
61
|
+
*
|
|
62
|
+
* ## How can we solve this?
|
|
63
|
+
* Via `html[data-localize-lang]`, developers are allowed to set the initial locale, without
|
|
64
|
+
* having to worry about whether locale is initialized before 3rd parties like Google Translate.
|
|
65
|
+
* When this value differs from html[lang], we assume the 3rd party took
|
|
66
|
+
* control over the page language and we set this.#localeSetByTranslationTool to html[lang]
|
|
67
|
+
*/
|
|
68
|
+
#shouldHandleTranslationTools = false;
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
/**
|
|
71
|
+
* The locale that is configured on html[data-localize-lang]
|
|
72
|
+
*/
|
|
73
|
+
#localeProvidedViaDataLangAttr = '';
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
/**
|
|
76
|
+
* The locale that is set on html[lang] by a 3rd party translation tool like Googl Translate
|
|
77
|
+
* @type {string|null}
|
|
78
|
+
*/
|
|
79
|
+
#localeSetByTranslationTool = null;
|
|
85
80
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
/**
|
|
82
|
+
* @type {Object<string, Object<string, Object>>}
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
__storage = {};
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
/**
|
|
88
|
+
* @type {Map<RegExp|string, function>}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
__namespacePatternsMap = new Map();
|
|
93
92
|
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
*
|
|
100
|
-
* Have the following scenario in mind:
|
|
101
|
-
* 1. locale is initialized by developer via html[data-localize-lang="en-US"] and
|
|
102
|
-
* html[lang="en-US"]. When localize is loaded (note that this also can be after step 2 below),
|
|
103
|
-
* it will sync its initial state from html[data-localize-lang]
|
|
104
|
-
* 2. Google Translate kicks in for the French language. It will set html[lang="fr"].
|
|
105
|
-
* This new language is not one known by us, so we most likely don't have translations for
|
|
106
|
-
* this file. Therefore, we do NOT sync this value to LocalizeManager. The manager should
|
|
107
|
-
* still ask for known resources (in this case for locale 'en-US')
|
|
108
|
-
* 3. locale is changed (think of a language dropdown)
|
|
109
|
-
* It's a bit of a weird case, because we would not expect an end user to do this. If he/she
|
|
110
|
-
* does, make sure that we do not go against Google Translate, so we maintain accessibility
|
|
111
|
-
* (by not altering html[lang]). We detect this by reading _langAttrSetByTranslationTool:
|
|
112
|
-
* when its value is null, we consider Google translate 'not active'.
|
|
113
|
-
*
|
|
114
|
-
* When Google Translate is turned off by the user (html[lang=auto]),
|
|
115
|
-
* `localize.locale` will be synced to html[lang] again
|
|
116
|
-
*
|
|
117
|
-
* Keep in mind that all of the above also works with other tools than Google Translate,
|
|
118
|
-
* but this is the most widely used tool and therefore used as an example.
|
|
119
|
-
*/
|
|
120
|
-
this._langAttrSetByTranslationTool = document.documentElement.lang || null;
|
|
121
|
-
}
|
|
93
|
+
/**
|
|
94
|
+
* @type {Object<string, function|null>}
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
__namespaceLoadersCache = {};
|
|
122
98
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
99
|
+
/**
|
|
100
|
+
* @type {Object<string, Object<string, Promise<Object|void>>>}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
__namespaceLoaderPromisesCache = {};
|
|
126
104
|
|
|
127
105
|
/**
|
|
128
106
|
* @returns {string}
|
|
129
107
|
*/
|
|
130
108
|
get locale() {
|
|
131
|
-
if (this
|
|
132
|
-
return
|
|
109
|
+
if (!this.#shouldHandleTranslationTools) {
|
|
110
|
+
return documentElement.lang || '';
|
|
133
111
|
}
|
|
134
|
-
return
|
|
112
|
+
return this.#localeProvidedViaDataLangAttr || '';
|
|
135
113
|
}
|
|
136
114
|
|
|
137
115
|
/**
|
|
138
|
-
* @param {string}
|
|
116
|
+
* @param {string} newLocale
|
|
139
117
|
*/
|
|
140
|
-
set locale(
|
|
141
|
-
|
|
142
|
-
let oldLocale;
|
|
143
|
-
if (this._supportExternalTranslationTools) {
|
|
144
|
-
oldLocale = /** @type {string} */ (this.__locale);
|
|
145
|
-
this.__locale = value;
|
|
146
|
-
if (this._langAttrSetByTranslationTool === null) {
|
|
147
|
-
this._setHtmlLangAttribute(value);
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
oldLocale = document.documentElement.lang;
|
|
151
|
-
this._setHtmlLangAttribute(value);
|
|
152
|
-
}
|
|
118
|
+
set locale(newLocale) {
|
|
119
|
+
this.#assertCorrectLocale(newLocale);
|
|
153
120
|
|
|
154
|
-
if (!
|
|
155
|
-
|
|
121
|
+
if (!this.#shouldHandleTranslationTools) {
|
|
122
|
+
const oldLocale = documentElement.lang;
|
|
123
|
+
this._setHtmlLangAttribute(newLocale);
|
|
124
|
+
this._onLocaleChanged(newLocale, oldLocale);
|
|
125
|
+
return;
|
|
156
126
|
}
|
|
157
127
|
|
|
158
|
-
|
|
128
|
+
const oldLocale = /** @type {string} */ (this.#localeProvidedViaDataLangAttr);
|
|
129
|
+
this.#localeProvidedViaDataLangAttr = newLocale;
|
|
130
|
+
const isLangAutoOrTranslationToolNotProcessed = this.#localeSetByTranslationTool === null;
|
|
131
|
+
if (isLangAutoOrTranslationToolNotProcessed) {
|
|
132
|
+
this._setHtmlLangAttribute(newLocale);
|
|
133
|
+
}
|
|
134
|
+
this._onLocaleChanged(newLocale, oldLocale);
|
|
159
135
|
}
|
|
160
136
|
|
|
161
137
|
/**
|
|
162
|
-
* @
|
|
163
|
-
* @
|
|
138
|
+
* @readonly
|
|
139
|
+
* @returns {Promise<Object|void>}
|
|
164
140
|
*/
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
this._setupHtmlLangAttributeObserver();
|
|
169
|
-
}
|
|
141
|
+
get loadingComplete() {
|
|
142
|
+
const hasPendingCacheForLocale =
|
|
143
|
+
typeof this.__namespaceLoaderPromisesCache[this.locale] === 'object';
|
|
170
144
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
* @private
|
|
175
|
-
*/
|
|
176
|
-
// eslint-disable-next-line class-methods-use-this
|
|
177
|
-
__handleLanguageOnly(value) {
|
|
178
|
-
throw new Error(`
|
|
179
|
-
Locale was set to ${value}.
|
|
180
|
-
Language only locales are not allowed, please use the full language locale e.g. 'en-GB' instead of 'en'.
|
|
181
|
-
See https://github.com/ing-bank/lion/issues/187 for more information.
|
|
182
|
-
`);
|
|
145
|
+
return !hasPendingCacheForLocale
|
|
146
|
+
? Promise.resolve()
|
|
147
|
+
: Promise.all(Object.values(this.__namespaceLoaderPromisesCache[this.locale]));
|
|
183
148
|
}
|
|
184
149
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
150
|
+
constructor({
|
|
151
|
+
allowOverridesForExistingNamespaces = false,
|
|
152
|
+
autoLoadOnLocaleChange = false,
|
|
153
|
+
showKeyAsFallback = false,
|
|
154
|
+
fallbackLocale = '',
|
|
155
|
+
} = {}) {
|
|
156
|
+
super();
|
|
157
|
+
|
|
158
|
+
/** @private */
|
|
159
|
+
this.__allowOverridesForExistingNamespaces = allowOverridesForExistingNamespaces;
|
|
160
|
+
/** @protected */
|
|
161
|
+
this._autoLoadOnLocaleChange = !!autoLoadOnLocaleChange;
|
|
162
|
+
/** @protected */
|
|
163
|
+
this._showKeyAsFallback = showKeyAsFallback;
|
|
164
|
+
/** @protected */
|
|
165
|
+
this._fallbackLocale = fallbackLocale;
|
|
166
|
+
|
|
167
|
+
const localeProvidedViaDataLangAttr = documentElement.getAttribute('data-localize-lang');
|
|
168
|
+
this.#shouldHandleTranslationTools = Boolean(localeProvidedViaDataLangAttr);
|
|
169
|
+
|
|
170
|
+
if (this.#shouldHandleTranslationTools) {
|
|
171
|
+
this.locale = /** @type {string} */ (localeProvidedViaDataLangAttr);
|
|
172
|
+
this._setupTranslationToolSupport();
|
|
191
173
|
}
|
|
192
|
-
return Promise.resolve();
|
|
193
|
-
}
|
|
194
174
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.
|
|
175
|
+
if (!documentElement.lang) {
|
|
176
|
+
documentElement.lang = this.locale || 'en-GB';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this._setupHtmlLangAttributeObserver();
|
|
200
180
|
}
|
|
201
181
|
|
|
202
182
|
/**
|
|
@@ -240,7 +220,7 @@ export class LocalizeManager {
|
|
|
240
220
|
* @param {NamespaceObject[]} namespaces
|
|
241
221
|
* @param {Object} options
|
|
242
222
|
* @param {string} [options.locale]
|
|
243
|
-
* @returns {Promise
|
|
223
|
+
* @returns {Promise<Object>}
|
|
244
224
|
*/
|
|
245
225
|
loadNamespaces(namespaces, { locale } = {}) {
|
|
246
226
|
return Promise.all(
|
|
@@ -255,7 +235,7 @@ export class LocalizeManager {
|
|
|
255
235
|
* @param {NamespaceObject} namespaceObj
|
|
256
236
|
* @param {Object} options
|
|
257
237
|
* @param {string} [options.locale]
|
|
258
|
-
* @returns {Promise
|
|
238
|
+
* @returns {Promise<Object|void>}
|
|
259
239
|
*/
|
|
260
240
|
loadNamespace(namespaceObj, { locale = this.locale } = { locale: this.locale }) {
|
|
261
241
|
const isDynamicImport = typeof namespaceObj === 'object';
|
|
@@ -278,7 +258,7 @@ export class LocalizeManager {
|
|
|
278
258
|
|
|
279
259
|
/**
|
|
280
260
|
* @param {string | string[]} keys
|
|
281
|
-
* @param {Object
|
|
261
|
+
* @param {Object<string,?>} [vars]
|
|
282
262
|
* @param {Object} [opts]
|
|
283
263
|
* @param {string} [opts.locale]
|
|
284
264
|
* @returns {string}
|
|
@@ -293,18 +273,84 @@ export class LocalizeManager {
|
|
|
293
273
|
return formatter.format(vars);
|
|
294
274
|
}
|
|
295
275
|
|
|
276
|
+
teardown() {
|
|
277
|
+
this._teardownHtmlLangAttributeObserver();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
reset() {
|
|
281
|
+
this.__storage = {};
|
|
282
|
+
this.__namespacePatternsMap = new Map();
|
|
283
|
+
this.__namespaceLoadersCache = {};
|
|
284
|
+
this.__namespaceLoaderPromisesCache = {};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @param {{locale:string, postProcessor:DatePostProcessor}} options
|
|
289
|
+
*/
|
|
290
|
+
setDatePostProcessorForLocale({ locale, postProcessor }) {
|
|
291
|
+
this.formatDateOptions?.postProcessors.set(locale, postProcessor);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @param {{locale:string, postProcessor:NumberPostProcessor}} options
|
|
296
|
+
*/
|
|
297
|
+
setNumberPostProcessorForLocale({ locale, postProcessor }) {
|
|
298
|
+
this.formatNumberOptions?.postProcessors.set(locale, postProcessor);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* This value allows for support for Google Translate (or other 3rd parties taking control
|
|
303
|
+
* of the html[lang] attribute).
|
|
304
|
+
*
|
|
305
|
+
* Have the following scenario in mind:
|
|
306
|
+
* 1. locale is initialized by developer via html[data-localize-lang="en-US"] and
|
|
307
|
+
* html[lang="en-US"]. When localize is loaded (note that this also can be after step 2 below),
|
|
308
|
+
* it will sync its initial state from html[data-localize-lang]
|
|
309
|
+
* 2. Google Translate kicks in for the French language. It will set html[lang="fr"].
|
|
310
|
+
* This new language is not one known by us, so we most likely don't have translations for
|
|
311
|
+
* this file. Therefore, we do NOT sync this value to LocalizeManager. The manager should
|
|
312
|
+
* still ask for known resources (in this case for locale 'en-US')
|
|
313
|
+
* 3. locale is changed (think of a language dropdown)
|
|
314
|
+
* It's a bit of a weird case, because we would not expect an end user to do this. If he/she
|
|
315
|
+
* does, make sure that we do not go against Google Translate, so we maintain accessibility
|
|
316
|
+
* (by not altering html[lang]). We detect this by reading #localeSetByTranslationTool:
|
|
317
|
+
* when its value is null, we consider Google translate 'not active'.
|
|
318
|
+
*
|
|
319
|
+
* When Google Translate is turned off by the user (html[lang=auto]),
|
|
320
|
+
* `localize.locale` will be synced to html[lang] again
|
|
321
|
+
*
|
|
322
|
+
* Keep in mind that all of the above also works with other tools than Google Translate,
|
|
323
|
+
* but this is the most widely used tool and therefore used as an example.
|
|
324
|
+
* @protected
|
|
325
|
+
*/
|
|
326
|
+
_setupTranslationToolSupport() {
|
|
327
|
+
this.#localeSetByTranslationTool = documentElement.lang || null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @param {string} locale
|
|
332
|
+
* @protected
|
|
333
|
+
*/
|
|
334
|
+
_setHtmlLangAttribute(locale) {
|
|
335
|
+
this._teardownHtmlLangAttributeObserver();
|
|
336
|
+
documentElement.lang = locale;
|
|
337
|
+
this._setupHtmlLangAttributeObserver();
|
|
338
|
+
}
|
|
339
|
+
|
|
296
340
|
/** @protected */
|
|
297
341
|
_setupHtmlLangAttributeObserver() {
|
|
342
|
+
if (isServer) return;
|
|
343
|
+
|
|
298
344
|
if (!this._htmlLangAttributeObserver) {
|
|
299
345
|
this._htmlLangAttributeObserver = new MutationObserver(mutations => {
|
|
300
346
|
mutations.forEach(mutation => {
|
|
301
|
-
if (this
|
|
302
|
-
if (
|
|
347
|
+
if (this.#shouldHandleTranslationTools) {
|
|
348
|
+
if (documentElement.lang === 'auto') {
|
|
303
349
|
// Google Translate is switched off
|
|
304
|
-
this
|
|
350
|
+
this.#localeSetByTranslationTool = null;
|
|
305
351
|
this._setHtmlLangAttribute(this.locale);
|
|
306
352
|
} else {
|
|
307
|
-
this
|
|
353
|
+
this.#localeSetByTranslationTool = document.documentElement.lang;
|
|
308
354
|
}
|
|
309
355
|
} else {
|
|
310
356
|
this._onLocaleChanged(document.documentElement.lang, mutation.oldValue || '');
|
|
@@ -352,7 +398,7 @@ export class LocalizeManager {
|
|
|
352
398
|
* @param {NamespaceObject} namespaceObj
|
|
353
399
|
* @param {boolean} isDynamicImport
|
|
354
400
|
* @param {string} namespace
|
|
355
|
-
* @returns {Promise
|
|
401
|
+
* @returns {Promise<Object|void>}
|
|
356
402
|
* @protected
|
|
357
403
|
*/
|
|
358
404
|
_loadNamespaceData(locale, namespaceObj, isDynamicImport, namespace) {
|
|
@@ -388,7 +434,7 @@ export class LocalizeManager {
|
|
|
388
434
|
let loader = this.__namespaceLoadersCache[namespace];
|
|
389
435
|
if (!loader) {
|
|
390
436
|
if (isDynamicImport) {
|
|
391
|
-
const _namespaceObj = /** @type {Object
|
|
437
|
+
const _namespaceObj = /** @type {Object<string,function>} */ (namespaceObj);
|
|
392
438
|
loader = _namespaceObj[namespace];
|
|
393
439
|
this.__namespaceLoadersCache[namespace] = loader;
|
|
394
440
|
} else {
|
|
@@ -411,7 +457,7 @@ export class LocalizeManager {
|
|
|
411
457
|
* @param {string} locale
|
|
412
458
|
* @param {string} namespace
|
|
413
459
|
* @param {string} [fallbackLocale]
|
|
414
|
-
* @returns {Promise
|
|
460
|
+
* @returns {Promise<any>}
|
|
415
461
|
* @throws {Error} Data for namespace and (locale or fallback locale) could not be loaded.
|
|
416
462
|
* @protected
|
|
417
463
|
*/
|
|
@@ -441,7 +487,7 @@ export class LocalizeManager {
|
|
|
441
487
|
/**
|
|
442
488
|
* @param {string} locale
|
|
443
489
|
* @param {string} namespace
|
|
444
|
-
* @param {Promise
|
|
490
|
+
* @param {Promise<Object|void>} promise
|
|
445
491
|
* @protected
|
|
446
492
|
*/
|
|
447
493
|
_cacheNamespaceLoaderPromise(locale, namespace, promise) {
|
|
@@ -480,31 +526,6 @@ export class LocalizeManager {
|
|
|
480
526
|
return locale.substring(0, 2);
|
|
481
527
|
}
|
|
482
528
|
|
|
483
|
-
/**
|
|
484
|
-
* @param {string} type
|
|
485
|
-
* @param {EventListener} listener
|
|
486
|
-
* @param {...Object} options
|
|
487
|
-
*/
|
|
488
|
-
addEventListener(type, listener, ...options) {
|
|
489
|
-
this.__delegationTarget.addEventListener(type, listener, ...options);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* @param {string} type
|
|
494
|
-
* @param {EventListener} listener
|
|
495
|
-
* @param {...Object} options
|
|
496
|
-
*/
|
|
497
|
-
removeEventListener(type, listener, ...options) {
|
|
498
|
-
this.__delegationTarget.removeEventListener(type, listener, ...options);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* @param {CustomEvent} event
|
|
503
|
-
*/
|
|
504
|
-
dispatchEvent(event) {
|
|
505
|
-
this.__delegationTarget.dispatchEvent(event);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
529
|
/**
|
|
509
530
|
* @param {string} newLocale
|
|
510
531
|
* @param {string} oldLocale
|
|
@@ -514,9 +535,8 @@ export class LocalizeManager {
|
|
|
514
535
|
_onLocaleChanged(newLocale, oldLocale) {
|
|
515
536
|
// Event firing immediately, does not wait for loading the translations
|
|
516
537
|
this.dispatchEvent(new CustomEvent('__localeChanging'));
|
|
517
|
-
if (newLocale === oldLocale)
|
|
518
|
-
|
|
519
|
-
}
|
|
538
|
+
if (newLocale === oldLocale) return;
|
|
539
|
+
|
|
520
540
|
if (this._autoLoadOnLocaleChange) {
|
|
521
541
|
this._loadAllMissing(newLocale, oldLocale);
|
|
522
542
|
this.loadingComplete.then(() => {
|
|
@@ -588,7 +608,7 @@ export class LocalizeManager {
|
|
|
588
608
|
const names = namesString.split('.');
|
|
589
609
|
const result = names.reduce(
|
|
590
610
|
/**
|
|
591
|
-
* @param {Object
|
|
611
|
+
* @param {Object<string, any> | string} message
|
|
592
612
|
* @param {string} name
|
|
593
613
|
* @returns {string}
|
|
594
614
|
*/
|
|
@@ -600,16 +620,51 @@ export class LocalizeManager {
|
|
|
600
620
|
}
|
|
601
621
|
|
|
602
622
|
/**
|
|
603
|
-
* @param {
|
|
623
|
+
* @param {string} value
|
|
624
|
+
* @throws {Error} Language only locales are not allowed(Use 'en-GB' instead of 'en')
|
|
604
625
|
*/
|
|
605
|
-
|
|
606
|
-
|
|
626
|
+
// eslint-disable-next-line class-methods-use-this
|
|
627
|
+
#assertCorrectLocale(value) {
|
|
628
|
+
if (value.includes('-')) return;
|
|
629
|
+
|
|
630
|
+
throw new Error(`
|
|
631
|
+
Locale was set to ${value}.
|
|
632
|
+
Language only locales are not allowed, please use the full language locale e.g. 'en-GB' instead of 'en'.
|
|
633
|
+
See https://github.com/ing-bank/lion/issues/187 for more information.
|
|
634
|
+
`);
|
|
607
635
|
}
|
|
608
636
|
|
|
637
|
+
// === TODO: delete below in a next breaking release ---
|
|
638
|
+
|
|
609
639
|
/**
|
|
610
|
-
* @
|
|
640
|
+
* @deprecated
|
|
641
|
+
* @protected
|
|
611
642
|
*/
|
|
612
|
-
|
|
613
|
-
this
|
|
643
|
+
get _supportExternalTranslationTools() {
|
|
644
|
+
return this.#shouldHandleTranslationTools;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @deprecated
|
|
649
|
+
* @protected
|
|
650
|
+
*/
|
|
651
|
+
set _supportExternalTranslationTools(supportsThem) {
|
|
652
|
+
this.#shouldHandleTranslationTools = supportsThem;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* @deprecated
|
|
657
|
+
* @protected
|
|
658
|
+
*/
|
|
659
|
+
get _langAttrSetByTranslationTool() {
|
|
660
|
+
return this.#localeProvidedViaDataLangAttr;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* @deprecated
|
|
665
|
+
* @protected
|
|
666
|
+
*/
|
|
667
|
+
set _langAttrSetByTranslationTool(newValue) {
|
|
668
|
+
this.#localeProvidedViaDataLangAttr = newValue;
|
|
614
669
|
}
|
|
615
670
|
}
|
|
@@ -578,7 +578,7 @@ export class OverlayController extends EventTarget {
|
|
|
578
578
|
// The role="dialog" is set on the contentNode (or another role), so role="none"
|
|
579
579
|
// is valid here, although AXE complains about this setup.
|
|
580
580
|
// For now we need to add `ignoredRules: ['aria-allowed-role']` in your AXE tests.
|
|
581
|
-
// see: https://lion
|
|
581
|
+
// see: https://lion.js.org/fundamentals/systems/overlays/rationale/#considerations
|
|
582
582
|
wrappingDialogElement.setAttribute('role', 'none');
|
|
583
583
|
wrappingDialogElement.setAttribute('data-overlay-outer-wrapper', '');
|
|
584
584
|
// N.B. position: fixed is needed to escape out of 'overflow: hidden'
|
|
@@ -189,6 +189,13 @@ export const OverlayMixinImplementation = superclass =>
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
/**
|
|
193
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
194
|
+
* @configure ReactiveElement
|
|
195
|
+
*/
|
|
196
|
+
// @ts-expect-error
|
|
197
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
198
|
+
|
|
192
199
|
get _overlayInvokerNode() {
|
|
193
200
|
return /** @type {HTMLElement | undefined} */ (
|
|
194
201
|
Array.from(this.children).find(child => child.slot === 'invoker')
|
|
@@ -93,6 +93,12 @@ export class LionProgressIndicator extends LocalizeMixin(LitElement) {
|
|
|
93
93
|
return !this.hasAttribute('value');
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
98
|
+
* @configure ReactiveElement
|
|
99
|
+
*/
|
|
100
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
101
|
+
|
|
96
102
|
/**
|
|
97
103
|
* In case of a determinate progress-indicator it returns the progress percentage
|
|
98
104
|
* based on value, min & max.
|
|
@@ -115,4 +115,10 @@ export class LionStep extends LitElement {
|
|
|
115
115
|
const result = this.condition(data);
|
|
116
116
|
return this.invertCondition ? !result : result;
|
|
117
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
121
|
+
* @configure ReactiveElement
|
|
122
|
+
*/
|
|
123
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
118
124
|
}
|
|
@@ -108,6 +108,12 @@ export class LionSteps extends LitElement {
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
113
|
+
* @configure ReactiveElement
|
|
114
|
+
*/
|
|
115
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
116
|
+
|
|
111
117
|
/**
|
|
112
118
|
* @param {number} newCurrent
|
|
113
119
|
* @param {number} oldCurrent
|
|
@@ -188,6 +188,12 @@ export class LionTabs extends LitElement {
|
|
|
188
188
|
);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
193
|
+
* @configure ReactiveElement
|
|
194
|
+
*/
|
|
195
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
196
|
+
|
|
191
197
|
/** @private */
|
|
192
198
|
__setupSlots() {
|
|
193
199
|
if (this.shadowRoot) {
|