@tolgee/core 5.8.0 → 5.8.2
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 +650 -716
- 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 +650 -716
- 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 +650 -716
- package/dist/tolgee.esm.mjs.map +1 -1
- package/dist/tolgee.umd.js +650 -716
- 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 +14 -14
- package/lib/Controller/Controller.d.ts +23 -23
- package/lib/Controller/Events/EventEmitter.d.ts +1 -1
- package/lib/Controller/Events/EventEmitterSelective.d.ts +1 -1
- package/lib/Controller/Events/Events.d.ts +2 -2
- package/lib/Controller/Plugins/Plugins.d.ts +17 -17
- package/lib/Controller/State/State.d.ts +20 -20
- package/lib/Controller/State/initState.d.ts +1 -1
- package/lib/TolgeeCore.d.ts +2 -2
- package/lib/helpers.d.ts +2 -2
- package/package.json +2 -2
- package/src/Controller/Cache/Cache.ts +175 -193
- package/src/Controller/Controller.ts +105 -114
- package/src/Controller/Events/EventEmitter.ts +21 -22
- package/src/Controller/Events/EventEmitterSelective.ts +59 -58
- package/src/Controller/Events/Events.ts +41 -52
- package/src/Controller/Plugins/Plugins.ts +206 -219
- package/src/Controller/State/State.ts +135 -152
- package/src/Controller/State/initState.ts +3 -3
- package/src/Controller/ValueObserver.ts +11 -12
- package/src/TolgeeCore.ts +7 -7
- package/src/__test/cache.test.ts +3 -2
- package/src/helpers.ts +6 -5
|
@@ -28,7 +28,7 @@ type CacheRecord = {
|
|
|
28
28
|
|
|
29
29
|
type StateCache = Map<string, CacheRecord>;
|
|
30
30
|
|
|
31
|
-
export
|
|
31
|
+
export function Cache(
|
|
32
32
|
onCacheChange: EventEmitterInstance<CacheDescriptorWithKey>,
|
|
33
33
|
backendGetRecord: BackendGetRecord,
|
|
34
34
|
backendGetDevRecord: BackendGetDevRecord,
|
|
@@ -36,32 +36,12 @@ export const Cache = (
|
|
|
36
36
|
isInitialLoading: () => boolean,
|
|
37
37
|
fetchingObserver: ValueObserverInstance<boolean>,
|
|
38
38
|
loadingObserver: ValueObserverInstance<boolean>
|
|
39
|
-
)
|
|
39
|
+
) {
|
|
40
40
|
const asyncRequests: CacheAsyncRequests = new Map();
|
|
41
41
|
const cache: StateCache = new Map();
|
|
42
42
|
let staticData: NonNullable<TolgeeStaticData> = {};
|
|
43
43
|
let version = 0;
|
|
44
44
|
|
|
45
|
-
function addStaticData(data: TolgeeStaticData | undefined) {
|
|
46
|
-
if (data) {
|
|
47
|
-
staticData = { ...staticData, ...data };
|
|
48
|
-
Object.entries(data).forEach(([key, value]) => {
|
|
49
|
-
if (typeof value !== 'function') {
|
|
50
|
-
const descriptor = decodeCacheKey(key);
|
|
51
|
-
const existing = cache.get(key);
|
|
52
|
-
if (!existing || existing.version === 0) {
|
|
53
|
-
addRecordInternal(descriptor, value, 0);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function invalidate() {
|
|
61
|
-
asyncRequests.clear();
|
|
62
|
-
version += 1;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
45
|
function addRecordInternal(
|
|
66
46
|
descriptor: CacheDescriptorInternal,
|
|
67
47
|
data: TreeTranslationsData,
|
|
@@ -75,109 +55,6 @@ export const Cache = (
|
|
|
75
55
|
onCacheChange.emit(descriptor);
|
|
76
56
|
}
|
|
77
57
|
|
|
78
|
-
function addRecord(
|
|
79
|
-
descriptor: CacheDescriptorInternal,
|
|
80
|
-
data: TreeTranslationsData
|
|
81
|
-
) {
|
|
82
|
-
addRecordInternal(descriptor, data, version);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function exists(descriptor: CacheDescriptorInternal, strict = false) {
|
|
86
|
-
const record = cache.get(encodeCacheKey(descriptor));
|
|
87
|
-
if (record && strict) {
|
|
88
|
-
return record.version === version;
|
|
89
|
-
}
|
|
90
|
-
return Boolean(record);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function getRecord(descriptor: CacheDescriptor) {
|
|
94
|
-
return cache.get(encodeCacheKey(withDefaultNs(descriptor)))?.data;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function getTranslation(descriptor: CacheDescriptorInternal, key: string) {
|
|
98
|
-
return cache.get(encodeCacheKey(descriptor))?.data.get(key);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function getTranslationNs(
|
|
102
|
-
namespaces: string[],
|
|
103
|
-
languages: string[],
|
|
104
|
-
key: string
|
|
105
|
-
) {
|
|
106
|
-
for (const namespace of namespaces) {
|
|
107
|
-
for (const language of languages) {
|
|
108
|
-
const value = cache
|
|
109
|
-
.get(encodeCacheKey({ language, namespace }))
|
|
110
|
-
?.data.get(key);
|
|
111
|
-
if (value !== undefined && value !== null) {
|
|
112
|
-
return [namespace];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return unique(namespaces);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function getTranslationFallback(
|
|
120
|
-
namespaces: string[],
|
|
121
|
-
languages: string[],
|
|
122
|
-
key: string
|
|
123
|
-
) {
|
|
124
|
-
for (const namespace of namespaces) {
|
|
125
|
-
for (const language of languages) {
|
|
126
|
-
const value = cache
|
|
127
|
-
.get(encodeCacheKey({ language, namespace }))
|
|
128
|
-
?.data.get(key);
|
|
129
|
-
if (value !== undefined && value !== null) {
|
|
130
|
-
return value;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return undefined;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function changeTranslation(
|
|
138
|
-
descriptor: CacheDescriptorInternal,
|
|
139
|
-
key: string,
|
|
140
|
-
value: TranslationValue
|
|
141
|
-
) {
|
|
142
|
-
const record = cache.get(encodeCacheKey(descriptor))?.data;
|
|
143
|
-
record?.set(key, value);
|
|
144
|
-
onCacheChange.emit({ ...descriptor, key });
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function isFetching(ns?: NsFallback) {
|
|
148
|
-
if (isInitialLoading()) {
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (ns === undefined) {
|
|
153
|
-
return asyncRequests.size > 0;
|
|
154
|
-
}
|
|
155
|
-
const namespaces = getFallbackArray(ns);
|
|
156
|
-
return Boolean(
|
|
157
|
-
Array.from(asyncRequests.keys()).find((key) =>
|
|
158
|
-
namespaces.includes(decodeCacheKey(key).namespace)
|
|
159
|
-
)
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function isLoading(language: string | undefined, ns?: NsFallback) {
|
|
164
|
-
const namespaces = getFallbackArray(ns);
|
|
165
|
-
|
|
166
|
-
return Boolean(
|
|
167
|
-
isInitialLoading() ||
|
|
168
|
-
Array.from(asyncRequests.keys()).find((key) => {
|
|
169
|
-
const descriptor = decodeCacheKey(key);
|
|
170
|
-
return (
|
|
171
|
-
(!namespaces.length || namespaces.includes(descriptor.namespace)) &&
|
|
172
|
-
!exists({
|
|
173
|
-
namespace: descriptor.namespace,
|
|
174
|
-
language: language!,
|
|
175
|
-
})
|
|
176
|
-
);
|
|
177
|
-
})
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
58
|
/**
|
|
182
59
|
* Fetches production data
|
|
183
60
|
*/
|
|
@@ -219,82 +96,187 @@ export const Cache = (
|
|
|
219
96
|
return dataPromise;
|
|
220
97
|
}
|
|
221
98
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
99
|
+
const self = Object.freeze({
|
|
100
|
+
addStaticData(data: TolgeeStaticData | undefined) {
|
|
101
|
+
if (data) {
|
|
102
|
+
staticData = { ...staticData, ...data };
|
|
103
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
104
|
+
if (typeof value !== 'function') {
|
|
105
|
+
const descriptor = decodeCacheKey(key);
|
|
106
|
+
const existing = cache.get(key);
|
|
107
|
+
if (!existing || existing.version === 0) {
|
|
108
|
+
addRecordInternal(descriptor, value, 0);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
invalidate() {
|
|
116
|
+
asyncRequests.clear();
|
|
117
|
+
version += 1;
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
addRecord(descriptor: CacheDescriptorInternal, data: TreeTranslationsData) {
|
|
121
|
+
addRecordInternal(descriptor, data, version);
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
exists(descriptor: CacheDescriptorInternal, strict = false) {
|
|
125
|
+
const record = cache.get(encodeCacheKey(descriptor));
|
|
126
|
+
if (record && strict) {
|
|
127
|
+
return record.version === version;
|
|
128
|
+
}
|
|
129
|
+
return Boolean(record);
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
getRecord(descriptor: CacheDescriptor) {
|
|
133
|
+
return cache.get(encodeCacheKey(withDefaultNs(descriptor)))?.data;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
getTranslation(descriptor: CacheDescriptorInternal, key: string) {
|
|
137
|
+
return cache.get(encodeCacheKey(descriptor))?.data.get(key);
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
getTranslationNs(namespaces: string[], languages: string[], key: string) {
|
|
141
|
+
for (const namespace of namespaces) {
|
|
142
|
+
for (const language of languages) {
|
|
143
|
+
const value = cache
|
|
144
|
+
.get(encodeCacheKey({ language, namespace }))
|
|
145
|
+
?.data.get(key);
|
|
146
|
+
if (value !== undefined && value !== null) {
|
|
147
|
+
return [namespace];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return unique(namespaces);
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
getTranslationFallback(
|
|
155
|
+
namespaces: string[],
|
|
156
|
+
languages: string[],
|
|
157
|
+
key: string
|
|
158
|
+
) {
|
|
159
|
+
for (const namespace of namespaces) {
|
|
160
|
+
for (const language of languages) {
|
|
161
|
+
const value = cache
|
|
162
|
+
.get(encodeCacheKey({ language, namespace }))
|
|
163
|
+
?.data.get(key);
|
|
164
|
+
if (value !== undefined && value !== null) {
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
changeTranslation(
|
|
173
|
+
descriptor: CacheDescriptorInternal,
|
|
174
|
+
key: string,
|
|
175
|
+
value: TranslationValue
|
|
176
|
+
) {
|
|
177
|
+
const record = cache.get(encodeCacheKey(descriptor))?.data;
|
|
178
|
+
record?.set(key, value);
|
|
179
|
+
onCacheChange.emit({ ...descriptor, key });
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
isFetching(ns?: NsFallback) {
|
|
183
|
+
if (isInitialLoading()) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
227
186
|
|
|
228
|
-
if (
|
|
187
|
+
if (ns === undefined) {
|
|
188
|
+
return asyncRequests.size > 0;
|
|
189
|
+
}
|
|
190
|
+
const namespaces = getFallbackArray(ns);
|
|
191
|
+
return Boolean(
|
|
192
|
+
Array.from(asyncRequests.keys()).find((key) =>
|
|
193
|
+
namespaces.includes(decodeCacheKey(key).namespace)
|
|
194
|
+
)
|
|
195
|
+
);
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
isLoading(language: string | undefined, ns?: NsFallback) {
|
|
199
|
+
const namespaces = getFallbackArray(ns);
|
|
200
|
+
|
|
201
|
+
return Boolean(
|
|
202
|
+
isInitialLoading() ||
|
|
203
|
+
Array.from(asyncRequests.keys()).find((key) => {
|
|
204
|
+
const descriptor = decodeCacheKey(key);
|
|
205
|
+
return (
|
|
206
|
+
(!namespaces.length ||
|
|
207
|
+
namespaces.includes(descriptor.namespace)) &&
|
|
208
|
+
!self.exists({
|
|
209
|
+
namespace: descriptor.namespace,
|
|
210
|
+
language: language!,
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
})
|
|
214
|
+
);
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
async loadRecords(descriptors: CacheDescriptor[], isDev: boolean) {
|
|
218
|
+
const withPromises = descriptors.map((descriptor) => {
|
|
219
|
+
const keyObject = withDefaultNs(descriptor);
|
|
220
|
+
const cacheKey = encodeCacheKey(keyObject);
|
|
221
|
+
const existingPromise = asyncRequests.get(cacheKey);
|
|
222
|
+
|
|
223
|
+
if (existingPromise) {
|
|
224
|
+
return {
|
|
225
|
+
new: false,
|
|
226
|
+
promise: existingPromise,
|
|
227
|
+
keyObject,
|
|
228
|
+
cacheKey,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const dataPromise =
|
|
232
|
+
fetchData(keyObject, isDev) || Promise.resolve(undefined);
|
|
233
|
+
asyncRequests.set(cacheKey, dataPromise);
|
|
229
234
|
return {
|
|
230
|
-
new:
|
|
231
|
-
promise:
|
|
235
|
+
new: true,
|
|
236
|
+
promise: dataPromise,
|
|
232
237
|
keyObject,
|
|
233
238
|
cacheKey,
|
|
234
239
|
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// new data are being fetched
|
|
256
|
-
if (value.new && !promiseChanged) {
|
|
257
|
-
asyncRequests.delete(value.cacheKey);
|
|
258
|
-
const data = results[i];
|
|
259
|
-
if (data) {
|
|
260
|
-
addRecord(value.keyObject, data);
|
|
261
|
-
} else if (!getRecord(value.keyObject)) {
|
|
262
|
-
// if no data exist, put empty object
|
|
263
|
-
addRecord(value.keyObject, {});
|
|
240
|
+
});
|
|
241
|
+
fetchingObserver.notify();
|
|
242
|
+
loadingObserver.notify();
|
|
243
|
+
|
|
244
|
+
const results = await Promise.all(withPromises.map((val) => val.promise));
|
|
245
|
+
|
|
246
|
+
withPromises.forEach((value, i) => {
|
|
247
|
+
const promiseChanged =
|
|
248
|
+
asyncRequests.get(value.cacheKey) !== value.promise;
|
|
249
|
+
// if promise has changed in between, it means cache been invalidated or
|
|
250
|
+
// new data are being fetched
|
|
251
|
+
if (value.new && !promiseChanged) {
|
|
252
|
+
asyncRequests.delete(value.cacheKey);
|
|
253
|
+
const data = results[i];
|
|
254
|
+
if (data) {
|
|
255
|
+
self.addRecord(value.keyObject, data);
|
|
256
|
+
} else if (!self.getRecord(value.keyObject)) {
|
|
257
|
+
// if no data exist, put empty object
|
|
258
|
+
self.addRecord(value.keyObject, {});
|
|
259
|
+
}
|
|
264
260
|
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
loadingObserver.notify();
|
|
269
|
-
|
|
270
|
-
return withPromises.map((val) => getRecord(val.keyObject)!);
|
|
271
|
-
}
|
|
261
|
+
});
|
|
262
|
+
fetchingObserver.notify();
|
|
263
|
+
loadingObserver.notify();
|
|
272
264
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return entries.map(([key, entry]) => {
|
|
276
|
-
return {
|
|
277
|
-
...decodeCacheKey(key),
|
|
278
|
-
data: entry.data,
|
|
279
|
-
};
|
|
280
|
-
});
|
|
281
|
-
}
|
|
265
|
+
return withPromises.map((val) => self.getRecord(val.keyObject)!);
|
|
266
|
+
},
|
|
282
267
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
changeTranslation,
|
|
293
|
-
isFetching,
|
|
294
|
-
isLoading,
|
|
295
|
-
loadRecords,
|
|
296
|
-
getAllRecords,
|
|
268
|
+
getAllRecords() {
|
|
269
|
+
const entries = Array.from(cache.entries());
|
|
270
|
+
return entries.map(([key, entry]) => {
|
|
271
|
+
return {
|
|
272
|
+
...decodeCacheKey(key),
|
|
273
|
+
data: entry.data,
|
|
274
|
+
};
|
|
275
|
+
});
|
|
276
|
+
},
|
|
297
277
|
});
|
|
298
|
-
|
|
278
|
+
|
|
279
|
+
return self;
|
|
280
|
+
}
|
|
299
281
|
|
|
300
282
|
export type CacheInstance = ReturnType<typeof Cache>;
|
|
@@ -19,7 +19,7 @@ type StateServiceProps = {
|
|
|
19
19
|
options?: Partial<TolgeeOptions>;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
export
|
|
22
|
+
export function Controller({ options }: StateServiceProps) {
|
|
23
23
|
const events = Events(getFallbackNs, getDefaultNs);
|
|
24
24
|
const fetchingObserver = ValueObserver<boolean>(
|
|
25
25
|
false,
|
|
@@ -28,7 +28,7 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
28
28
|
);
|
|
29
29
|
const loadingObserver = ValueObserver<boolean>(
|
|
30
30
|
false,
|
|
31
|
-
() => isLoading(),
|
|
31
|
+
() => self.isLoading(),
|
|
32
32
|
events.onLoadingChange.emit
|
|
33
33
|
);
|
|
34
34
|
|
|
@@ -99,7 +99,7 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
99
99
|
const previousValue = cache.getTranslation(keyObject, key);
|
|
100
100
|
cache.changeTranslation(keyObject, key, value);
|
|
101
101
|
return {
|
|
102
|
-
revert
|
|
102
|
+
revert() {
|
|
103
103
|
cache.changeTranslation(keyObject, key, previousValue);
|
|
104
104
|
},
|
|
105
105
|
};
|
|
@@ -110,25 +110,6 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
110
110
|
cache.addStaticData(state.getInitialOptions().staticData);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function isLoading(ns?: NsFallback) {
|
|
114
|
-
return cache.isLoading(state.getLanguage()!, ns);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isDev() {
|
|
118
|
-
return Boolean(
|
|
119
|
-
state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function addActiveNs(ns: NsFallback, forget?: boolean) {
|
|
124
|
-
if (!forget) {
|
|
125
|
-
state.addActiveNs(ns);
|
|
126
|
-
}
|
|
127
|
-
if (state.isRunning()) {
|
|
128
|
-
await loadRequiredRecords(undefined, ns);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
113
|
function getRequiredRecords(lang?: string, ns?: NsFallback) {
|
|
133
114
|
const languages = state.getFallbackLangs(lang);
|
|
134
115
|
const namespaces = getRequiredNamespaces(ns);
|
|
@@ -143,49 +124,10 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
143
124
|
return result;
|
|
144
125
|
}
|
|
145
126
|
|
|
146
|
-
function isLoaded(ns?: NsFallback) {
|
|
147
|
-
const language = state.getLanguage();
|
|
148
|
-
if (!language) {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
const languages = state.getFallbackLangs(language);
|
|
152
|
-
const namespaces = getRequiredNamespaces(ns);
|
|
153
|
-
const result: CacheDescriptor[] = [];
|
|
154
|
-
languages.forEach((language) => {
|
|
155
|
-
namespaces.forEach((namespace) => {
|
|
156
|
-
if (!cache.exists({ language, namespace })) {
|
|
157
|
-
result.push({ language, namespace });
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
return result.length === 0;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
127
|
function loadRequiredRecords(lang?: string, ns?: NsFallback) {
|
|
165
128
|
const descriptors = getRequiredRecords(lang, ns);
|
|
166
129
|
if (descriptors.length) {
|
|
167
|
-
return valueOrPromise(loadRecords(descriptors), () => {});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async function changeLanguage(language: string) {
|
|
172
|
-
if (
|
|
173
|
-
state.getPendingLanguage() === language &&
|
|
174
|
-
state.getLanguage() === language
|
|
175
|
-
) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
state.setPendingLanguage(language);
|
|
179
|
-
|
|
180
|
-
if (state.isRunning()) {
|
|
181
|
-
await loadRequiredRecords(language);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (language === state.getPendingLanguage()) {
|
|
185
|
-
// there might be parallel language change
|
|
186
|
-
// we only want to apply latest
|
|
187
|
-
state.setLanguage(language);
|
|
188
|
-
pluginService.setStoredLanguage(language);
|
|
130
|
+
return valueOrPromise(self.loadRecords(descriptors), () => {});
|
|
189
131
|
}
|
|
190
132
|
}
|
|
191
133
|
|
|
@@ -239,15 +181,7 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
239
181
|
});
|
|
240
182
|
}
|
|
241
183
|
|
|
242
|
-
|
|
243
|
-
return (await loadRecords([descriptor]))[0];
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function loadRecords(descriptors: CacheDescriptor[]) {
|
|
247
|
-
return cache.loadRecords(descriptors, isDev());
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const checkCorrectConfiguration = () => {
|
|
184
|
+
function checkCorrectConfiguration() {
|
|
251
185
|
const languageComputable =
|
|
252
186
|
pluginService.getLanguageDetector() || pluginService.getLanguageStorage();
|
|
253
187
|
if (languageComputable) {
|
|
@@ -263,55 +197,112 @@ export const Controller = ({ options }: StateServiceProps) => {
|
|
|
263
197
|
throw new Error(missingOptionError('language'));
|
|
264
198
|
}
|
|
265
199
|
}
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
function run() {
|
|
269
|
-
let result: Promise<void> | undefined = undefined;
|
|
270
|
-
checkCorrectConfiguration();
|
|
271
|
-
if (!state.isRunning()) {
|
|
272
|
-
if (isDev()) {
|
|
273
|
-
cache.invalidate();
|
|
274
|
-
}
|
|
275
|
-
state.setRunning(true);
|
|
276
|
-
pluginService.run();
|
|
277
|
-
result = loadInitial();
|
|
278
|
-
}
|
|
279
|
-
return Promise.resolve(result);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function stop() {
|
|
283
|
-
if (state.isRunning()) {
|
|
284
|
-
pluginService.stop();
|
|
285
|
-
state.setRunning(false);
|
|
286
|
-
}
|
|
287
200
|
}
|
|
288
201
|
|
|
289
|
-
const
|
|
290
|
-
// @ts-ignore
|
|
291
|
-
const params = getTranslateProps(...args);
|
|
292
|
-
const translation = getTranslation(params);
|
|
293
|
-
return pluginService.formatTranslation({ ...params, translation });
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
return Object.freeze({
|
|
202
|
+
const self = Object.freeze({
|
|
297
203
|
...events,
|
|
298
204
|
...state,
|
|
299
205
|
...pluginService,
|
|
300
206
|
...cache,
|
|
301
|
-
init,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
207
|
+
init: init,
|
|
208
|
+
getTranslation: getTranslation,
|
|
209
|
+
changeTranslation: changeTranslation,
|
|
210
|
+
async changeLanguage(language: string) {
|
|
211
|
+
if (
|
|
212
|
+
state.getPendingLanguage() === language &&
|
|
213
|
+
state.getLanguage() === language
|
|
214
|
+
) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
state.setPendingLanguage(language);
|
|
218
|
+
|
|
219
|
+
if (state.isRunning()) {
|
|
220
|
+
await loadRequiredRecords(language);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (language === state.getPendingLanguage()) {
|
|
224
|
+
// there might be parallel language change
|
|
225
|
+
// we only want to apply latest
|
|
226
|
+
state.setLanguage(language);
|
|
227
|
+
pluginService.setStoredLanguage(language);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
async addActiveNs(ns: NsFallback, forget?: boolean) {
|
|
232
|
+
if (!forget) {
|
|
233
|
+
state.addActiveNs(ns);
|
|
234
|
+
}
|
|
235
|
+
if (state.isRunning()) {
|
|
236
|
+
await loadRequiredRecords(undefined, ns);
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
loadRecords(descriptors: CacheDescriptor[]) {
|
|
241
|
+
return cache.loadRecords(descriptors, self.isDev());
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
async loadRecord(descriptor: CacheDescriptor) {
|
|
245
|
+
return (await self.loadRecords([descriptor]))[0];
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
isLoading(ns?: NsFallback) {
|
|
249
|
+
return cache.isLoading(state.getLanguage()!, ns);
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
isLoaded(ns?: NsFallback) {
|
|
253
|
+
const language = state.getLanguage();
|
|
254
|
+
if (!language) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
const languages = state.getFallbackLangs(language);
|
|
258
|
+
const namespaces = getRequiredNamespaces(ns);
|
|
259
|
+
const result: CacheDescriptor[] = [];
|
|
260
|
+
languages.forEach((language) => {
|
|
261
|
+
namespaces.forEach((namespace) => {
|
|
262
|
+
if (!cache.exists({ language, namespace })) {
|
|
263
|
+
result.push({ language, namespace });
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
return result.length === 0;
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
t: ((...args: Parameters<TFnType>) => {
|
|
271
|
+
// @ts-ignore
|
|
272
|
+
const params = getTranslateProps(...args);
|
|
273
|
+
const translation = getTranslation(params);
|
|
274
|
+
return pluginService.formatTranslation({ ...params, translation });
|
|
275
|
+
}) as TFnType,
|
|
276
|
+
|
|
277
|
+
isDev() {
|
|
278
|
+
return Boolean(
|
|
279
|
+
state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl
|
|
280
|
+
);
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
run() {
|
|
284
|
+
let result: Promise<void> | undefined = undefined;
|
|
285
|
+
checkCorrectConfiguration();
|
|
286
|
+
if (!state.isRunning()) {
|
|
287
|
+
if (self.isDev()) {
|
|
288
|
+
cache.invalidate();
|
|
289
|
+
}
|
|
290
|
+
state.setRunning(true);
|
|
291
|
+
pluginService.run();
|
|
292
|
+
result = loadInitial();
|
|
293
|
+
}
|
|
294
|
+
return Promise.resolve(result);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
stop() {
|
|
298
|
+
if (state.isRunning()) {
|
|
299
|
+
pluginService.stop();
|
|
300
|
+
state.setRunning(false);
|
|
301
|
+
}
|
|
302
|
+
},
|
|
314
303
|
});
|
|
315
|
-
|
|
304
|
+
|
|
305
|
+
return self;
|
|
306
|
+
}
|
|
316
307
|
|
|
317
308
|
export type ControllerInstance = ReturnType<typeof Controller>;
|