@tolgee/core 5.33.2 → 5.33.3-prerelease.2efc0e6b.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/dist/tolgee.cjs.js +227 -186
- 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.js +227 -186
- package/dist/tolgee.esm.js.map +1 -1
- package/dist/tolgee.esm.min.js +1 -1
- package/dist/tolgee.esm.min.js.map +1 -1
- package/dist/tolgee.esm.min.mjs +1 -1
- package/dist/tolgee.esm.min.mjs.map +1 -1
- package/dist/tolgee.esm.mjs +227 -186
- package/dist/tolgee.esm.mjs.map +1 -1
- package/dist/tolgee.umd.js +227 -186
- 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 +8 -12
- package/lib/Controller/Cache/helpers.d.ts +3 -2
- package/lib/Controller/Controller.d.ts +57 -26
- package/lib/Controller/Events/EventEmitter.d.ts +5 -5
- package/lib/Controller/Events/EventEmitterCombined.d.ts +6 -0
- package/lib/Controller/Events/Events.d.ts +39 -12
- package/lib/Controller/State/State.d.ts +10 -4
- package/lib/Controller/State/initState.d.ts +29 -7
- package/lib/TolgeeCore.d.ts +25 -28
- package/lib/helpers.d.ts +2 -2
- package/lib/types/cache.d.ts +19 -1
- package/lib/types/events.d.ts +24 -23
- package/lib/types/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/Controller/Cache/Cache.test.ts +189 -0
- package/src/Controller/Cache/Cache.ts +118 -57
- package/src/Controller/Cache/helpers.ts +12 -3
- package/src/Controller/Controller.ts +81 -27
- package/src/Controller/Events/EventEmitter.ts +23 -15
- package/src/Controller/Events/EventEmitterCombined.ts +55 -0
- package/src/Controller/Events/Events.ts +31 -23
- package/src/Controller/Plugins/Plugins.ts +5 -0
- package/src/Controller/State/State.ts +26 -6
- package/src/Controller/State/initState.ts +35 -7
- package/src/TolgeeCore.ts +14 -17
- package/src/__test/cache.test.ts +2 -26
- package/src/__test/client.test.ts +3 -3
- package/src/__test/events.test.ts +40 -13
- package/src/__test/load.matrix.test.ts +123 -0
- package/src/__test/load.required.test.ts +71 -0
- package/src/__test/namespaces.required.test.ts +52 -0
- package/src/__test/options.test.ts +1 -1
- package/src/__test/testTools.ts +39 -0
- package/src/helpers.ts +2 -1
- package/src/types/cache.ts +24 -1
- package/src/types/events.ts +33 -24
- package/src/types/index.ts +1 -0
- package/lib/Controller/Events/EventEmitterSelective.d.ts +0 -7
- package/src/Controller/Events/EventEmitterSelective.test.ts +0 -110
- package/src/Controller/Events/EventEmitterSelective.ts +0 -133
package/dist/tolgee.cjs.js
CHANGED
|
@@ -90,9 +90,9 @@ const createFetchFunction = (fetchFn = defaultFetchFunction) => {
|
|
|
90
90
|
};
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
const EventEmitter = (type, isActive) => {
|
|
94
94
|
let handlers = [];
|
|
95
|
-
return
|
|
95
|
+
return {
|
|
96
96
|
listen(handler) {
|
|
97
97
|
const handlerWrapper = (e) => {
|
|
98
98
|
handler(e);
|
|
@@ -106,27 +106,14 @@ function EventEmitter(isActive) {
|
|
|
106
106
|
},
|
|
107
107
|
emit(data) {
|
|
108
108
|
if (isActive()) {
|
|
109
|
-
handlers.forEach((handler) => handler({ value: data }));
|
|
109
|
+
handlers.forEach((handler) => handler({ type: type, value: data }));
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
|
-
}
|
|
113
|
-
}
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
114
|
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
const partialListeners = new Set();
|
|
118
|
-
function callHandlers(ns) {
|
|
119
|
-
// everything is implicitly subscribed to fallbacks
|
|
120
|
-
// as it can always fall through to it
|
|
121
|
-
const fallbackNamespaces = new Set(getFallbackNs());
|
|
122
|
-
partialListeners.forEach((handler) => {
|
|
123
|
-
const nsMatches = ns === undefined ||
|
|
124
|
-
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => fallbackNamespaces.has(ns) || handler.namespaces.has(ns))) !== -1;
|
|
125
|
-
if (nsMatches) {
|
|
126
|
-
handler.fn({ value: undefined });
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
115
|
+
function EventEmitterCombined(isActive) {
|
|
116
|
+
let handlers = [];
|
|
130
117
|
let queue = [];
|
|
131
118
|
// merge events in queue into one event
|
|
132
119
|
function solveQueue() {
|
|
@@ -135,87 +122,54 @@ function EventEmitterSelective(isActive, getFallbackNs, getDefaultNs) {
|
|
|
135
122
|
}
|
|
136
123
|
const queueCopy = queue;
|
|
137
124
|
queue = [];
|
|
138
|
-
|
|
139
|
-
handler(
|
|
125
|
+
handlers.forEach((handler) => {
|
|
126
|
+
handler(queueCopy);
|
|
140
127
|
});
|
|
141
|
-
let namespaces = new Set();
|
|
142
|
-
queueCopy.forEach((ns) => {
|
|
143
|
-
if (ns === undefined) {
|
|
144
|
-
// when no ns specified, it affects all namespaces
|
|
145
|
-
namespaces = undefined;
|
|
146
|
-
}
|
|
147
|
-
else if (namespaces !== undefined) {
|
|
148
|
-
ns.forEach((ns) => namespaces.add(ns));
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
const namespacesArray = namespaces
|
|
152
|
-
? Array.from(namespaces.keys())
|
|
153
|
-
: undefined;
|
|
154
|
-
callHandlers(namespacesArray);
|
|
155
128
|
}
|
|
156
129
|
return Object.freeze({
|
|
157
|
-
emit(ns, delayed) {
|
|
158
|
-
if (isActive()) {
|
|
159
|
-
queue.push(ns);
|
|
160
|
-
if (!delayed) {
|
|
161
|
-
solveQueue();
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
setTimeout(solveQueue, 0);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
130
|
listen(handler) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
unsubscribe: () => {
|
|
172
|
-
listeners.delete(handler);
|
|
173
|
-
},
|
|
131
|
+
const handlerWrapper = (events) => {
|
|
132
|
+
handler(events);
|
|
174
133
|
};
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
fn: (e) => {
|
|
180
|
-
handler(e);
|
|
134
|
+
handlers.push(handlerWrapper);
|
|
135
|
+
return {
|
|
136
|
+
unsubscribe() {
|
|
137
|
+
handlers = handlers.filter((i) => handlerWrapper !== i);
|
|
181
138
|
},
|
|
182
|
-
namespaces: new Set(),
|
|
183
139
|
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (ns === undefined) {
|
|
192
|
-
// subscribing to default ns
|
|
193
|
-
handlerWrapper.namespaces.add(getDefaultNs());
|
|
140
|
+
},
|
|
141
|
+
emit(e, delayed) {
|
|
142
|
+
if (isActive()) {
|
|
143
|
+
if (isActive()) {
|
|
144
|
+
queue.push(e);
|
|
145
|
+
if (!delayed) {
|
|
146
|
+
solveQueue();
|
|
194
147
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
148
|
+
else {
|
|
149
|
+
setTimeout(solveQueue, 0);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
199
153
|
},
|
|
200
154
|
});
|
|
201
155
|
}
|
|
202
156
|
|
|
203
|
-
function Events(
|
|
157
|
+
function Events() {
|
|
204
158
|
let emitterActive = true;
|
|
205
159
|
function isActive() {
|
|
206
160
|
return emitterActive;
|
|
207
161
|
}
|
|
208
162
|
const self = Object.freeze({
|
|
209
|
-
onPendingLanguageChange: EventEmitter(isActive),
|
|
210
|
-
onLanguageChange: EventEmitter(isActive),
|
|
211
|
-
onLoadingChange: EventEmitter(isActive),
|
|
212
|
-
onFetchingChange: EventEmitter(isActive),
|
|
213
|
-
onInitialLoaded: EventEmitter(isActive),
|
|
214
|
-
onRunningChange: EventEmitter(isActive),
|
|
215
|
-
onCacheChange: EventEmitter(isActive),
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
163
|
+
onPendingLanguageChange: EventEmitter('pendingLanguage', isActive),
|
|
164
|
+
onLanguageChange: EventEmitter('language', isActive),
|
|
165
|
+
onLoadingChange: EventEmitter('loading', isActive),
|
|
166
|
+
onFetchingChange: EventEmitter('fetching', isActive),
|
|
167
|
+
onInitialLoaded: EventEmitter('initialLoad', isActive),
|
|
168
|
+
onRunningChange: EventEmitter('running', isActive),
|
|
169
|
+
onCacheChange: EventEmitter('cache', isActive),
|
|
170
|
+
onPermanentChange: EventEmitter('permanentChange', isActive),
|
|
171
|
+
onError: EventEmitter('error', isActive),
|
|
172
|
+
onUpdate: EventEmitterCombined(isActive),
|
|
219
173
|
setEmitterActive(active) {
|
|
220
174
|
emitterActive = active;
|
|
221
175
|
},
|
|
@@ -244,9 +198,9 @@ function Events(getFallbackNs, getDefaultNs) {
|
|
|
244
198
|
}
|
|
245
199
|
}),
|
|
246
200
|
});
|
|
247
|
-
self.onInitialLoaded.listen(() => self.onUpdate.emit());
|
|
248
|
-
self.onLanguageChange.listen(() => self.onUpdate.emit());
|
|
249
|
-
self.onCacheChange.listen((
|
|
201
|
+
self.onInitialLoaded.listen((e) => self.onUpdate.emit(e, false));
|
|
202
|
+
self.onLanguageChange.listen((e) => self.onUpdate.emit(e, false));
|
|
203
|
+
self.onCacheChange.listen((e) => self.onUpdate.emit(e, true));
|
|
250
204
|
return self;
|
|
251
205
|
}
|
|
252
206
|
|
|
@@ -276,7 +230,7 @@ class LanguageStorageError extends Error {
|
|
|
276
230
|
}
|
|
277
231
|
}
|
|
278
232
|
|
|
279
|
-
const
|
|
233
|
+
const flattenTranslationsToMap = (data) => {
|
|
280
234
|
const result = new Map();
|
|
281
235
|
Object.entries(data).forEach(([key, value]) => {
|
|
282
236
|
// ignore empty values
|
|
@@ -284,7 +238,7 @@ const flattenTranslations = (data) => {
|
|
|
284
238
|
return;
|
|
285
239
|
}
|
|
286
240
|
if (typeof value === 'object') {
|
|
287
|
-
|
|
241
|
+
flattenTranslationsToMap(value).forEach((flatValue, flatKey) => {
|
|
288
242
|
result.set(key + '.' + flatKey, flatValue);
|
|
289
243
|
});
|
|
290
244
|
return;
|
|
@@ -293,6 +247,9 @@ const flattenTranslations = (data) => {
|
|
|
293
247
|
});
|
|
294
248
|
return result;
|
|
295
249
|
};
|
|
250
|
+
const flattenTranslations = (data) => {
|
|
251
|
+
return Object.fromEntries(flattenTranslationsToMap(data).entries());
|
|
252
|
+
};
|
|
296
253
|
const decodeCacheKey = (key) => {
|
|
297
254
|
const [firstPart, ...rest] = key.split(':');
|
|
298
255
|
// if namespaces contains ":" it won't get lost
|
|
@@ -308,7 +265,7 @@ const encodeCacheKey = ({ language, namespace, }) => {
|
|
|
308
265
|
}
|
|
309
266
|
};
|
|
310
267
|
|
|
311
|
-
function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isInitialLoading, fetchingObserver, loadingObserver) {
|
|
268
|
+
function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isInitialLoading, isCacheDisabled, fetchingObserver, loadingObserver) {
|
|
312
269
|
const asyncRequests = new Map();
|
|
313
270
|
const cache = new Map();
|
|
314
271
|
let staticData = {};
|
|
@@ -319,7 +276,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
319
276
|
data: flattenTranslations(data),
|
|
320
277
|
version: recordVersion,
|
|
321
278
|
});
|
|
322
|
-
events.onCacheChange.emit(
|
|
279
|
+
events.onCacheChange.emit(decodeCacheKey(cacheKey));
|
|
323
280
|
}
|
|
324
281
|
/**
|
|
325
282
|
* Fetches production data
|
|
@@ -372,14 +329,23 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
372
329
|
}
|
|
373
330
|
const self = Object.freeze({
|
|
374
331
|
addStaticData(data) {
|
|
375
|
-
if (data) {
|
|
332
|
+
if (Array.isArray(data)) {
|
|
333
|
+
for (const record of data) {
|
|
334
|
+
const key = encodeCacheKey(record);
|
|
335
|
+
const existing = cache.get(key);
|
|
336
|
+
if (!existing || existing.version === 0) {
|
|
337
|
+
addRecordInternal(record, flattenTranslations(record.data), 0);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else if (data) {
|
|
376
342
|
staticData = Object.assign(Object.assign({}, staticData), data);
|
|
377
343
|
Object.entries(data).forEach(([key, value]) => {
|
|
378
344
|
if (typeof value !== 'function') {
|
|
379
345
|
const descriptor = decodeCacheKey(key);
|
|
380
346
|
const existing = cache.get(key);
|
|
381
347
|
if (!existing || existing.version === 0) {
|
|
382
|
-
addRecordInternal(descriptor, value, 0);
|
|
348
|
+
addRecordInternal(descriptor, flattenTranslations(value), 0);
|
|
383
349
|
}
|
|
384
350
|
}
|
|
385
351
|
});
|
|
@@ -390,7 +356,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
390
356
|
version += 1;
|
|
391
357
|
},
|
|
392
358
|
addRecord(descriptor, data) {
|
|
393
|
-
addRecordInternal(descriptor, data, version);
|
|
359
|
+
addRecordInternal(descriptor, flattenTranslations(data), version);
|
|
394
360
|
},
|
|
395
361
|
exists(descriptor, strict = false) {
|
|
396
362
|
const record = cache.get(encodeCacheKey(descriptor));
|
|
@@ -400,19 +366,27 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
400
366
|
return Boolean(record);
|
|
401
367
|
},
|
|
402
368
|
getRecord(descriptor) {
|
|
403
|
-
|
|
404
|
-
|
|
369
|
+
const descriptorWithNs = withDefaultNs(descriptor);
|
|
370
|
+
const cacheKey = encodeCacheKey(descriptorWithNs);
|
|
371
|
+
const cacheRecord = cache.get(cacheKey);
|
|
372
|
+
if (!cacheRecord) {
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
375
|
+
return Object.assign(Object.assign({}, descriptorWithNs), { cacheKey, data: cacheRecord.data });
|
|
376
|
+
},
|
|
377
|
+
getAllRecords() {
|
|
378
|
+
const entries = Array.from(cache.entries());
|
|
379
|
+
return entries.map(([key]) => self.getRecord(decodeCacheKey(key)));
|
|
405
380
|
},
|
|
406
381
|
getTranslation(descriptor, key) {
|
|
407
382
|
var _a;
|
|
408
|
-
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data
|
|
383
|
+
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
409
384
|
},
|
|
410
385
|
getTranslationNs(namespaces, languages, key) {
|
|
411
386
|
var _a;
|
|
412
387
|
for (const namespace of namespaces) {
|
|
413
388
|
for (const language of languages) {
|
|
414
|
-
const value = (_a = cache
|
|
415
|
-
.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data.get(key);
|
|
389
|
+
const value = (_a = cache.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
416
390
|
if (value !== undefined && value !== null) {
|
|
417
391
|
return [namespace];
|
|
418
392
|
}
|
|
@@ -424,8 +398,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
424
398
|
var _a;
|
|
425
399
|
for (const namespace of namespaces) {
|
|
426
400
|
for (const language of languages) {
|
|
427
|
-
const value = (_a = cache
|
|
428
|
-
.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data.get(key);
|
|
401
|
+
const value = (_a = cache.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
429
402
|
if (value !== undefined && value !== null) {
|
|
430
403
|
return value;
|
|
431
404
|
}
|
|
@@ -436,8 +409,10 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
436
409
|
changeTranslation(descriptor, key, value) {
|
|
437
410
|
var _a;
|
|
438
411
|
const record = (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data;
|
|
439
|
-
record === null || record === void 0 ? void 0 : record
|
|
440
|
-
|
|
412
|
+
if (record === null || record === void 0 ? void 0 : record[key]) {
|
|
413
|
+
record[key] = value;
|
|
414
|
+
events.onCacheChange.emit(Object.assign(Object.assign({}, descriptor), { key }));
|
|
415
|
+
}
|
|
441
416
|
},
|
|
442
417
|
isFetching(ns) {
|
|
443
418
|
if (isInitialLoading()) {
|
|
@@ -451,66 +426,74 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
451
426
|
},
|
|
452
427
|
isLoading(language, ns) {
|
|
453
428
|
const namespaces = getFallbackArray(ns);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
429
|
+
if (isInitialLoading()) {
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
const pendingCacheKeys = Array.from(asyncRequests.keys());
|
|
433
|
+
return Boolean(pendingCacheKeys.find((key) => {
|
|
434
|
+
const descriptor = decodeCacheKey(key);
|
|
435
|
+
return ((!namespaces.length || namespaces.includes(descriptor.namespace)) &&
|
|
436
|
+
!self.exists({
|
|
437
|
+
namespace: descriptor.namespace,
|
|
438
|
+
language: language,
|
|
439
|
+
}));
|
|
440
|
+
}));
|
|
441
|
+
},
|
|
442
|
+
async loadRecords(descriptors, options) {
|
|
466
443
|
const withPromises = descriptors.map((descriptor) => {
|
|
467
444
|
const keyObject = withDefaultNs(descriptor);
|
|
468
445
|
const cacheKey = encodeCacheKey(keyObject);
|
|
446
|
+
if (options === null || options === void 0 ? void 0 : options.useCache) {
|
|
447
|
+
const exists = self.exists(keyObject, true);
|
|
448
|
+
if (exists) {
|
|
449
|
+
return Object.assign(Object.assign({}, keyObject), { new: false, cacheKey, data: self.getRecord(keyObject).data });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
469
452
|
const existingPromise = asyncRequests.get(cacheKey);
|
|
470
453
|
if (existingPromise) {
|
|
471
|
-
return {
|
|
472
|
-
new: false,
|
|
473
|
-
promise: existingPromise,
|
|
474
|
-
keyObject,
|
|
475
|
-
cacheKey,
|
|
476
|
-
};
|
|
454
|
+
return Object.assign(Object.assign({}, keyObject), { new: false, promise: existingPromise, cacheKey });
|
|
477
455
|
}
|
|
478
|
-
const dataPromise = fetchData(keyObject,
|
|
456
|
+
const dataPromise = fetchData(keyObject, !(options === null || options === void 0 ? void 0 : options.noDev)) || Promise.resolve(undefined);
|
|
479
457
|
asyncRequests.set(cacheKey, dataPromise);
|
|
480
|
-
return {
|
|
481
|
-
new: true,
|
|
482
|
-
promise: dataPromise,
|
|
483
|
-
keyObject,
|
|
484
|
-
cacheKey,
|
|
485
|
-
};
|
|
458
|
+
return Object.assign(Object.assign({}, keyObject), { new: true, promise: dataPromise, cacheKey });
|
|
486
459
|
});
|
|
487
460
|
fetchingObserver.notify();
|
|
488
461
|
loadingObserver.notify();
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
462
|
+
const promisesToWait = withPromises
|
|
463
|
+
.map((val) => val.promise)
|
|
464
|
+
.filter(Boolean);
|
|
465
|
+
const fetchedData = await Promise.all(promisesToWait);
|
|
466
|
+
withPromises.forEach((value) => {
|
|
467
|
+
var _a;
|
|
468
|
+
if (value.promise) {
|
|
469
|
+
value.data = flattenTranslations((_a = fetchedData[0]) !== null && _a !== void 0 ? _a : {});
|
|
470
|
+
fetchedData.shift();
|
|
471
|
+
}
|
|
492
472
|
// if promise has changed in between, it means cache been invalidated or
|
|
493
473
|
// new data are being fetched
|
|
474
|
+
const promiseChanged = asyncRequests.get(value.cacheKey) !== value.promise;
|
|
494
475
|
if (value.new && !promiseChanged) {
|
|
495
476
|
asyncRequests.delete(value.cacheKey);
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
self.addRecord(value.keyObject, data);
|
|
477
|
+
if (value.data) {
|
|
478
|
+
self.addRecord(value, value.data);
|
|
499
479
|
}
|
|
500
|
-
else if (!self.getRecord(value
|
|
480
|
+
else if (!self.getRecord(value)) {
|
|
501
481
|
// if no data exist, put empty object
|
|
502
|
-
|
|
482
|
+
// so we know we don't have to fetch again
|
|
483
|
+
self.addRecord(value, {});
|
|
503
484
|
}
|
|
504
485
|
}
|
|
505
486
|
});
|
|
506
487
|
fetchingObserver.notify();
|
|
507
488
|
loadingObserver.notify();
|
|
508
|
-
return withPromises.map((val) =>
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
489
|
+
return withPromises.map((val) => {
|
|
490
|
+
var _a;
|
|
491
|
+
return ({
|
|
492
|
+
language: val.language,
|
|
493
|
+
namespace: val.namespace,
|
|
494
|
+
data: (_a = val.data) !== null && _a !== void 0 ? _a : {},
|
|
495
|
+
cacheKey: val.cacheKey,
|
|
496
|
+
});
|
|
514
497
|
});
|
|
515
498
|
},
|
|
516
499
|
});
|
|
@@ -565,13 +548,14 @@ const DEFAULT_FORMAT_ERROR = 'invalid';
|
|
|
565
548
|
const DEFAULT_API_URL = 'https://app.tolgee.io';
|
|
566
549
|
const DEFAULT_MISSING_TRANSLATION = ({ key, }) => key;
|
|
567
550
|
const defaultValues = {
|
|
568
|
-
defaultNs: '',
|
|
569
551
|
observerOptions: defaultObserverOptions,
|
|
570
552
|
observerType: 'invisible',
|
|
571
553
|
onFormatError: DEFAULT_FORMAT_ERROR,
|
|
572
554
|
apiUrl: DEFAULT_API_URL,
|
|
555
|
+
autoLoadRequiredData: true,
|
|
573
556
|
fetch: createFetchFunction(),
|
|
574
557
|
onTranslationMissing: DEFAULT_MISSING_TRANSLATION,
|
|
558
|
+
disableCache: false,
|
|
575
559
|
};
|
|
576
560
|
const combineOptions = (...states) => {
|
|
577
561
|
let result = {};
|
|
@@ -765,6 +749,9 @@ function Plugins(getLanguage, getInitialOptions, getAvailableLanguages, getFallb
|
|
|
765
749
|
getBackendDevRecord: (async ({ language, namespace }) => {
|
|
766
750
|
var _a;
|
|
767
751
|
const { apiKey, apiUrl, projectId, filterTag } = getInitialOptions();
|
|
752
|
+
if (!apiKey || !apiUrl || !self.hasDevBackend()) {
|
|
753
|
+
return undefined;
|
|
754
|
+
}
|
|
768
755
|
return (_a = instances.devBackend) === null || _a === void 0 ? void 0 : _a.getRecord(Object.assign({ apiKey,
|
|
769
756
|
apiUrl,
|
|
770
757
|
projectId,
|
|
@@ -908,6 +895,9 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
908
895
|
isInitialLoading() {
|
|
909
896
|
return state.isInitialLoading;
|
|
910
897
|
},
|
|
898
|
+
isCacheDisabled() {
|
|
899
|
+
return state.initialOptions.disableCache;
|
|
900
|
+
},
|
|
911
901
|
setInitialLoading(value) {
|
|
912
902
|
state.isInitialLoading = value;
|
|
913
903
|
},
|
|
@@ -958,7 +948,8 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
958
948
|
},
|
|
959
949
|
getRequiredNamespaces() {
|
|
960
950
|
return unique([
|
|
961
|
-
|
|
951
|
+
self.getDefaultNs(),
|
|
952
|
+
...(state.initialOptions.ns || []),
|
|
962
953
|
...getFallbackArray(state.initialOptions.fallbackNs),
|
|
963
954
|
...state.activeNamespaces.keys(),
|
|
964
955
|
]);
|
|
@@ -976,8 +967,17 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
976
967
|
getFallbackNs() {
|
|
977
968
|
return getFallbackArray(state.initialOptions.fallbackNs);
|
|
978
969
|
},
|
|
970
|
+
getNs() {
|
|
971
|
+
var _a, _b;
|
|
972
|
+
return ((_a = state.initialOptions.ns) === null || _a === void 0 ? void 0 : _a.length)
|
|
973
|
+
? state.initialOptions.ns
|
|
974
|
+
: [(_b = state.initialOptions.defaultNs) !== null && _b !== void 0 ? _b : ''];
|
|
975
|
+
},
|
|
979
976
|
getDefaultNs(ns) {
|
|
980
|
-
|
|
977
|
+
var _a, _b, _c;
|
|
978
|
+
return ns === undefined
|
|
979
|
+
? (_c = (_a = state.initialOptions.defaultNs) !== null && _a !== void 0 ? _a : (_b = state.initialOptions.ns) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : ''
|
|
980
|
+
: ns;
|
|
981
981
|
},
|
|
982
982
|
getAvailableLanguages() {
|
|
983
983
|
if (state.initialOptions.availableLanguages) {
|
|
@@ -988,10 +988,13 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
988
988
|
return Array.from(new Set(languagesFromStaticData));
|
|
989
989
|
}
|
|
990
990
|
},
|
|
991
|
+
getAvailableNs() {
|
|
992
|
+
return state.initialOptions.availableNs;
|
|
993
|
+
},
|
|
991
994
|
withDefaultNs(descriptor) {
|
|
992
995
|
return {
|
|
993
996
|
namespace: descriptor.namespace === undefined
|
|
994
|
-
? self.
|
|
997
|
+
? self.getDefaultNs()
|
|
995
998
|
: descriptor.namespace,
|
|
996
999
|
language: descriptor.language,
|
|
997
1000
|
};
|
|
@@ -1041,12 +1044,12 @@ const getTranslateProps = (keyOrProps, ...params) => {
|
|
|
1041
1044
|
};
|
|
1042
1045
|
|
|
1043
1046
|
function Controller({ options }) {
|
|
1044
|
-
const events = Events(
|
|
1047
|
+
const events = Events();
|
|
1045
1048
|
const fetchingObserver = ValueObserver(false, () => cache.isFetching(), events.onFetchingChange.emit);
|
|
1046
1049
|
const loadingObserver = ValueObserver(false, () => self.isLoading(), events.onLoadingChange.emit);
|
|
1047
1050
|
const state = State(events.onLanguageChange, events.onPendingLanguageChange, events.onRunningChange);
|
|
1048
1051
|
const pluginService = Plugins(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getDefaultAndFallbackNs, getTranslationNs, getTranslation, changeTranslation, events);
|
|
1049
|
-
const cache = Cache(events, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, fetchingObserver, loadingObserver);
|
|
1052
|
+
const cache = Cache(events, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, state.isCacheDisabled, fetchingObserver, loadingObserver);
|
|
1050
1053
|
if (options) {
|
|
1051
1054
|
init(options);
|
|
1052
1055
|
}
|
|
@@ -1065,15 +1068,15 @@ function Controller({ options }) {
|
|
|
1065
1068
|
// gets all namespaces where translation could be located
|
|
1066
1069
|
// takes (ns|default, fallback ns)
|
|
1067
1070
|
function getDefaultAndFallbackNs(ns) {
|
|
1068
|
-
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
|
|
1071
|
+
return unique([...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()]);
|
|
1069
1072
|
}
|
|
1070
1073
|
// gets all namespaces which need to be loaded
|
|
1071
1074
|
// takes (ns|default, initial ns, fallback ns, active ns)
|
|
1072
1075
|
function getRequiredNamespaces(ns) {
|
|
1073
|
-
return [
|
|
1076
|
+
return unique([
|
|
1074
1077
|
...getFallbackArray(ns !== null && ns !== void 0 ? ns : getDefaultNs()),
|
|
1075
1078
|
...state.getRequiredNamespaces(),
|
|
1076
|
-
];
|
|
1079
|
+
]);
|
|
1077
1080
|
}
|
|
1078
1081
|
function changeTranslation(descriptor, key, value) {
|
|
1079
1082
|
const keyObject = state.withDefaultNs(descriptor);
|
|
@@ -1089,24 +1092,50 @@ function Controller({ options }) {
|
|
|
1089
1092
|
state.init(options);
|
|
1090
1093
|
cache.addStaticData(state.getInitialOptions().staticData);
|
|
1091
1094
|
}
|
|
1092
|
-
function
|
|
1095
|
+
function getRequiredDescriptors(lang, ns) {
|
|
1093
1096
|
const languages = state.getFallbackLangs(lang);
|
|
1094
1097
|
const namespaces = getRequiredNamespaces(ns);
|
|
1095
1098
|
const result = [];
|
|
1096
1099
|
languages.forEach((language) => {
|
|
1097
1100
|
namespaces.forEach((namespace) => {
|
|
1098
|
-
|
|
1099
|
-
result.push({ language, namespace });
|
|
1100
|
-
}
|
|
1101
|
+
result.push({ language, namespace });
|
|
1101
1102
|
});
|
|
1102
1103
|
});
|
|
1103
1104
|
return result;
|
|
1104
1105
|
}
|
|
1105
|
-
function
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1106
|
+
function getMissingDescriptors(lang, ns) {
|
|
1107
|
+
return getRequiredDescriptors(lang, ns).filter((descriptor) => !cache.exists(descriptor, true));
|
|
1108
|
+
}
|
|
1109
|
+
function getMatrixRecords(options) {
|
|
1110
|
+
let languages = [];
|
|
1111
|
+
let namespaces = [];
|
|
1112
|
+
if (Array.isArray(options.languages)) {
|
|
1113
|
+
languages = options.languages;
|
|
1114
|
+
}
|
|
1115
|
+
else if (options.languages === 'all') {
|
|
1116
|
+
const availableLanguages = self.getAvailableLanguages();
|
|
1117
|
+
if (!availableLanguages) {
|
|
1118
|
+
throw new Error(missingOptionError('availableLanguages'));
|
|
1119
|
+
}
|
|
1120
|
+
languages = availableLanguages;
|
|
1121
|
+
}
|
|
1122
|
+
if (Array.isArray(options.namespaces)) {
|
|
1123
|
+
namespaces = options.namespaces;
|
|
1124
|
+
}
|
|
1125
|
+
else if (options.namespaces === 'all') {
|
|
1126
|
+
const availableNs = self.getAvailableNs();
|
|
1127
|
+
if (!availableNs) {
|
|
1128
|
+
throw new Error(missingOptionError('availableNs'));
|
|
1129
|
+
}
|
|
1130
|
+
namespaces = availableNs;
|
|
1109
1131
|
}
|
|
1132
|
+
const records = [];
|
|
1133
|
+
languages.forEach((language) => {
|
|
1134
|
+
namespaces.forEach((namespace) => {
|
|
1135
|
+
records.push({ language, namespace });
|
|
1136
|
+
});
|
|
1137
|
+
});
|
|
1138
|
+
return records;
|
|
1110
1139
|
}
|
|
1111
1140
|
function getTranslationNs({ key, ns }) {
|
|
1112
1141
|
const languages = state.getFallbackLangs();
|
|
@@ -1120,8 +1149,11 @@ function Controller({ options }) {
|
|
|
1120
1149
|
}
|
|
1121
1150
|
function loadInitial() {
|
|
1122
1151
|
const data = valueOrPromise(initializeLanguage(), () => {
|
|
1123
|
-
|
|
1124
|
-
|
|
1152
|
+
const missingDescriptors = getMissingDescriptors();
|
|
1153
|
+
if (missingDescriptors.length &&
|
|
1154
|
+
state.getInitialOptions().autoLoadRequiredData) {
|
|
1155
|
+
return cache.loadRecords(missingDescriptors, { useCache: true });
|
|
1156
|
+
}
|
|
1125
1157
|
});
|
|
1126
1158
|
if (isPromise(data)) {
|
|
1127
1159
|
state.setInitialLoading(true);
|
|
@@ -1162,14 +1194,16 @@ function Controller({ options }) {
|
|
|
1162
1194
|
throw new Error(missingOptionError(['defaultLanguage', 'language']));
|
|
1163
1195
|
}
|
|
1164
1196
|
}
|
|
1165
|
-
const self = Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, events), state), pluginService), cache), { init: init, getTranslation: getTranslation, changeTranslation: changeTranslation, getTranslationNs: getTranslationNs, getDefaultAndFallbackNs: getDefaultAndFallbackNs, findPositions: pluginService.findPositions,
|
|
1197
|
+
const self = Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, events), state), pluginService), cache), { init: init, getTranslation: getTranslation, changeTranslation: changeTranslation, getTranslationNs: getTranslationNs, getDefaultAndFallbackNs: getDefaultAndFallbackNs, findPositions: pluginService.findPositions, getRequiredDescriptors: getRequiredDescriptors, async changeLanguage(language) {
|
|
1166
1198
|
if (state.getPendingLanguage() === language &&
|
|
1167
1199
|
state.getLanguage() === language) {
|
|
1168
1200
|
return;
|
|
1169
1201
|
}
|
|
1170
1202
|
state.setPendingLanguage(language);
|
|
1171
|
-
if (state.isRunning()) {
|
|
1172
|
-
await
|
|
1203
|
+
if (state.isRunning() && state.getInitialOptions().autoLoadRequiredData) {
|
|
1204
|
+
await cache.loadRecords(getRequiredDescriptors(language), {
|
|
1205
|
+
useCache: true,
|
|
1206
|
+
});
|
|
1173
1207
|
}
|
|
1174
1208
|
if (language === state.getPendingLanguage()) {
|
|
1175
1209
|
// there might be parallel language change
|
|
@@ -1183,14 +1217,14 @@ function Controller({ options }) {
|
|
|
1183
1217
|
state.addActiveNs(ns);
|
|
1184
1218
|
}
|
|
1185
1219
|
if (state.isRunning()) {
|
|
1186
|
-
await
|
|
1220
|
+
await cache.loadRecords(getRequiredDescriptors(undefined, ns), {
|
|
1221
|
+
useCache: true,
|
|
1222
|
+
});
|
|
1187
1223
|
}
|
|
1188
1224
|
},
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
async loadRecord(descriptor) {
|
|
1193
|
-
return (await self.loadRecords([descriptor]))[0];
|
|
1225
|
+
async loadRecord(descriptor, options) {
|
|
1226
|
+
var _a;
|
|
1227
|
+
return (_a = (await self.loadRecords([descriptor], options))[0]) === null || _a === void 0 ? void 0 : _a.data;
|
|
1194
1228
|
},
|
|
1195
1229
|
isLoading(ns) {
|
|
1196
1230
|
return cache.isLoading(state.getLanguage(), ns);
|
|
@@ -1219,6 +1253,17 @@ function Controller({ options }) {
|
|
|
1219
1253
|
}), isDev() {
|
|
1220
1254
|
return Boolean(state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl);
|
|
1221
1255
|
},
|
|
1256
|
+
async loadRequired(options) {
|
|
1257
|
+
if (!(options === null || options === void 0 ? void 0 : options.language)) {
|
|
1258
|
+
await initializeLanguage();
|
|
1259
|
+
}
|
|
1260
|
+
const requiredRecords = getRequiredDescriptors(options === null || options === void 0 ? void 0 : options.language);
|
|
1261
|
+
return self.loadRecords(requiredRecords, options);
|
|
1262
|
+
},
|
|
1263
|
+
async loadMatrix(options) {
|
|
1264
|
+
const records = getMatrixRecords(options);
|
|
1265
|
+
return self.loadRecords(records, options);
|
|
1266
|
+
},
|
|
1222
1267
|
run() {
|
|
1223
1268
|
checkCorrectConfiguration();
|
|
1224
1269
|
if (!state.isRunning()) {
|
|
@@ -1259,20 +1304,6 @@ function createTolgee(options) {
|
|
|
1259
1304
|
* Listen to tolgee events.
|
|
1260
1305
|
*/
|
|
1261
1306
|
on: controller.on,
|
|
1262
|
-
/**
|
|
1263
|
-
* Listen for specific namespaces changes.
|
|
1264
|
-
*
|
|
1265
|
-
* ```
|
|
1266
|
-
* const sub = tolgee.onUpdate(handler)
|
|
1267
|
-
*
|
|
1268
|
-
* // subscribe to selected namespace
|
|
1269
|
-
* sub.subscribeNs(['common'])
|
|
1270
|
-
*
|
|
1271
|
-
* // unsubscribe
|
|
1272
|
-
* sub.unsubscribe()
|
|
1273
|
-
* ```
|
|
1274
|
-
*/
|
|
1275
|
-
onNsUpdate: controller.onUpdate.listenSome,
|
|
1276
1307
|
/**
|
|
1277
1308
|
* Turn off/on events emitting. Is on by default.
|
|
1278
1309
|
*/
|
|
@@ -1310,6 +1341,16 @@ function createTolgee(options) {
|
|
|
1310
1341
|
* so this method will remove namespace only if the counter goes down to 0.
|
|
1311
1342
|
*/
|
|
1312
1343
|
removeActiveNs: controller.removeActiveNs,
|
|
1344
|
+
/**
|
|
1345
|
+
* Load records which would be loaded by `run` function
|
|
1346
|
+
*
|
|
1347
|
+
* You can provide language if not previously set on tolgee instance
|
|
1348
|
+
*/
|
|
1349
|
+
loadRequired: controller.loadRequired,
|
|
1350
|
+
/**
|
|
1351
|
+
* Load records in matrix (languages x namespaces)
|
|
1352
|
+
*/
|
|
1353
|
+
loadMatrix: controller.loadMatrix,
|
|
1313
1354
|
/**
|
|
1314
1355
|
* Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
|
|
1315
1356
|
*
|
|
@@ -1338,9 +1379,9 @@ function createTolgee(options) {
|
|
|
1338
1379
|
*/
|
|
1339
1380
|
isLoaded: controller.isLoaded,
|
|
1340
1381
|
/**
|
|
1341
|
-
* Returns records needed for instance to be `loaded`
|
|
1382
|
+
* Returns descriptors of records needed for instance to be `loaded`
|
|
1342
1383
|
*/
|
|
1343
|
-
|
|
1384
|
+
getRequiredDescriptors: controller.getRequiredDescriptors,
|
|
1344
1385
|
/**
|
|
1345
1386
|
* @return `true` if tolgee is loading initial data (triggered by `run`).
|
|
1346
1387
|
*/
|