@ornery/web-components 1.1.8 → 4.0.0
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/.github/workflows/publish.yml +25 -0
- package/esbuild.js +2 -0
- package/html.d.ts +7 -0
- package/index.js +7 -17
- package/jestLoader.js +5 -3
- package/loader.js +1 -2
- package/package.json +26 -18
- package/rollup.js +2 -0
- package/rspack.js +2 -0
- package/src/bind-events.js +2 -2
- package/src/context-binding.js +1 -1
- package/src/data-manager.js +51 -52
- package/src/event-map.js +1 -1
- package/src/i18n.js +87 -187
- package/src/index.js +5 -7
- package/src/loaders/attrs-parser.js +2 -2
- package/src/loaders/html-loader.js +107 -131
- package/src/plugin.js +14 -0
- package/src/setup-connect.js +1 -1
- package/src/utils.js +46 -36
- package/templates.js +2 -7
- package/tests/fixtures/list.html +10 -0
- package/tests/fixtures/list.scss +12 -0
- package/tests/loader.smoke.test.mjs +127 -0
- package/vite.js +2 -0
- package/webpack.js +2 -0
- package/src/loaders/rules.js +0 -17
package/src/i18n.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const withContext = require('./context-binding');
|
|
1
|
+
import DataManager from './data-manager.js';
|
|
2
|
+
import {template, getFromObj, toLowerMap} from './utils.js';
|
|
4
3
|
|
|
5
|
-
if (typeof HTMLElement === 'undefined') {
|
|
6
|
-
|
|
7
|
-
HTMLElement = class {};
|
|
4
|
+
if (typeof globalThis.HTMLElement === 'undefined') {
|
|
5
|
+
globalThis.HTMLElement = class {};
|
|
8
6
|
}
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
*
|
|
12
10
|
* @class I18n
|
|
13
11
|
* @description Import strings here and call I18n.addStrings() with the supported locale identifier
|
|
14
|
-
* and the strings object exported from the
|
|
12
|
+
* and the strings object exported from the locale file
|
|
15
13
|
* By default, it will set the values on window.i18n, if defined when loaded, as the starting messages.
|
|
16
14
|
* This is useful if you wish to server-side render HTML certain content before laoding scripts on the client.
|
|
17
15
|
* @example
|
|
@@ -37,84 +35,93 @@ if (typeof HTMLElement === 'undefined') {
|
|
|
37
35
|
* console.log(I18n.getMessages()) // will log the window.i18n object
|
|
38
36
|
*
|
|
39
37
|
*/
|
|
40
|
-
|
|
41
|
-
constructor() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
setDefaultLang(lang = 'en') {
|
|
66
|
-
this._defaultLang = lang.toLowerCase();
|
|
67
|
-
this._fallbackMessages = this.getMessages(this._defaultLang);
|
|
38
|
+
class I18n {
|
|
39
|
+
constructor(options) {
|
|
40
|
+
const {
|
|
41
|
+
store = new DataManager(),
|
|
42
|
+
messages = null,
|
|
43
|
+
locale = null,
|
|
44
|
+
fallbackLocale = {
|
|
45
|
+
'default': 'en',
|
|
46
|
+
'de-ch': ['fr', 'it'],
|
|
47
|
+
'zh-hant': ['zh-hans'],
|
|
48
|
+
'es-cl': ['es-ar'],
|
|
49
|
+
'es': ['en'],
|
|
50
|
+
'pt': ['es-ar'],
|
|
51
|
+
},
|
|
52
|
+
} = options;
|
|
53
|
+
this.store = store;
|
|
54
|
+
this.setFallbackLocale(fallbackLocale);
|
|
55
|
+
if (locale) this.setLocale(locale);
|
|
56
|
+
if (messages) this.setMessages(messages);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setFallbackLocale(fallbackLocales) {
|
|
60
|
+
this._fallbackLocale = toLowerMap(fallbackLocales);
|
|
68
61
|
}
|
|
69
62
|
/**
|
|
70
63
|
* @memberof I18n
|
|
71
|
-
* @return {String}
|
|
72
|
-
* @description returns the current
|
|
64
|
+
* @return {String} locale
|
|
65
|
+
* @description returns the current locale. defaults to the browser's navigator.locale value.
|
|
73
66
|
* @example
|
|
74
67
|
*
|
|
75
|
-
* navigator.
|
|
68
|
+
* navigator.locale = 'en-US';
|
|
76
69
|
* import { I18n } from '@ornery/web-components';
|
|
77
70
|
*
|
|
78
|
-
* console.log(I18n.
|
|
71
|
+
* console.log(I18n.getLocale()) // "en-US"
|
|
79
72
|
*/
|
|
80
|
-
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
getLocale() {
|
|
74
|
+
return this.store.get('i18n-locale') || '';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getFallbackLocale() {
|
|
78
|
+
const locale = this.getLocale();
|
|
79
|
+
const defaultLocale = this._fallbackLocale.default;
|
|
80
|
+
const fallbackMap = this._fallbackLocale[locale];
|
|
81
|
+
let fallbackLocale;
|
|
82
|
+
if (fallbackMap) {
|
|
83
|
+
const allMessages = this.store.get('i18n-messages') || {};
|
|
84
|
+
for (let i = 0; i < fallbackMap.length; i++) {
|
|
85
|
+
const fbl = fallbackMap[i];
|
|
86
|
+
if (allMessages[fbl]) {
|
|
87
|
+
fallbackLocale = fbl;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return fallbackLocale || defaultLocale || 'en';
|
|
85
93
|
}
|
|
86
94
|
/**
|
|
87
95
|
* @memberof I18n
|
|
88
|
-
* @param {String}
|
|
89
|
-
* @return {String}
|
|
90
|
-
* @description sets the current i18n
|
|
96
|
+
* @param {String} locale
|
|
97
|
+
* @return {String} locale
|
|
98
|
+
* @description sets the current i18n locale. This does not change the browser locale.
|
|
91
99
|
* @example
|
|
92
100
|
*
|
|
93
101
|
* import { I18n } from '@ornery/web-components';
|
|
94
102
|
*
|
|
95
|
-
* I18n.
|
|
96
|
-
* console.log(I18n.
|
|
103
|
+
* I18n.setLocale('en-US')
|
|
104
|
+
* console.log(I18n.getLocale()) //'en-US'
|
|
97
105
|
*/
|
|
98
|
-
|
|
99
|
-
return
|
|
106
|
+
setLocale(locale = '') {
|
|
107
|
+
return this.store.set('i18n-locale', locale);
|
|
100
108
|
}
|
|
101
109
|
/**
|
|
102
110
|
* @memberof I18n
|
|
103
|
-
* @param {String}
|
|
104
|
-
* @return {String}
|
|
111
|
+
* @param {String} locale
|
|
112
|
+
* @return {String} locale
|
|
105
113
|
* @description returns the current i18n messages set in the DataManager
|
|
106
114
|
*/
|
|
107
|
-
getMessages(
|
|
108
|
-
const allMessages =
|
|
109
|
-
if (
|
|
115
|
+
getMessages(locale = null) {
|
|
116
|
+
const allMessages = this.store.get('i18n-messages') || {};
|
|
117
|
+
if (locale === 'all') {
|
|
110
118
|
return allMessages;
|
|
111
119
|
} else {
|
|
112
|
-
|
|
113
|
-
const
|
|
120
|
+
locale = locale || this.getLocale();
|
|
121
|
+
const fallbackLocale = this.getFallbackLocale();
|
|
114
122
|
return {
|
|
115
|
-
...
|
|
116
|
-
...allMessages[
|
|
117
|
-
...allMessages[lang],
|
|
123
|
+
...allMessages[fallbackLocale] || {},
|
|
124
|
+
...allMessages[locale] || {},
|
|
118
125
|
};
|
|
119
126
|
}
|
|
120
127
|
}
|
|
@@ -136,15 +143,14 @@ const I18n = new (class {
|
|
|
136
143
|
* })
|
|
137
144
|
*/
|
|
138
145
|
setMessages(values) {
|
|
139
|
-
const response =
|
|
140
|
-
this.setFallbackMessages();
|
|
146
|
+
const response = this.store.set('i18n-messages', values);
|
|
141
147
|
return response;
|
|
142
148
|
}
|
|
143
149
|
/**
|
|
144
150
|
* @memberof I18n
|
|
145
|
-
* @param {{String}|{Object}}
|
|
151
|
+
* @param {{String}|{Object}} locale
|
|
146
152
|
* @param {Object} newStrings
|
|
147
|
-
* @description add more strings to the existing
|
|
153
|
+
* @description add more strings to the existing locale set.
|
|
148
154
|
*
|
|
149
155
|
* @example
|
|
150
156
|
*
|
|
@@ -154,39 +160,30 @@ const I18n = new (class {
|
|
|
154
160
|
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
155
161
|
* });
|
|
156
162
|
*/
|
|
157
|
-
addMessages(
|
|
158
|
-
if (typeof
|
|
159
|
-
newStrings =
|
|
160
|
-
|
|
163
|
+
addMessages(locale, newStrings) {
|
|
164
|
+
if (typeof locale !== 'string') {
|
|
165
|
+
newStrings = locale;
|
|
166
|
+
locale = this.getLocale();
|
|
161
167
|
}
|
|
162
|
-
|
|
163
|
-
const
|
|
168
|
+
locale = locale.toLowerCase();
|
|
169
|
+
const fallbackLocale = this.getFallbackLocale();
|
|
164
170
|
const existing = this.getMessages('all');
|
|
165
|
-
existing[
|
|
166
|
-
...(existing[
|
|
171
|
+
existing[locale] = {
|
|
172
|
+
...(existing[locale] || {}),
|
|
167
173
|
...newStrings,
|
|
168
174
|
};
|
|
169
|
-
if (
|
|
170
|
-
existing[
|
|
171
|
-
...(existing[
|
|
175
|
+
if (fallbackLocale !== locale) {
|
|
176
|
+
existing[fallbackLocale] = {
|
|
177
|
+
...(existing[fallbackLocale] || {}),
|
|
172
178
|
...newStrings,
|
|
173
179
|
};
|
|
174
180
|
}
|
|
175
181
|
this.setMessages(existing);
|
|
176
|
-
this.setFallbackMessages();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
setFallbackMessages(){
|
|
180
|
-
const rootLang = this.getRootLang(this._defaultLang);
|
|
181
|
-
this._fallbackMessages = {
|
|
182
|
-
...this.getMessages(this._defaultLang),
|
|
183
|
-
...this.getMessages(rootLang)
|
|
184
|
-
};
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
/**
|
|
188
185
|
* @memberof I18n
|
|
189
|
-
* @param {String} key they key of the string to retrieve from the current
|
|
186
|
+
* @param {String} key they key of the string to retrieve from the current locale set.
|
|
190
187
|
* @param {Object} data Optional, The data to process tokens in the string with.
|
|
191
188
|
* @return {String} Returns the value for the key. Processed if a data context is provided as the second argument.
|
|
192
189
|
* @description Returns the value for the key. If a context is provided as the second argument for tokens,
|
|
@@ -206,7 +203,6 @@ const I18n = new (class {
|
|
|
206
203
|
*/
|
|
207
204
|
get(key, data = {}) {
|
|
208
205
|
const context = {
|
|
209
|
-
...this._fallbackMessages,
|
|
210
206
|
...this.getMessages(),
|
|
211
207
|
...data,
|
|
212
208
|
};
|
|
@@ -217,7 +213,7 @@ const I18n = new (class {
|
|
|
217
213
|
* @memberof I18n
|
|
218
214
|
* @param {String} namespace
|
|
219
215
|
* @param {String} context
|
|
220
|
-
* @return {Object} Returns all the messages for the given
|
|
216
|
+
* @return {Object} Returns all the messages for the given locale. Filtered to namespace if provided.
|
|
221
217
|
* @description If a namespace is provided, returns all the key value pairs for that
|
|
222
218
|
* namespace without the namespace in the keys.
|
|
223
219
|
*
|
|
@@ -243,106 +239,10 @@ const I18n = new (class {
|
|
|
243
239
|
return this.getMessages('all');
|
|
244
240
|
}
|
|
245
241
|
}
|
|
246
|
-
})();
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* @class I18nMessage
|
|
250
|
-
* @description <i18n-message> HTML element. Provides tranlsation and interpolation for
|
|
251
|
-
* translatable strings
|
|
252
|
-
* @param {String} key the key for the strings based on current language. can be set as the innerHTML or
|
|
253
|
-
* defined as the attibutes: key, id, data-key, data-id
|
|
254
|
-
* @param {JSON} values can be passed as data-* attributes or as a json-parseable object string as "data-values"
|
|
255
|
-
* @param {String} dataAttributes
|
|
256
|
-
* @example <caption>Given the following configuration</caption>
|
|
257
|
-
* import { I18n } from '@ornery/web-components';
|
|
258
|
-
* I18n.addMessages('en-US', {
|
|
259
|
-
* 'translatable.message.name': "I'm a translated string from i18n",
|
|
260
|
-
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
261
|
-
* });
|
|
262
|
-
* @example @lang html <caption>With the following usage</caption>
|
|
263
|
-
* <i18n-message>translatable.message.name</i18n-message>
|
|
264
|
-
* <div>
|
|
265
|
-
* <i18n-message data-values="{'color: 'grey', 'animal': 'monkey'}">tokenized.message</i18n-message>
|
|
266
|
-
* <i18n-message data-color="grey" data-animal="monkey">tokenized.message</i18n-message>
|
|
267
|
-
* <i18n-message key="tokenized.message"/>
|
|
268
|
-
* <!-- React does not pass key or ref props so you can use "data-key" or "data-id" as well-->
|
|
269
|
-
* <i18n-message data-key="tokenized.message"/>
|
|
270
|
-
* <i18n-message id="translatable.message.name"/>
|
|
271
|
-
* <i18n-message data-id="translatable.message.name"/>
|
|
272
|
-
* </div>
|
|
273
|
-
*
|
|
274
|
-
* @example @lang html <caption>Renders the HTML</caption>
|
|
275
|
-
* <i18n-message>I'm a translated string from i18n</i18n-message>
|
|
276
|
-
* <i18n-message>I have a grey monkey</i18n-message>
|
|
277
|
-
*/
|
|
278
|
-
class I18nMessage extends HTMLElement {
|
|
279
|
-
constructor() {
|
|
280
|
-
super();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
static get observedAttributes() {
|
|
284
|
-
return ['key', 'id', 'data-values'];
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
get useShadow() {
|
|
288
|
-
if (this.hasAttribute('shadow')) {
|
|
289
|
-
const current = this.getAttribute('shadow');
|
|
290
|
-
if (current === 'false') {
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
get translate() {
|
|
298
|
-
return this.getAttribute('key') || this.getAttribute('id');
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
attributeChangedCallback(name) {
|
|
302
|
-
this.update();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
update() {
|
|
306
|
-
const root = this.shadowRoot || this;
|
|
307
|
-
const context = {...this.getAttribute('data-values'), ...this.dataset};
|
|
308
|
-
let newMesage = I18n.get(this.translate, context);
|
|
309
|
-
if (shouldEncode(newMesage)) {
|
|
310
|
-
newMesage = encodeHTML(newMesage);
|
|
311
|
-
}
|
|
312
|
-
if (!root.innerHTML) {
|
|
313
|
-
root.innerHTML = newMesage;
|
|
314
|
-
} else if (newMesage !== this.translate || newMesage !== root.innerHTML) {
|
|
315
|
-
root.innerHTML = newMesage;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
242
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
this._i18nListener = DataManager.subscribe((newVals) => {
|
|
322
|
-
this.update();
|
|
323
|
-
});
|
|
324
|
-
const attrObserver = new MutationObserver(() => this.update());
|
|
325
|
-
attrObserver.observe(this, {attributes: true, childList: this.useShadow});
|
|
243
|
+
subscribe(callback) {
|
|
244
|
+
return this.store.subscribe(callback);
|
|
326
245
|
}
|
|
327
|
-
|
|
328
|
-
disconnectedCallback() {
|
|
329
|
-
if (this._i18nListener) {
|
|
330
|
-
this._i18nListener.destroy();
|
|
331
|
-
this._i18nListener = null;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (
|
|
337
|
-
typeof window !== 'undefined' &&
|
|
338
|
-
typeof customElements !== 'undefined' &&
|
|
339
|
-
!customElements.get('i18n-message')
|
|
340
|
-
) {
|
|
341
|
-
window.I18n = I18n;
|
|
342
|
-
customElements.define('i18n-message', withContext(I18nMessage));
|
|
343
246
|
}
|
|
344
247
|
|
|
345
|
-
|
|
346
|
-
I18n,
|
|
347
|
-
I18nMessage,
|
|
348
|
-
};
|
|
248
|
+
export { I18n };
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import ContextBinding from './context-binding';
|
|
2
|
-
import DataManager from './data-manager';
|
|
3
|
-
import EventMap from './event-map';
|
|
4
|
-
|
|
5
|
-
export * from './
|
|
1
|
+
import ContextBinding from './context-binding.js';
|
|
2
|
+
import DataManager from './data-manager.js';
|
|
3
|
+
import EventMap from './event-map.js';
|
|
4
|
+
export * from './utils.js';
|
|
5
|
+
export * from './i18n.js';
|
|
6
6
|
|
|
7
7
|
export {
|
|
8
8
|
ContextBinding,
|
|
9
9
|
DataManager,
|
|
10
10
|
EventMap,
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
export default HTMLLoader;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import Parser from 'fastparse';
|
|
2
2
|
|
|
3
3
|
const attrsParser = new Parser({
|
|
4
4
|
outside: {
|
|
@@ -41,7 +41,7 @@ const attrsParser = new Parser({
|
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
export default (html, tagAttr) => {
|
|
45
45
|
return attrsParser.parse('outside', html, {
|
|
46
46
|
currentTag: null,
|
|
47
47
|
results: [],
|