i18next 25.10.10 → 26.0.1
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/LICENSE +1 -1
- package/dist/cjs/i18next.js +63 -86
- package/dist/esm/i18next.bundled.js +63 -86
- package/dist/esm/i18next.js +63 -86
- package/dist/esm/package.json +1 -1
- package/dist/umd/i18next.js +63 -86
- package/dist/umd/i18next.min.js +1 -1
- package/eslint.config.mjs +32 -0
- package/i18next.js +63 -86
- package/i18next.min.js +1 -1
- package/index.d.mts +1 -1
- package/index.d.ts +10 -1
- package/package.json +11 -16
- package/typescript/options.d.ts +0 -22
- package/jsr.json +0 -15
package/LICENSE
CHANGED
package/dist/cjs/i18next.js
CHANGED
|
@@ -14,7 +14,7 @@ const defer = () => {
|
|
|
14
14
|
};
|
|
15
15
|
const makeString = object => {
|
|
16
16
|
if (object == null) return '';
|
|
17
|
-
return
|
|
17
|
+
return String(object);
|
|
18
18
|
};
|
|
19
19
|
const copy = (a, s, t) => {
|
|
20
20
|
a.forEach(m => {
|
|
@@ -22,7 +22,7 @@ const copy = (a, s, t) => {
|
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
24
|
const lastOfPathSeparatorRegExp = /###/g;
|
|
25
|
-
const cleanKey = key => key && key.
|
|
25
|
+
const cleanKey = key => key && key.includes('###') ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
|
|
26
26
|
const canNotTraverseDeeper = object => !object || isString(object);
|
|
27
27
|
const getLastOfPath = (object, path, Empty) => {
|
|
28
28
|
const stack = !isString(path) ? path : path.split('.');
|
|
@@ -107,7 +107,7 @@ const deepExtend = (target, source, overwrite) => {
|
|
|
107
107
|
return target;
|
|
108
108
|
};
|
|
109
109
|
const regexEscape = str => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
|
110
|
-
|
|
110
|
+
const _entityMap = {
|
|
111
111
|
'&': '&',
|
|
112
112
|
'<': '<',
|
|
113
113
|
'>': '>',
|
|
@@ -146,7 +146,7 @@ const looksLikeObjectPathRegExpCache = new RegExpCache(20);
|
|
|
146
146
|
const looksLikeObjectPath = (key, nsSeparator, keySeparator) => {
|
|
147
147
|
nsSeparator = nsSeparator || '';
|
|
148
148
|
keySeparator = keySeparator || '';
|
|
149
|
-
const possibleChars = chars.filter(c => nsSeparator.
|
|
149
|
+
const possibleChars = chars.filter(c => !nsSeparator.includes(c) && !keySeparator.includes(c));
|
|
150
150
|
if (possibleChars.length === 0) return true;
|
|
151
151
|
const r = looksLikeObjectPathRegExpCache.getRegExp(`(${possibleChars.map(c => c === '?' ? '\\?' : c).join('|')})`);
|
|
152
152
|
let matched = !r.test(key);
|
|
@@ -179,7 +179,7 @@ const deepFind = (obj, path, keySeparator = '.') => {
|
|
|
179
179
|
nextPath += tokens[j];
|
|
180
180
|
next = current[nextPath];
|
|
181
181
|
if (next !== undefined) {
|
|
182
|
-
if (['string', 'number', 'boolean'].
|
|
182
|
+
if (['string', 'number', 'boolean'].includes(typeof next) && j < tokens.length - 1) {
|
|
183
183
|
continue;
|
|
184
184
|
}
|
|
185
185
|
i += j - i + 1;
|
|
@@ -270,6 +270,14 @@ class EventEmitter {
|
|
|
270
270
|
}
|
|
271
271
|
this.observers[event].delete(listener);
|
|
272
272
|
}
|
|
273
|
+
once(event, listener) {
|
|
274
|
+
const wrapper = (...args) => {
|
|
275
|
+
listener(...args);
|
|
276
|
+
this.off(event, wrapper);
|
|
277
|
+
};
|
|
278
|
+
this.on(event, wrapper);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
273
281
|
emit(event, ...args) {
|
|
274
282
|
if (this.observers[event]) {
|
|
275
283
|
const cloned = Array.from(this.observers[event].entries());
|
|
@@ -283,7 +291,7 @@ class EventEmitter {
|
|
|
283
291
|
const cloned = Array.from(this.observers['*'].entries());
|
|
284
292
|
cloned.forEach(([observer, numTimesAdded]) => {
|
|
285
293
|
for (let i = 0; i < numTimesAdded; i++) {
|
|
286
|
-
observer
|
|
294
|
+
observer(event, ...args);
|
|
287
295
|
}
|
|
288
296
|
});
|
|
289
297
|
}
|
|
@@ -306,7 +314,7 @@ class ResourceStore extends EventEmitter {
|
|
|
306
314
|
}
|
|
307
315
|
}
|
|
308
316
|
addNamespaces(ns) {
|
|
309
|
-
if (this.options.ns.
|
|
317
|
+
if (!this.options.ns.includes(ns)) {
|
|
310
318
|
this.options.ns.push(ns);
|
|
311
319
|
}
|
|
312
320
|
}
|
|
@@ -320,7 +328,7 @@ class ResourceStore extends EventEmitter {
|
|
|
320
328
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
321
329
|
const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
|
|
322
330
|
let path;
|
|
323
|
-
if (lng.
|
|
331
|
+
if (lng.includes('.')) {
|
|
324
332
|
path = lng.split('.');
|
|
325
333
|
} else {
|
|
326
334
|
path = [lng, ns];
|
|
@@ -335,7 +343,7 @@ class ResourceStore extends EventEmitter {
|
|
|
335
343
|
}
|
|
336
344
|
}
|
|
337
345
|
const result = getPath(this.data, path);
|
|
338
|
-
if (!result && !ns && !key && lng.
|
|
346
|
+
if (!result && !ns && !key && lng.includes('.')) {
|
|
339
347
|
lng = path[0];
|
|
340
348
|
ns = path[1];
|
|
341
349
|
key = path.slice(2).join('.');
|
|
@@ -349,7 +357,7 @@ class ResourceStore extends EventEmitter {
|
|
|
349
357
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
350
358
|
let path = [lng, ns];
|
|
351
359
|
if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key);
|
|
352
|
-
if (lng.
|
|
360
|
+
if (lng.includes('.')) {
|
|
353
361
|
path = lng.split('.');
|
|
354
362
|
value = ns;
|
|
355
363
|
ns = path[1];
|
|
@@ -373,7 +381,7 @@ class ResourceStore extends EventEmitter {
|
|
|
373
381
|
skipCopy: false
|
|
374
382
|
}) {
|
|
375
383
|
let path = [lng, ns];
|
|
376
|
-
if (lng.
|
|
384
|
+
if (lng.includes('.')) {
|
|
377
385
|
path = lng.split('.');
|
|
378
386
|
deep = resources;
|
|
379
387
|
resources = ns;
|
|
@@ -463,7 +471,6 @@ function keysFromSelector(selector, opts) {
|
|
|
463
471
|
return path.join(keySeparator);
|
|
464
472
|
}
|
|
465
473
|
|
|
466
|
-
const checkedLoadedFor = {};
|
|
467
474
|
const shouldHandleAsObject = res => !isString(res) && typeof res !== 'boolean' && typeof res !== 'number';
|
|
468
475
|
class Translator extends EventEmitter {
|
|
469
476
|
constructor(services, options = {}) {
|
|
@@ -474,6 +481,7 @@ class Translator extends EventEmitter {
|
|
|
474
481
|
this.options.keySeparator = '.';
|
|
475
482
|
}
|
|
476
483
|
this.logger = baseLogger.create('translator');
|
|
484
|
+
this.checkedLoadedFor = {};
|
|
477
485
|
}
|
|
478
486
|
changeLanguage(lng) {
|
|
479
487
|
if (lng) this.language = lng;
|
|
@@ -498,7 +506,7 @@ class Translator extends EventEmitter {
|
|
|
498
506
|
if (nsSeparator === undefined) nsSeparator = ':';
|
|
499
507
|
const keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
|
|
500
508
|
let namespaces = opt.ns || this.options.defaultNS || [];
|
|
501
|
-
const wouldCheckForNsInKey = nsSeparator && key.
|
|
509
|
+
const wouldCheckForNsInKey = nsSeparator && key.includes(nsSeparator);
|
|
502
510
|
const seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !opt.keySeparator && !this.options.userDefinedNsSeparator && !opt.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator);
|
|
503
511
|
if (wouldCheckForNsInKey && !seemsNaturalLanguage) {
|
|
504
512
|
const m = key.match(this.interpolator.nestingRegexp);
|
|
@@ -509,7 +517,7 @@ class Translator extends EventEmitter {
|
|
|
509
517
|
};
|
|
510
518
|
}
|
|
511
519
|
const parts = key.split(nsSeparator);
|
|
512
|
-
if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.
|
|
520
|
+
if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.includes(parts[0])) namespaces = parts.shift();
|
|
513
521
|
key = parts.join(keySeparator);
|
|
514
522
|
}
|
|
515
523
|
return {
|
|
@@ -596,7 +604,7 @@ class Translator extends EventEmitter {
|
|
|
596
604
|
}
|
|
597
605
|
const handleAsObject = shouldHandleAsObject(resForObjHndl);
|
|
598
606
|
const resType = Object.prototype.toString.apply(resForObjHndl);
|
|
599
|
-
if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && noObject.
|
|
607
|
+
if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && !noObject.includes(resType) && !(isString(joinArrays) && Array.isArray(resForObjHndl))) {
|
|
600
608
|
if (!opt.returnObjects && !this.options.returnObjects) {
|
|
601
609
|
if (!this.options.returnedObjectHandler) {
|
|
602
610
|
this.logger.warn('accessing an object - but returnObjects options is not enabled!');
|
|
@@ -692,7 +700,7 @@ class Translator extends EventEmitter {
|
|
|
692
700
|
if (this.options.saveMissingPlurals && needsPluralHandling) {
|
|
693
701
|
lngs.forEach(language => {
|
|
694
702
|
const suffixes = this.pluralResolver.getSuffixes(language, opt);
|
|
695
|
-
if (needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.
|
|
703
|
+
if (needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] && !suffixes.includes(`${this.options.pluralSeparator}zero`)) {
|
|
696
704
|
suffixes.push(`${this.options.pluralSeparator}zero`);
|
|
697
705
|
}
|
|
698
706
|
suffixes.forEach(suffix => {
|
|
@@ -802,8 +810,8 @@ class Translator extends EventEmitter {
|
|
|
802
810
|
namespaces.forEach(ns => {
|
|
803
811
|
if (this.isValidLookup(found)) return;
|
|
804
812
|
usedNS = ns;
|
|
805
|
-
if (!checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) {
|
|
806
|
-
checkedLoadedFor[`${codes[0]}-${ns}`] = true;
|
|
813
|
+
if (!this.checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) {
|
|
814
|
+
this.checkedLoadedFor[`${codes[0]}-${ns}`] = true;
|
|
807
815
|
this.logger.warn(`key "${usedKey}" for languages "${codes.join(', ')}" won't get resolved as namespace "${usedNS}" was not yet loaded`, 'This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!');
|
|
808
816
|
}
|
|
809
817
|
codes.forEach(code => {
|
|
@@ -818,7 +826,7 @@ class Translator extends EventEmitter {
|
|
|
818
826
|
const zeroSuffix = `${this.options.pluralSeparator}zero`;
|
|
819
827
|
const ordinalPrefix = `${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;
|
|
820
828
|
if (needsPluralHandling) {
|
|
821
|
-
if (opt.ordinal && pluralSuffix.
|
|
829
|
+
if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
|
|
822
830
|
finalKeys.push(key + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
|
|
823
831
|
}
|
|
824
832
|
finalKeys.push(key + pluralSuffix);
|
|
@@ -830,7 +838,7 @@ class Translator extends EventEmitter {
|
|
|
830
838
|
const contextKey = `${key}${this.options.contextSeparator || '_'}${opt.context}`;
|
|
831
839
|
finalKeys.push(contextKey);
|
|
832
840
|
if (needsPluralHandling) {
|
|
833
|
-
if (opt.ordinal && pluralSuffix.
|
|
841
|
+
if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
|
|
834
842
|
finalKeys.push(contextKey + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
|
|
835
843
|
}
|
|
836
844
|
finalKeys.push(contextKey + pluralSuffix);
|
|
@@ -891,7 +899,7 @@ class Translator extends EventEmitter {
|
|
|
891
899
|
static hasDefaultValue(options) {
|
|
892
900
|
const prefix = 'defaultValue';
|
|
893
901
|
for (const option in options) {
|
|
894
|
-
if (Object.prototype.hasOwnProperty.call(options, option) &&
|
|
902
|
+
if (Object.prototype.hasOwnProperty.call(options, option) && option.startsWith(prefix) && undefined !== options[option]) {
|
|
895
903
|
return true;
|
|
896
904
|
}
|
|
897
905
|
}
|
|
@@ -907,7 +915,7 @@ class LanguageUtil {
|
|
|
907
915
|
}
|
|
908
916
|
getScriptPartFromCode(code) {
|
|
909
917
|
code = getCleanedCode(code);
|
|
910
|
-
if (!code || code.
|
|
918
|
+
if (!code || !code.includes('-')) return null;
|
|
911
919
|
const p = code.split('-');
|
|
912
920
|
if (p.length === 2) return null;
|
|
913
921
|
p.pop();
|
|
@@ -916,12 +924,12 @@ class LanguageUtil {
|
|
|
916
924
|
}
|
|
917
925
|
getLanguagePartFromCode(code) {
|
|
918
926
|
code = getCleanedCode(code);
|
|
919
|
-
if (!code || code.
|
|
927
|
+
if (!code || !code.includes('-')) return code;
|
|
920
928
|
const p = code.split('-');
|
|
921
929
|
return this.formatLanguageCode(p[0]);
|
|
922
930
|
}
|
|
923
931
|
formatLanguageCode(code) {
|
|
924
|
-
if (isString(code) && code.
|
|
932
|
+
if (isString(code) && code.includes('-')) {
|
|
925
933
|
let formattedCode;
|
|
926
934
|
try {
|
|
927
935
|
formattedCode = Intl.getCanonicalLocales(code)[0];
|
|
@@ -941,7 +949,7 @@ class LanguageUtil {
|
|
|
941
949
|
if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) {
|
|
942
950
|
code = this.getLanguagePartFromCode(code);
|
|
943
951
|
}
|
|
944
|
-
return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.
|
|
952
|
+
return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.includes(code);
|
|
945
953
|
}
|
|
946
954
|
getBestMatchFromCodes(codes) {
|
|
947
955
|
if (!codes) return null;
|
|
@@ -959,10 +967,11 @@ class LanguageUtil {
|
|
|
959
967
|
const lngOnly = this.getLanguagePartFromCode(code);
|
|
960
968
|
if (this.isSupportedCode(lngOnly)) return found = lngOnly;
|
|
961
969
|
found = this.options.supportedLngs.find(supportedLng => {
|
|
962
|
-
if (supportedLng === lngOnly) return
|
|
963
|
-
if (supportedLng.
|
|
964
|
-
if (supportedLng.
|
|
965
|
-
if (supportedLng.
|
|
970
|
+
if (supportedLng === lngOnly) return true;
|
|
971
|
+
if (!supportedLng.includes('-') && !lngOnly.includes('-')) return false;
|
|
972
|
+
if (supportedLng.includes('-') && !lngOnly.includes('-') && supportedLng.slice(0, supportedLng.indexOf('-')) === lngOnly) return true;
|
|
973
|
+
if (supportedLng.startsWith(lngOnly) && lngOnly.length > 1) return true;
|
|
974
|
+
return false;
|
|
966
975
|
});
|
|
967
976
|
});
|
|
968
977
|
}
|
|
@@ -993,7 +1002,7 @@ class LanguageUtil {
|
|
|
993
1002
|
this.logger.warn(`rejecting language code not found in supportedLngs: ${c}`);
|
|
994
1003
|
}
|
|
995
1004
|
};
|
|
996
|
-
if (isString(code) && (code.
|
|
1005
|
+
if (isString(code) && (code.includes('-') || code.includes('_'))) {
|
|
997
1006
|
if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code));
|
|
998
1007
|
if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code));
|
|
999
1008
|
if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code));
|
|
@@ -1001,7 +1010,7 @@ class LanguageUtil {
|
|
|
1001
1010
|
addCode(this.formatLanguageCode(code));
|
|
1002
1011
|
}
|
|
1003
1012
|
fallbackCodes.forEach(fc => {
|
|
1004
|
-
if (codes.
|
|
1013
|
+
if (!codes.includes(fc)) addCode(this.formatLanguageCode(fc));
|
|
1005
1014
|
});
|
|
1006
1015
|
return codes;
|
|
1007
1016
|
}
|
|
@@ -1157,7 +1166,7 @@ class Interpolator {
|
|
|
1157
1166
|
let replaces;
|
|
1158
1167
|
const defaultData = this.options && this.options.interpolation && this.options.interpolation.defaultVariables || {};
|
|
1159
1168
|
const handleFormat = key => {
|
|
1160
|
-
if (key.
|
|
1169
|
+
if (!key.includes(this.formatSeparator)) {
|
|
1161
1170
|
const path = deepFindWithDefaults(data, defaultData, key, this.options.keySeparator, this.options.ignoreJSONStructure);
|
|
1162
1171
|
return this.alwaysFormat ? this.format(path, undefined, lng, {
|
|
1163
1172
|
...options,
|
|
@@ -1227,7 +1236,7 @@ class Interpolator {
|
|
|
1227
1236
|
let clonedOptions;
|
|
1228
1237
|
const handleHasOptions = (key, inheritedOptions) => {
|
|
1229
1238
|
const sep = this.nestingOptionsSeparator;
|
|
1230
|
-
if (key.
|
|
1239
|
+
if (!key.includes(sep)) return key;
|
|
1231
1240
|
const c = key.split(new RegExp(`${regexEscape(sep)}[ ]*{`));
|
|
1232
1241
|
let optionsString = `{${c[1]}`;
|
|
1233
1242
|
key = c[0];
|
|
@@ -1247,7 +1256,7 @@ class Interpolator {
|
|
|
1247
1256
|
this.logger.warn(`failed parsing options string in nesting for key ${key}`, e);
|
|
1248
1257
|
return `${key}${sep}${optionsString}`;
|
|
1249
1258
|
}
|
|
1250
|
-
if (clonedOptions.defaultValue && clonedOptions.defaultValue.
|
|
1259
|
+
if (clonedOptions.defaultValue && clonedOptions.defaultValue.includes(this.prefix)) delete clonedOptions.defaultValue;
|
|
1251
1260
|
return key;
|
|
1252
1261
|
};
|
|
1253
1262
|
while (match = this.nestingRegexp.exec(str)) {
|
|
@@ -1286,13 +1295,13 @@ class Interpolator {
|
|
|
1286
1295
|
const parseFormatStr = formatStr => {
|
|
1287
1296
|
let formatName = formatStr.toLowerCase().trim();
|
|
1288
1297
|
const formatOptions = {};
|
|
1289
|
-
if (formatStr.
|
|
1298
|
+
if (formatStr.includes('(')) {
|
|
1290
1299
|
const p = formatStr.split('(');
|
|
1291
1300
|
formatName = p[0].toLowerCase().trim();
|
|
1292
|
-
const optStr = p[1].
|
|
1293
|
-
if (formatName === 'currency' && optStr.
|
|
1301
|
+
const optStr = p[1].slice(0, -1);
|
|
1302
|
+
if (formatName === 'currency' && !optStr.includes(':')) {
|
|
1294
1303
|
if (!formatOptions.currency) formatOptions.currency = optStr.trim();
|
|
1295
|
-
} else if (formatName === 'relativetime' && optStr.
|
|
1304
|
+
} else if (formatName === 'relativetime' && !optStr.includes(':')) {
|
|
1296
1305
|
if (!formatOptions.range) formatOptions.range = optStr.trim();
|
|
1297
1306
|
} else {
|
|
1298
1307
|
const opts = optStr.split(';');
|
|
@@ -1386,9 +1395,11 @@ class Formatter {
|
|
|
1386
1395
|
this.formats[name.toLowerCase().trim()] = createCachedFormatter(fc);
|
|
1387
1396
|
}
|
|
1388
1397
|
format(value, format, lng, options = {}) {
|
|
1398
|
+
if (!format) return value;
|
|
1399
|
+
if (value == null) return value;
|
|
1389
1400
|
const formats = format.split(this.formatSeparator);
|
|
1390
|
-
if (formats.length > 1 && formats[0].indexOf('(') > 1 && formats[0].
|
|
1391
|
-
const lastIndex = formats.findIndex(f => f.
|
|
1401
|
+
if (formats.length > 1 && formats[0].indexOf('(') > 1 && !formats[0].includes(')') && formats.find(f => f.includes(')'))) {
|
|
1402
|
+
const lastIndex = formats.findIndex(f => f.includes(')'));
|
|
1392
1403
|
formats[0] = [formats[0], ...formats.splice(1, lastIndex)].join(this.formatSeparator);
|
|
1393
1404
|
}
|
|
1394
1405
|
const result = formats.reduce((mem, f) => {
|
|
@@ -1542,7 +1553,7 @@ class Connector extends EventEmitter {
|
|
|
1542
1553
|
}
|
|
1543
1554
|
if (err && data && tried < this.maxRetries) {
|
|
1544
1555
|
setTimeout(() => {
|
|
1545
|
-
this.read
|
|
1556
|
+
this.read(lng, ns, fcName, tried + 1, wait * 2, callback);
|
|
1546
1557
|
}, wait);
|
|
1547
1558
|
return;
|
|
1548
1559
|
}
|
|
@@ -1646,7 +1657,6 @@ const get = () => ({
|
|
|
1646
1657
|
nonExplicitSupportedLngs: false,
|
|
1647
1658
|
load: 'all',
|
|
1648
1659
|
preload: false,
|
|
1649
|
-
simplifyPluralSuffix: true,
|
|
1650
1660
|
keySeparator: '.',
|
|
1651
1661
|
nsSeparator: ':',
|
|
1652
1662
|
pluralSeparator: '_',
|
|
@@ -1683,7 +1693,6 @@ const get = () => ({
|
|
|
1683
1693
|
},
|
|
1684
1694
|
interpolation: {
|
|
1685
1695
|
escapeValue: true,
|
|
1686
|
-
format: value => value,
|
|
1687
1696
|
prefix: '{{',
|
|
1688
1697
|
suffix: '}}',
|
|
1689
1698
|
formatSeparator: ',',
|
|
@@ -1700,10 +1709,9 @@ const transformOptions = options => {
|
|
|
1700
1709
|
if (isString(options.ns)) options.ns = [options.ns];
|
|
1701
1710
|
if (isString(options.fallbackLng)) options.fallbackLng = [options.fallbackLng];
|
|
1702
1711
|
if (isString(options.fallbackNS)) options.fallbackNS = [options.fallbackNS];
|
|
1703
|
-
if (options.supportedLngs
|
|
1712
|
+
if (options.supportedLngs && !options.supportedLngs.includes('cimode')) {
|
|
1704
1713
|
options.supportedLngs = options.supportedLngs.concat(['cimode']);
|
|
1705
1714
|
}
|
|
1706
|
-
if (typeof options.initImmediate === 'boolean') options.initAsync = options.initImmediate;
|
|
1707
1715
|
return options;
|
|
1708
1716
|
};
|
|
1709
1717
|
|
|
@@ -1716,28 +1724,6 @@ const bindMemberFunctions = inst => {
|
|
|
1716
1724
|
}
|
|
1717
1725
|
});
|
|
1718
1726
|
};
|
|
1719
|
-
const SUPPORT_NOTICE_KEY = '__i18next_supportNoticeShown';
|
|
1720
|
-
const getSupportNoticeShown = () => {
|
|
1721
|
-
if (typeof globalThis !== 'undefined' && !!globalThis[SUPPORT_NOTICE_KEY]) return true;
|
|
1722
|
-
if (typeof process !== 'undefined' && process.env && process.env.I18NEXT_NO_SUPPORT_NOTICE) return true;
|
|
1723
|
-
if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production') return true;
|
|
1724
|
-
return false;
|
|
1725
|
-
};
|
|
1726
|
-
const setSupportNoticeShown = () => {
|
|
1727
|
-
if (typeof globalThis !== 'undefined') globalThis[SUPPORT_NOTICE_KEY] = true;
|
|
1728
|
-
};
|
|
1729
|
-
const usesLocize = inst => {
|
|
1730
|
-
if (inst?.modules?.backend?.name?.indexOf('Locize') > 0) return true;
|
|
1731
|
-
if (inst?.modules?.backend?.constructor?.name?.indexOf('Locize') > 0) return true;
|
|
1732
|
-
if (inst?.options?.backend?.backends) {
|
|
1733
|
-
if (inst.options.backend.backends.some(b => b?.name?.indexOf('Locize') > 0 || b?.constructor?.name?.indexOf('Locize') > 0)) return true;
|
|
1734
|
-
}
|
|
1735
|
-
if (inst?.options?.backend?.projectId) return true;
|
|
1736
|
-
if (inst?.options?.backend?.backendOptions) {
|
|
1737
|
-
if (inst.options.backend.backendOptions.some(b => b?.projectId)) return true;
|
|
1738
|
-
}
|
|
1739
|
-
return false;
|
|
1740
|
-
};
|
|
1741
1727
|
class I18n extends EventEmitter {
|
|
1742
1728
|
constructor(options = {}, callback) {
|
|
1743
1729
|
super();
|
|
@@ -1767,7 +1753,7 @@ class I18n extends EventEmitter {
|
|
|
1767
1753
|
if (options.defaultNS == null && options.ns) {
|
|
1768
1754
|
if (isString(options.ns)) {
|
|
1769
1755
|
options.defaultNS = options.ns;
|
|
1770
|
-
} else if (options.ns.
|
|
1756
|
+
} else if (!options.ns.includes('translation')) {
|
|
1771
1757
|
options.defaultNS = options.ns[0];
|
|
1772
1758
|
}
|
|
1773
1759
|
}
|
|
@@ -1790,10 +1776,6 @@ class I18n extends EventEmitter {
|
|
|
1790
1776
|
if (typeof this.options.overloadTranslationOptionHandler !== 'function') {
|
|
1791
1777
|
this.options.overloadTranslationOptionHandler = defOpts.overloadTranslationOptionHandler;
|
|
1792
1778
|
}
|
|
1793
|
-
if (this.options.showSupportNotice !== false && !usesLocize(this) && !getSupportNoticeShown()) {
|
|
1794
|
-
if (typeof console !== 'undefined' && typeof console.info !== 'undefined') console.info('🌐 i18next is made possible by our own product, Locize — consider powering your project with managed localization (AI, CDN, integrations): https://locize.com 💙');
|
|
1795
|
-
setSupportNoticeShown();
|
|
1796
|
-
}
|
|
1797
1779
|
const createClassOnDemand = ClassOrObject => {
|
|
1798
1780
|
if (!ClassOrObject) return null;
|
|
1799
1781
|
if (typeof ClassOrObject === 'function') return new ClassOrObject();
|
|
@@ -1818,14 +1800,9 @@ class I18n extends EventEmitter {
|
|
|
1818
1800
|
s.resourceStore = this.store;
|
|
1819
1801
|
s.languageUtils = lu;
|
|
1820
1802
|
s.pluralResolver = new PluralResolver(lu, {
|
|
1821
|
-
prepend: this.options.pluralSeparator
|
|
1822
|
-
simplifyPluralSuffix: this.options.simplifyPluralSuffix
|
|
1803
|
+
prepend: this.options.pluralSeparator
|
|
1823
1804
|
});
|
|
1824
|
-
|
|
1825
|
-
if (usingLegacyFormatFunction) {
|
|
1826
|
-
this.logger.deprecate(`init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting`);
|
|
1827
|
-
}
|
|
1828
|
-
if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) {
|
|
1805
|
+
if (formatter) {
|
|
1829
1806
|
s.formatter = createClassOnDemand(formatter);
|
|
1830
1807
|
if (s.formatter.init) s.formatter.init(s, this.options);
|
|
1831
1808
|
this.options.interpolation.format = s.formatter.format.bind(s.formatter);
|
|
@@ -1908,7 +1885,7 @@ class I18n extends EventEmitter {
|
|
|
1908
1885
|
const lngs = this.services.languageUtils.toResolveHierarchy(lng);
|
|
1909
1886
|
lngs.forEach(l => {
|
|
1910
1887
|
if (l === 'cimode') return;
|
|
1911
|
-
if (toLoad.
|
|
1888
|
+
if (!toLoad.includes(l)) toLoad.push(l);
|
|
1912
1889
|
});
|
|
1913
1890
|
};
|
|
1914
1891
|
if (!usedLng) {
|
|
@@ -1973,16 +1950,16 @@ class I18n extends EventEmitter {
|
|
|
1973
1950
|
}
|
|
1974
1951
|
setResolvedLanguage(l) {
|
|
1975
1952
|
if (!l || !this.languages) return;
|
|
1976
|
-
if (['cimode', 'dev'].
|
|
1953
|
+
if (['cimode', 'dev'].includes(l)) return;
|
|
1977
1954
|
for (let li = 0; li < this.languages.length; li++) {
|
|
1978
1955
|
const lngInLngs = this.languages[li];
|
|
1979
|
-
if (['cimode', 'dev'].
|
|
1956
|
+
if (['cimode', 'dev'].includes(lngInLngs)) continue;
|
|
1980
1957
|
if (this.store.hasLanguageSomeTranslations(lngInLngs)) {
|
|
1981
1958
|
this.resolvedLanguage = lngInLngs;
|
|
1982
1959
|
break;
|
|
1983
1960
|
}
|
|
1984
1961
|
}
|
|
1985
|
-
if (!this.resolvedLanguage && this.languages.
|
|
1962
|
+
if (!this.resolvedLanguage && !this.languages.includes(l) && this.store.hasLanguageSomeTranslations(l)) {
|
|
1986
1963
|
this.resolvedLanguage = l;
|
|
1987
1964
|
this.languages.unshift(l);
|
|
1988
1965
|
}
|
|
@@ -2124,7 +2101,7 @@ class I18n extends EventEmitter {
|
|
|
2124
2101
|
}
|
|
2125
2102
|
if (isString(ns)) ns = [ns];
|
|
2126
2103
|
ns.forEach(n => {
|
|
2127
|
-
if (this.options.ns.
|
|
2104
|
+
if (!this.options.ns.includes(n)) this.options.ns.push(n);
|
|
2128
2105
|
});
|
|
2129
2106
|
this.loadResources(err => {
|
|
2130
2107
|
deferred.resolve();
|
|
@@ -2136,7 +2113,7 @@ class I18n extends EventEmitter {
|
|
|
2136
2113
|
const deferred = defer();
|
|
2137
2114
|
if (isString(lngs)) lngs = [lngs];
|
|
2138
2115
|
const preloaded = this.options.preload || [];
|
|
2139
|
-
const newLngs = lngs.filter(lng => preloaded.
|
|
2116
|
+
const newLngs = lngs.filter(lng => !preloaded.includes(lng) && this.services.languageUtils.isSupportedCode(lng));
|
|
2140
2117
|
if (!newLngs.length) {
|
|
2141
2118
|
if (callback) callback();
|
|
2142
2119
|
return Promise.resolve();
|
|
@@ -2161,7 +2138,7 @@ class I18n extends EventEmitter {
|
|
|
2161
2138
|
const rtlLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ug', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam', 'ckb'];
|
|
2162
2139
|
const languageUtils = this.services?.languageUtils || new LanguageUtil(get());
|
|
2163
2140
|
if (lng.toLowerCase().indexOf('-latn') > 1) return 'ltr';
|
|
2164
|
-
return rtlLngs.
|
|
2141
|
+
return rtlLngs.includes(languageUtils.getLanguagePartFromCode(lng)) || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
|
|
2165
2142
|
}
|
|
2166
2143
|
static createInstance(options = {}, callback) {
|
|
2167
2144
|
const instance = new I18n(options, callback);
|