@ornery/web-components 1.1.4 → 1.1.8
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/package.json +1 -1
- package/src/i18n.js +257 -240
- package/src/utils.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ornery/web-components",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "WebComponents html loader and optional runtime mixins to enable creation of custom HTML elements using es6 template literal syntax in *.html files.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
package/src/i18n.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
const DataManager = require(
|
|
2
|
-
const {
|
|
3
|
-
const withContext = require(
|
|
1
|
+
const DataManager = require('./data-manager');
|
|
2
|
+
const {template, getFromObj, shouldEncode, encodeHTML} = require('./utils');
|
|
3
|
+
const withContext = require('./context-binding');
|
|
4
4
|
|
|
5
|
-
if (typeof HTMLElement ===
|
|
6
|
-
|
|
5
|
+
if (typeof HTMLElement === 'undefined') {
|
|
6
|
+
// eslint-disable-next-line no-global-assign
|
|
7
|
+
HTMLElement = class {};
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -37,200 +38,211 @@ if (typeof HTMLElement === "undefined") {
|
|
|
37
38
|
*
|
|
38
39
|
*/
|
|
39
40
|
const I18n = new (class {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
41
|
+
constructor() {
|
|
42
|
+
// language without region code;
|
|
43
|
+
this._altLangRegex = /[_-]/i;
|
|
44
|
+
this.setDefaultLang();
|
|
45
|
+
this.setLang();
|
|
46
|
+
if (typeof window !== 'undefined') {
|
|
47
|
+
if (typeof navigator !== 'undefined') {
|
|
48
|
+
this.setLang(navigator.language);
|
|
49
|
+
}
|
|
50
|
+
this.setMessages(window.i18n || {});
|
|
51
|
+
} else {
|
|
52
|
+
if (typeof process !== 'undefined') {
|
|
53
|
+
const {env} = process;
|
|
54
|
+
this.setLang(
|
|
55
|
+
env.LANG ||
|
|
56
|
+
env.LANGUAGE ||
|
|
57
|
+
env.LC_ALL ||
|
|
58
|
+
env.LC_MESSAGES ||
|
|
59
|
+
this._defaultLang,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
62
|
}
|
|
63
|
+
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
setDefaultLang(lang = 'en') {
|
|
66
|
+
this._defaultLang = lang.toLowerCase();
|
|
67
|
+
this._fallbackMessages = this.getMessages(this._defaultLang);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* @memberof I18n
|
|
71
|
+
* @return {String} lang
|
|
72
|
+
* @description returns the current language. defaults to the browser's navigator.language value.
|
|
73
|
+
* @example
|
|
74
|
+
*
|
|
75
|
+
* navigator.language = 'en-US';
|
|
76
|
+
* import { I18n } from '@ornery/web-components';
|
|
77
|
+
*
|
|
78
|
+
* console.log(I18n.getLang()) // "en-US"
|
|
79
|
+
*/
|
|
80
|
+
getLang() {
|
|
81
|
+
return DataManager.get('i18n-language') || '';
|
|
82
|
+
}
|
|
83
|
+
getRootLang(lang) {
|
|
84
|
+
return (lang || this.getLang()).split(this._altLangRegex)[0];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* @memberof I18n
|
|
88
|
+
* @param {String} lang
|
|
89
|
+
* @return {String} lang
|
|
90
|
+
* @description sets the current i18n language. This does not change the browser language.
|
|
91
|
+
* @example
|
|
92
|
+
*
|
|
93
|
+
* import { I18n } from '@ornery/web-components';
|
|
94
|
+
*
|
|
95
|
+
* I18n.setLang('en-US')
|
|
96
|
+
* console.log(I18n.getLang()) //'en-US'
|
|
97
|
+
*/
|
|
98
|
+
setLang(lang = '') {
|
|
99
|
+
return DataManager.set('i18n-language', lang);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* @memberof I18n
|
|
103
|
+
* @param {String} lang
|
|
104
|
+
* @return {String} lang
|
|
105
|
+
* @description returns the current i18n messages set in the DataManager
|
|
106
|
+
*/
|
|
107
|
+
getMessages(lang) {
|
|
108
|
+
const allMessages = DataManager.get('i18n-messages') || {};
|
|
109
|
+
if (lang === 'all') {
|
|
110
|
+
return allMessages;
|
|
111
|
+
} else {
|
|
112
|
+
lang = lang || this.getLang();
|
|
113
|
+
const rootLang = this.getRootLang(lang);
|
|
114
|
+
return {
|
|
115
|
+
...this._fallbackMessages,
|
|
116
|
+
...allMessages[rootLang],
|
|
117
|
+
...allMessages[lang],
|
|
118
|
+
};
|
|
84
119
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @memberof I18n
|
|
123
|
+
* @param {Object} values
|
|
124
|
+
* @return {{state}|*}
|
|
125
|
+
* @description sets the strings as a whole. This overrides all existing strings.
|
|
126
|
+
* Use addMessages to add more strings to the existing set.
|
|
127
|
+
* @example
|
|
128
|
+
*
|
|
129
|
+
* import { I18n } from '@ornery/web-components';
|
|
130
|
+
*
|
|
131
|
+
* I18n.setMessages({
|
|
132
|
+
* 'en-US': {
|
|
133
|
+
* 'translatable.message.name': "I'm a translated string from i18n",
|
|
134
|
+
* 'tokenized.message': "I have a ${this.color} ${this.animal}"
|
|
135
|
+
* }
|
|
136
|
+
* })
|
|
137
|
+
*/
|
|
138
|
+
setMessages(values) {
|
|
139
|
+
const response = DataManager.set('i18n-messages', values);
|
|
140
|
+
this.setFallbackMessages();
|
|
141
|
+
return response;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* @memberof I18n
|
|
145
|
+
* @param {{String}|{Object}} lang
|
|
146
|
+
* @param {Object} newStrings
|
|
147
|
+
* @description add more strings to the existing language set.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
*
|
|
151
|
+
* import { I18n } from '@ornery/web-components';
|
|
152
|
+
* I18n.addMessages('en-US', {
|
|
153
|
+
* 'translatable.message.name': "I'm a translated string from i18n",
|
|
154
|
+
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
155
|
+
* });
|
|
156
|
+
*/
|
|
157
|
+
addMessages(lang, newStrings) {
|
|
158
|
+
if (typeof lang !== 'string') {
|
|
159
|
+
newStrings = lang;
|
|
160
|
+
lang = this.getLang();
|
|
118
161
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
* 'tokenized.message': "I have a ${this.color} ${this.animal}"
|
|
132
|
-
* }
|
|
133
|
-
* })
|
|
134
|
-
*/
|
|
135
|
-
setMessages(values) {
|
|
136
|
-
return DataManager.set("i18n-messages", values);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* @memberof I18n
|
|
140
|
-
* @param {String} lang
|
|
141
|
-
* @param {Object} strings
|
|
142
|
-
* @description add more strings to the existing language set.
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
*
|
|
146
|
-
* import { I18n } from '@ornery/web-components';
|
|
147
|
-
* I18n.addMessages('en-US', {
|
|
148
|
-
* 'translatable.message.name': "I'm a translated string from i18n",
|
|
149
|
-
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
150
|
-
* });
|
|
151
|
-
*/
|
|
152
|
-
addMessages(lang, newStrings) {
|
|
153
|
-
if (typeof lang !== "string") {
|
|
154
|
-
newStrings = lang;
|
|
155
|
-
lang = this.getLang();
|
|
156
|
-
}
|
|
157
|
-
lang = lang.toLowerCase();
|
|
158
|
-
const rootLang = lang.split(this._altLangRegex)[0];
|
|
159
|
-
const existing = this.getMessages("all");
|
|
160
|
-
existing[rootLang] = {
|
|
161
|
-
...(existing[rootLang] || {}),
|
|
162
|
-
...newStrings,
|
|
163
|
-
};
|
|
164
|
-
existing[lang] = {
|
|
165
|
-
...(existing[lang] || {}),
|
|
166
|
-
...newStrings,
|
|
167
|
-
};
|
|
168
|
-
this.setMessages(existing);
|
|
169
|
-
if (lang === this._defaultLang) {
|
|
170
|
-
this._fallbackMessages = this.getMessages(lang);
|
|
171
|
-
} else if (rootLang === this._defaultLang) {
|
|
172
|
-
this._fallbackMessages = this.getMessages(rootLang);
|
|
173
|
-
}
|
|
162
|
+
lang = lang.toLowerCase();
|
|
163
|
+
const rootLang = this.getRootLang(lang);
|
|
164
|
+
const existing = this.getMessages('all');
|
|
165
|
+
existing[lang] = {
|
|
166
|
+
...(existing[lang] || {}),
|
|
167
|
+
...newStrings,
|
|
168
|
+
};
|
|
169
|
+
if (rootLang !== lang) {
|
|
170
|
+
existing[rootLang] = {
|
|
171
|
+
...(existing[rootLang] || {}),
|
|
172
|
+
...newStrings,
|
|
173
|
+
};
|
|
174
174
|
}
|
|
175
|
+
this.setMessages(existing);
|
|
176
|
+
this.setFallbackMessages();
|
|
177
|
+
}
|
|
175
178
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
* @example
|
|
184
|
-
*
|
|
185
|
-
* import { I18n } from '@ornery/web-components';
|
|
186
|
-
* I18n.addMessages('en-US', {
|
|
187
|
-
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
188
|
-
* });
|
|
189
|
-
*
|
|
190
|
-
* const stringTestData = {
|
|
191
|
-
* color: "grey",
|
|
192
|
-
* animal: "monkey"
|
|
193
|
-
* };
|
|
194
|
-
* console.log(I18n.get('tokenized.message', stringTestData)) // "I have a grey monkey"
|
|
195
|
-
*/
|
|
196
|
-
get(key, data = {}) {
|
|
197
|
-
const context = {
|
|
198
|
-
...this._fallbackMessages,
|
|
199
|
-
...this.getMessages(),
|
|
200
|
-
...data,
|
|
201
|
-
};
|
|
202
|
-
return template(getFromObj(key, context), context);
|
|
203
|
-
}
|
|
179
|
+
setFallbackMessages(){
|
|
180
|
+
const rootLang = this.getRootLang(this._defaultLang);
|
|
181
|
+
this._fallbackMessages = {
|
|
182
|
+
...this.getMessages(this._defaultLang),
|
|
183
|
+
...this.getMessages(rootLang)
|
|
184
|
+
};
|
|
185
|
+
}
|
|
204
186
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
187
|
+
/**
|
|
188
|
+
* @memberof I18n
|
|
189
|
+
* @param {String} key they key of the string to retrieve from the current language set.
|
|
190
|
+
* @param {Object} data Optional, The data to process tokens in the string with.
|
|
191
|
+
* @return {String} Returns the value for the key. Processed if a data context is provided as the second argument.
|
|
192
|
+
* @description Returns the value for the key. If a context is provided as the second argument for tokens,
|
|
193
|
+
* the tokens will be replaced in the returned string.
|
|
194
|
+
* @example
|
|
195
|
+
*
|
|
196
|
+
* import { I18n } from '@ornery/web-components';
|
|
197
|
+
* I18n.addMessages('en-US', {
|
|
198
|
+
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
199
|
+
* });
|
|
200
|
+
*
|
|
201
|
+
* const stringTestData = {
|
|
202
|
+
* color: "grey",
|
|
203
|
+
* animal: "monkey"
|
|
204
|
+
* };
|
|
205
|
+
* console.log(I18n.get('tokenized.message', stringTestData)) // "I have a grey monkey"
|
|
206
|
+
*/
|
|
207
|
+
get(key, data = {}) {
|
|
208
|
+
const context = {
|
|
209
|
+
...this._fallbackMessages,
|
|
210
|
+
...this.getMessages(),
|
|
211
|
+
...data,
|
|
212
|
+
};
|
|
213
|
+
return template(getFromObj(key, context), context);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @memberof I18n
|
|
218
|
+
* @param {String} namespace
|
|
219
|
+
* @param {String} context
|
|
220
|
+
* @return {Object} Returns all the messages for the given language. Filtered to namespace if provided.
|
|
221
|
+
* @description If a namespace is provided, returns all the key value pairs for that
|
|
222
|
+
* namespace without the namespace in the keys.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
*
|
|
226
|
+
* import { I18n } from '@ornery/web-components';
|
|
227
|
+
* I18n.addMessages('en-US', {
|
|
228
|
+
* 'translatable.message.name': "I'm a translated string from i18n",
|
|
229
|
+
* 'tokenized.message': "I have a ${color} ${animal}"
|
|
230
|
+
* });
|
|
231
|
+
*
|
|
232
|
+
* console.log(I18n.getAll('tokenized', {color: "red", animal: "panda"})) // {"message": "I have a red panda"}
|
|
233
|
+
*/
|
|
234
|
+
getAll(namespace, context) {
|
|
235
|
+
if (namespace) {
|
|
236
|
+
return Object.keys(this.getMessages()).reduce((reducer, key) => {
|
|
237
|
+
if (key.startsWith(namespace)) {
|
|
238
|
+
reducer[key.replace(namespace + '.', '')] = this.get(key, context);
|
|
232
239
|
}
|
|
240
|
+
return reducer;
|
|
241
|
+
}, {});
|
|
242
|
+
} else {
|
|
243
|
+
return this.getMessages('all');
|
|
233
244
|
}
|
|
245
|
+
}
|
|
234
246
|
})();
|
|
235
247
|
|
|
236
248
|
/**
|
|
@@ -263,69 +275,74 @@ const I18n = new (class {
|
|
|
263
275
|
* <i18n-message>I'm a translated string from i18n</i18n-message>
|
|
264
276
|
* <i18n-message>I have a grey monkey</i18n-message>
|
|
265
277
|
*/
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
278
|
+
class I18nMessage extends HTMLElement {
|
|
279
|
+
constructor() {
|
|
280
|
+
super();
|
|
281
|
+
}
|
|
270
282
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
283
|
+
static get observedAttributes() {
|
|
284
|
+
return ['key', 'id', 'data-values'];
|
|
285
|
+
}
|
|
274
286
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
return true;
|
|
287
|
+
get useShadow() {
|
|
288
|
+
if (this.hasAttribute('shadow')) {
|
|
289
|
+
const current = this.getAttribute('shadow');
|
|
290
|
+
if (current === 'false') {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
283
293
|
}
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
284
296
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
297
|
+
get translate() {
|
|
298
|
+
return this.getAttribute('key') || this.getAttribute('id');
|
|
299
|
+
}
|
|
288
300
|
|
|
289
|
-
|
|
290
|
-
|
|
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);
|
|
291
311
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
let newMesage = I18n.get(this.translate, context);
|
|
297
|
-
if (shouldEncode(newMesage)) {
|
|
298
|
-
newMesage = encodeHTML(newMesage);
|
|
299
|
-
}
|
|
300
|
-
if (!root.innerHTML) {
|
|
301
|
-
root.innerHTML = newMesage;
|
|
302
|
-
} else if (newMesage !== this.translate && newMesage !== root.innerHTML) {
|
|
303
|
-
root.innerHTML = newMesage;
|
|
304
|
-
}
|
|
312
|
+
if (!root.innerHTML) {
|
|
313
|
+
root.innerHTML = newMesage;
|
|
314
|
+
} else if (newMesage !== this.translate || newMesage !== root.innerHTML) {
|
|
315
|
+
root.innerHTML = newMesage;
|
|
305
316
|
}
|
|
317
|
+
}
|
|
306
318
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
319
|
+
connectedCallback() {
|
|
320
|
+
if (this.useShadow && !this.shadowRoot) this.attachShadow({mode: 'open'});
|
|
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});
|
|
326
|
+
}
|
|
315
327
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
328
|
+
disconnectedCallback() {
|
|
329
|
+
if (this._i18nListener) {
|
|
330
|
+
this._i18nListener.destroy();
|
|
331
|
+
this._i18nListener = null;
|
|
321
332
|
}
|
|
333
|
+
}
|
|
322
334
|
}
|
|
323
335
|
|
|
324
|
-
if (
|
|
325
|
-
|
|
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));
|
|
326
343
|
}
|
|
327
344
|
|
|
328
345
|
module.exports = {
|
|
329
|
-
|
|
330
|
-
|
|
346
|
+
I18n,
|
|
347
|
+
I18nMessage,
|
|
331
348
|
};
|