gt-i18n 0.8.6 → 0.8.8
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 +18 -0
- package/dist/fallbacks.cjs +1 -1
- package/dist/fallbacks.mjs +1 -1
- package/dist/{helpers-DUaQNdel.cjs → helpers-D0T1EpJa.cjs} +77 -53
- package/dist/helpers-D0T1EpJa.cjs.map +1 -0
- package/dist/{helpers-ld2LqFID.mjs → helpers-DB3t35tn.mjs} +71 -47
- package/dist/helpers-DB3t35tn.mjs.map +1 -0
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/internal-types.d.cts +1 -1
- package/dist/internal-types.d.mts +1 -1
- package/dist/internal.cjs +2 -2
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +11 -8
- package/dist/internal.d.mts +11 -8
- package/dist/internal.mjs +2 -2
- package/dist/internal.mjs.map +1 -1
- package/dist/{isEncodedTranslationOptions-B33AZBqH.cjs → isEncodedTranslationOptions-D7ltjc4f.cjs} +5 -5
- package/dist/isEncodedTranslationOptions-D7ltjc4f.cjs.map +1 -0
- package/dist/{isEncodedTranslationOptions-CIuvDwly.mjs → isEncodedTranslationOptions-DdHEzDDM.mjs} +2 -2
- package/dist/isEncodedTranslationOptions-DdHEzDDM.mjs.map +1 -0
- package/dist/{mFallback-CHAfezd9.mjs → mFallback-BQX_yiE-.mjs} +2 -2
- package/dist/{mFallback-CHAfezd9.mjs.map → mFallback-BQX_yiE-.mjs.map} +1 -1
- package/dist/{mFallback-4Qb8OeCB.cjs → mFallback-CoPRtKyL.cjs} +2 -2
- package/dist/{mFallback-4Qb8OeCB.cjs.map → mFallback-CoPRtKyL.cjs.map} +1 -1
- package/dist/{types-CI5axgXi.d.cts → types-J_6OXeaq.d.cts} +1 -2
- package/dist/{types-KGn4sCHt.d.mts → types-tZ12Fev6.d.mts} +1 -2
- package/package.json +3 -3
- package/dist/helpers-DUaQNdel.cjs.map +0 -1
- package/dist/helpers-ld2LqFID.mjs.map +0 -1
- package/dist/isEncodedTranslationOptions-B33AZBqH.cjs.map +0 -1
- package/dist/isEncodedTranslationOptions-CIuvDwly.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# gt-i18n
|
|
2
2
|
|
|
3
|
+
## 0.8.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1278](https://github.com/generaltranslation/gt/pull/1278) [`ce0933a`](https://github.com/generaltranslation/gt/commit/ce0933ab102d34a0c38634f7c2b0d634c9a620a8) Thanks [@bgub](https://github.com/bgub)! - Add a `generaltranslation/core` entrypoint for locale and formatting helpers, and update `gt-i18n` to consume it where possible.
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`ce0933a`](https://github.com/generaltranslation/gt/commit/ce0933ab102d34a0c38634f7c2b0d634c9a620a8)]:
|
|
10
|
+
- generaltranslation@8.2.9
|
|
11
|
+
- @generaltranslation/supported-locales@2.0.67
|
|
12
|
+
|
|
13
|
+
## 0.8.7
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [[`b12d57d`](https://github.com/generaltranslation/gt/commit/b12d57dab1d5cb1f602c5ac24a702b48cda7f11e)]:
|
|
18
|
+
- generaltranslation@8.2.8
|
|
19
|
+
- @generaltranslation/supported-locales@2.0.66
|
|
20
|
+
|
|
3
21
|
## 0.8.6
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/fallbacks.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_mFallback = require("./mFallback-
|
|
2
|
+
const require_mFallback = require("./mFallback-CoPRtKyL.cjs");
|
|
3
3
|
exports.gtFallback = require_mFallback.gtFallback;
|
|
4
4
|
exports.mFallback = require_mFallback.mFallback;
|
package/dist/fallbacks.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as gtFallback, t as mFallback } from "./mFallback-
|
|
1
|
+
import { n as gtFallback, t as mFallback } from "./mFallback-BQX_yiE-.mjs";
|
|
2
2
|
export { gtFallback, mFallback };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
const require_isEncodedTranslationOptions = require("./isEncodedTranslationOptions-
|
|
1
|
+
const require_isEncodedTranslationOptions = require("./isEncodedTranslationOptions-D7ltjc4f.cjs");
|
|
2
2
|
let generaltranslation_internal = require("generaltranslation/internal");
|
|
3
|
+
let generaltranslation_core = require("generaltranslation/core");
|
|
3
4
|
let generaltranslation = require("generaltranslation");
|
|
4
5
|
let generaltranslation_id = require("generaltranslation/id");
|
|
5
6
|
//#region src/i18n-manager/validation/publishValidationResults.ts
|
|
@@ -155,7 +156,7 @@ function validateLocales(params) {
|
|
|
155
156
|
if (!getGTServicesEnabled(params)) return results;
|
|
156
157
|
const { defaultLocale, locales, customMapping } = params;
|
|
157
158
|
new Set([...defaultLocale ? [defaultLocale] : [], ...locales || []]).forEach((locale) => {
|
|
158
|
-
if (!(0,
|
|
159
|
+
if (!(0, generaltranslation_core.isValidLocale)(locale, customMapping)) results.push({
|
|
159
160
|
type: "error",
|
|
160
161
|
message: `Invalid locale: ${locale}`
|
|
161
162
|
});
|
|
@@ -212,11 +213,7 @@ var FallbackStorageAdapter = class extends StorageAdapter {
|
|
|
212
213
|
* @returns The translate many function
|
|
213
214
|
*/
|
|
214
215
|
function createTranslateManyFactory(gtInstance, timeout) {
|
|
215
|
-
return (locale) => {
|
|
216
|
-
return (sources) => {
|
|
217
|
-
return gtInstance.translateMany(sources, { targetLocale: locale }, timeout);
|
|
218
|
-
};
|
|
219
|
-
};
|
|
216
|
+
return (locale) => (sources) => gtInstance.translateMany(sources, { targetLocale: locale }, timeout);
|
|
220
217
|
}
|
|
221
218
|
//#endregion
|
|
222
219
|
//#region src/i18n-manager/translations-manager/translations-loaders/createRemoteTranslationLoader.ts
|
|
@@ -230,7 +227,7 @@ function createTranslateManyFactory(gtInstance, timeout) {
|
|
|
230
227
|
function createRemoteTranslationLoader(params) {
|
|
231
228
|
const unlocalizedUrl = generateUrl(params);
|
|
232
229
|
const loader = async (locale) => {
|
|
233
|
-
locale = (0,
|
|
230
|
+
locale = (0, generaltranslation_core.resolveCanonicalLocale)(locale, params.customMapping);
|
|
234
231
|
const url = unlocalizedUrl.replace("[locale]", locale);
|
|
235
232
|
const response = await fetch(url);
|
|
236
233
|
if (!response.ok) throw new Error(`Failed to load translations from ${url}`);
|
|
@@ -774,11 +771,16 @@ var I18nManager = class extends EventEmitter {
|
|
|
774
771
|
*/
|
|
775
772
|
constructor(params) {
|
|
776
773
|
super();
|
|
777
|
-
this.resolveTranslationSync = (message, options) => {
|
|
774
|
+
this.resolveTranslationSync = (message, options = {}) => {
|
|
778
775
|
return this.lookupTranslation(message, options);
|
|
779
776
|
};
|
|
780
777
|
publishValidationResults(validateConfig(params), "I18nManager: ");
|
|
781
778
|
this.config = standardizeConfig(params);
|
|
779
|
+
this.localeConfig = new generaltranslation_core.LocaleConfig({
|
|
780
|
+
defaultLocale: this.config.defaultLocale,
|
|
781
|
+
locales: this.config.locales,
|
|
782
|
+
customMapping: this.config.customMapping
|
|
783
|
+
});
|
|
782
784
|
this.storeAdapter = params.storeAdapter ?? new FallbackStorageAdapter();
|
|
783
785
|
const loadTranslations = createTranslationLoader(params);
|
|
784
786
|
const createTranslateMany = createTranslateManyFactory(this.getGTClassClean(), DEFAULT_TRANSLATION_TIMEOUT);
|
|
@@ -826,8 +828,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
826
828
|
*/
|
|
827
829
|
setLocale(locale) {
|
|
828
830
|
try {
|
|
829
|
-
this.
|
|
830
|
-
const newLocale = this.getGTClassClean().determineLocale(locale);
|
|
831
|
+
const newLocale = this.resolveLocale(locale);
|
|
831
832
|
const previousLocale = this.getLocale();
|
|
832
833
|
this.storeAdapter.setItem("locale", newLocale);
|
|
833
834
|
this.emit("locale-update", {
|
|
@@ -882,10 +883,10 @@ var I18nManager = class extends EventEmitter {
|
|
|
882
883
|
*/
|
|
883
884
|
async loadTranslations(locale = this.getLocale()) {
|
|
884
885
|
try {
|
|
885
|
-
this.
|
|
886
|
-
if (!this.requiresTranslation(
|
|
887
|
-
let txCache = this.localesCache.get(
|
|
888
|
-
if (!txCache) txCache = await this.localesCache.miss(
|
|
886
|
+
const resolvedLocale = this.resolveLocale(locale);
|
|
887
|
+
if (!this.requiresTranslation(resolvedLocale)) return {};
|
|
888
|
+
let txCache = this.localesCache.get(resolvedLocale);
|
|
889
|
+
if (!txCache) txCache = await this.localesCache.miss(resolvedLocale);
|
|
889
890
|
return txCache.getInternalCache();
|
|
890
891
|
} catch (error) {
|
|
891
892
|
this.handleError(error);
|
|
@@ -895,16 +896,15 @@ var I18nManager = class extends EventEmitter {
|
|
|
895
896
|
/**
|
|
896
897
|
* Just lookup a translation
|
|
897
898
|
*/
|
|
898
|
-
lookupTranslation(message, options) {
|
|
899
|
+
lookupTranslation(message, options = {}) {
|
|
899
900
|
try {
|
|
900
|
-
const locale
|
|
901
|
-
this.validateLocale(locale);
|
|
901
|
+
const { locale, options: lookupOptions } = this.resolveLookupParams(options);
|
|
902
902
|
if (!this.requiresTranslation(locale)) return message;
|
|
903
903
|
const txCache = this.localesCache.get(locale);
|
|
904
904
|
if (!txCache) return void 0;
|
|
905
905
|
return txCache.get({
|
|
906
906
|
message,
|
|
907
|
-
options
|
|
907
|
+
options: lookupOptions
|
|
908
908
|
});
|
|
909
909
|
} catch (error) {
|
|
910
910
|
this.handleError(error);
|
|
@@ -915,20 +915,19 @@ var I18nManager = class extends EventEmitter {
|
|
|
915
915
|
* Look up a translation
|
|
916
916
|
* If it's not found, use the fallback (runtime translate)
|
|
917
917
|
*/
|
|
918
|
-
async lookupTranslationWithFallback(message, options) {
|
|
918
|
+
async lookupTranslationWithFallback(message, options = {}) {
|
|
919
919
|
try {
|
|
920
|
-
const locale
|
|
921
|
-
this.validateLocale(locale);
|
|
920
|
+
const { locale, options: lookupOptions } = this.resolveLookupParams(options);
|
|
922
921
|
if (!this.requiresTranslation(locale)) return message;
|
|
923
922
|
let txCache = this.localesCache.get(locale);
|
|
924
923
|
if (!txCache) txCache = await this.localesCache.miss(locale);
|
|
925
924
|
let translation = txCache.get({
|
|
926
925
|
message,
|
|
927
|
-
options
|
|
926
|
+
options: lookupOptions
|
|
928
927
|
});
|
|
929
928
|
if (translation == null) translation = await txCache.miss({
|
|
930
929
|
message,
|
|
931
|
-
options
|
|
930
|
+
options: lookupOptions
|
|
932
931
|
});
|
|
933
932
|
return translation;
|
|
934
933
|
} catch (error) {
|
|
@@ -947,18 +946,18 @@ var I18nManager = class extends EventEmitter {
|
|
|
947
946
|
*/
|
|
948
947
|
async getLookupTranslation(locale = this.getLocale(), prefetchEntries = []) {
|
|
949
948
|
try {
|
|
950
|
-
this.
|
|
951
|
-
if (!this.requiresTranslation(
|
|
952
|
-
const
|
|
953
|
-
if (
|
|
954
|
-
let txCache = this.localesCache.get(
|
|
955
|
-
if (!txCache) txCache = await this.localesCache.miss(
|
|
949
|
+
const resolvedLocale = this.resolveLocale(locale);
|
|
950
|
+
if (!this.requiresTranslation(resolvedLocale)) return (message) => message;
|
|
951
|
+
const resolvedPrefetchEntries = resolvePrefetchEntriesByLocale(prefetchEntries, resolvedLocale, (entryLocale) => this.resolveLocale(entryLocale));
|
|
952
|
+
if (resolvedPrefetchEntries.length !== prefetchEntries.length) require_isEncodedTranslationOptions.logger_default.warn(`I18nManager: getLookupTranslation(): prefetchEntries must all be the same locale, ignoring all entries that are not for ${resolvedLocale}`);
|
|
953
|
+
let txCache = this.localesCache.get(resolvedLocale);
|
|
954
|
+
if (!txCache) txCache = await this.localesCache.miss(resolvedLocale);
|
|
956
955
|
if (!txCache) return () => void 0;
|
|
957
|
-
await Promise.all(
|
|
958
|
-
return (message, options) => {
|
|
956
|
+
await Promise.all(resolvedPrefetchEntries.filter((entry) => txCache.get(entry) == null).map((entry) => txCache.miss(entry)));
|
|
957
|
+
return (message, options = {}) => {
|
|
959
958
|
return txCache.get({
|
|
960
959
|
message,
|
|
961
|
-
options
|
|
960
|
+
options: this.resolveLookupOptions(options)
|
|
962
961
|
});
|
|
963
962
|
};
|
|
964
963
|
} catch (error) {
|
|
@@ -972,7 +971,6 @@ var I18nManager = class extends EventEmitter {
|
|
|
972
971
|
*/
|
|
973
972
|
async getTranslations(locale = this.getLocale()) {
|
|
974
973
|
try {
|
|
975
|
-
this.validateLocale(locale);
|
|
976
974
|
return this.loadTranslations(locale);
|
|
977
975
|
} catch (error) {
|
|
978
976
|
this.handleError(error);
|
|
@@ -999,9 +997,8 @@ var I18nManager = class extends EventEmitter {
|
|
|
999
997
|
*/
|
|
1000
998
|
requiresTranslation(locale = this.getLocale()) {
|
|
1001
999
|
const defaultLocale = this.getDefaultLocale();
|
|
1002
|
-
const gtInstance = this.getGTClass();
|
|
1003
1000
|
const locales = this.getLocales();
|
|
1004
|
-
return this.isTranslationEnabled() &&
|
|
1001
|
+
return this.isTranslationEnabled() && this.localeConfig.requiresTranslation(locale, defaultLocale, locales);
|
|
1005
1002
|
}
|
|
1006
1003
|
/**
|
|
1007
1004
|
* Returns true if dialect translation is required
|
|
@@ -1010,8 +1007,7 @@ var I18nManager = class extends EventEmitter {
|
|
|
1010
1007
|
*/
|
|
1011
1008
|
requiresDialectTranslation(locale = this.getLocale()) {
|
|
1012
1009
|
const defaultLocale = this.getDefaultLocale();
|
|
1013
|
-
|
|
1014
|
-
return this.requiresTranslation(locale) && gt.isSameLanguage(defaultLocale, locale);
|
|
1010
|
+
return this.requiresTranslation(locale) && this.localeConfig.isSameLanguage(defaultLocale, locale);
|
|
1015
1011
|
}
|
|
1016
1012
|
/**
|
|
1017
1013
|
* Handle errors
|
|
@@ -1025,12 +1021,24 @@ var I18nManager = class extends EventEmitter {
|
|
|
1025
1021
|
break;
|
|
1026
1022
|
}
|
|
1027
1023
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1024
|
+
resolveLocale(locale) {
|
|
1025
|
+
const resolvedLocale = this.localeConfig.determineLocale(locale);
|
|
1026
|
+
if (!this.localeConfig.isValidLocale(locale) || !resolvedLocale) throw new Error(`I18nManager: validateLocale(): locale ${locale} is not valid`);
|
|
1027
|
+
return resolvedLocale;
|
|
1028
|
+
}
|
|
1029
|
+
resolveLookupParams(options = {}) {
|
|
1030
|
+
const locale = this.resolveLocale(options.$locale ?? this.getLocale());
|
|
1031
|
+
return {
|
|
1032
|
+
locale,
|
|
1033
|
+
options: this.resolveLookupOptions(options, locale)
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
resolveLookupOptions(options = {}, resolvedLocale) {
|
|
1037
|
+
if (!options.$locale) return options;
|
|
1038
|
+
return {
|
|
1039
|
+
...options,
|
|
1040
|
+
$locale: resolvedLocale ?? this.resolveLocale(options.$locale)
|
|
1041
|
+
};
|
|
1034
1042
|
}
|
|
1035
1043
|
/**
|
|
1036
1044
|
* A helper function to create a gt class that is locale agnostic
|
|
@@ -1089,26 +1097,42 @@ function dedupeLocales({ defaultLocale, locales, customMapping }) {
|
|
|
1089
1097
|
*/
|
|
1090
1098
|
function standardizeLocales(config) {
|
|
1091
1099
|
return {
|
|
1092
|
-
defaultLocale: (0,
|
|
1100
|
+
defaultLocale: (0, generaltranslation_core.standardizeLocale)(config.defaultLocale),
|
|
1093
1101
|
locales: config.locales.map((locale) => {
|
|
1094
1102
|
if (typeof config.customMapping?.[locale] === "string" ? config.customMapping?.[locale] : config.customMapping?.[locale]?.code) return locale;
|
|
1095
|
-
else return (0,
|
|
1103
|
+
else return (0, generaltranslation_core.standardizeLocale)(locale);
|
|
1096
1104
|
}),
|
|
1097
|
-
customMapping: Object.fromEntries(Object.entries(config.customMapping || {}).map(([key, value]) => [key, typeof value === "string" ? (0,
|
|
1105
|
+
customMapping: Object.fromEntries(Object.entries(config.customMapping || {}).map(([key, value]) => [key, typeof value === "string" ? (0, generaltranslation_core.standardizeLocale)(value) : {
|
|
1098
1106
|
...value,
|
|
1099
|
-
...value.code ? { code: (0,
|
|
1107
|
+
...value.code ? { code: (0, generaltranslation_core.standardizeLocale)(value.code) } : {}
|
|
1100
1108
|
}]))
|
|
1101
1109
|
};
|
|
1102
1110
|
}
|
|
1103
1111
|
/**
|
|
1104
|
-
*
|
|
1112
|
+
* Resolve prefetch entry locales and keep entries matching the active locale.
|
|
1105
1113
|
* @template TranslationType - The type of the translation
|
|
1106
1114
|
* @param {PrefetchEntry<TranslationType>[]} prefetchEntries - The prefetch entries to filter
|
|
1107
1115
|
* @param {string} locale - The locale to filter by
|
|
1108
1116
|
* @returns {PrefetchEntry<TranslationType>[]} The filtered prefetch entries
|
|
1109
1117
|
*/
|
|
1110
|
-
function
|
|
1111
|
-
return prefetchEntries.
|
|
1118
|
+
function resolvePrefetchEntriesByLocale(prefetchEntries, locale, resolveLocale) {
|
|
1119
|
+
return prefetchEntries.flatMap((entry) => {
|
|
1120
|
+
const entryLocale = entry.options.$locale;
|
|
1121
|
+
if (entryLocale == null) return [entry];
|
|
1122
|
+
try {
|
|
1123
|
+
const resolvedLocale = resolveLocale(entryLocale);
|
|
1124
|
+
if (resolvedLocale !== locale) return [];
|
|
1125
|
+
return [{
|
|
1126
|
+
message: entry.message,
|
|
1127
|
+
options: {
|
|
1128
|
+
...entry.options,
|
|
1129
|
+
$locale: resolvedLocale
|
|
1130
|
+
}
|
|
1131
|
+
}];
|
|
1132
|
+
} catch {
|
|
1133
|
+
return [];
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1112
1136
|
}
|
|
1113
1137
|
/**
|
|
1114
1138
|
* Helper function for creating a translation loader
|
|
@@ -1160,7 +1184,7 @@ function setI18nManager(i18nManagerInstance) {
|
|
|
1160
1184
|
* String interpolation function
|
|
1161
1185
|
*/
|
|
1162
1186
|
function interpolateStringMessage(encodedMsg, options) {
|
|
1163
|
-
return (0,
|
|
1187
|
+
return (0, generaltranslation_core.formatCutoff)(encodedMsg, {
|
|
1164
1188
|
locales: options.$locale ?? options.$_locales,
|
|
1165
1189
|
maxChars: options.$maxChars
|
|
1166
1190
|
});
|
|
@@ -1344,4 +1368,4 @@ Object.defineProperty(exports, "setI18nManager", {
|
|
|
1344
1368
|
}
|
|
1345
1369
|
});
|
|
1346
1370
|
|
|
1347
|
-
//# sourceMappingURL=helpers-
|
|
1371
|
+
//# sourceMappingURL=helpers-D0T1EpJa.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers-D0T1EpJa.cjs","names":["defaultCacheUrl","defaultRuntimeApiUrl","defaultCacheUrl","LocaleConfig","GT","libraryDefaultLocale","libraryDefaultLocale","interpolateIcuMessage"],"sources":["../src/i18n-manager/validation/publishValidationResults.ts","../src/i18n-manager/utils/getLoadTranslationsType.ts","../src/i18n-manager/validation/config-validation/validateLoadTranslations.ts","../src/i18n-manager/utils/getTranslationApiType.ts","../src/i18n-manager/validation/config-validation/validateTranslationApi.ts","../src/i18n-manager/utils/getGTServicesEnabled.ts","../src/i18n-manager/validation/config-validation/validateLocales.ts","../src/i18n-manager/validation/validateConfig.ts","../src/i18n-manager/storage-adapter/StorageAdapter.ts","../src/i18n-manager/storage-adapter/FallbackStorageAdapter.ts","../src/i18n-manager/translations-manager/utils/createTranslateMany.ts","../src/i18n-manager/translations-manager/translations-loaders/createRemoteTranslationLoader.ts","../src/i18n-manager/translations-manager/translations-loaders/createFallbackTranslationLoader.ts","../src/i18n-manager/translations-manager/translations-loaders/routeCreateTranslationLoader.ts","../src/i18n-manager/translations-manager/Cache.ts","../src/utils/hashMessage.ts","../src/i18n-manager/translations-manager/TranslationsCache.ts","../src/i18n-manager/translations-manager/utils/constants.ts","../src/i18n-manager/translations-manager/LocalesCache.ts","../src/i18n-manager/lifecycle-hooks/createLifecycleCallbacks.ts","../src/i18n-manager/event-subscription/EventEmitter.ts","../src/i18n-manager/lifecycle-hooks/subscribeLifecycleCallbacks.ts","../src/i18n-manager/I18nManager.ts","../src/i18n-manager/singleton-operations.ts","../src/translation-functions/utils/interpolation/interpolateStringMessage.ts","../src/translation-functions/utils/interpolation/interpolateMessage.ts","../src/translation-functions/internal/helpers.ts"],"sourcesContent":["import { ValidationResult } from './types';\nimport logger from '../../logs/logger';\n\n/**\n * Throw errors if there are any errors and log warnings if there are any warnings\n * @param {ValidationResult[]} results - The results to print\n * @param {string} [prefix] - The prefix to add to the results\n * @param {boolean} [throwOnError] - Whether to throw an error if there are any errors\n *\n * TODO: dedupe messages\n * TODO: logging system\n */\nexport function publishValidationResults(\n results: ValidationResult[],\n prefix: string = '',\n throwOnError: boolean = true\n): void {\n // Log the results\n results.forEach((result) => {\n switch (result.type) {\n case 'error':\n logger.error(prefix + result.message);\n break;\n case 'warning':\n logger.warn(prefix + result.message);\n break;\n }\n });\n\n // Throw if there are any errors\n if (throwOnError && results.some((result) => result.type === 'error')) {\n throw new Error('Validation errors occurred');\n }\n}\n","import { TranslationsLoader } from '../translations-manager/translations-loaders/types';\nimport { defaultCacheUrl } from 'generaltranslation/internal';\n\n/**\n * Loader translations type\n * - GT_REMOTE: use the default remote store URL {@link defaultCacheUrl}\n * - REMOTE: use a custom remote store URL\n * - CUSTOM: use a custom translations loader\n * - DISABLED: no translations loading\n */\nexport enum LoadTranslationsType {\n GT_REMOTE = 'gt-remote',\n REMOTE = 'remote',\n CUSTOM = 'custom',\n DISABLED = 'disabled',\n}\n\n/**\n * Based on the configurtion return the load translations type\n *\n * cacheUrl = null means disabled\n */\nexport function getLoadTranslationsType(config: {\n projectId?: string;\n cacheUrl?: string | null;\n loadTranslations?: TranslationsLoader;\n}): LoadTranslationsType {\n if (config.loadTranslations) {\n return LoadTranslationsType.CUSTOM;\n } else if (config.cacheUrl) {\n return LoadTranslationsType.REMOTE;\n } else if (\n (config.cacheUrl === undefined || config.cacheUrl === defaultCacheUrl) &&\n config.projectId\n ) {\n return LoadTranslationsType.GT_REMOTE;\n } else {\n return LoadTranslationsType.DISABLED;\n }\n}\n","import { TranslationsLoader } from '../../translations-manager/translations-loaders/types';\nimport { LoadTranslationsType } from '../../utils/getLoadTranslationsType';\nimport { getLoadTranslationsType } from '../../utils/getLoadTranslationsType';\nimport { ValidationResult } from '../types';\n\n/**\n * Load translation configuration\n *\n * Types of load translations:\n * - GT_REMOTE: use the default remote store URL {@link defaultCacheUrl}\n * - REMOTE: use a custom remote store URL\n * - CUSTOM: use a custom translations loader\n * - DISABLED: no translations loading\n *\n * Requirements:\n * - REMOTE:\n * - GT_REMOTE:\n * - projectId is required\n * - CUSTOM:\n * - loadTranslations is required\n * - DISABLED:\n * - no requirements\n */\nexport function validateLoadTranslations(params: {\n projectId?: string;\n cacheUrl?: string | null;\n loadTranslations?: TranslationsLoader;\n}): ValidationResult[] {\n const results: ValidationResult[] = [];\n const { projectId, loadTranslations } = params;\n\n const loadTranslationsType = getLoadTranslationsType(params);\n switch (loadTranslationsType) {\n case LoadTranslationsType.REMOTE:\n case LoadTranslationsType.GT_REMOTE:\n if (!projectId) {\n results.push({\n type: 'warning',\n message:\n 'projectId is required when loading translations from a remote store',\n });\n }\n break;\n case LoadTranslationsType.CUSTOM:\n if (!loadTranslations) {\n results.push({\n type: 'error',\n message:\n 'loadTranslations is required when loading translations from a custom loader',\n });\n }\n break;\n case LoadTranslationsType.DISABLED:\n break;\n }\n\n return results;\n}\n","import { defaultRuntimeApiUrl } from 'generaltranslation/internal';\n\n/**\n * Runtime API translation type\n * - GT: use the default runtime API URL {@link defaultRuntimeApiUrl}\n * - CUSTOM: use a custom runtime API URL\n * - DISABLED: no runtime API translation\n */\nexport enum TranslationApiType {\n GT = 'gt',\n CUSTOM = 'custom',\n DISABLED = 'disabled',\n}\n\n/**\n * Based on the configurtion return the runtime translation type\n * @param params - The parameters to validate\n * @returns The runtime translation type\n */\nexport function getTranslationApiType(params: {\n projectId?: string;\n devApiKey?: string;\n apiKey?: string;\n runtimeUrl?: string | null;\n}): TranslationApiType {\n if (\n (params.runtimeUrl === undefined ||\n params.runtimeUrl === defaultRuntimeApiUrl) &&\n params.projectId &&\n (params.devApiKey || params.apiKey)\n ) {\n return TranslationApiType.GT;\n } else if (params.runtimeUrl) {\n return TranslationApiType.CUSTOM;\n } else {\n return TranslationApiType.DISABLED;\n }\n}\n","import { ValidationResult } from '../types';\nimport {\n TranslationApiType,\n getTranslationApiType,\n} from '../../utils/getTranslationApiType';\n\n/**\n * Validate the translation API configuration\n * @param params - The parameters to validate\n * @returns The validation results\n *\n * Types of translation API:\n * - GT: use the default runtime API URL {@link defaultRuntimeApiUrl}\n * - CUSTOM: use a custom runtime API URL\n * - DISABLED: no runtime API translation\n *\n * Requirements:\n * - CUSTOM:\n * - GT:\n * - projectId is required\n * - devApiKey or apiKey is required\n * - DISABLED:\n * - no requirements\n *\n * TODO: reject dev api key in production\n */\nexport function validateTranslationApi(params: {\n projectId?: string;\n devApiKey?: string;\n apiKey?: string;\n runtimeUrl?: string | null;\n}): ValidationResult[] {\n const results: ValidationResult[] = [];\n\n const translationApiType = getTranslationApiType(params);\n\n switch (translationApiType) {\n case TranslationApiType.CUSTOM:\n case TranslationApiType.GT:\n if (!params.projectId) {\n results.push({\n type: 'warning',\n message: 'projectId is required',\n });\n }\n if (!params.devApiKey && !params.apiKey) {\n results.push({\n type: 'warning',\n message: 'devApiKey or apiKey is required',\n });\n }\n break;\n case TranslationApiType.DISABLED:\n break;\n }\n return results;\n}\n","import {\n getLoadTranslationsType,\n LoadTranslationsType,\n} from './getLoadTranslationsType';\nimport {\n getTranslationApiType,\n TranslationApiType,\n} from './getTranslationApiType';\n\n/**\n * Returns true if GT services are enabled\n * @param config - The configuration\n * @returns True if GT services are enabled\n */\nexport function getGTServicesEnabled(config: {\n projectId?: string;\n devApiKey?: string;\n apiKey?: string;\n cacheUrl?: string | null;\n runtimeUrl?: string | null;\n}): boolean {\n return (\n getLoadTranslationsType(config) === LoadTranslationsType.GT_REMOTE ||\n getTranslationApiType(config) === TranslationApiType.GT\n );\n}\n","import { isValidLocale } from 'generaltranslation/core';\nimport { getGTServicesEnabled } from '../../utils/getGTServicesEnabled';\nimport { ValidationResult } from '../types';\nimport type { CustomMapping } from 'generaltranslation/types';\n\n/**\n * Validate the locales configuration\n * @param params - The parameters to validate\n * @returns The validation results\n *\n * Only apply if using GT services\n */\nexport function validateLocales(params: {\n projectId?: string;\n devApiKey?: string;\n apiKey?: string;\n defaultLocale?: string;\n locales?: string[];\n customMapping?: CustomMapping;\n cacheUrl?: string | null;\n runtimeUrl?: string | null;\n}): ValidationResult[] {\n const results: ValidationResult[] = [];\n if (!getGTServicesEnabled(params)) {\n return results;\n }\n const { defaultLocale, locales, customMapping } = params;\n\n const localesToValidate = new Set([\n ...(defaultLocale ? [defaultLocale] : []),\n ...(locales || []),\n ]);\n\n localesToValidate.forEach((locale) => {\n if (!isValidLocale(locale, customMapping)) {\n results.push({\n type: 'error',\n message: `Invalid locale: ${locale}`,\n });\n }\n });\n\n return results;\n}\n","import { ValidationResult } from './types';\nimport { I18nManagerConstructorParams } from '../types';\nimport { validateLoadTranslations } from './config-validation/validateLoadTranslations';\nimport { validateTranslationApi } from './config-validation/validateTranslationApi';\nimport { validateLocales } from './config-validation/validateLocales';\n\n/**\n * Validate the configuration\n * @param config - The configuration to validate\n * @returns The validation results\n */\nexport function validateConfig(\n config: I18nManagerConstructorParams\n): ValidationResult[] {\n const results: ValidationResult[] = [];\n\n results.push(...validateLoadTranslations(config));\n results.push(...validateTranslationApi(config));\n results.push(...validateLocales(config));\n\n return results;\n}\n","import { StorageAdapterType } from './types';\n\n/**\n * Abstract class to be overridden by the wrapper library.\n */\nabstract class StorageAdapter {\n abstract readonly type: StorageAdapterType;\n\n /**\n * Get an item from the storage\n * @param key - The key to get the item for\n * @returns The item or undefined if not found\n */\n abstract getItem(key: string): string | undefined;\n\n /**\n * Set an item in the storage\n * @param key - The key to set the item for\n * @param value - The value to set the item to\n */\n abstract setItem(key: string, value: string): void;\n\n /**\n * Remove an item from the storage\n * @param key - The key to remove the item for\n */\n abstract removeItem(key: string): void;\n}\n\nexport { StorageAdapter };\n","import { StorageAdapter } from './StorageAdapter';\nimport { StorageAdapterType } from './types';\n\nconst FALLBACK_STORAGE_ADAPTER_TYPE: StorageAdapterType =\n 'fallback-storage-adapter' as const;\n\n/**\n * Fallback to storage adapter that is scoped to the entire process\n */\nclass FallbackStorageAdapter extends StorageAdapter {\n readonly type = FALLBACK_STORAGE_ADAPTER_TYPE;\n\n private storage: Record<string, string> = {};\n\n getItem(key: string): string | undefined {\n return this.storage[key];\n }\n\n setItem(key: string, value: string): void {\n this.storage[key] = value;\n }\n\n removeItem(key: string): void {\n delete this.storage[key];\n }\n}\n\nexport { FallbackStorageAdapter, FALLBACK_STORAGE_ADAPTER_TYPE };\n","import type { Locale } from '../LocalesCache';\nimport type { TranslateMany } from '../TranslationsCache';\n\ntype TranslateManyClient = {\n translateMany(\n sources: Parameters<TranslateMany>[0],\n options: { targetLocale: string },\n timeout?: number\n ): ReturnType<TranslateMany>;\n};\n\n/**\n * CreateTranslateMany function type\n */\nexport type CreateTranslateMany = (locale: Locale) => TranslateMany;\n\n/**\n * Create a translate many function\n * @param locale - The locale\n * @returns The translate many function\n */\nexport function createTranslateManyFactory(\n gtInstance: TranslateManyClient,\n timeout?: number\n): CreateTranslateMany {\n return (locale) => (sources) =>\n gtInstance.translateMany(sources, { targetLocale: locale }, timeout);\n}\n","import { resolveCanonicalLocale } from 'generaltranslation/core';\nimport { TranslationsLoader } from './types';\nimport { defaultCacheUrl } from 'generaltranslation/internal';\nimport { Translation } from '../utils/types/translation-data';\nimport type { CustomMapping } from 'generaltranslation/types';\n\n/**\n * Parameters for the createRemoteTranslationLoader function\n * @param cacheUrl - The cache url\n * @param projectId - The project id\n * @param _versionId - The version id\n * @param _branchId - The branch id\n */\nexport type CreateRemoteTranslationLoaderParams = {\n cacheUrl: string;\n projectId: string;\n _versionId?: string;\n _branchId?: string;\n customMapping?: CustomMapping;\n};\n\n/**\n * Creates a translations loader function that loads translations from a remote store (CDN or other)\n * @param params - The parameters for the createRemoteTranslationLoader function\n * @returns A translations loader function\n *\n * TODO: validate projectId, cacheUrl, _versionId, _branchId\n */\nexport function createRemoteTranslationLoader(\n params: CreateRemoteTranslationLoaderParams\n): TranslationsLoader {\n // Get url\n const unlocalizedUrl = generateUrl(params);\n\n // define loader function (error handled by wrapper)\n const loader: TranslationsLoader = async (locale: string) => {\n // Standardize locale\n locale = resolveCanonicalLocale(locale, params.customMapping);\n const url = unlocalizedUrl.replace('[locale]', locale);\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to load translations from ${url}`);\n }\n return (await response.json()) as Record<string, Translation>;\n };\n\n return loader;\n}\n\n// ===== HELPER FUNCTIONS ===== //\n\n/**\n * Generate a URL for a translations file\n */\nfunction generateUrl(params: CreateRemoteTranslationLoaderParams): string {\n const {\n cacheUrl = defaultCacheUrl,\n projectId,\n _versionId,\n _branchId,\n } = params;\n\n // Generate version id segment and branch id query\n const versionIdSegment = _versionId ? `/${_versionId}` : '';\n const branchIdQuery = _branchId ? `?branchId=${_branchId}` : '';\n\n // Generate URL\n const url =\n `${cacheUrl}/${projectId}/[locale]` + versionIdSegment + branchIdQuery;\n\n return url;\n}\n","import { TranslationsLoader } from './types';\n\n/**\n * Creates a fallback translations loader function that loads translations from a fallback source\n * @returns A translations loader function\n */\nexport function createFallbackTranslationLoader(): TranslationsLoader {\n // eslint-disable-next-line no-unused-vars\n const loader: TranslationsLoader = async (_locale: string) => {\n return {};\n };\n\n return loader;\n}\n","import type { CustomMapping } from 'generaltranslation/types';\nimport { TranslationsLoader } from './types';\nimport { LoadTranslationsType } from '../../utils/getLoadTranslationsType';\nimport logger from '../../../logs/logger';\nimport { createRemoteTranslationLoader } from './createRemoteTranslationLoader';\nimport { createFallbackTranslationLoader } from './createFallbackTranslationLoader';\n\n/**\n * Creates a translation loader function that loads translations from a remote store (CDN or other)\n * @param params - The parameters for the createTranslationLoader function\n * @param params.type - The type of translation loader to create\n * @param params.remoteTranslationLoaderParams - The parameters for the remote translation loader\n * @param params.loadTranslations - The custom translations loader function\n * @returns A translation loader function\n */\nexport function routeCreateTranslationLoader({\n type,\n remoteTranslationLoaderParams,\n loadTranslations,\n}: {\n type: LoadTranslationsType;\n remoteTranslationLoaderParams: {\n cacheUrl?: string | null;\n projectId?: string;\n _versionId?: string;\n _branchId?: string;\n customMapping?: CustomMapping;\n };\n loadTranslations?: TranslationsLoader;\n}): TranslationsLoader {\n if (type === LoadTranslationsType.DISABLED) {\n // TODO: move this warning to validation layer\n logger.warn(\n 'I18nManager: No translation loader found. No translations will be loaded.'\n );\n }\n\n const { cacheUrl, projectId, _versionId, _branchId, customMapping } =\n remoteTranslationLoaderParams;\n\n switch (type) {\n case LoadTranslationsType.REMOTE:\n case LoadTranslationsType.GT_REMOTE:\n return createRemoteTranslationLoader({\n cacheUrl: cacheUrl || '',\n projectId: projectId || '',\n _versionId,\n _branchId,\n customMapping,\n });\n case LoadTranslationsType.CUSTOM:\n return loadTranslations!;\n case LoadTranslationsType.DISABLED:\n return createFallbackTranslationLoader();\n }\n}\n","import type {\n LifecycleCallback,\n LifecycleParam,\n} from '../lifecycle-hooks/types';\n\n/**\n * Cache class\n * This is designed in such a way that it is the responsibility of the client\n * to invoke the cache miss method when a cache miss occurs.\n *\n * TODO: maybe add \"OutputValue\" as a reflection of \"InputKey\"\n */\nabstract class Cache<\n InputKey,\n CacheKey extends string,\n CacheValue,\n OutputValue extends unknown,\n> {\n /**\n * Cache of items\n */\n private cache: Record<CacheKey, CacheValue> = {} as Record<\n CacheKey,\n CacheValue\n >;\n\n /**\n * Promise cache for inflight fallbacks\n */\n private fallbackPromises: Partial<Record<CacheKey, Promise<CacheValue>>> =\n {} as Record<CacheKey, Promise<CacheValue>>;\n\n /**\n * Lifecycle callbacks - invoked in implementation of the abstract methods\n * - onHit: invoked when a cache hit occurs\n * - onMiss: invoked when a cache miss occurs\n */\n protected onHit?: LifecycleCallback<\n InputKey,\n CacheKey,\n CacheValue,\n OutputValue\n >;\n protected onMiss?: LifecycleCallback<\n InputKey,\n CacheKey,\n CacheValue,\n OutputValue\n >;\n\n /**\n * Constructor\n * @param {Object} params - The parameters for the cache\n * @param {Record<CacheKey, CacheValue>} params.init - The initial cache\n * @param {CacheLifecycle} [lifecycle] - Optional lifecycle callbacks\n */\n constructor(\n init: Record<CacheKey, CacheValue>,\n lifecycle?: LifecycleParam<InputKey, CacheKey, CacheValue, OutputValue>\n ) {\n // eslint-disable-next-line no-undef\n this.cache = structuredClone(init);\n this.onHit = lifecycle?.onHit;\n this.onMiss = lifecycle?.onMiss;\n }\n\n /**\n * Set the value for a key\n */\n protected setCache(cacheKey: CacheKey, value: CacheValue): void {\n this.cache[cacheKey] = value;\n }\n\n /**\n * Look up the key\n */\n protected getCache(key: InputKey): CacheValue | undefined {\n const cacheKey = this.genKey(key);\n return this.cache[cacheKey];\n }\n\n /**\n * Get the internal cache\n * @returns The internal cache\n *\n * @internal - used by gt-tanstack-start\n */\n public getInternalCache(): Record<CacheKey, CacheValue> {\n return this.cache;\n }\n\n /**\n * Fallback to the value from the fallback function on a cache miss\n * @important assumes that the fallback error handling done upstream\n */\n protected async missCache(key: InputKey): Promise<CacheValue> {\n // Check for inflight fallback\n const cacheKey = this.genKey(key);\n if (this.fallbackPromises[cacheKey] !== undefined) {\n return await this.fallbackPromises[cacheKey];\n }\n\n // Add to inflight fallback cache\n const fallbackPromise = this.fallback(key);\n this.fallbackPromises[cacheKey] = fallbackPromise;\n\n // Wait for fallback to complete\n try {\n // Wait for fallback to complete\n const value = await fallbackPromise;\n\n // Update cache\n this.cache[cacheKey] = value;\n return value;\n } finally {\n delete this.fallbackPromises[cacheKey];\n }\n }\n\n // ===== Abstract Methods ===== //\n\n /**\n * Customizable helper function that calculates the cache key from an input key\n */\n protected abstract genKey(key: InputKey): CacheKey;\n\n /**\n * Get the fallback value for a cache miss\n */\n protected abstract fallback(key: InputKey): Promise<CacheValue>;\n\n /**\n * Lookup a value in the cache\n */\n public abstract get(key: InputKey): OutputValue | undefined;\n\n /**\n * Miss the cache\n */\n public abstract miss(key: InputKey): Promise<OutputValue | undefined>;\n}\n\nexport { Cache };\n","import { hashSource } from 'generaltranslation/id';\nimport { indexVars } from 'generaltranslation/internal';\nimport { LookupOptions } from '../translation-functions/types/options';\nimport { Translation } from '../types';\nimport type { IcuMessage } from 'generaltranslation/types';\n\n/**\n * Hash a message string\n */\nexport function hashMessage<T extends Translation>(\n message: T,\n options: LookupOptions\n): string {\n return hashSource({\n source:\n options.$format === 'ICU' ? indexVars(message as IcuMessage) : message,\n ...(options?.$context && { context: options.$context }),\n ...(options?.$id && { id: options.$id }),\n ...('$maxChars' in options &&\n options.$maxChars != null && {\n maxChars: Math.abs(options.$maxChars),\n }),\n dataFormat: options.$format,\n });\n}\n","import { LookupOptions } from '../../translation-functions/types/options';\nimport { Cache } from './Cache';\nimport type { LifecycleParam } from '../lifecycle-hooks/types';\nimport { Translation } from './utils/types/translation-data';\nimport { hashMessage } from '../../utils/hashMessage';\nimport type {\n Content,\n EntryMetadata,\n TranslateManyEntry,\n TranslationResult,\n} from 'generaltranslation/types';\n\n// See gt-next\nconst MAX_BATCH_SIZE = 25;\nconst MAX_CONCURRENT_REQUESTS = 100;\nconst BATCH_INTERVAL = 50;\n\n/**\n * InputKey type for lookups\n * @typedef {Object} TranslationKey\n * @property {TranslationValue} message - The message from the source\n * @property {LookupOptions} options - The options for the translation\n */\nexport type TranslationKey<TranslationValue extends Translation> = {\n message: TranslationValue;\n options: LookupOptions;\n};\n\n/**\n * Just a way to be more explicit about what \"hash\" is\n */\nexport type Hash = string;\n\n/**\n * A queue entry for batching, used to also handle reject and resolve\n */\ntype QueueEntry<TranslationValue extends Translation> = {\n key: Hash;\n source: TranslationValue;\n metadata: EntryMetadata;\n resolve: (value: Translation) => void;\n reject: (reason?: unknown) => void;\n};\n\n/**\n * TranslateMany call signature\n */\nexport type TranslateMany = (\n sources: Record<Hash, TranslateManyEntry>\n) => Promise<Record<string, TranslationResult>>;\n\n/**\n * A cache for a single locale's translations\n *\n * Principles:\n * - This class is language agnostic, and should never store the locale code as a parameter.\n * Locale logic is handled at the LocalesCache level. Use a callback function that has the\n * locale parameter embedded if you wish to use the locale code.\n */\nexport class TranslationsCache<\n TranslationValue extends Translation,\n> extends Cache<\n TranslationKey<TranslationValue>,\n Hash,\n TranslationValue,\n TranslationValue\n> {\n /**\n * Queue of translation requests\n */\n private _queue: Array<QueueEntry<TranslationValue>> = [];\n\n /**\n * Timer for batching\n */\n // eslint-disable-next-line no-undef\n private _batchTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Number of active requests\n */\n private _activeRequests = 0;\n\n /**\n * Translate many function\n */\n private _translateMany: TranslateMany;\n\n /**\n * Constructor\n * @param {Object} params - The parameters for the cache\n * @param {Record<Hash, TranslationValue>} params.init - The initial cache\n * @param {Function} params.fallback - Get the fallback value for a cache miss\n */\n constructor({\n init,\n translateMany,\n lifecycle,\n }: {\n init: Record<Hash, TranslationValue>;\n translateMany: TranslateMany;\n lifecycle: LifecycleParam<\n TranslationKey<TranslationValue>,\n Hash,\n TranslationValue,\n TranslationValue\n >;\n }) {\n super(init, lifecycle);\n this._translateMany = translateMany;\n }\n\n /**\n * Get the translation value for a given key\n * @param key - The translation key\n * @returns The translation value\n */\n public get<T extends TranslationValue>(\n key: TranslationKey<T>\n ): T | undefined {\n const value = this.getCache(key) as T | undefined;\n if (value != null && this.onHit) {\n this.onHit({\n inputKey: key,\n cacheKey: this.genKey(key),\n cacheValue: value,\n outputValue: value,\n });\n }\n return value;\n }\n\n /**\n * Miss the cache\n * @param key - The translation key\n * @returns The translation value\n */\n public async miss<T extends TranslationValue>(\n key: TranslationKey<T>\n ): Promise<T | undefined> {\n const value = await this.missCache(key);\n if (value != null && this.onMiss) {\n this.onMiss({\n inputKey: key,\n cacheKey: this.genKey(key),\n cacheValue: value,\n outputValue: value,\n });\n }\n return value as T | undefined;\n }\n\n /**\n * Generate a key for the cache\n * @param key - The translation key\n * @returns The key\n */\n protected genKey(key: TranslationKey<TranslationValue>): Hash {\n return hashMessage(key.message, key.options);\n }\n\n /**\n * Get the fallback value for a cache miss\n * @param key - The translation key\n * @returns The fallback value\n */\n protected fallback(\n key: TranslationKey<TranslationValue>\n ): Promise<TranslationValue> {\n // Add translation request to queue\n const translationPromise = this._enqueueTranslation(key);\n\n // If batch is full, flush now\n if (this._queue.length >= MAX_BATCH_SIZE) {\n this._flushNow();\n } else {\n this._scheduleBatch();\n }\n\n return translationPromise;\n }\n\n // ===== PRIVATE METHODS ===== //\n\n // --- QUEUE MANAGEMENT --- //\n\n /**\n * Flush the queue now\n */\n private _flushNow(): void {\n if (this._batchTimer) {\n // eslint-disable-next-line no-undef\n clearTimeout(this._batchTimer);\n this._batchTimer = null;\n }\n this._drainQueue();\n }\n\n /**\n * Schedule a batch of translations\n */\n private _scheduleBatch(): void {\n if (this._batchTimer) return; // already scheduled\n // eslint-disable-next-line no-undef\n this._batchTimer = setTimeout(() => {\n this._batchTimer = null;\n this._drainQueue();\n }, BATCH_INTERVAL);\n }\n\n /**\n * Drain the queue\n */\n private _drainQueue(): void {\n while (\n this._queue.length > 0 &&\n this._activeRequests < MAX_CONCURRENT_REQUESTS\n ) {\n const batch = this._queue.splice(0, MAX_BATCH_SIZE);\n this._sendBatchRequest(batch);\n }\n // If items remain (hit concurrency limit), schedule again\n if (this._queue.length > 0) {\n this._scheduleBatch();\n }\n }\n\n /**\n * Enqueue translation request and return a promise that resolves when the translation is ready\n * @param {TranslationKey<TranslationValue>} key - The translation key\n * @returns {Promise<TranslationValue>} The translation promise\n */\n private _enqueueTranslation(\n key: TranslationKey<TranslationValue>\n ): Promise<TranslationValue> {\n const cacheKey = this.genKey(key);\n const options = key.options;\n return new Promise<TranslationValue>((resolve, reject) => {\n this._queue.push({\n key: cacheKey,\n source: key.message,\n metadata: {\n ...(options?.$context && { context: options.$context }),\n ...(options?.$id && { id: options.$id }),\n ...('$maxChars' in options &&\n options.$maxChars != null && {\n $maxChars: Math.abs(options.$maxChars),\n }),\n dataFormat: options.$format,\n },\n resolve: (value) => resolve(value as TranslationValue),\n reject,\n });\n });\n }\n\n // --- SEND REQUESTS --- //\n\n /**\n * Send a batch request for translations\n * @param {QueueEntry<TranslationValue>[]} batch - The batch of requests to send\n */\n private async _sendBatchRequest(\n batch: QueueEntry<TranslationValue>[]\n ): Promise<void> {\n this._activeRequests++;\n\n const requests = convertBatchToTranslateManyParams(batch);\n const response = await this._sendBatchRequestWithErrorHandling(\n batch,\n requests\n );\n if (response) {\n this._handleTranslationResponse(batch, response);\n }\n\n this._activeRequests--;\n }\n\n /**\n * Send a translation request with error handling\n */\n private async _sendBatchRequestWithErrorHandling(\n batch: QueueEntry<TranslationValue>[],\n requests: Record<Hash, TranslateManyEntry>\n ): Promise<ReturnType<TranslateMany> | undefined> {\n try {\n return await this._translateMany(requests);\n } catch (error) {\n for (const entry of batch) {\n entry.reject(error);\n }\n return undefined;\n }\n }\n\n /**\n * Handle a translation response\n */\n private _handleTranslationResponse(\n batch: QueueEntry<TranslationValue>[],\n response: Awaited<ReturnType<TranslateMany>>\n ): void {\n for (const entry of batch) {\n const { key } = entry;\n const result = response[key];\n if (result && result.success) {\n const translation = result.translation as TranslationValue;\n this.setCache(key, translation);\n entry.resolve(translation);\n } else {\n entry.reject(result?.error);\n }\n }\n }\n}\n\n/**\n * Convert a TranslationKey to a TranslateManyEntry\n */\nfunction convertBatchToTranslateManyParams<\n TranslationValue extends Translation,\n>(batch: QueueEntry<TranslationValue>[]): Record<Hash, TranslateManyEntry> {\n return batch.reduce<Record<Hash, TranslateManyEntry>>((acc, entry) => {\n acc[entry.key] = {\n source: entry.source as Content,\n metadata: entry.metadata,\n };\n return acc;\n }, {});\n}\n","/**\n * Default cache expiry time in milliseconds\n */\nexport const DEFAULT_CACHE_EXPIRY_TIME = 60_000; // 60 sec\n","import { Cache } from './Cache';\nimport { Hash, TranslationKey, TranslationsCache } from './TranslationsCache';\nimport { Translation } from './utils/types/translation-data';\nimport { DEFAULT_CACHE_EXPIRY_TIME } from './utils/constants';\nimport { CreateTranslateMany } from './utils/createTranslateMany';\nimport type {\n LifecycleParam,\n LocalesCacheLifecycleCallbacks,\n TranslationsCacheLifecycleCallback,\n} from '../lifecycle-hooks/types';\n\n/**\n * Just being explicit about the purpose of this type\n */\nexport type Locale = string;\n\n/**\n * Cache entry\n * @typedef {Object} CacheEntry\n * @property {number} expiresAt - The time at which the cache entry expires.\n * @property {TranslationsCache<TranslationValue>} translationsCache - The translations cache for the locale.\n */\nexport type CacheEntry<TranslationValue extends Translation> = {\n expiresAt: number;\n translationsCache: TranslationsCache<TranslationValue>;\n};\n\n/**\n * Safe translations loader function type\n * @returns A promise that resolves to a mapping of strings to {@link Translation}\n * TODO: rename this because we are no longer doing try/catch around the translation loader\n */\nexport type SafeTranslationsLoader<TranslationValue extends Translation> = (\n locale: string\n) => Promise<Record<Hash, TranslationValue>>;\n\n/**\n * Cache for looking up translations by locale\n */\nexport class LocalesCache<TranslationValue extends Translation> extends Cache<\n Locale,\n Locale,\n CacheEntry<TranslationValue>,\n CacheEntry<TranslationValue>['translationsCache']\n> {\n /**\n * Translation loader function\n */\n private _translationLoader: SafeTranslationsLoader<TranslationValue>;\n\n /**\n * Translate many function\n */\n private _createTranslateMany: CreateTranslateMany;\n\n /**\n * Time to live for cache entries\n */\n private ttl: number = DEFAULT_CACHE_EXPIRY_TIME;\n\n /**\n * Translations cache lifecycle callbacks (locale embedded)\n */\n private _onTranslationsCacheHit?: TranslationsCacheLifecycleCallback<TranslationValue>;\n private _onTranslationsCacheMiss?: TranslationsCacheLifecycleCallback<TranslationValue>;\n\n /**\n * Constructor\n * @param {Object} params - The parameters for the cache\n * @param {Record<string, CacheEntry<TranslationValue>>} params.init - The initial cache\n * @param {number | null} params.ttl - The time to live for cache entries\n * @param {SafeTranslationsLoader<TranslationValue>} params.loadTranslations - The translation loader function\n * @param {CreateTranslateMany} params.createTranslateMany - Factory function for creating a translate many function\n */\n constructor({\n init = {},\n ttl,\n loadTranslations,\n createTranslateMany,\n lifecycle: {\n onLocalesCacheHit: onHit,\n onLocalesCacheMiss: onMiss,\n onTranslationsCacheHit,\n onTranslationsCacheMiss,\n },\n }: {\n init?: Record<string, CacheEntry<TranslationValue>>;\n ttl?: number | null;\n createTranslateMany: CreateTranslateMany;\n loadTranslations: SafeTranslationsLoader<TranslationValue>;\n lifecycle: LocalesCacheLifecycleCallbacks<TranslationValue>;\n }) {\n super(init, { onHit, onMiss });\n\n // Set time to live\n this.ttl = ttl === null ? -1 : (ttl ?? DEFAULT_CACHE_EXPIRY_TIME);\n\n this._translationLoader = loadTranslations;\n this._createTranslateMany = createTranslateMany;\n this._onTranslationsCacheHit = onTranslationsCacheHit;\n this._onTranslationsCacheMiss = onTranslationsCacheMiss;\n }\n\n /**\n * Get the translations for a given locale\n * @param key - The locale\n * @returns The translations\n */\n public get(\n key: Locale\n ): CacheEntry<TranslationValue>['translationsCache'] | undefined {\n // Get the cache entry\n const entry = this.getCache(key);\n if (!entry || (entry.expiresAt > 0 && entry.expiresAt < Date.now())) {\n return undefined;\n }\n const value = entry.translationsCache;\n\n // Life cycle callback\n if (value != null && this.onHit) {\n this.onHit({\n inputKey: key,\n cacheKey: this.genKey(key),\n cacheValue: entry,\n outputValue: value,\n });\n }\n\n return value;\n }\n\n /**\n * Miss the cache\n * @param key - The locale\n * @returns The translations cache\n */\n public async miss(\n key: Locale\n ): Promise<CacheEntry<TranslationValue>['translationsCache']> {\n // Miss the cache\n const cacheValue = await this.missCache(key);\n\n // Life cycle callback\n const value = cacheValue.translationsCache;\n if (value != null && this.onMiss) {\n this.onMiss({\n inputKey: key,\n cacheKey: this.genKey(key),\n cacheValue: cacheValue,\n outputValue: value,\n });\n }\n\n return value;\n }\n\n /**\n * Generate the cache key for a given locale\n * @param key - The locale\n * @returns The cache key\n *\n * This is just an identity function, no transformation needed\n */\n protected genKey(key: Locale): Locale {\n return key;\n }\n\n /**\n * Fallback for a cache miss\n * @param locale - The locale\n * @returns The cache entry\n */\n protected async fallback(\n locale: Locale\n ): Promise<CacheEntry<TranslationValue>> {\n // Fetch translations\n const translationsPromise = this._translationLoader(locale);\n\n // Get cache expiry time\n const expiresAt = this.ttl < 0 ? this.ttl : Date.now() + this.ttl;\n\n // Cache the promise and expiry timestamp\n const translationsCache = new TranslationsCache<TranslationValue>({\n init: await translationsPromise,\n lifecycle: this._createTranslationsCacheLifecycle(locale),\n translateMany: this._createTranslateMany(locale),\n });\n\n return { translationsCache, expiresAt };\n }\n\n // ===== PRIVATE METHODS ===== //\n\n /**\n * Create the translations cache lifecycle\n * @param locale - The locale\n * @returns The translations cache lifecycle\n */\n private _createTranslationsCacheLifecycle(\n locale: Locale\n ): LifecycleParam<\n TranslationKey<TranslationValue>,\n Hash,\n TranslationValue,\n TranslationValue\n > {\n return {\n onHit: this._onTranslationsCacheHit\n ? (params) =>\n this._onTranslationsCacheHit!({\n locale,\n ...params,\n })\n : undefined,\n onMiss: this._onTranslationsCacheMiss\n ? (params) =>\n this._onTranslationsCacheMiss!({\n locale,\n ...params,\n })\n : undefined,\n };\n }\n}\n","import { EventEmitter } from '../event-subscription/EventEmitter';\nimport type { Translation } from '../translations-manager/utils/types/translation-data';\nimport type { LocalesCacheLifecycleCallbacks } from './types';\nimport type { I18nEvents } from '../event-subscription/types';\n/**\n * Maps consumer-facing lifecycle callbacks to internal locales cache lifecycle callbacks.\n * The consumer API exposes simplified params (locale, hash, value) while the internal\n * API uses the full cache lifecycle params (inputKey, cacheKey, cacheValue, outputValue).\n *\n * @deprecated - move to subscription api instead\n */\nexport function createLifecycleCallbacks<TranslationValue extends Translation>(\n emit: EventEmitter<I18nEvents<TranslationValue>>['emit']\n): LocalesCacheLifecycleCallbacks<TranslationValue> {\n return {\n onLocalesCacheHit: (params) => {\n emit('locales-cache-hit', {\n locale: params.inputKey,\n translations: params.outputValue.getInternalCache(),\n });\n },\n onLocalesCacheMiss: (params) => {\n emit('locales-cache-miss', {\n locale: params.inputKey,\n translations: params.outputValue.getInternalCache(),\n });\n },\n onTranslationsCacheHit: (params) => {\n emit('translations-cache-hit', {\n locale: params.locale,\n hash: params.cacheKey,\n translation: params.outputValue,\n });\n },\n onTranslationsCacheMiss: (params) => {\n emit('translations-cache-miss', {\n locale: params.locale,\n hash: params.cacheKey,\n translation: params.outputValue,\n });\n },\n };\n}\n","import type { BaseEvent, Listener, ListenerStore } from './types';\n\n/**\n * Base class for event emitters\n */\nexport class EventEmitter<Events extends BaseEvent> {\n /**\n * Events map\n */\n protected listeners: ListenerStore<Events> = {};\n\n private getOrCreateListeners<EventName extends keyof Events>(\n eventName: EventName\n ): Set<Listener<Events, EventName>> {\n if (!this.listeners[eventName]) {\n this.listeners[eventName] = new Set();\n }\n return this.listeners[eventName]!;\n }\n\n /**\n * Subscribe to an event, returns an unsubscribe function\n */\n public subscribe<EventName extends keyof Events>(\n eventName: EventName,\n listener: Listener<Events, EventName>\n ) {\n const set = this.getOrCreateListeners(eventName);\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n }\n\n /**\n * Emit an event\n */\n protected emit<EventName extends keyof Events>(\n eventName: EventName,\n event: Events[EventName]\n ) {\n this.listeners[eventName]?.forEach((subscriber) => subscriber(event));\n }\n}\n","import { EventEmitter } from '../event-subscription/EventEmitter';\nimport type { Translation } from '../translations-manager/utils/types/translation-data';\nimport type { LifecycleCallbacks } from './types';\nimport type { I18nEvents } from '../event-subscription/types';\n\n/**\n * Subscribes to the lifecycle callbacks and emits the events to the event emitter\n * @deprecated - move to subscription api instead\n *\n * NOTE: we do not have to worry about unsubscribe here as this is a deprecated api\n * and is only used internally\n */\nexport function subscribeLifecycleCallbacks<\n TranslationValue extends Translation,\n>(\n {\n onLocalesCacheHit,\n onLocalesCacheMiss,\n onTranslationsCacheHit,\n onTranslationsCacheMiss,\n }: LifecycleCallbacks<TranslationValue>,\n subscribe: EventEmitter<I18nEvents<TranslationValue>>['subscribe']\n) {\n if (onLocalesCacheHit) {\n subscribe('locales-cache-hit', (event) => {\n onLocalesCacheHit({\n ...event,\n value: event.translations,\n });\n });\n }\n if (onLocalesCacheMiss) {\n subscribe('locales-cache-miss', (event) => {\n onLocalesCacheMiss({\n ...event,\n value: event.translations,\n });\n });\n }\n if (onTranslationsCacheHit) {\n subscribe('translations-cache-hit', (event) => {\n onTranslationsCacheHit({\n ...event,\n value: event.translation,\n });\n });\n }\n if (onTranslationsCacheMiss) {\n subscribe('translations-cache-miss', (event) => {\n onTranslationsCacheMiss({\n ...event,\n value: event.translation,\n });\n });\n }\n}\n","import { publishValidationResults } from './validation/publishValidationResults';\nimport logger from '../logs/logger';\nimport { I18nManagerConfig, I18nManagerConstructorParams } from './types';\nimport { StorageAdapterType } from './storage-adapter/types';\nimport { validateConfig } from './validation/validateConfig';\nimport { Translation } from './translations-manager/utils/types/translation-data';\nimport { StorageAdapter } from './storage-adapter/StorageAdapter';\nimport { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { GT } from 'generaltranslation';\nimport { LocaleConfig, standardizeLocale } from 'generaltranslation/core';\nimport type { CustomMapping } from 'generaltranslation/types';\nimport { LookupOptions } from '../translation-functions/types/options';\nimport { FallbackStorageAdapter } from './storage-adapter/FallbackStorageAdapter';\nimport { getGTServicesEnabled } from './utils/getGTServicesEnabled';\nimport {\n SafeTranslationsLoader,\n TranslationsLoader,\n} from './translations-manager/translations-loaders/types';\nimport { createTranslateManyFactory } from './translations-manager/utils/createTranslateMany';\nimport { routeCreateTranslationLoader } from './translations-manager/translations-loaders/routeCreateTranslationLoader';\nimport { getLoadTranslationsType } from './utils/getLoadTranslationsType';\nimport { Locale, LocalesCache } from './translations-manager/LocalesCache';\nimport { Hash } from './translations-manager/TranslationsCache';\nimport { createLifecycleCallbacks } from './lifecycle-hooks/createLifecycleCallbacks';\nimport { EventEmitter } from './event-subscription/EventEmitter';\nimport { subscribeLifecycleCallbacks } from './lifecycle-hooks/subscribeLifecycleCallbacks';\nimport { I18nEvents } from './event-subscription/types';\n\n/**\n * Default translation timeout in milliseconds for a runtime translation request\n */\nconst DEFAULT_TRANSLATION_TIMEOUT = 12_000; // 12 seconds\n\n/**\n * A translation resolver is a function that synchronously resolves a translation\n * @template U - The type of the translation (default: Translation)\n * @param {U} message - The message to get the translation for\n * @param {LookupOptions} [options] - The options for the translation\n * @returns {U | undefined} The translation for the given message and options or undefined if the translation is not found\n */\ntype TranslationResolver<U extends Translation = Translation> = <\n T extends U = U,\n>(\n message: T,\n options?: LookupOptions\n) => T | undefined;\n\n/**\n * A prefetch entry is an entry that we want to prefetch during the async period\n * @template TranslationType - The type of the translation\n * @param {TranslationType} message - The message to prefetch\n * @param {LookupOptions} options - The options for the prefetch\n * @returns {PrefetchEntry<TranslationType>} The prefetch entry\n */\ntype PrefetchEntry<TranslationType extends Translation> = {\n message: TranslationType;\n options: LookupOptions;\n};\n\n/**\n * Class for managing translation functionality\n * @template StorageAdapterInstanceType - The type of the storage adapter\n * @template TranslationValue - The type of the translation that will be cached\n */\nclass I18nManager<\n StorageAdapterInstanceType extends StorageAdapter = StorageAdapter,\n TranslationValue extends Translation = Translation,\n> extends EventEmitter<I18nEvents<TranslationValue>> {\n protected config: I18nManagerConfig;\n\n /**\n * Store adapter\n */\n protected storeAdapter: StorageAdapterInstanceType;\n\n /**\n * Cache for translations\n */\n private localesCache: LocalesCache<TranslationValue>;\n\n /**\n * Runtime-safe locale and formatting helpers\n */\n private localeConfig: LocaleConfig;\n\n /**\n * Creates an instance of I18nManager.\n * TODO: resolve gtConfig from just file path\n * @param params - The parameters for the I18nManager constructor\n * @param params.config - The configuration for the I18nManager\n */\n constructor(\n params: I18nManagerConstructorParams<StorageAdapterInstanceType>\n ) {\n super();\n\n // Validation\n const validationResults = validateConfig(params);\n publishValidationResults(validationResults, 'I18nManager: ');\n\n // Setup\n this.config = standardizeConfig(params);\n this.localeConfig = new LocaleConfig({\n defaultLocale: this.config.defaultLocale,\n locales: this.config.locales,\n customMapping: this.config.customMapping,\n });\n this.storeAdapter =\n (params.storeAdapter as StorageAdapterInstanceType) ??\n new FallbackStorageAdapter();\n\n // Create cache miss handlers\n const loadTranslations = createTranslationLoader<TranslationValue>(params);\n const createTranslateMany = createTranslateManyFactory(\n this.getGTClassClean(),\n DEFAULT_TRANSLATION_TIMEOUT\n );\n\n // Subscribe lifecycle callbacks\n subscribeLifecycleCallbacks(params.lifecycle ?? {}, (...args) =>\n this.subscribe(...args)\n );\n\n // Setup translations cache\n this.localesCache = new LocalesCache<TranslationValue>({\n loadTranslations:\n loadTranslations as SafeTranslationsLoader<TranslationValue>,\n createTranslateMany,\n lifecycle: createLifecycleCallbacks((...args) => this.emit(...args)),\n });\n }\n\n // ========== Subscribers and Emitters ========== //\n\n /**\n * Subscribes to a change in a translation entry (eg a runtime translation)\n * @param listener - The subscriber function\n * @param locale - The locale of the translation entry\n * @param hash - The hash of the translation entry\n * @returns An unsubscribe function\n *\n * Pair this with {@link lookupTranslation} to get the translation entry\n */\n subscribeToTranslationsCacheMiss(\n listener: (\n event: I18nEvents<TranslationValue>['translations-cache-miss']\n ) => void,\n locale: Locale,\n hash: Hash\n ) {\n return this.subscribe('translations-cache-miss', (event) => {\n if (event.locale !== locale || event.hash !== hash) {\n return;\n }\n listener(event);\n });\n }\n\n // ========== Getters and Setters ========== //\n\n /**\n * Get adapter type\n */\n getAdapterType(): StorageAdapterType {\n return this.storeAdapter.type;\n }\n\n /**\n * Get the locale\n */\n getLocale(): string {\n const locale = this.storeAdapter.getItem('locale');\n if (!locale) {\n logger.warn(\n 'getLocale() invoked outside of translation context, falling back to default locale'\n );\n return this.config.defaultLocale;\n }\n return locale;\n }\n\n /**\n * Set the locale\n */\n setLocale(locale: string): void {\n try {\n const newLocale = this.resolveLocale(locale);\n const previousLocale = this.getLocale();\n this.storeAdapter.setItem('locale', newLocale);\n this.emit('locale-update', {\n previousLocale,\n newLocale,\n });\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Get the default locale\n */\n getDefaultLocale(): string {\n return this.config.defaultLocale;\n }\n\n /**\n * Get the locales\n */\n getLocales(): string[] {\n return this.config.locales;\n }\n\n /**\n * Get the version ID\n */\n getVersionId(): string | undefined {\n return this.config._versionId;\n }\n\n /**\n * Get a gt class instance\n * TODO: keep a cache to avoid creating new instances unnecessarily\n */\n getGTClass(): GT {\n return this.getGTClassClean(this.getLocale());\n }\n\n /**\n * Is translation enabled?\n */\n isTranslationEnabled(): boolean {\n return this.config.enableI18n;\n }\n\n // ========== Translation Loading ========== //\n\n /**\n * Get the translation loader function\n * @deprecated wrap a cb around loadTranslations instead\n */\n getTranslationLoader(): TranslationsLoader {\n return (locale: string) => this.loadTranslations(locale);\n }\n\n // ========== Translation Resolution ========== //\n\n // ----- New Operations ----- //\n\n /**\n * Loads in translations for a given locale\n * Edge case usage: access the translations object directly\n */\n async loadTranslations(\n locale: string = this.getLocale()\n ): Promise<Record<Hash, TranslationValue>> {\n try {\n // Validate\n const resolvedLocale = this.resolveLocale(locale);\n if (!this.requiresTranslation(resolvedLocale)) {\n return {};\n }\n\n // Get the locale cache\n let txCache = this.localesCache.get(resolvedLocale);\n if (!txCache) txCache = await this.localesCache.miss(resolvedLocale);\n\n // Get the translations\n const translations = txCache.getInternalCache();\n return translations;\n } catch (error) {\n this.handleError(error);\n return {};\n }\n }\n\n /**\n * Just lookup a translation\n */\n lookupTranslation<T extends TranslationValue = TranslationValue>(\n message: T,\n options: LookupOptions = {} as LookupOptions\n ): T | undefined {\n try {\n // Validate\n const { locale, options: lookupOptions } =\n this.resolveLookupParams(options);\n\n // Early return if in default locale\n if (!this.requiresTranslation(locale)) {\n return message;\n }\n\n // Get the locale cache\n const txCache = this.localesCache.get(locale);\n if (!txCache) return undefined;\n\n // Get the translation\n return txCache.get({ message, options: lookupOptions });\n } catch (error) {\n this.handleError(error);\n return undefined;\n }\n }\n\n /**\n * Look up a translation\n * If it's not found, use the fallback (runtime translate)\n */\n async lookupTranslationWithFallback<\n T extends TranslationValue = TranslationValue,\n >(\n message: T,\n options: LookupOptions = {} as LookupOptions\n ): Promise<T | undefined> {\n try {\n // Validate\n const { locale, options: lookupOptions } =\n this.resolveLookupParams(options);\n\n // Early return if in default locale\n if (!this.requiresTranslation(locale)) {\n return message;\n }\n\n // Get the locale cache\n let txCache = this.localesCache.get(locale);\n if (!txCache) txCache = await this.localesCache.miss(locale);\n\n // Get the translation (falling back to runtime translate)\n let translation = txCache.get({ message, options: lookupOptions });\n if (translation == null)\n translation = await txCache.miss({ message, options: lookupOptions });\n return translation;\n } catch (error) {\n this.handleError(error);\n return undefined;\n }\n }\n\n /**\n * Saves a current lookup translation function immune to expiry\n * Useful for operations involving lookup callbacks like useGT()\n * @param locale - The locale to get the lookup translation for\n * @param prefetchEntries - Any entries we want to prefetch during the async period\n * @returns A lookup translation function\n *\n * @important prefetchEntries must all be the same locale\n */\n async getLookupTranslation(\n locale: string = this.getLocale(),\n prefetchEntries: {\n message: TranslationValue;\n options: LookupOptions;\n }[] = []\n ): Promise<TranslationResolver<TranslationValue>> {\n try {\n // Validate\n const resolvedLocale = this.resolveLocale(locale);\n\n // Early return if i18n is disabled or default locale\n if (!this.requiresTranslation(resolvedLocale)) {\n return (message) => message;\n }\n\n // Invariant: all prefetchEntries must be the same locale\n const resolvedPrefetchEntries = resolvePrefetchEntriesByLocale(\n prefetchEntries,\n resolvedLocale,\n (entryLocale) => this.resolveLocale(entryLocale)\n );\n if (resolvedPrefetchEntries.length !== prefetchEntries.length) {\n logger.warn(\n `I18nManager: getLookupTranslation(): prefetchEntries must all be the same locale, ignoring all entries that are not for ${resolvedLocale}`\n );\n }\n\n // Get Locale Cache\n let txCache = this.localesCache.get(resolvedLocale);\n if (!txCache) txCache = await this.localesCache.miss(resolvedLocale);\n if (!txCache) return () => undefined;\n\n // Prefetch any entries during async block\n await Promise.all(\n resolvedPrefetchEntries\n .filter((entry) => txCache.get(entry) == null)\n .map((entry) => txCache.miss(entry))\n );\n\n // Create translation resolver\n return (message, options: LookupOptions = {} as LookupOptions) => {\n // Calculate hash\n return txCache.get({\n message,\n options: this.resolveLookupOptions(options),\n });\n };\n } catch (error) {\n this.handleError(error);\n return (message) => message;\n }\n }\n\n // ----- Sync Operations ----- //\n\n /**\n * Get the translations (error on unloaded translations)\n * @param {string} message - The message to get the translation for\n * @param {LookupOptions} [options] - The options for the translation\n * @returns {TranslationValue | undefined} The translation for the given message and options synchronously\n * @deprecated use lookupTranslation instead\n */\n resolveTranslationSync: TranslationResolver<TranslationValue> = <\n T extends TranslationValue = TranslationValue,\n >(\n message: T,\n options: LookupOptions = {} as LookupOptions\n ) => {\n return this.lookupTranslation(message, options);\n };\n\n // ----- Async Operations ----- //\n\n /**\n * Get the translations\n * @deprecated use loadTranslations instead\n */\n async getTranslations(\n locale: string = this.getLocale()\n ): Promise<Record<Hash, TranslationValue>> {\n try {\n return this.loadTranslations(locale);\n } catch (error) {\n this.handleError(error);\n return {};\n }\n }\n\n /**\n * Get translation for a given locale and message\n *\n * @param {string} [locale] - The locale to get the translation for (if not provided, will use the current locale)\n * @returns A function that resolves the translations for a given message and options synchronously\n *\n * Note: we can assume that the translation is a string because we are passing a string\n *\n * @deprecated use getLookupTranslation instead\n */\n async getTranslationResolver(\n locale: string = this.getLocale()\n ): Promise<TranslationResolver<TranslationValue>> {\n return this.getLookupTranslation(locale);\n }\n\n // ========== Metadata ========== //\n\n /**\n * Returns true if translation is required\n * @param {string} [locale] - The user's locale\n * @returns {boolean} True if translation is required, otherwise false\n */\n requiresTranslation(locale: string = this.getLocale()): boolean {\n const defaultLocale = this.getDefaultLocale();\n const locales = this.getLocales();\n return (\n this.isTranslationEnabled() &&\n this.localeConfig.requiresTranslation(locale, defaultLocale, locales)\n );\n }\n\n /**\n * Returns true if dialect translation is required\n * @param {string} [locale] - The user's locale\n * @returns {boolean} True if dialect translation is required, otherwise false\n */\n requiresDialectTranslation(locale: string = this.getLocale()): boolean {\n const defaultLocale = this.getDefaultLocale();\n return (\n this.requiresTranslation(locale) &&\n this.localeConfig.isSameLanguage(defaultLocale, locale)\n );\n }\n\n /**\n * Handle errors\n * Soft error in production, throw in development\n */\n private handleError(error: unknown) {\n switch (this.config.environment) {\n case 'development':\n throw error;\n case 'production':\n default:\n logger.error('I18nManager: ' + error);\n break;\n }\n }\n\n private resolveLocale(locale: string) {\n const resolvedLocale = this.localeConfig.determineLocale(locale);\n if (!this.localeConfig.isValidLocale(locale) || !resolvedLocale) {\n throw new Error(\n `I18nManager: validateLocale(): locale ${locale} is not valid`\n );\n }\n return resolvedLocale;\n }\n\n private resolveLookupParams(options: LookupOptions = {} as LookupOptions) {\n const locale = this.resolveLocale(options.$locale ?? this.getLocale());\n return {\n locale,\n options: this.resolveLookupOptions(options, locale),\n };\n }\n\n private resolveLookupOptions(\n options: LookupOptions = {} as LookupOptions,\n resolvedLocale?: string\n ) {\n if (!options.$locale) {\n return options;\n }\n return {\n ...options,\n $locale: resolvedLocale ?? this.resolveLocale(options.$locale),\n };\n }\n\n /**\n * A helper function to create a gt class that is locale agnostic\n * This is helpful for when our getLocale function is bound to a\n * specifica context\n */\n private getGTClassClean(locale?: string) {\n return new GT({\n sourceLocale: this.config.defaultLocale,\n targetLocale: locale,\n locales: this.config.locales,\n customMapping: this.config.customMapping,\n projectId: this.config.projectId,\n baseUrl: this.config.runtimeUrl || undefined,\n apiKey: this.config.apiKey,\n devApiKey: this.config.devApiKey,\n });\n }\n}\n\nexport { I18nManager };\n\n// ===== Helper Functions ===== //\n\n/**\n * Standardize the config\n * @param config - The config to standardize\n * @returns The standardized config\n */\nfunction standardizeConfig<T extends StorageAdapter>(\n config: I18nManagerConstructorParams<T>\n): I18nManagerConfig {\n const gtServicesEnabled = getGTServicesEnabled(config);\n\n const dedupedLocales = dedupeLocales({\n defaultLocale: config.defaultLocale || libraryDefaultLocale,\n locales: config.locales || [libraryDefaultLocale],\n customMapping: config.customMapping,\n });\n\n return {\n environment: config.environment || 'production',\n enableI18n: config.enableI18n !== undefined ? config.enableI18n : true,\n projectId: config.projectId,\n devApiKey: config.devApiKey,\n apiKey: config.apiKey,\n runtimeUrl: config.runtimeUrl,\n _versionId: config._versionId,\n ...(gtServicesEnabled\n ? standardizeLocales(dedupedLocales)\n : dedupedLocales),\n };\n}\n\n/**\n * Dedupe locales and add defaultLocale\n */\nfunction dedupeLocales({\n defaultLocale,\n locales,\n customMapping,\n}: {\n defaultLocale: string;\n locales: string[];\n customMapping?: CustomMapping;\n}): {\n defaultLocale: string;\n locales: string[];\n customMapping: CustomMapping;\n} {\n return {\n defaultLocale,\n locales: Array.from(new Set([defaultLocale, ...locales])),\n customMapping: customMapping || {},\n };\n}\n\n/**\n * Standardize all locales in config\n * Only apply if using GT services\n */\nfunction standardizeLocales(config: {\n defaultLocale: string;\n locales: string[];\n customMapping: CustomMapping;\n}): {\n defaultLocale: string;\n locales: string[];\n customMapping: CustomMapping;\n} {\n // Sanitize defaultLocale and locales\n const defaultLocale = standardizeLocale(config.defaultLocale);\n const locales = config.locales.map((locale) => {\n const mappedLocale =\n typeof config.customMapping?.[locale] === 'string'\n ? config.customMapping?.[locale]\n : config.customMapping?.[locale]?.code;\n if (mappedLocale) {\n return locale;\n } else {\n return standardizeLocale(locale);\n }\n });\n\n // Sanitize customMapping\n const customMapping = Object.fromEntries(\n Object.entries(config.customMapping || {}).map(([key, value]) => [\n key,\n typeof value === 'string'\n ? standardizeLocale(value)\n : {\n ...value,\n ...(value.code ? { code: standardizeLocale(value.code) } : {}),\n },\n ])\n );\n\n return {\n defaultLocale,\n locales,\n customMapping,\n };\n}\n\n/**\n * Resolve prefetch entry locales and keep entries matching the active locale.\n * @template TranslationType - The type of the translation\n * @param {PrefetchEntry<TranslationType>[]} prefetchEntries - The prefetch entries to filter\n * @param {string} locale - The locale to filter by\n * @returns {PrefetchEntry<TranslationType>[]} The filtered prefetch entries\n */\nfunction resolvePrefetchEntriesByLocale<TranslationType extends Translation>(\n prefetchEntries: PrefetchEntry<TranslationType>[],\n locale: string,\n resolveLocale: (locale: string) => string\n) {\n return prefetchEntries.flatMap((entry) => {\n const entryLocale = entry.options.$locale;\n if (entryLocale == null) return [entry];\n\n try {\n const resolvedLocale = resolveLocale(entryLocale);\n if (resolvedLocale !== locale) return [];\n return [\n {\n message: entry.message,\n options: {\n ...entry.options,\n $locale: resolvedLocale,\n },\n },\n ];\n } catch {\n return [];\n }\n });\n}\n\n/**\n * Helper function for creating a translation loader\n */\nfunction createTranslationLoader<\n TranslationType extends Translation,\n StorageAdapterInstanceType extends StorageAdapter = StorageAdapter,\n>(\n params: I18nManagerConstructorParams<StorageAdapterInstanceType>\n): SafeTranslationsLoader<TranslationType> {\n return routeCreateTranslationLoader({\n loadTranslations: params.loadTranslations,\n type: getLoadTranslationsType(params),\n remoteTranslationLoaderParams: {\n cacheUrl: params.cacheUrl,\n projectId: params.projectId,\n _versionId: params._versionId,\n _branchId: params._branchId,\n customMapping: params.customMapping,\n },\n }) as SafeTranslationsLoader<TranslationType>;\n}\n","import { libraryDefaultLocale } from 'generaltranslation/internal';\nimport { I18nManager } from './I18nManager';\nimport logger from '../logs/logger';\nimport { StorageAdapter } from './storage-adapter/StorageAdapter';\nimport { Translation } from './translations-manager/utils/types/translation-data';\n\n// Singleton instance of I18nManager\nlet i18nManager: I18nManager | undefined = undefined;\n\n/**\n * Get the singleton instance of I18nManager\n * @returns The singleton instance of I18nManager\n * @template T - The type of the storage adapter\n * @template U - The type of the translation that will be cached\n */\nexport function getI18nManager<\n T extends StorageAdapter = StorageAdapter,\n U extends Translation = Translation,\n>():\n | I18nManager<T, U>\n | I18nManager<T, Translation>\n | I18nManager<StorageAdapter, U>\n | I18nManager<StorageAdapter, Translation> {\n if (!i18nManager) {\n logger.warn(\n 'getI18nManager(): Translation failed because I18nManager not initialized.'\n );\n i18nManager = new I18nManager({\n defaultLocale: libraryDefaultLocale,\n locales: [libraryDefaultLocale],\n });\n }\n return i18nManager;\n}\n\n/**\n * Configure the singleton instance of I18nManager\n * @param config - The configuration for the I18nManager\n *\n * Wraper libraries will export a configure function that will call this function.\n */\nexport function setI18nManager(i18nManagerInstance: I18nManager): void {\n i18nManager = i18nManagerInstance;\n}\n","import { formatCutoff } from 'generaltranslation/core';\nimport { InlineTranslationOptions } from '../../types/options';\n\n/**\n * String interpolation function\n */\nexport function interpolateStringMessage(\n encodedMsg: string,\n options: InlineTranslationOptions\n): string {\n const cutoffMessage = formatCutoff(encodedMsg, {\n locales: options.$locale ?? options.$_locales,\n maxChars: options.$maxChars,\n });\n return cutoffMessage;\n}\n","import { getI18nManager } from '../../../i18n-manager/singleton-operations';\nimport { InlineTranslationOptions } from '../../types/options';\nimport { interpolateIcuMessage } from './interpolateIcuMessage';\nimport { interpolateStringMessage } from './interpolateStringMessage';\nimport type { StringFormat } from 'generaltranslation/types';\n\n/**\n * Options for string interpolation\n * @internal\n */\nexport type InterpolationOptions = {\n $format: StringFormat;\n} & Omit<InlineTranslationOptions, '$format'>;\n\n/**\n * Interpolation router function for all {@link StringFormat} types\n */\nexport function interpolateMessage({\n source,\n target,\n options,\n}: {\n source: string;\n target?: string;\n options: InterpolationOptions;\n}): string {\n const i18nManager = getI18nManager();\n\n // Format translation\n if (target != null) {\n return routeInterpolation(target, {\n $locale: i18nManager.getLocale(),\n $_fallback: source,\n ...options,\n });\n }\n\n // Format source\n return routeInterpolation(source, {\n $locale: i18nManager.getDefaultLocale(),\n ...options,\n });\n}\n\n// ----- HELPERS ----- //\n\n/**\n * Route to appropriate formatting function\n */\nfunction routeInterpolation(\n content: string,\n options: InlineTranslationOptions\n): string {\n switch (options.$format ?? 'STRING') {\n case 'ICU':\n return interpolateIcuMessage(content, options);\n case 'I18NEXT':\n case 'STRING':\n return interpolateStringMessage(content, options);\n default:\n // e.g. $format: 'NONE'\n return content;\n }\n}\n","import { getI18nManager } from '../../i18n-manager/singleton-operations';\nimport { LookupOptions, ResolutionOptions } from '../types/options';\nimport {\n interpolateMessage,\n InterpolationOptions,\n} from '../utils/interpolation/interpolateMessage';\nimport type {\n DataFormat,\n JsxChildren,\n StringContent,\n StringFormat,\n} from 'generaltranslation/types';\n\n// ----- JSX TRANSLATION FUNCTIONS ----- //\n\n/**\n * Just do a simple lookup of the translation\n */\nexport function resolveJsx(\n content: JsxChildren,\n options: ResolutionOptions<'JSX'>\n): JsxChildren | undefined {\n const lookupOptions = getLookupOptions(options, 'JSX');\n const i18nManager = getI18nManager();\n const translation = i18nManager.lookupTranslation(content, lookupOptions);\n return translation;\n}\n\n/**\n * Lookup translation, fallback to source\n */\nexport function resolveJsxWithFallback(\n content: JsxChildren,\n options: ResolutionOptions<'JSX'>\n): JsxChildren {\n const translation = resolveJsx(content, options);\n return translation ?? content;\n}\n\n/**\n * Lookup translation\n * fallback to runtime translate\n * Fallback to source\n */\nexport async function resolveJsxWithRuntimeFallback(\n content: JsxChildren,\n options: ResolutionOptions<'JSX'>\n): Promise<JsxChildren> {\n const lookupOptions = getLookupOptions(options, 'JSX');\n const i18nManager = getI18nManager();\n const translation = await i18nManager.lookupTranslationWithFallback(\n content,\n lookupOptions\n );\n return translation ?? content;\n}\n\n// ----- STRING CONTENT TRANSLATION FUNCTIONS ----- //\n\n/**\n * Just do a simple lookup of the translation\n * And interpolate\n */\nexport function resolveStringContent(\n content: StringContent,\n options: ResolutionOptions<StringFormat>\n): StringContent | undefined {\n const lookupOptions = getLookupOptions(options, 'STRING');\n const i18nManager = getI18nManager();\n const translation = i18nManager.lookupTranslation(content, lookupOptions);\n if (translation == null) return undefined;\n return interpolateMessage({\n source: content,\n target: translation,\n options: lookupOptions as InterpolationOptions,\n });\n}\n\n/**\n * Lookup translation, fallback to source\n */\nexport function resolveStringContentWithFallback(\n content: StringContent,\n options: ResolutionOptions<StringFormat>\n): StringContent {\n const lookupOptions = getLookupOptions(options, 'STRING');\n const i18nManager = getI18nManager();\n const translation = i18nManager.lookupTranslation(content, lookupOptions);\n return interpolateMessage({\n source: content,\n target: translation,\n options: lookupOptions as InterpolationOptions,\n });\n}\n\n/**\n * Lookup translation\n * fallback to runtime translate\n * Fallback to source\n */\nexport async function resolveStringContentWithRuntimeFallback(\n content: StringContent,\n options: ResolutionOptions<StringFormat>\n): Promise<StringContent> {\n const lookupOptions = getLookupOptions(options, 'STRING');\n const i18nManager = getI18nManager();\n const translation = await i18nManager.lookupTranslationWithFallback(\n content,\n lookupOptions\n );\n return interpolateMessage({\n source: content,\n target: translation,\n options: lookupOptions as InterpolationOptions,\n });\n}\n// ----- HELPER FUNCTIONS ----- //\n\n/**\n * Helper function to construct lookupOptions object\n */\nfunction getLookupOptions<T extends DataFormat>(\n options: ResolutionOptions<T>,\n format: T\n): LookupOptions {\n return {\n $format: format,\n ...options,\n };\n}\n"],"mappings":"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"}
|