@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.esm.js
CHANGED
|
@@ -86,9 +86,9 @@ const createFetchFunction = (fetchFn = defaultFetchFunction) => {
|
|
|
86
86
|
};
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
const EventEmitter = (type, isActive) => {
|
|
90
90
|
let handlers = [];
|
|
91
|
-
return
|
|
91
|
+
return {
|
|
92
92
|
listen(handler) {
|
|
93
93
|
const handlerWrapper = (e) => {
|
|
94
94
|
handler(e);
|
|
@@ -102,27 +102,14 @@ function EventEmitter(isActive) {
|
|
|
102
102
|
},
|
|
103
103
|
emit(data) {
|
|
104
104
|
if (isActive()) {
|
|
105
|
-
handlers.forEach((handler) => handler({ value: data }));
|
|
105
|
+
handlers.forEach((handler) => handler({ type: type, value: data }));
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
|
-
}
|
|
109
|
-
}
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
110
|
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
const partialListeners = new Set();
|
|
114
|
-
function callHandlers(ns) {
|
|
115
|
-
// everything is implicitly subscribed to fallbacks
|
|
116
|
-
// as it can always fall through to it
|
|
117
|
-
const fallbackNamespaces = new Set(getFallbackNs());
|
|
118
|
-
partialListeners.forEach((handler) => {
|
|
119
|
-
const nsMatches = ns === undefined ||
|
|
120
|
-
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => fallbackNamespaces.has(ns) || handler.namespaces.has(ns))) !== -1;
|
|
121
|
-
if (nsMatches) {
|
|
122
|
-
handler.fn({ value: undefined });
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
111
|
+
function EventEmitterCombined(isActive) {
|
|
112
|
+
let handlers = [];
|
|
126
113
|
let queue = [];
|
|
127
114
|
// merge events in queue into one event
|
|
128
115
|
function solveQueue() {
|
|
@@ -131,87 +118,54 @@ function EventEmitterSelective(isActive, getFallbackNs, getDefaultNs) {
|
|
|
131
118
|
}
|
|
132
119
|
const queueCopy = queue;
|
|
133
120
|
queue = [];
|
|
134
|
-
|
|
135
|
-
handler(
|
|
121
|
+
handlers.forEach((handler) => {
|
|
122
|
+
handler(queueCopy);
|
|
136
123
|
});
|
|
137
|
-
let namespaces = new Set();
|
|
138
|
-
queueCopy.forEach((ns) => {
|
|
139
|
-
if (ns === undefined) {
|
|
140
|
-
// when no ns specified, it affects all namespaces
|
|
141
|
-
namespaces = undefined;
|
|
142
|
-
}
|
|
143
|
-
else if (namespaces !== undefined) {
|
|
144
|
-
ns.forEach((ns) => namespaces.add(ns));
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
const namespacesArray = namespaces
|
|
148
|
-
? Array.from(namespaces.keys())
|
|
149
|
-
: undefined;
|
|
150
|
-
callHandlers(namespacesArray);
|
|
151
124
|
}
|
|
152
125
|
return Object.freeze({
|
|
153
|
-
emit(ns, delayed) {
|
|
154
|
-
if (isActive()) {
|
|
155
|
-
queue.push(ns);
|
|
156
|
-
if (!delayed) {
|
|
157
|
-
solveQueue();
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
setTimeout(solveQueue, 0);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
126
|
listen(handler) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
unsubscribe: () => {
|
|
168
|
-
listeners.delete(handler);
|
|
169
|
-
},
|
|
127
|
+
const handlerWrapper = (events) => {
|
|
128
|
+
handler(events);
|
|
170
129
|
};
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
fn: (e) => {
|
|
176
|
-
handler(e);
|
|
130
|
+
handlers.push(handlerWrapper);
|
|
131
|
+
return {
|
|
132
|
+
unsubscribe() {
|
|
133
|
+
handlers = handlers.filter((i) => handlerWrapper !== i);
|
|
177
134
|
},
|
|
178
|
-
namespaces: new Set(),
|
|
179
135
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (ns === undefined) {
|
|
188
|
-
// subscribing to default ns
|
|
189
|
-
handlerWrapper.namespaces.add(getDefaultNs());
|
|
136
|
+
},
|
|
137
|
+
emit(e, delayed) {
|
|
138
|
+
if (isActive()) {
|
|
139
|
+
if (isActive()) {
|
|
140
|
+
queue.push(e);
|
|
141
|
+
if (!delayed) {
|
|
142
|
+
solveQueue();
|
|
190
143
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
144
|
+
else {
|
|
145
|
+
setTimeout(solveQueue, 0);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
195
149
|
},
|
|
196
150
|
});
|
|
197
151
|
}
|
|
198
152
|
|
|
199
|
-
function Events(
|
|
153
|
+
function Events() {
|
|
200
154
|
let emitterActive = true;
|
|
201
155
|
function isActive() {
|
|
202
156
|
return emitterActive;
|
|
203
157
|
}
|
|
204
158
|
const self = Object.freeze({
|
|
205
|
-
onPendingLanguageChange: EventEmitter(isActive),
|
|
206
|
-
onLanguageChange: EventEmitter(isActive),
|
|
207
|
-
onLoadingChange: EventEmitter(isActive),
|
|
208
|
-
onFetchingChange: EventEmitter(isActive),
|
|
209
|
-
onInitialLoaded: EventEmitter(isActive),
|
|
210
|
-
onRunningChange: EventEmitter(isActive),
|
|
211
|
-
onCacheChange: EventEmitter(isActive),
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
159
|
+
onPendingLanguageChange: EventEmitter('pendingLanguage', isActive),
|
|
160
|
+
onLanguageChange: EventEmitter('language', isActive),
|
|
161
|
+
onLoadingChange: EventEmitter('loading', isActive),
|
|
162
|
+
onFetchingChange: EventEmitter('fetching', isActive),
|
|
163
|
+
onInitialLoaded: EventEmitter('initialLoad', isActive),
|
|
164
|
+
onRunningChange: EventEmitter('running', isActive),
|
|
165
|
+
onCacheChange: EventEmitter('cache', isActive),
|
|
166
|
+
onPermanentChange: EventEmitter('permanentChange', isActive),
|
|
167
|
+
onError: EventEmitter('error', isActive),
|
|
168
|
+
onUpdate: EventEmitterCombined(isActive),
|
|
215
169
|
setEmitterActive(active) {
|
|
216
170
|
emitterActive = active;
|
|
217
171
|
},
|
|
@@ -240,9 +194,9 @@ function Events(getFallbackNs, getDefaultNs) {
|
|
|
240
194
|
}
|
|
241
195
|
}),
|
|
242
196
|
});
|
|
243
|
-
self.onInitialLoaded.listen(() => self.onUpdate.emit());
|
|
244
|
-
self.onLanguageChange.listen(() => self.onUpdate.emit());
|
|
245
|
-
self.onCacheChange.listen((
|
|
197
|
+
self.onInitialLoaded.listen((e) => self.onUpdate.emit(e, false));
|
|
198
|
+
self.onLanguageChange.listen((e) => self.onUpdate.emit(e, false));
|
|
199
|
+
self.onCacheChange.listen((e) => self.onUpdate.emit(e, true));
|
|
246
200
|
return self;
|
|
247
201
|
}
|
|
248
202
|
|
|
@@ -272,7 +226,7 @@ class LanguageStorageError extends Error {
|
|
|
272
226
|
}
|
|
273
227
|
}
|
|
274
228
|
|
|
275
|
-
const
|
|
229
|
+
const flattenTranslationsToMap = (data) => {
|
|
276
230
|
const result = new Map();
|
|
277
231
|
Object.entries(data).forEach(([key, value]) => {
|
|
278
232
|
// ignore empty values
|
|
@@ -280,7 +234,7 @@ const flattenTranslations = (data) => {
|
|
|
280
234
|
return;
|
|
281
235
|
}
|
|
282
236
|
if (typeof value === 'object') {
|
|
283
|
-
|
|
237
|
+
flattenTranslationsToMap(value).forEach((flatValue, flatKey) => {
|
|
284
238
|
result.set(key + '.' + flatKey, flatValue);
|
|
285
239
|
});
|
|
286
240
|
return;
|
|
@@ -289,6 +243,9 @@ const flattenTranslations = (data) => {
|
|
|
289
243
|
});
|
|
290
244
|
return result;
|
|
291
245
|
};
|
|
246
|
+
const flattenTranslations = (data) => {
|
|
247
|
+
return Object.fromEntries(flattenTranslationsToMap(data).entries());
|
|
248
|
+
};
|
|
292
249
|
const decodeCacheKey = (key) => {
|
|
293
250
|
const [firstPart, ...rest] = key.split(':');
|
|
294
251
|
// if namespaces contains ":" it won't get lost
|
|
@@ -304,7 +261,7 @@ const encodeCacheKey = ({ language, namespace, }) => {
|
|
|
304
261
|
}
|
|
305
262
|
};
|
|
306
263
|
|
|
307
|
-
function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isInitialLoading, fetchingObserver, loadingObserver) {
|
|
264
|
+
function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isInitialLoading, isCacheDisabled, fetchingObserver, loadingObserver) {
|
|
308
265
|
const asyncRequests = new Map();
|
|
309
266
|
const cache = new Map();
|
|
310
267
|
let staticData = {};
|
|
@@ -315,7 +272,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
315
272
|
data: flattenTranslations(data),
|
|
316
273
|
version: recordVersion,
|
|
317
274
|
});
|
|
318
|
-
events.onCacheChange.emit(
|
|
275
|
+
events.onCacheChange.emit(decodeCacheKey(cacheKey));
|
|
319
276
|
}
|
|
320
277
|
/**
|
|
321
278
|
* Fetches production data
|
|
@@ -368,14 +325,23 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
368
325
|
}
|
|
369
326
|
const self = Object.freeze({
|
|
370
327
|
addStaticData(data) {
|
|
371
|
-
if (data) {
|
|
328
|
+
if (Array.isArray(data)) {
|
|
329
|
+
for (const record of data) {
|
|
330
|
+
const key = encodeCacheKey(record);
|
|
331
|
+
const existing = cache.get(key);
|
|
332
|
+
if (!existing || existing.version === 0) {
|
|
333
|
+
addRecordInternal(record, flattenTranslations(record.data), 0);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if (data) {
|
|
372
338
|
staticData = Object.assign(Object.assign({}, staticData), data);
|
|
373
339
|
Object.entries(data).forEach(([key, value]) => {
|
|
374
340
|
if (typeof value !== 'function') {
|
|
375
341
|
const descriptor = decodeCacheKey(key);
|
|
376
342
|
const existing = cache.get(key);
|
|
377
343
|
if (!existing || existing.version === 0) {
|
|
378
|
-
addRecordInternal(descriptor, value, 0);
|
|
344
|
+
addRecordInternal(descriptor, flattenTranslations(value), 0);
|
|
379
345
|
}
|
|
380
346
|
}
|
|
381
347
|
});
|
|
@@ -386,7 +352,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
386
352
|
version += 1;
|
|
387
353
|
},
|
|
388
354
|
addRecord(descriptor, data) {
|
|
389
|
-
addRecordInternal(descriptor, data, version);
|
|
355
|
+
addRecordInternal(descriptor, flattenTranslations(data), version);
|
|
390
356
|
},
|
|
391
357
|
exists(descriptor, strict = false) {
|
|
392
358
|
const record = cache.get(encodeCacheKey(descriptor));
|
|
@@ -396,19 +362,27 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
396
362
|
return Boolean(record);
|
|
397
363
|
},
|
|
398
364
|
getRecord(descriptor) {
|
|
399
|
-
|
|
400
|
-
|
|
365
|
+
const descriptorWithNs = withDefaultNs(descriptor);
|
|
366
|
+
const cacheKey = encodeCacheKey(descriptorWithNs);
|
|
367
|
+
const cacheRecord = cache.get(cacheKey);
|
|
368
|
+
if (!cacheRecord) {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
return Object.assign(Object.assign({}, descriptorWithNs), { cacheKey, data: cacheRecord.data });
|
|
372
|
+
},
|
|
373
|
+
getAllRecords() {
|
|
374
|
+
const entries = Array.from(cache.entries());
|
|
375
|
+
return entries.map(([key]) => self.getRecord(decodeCacheKey(key)));
|
|
401
376
|
},
|
|
402
377
|
getTranslation(descriptor, key) {
|
|
403
378
|
var _a;
|
|
404
|
-
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data
|
|
379
|
+
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
405
380
|
},
|
|
406
381
|
getTranslationNs(namespaces, languages, key) {
|
|
407
382
|
var _a;
|
|
408
383
|
for (const namespace of namespaces) {
|
|
409
384
|
for (const language of languages) {
|
|
410
|
-
const value = (_a = cache
|
|
411
|
-
.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data.get(key);
|
|
385
|
+
const value = (_a = cache.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
412
386
|
if (value !== undefined && value !== null) {
|
|
413
387
|
return [namespace];
|
|
414
388
|
}
|
|
@@ -420,8 +394,7 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
420
394
|
var _a;
|
|
421
395
|
for (const namespace of namespaces) {
|
|
422
396
|
for (const language of languages) {
|
|
423
|
-
const value = (_a = cache
|
|
424
|
-
.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data.get(key);
|
|
397
|
+
const value = (_a = cache.get(encodeCacheKey({ language, namespace }))) === null || _a === void 0 ? void 0 : _a.data[key];
|
|
425
398
|
if (value !== undefined && value !== null) {
|
|
426
399
|
return value;
|
|
427
400
|
}
|
|
@@ -432,8 +405,10 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
432
405
|
changeTranslation(descriptor, key, value) {
|
|
433
406
|
var _a;
|
|
434
407
|
const record = (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data;
|
|
435
|
-
record === null || record === void 0 ? void 0 : record
|
|
436
|
-
|
|
408
|
+
if (record === null || record === void 0 ? void 0 : record[key]) {
|
|
409
|
+
record[key] = value;
|
|
410
|
+
events.onCacheChange.emit(Object.assign(Object.assign({}, descriptor), { key }));
|
|
411
|
+
}
|
|
437
412
|
},
|
|
438
413
|
isFetching(ns) {
|
|
439
414
|
if (isInitialLoading()) {
|
|
@@ -447,66 +422,74 @@ function Cache(events, backendGetRecord, backendGetDevRecord, withDefaultNs, isI
|
|
|
447
422
|
},
|
|
448
423
|
isLoading(language, ns) {
|
|
449
424
|
const namespaces = getFallbackArray(ns);
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
425
|
+
if (isInitialLoading()) {
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
const pendingCacheKeys = Array.from(asyncRequests.keys());
|
|
429
|
+
return Boolean(pendingCacheKeys.find((key) => {
|
|
430
|
+
const descriptor = decodeCacheKey(key);
|
|
431
|
+
return ((!namespaces.length || namespaces.includes(descriptor.namespace)) &&
|
|
432
|
+
!self.exists({
|
|
433
|
+
namespace: descriptor.namespace,
|
|
434
|
+
language: language,
|
|
435
|
+
}));
|
|
436
|
+
}));
|
|
437
|
+
},
|
|
438
|
+
async loadRecords(descriptors, options) {
|
|
462
439
|
const withPromises = descriptors.map((descriptor) => {
|
|
463
440
|
const keyObject = withDefaultNs(descriptor);
|
|
464
441
|
const cacheKey = encodeCacheKey(keyObject);
|
|
442
|
+
if (options === null || options === void 0 ? void 0 : options.useCache) {
|
|
443
|
+
const exists = self.exists(keyObject, true);
|
|
444
|
+
if (exists) {
|
|
445
|
+
return Object.assign(Object.assign({}, keyObject), { new: false, cacheKey, data: self.getRecord(keyObject).data });
|
|
446
|
+
}
|
|
447
|
+
}
|
|
465
448
|
const existingPromise = asyncRequests.get(cacheKey);
|
|
466
449
|
if (existingPromise) {
|
|
467
|
-
return {
|
|
468
|
-
new: false,
|
|
469
|
-
promise: existingPromise,
|
|
470
|
-
keyObject,
|
|
471
|
-
cacheKey,
|
|
472
|
-
};
|
|
450
|
+
return Object.assign(Object.assign({}, keyObject), { new: false, promise: existingPromise, cacheKey });
|
|
473
451
|
}
|
|
474
|
-
const dataPromise = fetchData(keyObject,
|
|
452
|
+
const dataPromise = fetchData(keyObject, !(options === null || options === void 0 ? void 0 : options.noDev)) || Promise.resolve(undefined);
|
|
475
453
|
asyncRequests.set(cacheKey, dataPromise);
|
|
476
|
-
return {
|
|
477
|
-
new: true,
|
|
478
|
-
promise: dataPromise,
|
|
479
|
-
keyObject,
|
|
480
|
-
cacheKey,
|
|
481
|
-
};
|
|
454
|
+
return Object.assign(Object.assign({}, keyObject), { new: true, promise: dataPromise, cacheKey });
|
|
482
455
|
});
|
|
483
456
|
fetchingObserver.notify();
|
|
484
457
|
loadingObserver.notify();
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
458
|
+
const promisesToWait = withPromises
|
|
459
|
+
.map((val) => val.promise)
|
|
460
|
+
.filter(Boolean);
|
|
461
|
+
const fetchedData = await Promise.all(promisesToWait);
|
|
462
|
+
withPromises.forEach((value) => {
|
|
463
|
+
var _a;
|
|
464
|
+
if (value.promise) {
|
|
465
|
+
value.data = flattenTranslations((_a = fetchedData[0]) !== null && _a !== void 0 ? _a : {});
|
|
466
|
+
fetchedData.shift();
|
|
467
|
+
}
|
|
488
468
|
// if promise has changed in between, it means cache been invalidated or
|
|
489
469
|
// new data are being fetched
|
|
470
|
+
const promiseChanged = asyncRequests.get(value.cacheKey) !== value.promise;
|
|
490
471
|
if (value.new && !promiseChanged) {
|
|
491
472
|
asyncRequests.delete(value.cacheKey);
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
self.addRecord(value.keyObject, data);
|
|
473
|
+
if (value.data) {
|
|
474
|
+
self.addRecord(value, value.data);
|
|
495
475
|
}
|
|
496
|
-
else if (!self.getRecord(value
|
|
476
|
+
else if (!self.getRecord(value)) {
|
|
497
477
|
// if no data exist, put empty object
|
|
498
|
-
|
|
478
|
+
// so we know we don't have to fetch again
|
|
479
|
+
self.addRecord(value, {});
|
|
499
480
|
}
|
|
500
481
|
}
|
|
501
482
|
});
|
|
502
483
|
fetchingObserver.notify();
|
|
503
484
|
loadingObserver.notify();
|
|
504
|
-
return withPromises.map((val) =>
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
485
|
+
return withPromises.map((val) => {
|
|
486
|
+
var _a;
|
|
487
|
+
return ({
|
|
488
|
+
language: val.language,
|
|
489
|
+
namespace: val.namespace,
|
|
490
|
+
data: (_a = val.data) !== null && _a !== void 0 ? _a : {},
|
|
491
|
+
cacheKey: val.cacheKey,
|
|
492
|
+
});
|
|
510
493
|
});
|
|
511
494
|
},
|
|
512
495
|
});
|
|
@@ -561,13 +544,14 @@ const DEFAULT_FORMAT_ERROR = 'invalid';
|
|
|
561
544
|
const DEFAULT_API_URL = 'https://app.tolgee.io';
|
|
562
545
|
const DEFAULT_MISSING_TRANSLATION = ({ key, }) => key;
|
|
563
546
|
const defaultValues = {
|
|
564
|
-
defaultNs: '',
|
|
565
547
|
observerOptions: defaultObserverOptions,
|
|
566
548
|
observerType: 'invisible',
|
|
567
549
|
onFormatError: DEFAULT_FORMAT_ERROR,
|
|
568
550
|
apiUrl: DEFAULT_API_URL,
|
|
551
|
+
autoLoadRequiredData: true,
|
|
569
552
|
fetch: createFetchFunction(),
|
|
570
553
|
onTranslationMissing: DEFAULT_MISSING_TRANSLATION,
|
|
554
|
+
disableCache: false,
|
|
571
555
|
};
|
|
572
556
|
const combineOptions = (...states) => {
|
|
573
557
|
let result = {};
|
|
@@ -761,6 +745,9 @@ function Plugins(getLanguage, getInitialOptions, getAvailableLanguages, getFallb
|
|
|
761
745
|
getBackendDevRecord: (async ({ language, namespace }) => {
|
|
762
746
|
var _a;
|
|
763
747
|
const { apiKey, apiUrl, projectId, filterTag } = getInitialOptions();
|
|
748
|
+
if (!apiKey || !apiUrl || !self.hasDevBackend()) {
|
|
749
|
+
return undefined;
|
|
750
|
+
}
|
|
764
751
|
return (_a = instances.devBackend) === null || _a === void 0 ? void 0 : _a.getRecord(Object.assign({ apiKey,
|
|
765
752
|
apiUrl,
|
|
766
753
|
projectId,
|
|
@@ -904,6 +891,9 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
904
891
|
isInitialLoading() {
|
|
905
892
|
return state.isInitialLoading;
|
|
906
893
|
},
|
|
894
|
+
isCacheDisabled() {
|
|
895
|
+
return state.initialOptions.disableCache;
|
|
896
|
+
},
|
|
907
897
|
setInitialLoading(value) {
|
|
908
898
|
state.isInitialLoading = value;
|
|
909
899
|
},
|
|
@@ -954,7 +944,8 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
954
944
|
},
|
|
955
945
|
getRequiredNamespaces() {
|
|
956
946
|
return unique([
|
|
957
|
-
|
|
947
|
+
self.getDefaultNs(),
|
|
948
|
+
...(state.initialOptions.ns || []),
|
|
958
949
|
...getFallbackArray(state.initialOptions.fallbackNs),
|
|
959
950
|
...state.activeNamespaces.keys(),
|
|
960
951
|
]);
|
|
@@ -972,8 +963,17 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
972
963
|
getFallbackNs() {
|
|
973
964
|
return getFallbackArray(state.initialOptions.fallbackNs);
|
|
974
965
|
},
|
|
966
|
+
getNs() {
|
|
967
|
+
var _a, _b;
|
|
968
|
+
return ((_a = state.initialOptions.ns) === null || _a === void 0 ? void 0 : _a.length)
|
|
969
|
+
? state.initialOptions.ns
|
|
970
|
+
: [(_b = state.initialOptions.defaultNs) !== null && _b !== void 0 ? _b : ''];
|
|
971
|
+
},
|
|
975
972
|
getDefaultNs(ns) {
|
|
976
|
-
|
|
973
|
+
var _a, _b, _c;
|
|
974
|
+
return ns === undefined
|
|
975
|
+
? (_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 : ''
|
|
976
|
+
: ns;
|
|
977
977
|
},
|
|
978
978
|
getAvailableLanguages() {
|
|
979
979
|
if (state.initialOptions.availableLanguages) {
|
|
@@ -984,10 +984,13 @@ function State(onLanguageChange, onPendingLanguageChange, onRunningChange) {
|
|
|
984
984
|
return Array.from(new Set(languagesFromStaticData));
|
|
985
985
|
}
|
|
986
986
|
},
|
|
987
|
+
getAvailableNs() {
|
|
988
|
+
return state.initialOptions.availableNs;
|
|
989
|
+
},
|
|
987
990
|
withDefaultNs(descriptor) {
|
|
988
991
|
return {
|
|
989
992
|
namespace: descriptor.namespace === undefined
|
|
990
|
-
? self.
|
|
993
|
+
? self.getDefaultNs()
|
|
991
994
|
: descriptor.namespace,
|
|
992
995
|
language: descriptor.language,
|
|
993
996
|
};
|
|
@@ -1037,12 +1040,12 @@ const getTranslateProps = (keyOrProps, ...params) => {
|
|
|
1037
1040
|
};
|
|
1038
1041
|
|
|
1039
1042
|
function Controller({ options }) {
|
|
1040
|
-
const events = Events(
|
|
1043
|
+
const events = Events();
|
|
1041
1044
|
const fetchingObserver = ValueObserver(false, () => cache.isFetching(), events.onFetchingChange.emit);
|
|
1042
1045
|
const loadingObserver = ValueObserver(false, () => self.isLoading(), events.onLoadingChange.emit);
|
|
1043
1046
|
const state = State(events.onLanguageChange, events.onPendingLanguageChange, events.onRunningChange);
|
|
1044
1047
|
const pluginService = Plugins(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getDefaultAndFallbackNs, getTranslationNs, getTranslation, changeTranslation, events);
|
|
1045
|
-
const cache = Cache(events, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, fetchingObserver, loadingObserver);
|
|
1048
|
+
const cache = Cache(events, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, state.isCacheDisabled, fetchingObserver, loadingObserver);
|
|
1046
1049
|
if (options) {
|
|
1047
1050
|
init(options);
|
|
1048
1051
|
}
|
|
@@ -1061,15 +1064,15 @@ function Controller({ options }) {
|
|
|
1061
1064
|
// gets all namespaces where translation could be located
|
|
1062
1065
|
// takes (ns|default, fallback ns)
|
|
1063
1066
|
function getDefaultAndFallbackNs(ns) {
|
|
1064
|
-
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
|
|
1067
|
+
return unique([...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()]);
|
|
1065
1068
|
}
|
|
1066
1069
|
// gets all namespaces which need to be loaded
|
|
1067
1070
|
// takes (ns|default, initial ns, fallback ns, active ns)
|
|
1068
1071
|
function getRequiredNamespaces(ns) {
|
|
1069
|
-
return [
|
|
1072
|
+
return unique([
|
|
1070
1073
|
...getFallbackArray(ns !== null && ns !== void 0 ? ns : getDefaultNs()),
|
|
1071
1074
|
...state.getRequiredNamespaces(),
|
|
1072
|
-
];
|
|
1075
|
+
]);
|
|
1073
1076
|
}
|
|
1074
1077
|
function changeTranslation(descriptor, key, value) {
|
|
1075
1078
|
const keyObject = state.withDefaultNs(descriptor);
|
|
@@ -1085,24 +1088,50 @@ function Controller({ options }) {
|
|
|
1085
1088
|
state.init(options);
|
|
1086
1089
|
cache.addStaticData(state.getInitialOptions().staticData);
|
|
1087
1090
|
}
|
|
1088
|
-
function
|
|
1091
|
+
function getRequiredDescriptors(lang, ns) {
|
|
1089
1092
|
const languages = state.getFallbackLangs(lang);
|
|
1090
1093
|
const namespaces = getRequiredNamespaces(ns);
|
|
1091
1094
|
const result = [];
|
|
1092
1095
|
languages.forEach((language) => {
|
|
1093
1096
|
namespaces.forEach((namespace) => {
|
|
1094
|
-
|
|
1095
|
-
result.push({ language, namespace });
|
|
1096
|
-
}
|
|
1097
|
+
result.push({ language, namespace });
|
|
1097
1098
|
});
|
|
1098
1099
|
});
|
|
1099
1100
|
return result;
|
|
1100
1101
|
}
|
|
1101
|
-
function
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1102
|
+
function getMissingDescriptors(lang, ns) {
|
|
1103
|
+
return getRequiredDescriptors(lang, ns).filter((descriptor) => !cache.exists(descriptor, true));
|
|
1104
|
+
}
|
|
1105
|
+
function getMatrixRecords(options) {
|
|
1106
|
+
let languages = [];
|
|
1107
|
+
let namespaces = [];
|
|
1108
|
+
if (Array.isArray(options.languages)) {
|
|
1109
|
+
languages = options.languages;
|
|
1110
|
+
}
|
|
1111
|
+
else if (options.languages === 'all') {
|
|
1112
|
+
const availableLanguages = self.getAvailableLanguages();
|
|
1113
|
+
if (!availableLanguages) {
|
|
1114
|
+
throw new Error(missingOptionError('availableLanguages'));
|
|
1115
|
+
}
|
|
1116
|
+
languages = availableLanguages;
|
|
1117
|
+
}
|
|
1118
|
+
if (Array.isArray(options.namespaces)) {
|
|
1119
|
+
namespaces = options.namespaces;
|
|
1120
|
+
}
|
|
1121
|
+
else if (options.namespaces === 'all') {
|
|
1122
|
+
const availableNs = self.getAvailableNs();
|
|
1123
|
+
if (!availableNs) {
|
|
1124
|
+
throw new Error(missingOptionError('availableNs'));
|
|
1125
|
+
}
|
|
1126
|
+
namespaces = availableNs;
|
|
1105
1127
|
}
|
|
1128
|
+
const records = [];
|
|
1129
|
+
languages.forEach((language) => {
|
|
1130
|
+
namespaces.forEach((namespace) => {
|
|
1131
|
+
records.push({ language, namespace });
|
|
1132
|
+
});
|
|
1133
|
+
});
|
|
1134
|
+
return records;
|
|
1106
1135
|
}
|
|
1107
1136
|
function getTranslationNs({ key, ns }) {
|
|
1108
1137
|
const languages = state.getFallbackLangs();
|
|
@@ -1116,8 +1145,11 @@ function Controller({ options }) {
|
|
|
1116
1145
|
}
|
|
1117
1146
|
function loadInitial() {
|
|
1118
1147
|
const data = valueOrPromise(initializeLanguage(), () => {
|
|
1119
|
-
|
|
1120
|
-
|
|
1148
|
+
const missingDescriptors = getMissingDescriptors();
|
|
1149
|
+
if (missingDescriptors.length &&
|
|
1150
|
+
state.getInitialOptions().autoLoadRequiredData) {
|
|
1151
|
+
return cache.loadRecords(missingDescriptors, { useCache: true });
|
|
1152
|
+
}
|
|
1121
1153
|
});
|
|
1122
1154
|
if (isPromise(data)) {
|
|
1123
1155
|
state.setInitialLoading(true);
|
|
@@ -1158,14 +1190,16 @@ function Controller({ options }) {
|
|
|
1158
1190
|
throw new Error(missingOptionError(['defaultLanguage', 'language']));
|
|
1159
1191
|
}
|
|
1160
1192
|
}
|
|
1161
|
-
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,
|
|
1193
|
+
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) {
|
|
1162
1194
|
if (state.getPendingLanguage() === language &&
|
|
1163
1195
|
state.getLanguage() === language) {
|
|
1164
1196
|
return;
|
|
1165
1197
|
}
|
|
1166
1198
|
state.setPendingLanguage(language);
|
|
1167
|
-
if (state.isRunning()) {
|
|
1168
|
-
await
|
|
1199
|
+
if (state.isRunning() && state.getInitialOptions().autoLoadRequiredData) {
|
|
1200
|
+
await cache.loadRecords(getRequiredDescriptors(language), {
|
|
1201
|
+
useCache: true,
|
|
1202
|
+
});
|
|
1169
1203
|
}
|
|
1170
1204
|
if (language === state.getPendingLanguage()) {
|
|
1171
1205
|
// there might be parallel language change
|
|
@@ -1179,14 +1213,14 @@ function Controller({ options }) {
|
|
|
1179
1213
|
state.addActiveNs(ns);
|
|
1180
1214
|
}
|
|
1181
1215
|
if (state.isRunning()) {
|
|
1182
|
-
await
|
|
1216
|
+
await cache.loadRecords(getRequiredDescriptors(undefined, ns), {
|
|
1217
|
+
useCache: true,
|
|
1218
|
+
});
|
|
1183
1219
|
}
|
|
1184
1220
|
},
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
async loadRecord(descriptor) {
|
|
1189
|
-
return (await self.loadRecords([descriptor]))[0];
|
|
1221
|
+
async loadRecord(descriptor, options) {
|
|
1222
|
+
var _a;
|
|
1223
|
+
return (_a = (await self.loadRecords([descriptor], options))[0]) === null || _a === void 0 ? void 0 : _a.data;
|
|
1190
1224
|
},
|
|
1191
1225
|
isLoading(ns) {
|
|
1192
1226
|
return cache.isLoading(state.getLanguage(), ns);
|
|
@@ -1215,6 +1249,17 @@ function Controller({ options }) {
|
|
|
1215
1249
|
}), isDev() {
|
|
1216
1250
|
return Boolean(state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl);
|
|
1217
1251
|
},
|
|
1252
|
+
async loadRequired(options) {
|
|
1253
|
+
if (!(options === null || options === void 0 ? void 0 : options.language)) {
|
|
1254
|
+
await initializeLanguage();
|
|
1255
|
+
}
|
|
1256
|
+
const requiredRecords = getRequiredDescriptors(options === null || options === void 0 ? void 0 : options.language);
|
|
1257
|
+
return self.loadRecords(requiredRecords, options);
|
|
1258
|
+
},
|
|
1259
|
+
async loadMatrix(options) {
|
|
1260
|
+
const records = getMatrixRecords(options);
|
|
1261
|
+
return self.loadRecords(records, options);
|
|
1262
|
+
},
|
|
1218
1263
|
run() {
|
|
1219
1264
|
checkCorrectConfiguration();
|
|
1220
1265
|
if (!state.isRunning()) {
|
|
@@ -1255,20 +1300,6 @@ function createTolgee(options) {
|
|
|
1255
1300
|
* Listen to tolgee events.
|
|
1256
1301
|
*/
|
|
1257
1302
|
on: controller.on,
|
|
1258
|
-
/**
|
|
1259
|
-
* Listen for specific namespaces changes.
|
|
1260
|
-
*
|
|
1261
|
-
* ```
|
|
1262
|
-
* const sub = tolgee.onUpdate(handler)
|
|
1263
|
-
*
|
|
1264
|
-
* // subscribe to selected namespace
|
|
1265
|
-
* sub.subscribeNs(['common'])
|
|
1266
|
-
*
|
|
1267
|
-
* // unsubscribe
|
|
1268
|
-
* sub.unsubscribe()
|
|
1269
|
-
* ```
|
|
1270
|
-
*/
|
|
1271
|
-
onNsUpdate: controller.onUpdate.listenSome,
|
|
1272
1303
|
/**
|
|
1273
1304
|
* Turn off/on events emitting. Is on by default.
|
|
1274
1305
|
*/
|
|
@@ -1306,6 +1337,16 @@ function createTolgee(options) {
|
|
|
1306
1337
|
* so this method will remove namespace only if the counter goes down to 0.
|
|
1307
1338
|
*/
|
|
1308
1339
|
removeActiveNs: controller.removeActiveNs,
|
|
1340
|
+
/**
|
|
1341
|
+
* Load records which would be loaded by `run` function
|
|
1342
|
+
*
|
|
1343
|
+
* You can provide language if not previously set on tolgee instance
|
|
1344
|
+
*/
|
|
1345
|
+
loadRequired: controller.loadRequired,
|
|
1346
|
+
/**
|
|
1347
|
+
* Load records in matrix (languages x namespaces)
|
|
1348
|
+
*/
|
|
1349
|
+
loadMatrix: controller.loadMatrix,
|
|
1309
1350
|
/**
|
|
1310
1351
|
* Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
|
|
1311
1352
|
*
|
|
@@ -1334,9 +1375,9 @@ function createTolgee(options) {
|
|
|
1334
1375
|
*/
|
|
1335
1376
|
isLoaded: controller.isLoaded,
|
|
1336
1377
|
/**
|
|
1337
|
-
* Returns records needed for instance to be `loaded`
|
|
1378
|
+
* Returns descriptors of records needed for instance to be `loaded`
|
|
1338
1379
|
*/
|
|
1339
|
-
|
|
1380
|
+
getRequiredDescriptors: controller.getRequiredDescriptors,
|
|
1340
1381
|
/**
|
|
1341
1382
|
* @return `true` if tolgee is loading initial data (triggered by `run`).
|
|
1342
1383
|
*/
|