@schukai/monster 3.8.0 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +1 -1
- package/source/data/datasource/server/restapi.mjs +0 -2
- package/source/data/transformer.mjs +31 -79
- package/source/i18n/provider.mjs +72 -4
- package/source/i18n/providers/embed.mjs +68 -20
- package/source/i18n/translations.mjs +59 -8
- package/source/types/version.mjs +1 -1
- package/test/cases/data/datasource/server/restapi.mjs +0 -1
- package/test/cases/data/transformer.mjs +61 -1
- package/test/cases/dom/locale.mjs +9 -6
- package/test/cases/i18n/provider.mjs +66 -3
- package/test/cases/i18n/translations.mjs +78 -1
- package/test/cases/monster.mjs +1 -1
- package/test/util/jsdom.mjs +1 -2
- package/test/web/import.js +1 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +5736 -3152
package/package.json
CHANGED
@@ -8,8 +8,6 @@
|
|
8
8
|
import { internalSymbol, instanceSymbol } from "../../../constants.mjs";
|
9
9
|
import { isObject } from "../../../types/is.mjs";
|
10
10
|
import { Server } from "../server.mjs";
|
11
|
-
import { Pathfinder } from "../../pathfinder.mjs";
|
12
|
-
import { Pipe } from "../../pipe.mjs";
|
13
11
|
import { WriteError } from "./restapi/writeerror.mjs";
|
14
12
|
|
15
13
|
export { RestAPI };
|
@@ -5,10 +5,11 @@
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
6
|
*/
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import {
|
8
|
+
import {Base} from "../types/base.mjs";
|
9
|
+
import {getGlobal, getGlobalObject} from "../types/global.mjs";
|
10
|
+
import {ID} from "../types/id.mjs";
|
11
|
+
import {isArray, isObject, isString} from "../types/is.mjs";
|
12
|
+
import {getDocumentTranslations, Translations} from "../i18n/translations.mjs";
|
12
13
|
import {
|
13
14
|
validateFunction,
|
14
15
|
validateInteger,
|
@@ -16,10 +17,10 @@ import {
|
|
16
17
|
validatePrimitive,
|
17
18
|
validateString,
|
18
19
|
} from "../types/validate.mjs";
|
19
|
-
import {
|
20
|
-
import {
|
20
|
+
import {clone} from "../util/clone.mjs";
|
21
|
+
import {Pathfinder} from "./pathfinder.mjs";
|
21
22
|
|
22
|
-
export {
|
23
|
+
export {Transformer};
|
23
24
|
|
24
25
|
/**
|
25
26
|
* The transformer class is a swiss army knife for manipulating values. especially in combination with the pipe, processing chains can be built up.
|
@@ -30,78 +31,7 @@ export { Transformer };
|
|
30
31
|
* let t = new Transformer('tolower').run('ABC'); // ↦ abc
|
31
32
|
* ```
|
32
33
|
*
|
33
|
-
*
|
34
|
-
*
|
35
|
-
* in the following table all commands, parameters and existing aliases are described.
|
36
|
-
*
|
37
|
-
* | command | parameter | alias | description |
|
38
|
-
* |:-------------|:---------------------------|:------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
39
|
-
* | to-base64 | | base64, btob | Converts the value to base64 |
|
40
|
-
* | from-base64 | | atob | Converts the value from base64 |
|
41
|
-
* | call | function:param1:param2:... | | Calling a callback function. The function can be defined in three places: either globally, in the context `addCallback` or in the passed object |
|
42
|
-
* | default | value:type | ?? | If the value is undefined the first argument is returned, otherwise the value. The third optional parameter specifies the desired type. If no type is specified, string is used. Valid types are bool, string, int, float, undefined and object. An object default value must be specified as a base64 encoded json string. (since 1.12.0) |
|
43
|
-
* | debug | | | the passed value is output (console) and returned |
|
44
|
-
* | empty | | | Return empty String "" |
|
45
|
-
* | first-key | default | | Can be applied to objects and returns the value of the first key. All keys of the object are fetched and sorted. (since 1.23.0) |
|
46
|
-
* | fromjson | | | Type conversion from a JSON string (since 1.12.0) |
|
47
|
-
* | if | statement1:statement2 | ? | Is the ternary operator, the first parameter is the valid statement, the second is the false part. To use the current value in the queue, you can set the value keyword. On the other hand, if you want to have the static string "value", you have to put one backslash \\ in front of it and write value. the follow values are true: 'on', true, 'true'. If you want to have a space, you also have to write \\ in front of the space. |
|
48
|
-
* | index | key:default | property, key | Fetches a value from an object, an array, a map or a set |
|
49
|
-
* | last-key | default | | Can be applied to objects and returns the value of the last key. All keys of the object are fetched and sorted. (since 1.23.0) |
|
50
|
-
* | length | | count | Length of the string or entries of an array or object |
|
51
|
-
* | nop | | | Do nothing |
|
52
|
-
* | nth-key | index:default | | Can be applied to objects and returns the value of the nth key. All keys of the object are fetched and sorted. (since 1.23.0) |
|
53
|
-
* | nth-last-key | index:default | | Can be applied to objects and returns the value of the nth key from behind. All keys of the object are fetched and sorted. (since 1.23.0) |
|
54
|
-
* | path | path | | The access to an object is done via a Pathfinder object |
|
55
|
-
* | path-exists | path | | Check if the specified path is available in the value (since 1.24.0) |
|
56
|
-
* | plaintext | | plain | All HTML tags are removed (*) |
|
57
|
-
* | prefix | text | | Adds a prefix |
|
58
|
-
* | rawurlencode | | | URL coding |
|
59
|
-
* | static | | none | The Arguments value is used and passed to the value. Special characters \ <space> and : can be quotet by a preceding \. |
|
60
|
-
* | substring | start:length | | Returns a substring |
|
61
|
-
* | suffix | text | | Adds a suffix |
|
62
|
-
* | tointeger | | | Type conversion to an integer value |
|
63
|
-
* | tojson | | | Type conversion to a JSON string (since 1.8.0) |
|
64
|
-
* | tolower | | strtolower, tolowercase | The input value is converted to lowercase letters |
|
65
|
-
* | tostring | | | Type conversion to a string. |
|
66
|
-
* | toupper | | strtoupper, touppercase | The input value is converted to uppercase letters |
|
67
|
-
* | trim | | | Remove spaces at the beginning and end |
|
68
|
-
* | ucfirst | | | First character large |
|
69
|
-
* | ucwords | | | Any word beginning large |
|
70
|
-
* | undefined | | | Return undefined |
|
71
|
-
* | uniqid | | | Creates a string with a unique value (**)
|
72
|
-
*
|
73
|
-
* (*) for this functionality the extension [jsdom](https://www.npmjs.com/package/jsdom) must be loaded in the nodejs context.
|
74
|
-
*
|
75
|
-
* ```
|
76
|
-
* // polyfill
|
77
|
-
* if (typeof window !== "object") {
|
78
|
-
* const {window} = new JSDOM('', {
|
79
|
-
* url: 'http://example.com/',
|
80
|
-
* pretendToBeVisual: true
|
81
|
-
* });
|
82
|
-
*
|
83
|
-
* [
|
84
|
-
* 'self',
|
85
|
-
* 'document',
|
86
|
-
* 'Node',
|
87
|
-
* 'Element',
|
88
|
-
* 'HTMLElement',
|
89
|
-
* 'DocumentFragment',
|
90
|
-
* 'DOMParser',
|
91
|
-
* 'XMLSerializer',
|
92
|
-
* 'NodeFilter',
|
93
|
-
* 'InputEvent',
|
94
|
-
* 'CustomEvent'
|
95
|
-
* ].forEach(key => (global[key] = window[key]));
|
96
|
-
* }
|
97
|
-
* ```
|
98
|
-
*
|
99
|
-
* (**) for this command the crypt library is necessary in the nodejs context.
|
100
|
-
*
|
101
|
-
* ```
|
102
|
-
* import * as Crypto from "@peculiar/webcrypto";
|
103
|
-
* global['crypto'] = new Crypto.Crypto();
|
104
|
-
* ```
|
34
|
+
* @see {@link https://monsterjs.org/en/doc/#transformer|Monster Docs}
|
105
35
|
*
|
106
36
|
* @externalExample ../../example/data/transformer.mjs
|
107
37
|
* @license AGPLv3
|
@@ -236,6 +166,10 @@ function transform(value) {
|
|
236
166
|
let key;
|
237
167
|
let defaultValue;
|
238
168
|
|
169
|
+
let element;
|
170
|
+
let attribute;
|
171
|
+
let translations;
|
172
|
+
|
239
173
|
switch (this.command) {
|
240
174
|
case "static":
|
241
175
|
return this.args.join(":");
|
@@ -260,9 +194,11 @@ function transform(value) {
|
|
260
194
|
validateInteger(n);
|
261
195
|
return n;
|
262
196
|
|
197
|
+
case "to-json":
|
263
198
|
case "tojson":
|
264
199
|
return JSON.stringify(value);
|
265
200
|
|
201
|
+
case "from-json":
|
266
202
|
case "fromjson":
|
267
203
|
return JSON.parse(value);
|
268
204
|
|
@@ -527,6 +463,22 @@ function transform(value) {
|
|
527
463
|
|
528
464
|
throw new Error("type not supported");
|
529
465
|
|
466
|
+
case "i18n":
|
467
|
+
case "translation":
|
468
|
+
|
469
|
+
translations = getDocumentTranslations();
|
470
|
+
if (!(translations instanceof Translations)) {
|
471
|
+
throw new Error("missing translations");
|
472
|
+
}
|
473
|
+
|
474
|
+
key = args.shift() || undefined;
|
475
|
+
if (key === undefined) {
|
476
|
+
key = value;
|
477
|
+
}
|
478
|
+
|
479
|
+
defaultValue = args.shift() || undefined;
|
480
|
+
return translations.getText(key, defaultValue);
|
481
|
+
|
530
482
|
default:
|
531
483
|
throw new Error(`unknown command ${this.command}`);
|
532
484
|
}
|
package/source/i18n/provider.mjs
CHANGED
@@ -5,11 +5,22 @@
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
6
|
*/
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
8
|
+
import {hasObjectLink, getLinkedObjects,addToObjectLink} from "../dom/attributes.mjs";
|
9
|
+
import {getLocaleOfDocument} from "../dom/locale.mjs";
|
10
|
+
import {BaseWithOptions} from "../types/basewithoptions.mjs";
|
11
|
+
import {Locale} from "./locale.mjs";
|
12
|
+
import {Translations} from "./translations.mjs";
|
11
13
|
|
12
|
-
export {
|
14
|
+
export {Provider, translationsLinkSymbol};
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @memberOf Monster.I18n
|
18
|
+
* @type {symbol}
|
19
|
+
* @license AGPLv3
|
20
|
+
* @since 3.9.0
|
21
|
+
* @private
|
22
|
+
*/
|
23
|
+
const translationsLinkSymbol = Symbol.for("@schukai/monster/i18n/translations@@link");
|
13
24
|
|
14
25
|
/**
|
15
26
|
* A provider makes a translation object available.
|
@@ -26,6 +37,11 @@ class Provider extends BaseWithOptions {
|
|
26
37
|
* @return {Promise}
|
27
38
|
*/
|
28
39
|
getTranslations(locale) {
|
40
|
+
|
41
|
+
if (locale === undefined) {
|
42
|
+
locale = getLocaleOfDocument();
|
43
|
+
}
|
44
|
+
|
29
45
|
return new Promise((resolve, reject) => {
|
30
46
|
try {
|
31
47
|
resolve(new Translations(locale));
|
@@ -34,4 +50,56 @@ class Provider extends BaseWithOptions {
|
|
34
50
|
}
|
35
51
|
});
|
36
52
|
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* @param {Locale|string} locale
|
56
|
+
* @param {HTMLElement} element
|
57
|
+
* @return {Provider}
|
58
|
+
*/
|
59
|
+
assignToElement(locale, element) {
|
60
|
+
|
61
|
+
if (locale === undefined) {
|
62
|
+
locale = getLocaleOfDocument();
|
63
|
+
}
|
64
|
+
|
65
|
+
if (!(locale instanceof Locale)) {
|
66
|
+
throw new Error("Locale is not an instance of Locale");
|
67
|
+
}
|
68
|
+
|
69
|
+
if (!(element instanceof HTMLElement)) {
|
70
|
+
element = document.querySelector("body");
|
71
|
+
}
|
72
|
+
|
73
|
+
if (!(element instanceof HTMLElement)) {
|
74
|
+
throw new Error("Element is not an HTMLElement");
|
75
|
+
}
|
76
|
+
|
77
|
+
return this.getTranslations(locale).then((obj) => {
|
78
|
+
|
79
|
+
let translations = null;
|
80
|
+
if (hasObjectLink(element, translationsLinkSymbol)) {
|
81
|
+
const objects = getLinkedObjects(element, translationsLinkSymbol);
|
82
|
+
for (const o of objects) {
|
83
|
+
if (o instanceof Translations) {
|
84
|
+
translations = o;
|
85
|
+
break;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
if (!(translations instanceof Translations)) {
|
90
|
+
throw new Error("Object is not an instance of Translations");
|
91
|
+
}
|
92
|
+
|
93
|
+
translations.assignTranslations(obj);
|
94
|
+
|
95
|
+
} else {
|
96
|
+
addToObjectLink(element, translationsLinkSymbol, obj);
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
return obj;
|
101
|
+
});
|
102
|
+
|
103
|
+
}
|
104
|
+
|
37
105
|
}
|
@@ -5,16 +5,16 @@
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
6
|
*/
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import {
|
12
|
-
import {
|
13
|
-
import {
|
14
|
-
import {
|
15
|
-
import {
|
8
|
+
import {internalSymbol} from "../../constants.mjs";
|
9
|
+
import {extend} from "../../data/extend.mjs";
|
10
|
+
import {getDocument} from "../../dom/util.mjs";
|
11
|
+
import {isString} from "../../types/is.mjs";
|
12
|
+
import {validateObject, validateString} from "../../types/validate.mjs";
|
13
|
+
import {parseLocale} from "../locale.mjs";
|
14
|
+
import {Provider} from "../provider.mjs";
|
15
|
+
import {Translations} from "../translations.mjs";
|
16
16
|
|
17
|
-
export {
|
17
|
+
export {Embed};
|
18
18
|
|
19
19
|
/**
|
20
20
|
* The Embed provider retrieves a JSON file from the given Script Tag.
|
@@ -42,22 +42,27 @@ class Embed extends Provider {
|
|
42
42
|
* new Embed('translations')
|
43
43
|
* ```
|
44
44
|
*
|
45
|
-
* @param {string}
|
45
|
+
* @param {HTMLElement|string} elementOrId
|
46
46
|
* @param {Object} options
|
47
47
|
*/
|
48
|
-
constructor(
|
48
|
+
constructor(elementOrId, options) {
|
49
49
|
super(options);
|
50
50
|
|
51
51
|
if (options === undefined) {
|
52
52
|
options = {};
|
53
53
|
}
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
55
|
+
if (elementOrId instanceof HTMLElement) {
|
56
|
+
/**
|
57
|
+
* @property {HTMLElement|string}
|
58
|
+
*/
|
59
|
+
this.translateElement = elementOrId;
|
60
|
+
} else {
|
61
|
+
/**
|
62
|
+
* @property {HTMLElement|string}
|
63
|
+
*/
|
64
|
+
this.translateElement = getDocument().getElementById(validateString(elementOrId));
|
65
|
+
}
|
61
66
|
|
62
67
|
/**
|
63
68
|
* @private
|
@@ -86,16 +91,25 @@ class Embed extends Provider {
|
|
86
91
|
}
|
87
92
|
|
88
93
|
return new Promise((resolve, reject) => {
|
89
|
-
let text = getGlobalObject("document").getElementById(this.textId);
|
90
94
|
|
91
|
-
if (
|
95
|
+
if (this.translateElement === null) {
|
92
96
|
reject(new Error("Text not found"));
|
93
97
|
return;
|
94
98
|
}
|
95
99
|
|
100
|
+
if (!(this.translateElement instanceof HTMLScriptElement)) {
|
101
|
+
reject(new Error("Element is not a script tag"));
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (this.translateElement.type !== "application/json") {
|
106
|
+
reject(new Error("Element is not a script tag with type application/json"));
|
107
|
+
return;
|
108
|
+
}
|
109
|
+
|
96
110
|
let translations = null;
|
97
111
|
try {
|
98
|
-
translations = JSON.parse(
|
112
|
+
translations = JSON.parse(this.translateElement.innerHTML);
|
99
113
|
} catch (e) {
|
100
114
|
reject(e);
|
101
115
|
return;
|
@@ -112,4 +126,38 @@ class Embed extends Provider {
|
|
112
126
|
resolve(t);
|
113
127
|
});
|
114
128
|
}
|
129
|
+
|
130
|
+
|
131
|
+
/**
|
132
|
+
* Initializes the translations for the current document.
|
133
|
+
*
|
134
|
+
* `script[data-monster-role=translations]` is searched for and the translations are assigned to the element.
|
135
|
+
*
|
136
|
+
* @param element
|
137
|
+
* @returns {Promise<unknown[]>}
|
138
|
+
*/
|
139
|
+
static assignTranslationsToElement(element) {
|
140
|
+
const d = getDocument()
|
141
|
+
|
142
|
+
if (!(element instanceof HTMLElement)) {
|
143
|
+
element = d.querySelector("body");
|
144
|
+
}
|
145
|
+
|
146
|
+
const list = d.querySelectorAll("script[data-monster-role=translations]");
|
147
|
+
if (list === null) {
|
148
|
+
return;
|
149
|
+
}
|
150
|
+
|
151
|
+
const promises = [];
|
152
|
+
|
153
|
+
let result
|
154
|
+
|
155
|
+
list.forEach((translationElement) => {
|
156
|
+
const p = new Embed(translationElement);
|
157
|
+
promises.push(p.assignToElement(undefined, element));
|
158
|
+
});
|
159
|
+
|
160
|
+
return Promise.all(promises);
|
161
|
+
}
|
162
|
+
|
115
163
|
}
|
@@ -5,12 +5,17 @@
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
6
|
*/
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import {
|
8
|
+
import { getLinkedObjects,hasObjectLink} from "../dom/attributes.mjs";
|
9
|
+
import {ATTRIBUTE_OBJECTLINK} from "../dom/constants.mjs";
|
10
|
+
import {getDocument} from "../dom/util.mjs";
|
11
|
+
import {Base} from "../types/base.mjs";
|
12
|
+
import {isObject, isString} from "../types/is.mjs";
|
13
|
+
import {validateInteger, validateObject, validateString} from "../types/validate.mjs";
|
14
|
+
import {Locale, parseLocale} from "./locale.mjs";
|
15
|
+
import {translationsLinkSymbol} from "./provider.mjs";
|
12
16
|
|
13
|
-
|
17
|
+
|
18
|
+
export {Translations, getDocumentTranslations};
|
14
19
|
|
15
20
|
/**
|
16
21
|
* With this class you can manage translations and access the keys.
|
@@ -30,11 +35,12 @@ class Translations extends Base {
|
|
30
35
|
constructor(locale) {
|
31
36
|
super();
|
32
37
|
|
33
|
-
if (
|
34
|
-
locale =
|
38
|
+
if (locale instanceof Locale) {
|
39
|
+
this.locale = locale;
|
40
|
+
} else {
|
41
|
+
this.locale = parseLocale(validateString(locale));
|
35
42
|
}
|
36
43
|
|
37
|
-
this.locale = validateInstance(locale, Locale);
|
38
44
|
this.storage = new Map();
|
39
45
|
}
|
40
46
|
|
@@ -165,6 +171,13 @@ class Translations extends Base {
|
|
165
171
|
*/
|
166
172
|
assignTranslations(translations) {
|
167
173
|
validateObject(translations);
|
174
|
+
|
175
|
+
if (translations instanceof Translations) {
|
176
|
+
translations.storage.forEach((v, k) => {
|
177
|
+
this.setText(k, v);
|
178
|
+
});
|
179
|
+
return this;
|
180
|
+
}
|
168
181
|
|
169
182
|
for (const [k, v] of Object.entries(translations)) {
|
170
183
|
this.setText(k, v);
|
@@ -173,3 +186,41 @@ class Translations extends Base {
|
|
173
186
|
return this;
|
174
187
|
}
|
175
188
|
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Returns the translations for the current document.
|
192
|
+
*
|
193
|
+
* @param element
|
194
|
+
* @returns {*}
|
195
|
+
* @throws {Error} Element is not an HTMLElement
|
196
|
+
* @throws {Error} Missing translations
|
197
|
+
*/
|
198
|
+
function getDocumentTranslations(element) {
|
199
|
+
|
200
|
+
const d = getDocument()
|
201
|
+
|
202
|
+
if (!(element instanceof HTMLElement)) {
|
203
|
+
element = d.querySelector('['+ATTRIBUTE_OBJECTLINK+'="' + translationsLinkSymbol.toString() + '"]');
|
204
|
+
}
|
205
|
+
|
206
|
+
if (!(element instanceof HTMLElement)) {
|
207
|
+
throw new Error("Element is not an HTMLElement");
|
208
|
+
}
|
209
|
+
|
210
|
+
if (!hasObjectLink(element, translationsLinkSymbol)) {
|
211
|
+
throw new Error("Missing translations");
|
212
|
+
}
|
213
|
+
|
214
|
+
let obj = getLinkedObjects(element, translationsLinkSymbol);
|
215
|
+
|
216
|
+
for (const t of obj) {
|
217
|
+
if (t instanceof Translations) {
|
218
|
+
return t;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
throw new Error("Missing translations");
|
223
|
+
|
224
|
+
}
|
225
|
+
|
226
|
+
|
package/source/types/version.mjs
CHANGED
@@ -4,7 +4,6 @@ import {expect} from "chai"
|
|
4
4
|
import {RestAPI} from "../../../../../../application/source/data/datasource/server/restapi.mjs";
|
5
5
|
import {validateObject} from "../../../../../../application/source/types/validate.mjs";
|
6
6
|
|
7
|
-
|
8
7
|
describe('RestAPI', function () {
|
9
8
|
|
10
9
|
let fetchReference;
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
import {expect} from "chai"
|
4
4
|
import {Transformer} from "../../../../application/source/data/transformer.mjs";
|
5
|
+
import {Embed} from "../../../../application/source/i18n/providers/embed.mjs";
|
5
6
|
import {initJSDOM} from "../../util/jsdom.mjs";
|
6
7
|
|
7
8
|
describe('Transformer', function () {
|
@@ -10,7 +11,7 @@ describe('Transformer', function () {
|
|
10
11
|
|
11
12
|
let promises = []
|
12
13
|
promises.push(initJSDOM());
|
13
|
-
if(!globalThis['crypto']) {
|
14
|
+
if (!globalThis['crypto']) {
|
14
15
|
promises.push(import("@peculiar/webcrypto").then(m => {
|
15
16
|
globalThis['crypto'] = new m.Crypto();
|
16
17
|
return true;
|
@@ -197,4 +198,63 @@ describe('Transformer', function () {
|
|
197
198
|
}).to.throw(TypeError);
|
198
199
|
});
|
199
200
|
});
|
201
|
+
|
202
|
+
|
203
|
+
describe('i18n', function () {
|
204
|
+
|
205
|
+
let html1 = `
|
206
|
+
<div id="mock-translations"></div>
|
207
|
+
<script type="application/json" data-monster-role="translations">
|
208
|
+
{
|
209
|
+
"test1": "xyz",
|
210
|
+
"test3": {
|
211
|
+
"other": "xyz"
|
212
|
+
}
|
213
|
+
}
|
214
|
+
</script>
|
215
|
+
`;
|
216
|
+
|
217
|
+
beforeEach((done) => {
|
218
|
+
let mocks = document.getElementById('mocks');
|
219
|
+
mocks.innerHTML = html1;
|
220
|
+
let elem = document.getElementById('mock-translations');
|
221
|
+
Embed.assignTranslationsToElement(elem).then((o) => {
|
222
|
+
done()
|
223
|
+
})
|
224
|
+
|
225
|
+
|
226
|
+
})
|
227
|
+
|
228
|
+
afterEach(() => {
|
229
|
+
let mocks = document.getElementById('mocks');
|
230
|
+
mocks.innerHTML = "";
|
231
|
+
})
|
232
|
+
|
233
|
+
before(function (done) {
|
234
|
+
initJSDOM().then(() => {
|
235
|
+
done()
|
236
|
+
});
|
237
|
+
});
|
238
|
+
|
239
|
+
[
|
240
|
+
[ 'i18n:test1',"", "xyz"],
|
241
|
+
[ 'i18n:',"test1", "xyz"], // key by value
|
242
|
+
[ 'i18n::',"test1", "xyz"], // key by value no default
|
243
|
+
[ 'i18n::eee',"test2", "eee"], // key by value with default
|
244
|
+
[ 'i18n::ddd',"test2", "ddd"], // key by value and default
|
245
|
+
|
246
|
+
].forEach(function (data) {
|
247
|
+
|
248
|
+
let a = data.shift()
|
249
|
+
let b = data.shift()
|
250
|
+
let c = data.shift()
|
251
|
+
|
252
|
+
it('should transform('+a+').run('+b+') return ' + JSON.stringify(c), function () {
|
253
|
+
const t = new Transformer(a);
|
254
|
+
expect(t.run(b)).to.be.eql(c);
|
255
|
+
});
|
256
|
+
})
|
257
|
+
})
|
258
|
+
|
259
|
+
|
200
260
|
});
|
@@ -33,24 +33,27 @@ describe('Attributes', function () {
|
|
33
33
|
node.setAttribute('lang', a);
|
34
34
|
expect(getLocaleOfDocument().toString()).to.be.equal(a);
|
35
35
|
})
|
36
|
-
|
37
|
-
|
36
|
+
|
38
37
|
|
39
38
|
});
|
40
39
|
|
41
40
|
|
42
41
|
});
|
43
|
-
|
44
|
-
|
42
|
+
|
43
|
+
|
45
44
|
it('return language en', function () {
|
46
45
|
let html = document.getElementsByTagName('html');
|
47
46
|
let node = html.item(0);
|
47
|
+
let lang= node.getAttribute('lang');
|
48
48
|
|
49
49
|
node.removeAttribute('lang');
|
50
50
|
const locale = getLocaleOfDocument();
|
51
51
|
expect(locale).to.be.instanceOf(Locale);
|
52
|
-
expect(locale.localeString).to.be.equal(
|
52
|
+
expect(locale.localeString).to.be.equal(navigator.language);
|
53
|
+
|
54
|
+
node.setAttribute('lang', lang);
|
55
|
+
|
53
56
|
})
|
54
|
-
|
57
|
+
|
55
58
|
|
56
59
|
})
|