@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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/i18n.js +257 -240
  3. 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.4",
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("./data-manager");
2
- const { template, getFromObj, shouldEncode, encodeHTML } = require("./utils");
3
- const withContext = require("./context-binding");
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 === "undefined") {
6
- HTMLElement = class {};
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
- constructor() {
41
- // language without region code;
42
- this._altLangRegex = /[_-]/i;
43
- this.setDefaultLang();
44
- this.setLang();
45
- if (typeof window !== "undefined") {
46
- if (typeof navigator !== "undefined") {
47
- this.setLang(navigator.language);
48
- }
49
- this.setMessages(window.i18n || {});
50
- } else {
51
- if (typeof process !== "undefined") {
52
- const { env } = process;
53
- this.setLang(
54
- env.LANG ||
55
- env.LANGUAGE ||
56
- env.LC_ALL ||
57
- env.LC_MESSAGES ||
58
- this._defaultLang
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
- setDefaultLang(lang = "en") {
65
- this._defaultLang = lang.toLowerCase();
66
- this._fallbackMessages = this.getMessages(this._defaultLang);
67
- }
68
- /**
69
- * @memberof I18n
70
- * @return {String} lang
71
- * @description returns the current language. defaults to the browser's navigator.language value.
72
- * @example
73
- *
74
- * navigator.language = 'en-US';
75
- * import { I18n } from '@ornery/web-components';
76
- *
77
- * console.log(I18n.getLang()) // "en-US"
78
- */
79
- getLang() {
80
- return DataManager.get("i18n-language") || '';
81
- }
82
- getRootLang() {
83
- return this.getLang().split(this._altLangRegex)[0];
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
- * @memberof I18n
87
- * @param {String} lang
88
- * @description sets the current i18n language. This does not change the browser language.
89
- * @example
90
- *
91
- * import { I18n } from '@ornery/web-components';
92
- *
93
- * I18n.setLang('en-US')
94
- * console.log(I18n.getLang()) //'en-US'
95
- */
96
- setLang(lang= "") {
97
- return DataManager.set("i18n-language", lang)
98
- }
99
- /**
100
- * @memberof I18n
101
- * @return {String} lang
102
- * @description returns the current i18n messages set in the DataManager
103
- */
104
- getMessages(lang) {
105
- const allMessages = DataManager.get("i18n-messages") || {};
106
- if (lang === "all") {
107
- return allMessages;
108
- } else {
109
- lang = lang || this.getLang();
110
- const rootLang = lang
111
- ? lang.split(this._altLangRegex)[0]
112
- : this.getRootLang();
113
- return {
114
- ...allMessages[rootLang],
115
- ...allMessages[lang],
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
- * @memberof I18n
121
- * @param {Object} values
122
- * @description sets the strings as a whole. This overrides all existing strings.
123
- * Use addMessages to add more strings to the existing set.
124
- * @example
125
- *
126
- * import { I18n } from '@ornery/web-components';
127
- *
128
- * I18n.setMessages({
129
- * 'en-US': {
130
- * 'translatable.message.name': "I'm a translated string from i18n",
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
- * @memberof I18n
178
- * @param {String} key they key of the string to retrieve from the current language set.
179
- * @param {Object} data Optional, The data to process tokens in the string with.
180
- * @return {String} Returns the value for the key. Processed if a data context is provided as the second argument.
181
- * @description Returns the value for the key. If a context is provided as the second argument for tokens,
182
- * the tokens will be replaced in the returned string.
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
- * @memberof I18n
207
- * @param {String} namespace
208
- * @return {Object} Returns all the messages for the given language. Filtered to namespace if provided.
209
- * @description If a namespace is provided, returns all the key value pairs for that
210
- * namespace without the namespace in the keys.
211
- *
212
- * @example
213
- *
214
- * import { I18n } from '@ornery/web-components';
215
- * I18n.addMessages('en-US', {
216
- * 'translatable.message.name': "I'm a translated string from i18n",
217
- * 'tokenized.message': "I have a ${color} ${animal}"
218
- * });
219
- *
220
- * console.log(I18n.getAll('tokenized', {color: "red", animal: "panda"})) // {"message": "I have a red panda"}
221
- */
222
- getAll(namespace, data) {
223
- if (namespace) {
224
- return Object.keys(this.getMessages()).reduce((reducer, key) => {
225
- if (key.startsWith(namespace)) {
226
- reducer[key.replace(namespace + ".", "")] = this.get(key, data);
227
- }
228
- return reducer;
229
- }, {});
230
- } else {
231
- return this.getMessages("all");
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
- class I18nMessage extends HTMLElement {
267
- constructor() {
268
- super();
269
- }
278
+ class I18nMessage extends HTMLElement {
279
+ constructor() {
280
+ super();
281
+ }
270
282
 
271
- static get observedAttributes() {
272
- return ["key", "id", "data-values"];
273
- }
283
+ static get observedAttributes() {
284
+ return ['key', 'id', 'data-values'];
285
+ }
274
286
 
275
- get useShadow() {
276
- if (this.hasAttribute("shadow")) {
277
- let current = this.getAttribute("shadow");
278
- if (current === "false") {
279
- return false;
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
- get translate() {
286
- return this.getAttribute("key") || this.getAttribute("id");
287
- }
297
+ get translate() {
298
+ return this.getAttribute('key') || this.getAttribute('id');
299
+ }
288
300
 
289
- attributeChangedCallback(name) {
290
- this.update();
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
- update() {
294
- const root = this.shadowRoot || this;
295
- const context = { ...this.getAttribute("data-values"), ...this.dataset };
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
- connectedCallback() {
308
- if (this.useShadow && !this.shadowRoot) this.attachShadow({ mode: "open" });
309
- this._i18nListener = DataManager.subscribe((newVals) => {
310
- this.update();
311
- });
312
- const attrObserver = new MutationObserver(() => this.update());
313
- attrObserver.observe(this, { attributes: true, childList: this.useShadow });
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
- disconnectedCallback() {
317
- if (this._i18nListener) {
318
- this._i18nListener.destroy();
319
- this._i18nListener = null;
320
- }
328
+ disconnectedCallback() {
329
+ if (this._i18nListener) {
330
+ this._i18nListener.destroy();
331
+ this._i18nListener = null;
321
332
  }
333
+ }
322
334
  }
323
335
 
324
- if (typeof window !== "undefined" && typeof customElements !== "undefined" && !customElements.get("i18n-message")) {
325
- customElements.define("i18n-message", withContext(I18nMessage));
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
- I18n,
330
- I18nMessage,
346
+ I18n,
347
+ I18nMessage,
331
348
  };
package/src/utils.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
  const keyRegexp = /^[\w\-]+(\.[\w\-]+)+$/g
18
18
  const getFromObj = (path, obj = {}) => {
19
- path = path.trim();
19
+ path = path && path.trim();
20
20
  if (path != null){
21
21
  if (obj[path] != null) {
22
22
  return obj[path];