gt-react 10.19.16 → 10.19.18
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/CHANGELOG.md +22 -0
- package/dist/browser.cjs +1086 -1138
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +80 -110
- package/dist/browser.d.cts.map +1 -1
- package/dist/browser.d.mts +80 -110
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.mjs +1082 -1133
- package/dist/browser.mjs.map +1 -1
- package/dist/client.cjs +399 -304
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +7 -8
- package/dist/client.d.cts.map +1 -1
- package/dist/client.d.mts +7 -8
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +399 -303
- package/dist/client.mjs.map +1 -1
- package/dist/index.cjs +602 -420
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +601 -418
- package/dist/index.mjs.map +1 -1
- package/dist/internal.cjs +590 -498
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +18 -18
- package/dist/internal.d.cts.map +1 -1
- package/dist/internal.d.mts +8 -8
- package/dist/internal.d.mts.map +1 -1
- package/dist/internal.mjs +556 -464
- package/dist/internal.mjs.map +1 -1
- package/dist/macros.cjs +559 -669
- package/dist/macros.cjs.map +1 -1
- package/dist/macros.mjs +559 -669
- package/dist/macros.mjs.map +1 -1
- package/package.json +7 -7
package/dist/macros.mjs
CHANGED
|
@@ -28,7 +28,46 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
28
28
|
};
|
|
29
29
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
30
|
//#endregion
|
|
31
|
-
//#region ../core/dist/base64-
|
|
31
|
+
//#region ../core/dist/base64-r7YWJYWt.mjs
|
|
32
|
+
function ensureSentence(text) {
|
|
33
|
+
const trimmed = text.trim();
|
|
34
|
+
if (!trimmed) return "";
|
|
35
|
+
return /[.!?)]$/.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
36
|
+
}
|
|
37
|
+
function stripSentence(text) {
|
|
38
|
+
const trimmed = text.trim();
|
|
39
|
+
let end = trimmed.length;
|
|
40
|
+
while (end > 0) {
|
|
41
|
+
const char = trimmed[end - 1];
|
|
42
|
+
if (char !== "." && char !== "!" && char !== "?") break;
|
|
43
|
+
end -= 1;
|
|
44
|
+
}
|
|
45
|
+
return trimmed.slice(0, end);
|
|
46
|
+
}
|
|
47
|
+
function lowercaseFirstWord(text) {
|
|
48
|
+
return text.replace(/^[A-Z][a-z]/, (match) => match.toLowerCase());
|
|
49
|
+
}
|
|
50
|
+
function formatDetails(details) {
|
|
51
|
+
if (!details) return "";
|
|
52
|
+
const detailText = Array.isArray(details) ? details.join(", ") : details;
|
|
53
|
+
if (!detailText.trim()) return "";
|
|
54
|
+
return ensureSentence(`Details: ${detailText}`);
|
|
55
|
+
}
|
|
56
|
+
function createDiagnosticMessage({ source, severity, whatHappened, reassurance, why, fix, wayOut, details, docsUrl }) {
|
|
57
|
+
const prefix = source ? severity ? `${source} ${severity}:` : `${source}:` : severity ? `${severity}:` : "";
|
|
58
|
+
const whatAndWhy = why ? `${stripSentence(whatHappened)} because ${lowercaseFirstWord(stripSentence(why))}` : whatHappened;
|
|
59
|
+
const shouldCombineWayOut = !!fix && !!wayOut && /^[a-z]/.test(stripSentence(wayOut));
|
|
60
|
+
const messageParts = [
|
|
61
|
+
whatAndWhy,
|
|
62
|
+
reassurance,
|
|
63
|
+
shouldCombineWayOut ? `${stripSentence(fix)}, or ${lowercaseFirstWord(stripSentence(wayOut))}` : fix,
|
|
64
|
+
shouldCombineWayOut ? void 0 : wayOut,
|
|
65
|
+
formatDetails(details)
|
|
66
|
+
].filter((part) => !!part).map(ensureSentence);
|
|
67
|
+
if (docsUrl) messageParts.push(`Learn more: ${docsUrl}`);
|
|
68
|
+
const message = messageParts.join(" ");
|
|
69
|
+
return prefix ? `${prefix} ${message}` : message;
|
|
70
|
+
}
|
|
32
71
|
const defaultCacheUrl = "https://cdn.gtx.dev";
|
|
33
72
|
//#endregion
|
|
34
73
|
//#region ../core/dist/isVariable-fAKEB7gF.mjs
|
|
@@ -4303,7 +4342,7 @@ function sanitizeJsxChildren(childrenAsObjects) {
|
|
|
4303
4342
|
return Array.isArray(childrenAsObjects) ? childrenAsObjects.map(sanitizeChild) : sanitizeChild(childrenAsObjects);
|
|
4304
4343
|
}
|
|
4305
4344
|
//#endregion
|
|
4306
|
-
//#region ../i18n/dist/versionId-
|
|
4345
|
+
//#region ../i18n/dist/versionId-BTjLA0FZ.mjs
|
|
4307
4346
|
/**
|
|
4308
4347
|
* Throw errors if there are any errors and log warnings if there are any warnings
|
|
4309
4348
|
* @param {ValidationResult[]} results - The results to print
|
|
@@ -4349,9 +4388,9 @@ function getLoadTranslationsType(config) {
|
|
|
4349
4388
|
* Requirements:
|
|
4350
4389
|
* - REMOTE:
|
|
4351
4390
|
* - GT_REMOTE:
|
|
4352
|
-
* - projectId is
|
|
4391
|
+
* - projectId is needed
|
|
4353
4392
|
* - CUSTOM:
|
|
4354
|
-
* - loadTranslations is
|
|
4393
|
+
* - loadTranslations is needed
|
|
4355
4394
|
* - DISABLED:
|
|
4356
4395
|
* - no requirements
|
|
4357
4396
|
*/
|
|
@@ -4363,13 +4402,19 @@ function validateLoadTranslations(params) {
|
|
|
4363
4402
|
case "gt-remote":
|
|
4364
4403
|
if (!projectId) results.push({
|
|
4365
4404
|
type: "warning",
|
|
4366
|
-
message:
|
|
4405
|
+
message: createDiagnosticMessage({
|
|
4406
|
+
whatHappened: "Loading translations from a remote store needs a projectId",
|
|
4407
|
+
fix: "Add projectId to the I18nManager config or disable remote translation loading"
|
|
4408
|
+
})
|
|
4367
4409
|
});
|
|
4368
4410
|
break;
|
|
4369
4411
|
case "custom":
|
|
4370
4412
|
if (!loadTranslations) results.push({
|
|
4371
4413
|
type: "error",
|
|
4372
|
-
message:
|
|
4414
|
+
message: createDiagnosticMessage({
|
|
4415
|
+
whatHappened: "Custom translation loading needs loadTranslations",
|
|
4416
|
+
fix: "Provide a loadTranslations function or disable custom translation loading"
|
|
4417
|
+
})
|
|
4373
4418
|
});
|
|
4374
4419
|
break;
|
|
4375
4420
|
case "disabled": break;
|
|
@@ -4382,8 +4427,9 @@ function validateLoadTranslations(params) {
|
|
|
4382
4427
|
* @returns The runtime translation type
|
|
4383
4428
|
*/
|
|
4384
4429
|
function getTranslationApiType(params) {
|
|
4385
|
-
|
|
4386
|
-
|
|
4430
|
+
const usesDefaultRuntimeUrl = params.runtimeUrl === void 0 || params.runtimeUrl === "https://runtime2.gtx.dev";
|
|
4431
|
+
if (usesDefaultRuntimeUrl && params.projectId && (params.devApiKey || params.apiKey)) return "gt";
|
|
4432
|
+
else if (params.runtimeUrl && !usesDefaultRuntimeUrl) return "custom";
|
|
4387
4433
|
else return "disabled";
|
|
4388
4434
|
}
|
|
4389
4435
|
/**
|
|
@@ -4399,8 +4445,8 @@ function getTranslationApiType(params) {
|
|
|
4399
4445
|
* Requirements:
|
|
4400
4446
|
* - CUSTOM:
|
|
4401
4447
|
* - GT:
|
|
4402
|
-
* - projectId is
|
|
4403
|
-
* - devApiKey or apiKey is
|
|
4448
|
+
* - projectId is needed
|
|
4449
|
+
* - devApiKey or apiKey is needed
|
|
4404
4450
|
* - DISABLED:
|
|
4405
4451
|
* - no requirements
|
|
4406
4452
|
*
|
|
@@ -4413,11 +4459,17 @@ function validateTranslationApi(params) {
|
|
|
4413
4459
|
case "gt":
|
|
4414
4460
|
if (!params.projectId) results.push({
|
|
4415
4461
|
type: "warning",
|
|
4416
|
-
message:
|
|
4462
|
+
message: createDiagnosticMessage({
|
|
4463
|
+
whatHappened: "Runtime translation needs a projectId",
|
|
4464
|
+
fix: "Add projectId to the I18nManager config or disable runtime translation"
|
|
4465
|
+
})
|
|
4417
4466
|
});
|
|
4418
4467
|
if (!params.devApiKey && !params.apiKey) results.push({
|
|
4419
4468
|
type: "warning",
|
|
4420
|
-
message:
|
|
4469
|
+
message: createDiagnosticMessage({
|
|
4470
|
+
whatHappened: "Runtime translation needs devApiKey or apiKey",
|
|
4471
|
+
fix: "Add credentials to the I18nManager config or disable runtime translation"
|
|
4472
|
+
})
|
|
4421
4473
|
});
|
|
4422
4474
|
break;
|
|
4423
4475
|
case "disabled": break;
|
|
@@ -4446,7 +4498,10 @@ function validateLocales(params) {
|
|
|
4446
4498
|
new Set([...defaultLocale ? [defaultLocale] : [], ...locales || []]).forEach((locale) => {
|
|
4447
4499
|
if (!isValidLocale(locale, customMapping)) results.push({
|
|
4448
4500
|
type: "error",
|
|
4449
|
-
message:
|
|
4501
|
+
message: createDiagnosticMessage({
|
|
4502
|
+
whatHappened: `Locale "${locale}" is not valid`,
|
|
4503
|
+
fix: "Use a valid BCP 47 locale code or add a custom mapping"
|
|
4504
|
+
})
|
|
4450
4505
|
});
|
|
4451
4506
|
});
|
|
4452
4507
|
return results;
|
|
@@ -4461,7 +4516,10 @@ function validateDictionary(params) {
|
|
|
4461
4516
|
const results = [];
|
|
4462
4517
|
if (params.loadDictionary && !params.dictionary) results.push({
|
|
4463
4518
|
type: "error",
|
|
4464
|
-
message:
|
|
4519
|
+
message: createDiagnosticMessage({
|
|
4520
|
+
whatHappened: "loadDictionary needs a source dictionary",
|
|
4521
|
+
fix: "Provide dictionary so the default locale has source content"
|
|
4522
|
+
})
|
|
4465
4523
|
});
|
|
4466
4524
|
return results;
|
|
4467
4525
|
}
|
|
@@ -4550,83 +4608,269 @@ function routeCreateTranslationLoader({ type, remoteTranslationLoaderParams, loa
|
|
|
4550
4608
|
case "disabled": return createFallbackTranslationLoader();
|
|
4551
4609
|
}
|
|
4552
4610
|
}
|
|
4553
|
-
function
|
|
4554
|
-
|
|
4555
|
-
const
|
|
4556
|
-
return
|
|
4611
|
+
function getDictionaryPath(id) {
|
|
4612
|
+
const path = id ? id.split(".") : [];
|
|
4613
|
+
for (const segment of path) assertSafeDictionaryPathSegment(segment, id);
|
|
4614
|
+
return path;
|
|
4615
|
+
}
|
|
4616
|
+
function assertSafeDictionaryPathSegment(segment, path) {
|
|
4617
|
+
if (segment === "__proto__" || segment === "constructor" || segment === "prototype") throw new Error(`Dictionary path "${path}" contains an unsafe segment`);
|
|
4557
4618
|
}
|
|
4558
|
-
function
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4619
|
+
function isDictionaryObject(value) {
|
|
4620
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
4621
|
+
}
|
|
4622
|
+
function cloneDictionaryValue(value) {
|
|
4623
|
+
if (value === void 0 || typeof value === "string") return value;
|
|
4624
|
+
return structuredClone(value);
|
|
4625
|
+
}
|
|
4626
|
+
function getDictionaryValueAtPath(dictionary, path) {
|
|
4627
|
+
let current = dictionary;
|
|
4628
|
+
for (const segment of getDictionaryPath(path)) {
|
|
4629
|
+
if (!isDictionaryObject(current)) return;
|
|
4630
|
+
current = current[segment];
|
|
4631
|
+
}
|
|
4632
|
+
return current;
|
|
4633
|
+
}
|
|
4634
|
+
function setDictionaryValueAtPath(dictionary, path, value) {
|
|
4635
|
+
const segments = getDictionaryPath(path);
|
|
4636
|
+
if (isDictionaryObject(value)) assertSafeDictionaryObject(value, path);
|
|
4637
|
+
if (segments.length === 0) {
|
|
4638
|
+
if (isDictionaryObject(value)) replaceDictionary(dictionary, value);
|
|
4639
|
+
return;
|
|
4640
|
+
}
|
|
4641
|
+
let current = dictionary;
|
|
4642
|
+
for (const segment of segments.slice(0, -1)) {
|
|
4643
|
+
const next = current[segment];
|
|
4644
|
+
if (!isDictionaryObject(next)) current[segment] = {};
|
|
4645
|
+
current = current[segment];
|
|
4646
|
+
}
|
|
4647
|
+
const leafSegment = segments[segments.length - 1];
|
|
4648
|
+
current[leafSegment] = value;
|
|
4649
|
+
}
|
|
4650
|
+
function getDictionaryEntry(value) {
|
|
4651
|
+
if (!isDictionaryLeafNode(value)) return;
|
|
4652
|
+
return {
|
|
4653
|
+
entry: Array.isArray(value) ? value[0] : value,
|
|
4654
|
+
options: Array.isArray(value) ? value[1] ?? {} : {}
|
|
4655
|
+
};
|
|
4656
|
+
}
|
|
4657
|
+
function getDictionaryValue(value) {
|
|
4658
|
+
if (Object.keys(value.options).length === 0) return value.entry;
|
|
4659
|
+
return [value.entry, value.options];
|
|
4660
|
+
}
|
|
4661
|
+
function resolveDictionaryLookupOptions(options) {
|
|
4662
|
+
const { $format, context, ...rest } = options;
|
|
4663
|
+
return {
|
|
4664
|
+
...rest,
|
|
4665
|
+
$format: isStringFormat($format) ? $format : "ICU",
|
|
4666
|
+
...rest.$context === void 0 && typeof context === "string" && { $context: context }
|
|
4667
|
+
};
|
|
4668
|
+
}
|
|
4669
|
+
function isDictionaryLeafNode(value) {
|
|
4670
|
+
if (typeof value === "string") return true;
|
|
4671
|
+
if (!Array.isArray(value) || typeof value[0] !== "string") return false;
|
|
4672
|
+
if (value.length === 1) return true;
|
|
4673
|
+
return value.length === 2 && isDictionaryOptions(value[1]);
|
|
4674
|
+
}
|
|
4675
|
+
function isDictionaryOptions(value) {
|
|
4676
|
+
if (typeof value !== "object" || value == null || Array.isArray(value)) return false;
|
|
4677
|
+
const options = value;
|
|
4678
|
+
return (options.$context === void 0 || typeof options.$context === "string") && (options.$format === void 0 || isStringFormat(options.$format)) && (options.$maxChars === void 0 || typeof options.$maxChars === "number") && (options.context === void 0 || typeof options.context === "string");
|
|
4679
|
+
}
|
|
4680
|
+
function isStringFormat(value) {
|
|
4681
|
+
return value === "ICU" || value === "I18NEXT" || value === "STRING";
|
|
4682
|
+
}
|
|
4683
|
+
function replaceDictionary(target, source) {
|
|
4684
|
+
for (const key of Object.keys(target)) delete target[key];
|
|
4685
|
+
for (const key of Object.keys(source)) target[key] = source[key];
|
|
4562
4686
|
}
|
|
4687
|
+
function assertSafeDictionaryObject(dictionary, parentPath = "") {
|
|
4688
|
+
for (const [key, value] of Object.entries(dictionary)) {
|
|
4689
|
+
const path = parentPath ? `${parentPath}.${key}` : key;
|
|
4690
|
+
assertSafeDictionaryPathSegment(key, path);
|
|
4691
|
+
if (isDictionaryObject(value)) assertSafeDictionaryObject(value, path);
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
var DictionarySourceNotFoundError = class extends Error {
|
|
4695
|
+
constructor(id) {
|
|
4696
|
+
super(`I18nManager: source dictionary entry ${id} is not defined`);
|
|
4697
|
+
this.name = "DictionarySourceNotFoundError";
|
|
4698
|
+
}
|
|
4699
|
+
};
|
|
4563
4700
|
/**
|
|
4564
|
-
*
|
|
4565
|
-
*
|
|
4566
|
-
* to invoke the cache miss method when a cache miss occurs.
|
|
4567
|
-
*
|
|
4568
|
-
* TODO: maybe add "OutputValue" as a reflection of "InputKey"
|
|
4701
|
+
* Builds the dictionary value for a requested path by combining existing target
|
|
4702
|
+
* translations with runtime translations of any source leaves that are missing.
|
|
4569
4703
|
*/
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4704
|
+
async function materializeDictionaryValue({ key, sourceValue, targetValue, translateEntry }) {
|
|
4705
|
+
if (getDictionaryEntry(targetValue) !== void 0) return cloneDictionaryValue(targetValue);
|
|
4706
|
+
if (isDictionaryObject(targetValue) && !isDictionaryObject(sourceValue)) return cloneDictionaryValue(targetValue);
|
|
4707
|
+
const sourceEntry = getDictionaryEntry(sourceValue);
|
|
4708
|
+
if (sourceEntry !== void 0) return await translateEntry(key, sourceEntry);
|
|
4709
|
+
if (!isDictionaryObject(sourceValue)) throw new DictionarySourceNotFoundError(key);
|
|
4710
|
+
const targetDictionary = isDictionaryObject(targetValue) ? targetValue : {};
|
|
4711
|
+
const keys = new Set([...Object.keys(sourceValue), ...Object.keys(targetDictionary)]);
|
|
4712
|
+
const entries = await Promise.all(Array.from(keys).map(async (childKey) => {
|
|
4713
|
+
const childPath = key ? `${key}.${childKey}` : childKey;
|
|
4714
|
+
assertSafeDictionaryPathSegment(childKey, childPath);
|
|
4715
|
+
const childSource = sourceValue[childKey];
|
|
4716
|
+
if (childSource === void 0) return [childKey, cloneDictionaryValue(targetDictionary[childKey])];
|
|
4717
|
+
return [childKey, await materializeDictionaryValue({
|
|
4718
|
+
key: childPath,
|
|
4719
|
+
sourceValue: childSource,
|
|
4720
|
+
targetValue: targetDictionary[childKey],
|
|
4721
|
+
translateEntry
|
|
4722
|
+
})];
|
|
4723
|
+
}));
|
|
4724
|
+
return Object.fromEntries(entries);
|
|
4725
|
+
}
|
|
4726
|
+
function cloneDictionaryEntry(entry) {
|
|
4727
|
+
return {
|
|
4728
|
+
entry: entry.entry,
|
|
4729
|
+
options: structuredClone(entry.options)
|
|
4730
|
+
};
|
|
4731
|
+
}
|
|
4732
|
+
var DictionaryCache = class {
|
|
4733
|
+
constructor({ init, lifecycle = {}, runtimeTranslate }) {
|
|
4734
|
+
this.pendingTranslations = /* @__PURE__ */ new Map();
|
|
4735
|
+
this.pendingMaterializations = /* @__PURE__ */ new Map();
|
|
4580
4736
|
this.cache = structuredClone(init);
|
|
4581
|
-
this.
|
|
4582
|
-
this.
|
|
4737
|
+
this.runtimeTranslate = runtimeTranslate;
|
|
4738
|
+
this.lifecycle = lifecycle;
|
|
4583
4739
|
}
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4740
|
+
getEntry(key) {
|
|
4741
|
+
const value = getDictionaryValueAtPath(this.cache, key);
|
|
4742
|
+
const entry = getDictionaryEntry(value);
|
|
4743
|
+
if (entry === void 0) return;
|
|
4744
|
+
const outputEntry = cloneDictionaryEntry(entry);
|
|
4745
|
+
this.lifecycle.onHit?.({
|
|
4746
|
+
inputKey: key,
|
|
4747
|
+
cacheKey: key,
|
|
4748
|
+
cacheValue: value,
|
|
4749
|
+
outputValue: outputEntry
|
|
4750
|
+
});
|
|
4751
|
+
return outputEntry;
|
|
4589
4752
|
}
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4753
|
+
getValue(key) {
|
|
4754
|
+
const value = getDictionaryValueAtPath(this.cache, key);
|
|
4755
|
+
if (value === void 0) return;
|
|
4756
|
+
const outputValue = cloneDictionaryValue(value);
|
|
4757
|
+
this.lifecycle.onDictionaryObjectCacheHit?.({
|
|
4758
|
+
inputKey: key,
|
|
4759
|
+
cacheKey: key,
|
|
4760
|
+
cacheValue: value,
|
|
4761
|
+
outputValue
|
|
4762
|
+
});
|
|
4763
|
+
return outputValue;
|
|
4764
|
+
}
|
|
4765
|
+
setValue(key, value) {
|
|
4766
|
+
setDictionaryValueAtPath(this.cache, key, cloneDictionaryValue(value));
|
|
4596
4767
|
}
|
|
4597
|
-
/**
|
|
4598
|
-
* Get the internal cache
|
|
4599
|
-
* @returns The internal cache
|
|
4600
|
-
*
|
|
4601
|
-
* @internal - used by gt-tanstack-start
|
|
4602
|
-
*/
|
|
4603
4768
|
getInternalCache() {
|
|
4604
|
-
return
|
|
4769
|
+
return cloneDictionaryValue(this.cache);
|
|
4770
|
+
}
|
|
4771
|
+
async materializeValue(key, sourceValue, targetValue = getDictionaryValueAtPath(this.cache, key)) {
|
|
4772
|
+
let materializationPromise = this.pendingMaterializations.get(key);
|
|
4773
|
+
if (!materializationPromise) {
|
|
4774
|
+
materializationPromise = materializeDictionaryValue({
|
|
4775
|
+
key,
|
|
4776
|
+
sourceValue,
|
|
4777
|
+
targetValue,
|
|
4778
|
+
translateEntry: async (entryKey, sourceEntry) => getDictionaryValue(await this.materializeEntry(entryKey, sourceEntry))
|
|
4779
|
+
}).then((value) => {
|
|
4780
|
+
this.setValue(key, value);
|
|
4781
|
+
return value;
|
|
4782
|
+
});
|
|
4783
|
+
this.pendingMaterializations.set(key, materializationPromise);
|
|
4784
|
+
}
|
|
4785
|
+
try {
|
|
4786
|
+
return await materializationPromise;
|
|
4787
|
+
} finally {
|
|
4788
|
+
this.pendingMaterializations.delete(key);
|
|
4789
|
+
}
|
|
4605
4790
|
}
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4791
|
+
async materializeEntry(key, sourceEntry) {
|
|
4792
|
+
let translationPromise = this.pendingTranslations.get(key);
|
|
4793
|
+
if (!translationPromise) {
|
|
4794
|
+
translationPromise = this.runtimeTranslate(key, sourceEntry).then((value) => {
|
|
4795
|
+
setDictionaryValueAtPath(this.cache, key, value);
|
|
4796
|
+
const entry = getDictionaryEntry(value);
|
|
4797
|
+
if (entry === void 0) throw new Error("DictionaryCache materializeEntry did not return a DictionaryEntry");
|
|
4798
|
+
this.lifecycle.onMiss?.({
|
|
4799
|
+
inputKey: key,
|
|
4800
|
+
cacheKey: key,
|
|
4801
|
+
cacheValue: value,
|
|
4802
|
+
outputValue: cloneDictionaryEntry(entry)
|
|
4803
|
+
});
|
|
4804
|
+
return cloneDictionaryEntry(entry);
|
|
4805
|
+
});
|
|
4806
|
+
this.pendingTranslations.set(key, translationPromise);
|
|
4807
|
+
}
|
|
4808
|
+
try {
|
|
4809
|
+
return cloneDictionaryEntry(await translationPromise);
|
|
4810
|
+
} finally {
|
|
4811
|
+
this.pendingTranslations.delete(key);
|
|
4812
|
+
}
|
|
4611
4813
|
}
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4814
|
+
};
|
|
4815
|
+
var ResourceCache = class {
|
|
4816
|
+
constructor({ load, lifecycle = {}, ttl }) {
|
|
4817
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
4818
|
+
this.pendingLoads = /* @__PURE__ */ new Map();
|
|
4819
|
+
this.loadResource = load;
|
|
4820
|
+
this.lifecycle = lifecycle;
|
|
4821
|
+
this.ttl = ttl === null ? -1 : ttl ?? 6e4;
|
|
4822
|
+
}
|
|
4823
|
+
get(key) {
|
|
4824
|
+
const entry = this.cache.get(key);
|
|
4825
|
+
if (!entry || this.isExpired(entry)) return;
|
|
4826
|
+
this.lifecycle.onHit?.({
|
|
4827
|
+
inputKey: key,
|
|
4828
|
+
cacheKey: key,
|
|
4829
|
+
cacheValue: entry,
|
|
4830
|
+
outputValue: entry.value
|
|
4831
|
+
});
|
|
4832
|
+
return entry.value;
|
|
4833
|
+
}
|
|
4834
|
+
set(key, value, { expiresAt = this.getExpiresAt() } = {}) {
|
|
4835
|
+
this.cache.set(key, {
|
|
4836
|
+
expiresAt,
|
|
4837
|
+
value
|
|
4838
|
+
});
|
|
4839
|
+
}
|
|
4840
|
+
async getOrLoad(key) {
|
|
4841
|
+
return this.get(key) ?? await this.load(key);
|
|
4842
|
+
}
|
|
4843
|
+
async load(key) {
|
|
4844
|
+
let loadPromise = this.pendingLoads.get(key);
|
|
4845
|
+
if (!loadPromise) {
|
|
4846
|
+
loadPromise = this.loadResource(key).then((value) => {
|
|
4847
|
+
const entry = {
|
|
4848
|
+
expiresAt: this.getExpiresAt(),
|
|
4849
|
+
value
|
|
4850
|
+
};
|
|
4851
|
+
this.cache.set(key, entry);
|
|
4852
|
+
this.lifecycle.onMiss?.({
|
|
4853
|
+
inputKey: key,
|
|
4854
|
+
cacheKey: key,
|
|
4855
|
+
cacheValue: entry,
|
|
4856
|
+
outputValue: entry.value
|
|
4857
|
+
});
|
|
4858
|
+
return entry;
|
|
4859
|
+
});
|
|
4860
|
+
this.pendingLoads.set(key, loadPromise);
|
|
4861
|
+
}
|
|
4622
4862
|
try {
|
|
4623
|
-
|
|
4624
|
-
this.setCache(cacheKey, value);
|
|
4625
|
-
return value;
|
|
4863
|
+
return (await loadPromise).value;
|
|
4626
4864
|
} finally {
|
|
4627
|
-
|
|
4865
|
+
this.pendingLoads.delete(key);
|
|
4628
4866
|
}
|
|
4629
4867
|
}
|
|
4868
|
+
getExpiresAt() {
|
|
4869
|
+
return this.ttl < 0 ? this.ttl : Date.now() + this.ttl;
|
|
4870
|
+
}
|
|
4871
|
+
isExpired(entry) {
|
|
4872
|
+
return entry.expiresAt > 0 && entry.expiresAt < Date.now();
|
|
4873
|
+
}
|
|
4630
4874
|
};
|
|
4631
4875
|
/**
|
|
4632
4876
|
* Hash a message string
|
|
@@ -4671,20 +4915,22 @@ function normalizeBatchConfig(batchConfig) {
|
|
|
4671
4915
|
* Locale logic is handled at the LocalesCache level. Use a callback function that has the
|
|
4672
4916
|
* locale parameter embedded if you wish to use the locale code.
|
|
4673
4917
|
*/
|
|
4674
|
-
var TranslationsCache = class
|
|
4918
|
+
var TranslationsCache = class {
|
|
4675
4919
|
/**
|
|
4676
4920
|
* Constructor
|
|
4677
4921
|
* @param {Object} params - The parameters for the cache
|
|
4678
4922
|
* @param {Record<Hash, TranslationValue>} params.init - The initial cache
|
|
4679
4923
|
* @param {Function} params.fallback - Get the fallback value for a cache miss
|
|
4680
4924
|
*/
|
|
4681
|
-
constructor({ init, translateMany, lifecycle, batchConfig }) {
|
|
4682
|
-
|
|
4683
|
-
this.
|
|
4684
|
-
this.
|
|
4685
|
-
this.
|
|
4686
|
-
this.
|
|
4687
|
-
this.
|
|
4925
|
+
constructor({ init, translateMany, lifecycle = {}, batchConfig }) {
|
|
4926
|
+
this.pendingTranslations = /* @__PURE__ */ new Map();
|
|
4927
|
+
this.queue = [];
|
|
4928
|
+
this.batchTimer = null;
|
|
4929
|
+
this.activeRequests = 0;
|
|
4930
|
+
this.cache = structuredClone(init);
|
|
4931
|
+
this.translateMany = translateMany;
|
|
4932
|
+
this.batchConfig = normalizeBatchConfig(batchConfig);
|
|
4933
|
+
this.lifecycle = lifecycle;
|
|
4688
4934
|
}
|
|
4689
4935
|
/**
|
|
4690
4936
|
* Get the translation value for a given key
|
|
@@ -4692,10 +4938,11 @@ var TranslationsCache = class extends Cache {
|
|
|
4692
4938
|
* @returns The translation value
|
|
4693
4939
|
*/
|
|
4694
4940
|
get(key) {
|
|
4695
|
-
const
|
|
4696
|
-
|
|
4941
|
+
const cacheKey = this.getCacheKey(key);
|
|
4942
|
+
const value = this.cache[cacheKey];
|
|
4943
|
+
if (value != null) this.lifecycle.onHit?.({
|
|
4697
4944
|
inputKey: key,
|
|
4698
|
-
cacheKey
|
|
4945
|
+
cacheKey,
|
|
4699
4946
|
cacheValue: value,
|
|
4700
4947
|
outputValue: value
|
|
4701
4948
|
});
|
|
@@ -4707,75 +4954,64 @@ var TranslationsCache = class extends Cache {
|
|
|
4707
4954
|
* @returns The translation value
|
|
4708
4955
|
*/
|
|
4709
4956
|
async miss(key) {
|
|
4710
|
-
const
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4957
|
+
const cacheKey = this.getCacheKey(key);
|
|
4958
|
+
let translationPromise = this.pendingTranslations.get(cacheKey);
|
|
4959
|
+
if (!translationPromise) {
|
|
4960
|
+
translationPromise = this.translate(key);
|
|
4961
|
+
this.pendingTranslations.set(cacheKey, translationPromise);
|
|
4962
|
+
}
|
|
4963
|
+
try {
|
|
4964
|
+
const value = await translationPromise;
|
|
4965
|
+
if (value != null) this.lifecycle.onMiss?.({
|
|
4966
|
+
inputKey: key,
|
|
4967
|
+
cacheKey,
|
|
4968
|
+
cacheValue: value,
|
|
4969
|
+
outputValue: value
|
|
4970
|
+
});
|
|
4971
|
+
return value;
|
|
4972
|
+
} finally {
|
|
4973
|
+
this.pendingTranslations.delete(cacheKey);
|
|
4974
|
+
}
|
|
4718
4975
|
}
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
*/
|
|
4724
|
-
genKey(key) {
|
|
4976
|
+
getInternalCache() {
|
|
4977
|
+
return structuredClone(this.cache);
|
|
4978
|
+
}
|
|
4979
|
+
getCacheKey(key) {
|
|
4725
4980
|
return hashMessage(key.message, key.options);
|
|
4726
4981
|
}
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
*/
|
|
4732
|
-
fallback(key) {
|
|
4733
|
-
const translationPromise = this._enqueueTranslation(key);
|
|
4734
|
-
if (this._queue.length >= this._batchConfig.maxBatchSize) this._flushNow();
|
|
4735
|
-
else this._scheduleBatch();
|
|
4982
|
+
translate(key) {
|
|
4983
|
+
const translationPromise = this.enqueueTranslation(key);
|
|
4984
|
+
if (this.queue.length >= this.batchConfig.maxBatchSize) this.flushNow();
|
|
4985
|
+
else this.scheduleBatch();
|
|
4736
4986
|
return translationPromise;
|
|
4737
4987
|
}
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
if (this._batchTimer) {
|
|
4743
|
-
clearTimeout(this._batchTimer);
|
|
4744
|
-
this._batchTimer = null;
|
|
4988
|
+
flushNow() {
|
|
4989
|
+
if (this.batchTimer) {
|
|
4990
|
+
clearTimeout(this.batchTimer);
|
|
4991
|
+
this.batchTimer = null;
|
|
4745
4992
|
}
|
|
4746
|
-
this.
|
|
4747
|
-
}
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
this.
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
* Drain the queue
|
|
4760
|
-
*/
|
|
4761
|
-
_drainQueue() {
|
|
4762
|
-
while (this._queue.length > 0 && this._activeRequests < this._batchConfig.maxConcurrentRequests) {
|
|
4763
|
-
const batch = this._queue.splice(0, this._batchConfig.maxBatchSize);
|
|
4764
|
-
this._sendBatchRequest(batch);
|
|
4993
|
+
this.drainQueue();
|
|
4994
|
+
}
|
|
4995
|
+
scheduleBatch() {
|
|
4996
|
+
if (this.batchTimer) return;
|
|
4997
|
+
this.batchTimer = setTimeout(() => {
|
|
4998
|
+
this.batchTimer = null;
|
|
4999
|
+
this.drainQueue();
|
|
5000
|
+
}, this.batchConfig.batchInterval);
|
|
5001
|
+
}
|
|
5002
|
+
drainQueue() {
|
|
5003
|
+
while (this.queue.length > 0 && this.activeRequests < this.batchConfig.maxConcurrentRequests) {
|
|
5004
|
+
const batch = this.queue.splice(0, this.batchConfig.maxBatchSize);
|
|
5005
|
+
this.sendBatchRequest(batch);
|
|
4765
5006
|
}
|
|
4766
|
-
if (this.
|
|
5007
|
+
if (this.queue.length > 0) this.scheduleBatch();
|
|
4767
5008
|
}
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
* @param {TranslationKey<TranslationValue>} key - The translation key
|
|
4771
|
-
* @returns {Promise<TranslationValue>} The translation promise
|
|
4772
|
-
*/
|
|
4773
|
-
_enqueueTranslation(key) {
|
|
4774
|
-
const hash = this.genKey(key);
|
|
5009
|
+
enqueueTranslation(key) {
|
|
5010
|
+
const hash = this.getCacheKey(key);
|
|
4775
5011
|
const options = key.options;
|
|
4776
5012
|
const metadataOptions = options;
|
|
4777
5013
|
return new Promise((resolve, reject) => {
|
|
4778
|
-
this.
|
|
5014
|
+
this.queue.push({
|
|
4779
5015
|
key: hash,
|
|
4780
5016
|
source: key.message,
|
|
4781
5017
|
metadata: {
|
|
@@ -4790,38 +5026,28 @@ var TranslationsCache = class extends Cache {
|
|
|
4790
5026
|
});
|
|
4791
5027
|
});
|
|
4792
5028
|
}
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
* @param {QueueEntry<TranslationValue>[]} batch - The batch of requests to send
|
|
4796
|
-
*/
|
|
4797
|
-
async _sendBatchRequest(batch) {
|
|
4798
|
-
this._activeRequests++;
|
|
5029
|
+
async sendBatchRequest(batch) {
|
|
5030
|
+
this.activeRequests++;
|
|
4799
5031
|
const requests = convertBatchToTranslateManyParams(batch);
|
|
4800
|
-
const response = await this.
|
|
4801
|
-
if (response) this.
|
|
4802
|
-
this.
|
|
5032
|
+
const response = await this.sendBatchRequestWithErrorHandling(batch, requests);
|
|
5033
|
+
if (response) this.handleTranslationResponse(batch, response);
|
|
5034
|
+
this.activeRequests--;
|
|
4803
5035
|
}
|
|
4804
|
-
|
|
4805
|
-
* Send a translation request with error handling
|
|
4806
|
-
*/
|
|
4807
|
-
async _sendBatchRequestWithErrorHandling(batch, requests) {
|
|
5036
|
+
async sendBatchRequestWithErrorHandling(batch, requests) {
|
|
4808
5037
|
try {
|
|
4809
|
-
return await this.
|
|
5038
|
+
return await this.translateMany(requests);
|
|
4810
5039
|
} catch (error) {
|
|
4811
5040
|
for (const entry of batch) entry.reject(error);
|
|
4812
5041
|
return;
|
|
4813
5042
|
}
|
|
4814
5043
|
}
|
|
4815
|
-
|
|
4816
|
-
* Handle a translation response
|
|
4817
|
-
*/
|
|
4818
|
-
_handleTranslationResponse(batch, response) {
|
|
5044
|
+
handleTranslationResponse(batch, response) {
|
|
4819
5045
|
for (const entry of batch) {
|
|
4820
5046
|
const { key } = entry;
|
|
4821
5047
|
const result = response[key];
|
|
4822
5048
|
if (result && result.success) {
|
|
4823
5049
|
const translation = result.translation;
|
|
4824
|
-
this.
|
|
5050
|
+
this.cache[key] = translation;
|
|
4825
5051
|
entry.resolve(translation);
|
|
4826
5052
|
} else entry.reject(result?.error);
|
|
4827
5053
|
}
|
|
@@ -4839,415 +5065,87 @@ function convertBatchToTranslateManyParams(batch) {
|
|
|
4839
5065
|
return acc;
|
|
4840
5066
|
}, {});
|
|
4841
5067
|
}
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
* @param {CreateTranslateMany} params.createTranslateMany - Factory function for creating a translate many function
|
|
4857
|
-
*/
|
|
4858
|
-
constructor({ init = {}, ttl, batchConfig, loadTranslations, createTranslateMany, lifecycle: { onLocalesCacheHit: onHit, onLocalesCacheMiss: onMiss, onTranslationsCacheHit, onTranslationsCacheMiss } }) {
|
|
4859
|
-
super(init, {
|
|
4860
|
-
onHit,
|
|
4861
|
-
onMiss
|
|
5068
|
+
var LocalesCache = class {
|
|
5069
|
+
constructor({ ttl, batchConfig, defaultLocale, dictionary = {}, loadTranslations, loadDictionary, createTranslateMany, translateDictionaryEntry, lifecycle }) {
|
|
5070
|
+
this.translations = new ResourceCache({
|
|
5071
|
+
ttl,
|
|
5072
|
+
load: async (locale) => new TranslationsCache({
|
|
5073
|
+
init: await loadTranslations(locale),
|
|
5074
|
+
lifecycle: createTranslationsCacheLifecycle(locale, lifecycle),
|
|
5075
|
+
translateMany: createTranslateMany(locale),
|
|
5076
|
+
batchConfig
|
|
5077
|
+
}),
|
|
5078
|
+
lifecycle: {
|
|
5079
|
+
onHit: lifecycle.onLocalesCacheHit,
|
|
5080
|
+
onMiss: lifecycle.onLocalesCacheMiss
|
|
5081
|
+
}
|
|
4862
5082
|
});
|
|
4863
|
-
this.
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
*/
|
|
4876
|
-
get(key) {
|
|
4877
|
-
const entry = this.getCache(key);
|
|
4878
|
-
if (!entry || entry.expiresAt > 0 && entry.expiresAt < Date.now()) return;
|
|
4879
|
-
const value = entry.translationsCache;
|
|
4880
|
-
if (value != null && this.onHit) this.onHit({
|
|
4881
|
-
inputKey: key,
|
|
4882
|
-
cacheKey: this.genKey(key),
|
|
4883
|
-
cacheValue: entry,
|
|
4884
|
-
outputValue: value
|
|
5083
|
+
this.dictionaries = new ResourceCache({
|
|
5084
|
+
ttl,
|
|
5085
|
+
load: async (locale) => createDictionaryCache({
|
|
5086
|
+
locale,
|
|
5087
|
+
dictionary: await loadDictionary(locale),
|
|
5088
|
+
translate: translateDictionaryEntry,
|
|
5089
|
+
lifecycle
|
|
5090
|
+
}),
|
|
5091
|
+
lifecycle: {
|
|
5092
|
+
onHit: lifecycle.onLocalesDictionaryCacheHit,
|
|
5093
|
+
onMiss: lifecycle.onLocalesDictionaryCacheMiss
|
|
5094
|
+
}
|
|
4885
5095
|
});
|
|
4886
|
-
|
|
5096
|
+
this.dictionaries.set(defaultLocale, createDictionaryCache({
|
|
5097
|
+
locale: defaultLocale,
|
|
5098
|
+
dictionary,
|
|
5099
|
+
translate: translateDictionaryEntry,
|
|
5100
|
+
lifecycle
|
|
5101
|
+
}), { expiresAt: -1 });
|
|
4887
5102
|
}
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
* @param key - The locale
|
|
4891
|
-
* @returns The translations cache
|
|
4892
|
-
*/
|
|
4893
|
-
async miss(key) {
|
|
4894
|
-
const cacheValue = await this.missCache(key);
|
|
4895
|
-
const value = cacheValue.translationsCache;
|
|
4896
|
-
if (value != null && this.onMiss) this.onMiss({
|
|
4897
|
-
inputKey: key,
|
|
4898
|
-
cacheKey: this.genKey(key),
|
|
4899
|
-
cacheValue,
|
|
4900
|
-
outputValue: value
|
|
4901
|
-
});
|
|
4902
|
-
return value;
|
|
5103
|
+
getTranslations(locale) {
|
|
5104
|
+
return this.translations.get(locale);
|
|
4903
5105
|
}
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
* @param key - The locale
|
|
4907
|
-
* @returns The cache key
|
|
4908
|
-
*
|
|
4909
|
-
* This is just an identity function, no transformation needed
|
|
4910
|
-
*/
|
|
4911
|
-
genKey(key) {
|
|
4912
|
-
return key;
|
|
5106
|
+
getOrLoadTranslations(locale) {
|
|
5107
|
+
return this.translations.getOrLoad(locale);
|
|
4913
5108
|
}
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
* @param locale - The locale
|
|
4917
|
-
* @returns The cache entry
|
|
4918
|
-
*/
|
|
4919
|
-
async fallback(locale) {
|
|
4920
|
-
return {
|
|
4921
|
-
translationsCache: new TranslationsCache({
|
|
4922
|
-
init: await this._translationLoader(locale),
|
|
4923
|
-
lifecycle: this._createTranslationsCacheLifecycle(locale),
|
|
4924
|
-
translateMany: this._createTranslateMany(locale),
|
|
4925
|
-
batchConfig: this._batchConfig
|
|
4926
|
-
}),
|
|
4927
|
-
expiresAt: this.ttl < 0 ? this.ttl : Date.now() + this.ttl
|
|
4928
|
-
};
|
|
5109
|
+
getDictionary(locale) {
|
|
5110
|
+
return this.dictionaries.get(locale);
|
|
4929
5111
|
}
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
* @param locale - The locale
|
|
4933
|
-
* @returns The translations cache lifecycle
|
|
4934
|
-
*/
|
|
4935
|
-
_createTranslationsCacheLifecycle(locale) {
|
|
4936
|
-
return {
|
|
4937
|
-
onHit: this._onTranslationsCacheHit ? (params) => this._onTranslationsCacheHit({
|
|
4938
|
-
locale,
|
|
4939
|
-
...params
|
|
4940
|
-
}) : void 0,
|
|
4941
|
-
onMiss: this._onTranslationsCacheMiss ? (params) => this._onTranslationsCacheMiss({
|
|
4942
|
-
locale,
|
|
4943
|
-
...params
|
|
4944
|
-
}) : void 0
|
|
4945
|
-
};
|
|
5112
|
+
getOrLoadDictionary(locale) {
|
|
5113
|
+
return this.dictionaries.getOrLoad(locale);
|
|
4946
5114
|
}
|
|
4947
5115
|
};
|
|
4948
|
-
function
|
|
4949
|
-
if (!id) return [];
|
|
4950
|
-
return id.split(".");
|
|
4951
|
-
}
|
|
4952
|
-
function isDictionaryValue(value) {
|
|
4953
|
-
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
4954
|
-
}
|
|
4955
|
-
function getDictionaryEntry(value) {
|
|
4956
|
-
if (!isDictionaryLeafNode(value)) return;
|
|
4957
|
-
return {
|
|
4958
|
-
entry: Array.isArray(value) ? value[0] : value,
|
|
4959
|
-
options: Array.isArray(value) ? value[1] ?? {} : {}
|
|
4960
|
-
};
|
|
4961
|
-
}
|
|
4962
|
-
function getDictionaryValue(value) {
|
|
4963
|
-
if (Object.keys(value.options).length === 0) return value.entry;
|
|
4964
|
-
return [value.entry, value.options];
|
|
4965
|
-
}
|
|
4966
|
-
function resolveDictionaryLookupOptions(options) {
|
|
4967
|
-
const { $format, ...rest } = options;
|
|
5116
|
+
function createTranslationsCacheLifecycle(locale, lifecycle) {
|
|
4968
5117
|
return {
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
...rest.$context === void 0 && typeof rest.context === "string" && { $context: rest.context }
|
|
5118
|
+
onHit: withLocale(locale, lifecycle.onTranslationsCacheHit),
|
|
5119
|
+
onMiss: withLocale(locale, lifecycle.onTranslationsCacheMiss)
|
|
4972
5120
|
};
|
|
4973
5121
|
}
|
|
4974
|
-
function
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
}
|
|
4985
|
-
function isStringFormat(value) {
|
|
4986
|
-
return value === "ICU" || value === "I18NEXT" || value === "STRING";
|
|
5122
|
+
function createDictionaryCache({ locale, dictionary, translate, lifecycle }) {
|
|
5123
|
+
const { onDictionaryCacheHit, onDictionaryCacheMiss, onDictionaryObjectCacheHit } = lifecycle;
|
|
5124
|
+
return new DictionaryCache({
|
|
5125
|
+
init: dictionary,
|
|
5126
|
+
runtimeTranslate: (key, sourceEntry) => translate(locale, key, sourceEntry),
|
|
5127
|
+
lifecycle: {
|
|
5128
|
+
onHit: withLocale(locale, onDictionaryCacheHit),
|
|
5129
|
+
onMiss: withLocale(locale, onDictionaryCacheMiss),
|
|
5130
|
+
onDictionaryObjectCacheHit: withLocale(locale, onDictionaryObjectCacheHit)
|
|
5131
|
+
}
|
|
5132
|
+
});
|
|
4987
5133
|
}
|
|
4988
|
-
function
|
|
4989
|
-
|
|
4990
|
-
|
|
5134
|
+
function withLocale(locale, callback) {
|
|
5135
|
+
return callback ? (params) => callback({
|
|
5136
|
+
locale,
|
|
5137
|
+
...params
|
|
5138
|
+
}) : void 0;
|
|
4991
5139
|
}
|
|
4992
|
-
|
|
4993
|
-
constructor(id) {
|
|
4994
|
-
super(`I18nManager: source dictionary entry ${id} is not defined`);
|
|
4995
|
-
this.name = "DictionarySourceNotFoundError";
|
|
4996
|
-
}
|
|
4997
|
-
};
|
|
4998
|
-
/**
|
|
4999
|
-
* A cache for a single locale's dictionary
|
|
5000
|
-
*
|
|
5001
|
-
* Principles:
|
|
5002
|
-
* - This class is language agnostic, and should never store the locale code as a parameter.
|
|
5003
|
-
* Locale logic is handled at the LocalesDictionaryCache level. Use a callback function
|
|
5004
|
-
* that has the locale parameter embedded if you wish to use the locale code.
|
|
5005
|
-
*/
|
|
5006
|
-
var DictionaryCache = class extends Cache {
|
|
5007
|
-
/**
|
|
5008
|
-
* Constructor
|
|
5009
|
-
* @param {Object} params - The parameters for the cache
|
|
5010
|
-
* @param {Dictionary} params.init - The initial cache
|
|
5011
|
-
*/
|
|
5012
|
-
constructor({ init, lifecycle, runtimeTranslate }) {
|
|
5013
|
-
super(init, lifecycle);
|
|
5014
|
-
this._runtimeTranslate = runtimeTranslate;
|
|
5015
|
-
this.onHitObj = lifecycle?.onHitObj;
|
|
5016
|
-
this.onMissObj = lifecycle?.onMissObj;
|
|
5017
|
-
}
|
|
5018
|
-
/**
|
|
5019
|
-
* Get the dictionary value for a given key
|
|
5020
|
-
* @param key - The dictionary key
|
|
5021
|
-
* @returns The dictionary value
|
|
5022
|
-
*/
|
|
5023
|
-
get(key) {
|
|
5024
|
-
const value = this.getCache(key);
|
|
5025
|
-
const entry = getDictionaryEntry(value);
|
|
5026
|
-
if (entry === void 0) return;
|
|
5027
|
-
if (this.onHit) this.onHit({
|
|
5028
|
-
inputKey: key,
|
|
5029
|
-
cacheKey: this.genKey(key),
|
|
5030
|
-
cacheValue: value,
|
|
5031
|
-
outputValue: entry
|
|
5032
|
-
});
|
|
5033
|
-
return entry;
|
|
5034
|
-
}
|
|
5035
|
-
set(key, value) {
|
|
5036
|
-
const dictionaryValue = getDictionaryValue(value);
|
|
5037
|
-
this.setCache(this.genKey(key), dictionaryValue);
|
|
5038
|
-
}
|
|
5039
|
-
getObj(key) {
|
|
5040
|
-
const value = this.getCache(key);
|
|
5041
|
-
if (value === void 0) return;
|
|
5042
|
-
const outputValue = structuredClone(value);
|
|
5043
|
-
if (this.onHitObj) this.onHitObj({
|
|
5044
|
-
inputKey: key,
|
|
5045
|
-
cacheKey: this.genKey(key),
|
|
5046
|
-
cacheValue: value,
|
|
5047
|
-
outputValue
|
|
5048
|
-
});
|
|
5049
|
-
return outputValue;
|
|
5050
|
-
}
|
|
5051
|
-
setObj(key, value) {
|
|
5052
|
-
this.setCache(this.genKey(key), structuredClone(value));
|
|
5053
|
-
}
|
|
5054
|
-
async missObj(key, sourceObject) {
|
|
5055
|
-
const sourceEntry = getDictionaryEntry(sourceObject);
|
|
5056
|
-
if (sourceEntry !== void 0) return getDictionaryValue(await this.miss(key, sourceEntry));
|
|
5057
|
-
if (!isDictionaryValue(sourceObject)) throw new DictionarySourceNotFoundError(key);
|
|
5058
|
-
const translatedEntries = await Promise.all(Object.entries(sourceObject).map(async ([childKey, childSource]) => {
|
|
5059
|
-
const childPath = key ? `${key}.${childKey}` : childKey;
|
|
5060
|
-
return [childKey, await this.missObj(childPath, childSource)];
|
|
5061
|
-
}));
|
|
5062
|
-
const translatedObject = Object.fromEntries(translatedEntries);
|
|
5063
|
-
this.setObj(key, translatedObject);
|
|
5064
|
-
return translatedObject;
|
|
5065
|
-
}
|
|
5066
|
-
/**
|
|
5067
|
-
* Miss the cache
|
|
5068
|
-
* @param key - The dictionary key
|
|
5069
|
-
* @returns The dictionary value
|
|
5070
|
-
*/
|
|
5071
|
-
async miss(key, sourceEntry) {
|
|
5072
|
-
const value = await this.missCache(key, sourceEntry);
|
|
5073
|
-
const entry = getDictionaryEntry(value);
|
|
5074
|
-
if (entry === void 0) throw new Error("DictionaryCache missCache did not return a DictionaryEntry");
|
|
5075
|
-
if (this.onMiss) this.onMiss({
|
|
5076
|
-
inputKey: key,
|
|
5077
|
-
cacheKey: this.genKey(key),
|
|
5078
|
-
cacheValue: value,
|
|
5079
|
-
outputValue: entry
|
|
5080
|
-
});
|
|
5081
|
-
return entry;
|
|
5082
|
-
}
|
|
5083
|
-
/**
|
|
5084
|
-
* Set the value for a key
|
|
5085
|
-
*/
|
|
5086
|
-
setCache(cacheKey, value) {
|
|
5087
|
-
const cache = this.getMutableCache();
|
|
5088
|
-
const dictionaryPath = getDictionaryPath(cacheKey);
|
|
5089
|
-
if (dictionaryPath.length === 0) {
|
|
5090
|
-
if (isDictionaryValue(value)) replaceDictionary(cache, value);
|
|
5091
|
-
return;
|
|
5092
|
-
}
|
|
5093
|
-
let current = cache;
|
|
5094
|
-
for (const key of dictionaryPath.slice(0, -1)) {
|
|
5095
|
-
const next = current[key];
|
|
5096
|
-
if (!isDictionaryValue(next)) current[key] = {};
|
|
5097
|
-
current = current[key];
|
|
5098
|
-
}
|
|
5099
|
-
current[dictionaryPath[dictionaryPath.length - 1]] = value;
|
|
5100
|
-
}
|
|
5101
|
-
/**
|
|
5102
|
-
* Look up the key
|
|
5103
|
-
*/
|
|
5104
|
-
getCache(key) {
|
|
5105
|
-
const dictionaryPath = getDictionaryPath(this.genKey(key));
|
|
5106
|
-
let current = this.getMutableCache();
|
|
5107
|
-
if (dictionaryPath.length === 0) return current;
|
|
5108
|
-
for (const pathSegment of dictionaryPath) {
|
|
5109
|
-
if (!isDictionaryValue(current)) return;
|
|
5110
|
-
current = current[pathSegment];
|
|
5111
|
-
}
|
|
5112
|
-
return current;
|
|
5113
|
-
}
|
|
5114
|
-
/**
|
|
5115
|
-
* Generate a key for the cache
|
|
5116
|
-
* @param key - The dictionary key
|
|
5117
|
-
* @returns The key
|
|
5118
|
-
*/
|
|
5119
|
-
genKey(key) {
|
|
5120
|
-
return key;
|
|
5121
|
-
}
|
|
5122
|
-
/**
|
|
5123
|
-
* Get the fallback value for a cache miss
|
|
5124
|
-
* @param key - The dictionary key
|
|
5125
|
-
* @returns The fallback value
|
|
5126
|
-
*
|
|
5127
|
-
* @throws {Error} - If the fallback is not implemented
|
|
5128
|
-
*/
|
|
5129
|
-
fallback(key, sourceEntry) {
|
|
5130
|
-
return this._runtimeTranslate(key, sourceEntry);
|
|
5131
|
-
}
|
|
5132
|
-
};
|
|
5133
|
-
/**
|
|
5134
|
-
* Cache for looking up dictionaries by locale
|
|
5135
|
-
*/
|
|
5136
|
-
var LocalesDictionaryCache = class extends Cache {
|
|
5137
|
-
/**
|
|
5138
|
-
* Constructor
|
|
5139
|
-
* @param {Object} params - The parameters for the cache
|
|
5140
|
-
* @param {number | null} params.ttl - The time to live for cache entries
|
|
5141
|
-
* @param {DictionaryLoader} params.loadDictionary - The dictionary loader function
|
|
5142
|
-
*/
|
|
5143
|
-
constructor({ ttl, defaultLocale, dictionary = {}, loadDictionary, runtimeTranslate, lifecycle: { onLocalesDictionaryCacheHit: onHit, onLocalesDictionaryCacheMiss: onMiss, onDictionaryCacheHit, onDictionaryCacheMiss, onDictionaryObjectCacheHit } }) {
|
|
5144
|
-
super({}, {
|
|
5145
|
-
onHit,
|
|
5146
|
-
onMiss
|
|
5147
|
-
});
|
|
5148
|
-
this.ttl = DEFAULT_CACHE_EXPIRY_TIME;
|
|
5149
|
-
this.ttl = ttl === null ? -1 : ttl ?? 6e4;
|
|
5150
|
-
this._dictionaryLoader = loadDictionary;
|
|
5151
|
-
this._runtimeTranslate = runtimeTranslate;
|
|
5152
|
-
this._onDictionaryCacheHit = onDictionaryCacheHit;
|
|
5153
|
-
this._onDictionaryCacheMiss = onDictionaryCacheMiss;
|
|
5154
|
-
this._onDictionaryObjectCacheHit = onDictionaryObjectCacheHit;
|
|
5155
|
-
this.setCache(defaultLocale, {
|
|
5156
|
-
dictionaryCache: new DictionaryCache({
|
|
5157
|
-
init: dictionary,
|
|
5158
|
-
runtimeTranslate: this._createDictionaryRuntimeTranslate(defaultLocale),
|
|
5159
|
-
lifecycle: this._createDictionaryCacheLifecycle(defaultLocale)
|
|
5160
|
-
}),
|
|
5161
|
-
expiresAt: -1
|
|
5162
|
-
});
|
|
5163
|
-
}
|
|
5164
|
-
/**
|
|
5165
|
-
* Get the dictionary for a given locale
|
|
5166
|
-
* @param key - The locale
|
|
5167
|
-
* @returns The dictionary
|
|
5168
|
-
*/
|
|
5169
|
-
get(key) {
|
|
5170
|
-
const entry = this.getCache(key);
|
|
5171
|
-
if (!entry || entry.expiresAt > 0 && entry.expiresAt < Date.now()) return;
|
|
5172
|
-
const value = entry.dictionaryCache;
|
|
5173
|
-
if (value != null && this.onHit) this.onHit({
|
|
5174
|
-
inputKey: key,
|
|
5175
|
-
cacheKey: this.genKey(key),
|
|
5176
|
-
cacheValue: entry,
|
|
5177
|
-
outputValue: value
|
|
5178
|
-
});
|
|
5179
|
-
return value;
|
|
5180
|
-
}
|
|
5181
|
-
/**
|
|
5182
|
-
* Miss the cache
|
|
5183
|
-
* @param key - The locale
|
|
5184
|
-
* @returns The dictionary cache
|
|
5185
|
-
*/
|
|
5186
|
-
async miss(key) {
|
|
5187
|
-
const cacheValue = await this.missCache(key);
|
|
5188
|
-
const value = cacheValue.dictionaryCache;
|
|
5189
|
-
if (value != null && this.onMiss) this.onMiss({
|
|
5190
|
-
inputKey: key,
|
|
5191
|
-
cacheKey: this.genKey(key),
|
|
5192
|
-
cacheValue,
|
|
5193
|
-
outputValue: value
|
|
5194
|
-
});
|
|
5195
|
-
return value;
|
|
5196
|
-
}
|
|
5197
|
-
/**
|
|
5198
|
-
* Generate the cache key for a given locale
|
|
5199
|
-
* @param key - The locale
|
|
5200
|
-
* @returns The cache key
|
|
5201
|
-
*
|
|
5202
|
-
* This is just an identity function, no transformation needed
|
|
5203
|
-
*/
|
|
5204
|
-
genKey(key) {
|
|
5205
|
-
return key;
|
|
5206
|
-
}
|
|
5207
|
-
/**
|
|
5208
|
-
* Fallback for a cache miss
|
|
5209
|
-
* @param locale - The locale
|
|
5210
|
-
* @returns The cache entry
|
|
5211
|
-
*/
|
|
5212
|
-
async fallback(locale) {
|
|
5213
|
-
return {
|
|
5214
|
-
dictionaryCache: new DictionaryCache({
|
|
5215
|
-
init: await this._dictionaryLoader(locale),
|
|
5216
|
-
runtimeTranslate: this._createDictionaryRuntimeTranslate(locale),
|
|
5217
|
-
lifecycle: this._createDictionaryCacheLifecycle(locale)
|
|
5218
|
-
}),
|
|
5219
|
-
expiresAt: this.ttl < 0 ? this.ttl : Date.now() + this.ttl
|
|
5220
|
-
};
|
|
5221
|
-
}
|
|
5222
|
-
/**
|
|
5223
|
-
* Create the dictionary cache lifecycle
|
|
5224
|
-
* @param locale - The locale
|
|
5225
|
-
* @returns The dictionary cache lifecycle
|
|
5226
|
-
*/
|
|
5227
|
-
_createDictionaryCacheLifecycle(locale) {
|
|
5228
|
-
return {
|
|
5229
|
-
onHit: this._onDictionaryCacheHit ? (params) => this._onDictionaryCacheHit({
|
|
5230
|
-
locale,
|
|
5231
|
-
...params
|
|
5232
|
-
}) : void 0,
|
|
5233
|
-
onMiss: this._onDictionaryCacheMiss ? (params) => this._onDictionaryCacheMiss({
|
|
5234
|
-
locale,
|
|
5235
|
-
...params
|
|
5236
|
-
}) : void 0,
|
|
5237
|
-
onHitObj: this._onDictionaryObjectCacheHit ? (params) => this._onDictionaryObjectCacheHit({
|
|
5238
|
-
locale,
|
|
5239
|
-
...params
|
|
5240
|
-
}) : void 0
|
|
5241
|
-
};
|
|
5242
|
-
}
|
|
5243
|
-
_createDictionaryRuntimeTranslate(locale) {
|
|
5244
|
-
return (key, sourceEntry) => this._runtimeTranslate(locale, key, sourceEntry);
|
|
5245
|
-
}
|
|
5246
|
-
};
|
|
5140
|
+
const LOCALES_CACHE_HIT_EVENT_NAME = "locales-cache-hit";
|
|
5247
5141
|
const LOCALES_CACHE_MISS_EVENT_NAME = "locales-cache-miss";
|
|
5142
|
+
const TRANSLATIONS_CACHE_HIT_EVENT_NAME = "translations-cache-hit";
|
|
5248
5143
|
const TRANSLATIONS_CACHE_MISS_EVENT_NAME = "translations-cache-miss";
|
|
5144
|
+
const LOCALES_DICTIONARY_CACHE_HIT_EVENT_NAME = "locales-dictionary-cache-hit";
|
|
5249
5145
|
const LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME = "locales-dictionary-cache-miss";
|
|
5146
|
+
const DICTIONARY_CACHE_HIT_EVENT_NAME = "dictionary-cache-hit";
|
|
5250
5147
|
const DICTIONARY_CACHE_MISS_EVENT_NAME = "dictionary-cache-miss";
|
|
5148
|
+
const DICTIONARY_OBJECT_CACHE_HIT_EVENT_NAME = "dictionary-object-cache-hit";
|
|
5251
5149
|
/**
|
|
5252
5150
|
* Maps consumer-facing lifecycle callbacks to internal locales cache lifecycle callbacks.
|
|
5253
5151
|
* The consumer API exposes simplified params (locale, hash, value) while the internal
|
|
@@ -5255,22 +5153,24 @@ const DICTIONARY_CACHE_MISS_EVENT_NAME = "dictionary-cache-miss";
|
|
|
5255
5153
|
*
|
|
5256
5154
|
* @deprecated - move to subscription api instead
|
|
5257
5155
|
*/
|
|
5258
|
-
function createLifecycleCallbacks(emit) {
|
|
5156
|
+
function createLifecycleCallbacks(emit, hasListeners = () => true) {
|
|
5259
5157
|
return {
|
|
5260
5158
|
onLocalesCacheHit: (params) => {
|
|
5261
|
-
|
|
5159
|
+
if (!hasListeners("locales-cache-hit")) return;
|
|
5160
|
+
emit(LOCALES_CACHE_HIT_EVENT_NAME, {
|
|
5262
5161
|
locale: params.inputKey,
|
|
5263
5162
|
translations: params.outputValue.getInternalCache()
|
|
5264
5163
|
});
|
|
5265
5164
|
},
|
|
5266
5165
|
onLocalesCacheMiss: (params) => {
|
|
5166
|
+
if (!hasListeners("locales-cache-miss")) return;
|
|
5267
5167
|
emit(LOCALES_CACHE_MISS_EVENT_NAME, {
|
|
5268
5168
|
locale: params.inputKey,
|
|
5269
5169
|
translations: params.outputValue.getInternalCache()
|
|
5270
5170
|
});
|
|
5271
5171
|
},
|
|
5272
5172
|
onTranslationsCacheHit: (params) => {
|
|
5273
|
-
emit(
|
|
5173
|
+
emit(TRANSLATIONS_CACHE_HIT_EVENT_NAME, {
|
|
5274
5174
|
locale: params.locale,
|
|
5275
5175
|
hash: params.cacheKey,
|
|
5276
5176
|
translation: params.outputValue
|
|
@@ -5284,19 +5184,21 @@ function createLifecycleCallbacks(emit) {
|
|
|
5284
5184
|
});
|
|
5285
5185
|
},
|
|
5286
5186
|
onLocalesDictionaryCacheHit: (params) => {
|
|
5287
|
-
|
|
5187
|
+
if (!hasListeners("locales-dictionary-cache-hit")) return;
|
|
5188
|
+
emit(LOCALES_DICTIONARY_CACHE_HIT_EVENT_NAME, {
|
|
5288
5189
|
locale: params.inputKey,
|
|
5289
5190
|
dictionary: params.outputValue.getInternalCache()
|
|
5290
5191
|
});
|
|
5291
5192
|
},
|
|
5292
5193
|
onLocalesDictionaryCacheMiss: (params) => {
|
|
5194
|
+
if (!hasListeners("locales-dictionary-cache-miss")) return;
|
|
5293
5195
|
emit(LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME, {
|
|
5294
5196
|
locale: params.inputKey,
|
|
5295
5197
|
dictionary: params.outputValue.getInternalCache()
|
|
5296
5198
|
});
|
|
5297
5199
|
},
|
|
5298
5200
|
onDictionaryCacheHit: (params) => {
|
|
5299
|
-
emit(
|
|
5201
|
+
emit(DICTIONARY_CACHE_HIT_EVENT_NAME, {
|
|
5300
5202
|
locale: params.locale,
|
|
5301
5203
|
id: params.cacheKey,
|
|
5302
5204
|
dictionaryEntry: params.outputValue
|
|
@@ -5310,7 +5212,7 @@ function createLifecycleCallbacks(emit) {
|
|
|
5310
5212
|
});
|
|
5311
5213
|
},
|
|
5312
5214
|
onDictionaryObjectCacheHit: (params) => {
|
|
5313
|
-
emit(
|
|
5215
|
+
emit(DICTIONARY_OBJECT_CACHE_HIT_EVENT_NAME, {
|
|
5314
5216
|
locale: params.locale,
|
|
5315
5217
|
id: params.cacheKey,
|
|
5316
5218
|
dictionaryValue: params.outputValue
|
|
@@ -5345,6 +5247,9 @@ var EventEmitter = class {
|
|
|
5345
5247
|
emit(eventName, event) {
|
|
5346
5248
|
this.listeners[eventName]?.forEach((subscriber) => subscriber(event));
|
|
5347
5249
|
}
|
|
5250
|
+
hasListeners(eventName) {
|
|
5251
|
+
return (this.listeners[eventName]?.size ?? 0) > 0;
|
|
5252
|
+
}
|
|
5348
5253
|
};
|
|
5349
5254
|
/**
|
|
5350
5255
|
* Subscribes to the lifecycle callbacks and emits the events to the event emitter
|
|
@@ -5354,7 +5259,7 @@ var EventEmitter = class {
|
|
|
5354
5259
|
* and is only used internally
|
|
5355
5260
|
*/
|
|
5356
5261
|
function subscribeLifecycleCallbacks({ onLocalesCacheHit, onLocalesCacheMiss, onTranslationsCacheHit, onTranslationsCacheMiss, onLocalesDictionaryCacheHit, onLocalesDictionaryCacheMiss, onDictionaryCacheHit, onDictionaryCacheMiss, onDictionaryObjectCacheHit }, subscribe) {
|
|
5357
|
-
if (onLocalesCacheHit) subscribe(
|
|
5262
|
+
if (onLocalesCacheHit) subscribe(LOCALES_CACHE_HIT_EVENT_NAME, (event) => {
|
|
5358
5263
|
onLocalesCacheHit({
|
|
5359
5264
|
...event,
|
|
5360
5265
|
value: event.translations
|
|
@@ -5366,7 +5271,7 @@ function subscribeLifecycleCallbacks({ onLocalesCacheHit, onLocalesCacheMiss, on
|
|
|
5366
5271
|
value: event.translations
|
|
5367
5272
|
});
|
|
5368
5273
|
});
|
|
5369
|
-
if (onTranslationsCacheHit) subscribe(
|
|
5274
|
+
if (onTranslationsCacheHit) subscribe(TRANSLATIONS_CACHE_HIT_EVENT_NAME, (event) => {
|
|
5370
5275
|
onTranslationsCacheHit({
|
|
5371
5276
|
...event,
|
|
5372
5277
|
value: event.translation
|
|
@@ -5378,19 +5283,19 @@ function subscribeLifecycleCallbacks({ onLocalesCacheHit, onLocalesCacheMiss, on
|
|
|
5378
5283
|
value: event.translation
|
|
5379
5284
|
});
|
|
5380
5285
|
});
|
|
5381
|
-
if (onLocalesDictionaryCacheHit) subscribe(
|
|
5286
|
+
if (onLocalesDictionaryCacheHit) subscribe(LOCALES_DICTIONARY_CACHE_HIT_EVENT_NAME, (event) => {
|
|
5382
5287
|
onLocalesDictionaryCacheHit(event);
|
|
5383
5288
|
});
|
|
5384
5289
|
if (onLocalesDictionaryCacheMiss) subscribe(LOCALES_DICTIONARY_CACHE_MISS_EVENT_NAME, (event) => {
|
|
5385
5290
|
onLocalesDictionaryCacheMiss(event);
|
|
5386
5291
|
});
|
|
5387
|
-
if (onDictionaryCacheHit) subscribe(
|
|
5292
|
+
if (onDictionaryCacheHit) subscribe(DICTIONARY_CACHE_HIT_EVENT_NAME, (event) => {
|
|
5388
5293
|
onDictionaryCacheHit(event);
|
|
5389
5294
|
});
|
|
5390
5295
|
if (onDictionaryCacheMiss) subscribe(DICTIONARY_CACHE_MISS_EVENT_NAME, (event) => {
|
|
5391
5296
|
onDictionaryCacheMiss(event);
|
|
5392
5297
|
});
|
|
5393
|
-
if (onDictionaryObjectCacheHit) subscribe(
|
|
5298
|
+
if (onDictionaryObjectCacheHit) subscribe(DICTIONARY_OBJECT_CACHE_HIT_EVENT_NAME, (event) => {
|
|
5394
5299
|
onDictionaryObjectCacheHit(event);
|
|
5395
5300
|
});
|
|
5396
5301
|
}
|
|
@@ -5421,26 +5326,32 @@ var I18nManager = class extends EventEmitter {
|
|
|
5421
5326
|
locales: this.config.locales,
|
|
5422
5327
|
customMapping: this.config.customMapping
|
|
5423
5328
|
});
|
|
5424
|
-
const loadTranslations =
|
|
5425
|
-
|
|
5329
|
+
const loadTranslations = routeCreateTranslationLoader({
|
|
5330
|
+
loadTranslations: params.loadTranslations,
|
|
5331
|
+
type: getLoadTranslationsType(params),
|
|
5332
|
+
remoteTranslationLoaderParams: {
|
|
5333
|
+
cacheUrl: params.cacheUrl,
|
|
5334
|
+
projectId: params.projectId,
|
|
5335
|
+
_versionId: params._versionId,
|
|
5336
|
+
_branchId: params._branchId,
|
|
5337
|
+
customMapping: params.customMapping
|
|
5338
|
+
}
|
|
5339
|
+
});
|
|
5340
|
+
const loadDictionary = params.loadDictionary ?? (() => Promise.resolve({}));
|
|
5426
5341
|
const runtimeTranslationTimeout = this.config.runtimeTranslation?.timeout ?? DEFAULT_TRANSLATION_TIMEOUT;
|
|
5427
5342
|
const runtimeTranslationMetadata = this.config.runtimeTranslation?.metadata ?? {};
|
|
5428
5343
|
const createTranslateMany = createTranslateManyFactory(this.getGTClassClean(), runtimeTranslationTimeout, runtimeTranslationMetadata);
|
|
5429
5344
|
subscribeLifecycleCallbacks(params.lifecycle ?? {}, (...args) => this.subscribe(...args));
|
|
5430
|
-
const lifecycle = createLifecycleCallbacks((...args) => this.emit(...args));
|
|
5345
|
+
const lifecycle = createLifecycleCallbacks((...args) => this.emit(...args), (eventName) => this.hasListeners(eventName));
|
|
5431
5346
|
this.localesCache = new LocalesCache({
|
|
5432
|
-
loadTranslations,
|
|
5433
|
-
createTranslateMany,
|
|
5434
|
-
lifecycle,
|
|
5435
|
-
ttl: this.config.cacheExpiryTime,
|
|
5436
|
-
batchConfig: this.config.batchConfig
|
|
5437
|
-
});
|
|
5438
|
-
this.localesDictionaryCache = new LocalesDictionaryCache({
|
|
5439
5347
|
defaultLocale: this.config.defaultLocale,
|
|
5440
5348
|
dictionary: params.dictionary,
|
|
5349
|
+
loadTranslations,
|
|
5441
5350
|
loadDictionary,
|
|
5442
|
-
|
|
5351
|
+
createTranslateMany,
|
|
5352
|
+
translateDictionaryEntry: (locale, id, sourceEntry) => this.translateDictionaryEntry(locale, id, sourceEntry),
|
|
5443
5353
|
ttl: this.config.cacheExpiryTime,
|
|
5354
|
+
batchConfig: this.config.batchConfig,
|
|
5444
5355
|
lifecycle
|
|
5445
5356
|
});
|
|
5446
5357
|
}
|
|
@@ -5512,9 +5423,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
5512
5423
|
try {
|
|
5513
5424
|
const translationLocale = this.resolveCacheLocale(locale);
|
|
5514
5425
|
if (!translationLocale) return {};
|
|
5515
|
-
|
|
5516
|
-
if (!txCache) txCache = await this.localesCache.miss(translationLocale);
|
|
5517
|
-
return txCache.getInternalCache();
|
|
5426
|
+
return (await this.localesCache.getOrLoadTranslations(translationLocale)).getInternalCache();
|
|
5518
5427
|
} catch (error) {
|
|
5519
5428
|
this.handleError(error);
|
|
5520
5429
|
return {};
|
|
@@ -5527,10 +5436,8 @@ var I18nManager = class extends EventEmitter {
|
|
|
5527
5436
|
async loadDictionary(locale) {
|
|
5528
5437
|
try {
|
|
5529
5438
|
const dictionaryLocale = this.resolveCacheLocale(locale);
|
|
5530
|
-
if (!dictionaryLocale) return this.
|
|
5531
|
-
|
|
5532
|
-
if (!dictionaryCache) dictionaryCache = await this.localesDictionaryCache.miss(dictionaryLocale);
|
|
5533
|
-
return dictionaryCache.getInternalCache();
|
|
5439
|
+
if (!dictionaryLocale) return this.getDefaultDictionaryCache()?.getInternalCache() ?? {};
|
|
5440
|
+
return (await this.localesCache.getOrLoadDictionary(dictionaryLocale)).getInternalCache();
|
|
5534
5441
|
} catch (error) {
|
|
5535
5442
|
this.handleError(error);
|
|
5536
5443
|
return {};
|
|
@@ -5541,8 +5448,8 @@ var I18nManager = class extends EventEmitter {
|
|
|
5541
5448
|
*/
|
|
5542
5449
|
lookupDictionary(locale, id) {
|
|
5543
5450
|
try {
|
|
5544
|
-
const dictionaryLocale = this.
|
|
5545
|
-
return this.
|
|
5451
|
+
const dictionaryLocale = this.resolveDictionaryCacheLocale(locale);
|
|
5452
|
+
return this.localesCache.getDictionary(dictionaryLocale)?.getEntry(id);
|
|
5546
5453
|
} catch (error) {
|
|
5547
5454
|
this.handleError(error);
|
|
5548
5455
|
return;
|
|
@@ -5553,8 +5460,8 @@ var I18nManager = class extends EventEmitter {
|
|
|
5553
5460
|
*/
|
|
5554
5461
|
lookupDictionaryObj(locale, id) {
|
|
5555
5462
|
try {
|
|
5556
|
-
const dictionaryLocale = this.
|
|
5557
|
-
return this.
|
|
5463
|
+
const dictionaryLocale = this.resolveDictionaryCacheLocale(locale);
|
|
5464
|
+
return this.localesCache.getDictionary(dictionaryLocale)?.getValue(id);
|
|
5558
5465
|
} catch (error) {
|
|
5559
5466
|
this.handleError(error);
|
|
5560
5467
|
return;
|
|
@@ -5567,19 +5474,10 @@ var I18nManager = class extends EventEmitter {
|
|
|
5567
5474
|
async lookupDictionaryWithFallback(locale, id) {
|
|
5568
5475
|
try {
|
|
5569
5476
|
const dictionaryLocale = this.resolveCacheLocale(locale);
|
|
5570
|
-
if (!dictionaryLocale)
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
}
|
|
5575
|
-
let dictionaryCache = this.localesDictionaryCache.get(dictionaryLocale);
|
|
5576
|
-
if (!dictionaryCache) dictionaryCache = await this.localesDictionaryCache.miss(dictionaryLocale);
|
|
5577
|
-
let dictionaryEntry = dictionaryCache.get(id);
|
|
5578
|
-
if (dictionaryEntry === void 0) {
|
|
5579
|
-
const sourceEntry = this.localesDictionaryCache.get(this.config.defaultLocale)?.get(id);
|
|
5580
|
-
if (sourceEntry === void 0) throw new DictionarySourceNotFoundError(id);
|
|
5581
|
-
dictionaryEntry = await dictionaryCache.miss(id, sourceEntry);
|
|
5582
|
-
}
|
|
5477
|
+
if (!dictionaryLocale) return this.getSourceDictionaryEntry(id);
|
|
5478
|
+
const dictionaryCache = await this.localesCache.getOrLoadDictionary(dictionaryLocale);
|
|
5479
|
+
let dictionaryEntry = dictionaryCache.getEntry(id);
|
|
5480
|
+
if (dictionaryEntry === void 0) dictionaryEntry = await dictionaryCache.materializeEntry(id, this.getSourceDictionaryEntry(id));
|
|
5583
5481
|
return dictionaryEntry;
|
|
5584
5482
|
} catch (error) {
|
|
5585
5483
|
this.handleError(error);
|
|
@@ -5593,25 +5491,41 @@ var I18nManager = class extends EventEmitter {
|
|
|
5593
5491
|
async lookupDictionaryObjWithFallback(locale, id) {
|
|
5594
5492
|
try {
|
|
5595
5493
|
const dictionaryLocale = this.resolveCacheLocale(locale);
|
|
5596
|
-
if (!dictionaryLocale)
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
let dictionaryObject = dictionaryCache.getObj(id);
|
|
5604
|
-
if (dictionaryObject === void 0) {
|
|
5605
|
-
const sourceObject = this.localesDictionaryCache.get(this.config.defaultLocale)?.getObj(id);
|
|
5606
|
-
if (sourceObject === void 0) throw new DictionarySourceNotFoundError(id);
|
|
5607
|
-
dictionaryObject = await dictionaryCache.missObj(id, sourceObject);
|
|
5494
|
+
if (!dictionaryLocale) return this.getSourceDictionaryObject(id);
|
|
5495
|
+
const dictionaryCache = await this.localesCache.getOrLoadDictionary(dictionaryLocale);
|
|
5496
|
+
const targetObject = dictionaryCache.getValue(id);
|
|
5497
|
+
const sourceObject = this.getSourceDictionaryObject(id, { throwOnMissing: false });
|
|
5498
|
+
if (sourceObject === void 0) {
|
|
5499
|
+
if (targetObject !== void 0) return targetObject;
|
|
5500
|
+
throw new DictionarySourceNotFoundError(id);
|
|
5608
5501
|
}
|
|
5609
|
-
return
|
|
5502
|
+
return await dictionaryCache.materializeValue(id, sourceObject, targetObject);
|
|
5610
5503
|
} catch (error) {
|
|
5611
5504
|
this.handleError(error);
|
|
5612
5505
|
return;
|
|
5613
5506
|
}
|
|
5614
5507
|
}
|
|
5508
|
+
async translateDictionaryEntry(locale, id, sourceEntry) {
|
|
5509
|
+
const translation = await this.lookupTranslationWithFallbackResolved(locale, sourceEntry.entry, resolveDictionaryLookupOptions(sourceEntry.options));
|
|
5510
|
+
if (typeof translation !== "string") throw new Error(`Dictionary entry "${id}" could not be translated into a string. Check the source entry and translation loader output.`);
|
|
5511
|
+
return translation;
|
|
5512
|
+
}
|
|
5513
|
+
getSourceDictionaryEntry(id) {
|
|
5514
|
+
const sourceEntry = this.getDefaultDictionaryCache()?.getEntry(id);
|
|
5515
|
+
if (sourceEntry === void 0) throw new DictionarySourceNotFoundError(id);
|
|
5516
|
+
return sourceEntry;
|
|
5517
|
+
}
|
|
5518
|
+
getSourceDictionaryObject(id, { throwOnMissing = true } = {}) {
|
|
5519
|
+
const sourceObject = this.getDefaultDictionaryCache()?.getValue(id);
|
|
5520
|
+
if (sourceObject === void 0 && throwOnMissing) throw new DictionarySourceNotFoundError(id);
|
|
5521
|
+
return sourceObject;
|
|
5522
|
+
}
|
|
5523
|
+
getDefaultDictionaryCache() {
|
|
5524
|
+
return this.localesCache.getDictionary(this.config.defaultLocale);
|
|
5525
|
+
}
|
|
5526
|
+
resolveDictionaryCacheLocale(locale) {
|
|
5527
|
+
return this.resolveCacheLocale(locale) ?? this.config.defaultLocale;
|
|
5528
|
+
}
|
|
5615
5529
|
/**
|
|
5616
5530
|
* Just lookup a translation
|
|
5617
5531
|
*/
|
|
@@ -5619,7 +5533,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
5619
5533
|
try {
|
|
5620
5534
|
const { translationLocale, options: lookupOptions } = this.resolveLookupParams(locale, options);
|
|
5621
5535
|
if (!translationLocale) return message;
|
|
5622
|
-
const txCache = this.localesCache.
|
|
5536
|
+
const txCache = this.localesCache.getTranslations(translationLocale);
|
|
5623
5537
|
if (!txCache) return void 0;
|
|
5624
5538
|
return txCache.get({
|
|
5625
5539
|
message,
|
|
@@ -5657,9 +5571,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
5657
5571
|
if (!translationLocale) return (message) => message;
|
|
5658
5572
|
const resolvedPrefetchEntries = resolvePrefetchEntriesByLocale(prefetchEntries, translationLocale, (entryLocale) => this.resolveCacheLocale(entryLocale) ?? this.resolveLocale(entryLocale));
|
|
5659
5573
|
if (resolvedPrefetchEntries.length !== prefetchEntries.length) logger_default.warn(`I18nManager: getLookupTranslation(): prefetchEntries must all be the same locale, ignoring all entries that are not for ${translationLocale}`);
|
|
5660
|
-
|
|
5661
|
-
if (!txCache) txCache = await this.localesCache.miss(translationLocale);
|
|
5662
|
-
if (!txCache) return () => void 0;
|
|
5574
|
+
const txCache = await this.localesCache.getOrLoadTranslations(translationLocale);
|
|
5663
5575
|
await Promise.all(resolvedPrefetchEntries.filter((entry) => txCache.get(entry) == null).map((entry) => txCache.miss(entry)));
|
|
5664
5576
|
return (message, options = {}) => {
|
|
5665
5577
|
return txCache.get({
|
|
@@ -5731,7 +5643,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
5731
5643
|
}
|
|
5732
5644
|
resolveLocale(locale) {
|
|
5733
5645
|
const resolvedLocale = this.localeConfig.determineLocale(locale);
|
|
5734
|
-
if (!this.localeConfig.isValidLocale(locale) || !resolvedLocale) throw new Error(`
|
|
5646
|
+
if (!this.localeConfig.isValidLocale(locale) || !resolvedLocale) throw new Error(`Locale "${locale}" is not valid. Use a valid BCP 47 locale code or add a custom mapping.`);
|
|
5735
5647
|
return resolvedLocale;
|
|
5736
5648
|
}
|
|
5737
5649
|
/**
|
|
@@ -5761,8 +5673,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
5761
5673
|
async lookupTranslationWithFallbackResolved(locale, message, options) {
|
|
5762
5674
|
const { translationLocale, options: lookupOptions } = this.resolveLookupParams(locale, options);
|
|
5763
5675
|
if (!translationLocale) return message;
|
|
5764
|
-
|
|
5765
|
-
if (!txCache) txCache = await this.localesCache.miss(translationLocale);
|
|
5676
|
+
const txCache = await this.localesCache.getOrLoadTranslations(translationLocale);
|
|
5766
5677
|
let translation = txCache.get({
|
|
5767
5678
|
message,
|
|
5768
5679
|
options: lookupOptions
|
|
@@ -5774,14 +5685,6 @@ var I18nManager = class extends EventEmitter {
|
|
|
5774
5685
|
return translation;
|
|
5775
5686
|
}
|
|
5776
5687
|
/**
|
|
5777
|
-
* Runtime lookup function for dictionaries
|
|
5778
|
-
*/
|
|
5779
|
-
async dictionaryRuntimeTranslate(locale, id, sourceEntry) {
|
|
5780
|
-
const translation = await this.lookupTranslationWithFallbackResolved(locale, sourceEntry.entry, resolveDictionaryLookupOptions(sourceEntry.options));
|
|
5781
|
-
if (typeof translation !== "string") throw new Error(`I18nManager: dictionaryRuntimeTranslate(): unable to translate dictionary entry ${id}`);
|
|
5782
|
-
return translation;
|
|
5783
|
-
}
|
|
5784
|
-
/**
|
|
5785
5688
|
* A helper function to create a gt class that is locale agnostic
|
|
5786
5689
|
* This is helpful for when our getLocale function is bound to a
|
|
5787
5690
|
* specific context
|
|
@@ -5878,28 +5781,6 @@ function resolvePrefetchEntriesByLocale(prefetchEntries, locale, resolveLocale)
|
|
|
5878
5781
|
}
|
|
5879
5782
|
});
|
|
5880
5783
|
}
|
|
5881
|
-
/**
|
|
5882
|
-
* Helper function for creating a translation loader
|
|
5883
|
-
*/
|
|
5884
|
-
function createTranslationLoader(params) {
|
|
5885
|
-
return routeCreateTranslationLoader({
|
|
5886
|
-
loadTranslations: params.loadTranslations,
|
|
5887
|
-
type: getLoadTranslationsType(params),
|
|
5888
|
-
remoteTranslationLoaderParams: {
|
|
5889
|
-
cacheUrl: params.cacheUrl,
|
|
5890
|
-
projectId: params.projectId,
|
|
5891
|
-
_versionId: params._versionId,
|
|
5892
|
-
_branchId: params._branchId,
|
|
5893
|
-
customMapping: params.customMapping
|
|
5894
|
-
}
|
|
5895
|
-
});
|
|
5896
|
-
}
|
|
5897
|
-
/**
|
|
5898
|
-
* Helper function for creating a dictionary loader
|
|
5899
|
-
*/
|
|
5900
|
-
function createDictionaryLoader(params) {
|
|
5901
|
-
return params.loadDictionary ?? (() => Promise.resolve({}));
|
|
5902
|
-
}
|
|
5903
5784
|
let i18nManager = void 0;
|
|
5904
5785
|
let fallbackDefaultLocale = "en";
|
|
5905
5786
|
let conditionStore = { getLocale: () => fallbackDefaultLocale };
|
|
@@ -5910,7 +5791,7 @@ let conditionStore = { getLocale: () => fallbackDefaultLocale };
|
|
|
5910
5791
|
*/
|
|
5911
5792
|
function getI18nManager() {
|
|
5912
5793
|
if (!i18nManager) {
|
|
5913
|
-
logger_default.warn("getI18nManager():
|
|
5794
|
+
logger_default.warn("getI18nManager(): I18nManager was not initialized. Falling back to the default locale until initializeGT() configures translations.");
|
|
5914
5795
|
i18nManager = new I18nManager({
|
|
5915
5796
|
defaultLocale: "en",
|
|
5916
5797
|
locales: ["en"]
|
|
@@ -6042,10 +5923,30 @@ function resolveTranslationSyncWithFallback(locale, message, options = {}) {
|
|
|
6042
5923
|
//#endregion
|
|
6043
5924
|
//#region src/shared/messages.ts
|
|
6044
5925
|
const PACKAGE_NAME = "gt-react";
|
|
6045
|
-
|
|
6046
|
-
`${PACKAGE_NAME}
|
|
6047
|
-
|
|
6048
|
-
|
|
5926
|
+
createDiagnosticMessage({
|
|
5927
|
+
source: `${PACKAGE_NAME}/browser`,
|
|
5928
|
+
severity: "Error",
|
|
5929
|
+
whatHappened: "This module requires a browser environment",
|
|
5930
|
+
fix: "Import it only from client-side code"
|
|
5931
|
+
});
|
|
5932
|
+
createDiagnosticMessage({
|
|
5933
|
+
source: PACKAGE_NAME,
|
|
5934
|
+
severity: "Error",
|
|
5935
|
+
whatHappened: "A browser-only module was imported outside the browser",
|
|
5936
|
+
fix: "Move this import to client-side code"
|
|
5937
|
+
});
|
|
5938
|
+
createDiagnosticMessage({
|
|
5939
|
+
source: PACKAGE_NAME,
|
|
5940
|
+
severity: "Error",
|
|
5941
|
+
whatHappened: "BrowserI18nManager is not initialized",
|
|
5942
|
+
fix: "Call initializeGT() before using browser translation APIs"
|
|
5943
|
+
});
|
|
5944
|
+
const createTranslationFailedDueToBrowserEnvironmentWarning = (message) => createDiagnosticMessage({
|
|
5945
|
+
source: PACKAGE_NAME,
|
|
5946
|
+
severity: "Warning",
|
|
5947
|
+
whatHappened: `t("${typeof message === "string" ? message : "`" + message?.join("${}") + "`"}") could not be translated because it ran outside the browser`,
|
|
5948
|
+
wayOut: "The original message will render as a fallback"
|
|
5949
|
+
});
|
|
6049
5950
|
//#endregion
|
|
6050
5951
|
//#region src/i18n-context/functions/translation/t.ts
|
|
6051
5952
|
/**
|
|
@@ -6091,7 +5992,7 @@ const t = (messageOrStrings, ...values) => {
|
|
|
6091
5992
|
*/
|
|
6092
5993
|
function handleTaggedTemplateLiteralTranslation(messageOrStrings, values) {
|
|
6093
5994
|
const locale = getLocale();
|
|
6094
|
-
const translatedInterpolatedTemplate = resolveTranslationSync(locale,
|
|
5995
|
+
const translatedInterpolatedTemplate = resolveTranslationSync(locale, messageOrStrings.map((string, index) => string + (values[index] ?? "")).join(""));
|
|
6095
5996
|
if (translatedInterpolatedTemplate) return translatedInterpolatedTemplate;
|
|
6096
5997
|
const { message, variables } = extractInterpolatableValues(messageOrStrings, values);
|
|
6097
5998
|
return resolveTranslationSyncWithFallback(locale, message, variables);
|
|
@@ -6120,17 +6021,6 @@ function extractInterpolatableValues(strings, values) {
|
|
|
6120
6021
|
variables
|
|
6121
6022
|
};
|
|
6122
6023
|
}
|
|
6123
|
-
/**
|
|
6124
|
-
* Interpolate a template literal
|
|
6125
|
-
* @param message - The message to interpolate.
|
|
6126
|
-
* @param variables - The variables to interpolate.
|
|
6127
|
-
* @returns The interpolated message.
|
|
6128
|
-
*/
|
|
6129
|
-
function interpolateTemplateLiteral(strings, values) {
|
|
6130
|
-
return strings.map((string, index) => {
|
|
6131
|
-
return string + (values[index] ?? "");
|
|
6132
|
-
}).join("");
|
|
6133
|
-
}
|
|
6134
6024
|
//#endregion
|
|
6135
6025
|
//#region src/macros.ts
|
|
6136
6026
|
globalThis.t = t;
|