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