@tolgee/core 5.0.0-rc.af99eec.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -0
- package/README.njk.md +61 -0
- package/dist/tolgee.cjs.js +733 -357
- package/dist/tolgee.cjs.js.map +1 -1
- package/dist/tolgee.cjs.min.js +1 -1
- package/dist/tolgee.cjs.min.js.map +1 -1
- package/dist/{tolgee.esm.mjs → tolgee.esm.js} +732 -352
- package/dist/tolgee.esm.js.map +1 -0
- package/dist/tolgee.esm.min.mjs +1 -1
- package/dist/tolgee.esm.min.mjs.map +1 -1
- package/dist/tolgee.umd.js +733 -357
- package/dist/tolgee.umd.js.map +1 -1
- package/dist/tolgee.umd.min.js +1 -1
- package/dist/tolgee.umd.min.js.map +1 -1
- package/lib/Controller/Cache/Cache.d.ts +10 -9
- package/lib/Controller/Controller.d.ts +104 -45
- package/lib/Controller/Events/EventEmitter.d.ts +6 -0
- package/lib/Controller/Events/EventEmitterSelective.d.ts +7 -0
- package/lib/Controller/Events/Events.d.ts +14 -0
- package/lib/Controller/Plugins/Plugins.d.ts +12 -25
- package/lib/Controller/State/State.d.ts +27 -9
- package/lib/Controller/State/initState.d.ts +46 -15
- package/lib/Controller/State/observerOptions.d.ts +41 -0
- package/lib/Controller/ValueObserver.d.ts +5 -5
- package/lib/FormatSimple/FormatError.d.ts +7 -0
- package/lib/FormatSimple/FormatSimple.d.ts +2 -0
- package/lib/FormatSimple/formatParser.d.ts +1 -0
- package/lib/FormatSimple/formatter.d.ts +2 -0
- package/lib/TolgeeCore.d.ts +204 -0
- package/lib/TranslateParams.d.ts +1 -1
- package/lib/helpers.d.ts +8 -0
- package/lib/index.d.ts +4 -4
- package/lib/types/cache.d.ts +25 -0
- package/lib/types/events.d.ts +66 -0
- package/lib/types/general.d.ts +34 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/plugin.d.ts +127 -0
- package/package.json +5 -4
- package/src/Controller/Cache/Cache.ts +39 -34
- package/src/Controller/Cache/helpers.ts +6 -6
- package/src/Controller/Controller.ts +81 -53
- package/src/Controller/Events/EventEmitter.ts +34 -0
- package/src/Controller/Events/EventEmitterSelective.test.ts +110 -0
- package/src/Controller/Events/EventEmitterSelective.ts +132 -0
- package/src/Controller/Events/Events.ts +69 -0
- package/src/Controller/Plugins/Plugins.ts +182 -133
- package/src/Controller/State/State.ts +43 -26
- package/src/Controller/State/initState.ts +97 -25
- package/src/Controller/State/observerOptions.ts +66 -0
- package/src/Controller/ValueObserver.ts +5 -2
- package/src/FormatSimple/FormatError.ts +26 -0
- package/src/FormatSimple/FormatSimple.ts +13 -0
- package/src/FormatSimple/formatParser.ts +133 -0
- package/src/FormatSimple/formatter.test.ts +190 -0
- package/src/FormatSimple/formatter.ts +19 -0
- package/src/TolgeeCore.ts +267 -0
- package/src/TranslateParams.test.ts +9 -12
- package/src/TranslateParams.ts +6 -5
- package/src/__test/backend.test.ts +6 -6
- package/src/__test/cache.test.ts +190 -0
- package/src/__test/client.test.ts +2 -2
- package/src/__test/events.test.ts +32 -7
- package/src/__test/format.simple.test.ts +14 -0
- package/src/__test/formatError.test.ts +61 -0
- package/src/__test/initialization.test.ts +15 -3
- package/src/__test/languageDetection.test.ts +14 -8
- package/src/__test/languageStorage.test.ts +10 -11
- package/src/__test/languages.test.ts +30 -6
- package/src/__test/loading.test.ts +2 -2
- package/src/__test/{namespacesFallback.test.ts → namespaces.fallback.test.ts} +10 -8
- package/src/__test/namespaces.test.ts +30 -7
- package/src/__test/options.test.ts +64 -0
- package/src/__test/plugins.test.ts +29 -18
- package/src/helpers.ts +53 -0
- package/src/index.ts +4 -10
- package/src/types/cache.ts +37 -0
- package/src/types/events.ts +85 -0
- package/src/types/general.ts +50 -0
- package/src/types/index.ts +19 -0
- package/src/types/plugin.ts +181 -0
- package/dist/tolgee.esm.mjs.map +0 -1
- package/lib/Controller/State/helpers.d.ts +0 -6
- package/lib/Events/EventEmitter.d.ts +0 -6
- package/lib/Events/EventEmitterSelective.d.ts +0 -15
- package/lib/Events/Events.d.ts +0 -50
- package/lib/Tolgee.d.ts +0 -2
- package/lib/constants.d.ts +0 -5
- package/lib/types.d.ts +0 -274
- package/src/Controller/State/helpers.ts +0 -41
- package/src/Events/EventEmitter.ts +0 -27
- package/src/Events/EventEmitterSelective.test.ts +0 -108
- package/src/Events/EventEmitterSelective.ts +0 -160
- package/src/Events/Events.ts +0 -66
- package/src/Tolgee.ts +0 -77
- package/src/constants.ts +0 -7
- package/src/types.ts +0 -380
package/dist/tolgee.umd.js
CHANGED
|
@@ -4,25 +4,18 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tolgee/core"] = {}));
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
const emit = (data) => {
|
|
21
|
-
handlers.forEach((handler) => handler({ value: data }));
|
|
22
|
-
};
|
|
23
|
-
return Object.freeze({ listen, emit });
|
|
7
|
+
function isPromise(value) {
|
|
8
|
+
return Boolean(value && typeof value.then === 'function');
|
|
9
|
+
}
|
|
10
|
+
const valueOrPromise = (value, callback) => {
|
|
11
|
+
if (isPromise(value)) {
|
|
12
|
+
return Promise.resolve(value).then(callback);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return callback(value);
|
|
16
|
+
}
|
|
24
17
|
};
|
|
25
|
-
|
|
18
|
+
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
|
|
26
19
|
function isObject(item) {
|
|
27
20
|
return typeof item === 'object' && !Array.isArray(item) && item !== null;
|
|
28
21
|
}
|
|
@@ -49,22 +42,40 @@
|
|
|
49
42
|
function unique(arr) {
|
|
50
43
|
return Array.from(new Set(arr));
|
|
51
44
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const currNum = map.get(value) || 0;
|
|
55
|
-
map.set(value, currNum + 1);
|
|
45
|
+
function sanitizeUrl(url) {
|
|
46
|
+
return url ? url.replace(/\/+$/, '') : url;
|
|
56
47
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (currNum <= 0) {
|
|
61
|
-
map.delete(value);
|
|
48
|
+
function getErrorMessage(error) {
|
|
49
|
+
if (typeof error === 'string') {
|
|
50
|
+
return error;
|
|
62
51
|
}
|
|
63
|
-
else {
|
|
64
|
-
|
|
52
|
+
else if (typeof (error === null || error === void 0 ? void 0 : error.message) === 'string') {
|
|
53
|
+
return error.message;
|
|
65
54
|
}
|
|
66
55
|
}
|
|
67
|
-
|
|
56
|
+
|
|
57
|
+
const EventEmitter = (isActive) => {
|
|
58
|
+
let handlers = [];
|
|
59
|
+
const listen = (handler) => {
|
|
60
|
+
const handlerWrapper = (e) => {
|
|
61
|
+
handler(e);
|
|
62
|
+
};
|
|
63
|
+
handlers.push(handlerWrapper);
|
|
64
|
+
return {
|
|
65
|
+
unsubscribe: () => {
|
|
66
|
+
handlers = handlers.filter((i) => handlerWrapper !== i);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
const emit = (data) => {
|
|
71
|
+
if (isActive()) {
|
|
72
|
+
handlers.forEach((handler) => handler({ value: data }));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return Object.freeze({ listen, emit });
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const EventEmitterSelective = (isActive, getFallbackNs, getDefaultNs) => {
|
|
68
79
|
const listeners = new Set();
|
|
69
80
|
const partialListeners = new Set();
|
|
70
81
|
const listen = (handler) => {
|
|
@@ -81,8 +92,7 @@
|
|
|
81
92
|
fn: (e) => {
|
|
82
93
|
handler(e);
|
|
83
94
|
},
|
|
84
|
-
|
|
85
|
-
namespaces: new Map(),
|
|
95
|
+
namespaces: new Set(),
|
|
86
96
|
};
|
|
87
97
|
partialListeners.add(handlerWrapper);
|
|
88
98
|
const result = {
|
|
@@ -90,105 +100,85 @@
|
|
|
90
100
|
partialListeners.delete(handlerWrapper);
|
|
91
101
|
},
|
|
92
102
|
subscribeNs: (ns) => {
|
|
93
|
-
getFallbackArray(ns).forEach((val) =>
|
|
94
|
-
return result;
|
|
95
|
-
},
|
|
96
|
-
unsubscribeNs: (ns) => {
|
|
97
|
-
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
|
|
98
|
-
return result;
|
|
99
|
-
},
|
|
100
|
-
subscribeKey: (descriptor) => {
|
|
101
|
-
const { key, ns } = descriptor;
|
|
102
|
-
incrementInMap(handlerWrapper.keys, key);
|
|
103
|
-
getFallbackArray(ns).forEach((val) => incrementInMap(handlerWrapper.namespaces, val));
|
|
103
|
+
getFallbackArray(ns).forEach((val) => handlerWrapper.namespaces.add(val));
|
|
104
104
|
if (ns === undefined) {
|
|
105
|
-
// subscribing to
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
return result;
|
|
109
|
-
},
|
|
110
|
-
unsubscribeKey: (descriptor) => {
|
|
111
|
-
const { key, ns } = descriptor;
|
|
112
|
-
decrementInMap(handlerWrapper.keys, key);
|
|
113
|
-
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
|
|
114
|
-
if (ns === undefined) {
|
|
115
|
-
// subscribing to all namespaces
|
|
116
|
-
decrementInMap(handlerWrapper.namespaces, undefined);
|
|
105
|
+
// subscribing to default ns
|
|
106
|
+
handlerWrapper.namespaces.add(getDefaultNs());
|
|
117
107
|
}
|
|
118
108
|
return result;
|
|
119
109
|
},
|
|
120
110
|
};
|
|
121
111
|
return result;
|
|
122
112
|
};
|
|
123
|
-
const callHandlers = (
|
|
113
|
+
const callHandlers = (ns) => {
|
|
114
|
+
// everything is implicitly subscribed to fallbacks
|
|
115
|
+
// as it can always fall through to it
|
|
116
|
+
const fallbackNamespaces = new Set(getFallbackNs());
|
|
124
117
|
partialListeners.forEach((handler) => {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const keyMentioned = key !== undefined;
|
|
129
|
-
const keyMatches = key === undefined || handler.keys.has(key) || handler.keys.size === 0;
|
|
130
|
-
if ((!nsMentioned || nsMatches) && (!keyMentioned || keyMatches)) {
|
|
118
|
+
const nsMatches = ns === undefined ||
|
|
119
|
+
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => fallbackNamespaces.has(ns) || handler.namespaces.has(ns))) !== -1;
|
|
120
|
+
if (nsMatches) {
|
|
131
121
|
handler.fn({ value: undefined });
|
|
132
122
|
}
|
|
133
123
|
});
|
|
134
124
|
};
|
|
135
125
|
let queue = [];
|
|
126
|
+
// merge events in queue into one event
|
|
136
127
|
const solveQueue = () => {
|
|
137
128
|
if (queue.length === 0) {
|
|
138
129
|
return;
|
|
139
130
|
}
|
|
131
|
+
const queueCopy = queue;
|
|
132
|
+
queue = [];
|
|
140
133
|
listeners.forEach((handler) => {
|
|
141
134
|
handler({ value: undefined });
|
|
142
135
|
});
|
|
143
|
-
let namespaces =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
136
|
+
let namespaces = new Set();
|
|
137
|
+
queueCopy.forEach((ns) => {
|
|
138
|
+
if (ns === undefined) {
|
|
139
|
+
// when no ns specified, it affects all namespaces
|
|
147
140
|
namespaces = undefined;
|
|
148
141
|
}
|
|
149
142
|
else if (namespaces !== undefined) {
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.key) === undefined) {
|
|
153
|
-
keys = undefined;
|
|
143
|
+
ns.forEach((ns) => namespaces.add(ns));
|
|
154
144
|
}
|
|
155
|
-
else if (keys !== undefined) {
|
|
156
|
-
keys = [...keys, descriptor.key];
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
(keys || [undefined]).forEach((key) => {
|
|
160
|
-
callHandlers(key, namespaces);
|
|
161
145
|
});
|
|
162
|
-
|
|
146
|
+
const namespacesArray = namespaces
|
|
147
|
+
? Array.from(namespaces.keys())
|
|
148
|
+
: undefined;
|
|
149
|
+
callHandlers(namespacesArray);
|
|
163
150
|
};
|
|
164
|
-
const emit = (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
Promise.resolve().then(() => {
|
|
151
|
+
const emit = (ns, delayed) => {
|
|
152
|
+
if (isActive()) {
|
|
153
|
+
queue.push(ns);
|
|
154
|
+
if (!delayed) {
|
|
171
155
|
solveQueue();
|
|
172
|
-
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
setTimeout(solveQueue, 0);
|
|
159
|
+
}
|
|
173
160
|
}
|
|
174
161
|
};
|
|
175
162
|
return Object.freeze({ listenSome, listen, emit });
|
|
176
163
|
};
|
|
177
164
|
|
|
178
|
-
const Events = () => {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
165
|
+
const Events = (getFallbackNs, getDefaultNs) => {
|
|
166
|
+
let emitterActive = true;
|
|
167
|
+
function isActive() {
|
|
168
|
+
return emitterActive;
|
|
169
|
+
}
|
|
170
|
+
const onPendingLanguageChange = EventEmitter(isActive);
|
|
171
|
+
const onLanguageChange = EventEmitter(isActive);
|
|
172
|
+
const onLoadingChange = EventEmitter(isActive);
|
|
173
|
+
const onFetchingChange = EventEmitter(isActive);
|
|
174
|
+
const onInitialLoaded = EventEmitter(isActive);
|
|
175
|
+
const onRunningChange = EventEmitter(isActive);
|
|
176
|
+
const onCacheChange = EventEmitter(isActive);
|
|
177
|
+
const onUpdate = EventEmitterSelective(isActive, getFallbackNs, getDefaultNs);
|
|
178
|
+
onInitialLoaded.listen(() => onUpdate.emit());
|
|
179
|
+
onLanguageChange.listen(() => onUpdate.emit());
|
|
190
180
|
onCacheChange.listen(({ value }) => {
|
|
191
|
-
|
|
181
|
+
onUpdate.emit([value.namespace], true);
|
|
192
182
|
});
|
|
193
183
|
const on = (event, handler) => {
|
|
194
184
|
switch (event) {
|
|
@@ -206,20 +196,23 @@
|
|
|
206
196
|
return onRunningChange.listen(handler);
|
|
207
197
|
case 'cache':
|
|
208
198
|
return onCacheChange.listen(handler);
|
|
209
|
-
case '
|
|
210
|
-
return
|
|
199
|
+
case 'update':
|
|
200
|
+
return onUpdate.listen(handler);
|
|
211
201
|
}
|
|
212
202
|
};
|
|
203
|
+
function setEmmiterActive(active) {
|
|
204
|
+
emitterActive = active;
|
|
205
|
+
}
|
|
213
206
|
return Object.freeze({
|
|
214
207
|
onPendingLanguageChange,
|
|
215
208
|
onLanguageChange,
|
|
216
|
-
onKeyChange,
|
|
217
|
-
onKeyUpdate,
|
|
218
209
|
onLoadingChange,
|
|
219
210
|
onFetchingChange,
|
|
220
211
|
onInitialLoaded,
|
|
221
212
|
onRunningChange,
|
|
222
213
|
onCacheChange,
|
|
214
|
+
onUpdate,
|
|
215
|
+
setEmmiterActive,
|
|
223
216
|
on,
|
|
224
217
|
});
|
|
225
218
|
};
|
|
@@ -232,7 +225,7 @@
|
|
|
232
225
|
return;
|
|
233
226
|
}
|
|
234
227
|
if (typeof value === 'object') {
|
|
235
|
-
|
|
228
|
+
flattenTranslations(value).forEach((flatValue, flatKey) => {
|
|
236
229
|
result.set(key + '.' + flatKey, flatValue);
|
|
237
230
|
});
|
|
238
231
|
return;
|
|
@@ -242,7 +235,9 @@
|
|
|
242
235
|
return result;
|
|
243
236
|
};
|
|
244
237
|
const decodeCacheKey = (key) => {
|
|
245
|
-
const [firstPart,
|
|
238
|
+
const [firstPart, ...rest] = key.split(':');
|
|
239
|
+
// if namespaces contains ":" it won't get lost
|
|
240
|
+
const secondPart = rest.join(':');
|
|
246
241
|
return { language: firstPart, namespace: secondPart || '' };
|
|
247
242
|
};
|
|
248
243
|
const encodeCacheKey = ({ language, namespace, }) => {
|
|
@@ -274,13 +269,14 @@
|
|
|
274
269
|
}
|
|
275
270
|
}
|
|
276
271
|
function invalidate() {
|
|
272
|
+
asyncRequests.clear();
|
|
277
273
|
version += 1;
|
|
278
274
|
}
|
|
279
|
-
function addRecordInternal(descriptor, data,
|
|
275
|
+
function addRecordInternal(descriptor, data, recordVersion) {
|
|
280
276
|
const cacheKey = encodeCacheKey(descriptor);
|
|
281
277
|
cache.set(cacheKey, {
|
|
282
278
|
data: flattenTranslations(data),
|
|
283
|
-
version:
|
|
279
|
+
version: recordVersion,
|
|
284
280
|
});
|
|
285
281
|
onCacheChange.emit(descriptor);
|
|
286
282
|
}
|
|
@@ -296,7 +292,7 @@
|
|
|
296
292
|
}
|
|
297
293
|
function getRecord(descriptor) {
|
|
298
294
|
var _a;
|
|
299
|
-
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data;
|
|
295
|
+
return (_a = cache.get(encodeCacheKey(withDefaultNs(descriptor)))) === null || _a === void 0 ? void 0 : _a.data;
|
|
300
296
|
}
|
|
301
297
|
function getTranslation(descriptor, key) {
|
|
302
298
|
var _a;
|
|
@@ -309,11 +305,11 @@
|
|
|
309
305
|
const value = (_a = cache
|
|
310
306
|
.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data.get(key);
|
|
311
307
|
if (value !== undefined && value !== null) {
|
|
312
|
-
return namespace;
|
|
308
|
+
return [namespace];
|
|
313
309
|
}
|
|
314
310
|
}
|
|
315
311
|
}
|
|
316
|
-
return
|
|
312
|
+
return unique(namespaces);
|
|
317
313
|
}
|
|
318
314
|
function getTranslationFallback(namespaces, languages, key) {
|
|
319
315
|
var _a;
|
|
@@ -334,9 +330,6 @@
|
|
|
334
330
|
record === null || record === void 0 ? void 0 : record.set(key, value);
|
|
335
331
|
onCacheChange.emit(Object.assign(Object.assign({}, descriptor), { key }));
|
|
336
332
|
}
|
|
337
|
-
function clear() {
|
|
338
|
-
cache.clear();
|
|
339
|
-
}
|
|
340
333
|
function isFetching(ns) {
|
|
341
334
|
if (isInitialLoading()) {
|
|
342
335
|
return true;
|
|
@@ -359,24 +352,20 @@
|
|
|
359
352
|
}));
|
|
360
353
|
}));
|
|
361
354
|
}
|
|
362
|
-
|
|
355
|
+
/**
|
|
356
|
+
* Fetches production data
|
|
357
|
+
*/
|
|
358
|
+
function fetchProd(keyObject) {
|
|
363
359
|
let dataPromise = undefined;
|
|
364
360
|
if (!dataPromise) {
|
|
365
361
|
const staticDataValue = staticData[encodeCacheKey(keyObject)];
|
|
366
362
|
if (typeof staticDataValue === 'function') {
|
|
367
363
|
dataPromise = staticDataValue();
|
|
368
364
|
}
|
|
369
|
-
else if (staticDataValue) {
|
|
370
|
-
dataPromise = Promise.resolve(staticDataValue);
|
|
371
|
-
}
|
|
372
365
|
}
|
|
373
366
|
if (!dataPromise) {
|
|
374
367
|
dataPromise = backendGetRecord(keyObject);
|
|
375
368
|
}
|
|
376
|
-
if (!dataPromise) {
|
|
377
|
-
// return empty data, so we know it has already been attempted to fetch
|
|
378
|
-
dataPromise = Promise.resolve({});
|
|
379
|
-
}
|
|
380
369
|
return dataPromise;
|
|
381
370
|
}
|
|
382
371
|
function fetchData(keyObject, isDev) {
|
|
@@ -386,12 +375,12 @@
|
|
|
386
375
|
dataPromise = (_a = backendGetDevRecord(keyObject)) === null || _a === void 0 ? void 0 : _a.catch(() => {
|
|
387
376
|
// eslint-disable-next-line no-console
|
|
388
377
|
console.warn(`Tolgee: Failed to fetch data from dev backend`);
|
|
389
|
-
// fallback to
|
|
390
|
-
return
|
|
378
|
+
// fallback to prod fetch if dev fails
|
|
379
|
+
return fetchProd(keyObject);
|
|
391
380
|
});
|
|
392
381
|
}
|
|
393
382
|
if (!dataPromise) {
|
|
394
|
-
dataPromise =
|
|
383
|
+
dataPromise = fetchProd(keyObject);
|
|
395
384
|
}
|
|
396
385
|
return dataPromise;
|
|
397
386
|
}
|
|
@@ -408,7 +397,7 @@
|
|
|
408
397
|
cacheKey,
|
|
409
398
|
};
|
|
410
399
|
}
|
|
411
|
-
const dataPromise = fetchData(keyObject, isDev);
|
|
400
|
+
const dataPromise = fetchData(keyObject, isDev) || Promise.resolve(undefined);
|
|
412
401
|
asyncRequests.set(cacheKey, dataPromise);
|
|
413
402
|
return {
|
|
414
403
|
new: true,
|
|
@@ -421,12 +410,19 @@
|
|
|
421
410
|
loadingObserver.notify();
|
|
422
411
|
const results = await Promise.all(withPromises.map((val) => val.promise));
|
|
423
412
|
withPromises.forEach((value, i) => {
|
|
424
|
-
|
|
413
|
+
const promiseChanged = asyncRequests.get(value.cacheKey) !== value.promise;
|
|
414
|
+
// if promise has changed in between, it means cache been invalidated or
|
|
415
|
+
// new data are being fetched
|
|
416
|
+
if (value.new && !promiseChanged) {
|
|
425
417
|
asyncRequests.delete(value.cacheKey);
|
|
426
418
|
const data = results[i];
|
|
427
419
|
if (data) {
|
|
428
420
|
addRecord(value.keyObject, data);
|
|
429
421
|
}
|
|
422
|
+
else if (!getRecord(value.keyObject)) {
|
|
423
|
+
// if no data exist, put empty object
|
|
424
|
+
addRecord(value.keyObject, {});
|
|
425
|
+
}
|
|
430
426
|
}
|
|
431
427
|
});
|
|
432
428
|
fetchingObserver.notify();
|
|
@@ -452,27 +448,85 @@
|
|
|
452
448
|
isFetching,
|
|
453
449
|
isLoading,
|
|
454
450
|
loadRecords,
|
|
455
|
-
clear,
|
|
456
451
|
getAllRecords,
|
|
457
452
|
});
|
|
458
453
|
};
|
|
459
454
|
|
|
460
|
-
|
|
461
|
-
|
|
455
|
+
/******************************************************************************
|
|
456
|
+
Copyright (c) Microsoft Corporation.
|
|
457
|
+
|
|
458
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
459
|
+
purpose with or without fee is hereby granted.
|
|
460
|
+
|
|
461
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
462
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
463
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
464
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
465
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
466
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
467
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
468
|
+
***************************************************************************** */
|
|
469
|
+
|
|
470
|
+
function __rest(s, e) {
|
|
471
|
+
var t = {};
|
|
472
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
473
|
+
t[p] = s[p];
|
|
474
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
475
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
476
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
477
|
+
t[p[i]] = s[p[i]];
|
|
478
|
+
}
|
|
479
|
+
return t;
|
|
462
480
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
481
|
+
|
|
482
|
+
const defaultObserverOptions = {
|
|
483
|
+
tagAttributes: {
|
|
484
|
+
textarea: ['placeholder'],
|
|
485
|
+
input: ['value', 'placeholder'],
|
|
486
|
+
img: ['alt'],
|
|
487
|
+
'*': ['aria-label', 'title'],
|
|
488
|
+
},
|
|
489
|
+
restrictedElements: ['script', 'style'],
|
|
490
|
+
highlightKeys: ['Alt'],
|
|
491
|
+
highlightColor: 'rgb(255, 0, 0)',
|
|
492
|
+
highlightWidth: 5,
|
|
493
|
+
inputPrefix: '%-%tolgee:',
|
|
494
|
+
inputSuffix: '%-%',
|
|
495
|
+
passToParent: ['option', 'optgroup'],
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
const DEFAULT_FORMAT_ERROR = 'invalid';
|
|
499
|
+
const defaultValues = {
|
|
500
|
+
defaultNs: '',
|
|
501
|
+
observerOptions: defaultObserverOptions,
|
|
502
|
+
observerType: 'invisible',
|
|
503
|
+
onFormatError: DEFAULT_FORMAT_ERROR,
|
|
504
|
+
};
|
|
505
|
+
const combineOptions = (...states) => {
|
|
506
|
+
let result = {};
|
|
507
|
+
states.forEach((state) => {
|
|
508
|
+
result = Object.assign(Object.assign(Object.assign({}, result), state), { observerOptions: Object.assign(Object.assign({}, result.observerOptions), state === null || state === void 0 ? void 0 : state.observerOptions) });
|
|
509
|
+
});
|
|
510
|
+
return result;
|
|
511
|
+
};
|
|
512
|
+
const initState = (options, previousState) => {
|
|
513
|
+
const initialOptions = combineOptions(defaultValues, previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions, options);
|
|
514
|
+
// remove extra '/' from url end
|
|
515
|
+
initialOptions.apiUrl = sanitizeUrl(initialOptions.apiUrl);
|
|
516
|
+
return {
|
|
517
|
+
initialOptions,
|
|
518
|
+
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
|
|
519
|
+
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
|
|
520
|
+
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
|
|
521
|
+
isInitialLoading: false,
|
|
522
|
+
isRunning: false,
|
|
523
|
+
};
|
|
470
524
|
};
|
|
471
|
-
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
|
|
472
525
|
|
|
473
|
-
const
|
|
526
|
+
const Plugins = (getLanguage, getInitialOptions, getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation) => {
|
|
474
527
|
const plugins = {
|
|
475
528
|
ui: undefined,
|
|
529
|
+
observer: undefined,
|
|
476
530
|
};
|
|
477
531
|
const instances = {
|
|
478
532
|
formatters: [],
|
|
@@ -484,39 +538,20 @@
|
|
|
484
538
|
languageDetector: undefined,
|
|
485
539
|
languageStorage: undefined,
|
|
486
540
|
};
|
|
487
|
-
const onClick = async (
|
|
541
|
+
const onClick = async ({ keysAndDefaults, event }) => {
|
|
488
542
|
var _a;
|
|
489
|
-
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) =>
|
|
490
|
-
|
|
491
|
-
defaultValue,
|
|
492
|
-
ns: getFallbackArray(getTranslationNs({ key, ns, defaultValue })),
|
|
493
|
-
translation: getTranslation({
|
|
543
|
+
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) => {
|
|
544
|
+
return {
|
|
494
545
|
key,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
new plugins.ui({
|
|
505
|
-
apiKey: getInitialOptions().apiKey,
|
|
506
|
-
apiUrl: getInitialOptions().apiUrl,
|
|
507
|
-
highlight,
|
|
508
|
-
changeTranslation,
|
|
509
|
-
});
|
|
510
|
-
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.run({ mouseHighlight: Boolean(instances.ui) });
|
|
511
|
-
checkCorrectConfiguration();
|
|
512
|
-
};
|
|
513
|
-
const checkCorrectConfiguration = () => {
|
|
514
|
-
if (instances.languageDetector) {
|
|
515
|
-
const availableLanguages = getAvailableLanguages();
|
|
516
|
-
if (!availableLanguages) {
|
|
517
|
-
throw new Error(missingOptionError('availableLanguages'));
|
|
518
|
-
}
|
|
519
|
-
}
|
|
546
|
+
defaultValue,
|
|
547
|
+
ns: getTranslationNs({ key, ns }),
|
|
548
|
+
translation: getTranslation({
|
|
549
|
+
key,
|
|
550
|
+
ns,
|
|
551
|
+
}),
|
|
552
|
+
};
|
|
553
|
+
});
|
|
554
|
+
(_a = instances.ui) === null || _a === void 0 ? void 0 : _a.handleElementClick(withNs, event);
|
|
520
555
|
};
|
|
521
556
|
const stop = () => {
|
|
522
557
|
var _a;
|
|
@@ -528,14 +563,17 @@
|
|
|
528
563
|
return ((_b = (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.highlight) === null || _b === void 0 ? void 0 : _b.call(_a, key, ns)) || { unhighlight() { } };
|
|
529
564
|
};
|
|
530
565
|
const translate = (props) => {
|
|
531
|
-
const translation = getTranslation(
|
|
566
|
+
const translation = getTranslation({
|
|
567
|
+
key: props.key,
|
|
568
|
+
ns: props.ns,
|
|
569
|
+
});
|
|
532
570
|
return formatTranslation(Object.assign(Object.assign({}, props), { translation, formatEnabled: true }));
|
|
533
571
|
};
|
|
534
572
|
const setObserver = (observer) => {
|
|
535
|
-
|
|
573
|
+
plugins.observer = observer;
|
|
536
574
|
};
|
|
537
|
-
const
|
|
538
|
-
return
|
|
575
|
+
const hasObserver = () => {
|
|
576
|
+
return Boolean(plugins.observer);
|
|
539
577
|
};
|
|
540
578
|
const addFormatter = (formatter) => {
|
|
541
579
|
if (formatter) {
|
|
@@ -546,14 +584,17 @@
|
|
|
546
584
|
instances.finalFormatter = formatter;
|
|
547
585
|
};
|
|
548
586
|
const setUi = (ui) => {
|
|
549
|
-
plugins.ui =
|
|
587
|
+
plugins.ui = ui;
|
|
550
588
|
};
|
|
551
|
-
const
|
|
552
|
-
return plugins.ui;
|
|
589
|
+
const hasUi = () => {
|
|
590
|
+
return Boolean(plugins.ui);
|
|
553
591
|
};
|
|
554
592
|
const setLanguageStorage = (storage) => {
|
|
555
593
|
instances.languageStorage = storage;
|
|
556
594
|
};
|
|
595
|
+
const getLanguageStorage = () => {
|
|
596
|
+
return instances.languageStorage;
|
|
597
|
+
};
|
|
557
598
|
const setStoredLanguage = (language) => {
|
|
558
599
|
var _a;
|
|
559
600
|
(_a = instances.languageStorage) === null || _a === void 0 ? void 0 : _a.setLanguage(language);
|
|
@@ -561,6 +602,9 @@
|
|
|
561
602
|
const setLanguageDetector = (detector) => {
|
|
562
603
|
instances.languageDetector = detector;
|
|
563
604
|
};
|
|
605
|
+
const getLanguageDetector = () => {
|
|
606
|
+
return instances.languageDetector;
|
|
607
|
+
};
|
|
564
608
|
const detectLanguage = () => {
|
|
565
609
|
if (!instances.languageDetector) {
|
|
566
610
|
return undefined;
|
|
@@ -590,14 +634,37 @@
|
|
|
590
634
|
const setDevBackend = (backend) => {
|
|
591
635
|
instances.devBackend = backend;
|
|
592
636
|
};
|
|
637
|
+
const run = () => {
|
|
638
|
+
var _a, _b, _c;
|
|
639
|
+
if (!instances.ui) {
|
|
640
|
+
const { apiKey, apiUrl, projectId } = getInitialOptions();
|
|
641
|
+
instances.ui = (_a = plugins.ui) === null || _a === void 0 ? void 0 : _a.call(plugins, {
|
|
642
|
+
apiKey: apiKey,
|
|
643
|
+
apiUrl: apiUrl,
|
|
644
|
+
projectId,
|
|
645
|
+
highlight,
|
|
646
|
+
changeTranslation,
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
if (!instances.observer) {
|
|
650
|
+
instances.observer = (_b = plugins.observer) === null || _b === void 0 ? void 0 : _b.call(plugins, {
|
|
651
|
+
translate,
|
|
652
|
+
onClick,
|
|
653
|
+
options: getInitialOptions().observerOptions,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
(_c = instances.observer) === null || _c === void 0 ? void 0 : _c.run({ mouseHighlight: true });
|
|
657
|
+
};
|
|
593
658
|
const getDevBackend = () => {
|
|
594
659
|
return instances.devBackend;
|
|
595
660
|
};
|
|
596
661
|
const getBackendDevRecord = ({ language, namespace }) => {
|
|
597
662
|
var _a;
|
|
663
|
+
const { apiKey, apiUrl, projectId } = getInitialOptions();
|
|
598
664
|
return (_a = instances.devBackend) === null || _a === void 0 ? void 0 : _a.getRecord({
|
|
599
|
-
apiKey
|
|
600
|
-
apiUrl
|
|
665
|
+
apiKey,
|
|
666
|
+
apiUrl,
|
|
667
|
+
projectId,
|
|
601
668
|
language,
|
|
602
669
|
namespace,
|
|
603
670
|
});
|
|
@@ -618,42 +685,97 @@
|
|
|
618
685
|
}
|
|
619
686
|
return undefined;
|
|
620
687
|
};
|
|
621
|
-
const
|
|
688
|
+
const unwrap = (text) => {
|
|
689
|
+
var _a;
|
|
690
|
+
if (instances.observer) {
|
|
691
|
+
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
|
|
692
|
+
}
|
|
693
|
+
return { text, keys: [] };
|
|
694
|
+
};
|
|
695
|
+
const retranslate = () => {
|
|
622
696
|
var _a;
|
|
697
|
+
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
|
|
698
|
+
};
|
|
699
|
+
function addPlugin(tolgeeInstance, plugin) {
|
|
700
|
+
const pluginTools = Object.freeze({
|
|
701
|
+
setFinalFormatter,
|
|
702
|
+
addFormatter,
|
|
703
|
+
setObserver,
|
|
704
|
+
hasObserver,
|
|
705
|
+
setUi,
|
|
706
|
+
hasUi,
|
|
707
|
+
setDevBackend,
|
|
708
|
+
addBackend,
|
|
709
|
+
setLanguageDetector,
|
|
710
|
+
setLanguageStorage,
|
|
711
|
+
});
|
|
712
|
+
plugin(tolgeeInstance, pluginTools);
|
|
713
|
+
}
|
|
714
|
+
function formatTranslation(_a) {
|
|
715
|
+
var _b;
|
|
716
|
+
var { formatEnabled } = _a, props = __rest(_a, ["formatEnabled"]);
|
|
717
|
+
const { key, translation, defaultValue, noWrap, params, orEmpty, ns } = props;
|
|
623
718
|
const formattableTranslation = translation || defaultValue;
|
|
624
719
|
let result = formattableTranslation || (orEmpty ? '' : key);
|
|
625
|
-
if (instances.observer && !noWrap) {
|
|
626
|
-
result = instances.observer.wrap({
|
|
627
|
-
key,
|
|
628
|
-
translation: result,
|
|
629
|
-
defaultValue,
|
|
630
|
-
params,
|
|
631
|
-
ns,
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
720
|
const language = getLanguage();
|
|
635
|
-
const isFormatEnabled = formatEnabled || !((
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
721
|
+
const isFormatEnabled = formatEnabled || !((_b = instances.observer) === null || _b === void 0 ? void 0 : _b.outputNotFormattable);
|
|
722
|
+
const wrap = (result) => {
|
|
723
|
+
if (instances.observer && !noWrap) {
|
|
724
|
+
return instances.observer.wrap({
|
|
725
|
+
key,
|
|
726
|
+
translation: result,
|
|
727
|
+
defaultValue,
|
|
728
|
+
params,
|
|
729
|
+
ns,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
return result;
|
|
733
|
+
};
|
|
734
|
+
result = wrap(result);
|
|
735
|
+
try {
|
|
736
|
+
if (formattableTranslation && language && isFormatEnabled) {
|
|
737
|
+
for (const formatter of instances.formatters) {
|
|
738
|
+
result = formatter.format({
|
|
739
|
+
translation: result,
|
|
740
|
+
language,
|
|
741
|
+
params,
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (instances.finalFormatter &&
|
|
746
|
+
formattableTranslation &&
|
|
747
|
+
language &&
|
|
748
|
+
isFormatEnabled) {
|
|
749
|
+
result = instances.finalFormatter.format({
|
|
639
750
|
translation: result,
|
|
640
751
|
language,
|
|
641
752
|
params,
|
|
642
753
|
});
|
|
643
754
|
}
|
|
644
755
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}
|
|
756
|
+
catch (e) {
|
|
757
|
+
// eslint-disable-next-line no-console
|
|
758
|
+
console.error(e);
|
|
759
|
+
const errorMessage = getErrorMessage(e) || DEFAULT_FORMAT_ERROR;
|
|
760
|
+
const onFormatError = getInitialOptions().onFormatError;
|
|
761
|
+
const formatErrorType = typeof onFormatError;
|
|
762
|
+
if (formatErrorType === 'string') {
|
|
763
|
+
result = onFormatError;
|
|
764
|
+
}
|
|
765
|
+
else if (formatErrorType === 'function') {
|
|
766
|
+
result = onFormatError(errorMessage, props);
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
result = DEFAULT_FORMAT_ERROR;
|
|
770
|
+
}
|
|
771
|
+
// wrap error message, so it's detectable
|
|
772
|
+
result = wrap(result);
|
|
654
773
|
}
|
|
655
774
|
return result;
|
|
656
|
-
}
|
|
775
|
+
}
|
|
776
|
+
function hasDevBackend() {
|
|
777
|
+
return Boolean(getDevBackend());
|
|
778
|
+
}
|
|
657
779
|
const wrap = (params) => {
|
|
658
780
|
var _a;
|
|
659
781
|
if (instances.observer) {
|
|
@@ -661,40 +783,23 @@
|
|
|
661
783
|
}
|
|
662
784
|
return params.translation;
|
|
663
785
|
};
|
|
664
|
-
const unwrap = (text) => {
|
|
665
|
-
var _a;
|
|
666
|
-
if (instances.observer) {
|
|
667
|
-
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
|
|
668
|
-
}
|
|
669
|
-
return { text, keys: [] };
|
|
670
|
-
};
|
|
671
|
-
const retranslate = () => {
|
|
672
|
-
var _a;
|
|
673
|
-
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
|
|
674
|
-
};
|
|
675
786
|
return Object.freeze({
|
|
676
|
-
|
|
677
|
-
addFormatter,
|
|
787
|
+
addPlugin,
|
|
678
788
|
formatTranslation,
|
|
679
|
-
setObserver,
|
|
680
|
-
getObserver,
|
|
681
|
-
setUi,
|
|
682
|
-
getUi,
|
|
683
|
-
addBackend,
|
|
684
|
-
setDevBackend,
|
|
685
789
|
getDevBackend,
|
|
686
790
|
getBackendRecord,
|
|
687
791
|
getBackendDevRecord,
|
|
688
|
-
|
|
689
|
-
|
|
792
|
+
getLanguageDetector,
|
|
793
|
+
getLanguageStorage,
|
|
690
794
|
getInitialLanguage,
|
|
691
795
|
setStoredLanguage,
|
|
692
796
|
run,
|
|
693
797
|
stop,
|
|
694
798
|
retranslate,
|
|
695
799
|
highlight,
|
|
696
|
-
wrap,
|
|
697
800
|
unwrap,
|
|
801
|
+
wrap,
|
|
802
|
+
hasDevBackend,
|
|
698
803
|
});
|
|
699
804
|
};
|
|
700
805
|
|
|
@@ -716,28 +821,9 @@
|
|
|
716
821
|
});
|
|
717
822
|
};
|
|
718
823
|
|
|
719
|
-
const defaultValues = {
|
|
720
|
-
enableLanguageStore: true,
|
|
721
|
-
defaultNs: '',
|
|
722
|
-
filesUrlPrefix: 'i18n/',
|
|
723
|
-
};
|
|
724
|
-
const initState = (options, previousState) => {
|
|
725
|
-
const initialOptions = Object.assign(Object.assign(Object.assign({}, defaultValues), previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions), options);
|
|
726
|
-
// remove extra '/' from url end
|
|
727
|
-
const apiUrl = initialOptions.apiUrl;
|
|
728
|
-
initialOptions.apiUrl = apiUrl ? apiUrl.replace(/\/+$/, '') : apiUrl;
|
|
729
|
-
return {
|
|
730
|
-
initialOptions,
|
|
731
|
-
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
|
|
732
|
-
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
|
|
733
|
-
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
|
|
734
|
-
isInitialLoading: false,
|
|
735
|
-
isRunning: false,
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
|
-
|
|
739
824
|
const State = (onLanguageChange, onPendingLanguageChange, onRunningChange) => {
|
|
740
825
|
let state = initState();
|
|
826
|
+
let devCredentials = undefined;
|
|
741
827
|
function init(options) {
|
|
742
828
|
state = initState(options, state);
|
|
743
829
|
}
|
|
@@ -759,13 +845,6 @@
|
|
|
759
845
|
function getLanguage() {
|
|
760
846
|
return state.language || state.initialOptions.language;
|
|
761
847
|
}
|
|
762
|
-
function getLanguageOrFail() {
|
|
763
|
-
const language = state.language || state.initialOptions.language;
|
|
764
|
-
if (!language) {
|
|
765
|
-
throw new Error(`No language set`);
|
|
766
|
-
}
|
|
767
|
-
return language;
|
|
768
|
-
}
|
|
769
848
|
function setLanguage(language) {
|
|
770
849
|
if (state.language !== language) {
|
|
771
850
|
state.language = language;
|
|
@@ -782,7 +861,7 @@
|
|
|
782
861
|
}
|
|
783
862
|
}
|
|
784
863
|
function getInitialOptions() {
|
|
785
|
-
return state.initialOptions;
|
|
864
|
+
return Object.assign(Object.assign({}, state.initialOptions), devCredentials);
|
|
786
865
|
}
|
|
787
866
|
function addActiveNs(ns) {
|
|
788
867
|
const namespaces = getFallbackArray(ns);
|
|
@@ -811,6 +890,7 @@
|
|
|
811
890
|
function getRequiredNamespaces() {
|
|
812
891
|
return unique([
|
|
813
892
|
...(state.initialOptions.ns || [state.initialOptions.defaultNs]),
|
|
893
|
+
...getFallbackArray(state.initialOptions.fallbackNs),
|
|
814
894
|
...state.activeNamespaces.keys(),
|
|
815
895
|
]);
|
|
816
896
|
}
|
|
@@ -824,11 +904,11 @@
|
|
|
824
904
|
...getFallbackFromStruct(language, state.initialOptions.fallbackLanguage),
|
|
825
905
|
]);
|
|
826
906
|
}
|
|
827
|
-
function
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
return
|
|
907
|
+
function getFallbackNs() {
|
|
908
|
+
return getFallbackArray(state.initialOptions.fallbackNs);
|
|
909
|
+
}
|
|
910
|
+
function getDefaultNs(ns) {
|
|
911
|
+
return ns === undefined ? state.initialOptions.defaultNs : ns;
|
|
832
912
|
}
|
|
833
913
|
function getAvailableLanguages() {
|
|
834
914
|
if (state.initialOptions.availableLanguages) {
|
|
@@ -847,6 +927,14 @@
|
|
|
847
927
|
language: descriptor.language,
|
|
848
928
|
};
|
|
849
929
|
}
|
|
930
|
+
function overrideCredentials(credentials) {
|
|
931
|
+
if (credentials) {
|
|
932
|
+
devCredentials = Object.assign(Object.assign({}, credentials), { apiUrl: sanitizeUrl(credentials.apiUrl) });
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
devCredentials = undefined;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
850
938
|
return Object.freeze({
|
|
851
939
|
init,
|
|
852
940
|
isRunning,
|
|
@@ -854,7 +942,6 @@
|
|
|
854
942
|
isInitialLoading,
|
|
855
943
|
setInitialLoading,
|
|
856
944
|
getLanguage,
|
|
857
|
-
getLanguageOrFail,
|
|
858
945
|
setLanguage,
|
|
859
946
|
getPendingLanguage,
|
|
860
947
|
setPendingLanguage,
|
|
@@ -863,50 +950,24 @@
|
|
|
863
950
|
removeActiveNs,
|
|
864
951
|
getRequiredNamespaces,
|
|
865
952
|
getFallbackLangs,
|
|
866
|
-
|
|
953
|
+
getFallbackNs,
|
|
954
|
+
getDefaultNs,
|
|
867
955
|
getAvailableLanguages,
|
|
868
956
|
withDefaultNs,
|
|
957
|
+
overrideCredentials,
|
|
869
958
|
});
|
|
870
959
|
};
|
|
871
960
|
|
|
872
|
-
/******************************************************************************
|
|
873
|
-
Copyright (c) Microsoft Corporation.
|
|
874
|
-
|
|
875
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
876
|
-
purpose with or without fee is hereby granted.
|
|
877
|
-
|
|
878
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
879
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
880
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
881
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
882
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
883
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
884
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
885
|
-
***************************************************************************** */
|
|
886
|
-
|
|
887
|
-
function __rest(s, e) {
|
|
888
|
-
var t = {};
|
|
889
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
890
|
-
t[p] = s[p];
|
|
891
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
892
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
893
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
894
|
-
t[p[i]] = s[p[i]];
|
|
895
|
-
}
|
|
896
|
-
return t;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
961
|
function parseCombinedOptions(_a) {
|
|
900
962
|
var { ns, noWrap, orEmpty, params } = _a, rest = __rest(_a, ["ns", "noWrap", "orEmpty", "params"]);
|
|
901
963
|
const options = {
|
|
902
964
|
ns: ns,
|
|
903
965
|
noWrap: noWrap,
|
|
904
966
|
orEmpty: orEmpty,
|
|
905
|
-
params: Object.assign(Object.assign({}, rest), params),
|
|
906
967
|
};
|
|
907
|
-
return options;
|
|
968
|
+
return Object.assign(Object.assign({}, options), { params: Object.assign({}, rest) });
|
|
908
969
|
}
|
|
909
|
-
const
|
|
970
|
+
const getTranslateProps = (keyOrProps, ...params) => {
|
|
910
971
|
let result = {};
|
|
911
972
|
let options;
|
|
912
973
|
if (typeof keyOrProps === 'object') {
|
|
@@ -928,28 +989,40 @@
|
|
|
928
989
|
return result;
|
|
929
990
|
};
|
|
930
991
|
|
|
931
|
-
const Controller = ({
|
|
992
|
+
const Controller = ({ options }) => {
|
|
993
|
+
const events = Events(getFallbackNs, getDefaultNs);
|
|
932
994
|
const fetchingObserver = ValueObserver(false, () => cache.isFetching(), events.onFetchingChange.emit);
|
|
933
995
|
const loadingObserver = ValueObserver(false, () => isLoading(), events.onLoadingChange.emit);
|
|
934
996
|
const state = State(events.onLanguageChange, events.onPendingLanguageChange, events.onRunningChange);
|
|
935
|
-
const pluginService =
|
|
997
|
+
const pluginService = Plugins(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation);
|
|
936
998
|
const cache = Cache(events.onCacheChange, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, fetchingObserver, loadingObserver);
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if (isDev()) {
|
|
940
|
-
cache.invalidate();
|
|
999
|
+
if (options) {
|
|
1000
|
+
init(options);
|
|
941
1001
|
}
|
|
942
|
-
events.
|
|
1002
|
+
events.onUpdate.listen(() => {
|
|
943
1003
|
if (state.isRunning()) {
|
|
944
1004
|
pluginService.retranslate();
|
|
945
1005
|
}
|
|
946
1006
|
});
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
return
|
|
952
|
-
}
|
|
1007
|
+
function getFallbackNs() {
|
|
1008
|
+
return state.getFallbackNs();
|
|
1009
|
+
}
|
|
1010
|
+
function getDefaultNs(ns) {
|
|
1011
|
+
return state.getDefaultNs(ns);
|
|
1012
|
+
}
|
|
1013
|
+
// gets all namespaces where translation could be located
|
|
1014
|
+
// takes (ns|default, fallback ns)
|
|
1015
|
+
function getDefaultAndFallbackNs(ns) {
|
|
1016
|
+
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
|
|
1017
|
+
}
|
|
1018
|
+
// gets all namespaces which need to be loaded
|
|
1019
|
+
// takes (ns|default, initial ns, fallback ns, active ns)
|
|
1020
|
+
function getRequiredNamespaces(ns) {
|
|
1021
|
+
return [
|
|
1022
|
+
...getFallbackArray(ns || getDefaultNs()),
|
|
1023
|
+
...state.getRequiredNamespaces(),
|
|
1024
|
+
];
|
|
1025
|
+
}
|
|
953
1026
|
function changeTranslation(descriptor, key, value) {
|
|
954
1027
|
const keyObject = state.withDefaultNs(descriptor);
|
|
955
1028
|
const previousValue = cache.getTranslation(keyObject, key);
|
|
@@ -963,15 +1036,12 @@
|
|
|
963
1036
|
function init(options) {
|
|
964
1037
|
state.init(options);
|
|
965
1038
|
cache.addStaticData(state.getInitialOptions().staticData);
|
|
966
|
-
if (isDev()) {
|
|
967
|
-
cache.invalidate();
|
|
968
|
-
}
|
|
969
1039
|
}
|
|
970
1040
|
function isLoading(ns) {
|
|
971
1041
|
return cache.isLoading(state.getLanguage(), ns);
|
|
972
1042
|
}
|
|
973
1043
|
function isDev() {
|
|
974
|
-
return Boolean(state.getInitialOptions().apiKey &&
|
|
1044
|
+
return Boolean(state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl);
|
|
975
1045
|
}
|
|
976
1046
|
async function addActiveNs(ns, forget) {
|
|
977
1047
|
if (!forget) {
|
|
@@ -983,7 +1053,7 @@
|
|
|
983
1053
|
}
|
|
984
1054
|
function getRequiredRecords(lang, ns) {
|
|
985
1055
|
const languages = state.getFallbackLangs(lang);
|
|
986
|
-
const namespaces =
|
|
1056
|
+
const namespaces = getRequiredNamespaces(ns);
|
|
987
1057
|
const result = [];
|
|
988
1058
|
languages.forEach((language) => {
|
|
989
1059
|
namespaces.forEach((namespace) => {
|
|
@@ -1000,7 +1070,7 @@
|
|
|
1000
1070
|
return false;
|
|
1001
1071
|
}
|
|
1002
1072
|
const languages = state.getFallbackLangs(language);
|
|
1003
|
-
const namespaces =
|
|
1073
|
+
const namespaces = getRequiredNamespaces(ns);
|
|
1004
1074
|
const result = [];
|
|
1005
1075
|
languages.forEach((language) => {
|
|
1006
1076
|
namespaces.forEach((namespace) => {
|
|
@@ -1033,24 +1103,19 @@
|
|
|
1033
1103
|
pluginService.setStoredLanguage(language);
|
|
1034
1104
|
}
|
|
1035
1105
|
}
|
|
1036
|
-
function getTranslationNs({ key, ns
|
|
1037
|
-
const namespaces = ns
|
|
1038
|
-
? getFallbackArray(ns)
|
|
1039
|
-
: state.getFallbackNamespaces();
|
|
1106
|
+
function getTranslationNs({ key, ns }) {
|
|
1040
1107
|
const languages = state.getFallbackLangs();
|
|
1108
|
+
const namespaces = getDefaultAndFallbackNs(ns);
|
|
1041
1109
|
return cache.getTranslationNs(namespaces, languages, key);
|
|
1042
1110
|
}
|
|
1043
|
-
function getTranslation({ key, ns
|
|
1044
|
-
const namespaces = ns
|
|
1045
|
-
? getFallbackArray(ns)
|
|
1046
|
-
: state.getFallbackNamespaces();
|
|
1111
|
+
function getTranslation({ key, ns }) {
|
|
1112
|
+
const namespaces = getDefaultAndFallbackNs(ns);
|
|
1047
1113
|
const languages = state.getFallbackLangs();
|
|
1048
1114
|
return cache.getTranslationFallback(namespaces, languages, key);
|
|
1049
1115
|
}
|
|
1050
1116
|
function loadInitial() {
|
|
1051
1117
|
const data = valueOrPromise(initializeLanguage(), () => {
|
|
1052
1118
|
// fail if there is no language
|
|
1053
|
-
state.getLanguageOrFail();
|
|
1054
1119
|
return loadRequiredRecords();
|
|
1055
1120
|
});
|
|
1056
1121
|
if (isPromise(data)) {
|
|
@@ -1089,9 +1154,30 @@
|
|
|
1089
1154
|
function loadRecords(descriptors) {
|
|
1090
1155
|
return cache.loadRecords(descriptors, isDev());
|
|
1091
1156
|
}
|
|
1157
|
+
const checkCorrectConfiguration = () => {
|
|
1158
|
+
const languageComputable = pluginService.getLanguageDetector() || pluginService.getLanguageStorage();
|
|
1159
|
+
if (languageComputable) {
|
|
1160
|
+
const availableLanguages = state.getAvailableLanguages();
|
|
1161
|
+
if (!availableLanguages) {
|
|
1162
|
+
throw new Error(missingOptionError('availableLanguages'));
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (!state.getLanguage() && !state.getInitialOptions().defaultLanguage) {
|
|
1166
|
+
if (languageComputable) {
|
|
1167
|
+
throw new Error(missingOptionError('defaultLanguage'));
|
|
1168
|
+
}
|
|
1169
|
+
else {
|
|
1170
|
+
throw new Error(missingOptionError('language'));
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1092
1174
|
function run() {
|
|
1093
1175
|
let result = undefined;
|
|
1176
|
+
checkCorrectConfiguration();
|
|
1094
1177
|
if (!state.isRunning()) {
|
|
1178
|
+
if (isDev()) {
|
|
1179
|
+
cache.invalidate();
|
|
1180
|
+
}
|
|
1095
1181
|
state.setRunning(true);
|
|
1096
1182
|
pluginService.run();
|
|
1097
1183
|
result = loadInitial();
|
|
@@ -1104,12 +1190,17 @@
|
|
|
1104
1190
|
state.setRunning(false);
|
|
1105
1191
|
}
|
|
1106
1192
|
}
|
|
1107
|
-
|
|
1193
|
+
const t = (...args) => {
|
|
1194
|
+
// @ts-ignore
|
|
1195
|
+
const params = getTranslateProps(...args);
|
|
1196
|
+
const translation = getTranslation(params);
|
|
1197
|
+
return pluginService.formatTranslation(Object.assign(Object.assign({}, params), { translation }));
|
|
1198
|
+
};
|
|
1199
|
+
return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, events), state), pluginService), cache), { init,
|
|
1108
1200
|
changeLanguage,
|
|
1109
1201
|
getTranslation,
|
|
1110
1202
|
changeTranslation,
|
|
1111
1203
|
addActiveNs,
|
|
1112
|
-
loadRequiredRecords,
|
|
1113
1204
|
loadRecords,
|
|
1114
1205
|
loadRecord,
|
|
1115
1206
|
isLoading,
|
|
@@ -1120,24 +1211,11 @@
|
|
|
1120
1211
|
stop }));
|
|
1121
1212
|
};
|
|
1122
1213
|
|
|
1123
|
-
const
|
|
1124
|
-
const events = Events();
|
|
1214
|
+
const createTolgee = (options) => {
|
|
1125
1215
|
const controller = Controller({
|
|
1126
|
-
events,
|
|
1127
1216
|
options,
|
|
1128
1217
|
});
|
|
1129
|
-
|
|
1130
|
-
setFinalFormatter: controller.setFinalFormatter,
|
|
1131
|
-
addFormatter: controller.addFormatter,
|
|
1132
|
-
setObserver: controller.setObserver,
|
|
1133
|
-
getObserver: controller.getObserver,
|
|
1134
|
-
setUi: controller.setUi,
|
|
1135
|
-
getUi: controller.getUi,
|
|
1136
|
-
setDevBackend: controller.setDevBackend,
|
|
1137
|
-
addBackend: controller.addBackend,
|
|
1138
|
-
setLanguageDetector: controller.setLanguageDetector,
|
|
1139
|
-
setLanguageStorage: controller.setLanguageStorage,
|
|
1140
|
-
});
|
|
1218
|
+
// restarts tolgee while applying callback
|
|
1141
1219
|
const withRestart = (callback) => {
|
|
1142
1220
|
const wasRunning = controller.isRunning();
|
|
1143
1221
|
wasRunning && controller.stop();
|
|
@@ -1145,65 +1223,363 @@
|
|
|
1145
1223
|
wasRunning && controller.run();
|
|
1146
1224
|
};
|
|
1147
1225
|
const tolgee = Object.freeze({
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1226
|
+
/**
|
|
1227
|
+
* Listen to tolgee events.
|
|
1228
|
+
*/
|
|
1229
|
+
on: controller.on,
|
|
1230
|
+
/**
|
|
1231
|
+
* Listen for specific namespaces changes.
|
|
1232
|
+
*
|
|
1233
|
+
* ```
|
|
1234
|
+
* const sub = tolgee.onUpdate(handler)
|
|
1235
|
+
*
|
|
1236
|
+
* // subscribe to selected namespace
|
|
1237
|
+
* sub.subscribeNs(['common'])
|
|
1238
|
+
*
|
|
1239
|
+
* // unsubscribe
|
|
1240
|
+
* sub.unsubscribe()
|
|
1241
|
+
* ```
|
|
1242
|
+
*/
|
|
1243
|
+
onNsUpdate: controller.onUpdate.listenSome,
|
|
1244
|
+
/**
|
|
1245
|
+
* Turn off/on events emitting. Is on by default.
|
|
1246
|
+
*/
|
|
1247
|
+
setEmmiterActive: controller.setEmmiterActive,
|
|
1248
|
+
/**
|
|
1249
|
+
* @return current language if set.
|
|
1250
|
+
*/
|
|
1152
1251
|
getLanguage: controller.getLanguage,
|
|
1252
|
+
/**
|
|
1253
|
+
* `pendingLanguage` represents language which is currently being loaded.
|
|
1254
|
+
* @return current `pendingLanguage` if set.
|
|
1255
|
+
*/
|
|
1153
1256
|
getPendingLanguage: controller.getPendingLanguage,
|
|
1257
|
+
/**
|
|
1258
|
+
* Change current language.
|
|
1259
|
+
* - if not running sets `pendingLanguage`, `language` to the new value
|
|
1260
|
+
* - if running sets `pendingLanguage` to the value, fetches necessary data and then changes `language`
|
|
1261
|
+
*
|
|
1262
|
+
* @return Promise which is resolved when `language` is changed.
|
|
1263
|
+
*/
|
|
1154
1264
|
changeLanguage: controller.changeLanguage,
|
|
1265
|
+
/**
|
|
1266
|
+
* Temporarily change translation in cache.
|
|
1267
|
+
* @return object with revert method.
|
|
1268
|
+
*/
|
|
1155
1269
|
changeTranslation: controller.changeTranslation,
|
|
1270
|
+
/**
|
|
1271
|
+
* Adds namespace(s) list of active namespaces. And if tolgee is running, loads required data.
|
|
1272
|
+
*/
|
|
1156
1273
|
addActiveNs: controller.addActiveNs,
|
|
1274
|
+
/**
|
|
1275
|
+
* Remove namespace(s) from active namespaces.
|
|
1276
|
+
*
|
|
1277
|
+
* Tolgee internally counts how many times was each active namespace added,
|
|
1278
|
+
* so this method will remove namespace only if the counter goes down to 0.
|
|
1279
|
+
*/
|
|
1157
1280
|
removeActiveNs: controller.removeActiveNs,
|
|
1281
|
+
/**
|
|
1282
|
+
* Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
|
|
1283
|
+
*
|
|
1284
|
+
* It loads data together and adds them to cache in one operation, to prevent partly loaded state.
|
|
1285
|
+
*/
|
|
1158
1286
|
loadRecords: controller.loadRecords,
|
|
1287
|
+
/**
|
|
1288
|
+
* Manually load record from `Backend` (or `DevBackend` when in dev mode)
|
|
1289
|
+
*/
|
|
1159
1290
|
loadRecord: controller.loadRecord,
|
|
1291
|
+
/**
|
|
1292
|
+
*
|
|
1293
|
+
*/
|
|
1160
1294
|
addStaticData: controller.addStaticData,
|
|
1295
|
+
/**
|
|
1296
|
+
* Get record from cache.
|
|
1297
|
+
*/
|
|
1161
1298
|
getRecord: controller.getRecord,
|
|
1299
|
+
/**
|
|
1300
|
+
* Get all records from cache.
|
|
1301
|
+
*/
|
|
1162
1302
|
getAllRecords: controller.getAllRecords,
|
|
1303
|
+
/**
|
|
1304
|
+
* @param ns optional list of namespaces that you are interested in
|
|
1305
|
+
* @return `true` if there are data that need to be fetched.
|
|
1306
|
+
*/
|
|
1163
1307
|
isLoaded: controller.isLoaded,
|
|
1308
|
+
/**
|
|
1309
|
+
* @return `true` if tolgee is loading initial data (triggered by `run`).
|
|
1310
|
+
*/
|
|
1164
1311
|
isInitialLoading: controller.isInitialLoading,
|
|
1312
|
+
/**
|
|
1313
|
+
* @param ns optional list of namespaces that you are interested in
|
|
1314
|
+
* @return `true` if tolgee is loading some translations for the first time.
|
|
1315
|
+
*/
|
|
1165
1316
|
isLoading: controller.isLoading,
|
|
1317
|
+
/**
|
|
1318
|
+
* @param ns optional list of namespaces that you are interested in
|
|
1319
|
+
* @return `true` if tolgee is fetching some translations.
|
|
1320
|
+
*/
|
|
1166
1321
|
isFetching: controller.isFetching,
|
|
1322
|
+
/**
|
|
1323
|
+
* @return `true` if tolgee is running.
|
|
1324
|
+
*/
|
|
1167
1325
|
isRunning: controller.isRunning,
|
|
1326
|
+
/**
|
|
1327
|
+
* Changes internal state to running: true and loads initial files.
|
|
1328
|
+
* Runs runnable plugins mainly Observer if present.
|
|
1329
|
+
*/
|
|
1168
1330
|
run: controller.run,
|
|
1331
|
+
/**
|
|
1332
|
+
* Changes internal state to running: false and stops runnable plugins.
|
|
1333
|
+
*/
|
|
1169
1334
|
stop: controller.stop,
|
|
1335
|
+
/**
|
|
1336
|
+
* Returns translated and formatted key.
|
|
1337
|
+
* If Observer is present and tolgee is running, wraps result to be identifiable in the DOM.
|
|
1338
|
+
*/
|
|
1170
1339
|
t: controller.t,
|
|
1340
|
+
/**
|
|
1341
|
+
* Highlight keys that match selection.
|
|
1342
|
+
*/
|
|
1171
1343
|
highlight: controller.highlight,
|
|
1344
|
+
/**
|
|
1345
|
+
* @return current Tolgee options.
|
|
1346
|
+
*/
|
|
1172
1347
|
getInitialOptions: controller.getInitialOptions,
|
|
1348
|
+
/**
|
|
1349
|
+
* Tolgee is in dev mode if `DevTools` plugin is used and `apiKey` + `apiUrl` are specified.
|
|
1350
|
+
* @return `true` if tolgee is in dev mode.
|
|
1351
|
+
*/
|
|
1173
1352
|
isDev: controller.isDev,
|
|
1353
|
+
/**
|
|
1354
|
+
* Wraps translation if there is `Observer` plugin
|
|
1355
|
+
*/
|
|
1174
1356
|
wrap: controller.wrap,
|
|
1357
|
+
/**
|
|
1358
|
+
* Unwrap translation
|
|
1359
|
+
*/
|
|
1175
1360
|
unwrap: controller.unwrap,
|
|
1176
|
-
|
|
1177
|
-
|
|
1361
|
+
/**
|
|
1362
|
+
* Override creadentials passed on initialization.
|
|
1363
|
+
*
|
|
1364
|
+
* When called in running state, tolgee stops and runs again.
|
|
1365
|
+
*/
|
|
1366
|
+
overrideCredentials(credentials) {
|
|
1367
|
+
withRestart(() => controller.overrideCredentials(credentials));
|
|
1368
|
+
},
|
|
1369
|
+
/**
|
|
1370
|
+
* Add tolgee plugin after initialization.
|
|
1371
|
+
*
|
|
1372
|
+
* When called in running state, tolgee stops and runs again.
|
|
1373
|
+
*/
|
|
1374
|
+
addPlugin(plugin) {
|
|
1178
1375
|
if (plugin) {
|
|
1179
|
-
withRestart(() =>
|
|
1376
|
+
withRestart(() => controller.addPlugin(tolgee, plugin));
|
|
1180
1377
|
}
|
|
1181
|
-
return tolgee;
|
|
1182
1378
|
},
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Updates options after instance creation. Extends existing options,
|
|
1381
|
+
* so it only changes the fields, that are listed.
|
|
1382
|
+
*
|
|
1383
|
+
* When called in running state, tolgee stops and runs again.
|
|
1384
|
+
*/
|
|
1385
|
+
updateOptions(options) {
|
|
1386
|
+
if (options) {
|
|
1387
|
+
withRestart(() => controller.init(options));
|
|
1388
|
+
}
|
|
1186
1389
|
},
|
|
1187
1390
|
});
|
|
1188
1391
|
return tolgee;
|
|
1189
1392
|
};
|
|
1393
|
+
/**
|
|
1394
|
+
* Tolgee chainable constructor.
|
|
1395
|
+
*
|
|
1396
|
+
* Usage:
|
|
1397
|
+
* ```
|
|
1398
|
+
* const tolgee = Tolgee().use(...).init(...)
|
|
1399
|
+
* ```
|
|
1400
|
+
*/
|
|
1401
|
+
const TolgeeCore = () => {
|
|
1402
|
+
const state = {
|
|
1403
|
+
plugins: [],
|
|
1404
|
+
options: {},
|
|
1405
|
+
};
|
|
1406
|
+
const tolgeeChain = Object.freeze({
|
|
1407
|
+
use(plugin) {
|
|
1408
|
+
state.plugins.push(plugin);
|
|
1409
|
+
return tolgeeChain;
|
|
1410
|
+
},
|
|
1411
|
+
updateDefaults(options) {
|
|
1412
|
+
state.options = combineOptions(state.options, options);
|
|
1413
|
+
return tolgeeChain;
|
|
1414
|
+
},
|
|
1415
|
+
init(options) {
|
|
1416
|
+
const tolgee = createTolgee(combineOptions(state.options, options));
|
|
1417
|
+
state.plugins.forEach(tolgee.addPlugin);
|
|
1418
|
+
return tolgee;
|
|
1419
|
+
},
|
|
1420
|
+
});
|
|
1421
|
+
return tolgeeChain;
|
|
1422
|
+
};
|
|
1190
1423
|
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1424
|
+
const ERROR_PARAM_EMPTY = 0, ERROR_UNEXPECTED_CHAR = 1, ERROR_UNEXPECTED_END = 2;
|
|
1425
|
+
class FormatError extends Error {
|
|
1426
|
+
constructor(code, index, text) {
|
|
1427
|
+
let error;
|
|
1428
|
+
if (code === ERROR_PARAM_EMPTY) {
|
|
1429
|
+
error = 'Empty parameter';
|
|
1430
|
+
}
|
|
1431
|
+
else if (code === ERROR_UNEXPECTED_CHAR) {
|
|
1432
|
+
error = 'Unexpected character';
|
|
1433
|
+
}
|
|
1434
|
+
else {
|
|
1435
|
+
error = 'Unexpected end';
|
|
1436
|
+
}
|
|
1437
|
+
super(`Tolgee parser: ${error} at ${index} in "${text}"`);
|
|
1438
|
+
this.code = code;
|
|
1439
|
+
this.index = index;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
function isWhitespace(ch) {
|
|
1444
|
+
return /\s/.test(ch);
|
|
1445
|
+
}
|
|
1446
|
+
const STATE_TEXT = 0, STATE_ESCAPE_MAYBE = 1, STATE_ESCAPE = 2, STATE_PARAM = 3, STATE_PARAM_AFTER = 4;
|
|
1447
|
+
const END_STATES = new Set([
|
|
1448
|
+
STATE_ESCAPE,
|
|
1449
|
+
STATE_ESCAPE_MAYBE,
|
|
1450
|
+
STATE_TEXT,
|
|
1451
|
+
]);
|
|
1452
|
+
const CHAR_ESCAPE = "'";
|
|
1453
|
+
const ESCAPABLE = new Set(['{', '}', CHAR_ESCAPE]);
|
|
1454
|
+
const isAllowedInParam = (char) => {
|
|
1455
|
+
return /[0-9a-zA-Z_]/.test(char);
|
|
1456
|
+
};
|
|
1457
|
+
function formatParser(translation) {
|
|
1458
|
+
let state = STATE_TEXT;
|
|
1459
|
+
let text = '';
|
|
1460
|
+
let param = '';
|
|
1461
|
+
let ch = '';
|
|
1462
|
+
const texts = [];
|
|
1463
|
+
const params = [];
|
|
1464
|
+
let i = 0;
|
|
1465
|
+
function parsingError(code) {
|
|
1466
|
+
throw new FormatError(code, i, translation);
|
|
1467
|
+
}
|
|
1468
|
+
const addText = () => {
|
|
1469
|
+
texts.push(text);
|
|
1470
|
+
text = '';
|
|
1471
|
+
};
|
|
1472
|
+
const addParamChar = () => {
|
|
1473
|
+
if (!isAllowedInParam(ch)) {
|
|
1474
|
+
parsingError(ERROR_UNEXPECTED_CHAR);
|
|
1475
|
+
}
|
|
1476
|
+
param += ch;
|
|
1477
|
+
};
|
|
1478
|
+
const addParam = () => {
|
|
1479
|
+
if (param === '') {
|
|
1480
|
+
parsingError(ERROR_PARAM_EMPTY);
|
|
1481
|
+
}
|
|
1482
|
+
params.push(param);
|
|
1483
|
+
param = '';
|
|
1484
|
+
};
|
|
1485
|
+
for (i = 0; i < translation.length; i++) {
|
|
1486
|
+
ch = translation[i];
|
|
1487
|
+
switch (state) {
|
|
1488
|
+
case STATE_TEXT:
|
|
1489
|
+
if (ch === CHAR_ESCAPE) {
|
|
1490
|
+
text += ch;
|
|
1491
|
+
state = STATE_ESCAPE_MAYBE;
|
|
1492
|
+
}
|
|
1493
|
+
else if (ch === '{') {
|
|
1494
|
+
addText();
|
|
1495
|
+
state = STATE_PARAM;
|
|
1496
|
+
}
|
|
1497
|
+
else {
|
|
1498
|
+
text += ch;
|
|
1499
|
+
state = STATE_TEXT;
|
|
1500
|
+
}
|
|
1501
|
+
break;
|
|
1502
|
+
case STATE_ESCAPE_MAYBE:
|
|
1503
|
+
if (ESCAPABLE.has(ch)) {
|
|
1504
|
+
text = text.slice(0, -1) + ch;
|
|
1505
|
+
state = STATE_ESCAPE;
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
text += ch;
|
|
1509
|
+
state = STATE_TEXT;
|
|
1510
|
+
}
|
|
1511
|
+
break;
|
|
1512
|
+
case STATE_ESCAPE:
|
|
1513
|
+
if (ch === CHAR_ESCAPE) {
|
|
1514
|
+
state = STATE_TEXT;
|
|
1515
|
+
}
|
|
1516
|
+
else {
|
|
1517
|
+
text += ch;
|
|
1518
|
+
state = STATE_ESCAPE;
|
|
1519
|
+
}
|
|
1520
|
+
break;
|
|
1521
|
+
case STATE_PARAM:
|
|
1522
|
+
if (ch === '}') {
|
|
1523
|
+
addParam();
|
|
1524
|
+
state = STATE_TEXT;
|
|
1525
|
+
}
|
|
1526
|
+
else if (!isWhitespace(ch)) {
|
|
1527
|
+
addParamChar();
|
|
1528
|
+
state = STATE_PARAM;
|
|
1529
|
+
}
|
|
1530
|
+
else if (param !== '') {
|
|
1531
|
+
addParam();
|
|
1532
|
+
state = STATE_PARAM_AFTER;
|
|
1533
|
+
}
|
|
1534
|
+
break;
|
|
1535
|
+
case STATE_PARAM_AFTER:
|
|
1536
|
+
if (ch == '}') {
|
|
1537
|
+
state = STATE_TEXT;
|
|
1538
|
+
}
|
|
1539
|
+
else if (isWhitespace(ch)) {
|
|
1540
|
+
state = STATE_PARAM_AFTER;
|
|
1541
|
+
}
|
|
1542
|
+
else {
|
|
1543
|
+
parsingError(ERROR_UNEXPECTED_CHAR);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if (!END_STATES.has(state)) {
|
|
1548
|
+
parsingError(ERROR_UNEXPECTED_END);
|
|
1549
|
+
}
|
|
1550
|
+
addText();
|
|
1551
|
+
return [texts, params];
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
function formatter(translation, params) {
|
|
1555
|
+
const [texts, pars] = formatParser(translation);
|
|
1556
|
+
const result = [texts[0]];
|
|
1557
|
+
for (let i = 1; i < texts.length; i++) {
|
|
1558
|
+
const parameter = params === null || params === void 0 ? void 0 : params[pars[i - 1]];
|
|
1559
|
+
if (parameter === undefined) {
|
|
1560
|
+
throw new Error(`Missing parameter "${pars[i - 1]}" in "${translation}"`);
|
|
1561
|
+
}
|
|
1562
|
+
result.push(String(parameter));
|
|
1563
|
+
result.push(texts[i]);
|
|
1564
|
+
}
|
|
1565
|
+
return result.join('');
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function createFormatSimple() {
|
|
1569
|
+
return {
|
|
1570
|
+
format: ({ translation, params }) => formatter(translation, params),
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
const FormatSimple = () => (tolgee, tools) => {
|
|
1574
|
+
tools.setFinalFormatter(createFormatSimple());
|
|
1575
|
+
return tolgee;
|
|
1576
|
+
};
|
|
1197
1577
|
|
|
1198
|
-
exports.
|
|
1199
|
-
exports.
|
|
1200
|
-
exports.TOLGEE_ATTRIBUTE_NAME = TOLGEE_ATTRIBUTE_NAME;
|
|
1201
|
-
exports.TOLGEE_HIGHLIGHTER_CLASS = TOLGEE_HIGHLIGHTER_CLASS;
|
|
1202
|
-
exports.TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE = TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE;
|
|
1203
|
-
exports.Tolgee = Tolgee;
|
|
1578
|
+
exports.FormatSimple = FormatSimple;
|
|
1579
|
+
exports.TolgeeCore = TolgeeCore;
|
|
1204
1580
|
exports.getFallback = getFallback;
|
|
1205
1581
|
exports.getFallbackArray = getFallbackArray;
|
|
1206
|
-
exports.
|
|
1582
|
+
exports.getTranslateProps = getTranslateProps;
|
|
1207
1583
|
|
|
1208
1584
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1209
1585
|
|