@knowark/componarkjs 1.13.4 → 1.14.1
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/README.md +57 -45
- package/lib/base/component/component.js +142 -20
- package/lib/base/component/component.test.js +753 -374
- package/lib/base/component/index.js +3 -0
- package/lib/base/styles/index.js +4 -1
- package/lib/base/utils/define.js +30 -7
- package/lib/base/utils/define.test.js +129 -42
- package/lib/base/utils/format.js +12 -6
- package/lib/base/utils/format.test.js +16 -16
- package/lib/base/utils/helpers.js +42 -9
- package/lib/base/utils/helpers.test.js +134 -115
- package/lib/base/utils/index.js +1 -0
- package/lib/base/utils/slots.js +3 -2
- package/lib/base/utils/slots.test.js +38 -38
- package/lib/base/utils/uuid.js +1 -1
- package/lib/base/utils/uuid.test.js +13 -13
- package/lib/components/audio/components/audio.js +36 -3
- package/lib/components/audio/components/audio.test.js +120 -90
- package/lib/components/audio/index.js +1 -0
- package/lib/components/audio/styles/index.js +5 -1
- package/lib/components/camera/components/camera.js +15 -0
- package/lib/components/camera/components/camera.test.js +96 -91
- package/lib/components/camera/index.js +1 -0
- package/lib/components/camera/styles/index.js +5 -1
- package/lib/components/capture/components/capture.js +48 -4
- package/lib/components/capture/components/capture.test.js +165 -97
- package/lib/components/capture/index.js +1 -0
- package/lib/components/droparea/components/droparea-preview.js +114 -19
- package/lib/components/droparea/components/droparea-preview.test.js +344 -80
- package/lib/components/droparea/components/droparea.js +82 -6
- package/lib/components/droparea/components/droparea.test.js +309 -299
- package/lib/components/droparea/index.js +1 -0
- package/lib/components/droparea/styles/index.js +5 -1
- package/lib/components/emit/components/emit.js +34 -4
- package/lib/components/emit/components/emit.test.js +192 -134
- package/lib/components/emit/index.js +1 -0
- package/lib/components/index.js +2 -1
- package/lib/components/list/components/item.js +6 -0
- package/lib/components/list/components/item.test.js +69 -68
- package/lib/components/list/components/list.js +51 -7
- package/lib/components/list/components/list.test.js +358 -227
- package/lib/components/list/index.js +1 -0
- package/lib/components/paginator/components/paginator.js +34 -8
- package/lib/components/paginator/components/paginator.test.js +146 -143
- package/lib/components/paginator/index.js +1 -0
- package/lib/components/paginator/styles/index.js +5 -1
- package/lib/components/spinner/components/spinner.js +10 -0
- package/lib/components/spinner/components/spinner.test.js +36 -41
- package/lib/components/spinner/index.js +1 -0
- package/lib/components/spinner/styles/index.js +5 -1
- package/lib/components/splitview/components/splitview.detail.js +10 -1
- package/lib/components/splitview/components/splitview.detail.test.js +75 -73
- package/lib/components/splitview/components/splitview.js +54 -11
- package/lib/components/splitview/components/splitview.master.js +37 -2
- package/lib/components/splitview/components/splitview.master.test.js +52 -52
- package/lib/components/splitview/components/splitview.test.js +135 -31
- package/lib/components/splitview/index.js +1 -0
- package/lib/components/translate/components/translate.js +65 -14
- package/lib/components/translate/components/translate.test.js +658 -131
- package/lib/components/translate/index.js +1 -0
- package/lib/index.js +3 -0
- package/package.json +4 -27
- package/scripts/node-test-setup.js +94 -0
- package/tsconfig.json +1 -1
- package/types/base/component/component.d.ts +43 -8
- package/types/base/component/component.d.ts.map +1 -1
- package/types/base/component/index.d.ts +4 -6
- package/types/base/component/index.d.ts.map +1 -1
- package/types/base/styles/index.d.ts +3 -2
- package/types/base/styles/index.d.ts.map +1 -1
- package/types/base/utils/define.d.ts +3 -2
- package/types/base/utils/define.d.ts.map +1 -1
- package/types/base/utils/format.d.ts +12 -6
- package/types/base/utils/format.d.ts.map +1 -1
- package/types/base/utils/helpers.d.ts +27 -7
- package/types/base/utils/helpers.d.ts.map +1 -1
- package/types/base/utils/slots.d.ts +8 -10
- package/types/base/utils/slots.d.ts.map +1 -1
- package/types/base/utils/uuid.d.ts +1 -1
- package/types/base/utils/uuid.d.ts.map +1 -1
- package/types/components/audio/components/audio.d.ts +23 -9
- package/types/components/audio/components/audio.d.ts.map +1 -1
- package/types/components/audio/styles/index.d.ts +3 -2
- package/types/components/audio/styles/index.d.ts.map +1 -1
- package/types/components/camera/components/camera.d.ts +11 -3
- package/types/components/camera/components/camera.d.ts.map +1 -1
- package/types/components/camera/styles/index.d.ts +3 -2
- package/types/components/camera/styles/index.d.ts.map +1 -1
- package/types/components/capture/components/capture.d.ts +23 -3
- package/types/components/capture/components/capture.d.ts.map +1 -1
- package/types/components/droparea/components/droparea-preview.d.ts +64 -11
- package/types/components/droparea/components/droparea-preview.d.ts.map +1 -1
- package/types/components/droparea/components/droparea.d.ts +58 -13
- package/types/components/droparea/components/droparea.d.ts.map +1 -1
- package/types/components/droparea/styles/index.d.ts +3 -2
- package/types/components/droparea/styles/index.d.ts.map +1 -1
- package/types/components/emit/components/emit.d.ts +15 -3
- package/types/components/emit/components/emit.d.ts.map +1 -1
- package/types/components/list/components/item.d.ts +8 -1
- package/types/components/list/components/item.d.ts.map +1 -1
- package/types/components/list/components/list.d.ts +23 -5
- package/types/components/list/components/list.d.ts.map +1 -1
- package/types/components/paginator/components/paginator.d.ts +32 -8
- package/types/components/paginator/components/paginator.d.ts.map +1 -1
- package/types/components/paginator/styles/index.d.ts +3 -2
- package/types/components/paginator/styles/index.d.ts.map +1 -1
- package/types/components/spinner/components/spinner.d.ts +14 -3
- package/types/components/spinner/components/spinner.d.ts.map +1 -1
- package/types/components/spinner/styles/index.d.ts +3 -2
- package/types/components/spinner/styles/index.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.d.ts +22 -4
- package/types/components/splitview/components/splitview.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.detail.d.ts +12 -2
- package/types/components/splitview/components/splitview.detail.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.master.d.ts +12 -1
- package/types/components/splitview/components/splitview.master.d.ts.map +1 -1
- package/types/components/translate/components/translate.d.ts +44 -10
- package/types/components/translate/components/translate.d.ts.map +1 -1
|
@@ -1,88 +1,457 @@
|
|
|
1
|
+
import { it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
import { Translate } from './translate.js'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
let container = null
|
|
6
|
+
|
|
7
|
+
const setup = () => {
|
|
8
|
+
document.body.innerHTML = '';
|
|
9
|
+
container = document.createElement('div')
|
|
10
|
+
document.body.appendChild(container)
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
it('can be instantiated', () => {
|
|
14
|
+
setup();
|
|
15
|
+
container.innerHTML = /* html */`
|
|
16
|
+
<ark-translate>
|
|
17
|
+
</ark-translate>
|
|
18
|
+
`
|
|
19
|
+
|
|
20
|
+
const translate = container.querySelector('ark-translate')
|
|
21
|
+
|
|
22
|
+
assert.ok(translate)
|
|
23
|
+
assert.strictEqual(translate, translate.init())
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('translates the marked text inside the given root', async () => {
|
|
27
|
+
setup();
|
|
28
|
+
const root = document.createElement('div')
|
|
29
|
+
root.innerHTML = /* html */`
|
|
30
|
+
<span data-i18n="hello">Hello</span>
|
|
31
|
+
<p>
|
|
32
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
33
|
+
<span data-i18n="world">World</span>!!!
|
|
34
|
+
</p>
|
|
35
|
+
`
|
|
36
|
+
container.appendChild(root)
|
|
37
|
+
const translateContainer = document.createElement('div')
|
|
38
|
+
translateContainer.innerHTML = /* html */`
|
|
39
|
+
<ark-translate>
|
|
40
|
+
<template>{
|
|
41
|
+
"en": {
|
|
42
|
+
"default": {
|
|
43
|
+
"hello": "Hello",
|
|
44
|
+
"world": "World"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"es": {
|
|
48
|
+
"default": {
|
|
49
|
+
"hello": "Hola",
|
|
50
|
+
"world": "Mundo"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}</template>
|
|
54
|
+
</ark-translate>
|
|
55
|
+
`
|
|
56
|
+
container.appendChild(translateContainer)
|
|
57
|
+
const translate = /** @type Translate **/ (
|
|
58
|
+
translateContainer.querySelector('ark-translate'))
|
|
59
|
+
|
|
60
|
+
await translate.transliterate()
|
|
61
|
+
|
|
62
|
+
const expectedRoot = document.createElement('div')
|
|
63
|
+
expectedRoot.innerHTML = /* html */`
|
|
64
|
+
<span data-i18n="hello">Hola</span>
|
|
65
|
+
<p>
|
|
66
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
67
|
+
<span data-i18n="world">Mundo</span>!!!
|
|
68
|
+
</p>
|
|
69
|
+
`
|
|
70
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('might use different translation languages and namespaces', async () => {
|
|
74
|
+
setup();
|
|
75
|
+
const root = document.createElement('div')
|
|
76
|
+
root.innerHTML = /* html */`
|
|
77
|
+
<span data-i18n="introModule:hello">hello</span>
|
|
78
|
+
<p>
|
|
79
|
+
<span data-i18n="introModule:happy">happy</span>!!!
|
|
80
|
+
<span data-i18n="introModule:world">world</span>!!!
|
|
81
|
+
</p>
|
|
82
|
+
`
|
|
83
|
+
container.appendChild(root)
|
|
84
|
+
const translateContainer = document.createElement('div')
|
|
85
|
+
translateContainer.innerHTML = /* html */`
|
|
86
|
+
<ark-translate>
|
|
87
|
+
<template>{
|
|
88
|
+
"es": {
|
|
89
|
+
"default": {
|
|
90
|
+
"hello": "Hola",
|
|
91
|
+
"world": "Mundo"
|
|
92
|
+
},
|
|
93
|
+
"introModule": {
|
|
94
|
+
"hello": "Quiubo",
|
|
95
|
+
"world": "Gente"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"en": {
|
|
99
|
+
"default": {
|
|
100
|
+
"hello": "Hello",
|
|
101
|
+
"world": "World"
|
|
102
|
+
},
|
|
103
|
+
"introModule": {
|
|
104
|
+
"hello": "Hey",
|
|
105
|
+
"world": "Folks"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}</template>
|
|
109
|
+
</ark-translate>
|
|
110
|
+
`
|
|
111
|
+
container.appendChild(translateContainer)
|
|
112
|
+
const translate = /** @type Translate **/ (
|
|
113
|
+
translateContainer.querySelector('ark-translate'))
|
|
114
|
+
|
|
115
|
+
let options = { language: 'en' }
|
|
116
|
+
await translate.transliterate(options)
|
|
117
|
+
|
|
118
|
+
const expectedRoot = document.createElement('div')
|
|
119
|
+
expectedRoot.innerHTML = /* html */`
|
|
120
|
+
<span data-i18n="introModule:hello">Hey</span>
|
|
121
|
+
<p>
|
|
122
|
+
<span data-i18n="introModule:happy">happy</span>!!!
|
|
123
|
+
<span data-i18n="introModule:world">Folks</span>!!!
|
|
124
|
+
</p>
|
|
125
|
+
`
|
|
126
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
127
|
+
|
|
128
|
+
// Unknown Namespace:
|
|
129
|
+
root.innerHTML = /* html */`
|
|
130
|
+
<span data-i18n="unknown:hello">Hello</span>
|
|
131
|
+
<p>
|
|
132
|
+
<span data-i18n="unknown:happy">Happy</span>!!!
|
|
133
|
+
<span data-i18n="unknown:world">World</span>!!!
|
|
134
|
+
</p>
|
|
135
|
+
`
|
|
136
|
+
|
|
137
|
+
options = { language: 'es' }
|
|
138
|
+
await translate.transliterate(options)
|
|
139
|
+
|
|
140
|
+
expectedRoot.innerHTML = /* html */`
|
|
141
|
+
<span data-i18n="unknown:hello">Hello</span>
|
|
142
|
+
<p>
|
|
143
|
+
<span data-i18n="unknown:happy">Happy</span>!!!
|
|
144
|
+
<span data-i18n="unknown:world">World</span>!!!
|
|
145
|
+
</p>
|
|
146
|
+
`
|
|
147
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('translates the page content on language changes', async () => {
|
|
151
|
+
setup();
|
|
152
|
+
const translateContainer = document.createElement('div')
|
|
153
|
+
translateContainer.innerHTML = /* html */`
|
|
154
|
+
<ark-translate languages="es,en">
|
|
155
|
+
<template>{
|
|
156
|
+
"es": {
|
|
157
|
+
"default": {
|
|
158
|
+
"hello": "Hola",
|
|
159
|
+
"world": "Mundo"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"en": {
|
|
163
|
+
"default": {
|
|
164
|
+
"hello": "Hello",
|
|
165
|
+
"world": "World"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}</template>
|
|
169
|
+
</ark-translate>
|
|
170
|
+
`
|
|
171
|
+
container.appendChild(translateContainer)
|
|
172
|
+
const translate = /** @type Translate **/ (
|
|
173
|
+
translateContainer.querySelector('ark-translate'))
|
|
174
|
+
const mockEvent = { target: { value: 'en' }, stopPropagation: () => {} }
|
|
175
|
+
let givenOptions = null
|
|
176
|
+
translate.transliterate = async (options) => {
|
|
177
|
+
givenOptions = options
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
await translate.onLanguageChanged(mockEvent)
|
|
181
|
+
|
|
182
|
+
assert.deepStrictEqual(givenOptions, { language: 'en' })
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('passes an undefined language when language change event has no target', async () => {
|
|
186
|
+
setup()
|
|
187
|
+
const translateContainer = document.createElement('div')
|
|
188
|
+
translateContainer.innerHTML = '<ark-translate></ark-translate>'
|
|
189
|
+
container.appendChild(translateContainer)
|
|
190
|
+
const translate = /** @type Translate **/ (
|
|
191
|
+
translateContainer.querySelector('ark-translate'))
|
|
192
|
+
let givenOptions = null
|
|
193
|
+
|
|
194
|
+
translate.transliterate = async (options) => {
|
|
195
|
+
givenOptions = options
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
await translate.onLanguageChanged({
|
|
199
|
+
stopPropagation: () => {},
|
|
200
|
+
target: null
|
|
8
201
|
})
|
|
9
202
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
203
|
+
assert.deepStrictEqual(givenOptions, { language: undefined })
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('fetches its translation files from the server', async () => {
|
|
207
|
+
setup();
|
|
208
|
+
const root = document.createElement('div')
|
|
209
|
+
root.innerHTML = /* html */`
|
|
210
|
+
<span data-i18n="hello">hello</span>
|
|
211
|
+
<p>
|
|
212
|
+
<span data-i18n="happy">happy</span>!!!
|
|
213
|
+
<span data-i18n="world">world</span>!!!
|
|
214
|
+
</p>
|
|
215
|
+
`
|
|
216
|
+
container.appendChild(root)
|
|
217
|
+
const translateContainer = document.createElement('div')
|
|
218
|
+
translateContainer.innerHTML = `
|
|
219
|
+
<ark-translate languages="es,en"></ark-translate>
|
|
220
|
+
`
|
|
221
|
+
container.appendChild(translateContainer)
|
|
222
|
+
const translate = /** @type Translate **/ (
|
|
223
|
+
translateContainer.querySelector('ark-translate'))
|
|
224
|
+
|
|
225
|
+
const mockFetch = async (url) => ({
|
|
226
|
+
json: async () => ({
|
|
227
|
+
hello: 'Hola',
|
|
228
|
+
world: 'Mundo',
|
|
229
|
+
happy: 'Feliz'
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
translate.init({
|
|
233
|
+
global: { fetch: mockFetch, document }
|
|
13
234
|
})
|
|
14
235
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
236
|
+
await translate.transliterate({ language: 'es' })
|
|
237
|
+
|
|
238
|
+
const expectedRoot = document.createElement('div')
|
|
239
|
+
expectedRoot.innerHTML = /* html */`
|
|
240
|
+
<span data-i18n="hello">Hola</span>
|
|
241
|
+
<p>
|
|
242
|
+
<span data-i18n="happy">Feliz</span>!!!
|
|
243
|
+
<span data-i18n="world">Mundo</span>!!!
|
|
244
|
+
</p>
|
|
245
|
+
`
|
|
246
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
247
|
+
})
|
|
20
248
|
|
|
21
|
-
|
|
249
|
+
it('renders unknown language codes without crashing', () => {
|
|
250
|
+
setup()
|
|
251
|
+
const translateContainer = document.createElement('div')
|
|
252
|
+
translateContainer.innerHTML = `
|
|
253
|
+
<ark-translate languages="es,de"></ark-translate>
|
|
254
|
+
`
|
|
255
|
+
container.appendChild(translateContainer)
|
|
256
|
+
const translate = /** @type Translate **/ (
|
|
257
|
+
translateContainer.querySelector('ark-translate'))
|
|
258
|
+
|
|
259
|
+
const option = translate.querySelector('option[value="de"]')
|
|
260
|
+
assert.ok(option)
|
|
261
|
+
assert.deepStrictEqual(option.textContent, 'de')
|
|
262
|
+
})
|
|
22
263
|
|
|
23
|
-
|
|
24
|
-
|
|
264
|
+
it('emits error when inline dictionary JSON is invalid', () => {
|
|
265
|
+
setup()
|
|
266
|
+
const translateContainer = document.createElement('div')
|
|
267
|
+
translateContainer.innerHTML = /* html */`
|
|
268
|
+
<ark-translate>
|
|
269
|
+
<template>{ invalid json }</template>
|
|
270
|
+
</ark-translate>
|
|
271
|
+
`
|
|
272
|
+
container.appendChild(translateContainer)
|
|
273
|
+
const translate = /** @type Translate **/ (
|
|
274
|
+
translateContainer.querySelector('ark-translate'))
|
|
275
|
+
let errorEvent = null
|
|
276
|
+
|
|
277
|
+
translate.addEventListener('error', (event) => {
|
|
278
|
+
errorEvent = event
|
|
25
279
|
})
|
|
280
|
+
translate.init()
|
|
26
281
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
282
|
+
assert.ok(errorEvent)
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('emits error when dictionary fetch fails', async () => {
|
|
286
|
+
setup()
|
|
287
|
+
const root = document.createElement('div')
|
|
288
|
+
root.innerHTML = /* html */`
|
|
289
|
+
<span data-i18n="hello">hello</span>
|
|
290
|
+
`
|
|
291
|
+
container.appendChild(root)
|
|
292
|
+
const translateContainer = document.createElement('div')
|
|
293
|
+
translateContainer.innerHTML = `
|
|
294
|
+
<ark-translate></ark-translate>
|
|
295
|
+
`
|
|
296
|
+
container.appendChild(translateContainer)
|
|
297
|
+
const translate = /** @type Translate **/ (
|
|
298
|
+
translateContainer.querySelector('ark-translate'))
|
|
299
|
+
let errorEvent = null
|
|
300
|
+
translate.addEventListener('error', (event) => {
|
|
301
|
+
errorEvent = event
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
translate.init({
|
|
305
|
+
global: {
|
|
306
|
+
document,
|
|
307
|
+
fetch: async () => {
|
|
308
|
+
throw new Error('Network failed')
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
await translate.transliterate({ language: 'es' })
|
|
314
|
+
|
|
315
|
+
assert.ok(errorEvent)
|
|
316
|
+
assert.deepStrictEqual(errorEvent.detail.message, 'Network failed')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('translates with dynamic options', async () => {
|
|
320
|
+
setup()
|
|
321
|
+
const root = document.createElement('div')
|
|
322
|
+
root.innerHTML = /* html */`
|
|
323
|
+
<span data-i18n="hello">hello</span>
|
|
324
|
+
<p>
|
|
325
|
+
<span data-i18n="happy">happy</span>!!!
|
|
326
|
+
<span data-i18n="world">world</span>!!!
|
|
327
|
+
</p>
|
|
328
|
+
`
|
|
329
|
+
container.appendChild(root)
|
|
330
|
+
const translateContainer = document.createElement('div')
|
|
331
|
+
translateContainer.innerHTML = /* html */`
|
|
332
|
+
<ark-translate languages="es,en">
|
|
333
|
+
<template>{
|
|
334
|
+
"es": {
|
|
335
|
+
"default": {
|
|
336
|
+
"hello": "Hola",
|
|
337
|
+
"world": "Mundo"
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
"en": {
|
|
341
|
+
"default": {
|
|
342
|
+
"hello": "Hello",
|
|
343
|
+
"world": "World"
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}</template>
|
|
347
|
+
</ark-translate>
|
|
348
|
+
`
|
|
349
|
+
container.appendChild(translateContainer)
|
|
350
|
+
const translate = /** @type Translate **/ (
|
|
351
|
+
translateContainer.querySelector('ark-translate'))
|
|
352
|
+
|
|
353
|
+
await translate.transliterate({ language: 'es' })
|
|
354
|
+
|
|
355
|
+
const expectedRoot = document.createElement('div')
|
|
356
|
+
expectedRoot.innerHTML = /* html */`
|
|
357
|
+
<span data-i18n="hello">Hola</span>
|
|
358
|
+
<p>
|
|
359
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
360
|
+
<span data-i18n="world">Mundo</span>!!!
|
|
361
|
+
</p>
|
|
362
|
+
`
|
|
363
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
it('renders the translate component correctly', async () => {
|
|
367
|
+
setup();
|
|
368
|
+
const template = `
|
|
39
369
|
<ark-translate>
|
|
40
370
|
<template>{
|
|
371
|
+
"es": {
|
|
372
|
+
"default": {
|
|
373
|
+
"hello": "Hola",
|
|
374
|
+
"world": "Mundo"
|
|
375
|
+
}
|
|
376
|
+
},
|
|
41
377
|
"en": {
|
|
42
378
|
"default": {
|
|
43
379
|
"hello": "Hello",
|
|
44
380
|
"world": "World"
|
|
45
381
|
}
|
|
46
|
-
}
|
|
382
|
+
}
|
|
383
|
+
}</template>
|
|
384
|
+
</ark-translate>
|
|
385
|
+
`;
|
|
386
|
+
container.innerHTML = template
|
|
387
|
+
const translateContainer = container.querySelector('ark-translate')
|
|
388
|
+
const translate = /** @type Translate **/ (translateContainer)
|
|
389
|
+
|
|
390
|
+
assert.strictEqual(translate, translate.init())
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('renders the translate component with a single language', async () => {
|
|
394
|
+
setup();
|
|
395
|
+
const root = document.createElement('div')
|
|
396
|
+
root.innerHTML = /* html */`
|
|
397
|
+
<span data-i18n="hello">Hello</span>
|
|
398
|
+
<p>
|
|
399
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
400
|
+
<span data-i18n="world">World</span>!!!
|
|
401
|
+
</p>
|
|
402
|
+
`
|
|
403
|
+
container.appendChild(root)
|
|
404
|
+
|
|
405
|
+
const translateContainer = document.createElement('div')
|
|
406
|
+
translateContainer.innerHTML = /* html */`
|
|
407
|
+
<ark-translate languages="es,en">
|
|
408
|
+
<template>{
|
|
47
409
|
"es": {
|
|
48
410
|
"default": {
|
|
49
411
|
"hello": "Hola",
|
|
50
412
|
"world": "Mundo"
|
|
51
413
|
}
|
|
414
|
+
},
|
|
415
|
+
"en": {
|
|
416
|
+
"default": {
|
|
417
|
+
"hello": "Hello",
|
|
418
|
+
"world": "World"
|
|
419
|
+
}
|
|
52
420
|
}
|
|
53
421
|
}</template>
|
|
54
422
|
</ark-translate>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
translateContainer.querySelector('ark-translate'))
|
|
423
|
+
`
|
|
424
|
+
container.appendChild(translateContainer)
|
|
425
|
+
const translate = /** @type Translate **/ (translateContainer.querySelector('ark-translate'))
|
|
59
426
|
|
|
60
|
-
|
|
427
|
+
await translate.transliterate({ language: 'es' })
|
|
61
428
|
|
|
62
|
-
|
|
63
|
-
|
|
429
|
+
const expectedRoot = document.createElement('div')
|
|
430
|
+
expectedRoot.innerHTML = /* html */`
|
|
64
431
|
<span data-i18n="hello">Hola</span>
|
|
65
432
|
<p>
|
|
66
433
|
<span data-i18n="happy">Happy</span>!!!
|
|
67
434
|
<span data-i18n="world">Mundo</span>!!!
|
|
68
435
|
</p>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
436
|
+
`
|
|
437
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
438
|
+
})
|
|
72
439
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
440
|
+
it('renders the translate component with a nested namespace', async () => {
|
|
441
|
+
setup();
|
|
442
|
+
const root = document.createElement('div')
|
|
443
|
+
root.innerHTML = /* html */`
|
|
444
|
+
<span data-i18n="introModule:hello">Hello</span>
|
|
77
445
|
<p>
|
|
78
|
-
<span data-i18n="introModule:happy">
|
|
79
|
-
<span data-i18n="introModule:world">
|
|
446
|
+
<span data-i18n="introModule:happy">Happy</span>!!!
|
|
447
|
+
<span data-i18n="introModule:world">World</span>!!!
|
|
80
448
|
</p>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
449
|
+
`
|
|
450
|
+
container.appendChild(root)
|
|
451
|
+
|
|
452
|
+
const translateContainer = document.createElement('div')
|
|
453
|
+
translateContainer.innerHTML = /* html */`
|
|
454
|
+
<ark-translate languages="es,en">
|
|
86
455
|
<template>{
|
|
87
456
|
"es": {
|
|
88
457
|
"default": {
|
|
@@ -106,50 +475,51 @@ describe('Translate', () => {
|
|
|
106
475
|
}
|
|
107
476
|
}</template>
|
|
108
477
|
</ark-translate>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
translateContainer.querySelector('ark-translate'))
|
|
478
|
+
`
|
|
479
|
+
container.appendChild(translateContainer)
|
|
480
|
+
const translate = /** @type Translate **/ (translateContainer.querySelector('ark-translate'))
|
|
113
481
|
|
|
114
|
-
|
|
115
|
-
await translate.transliterate(options)
|
|
482
|
+
await translate.transliterate({ language: 'es' })
|
|
116
483
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<span data-i18n="introModule:hello">
|
|
484
|
+
const expectedRoot = document.createElement('div')
|
|
485
|
+
expectedRoot.innerHTML = /* html */`
|
|
486
|
+
<span data-i18n="introModule:hello">Quiubo</span>
|
|
120
487
|
<p>
|
|
121
|
-
<span data-i18n="introModule:happy">
|
|
122
|
-
<span data-i18n="introModule:world">
|
|
488
|
+
<span data-i18n="introModule:happy">Happy</span>!!!
|
|
489
|
+
<span data-i18n="introModule:world">Gente</span>!!!
|
|
123
490
|
</p>
|
|
124
|
-
|
|
125
|
-
|
|
491
|
+
`
|
|
492
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
493
|
+
})
|
|
126
494
|
|
|
127
|
-
|
|
495
|
+
it('renders the translate component with an invalid dictionary JSON', () => {
|
|
496
|
+
setup();
|
|
497
|
+
|
|
498
|
+
const template = `<ark-translate>
|
|
499
|
+
<template>{ "invalid": {} }</template>
|
|
500
|
+
</ark-translate>`
|
|
501
|
+
container.innerHTML = template
|
|
502
|
+
const translateContainer = container.querySelector('ark-translate')
|
|
503
|
+
const translate = /** @type Translate **/ (translateContainer)
|
|
128
504
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
<p>
|
|
132
|
-
<span data-i18n="unknown:happy">Happy</span>!!!
|
|
133
|
-
<span data-i18n="unknown:world">World</span>!!!
|
|
134
|
-
</p>
|
|
135
|
-
`
|
|
136
|
-
|
|
137
|
-
options = { language: 'es' }
|
|
138
|
-
await translate.transliterate(options)
|
|
505
|
+
assert.strictEqual(translate, translate.init())
|
|
506
|
+
})
|
|
139
507
|
|
|
140
|
-
|
|
141
|
-
|
|
508
|
+
it('translates with dynamic options using global fetch', async () => {
|
|
509
|
+
setup();
|
|
510
|
+
|
|
511
|
+
const root = document.createElement('div')
|
|
512
|
+
root.innerHTML = /* html */`
|
|
513
|
+
<span data-i18n="hello">Hello</span>
|
|
142
514
|
<p>
|
|
143
|
-
<span data-i18n="
|
|
144
|
-
<span data-i18n="
|
|
515
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
516
|
+
<span data-i18n="world">World</span>!!!
|
|
145
517
|
</p>
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const translateContainer = document.createElement('div')
|
|
152
|
-
translateContainer.innerHTML = /* html */`
|
|
518
|
+
`
|
|
519
|
+
container.appendChild(root)
|
|
520
|
+
|
|
521
|
+
const translateContainer = document.createElement('div')
|
|
522
|
+
translateContainer.innerHTML = /* html */`
|
|
153
523
|
<ark-translate languages="es,en">
|
|
154
524
|
<template>{
|
|
155
525
|
"es": {
|
|
@@ -166,60 +536,217 @@ describe('Translate', () => {
|
|
|
166
536
|
}
|
|
167
537
|
}</template>
|
|
168
538
|
</ark-translate>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
translateContainer.querySelector('ark-translate'))
|
|
173
|
-
const mockEvent = { target: { value: 'en' }, stopPropagation: () => {} }
|
|
174
|
-
let givenOptions = null
|
|
175
|
-
translate.transliterate = async (options) => {
|
|
176
|
-
givenOptions = options
|
|
177
|
-
}
|
|
539
|
+
`
|
|
540
|
+
container.appendChild(translateContainer)
|
|
541
|
+
const translate = /** @type Translate **/ (translateContainer.querySelector('ark-translate'))
|
|
178
542
|
|
|
179
|
-
|
|
543
|
+
await translate.transliterate({ language: 'es' })
|
|
180
544
|
|
|
181
|
-
|
|
182
|
-
|
|
545
|
+
const expectedRoot = document.createElement('div')
|
|
546
|
+
expectedRoot.innerHTML = /* html */`
|
|
547
|
+
<span data-i18n="hello">Hola</span>
|
|
548
|
+
<p>
|
|
549
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
550
|
+
<span data-i18n="world">Mundo</span>!!!
|
|
551
|
+
</p>
|
|
552
|
+
`
|
|
553
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
it('renders the translate component with empty dictionaries', async () => {
|
|
557
|
+
setup();
|
|
558
|
+
|
|
559
|
+
const template = `<ark-translate>
|
|
560
|
+
<template>{ "es": {} }</template>
|
|
561
|
+
</ark-translate>`
|
|
562
|
+
container.innerHTML = template
|
|
563
|
+
const translateContainer = container.querySelector('ark-translate')
|
|
564
|
+
const translate = /** @type Translate **/ (translateContainer)
|
|
565
|
+
|
|
566
|
+
assert.strictEqual(translate, translate.init())
|
|
567
|
+
})
|
|
183
568
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
569
|
+
it('renders the translate component with an empty dictionary', async () => {
|
|
570
|
+
setup();
|
|
571
|
+
|
|
572
|
+
const root = document.createElement('div')
|
|
573
|
+
root.innerHTML = /* html */`
|
|
574
|
+
<span data-i18n="hello">Hello</span>
|
|
188
575
|
<p>
|
|
189
|
-
<span data-i18n="happy">
|
|
190
|
-
<span data-i18n="world">
|
|
576
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
577
|
+
<span data-i18n="world">World</span>!!!
|
|
191
578
|
</p>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
happy: 'Feliz'
|
|
207
|
-
})
|
|
208
|
-
})
|
|
209
|
-
translate.init({
|
|
210
|
-
global: { fetch: mockFetch, document }
|
|
211
|
-
})
|
|
579
|
+
`
|
|
580
|
+
container.appendChild(root)
|
|
581
|
+
|
|
582
|
+
const translateContainer = document.createElement('div')
|
|
583
|
+
translateContainer.innerHTML = /* html */`
|
|
584
|
+
<ark-translate languages="es,en">
|
|
585
|
+
<template>{
|
|
586
|
+
"es": {},
|
|
587
|
+
"en": {}
|
|
588
|
+
}</template>
|
|
589
|
+
</ark-translate>
|
|
590
|
+
`
|
|
591
|
+
container.appendChild(translateContainer)
|
|
592
|
+
const translate = /** @type Translate **/ (translateContainer.querySelector('ark-translate'))
|
|
212
593
|
|
|
213
|
-
|
|
594
|
+
await translate.transliterate({ language: 'es' })
|
|
214
595
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
<span data-i18n="hello">
|
|
596
|
+
const expectedRoot = document.createElement('div')
|
|
597
|
+
expectedRoot.innerHTML = /* html */`
|
|
598
|
+
<span data-i18n="hello">Hello</span>
|
|
218
599
|
<p>
|
|
219
|
-
<span data-i18n="happy">
|
|
220
|
-
<span data-i18n="world">
|
|
600
|
+
<span data-i18n="happy">Happy</span>!!!
|
|
601
|
+
<span data-i18n="world">World</span>!!!
|
|
221
602
|
</p>
|
|
222
|
-
|
|
223
|
-
|
|
603
|
+
`
|
|
604
|
+
assert.deepStrictEqual(root, expectedRoot)
|
|
605
|
+
})
|
|
606
|
+
|
|
607
|
+
it('does not render language options for an empty language list', () => {
|
|
608
|
+
setup()
|
|
609
|
+
container.innerHTML = '<ark-translate languages=""></ark-translate>'
|
|
610
|
+
const translate = container.querySelector('ark-translate')
|
|
611
|
+
|
|
612
|
+
translate.init()
|
|
613
|
+
|
|
614
|
+
const select = translate.querySelector('select')
|
|
615
|
+
assert.equal(select, null)
|
|
616
|
+
})
|
|
617
|
+
|
|
618
|
+
it('does nothing when the configured transliterate root does not exist', async () => {
|
|
619
|
+
setup()
|
|
620
|
+
const root = document.createElement('div')
|
|
621
|
+
root.innerHTML = /* html */`
|
|
622
|
+
<span data-i18n="hello">Hello</span>
|
|
623
|
+
`
|
|
624
|
+
root.id = 'translations'
|
|
625
|
+
container.appendChild(root)
|
|
626
|
+
const translateContainer = document.createElement('div')
|
|
627
|
+
translateContainer.innerHTML = '<ark-translate></ark-translate>'
|
|
628
|
+
container.appendChild(translateContainer)
|
|
629
|
+
const translate = /** @type Translate **/ (
|
|
630
|
+
translateContainer.querySelector('ark-translate'))
|
|
631
|
+
|
|
632
|
+
let called = false
|
|
633
|
+
translate.resolveDictionary = async () => {
|
|
634
|
+
called = true
|
|
635
|
+
return {}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
await translate.transliterate({ root: '#missing-root' })
|
|
639
|
+
|
|
640
|
+
assert.equal(called, false)
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
it('returns an empty dictionary when no fetch API is available', async () => {
|
|
644
|
+
setup()
|
|
645
|
+
const translateContainer = document.createElement('div')
|
|
646
|
+
translateContainer.innerHTML = '<ark-translate></ark-translate>'
|
|
647
|
+
container.appendChild(translateContainer)
|
|
648
|
+
const translate = /** @type Translate **/ (
|
|
649
|
+
translateContainer.querySelector('ark-translate'))
|
|
650
|
+
|
|
651
|
+
translate.init({ global: { document } })
|
|
652
|
+
|
|
653
|
+
const dictionary = await translate.resolveDictionary('es', 'default')
|
|
654
|
+
assert.deepStrictEqual(dictionary, {})
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
it('keeps original text when translation endpoint returns a non-ok response', async () => {
|
|
658
|
+
setup()
|
|
659
|
+
const root = document.createElement('div')
|
|
660
|
+
root.innerHTML = /* html */`
|
|
661
|
+
<span data-i18n="hello">Hello</span>
|
|
662
|
+
`
|
|
663
|
+
root.id = 'translate-root'
|
|
664
|
+
container.appendChild(root)
|
|
665
|
+
const translateContainer = document.createElement('div')
|
|
666
|
+
translateContainer.innerHTML = '<ark-translate languages="es"></ark-translate>'
|
|
667
|
+
container.appendChild(translateContainer)
|
|
668
|
+
const translate = /** @type Translate **/ (
|
|
669
|
+
translateContainer.querySelector('ark-translate'))
|
|
670
|
+
let requestedUrl = null
|
|
671
|
+
|
|
672
|
+
translate.init({
|
|
673
|
+
root: '#translate-root',
|
|
674
|
+
global: {
|
|
675
|
+
document,
|
|
676
|
+
fetch: async (url) => {
|
|
677
|
+
requestedUrl = url
|
|
678
|
+
return { ok: false }
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
await translate.transliterate({ language: 'es' })
|
|
684
|
+
|
|
685
|
+
assert.equal(requestedUrl, '/locales/es/default.json')
|
|
686
|
+
assert.equal(root.querySelector('[data-i18n="hello"]').textContent, 'Hello')
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
it('stores an empty dictionary cache entry when fetch returns null JSON', async () => {
|
|
690
|
+
setup()
|
|
691
|
+
const translateContainer = document.createElement('div')
|
|
692
|
+
translateContainer.innerHTML = '<ark-translate></ark-translate>'
|
|
693
|
+
container.appendChild(translateContainer)
|
|
694
|
+
const translate = /** @type Translate **/ (
|
|
695
|
+
translateContainer.querySelector('ark-translate'))
|
|
696
|
+
|
|
697
|
+
translate.init({
|
|
698
|
+
global: {
|
|
699
|
+
document,
|
|
700
|
+
fetch: async () => ({
|
|
701
|
+
ok: true,
|
|
702
|
+
json: async () => null
|
|
703
|
+
})
|
|
704
|
+
}
|
|
224
705
|
})
|
|
706
|
+
|
|
707
|
+
const dictionary = await translate.resolveDictionary('es', 'default')
|
|
708
|
+
|
|
709
|
+
assert.equal(dictionary, null)
|
|
710
|
+
assert.deepStrictEqual(translate.dictionary.es.default, {})
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
it('reuses cached dictionaries for repeated transliterations', async () => {
|
|
714
|
+
setup()
|
|
715
|
+
const root = document.createElement('div')
|
|
716
|
+
root.innerHTML = /* html */`
|
|
717
|
+
<span data-i18n="hello">Hello</span>
|
|
718
|
+
<span data-i18n="world">World</span>
|
|
719
|
+
`
|
|
720
|
+
root.id = 'translate-root'
|
|
721
|
+
container.appendChild(root)
|
|
722
|
+
const translateContainer = document.createElement('div')
|
|
723
|
+
translateContainer.innerHTML = '<ark-translate></ark-translate>'
|
|
724
|
+
container.appendChild(translateContainer)
|
|
725
|
+
const translate = /** @type Translate **/ (
|
|
726
|
+
translateContainer.querySelector('ark-translate'))
|
|
727
|
+
|
|
728
|
+
let fetchCalls = 0
|
|
729
|
+
translate.init({
|
|
730
|
+
root: '#translate-root',
|
|
731
|
+
global: {
|
|
732
|
+
document,
|
|
733
|
+
fetch: async () => {
|
|
734
|
+
fetchCalls += 1
|
|
735
|
+
return {
|
|
736
|
+
ok: true,
|
|
737
|
+
json: async () => ({
|
|
738
|
+
hello: 'Hola',
|
|
739
|
+
world: 'Mundo'
|
|
740
|
+
})
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
|
|
746
|
+
await translate.transliterate({ language: 'es' })
|
|
747
|
+
await translate.transliterate({ language: 'es' })
|
|
748
|
+
|
|
749
|
+
assert.equal(fetchCalls, 1)
|
|
750
|
+
assert.equal(root.querySelector('[data-i18n="hello"]').textContent, 'Hola')
|
|
751
|
+
assert.equal(root.querySelector('[data-i18n="world"]').textContent, 'Mundo')
|
|
225
752
|
})
|