@lion/ui 0.8.1 → 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/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-core/src/FormControlMixin.js +6 -0
- 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/icon/src/LionIcon.js +6 -0
- package/components/localize/src/LocalizeManager.js +258 -178
- 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 +685 -159
- 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-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/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 +108 -93
- 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/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 +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/api-table.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/api-table.md +1 -1
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/api-table.md +1 -1
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/api-table.md +1 -1
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-file/api-table.md +1 -1
- package/docs/components/input-file/overview.md +1 -1
- package/docs/components/input-iban/api-table.md +1 -1
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/api-table.md +1 -1
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/api-table.md +1 -1
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/api-table.md +1 -1
- 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 +1 -1
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/use-cases.md +1 -1
- package/docs/components/radio-group/api-table.md +1 -1
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select/api-table.md +1 -1
- 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 +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/components/textarea/api-table.md +1 -1
- 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/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 -37
- 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
26
|
export class LocalizeManager extends EventTarget {
|
|
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 = {};
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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 extends EventTarget {
|
|
|
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) {
|
|
@@ -489,9 +535,8 @@ export class LocalizeManager extends EventTarget {
|
|
|
489
535
|
_onLocaleChanged(newLocale, oldLocale) {
|
|
490
536
|
// Event firing immediately, does not wait for loading the translations
|
|
491
537
|
this.dispatchEvent(new CustomEvent('__localeChanging'));
|
|
492
|
-
if (newLocale === oldLocale)
|
|
493
|
-
|
|
494
|
-
}
|
|
538
|
+
if (newLocale === oldLocale) return;
|
|
539
|
+
|
|
495
540
|
if (this._autoLoadOnLocaleChange) {
|
|
496
541
|
this._loadAllMissing(newLocale, oldLocale);
|
|
497
542
|
this.loadingComplete.then(() => {
|
|
@@ -563,7 +608,7 @@ export class LocalizeManager extends EventTarget {
|
|
|
563
608
|
const names = namesString.split('.');
|
|
564
609
|
const result = names.reduce(
|
|
565
610
|
/**
|
|
566
|
-
* @param {Object
|
|
611
|
+
* @param {Object<string, any> | string} message
|
|
567
612
|
* @param {string} name
|
|
568
613
|
* @returns {string}
|
|
569
614
|
*/
|
|
@@ -575,16 +620,51 @@ export class LocalizeManager extends EventTarget {
|
|
|
575
620
|
}
|
|
576
621
|
|
|
577
622
|
/**
|
|
578
|
-
* @param {
|
|
623
|
+
* @param {string} value
|
|
624
|
+
* @throws {Error} Language only locales are not allowed(Use 'en-GB' instead of 'en')
|
|
579
625
|
*/
|
|
580
|
-
|
|
581
|
-
|
|
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
|
+
`);
|
|
582
635
|
}
|
|
583
636
|
|
|
637
|
+
// === TODO: delete below in a next breaking release ---
|
|
638
|
+
|
|
584
639
|
/**
|
|
585
|
-
* @
|
|
640
|
+
* @deprecated
|
|
641
|
+
* @protected
|
|
586
642
|
*/
|
|
587
|
-
|
|
588
|
-
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;
|
|
589
669
|
}
|
|
590
670
|
}
|
|
@@ -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) {
|
|
@@ -55,6 +55,12 @@ export class LionTooltip extends ArrowMixin(OverlayMixin(LitElement)) {
|
|
|
55
55
|
this.invokerRelation = 'description';
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* // TODO: check if this is a false positive or if we can improve
|
|
60
|
+
* @configure ReactiveElement
|
|
61
|
+
*/
|
|
62
|
+
static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
|
|
63
|
+
|
|
58
64
|
/** @protected */
|
|
59
65
|
// eslint-disable-next-line class-methods-use-this
|
|
60
66
|
_defineOverlayConfig() {
|