@fkui/i18next-translate 6.39.0 → 6.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +88 -90
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +88 -90
- package/dist/esm/index.js.map +1 -1
- package/dist/types/tsdoc-metadata.json +1 -1
- package/package.json +5 -5
package/dist/cjs/index.js
CHANGED
|
@@ -2080,7 +2080,7 @@ const defer = () => {
|
|
|
2080
2080
|
};
|
|
2081
2081
|
const makeString = object => {
|
|
2082
2082
|
if (object == null) return '';
|
|
2083
|
-
return
|
|
2083
|
+
return String(object);
|
|
2084
2084
|
};
|
|
2085
2085
|
const copy = (a, s, t) => {
|
|
2086
2086
|
a.forEach(m => {
|
|
@@ -2088,7 +2088,7 @@ const copy = (a, s, t) => {
|
|
|
2088
2088
|
});
|
|
2089
2089
|
};
|
|
2090
2090
|
const lastOfPathSeparatorRegExp = /###/g;
|
|
2091
|
-
const cleanKey = key => key && key.
|
|
2091
|
+
const cleanKey = key => key && key.includes('###') ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
|
|
2092
2092
|
const canNotTraverseDeeper = object => !object || isString(object);
|
|
2093
2093
|
const getLastOfPath = (object, path, Empty) => {
|
|
2094
2094
|
const stack = !isString(path) ? path : path.split('.');
|
|
@@ -2173,7 +2173,7 @@ const deepExtend = (target, source, overwrite) => {
|
|
|
2173
2173
|
return target;
|
|
2174
2174
|
};
|
|
2175
2175
|
const regexEscape = str => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
|
2176
|
-
|
|
2176
|
+
const _entityMap = {
|
|
2177
2177
|
'&': '&',
|
|
2178
2178
|
'<': '<',
|
|
2179
2179
|
'>': '>',
|
|
@@ -2212,7 +2212,7 @@ const looksLikeObjectPathRegExpCache = new RegExpCache(20);
|
|
|
2212
2212
|
const looksLikeObjectPath = (key, nsSeparator, keySeparator) => {
|
|
2213
2213
|
nsSeparator = nsSeparator || '';
|
|
2214
2214
|
keySeparator = keySeparator || '';
|
|
2215
|
-
const possibleChars = chars.filter(c => nsSeparator.
|
|
2215
|
+
const possibleChars = chars.filter(c => !nsSeparator.includes(c) && !keySeparator.includes(c));
|
|
2216
2216
|
if (possibleChars.length === 0) return true;
|
|
2217
2217
|
const r = looksLikeObjectPathRegExpCache.getRegExp(`(${possibleChars.map(c => c === '?' ? '\\?' : c).join('|')})`);
|
|
2218
2218
|
let matched = !r.test(key);
|
|
@@ -2245,7 +2245,7 @@ const deepFind = (obj, path, keySeparator = '.') => {
|
|
|
2245
2245
|
nextPath += tokens[j];
|
|
2246
2246
|
next = current[nextPath];
|
|
2247
2247
|
if (next !== undefined) {
|
|
2248
|
-
if (['string', 'number', 'boolean'].
|
|
2248
|
+
if (['string', 'number', 'boolean'].includes(typeof next) && j < tokens.length - 1) {
|
|
2249
2249
|
continue;
|
|
2250
2250
|
}
|
|
2251
2251
|
i += j - i + 1;
|
|
@@ -2336,6 +2336,14 @@ class EventEmitter {
|
|
|
2336
2336
|
}
|
|
2337
2337
|
this.observers[event].delete(listener);
|
|
2338
2338
|
}
|
|
2339
|
+
once(event, listener) {
|
|
2340
|
+
const wrapper = (...args) => {
|
|
2341
|
+
listener(...args);
|
|
2342
|
+
this.off(event, wrapper);
|
|
2343
|
+
};
|
|
2344
|
+
this.on(event, wrapper);
|
|
2345
|
+
return this;
|
|
2346
|
+
}
|
|
2339
2347
|
emit(event, ...args) {
|
|
2340
2348
|
if (this.observers[event]) {
|
|
2341
2349
|
const cloned = Array.from(this.observers[event].entries());
|
|
@@ -2349,7 +2357,7 @@ class EventEmitter {
|
|
|
2349
2357
|
const cloned = Array.from(this.observers['*'].entries());
|
|
2350
2358
|
cloned.forEach(([observer, numTimesAdded]) => {
|
|
2351
2359
|
for (let i = 0; i < numTimesAdded; i++) {
|
|
2352
|
-
observer
|
|
2360
|
+
observer(event, ...args);
|
|
2353
2361
|
}
|
|
2354
2362
|
});
|
|
2355
2363
|
}
|
|
@@ -2372,7 +2380,7 @@ class ResourceStore extends EventEmitter {
|
|
|
2372
2380
|
}
|
|
2373
2381
|
}
|
|
2374
2382
|
addNamespaces(ns) {
|
|
2375
|
-
if (this.options.ns.
|
|
2383
|
+
if (!this.options.ns.includes(ns)) {
|
|
2376
2384
|
this.options.ns.push(ns);
|
|
2377
2385
|
}
|
|
2378
2386
|
}
|
|
@@ -2386,7 +2394,7 @@ class ResourceStore extends EventEmitter {
|
|
|
2386
2394
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
2387
2395
|
const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
|
|
2388
2396
|
let path;
|
|
2389
|
-
if (lng.
|
|
2397
|
+
if (lng.includes('.')) {
|
|
2390
2398
|
path = lng.split('.');
|
|
2391
2399
|
} else {
|
|
2392
2400
|
path = [lng, ns];
|
|
@@ -2401,7 +2409,7 @@ class ResourceStore extends EventEmitter {
|
|
|
2401
2409
|
}
|
|
2402
2410
|
}
|
|
2403
2411
|
const result = getPath(this.data, path);
|
|
2404
|
-
if (!result && !ns && !key && lng.
|
|
2412
|
+
if (!result && !ns && !key && lng.includes('.')) {
|
|
2405
2413
|
lng = path[0];
|
|
2406
2414
|
ns = path[1];
|
|
2407
2415
|
key = path.slice(2).join('.');
|
|
@@ -2415,7 +2423,7 @@ class ResourceStore extends EventEmitter {
|
|
|
2415
2423
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
2416
2424
|
let path = [lng, ns];
|
|
2417
2425
|
if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key);
|
|
2418
|
-
if (lng.
|
|
2426
|
+
if (lng.includes('.')) {
|
|
2419
2427
|
path = lng.split('.');
|
|
2420
2428
|
value = ns;
|
|
2421
2429
|
ns = path[1];
|
|
@@ -2439,7 +2447,7 @@ class ResourceStore extends EventEmitter {
|
|
|
2439
2447
|
skipCopy: false
|
|
2440
2448
|
}) {
|
|
2441
2449
|
let path = [lng, ns];
|
|
2442
|
-
if (lng.
|
|
2450
|
+
if (lng.includes('.')) {
|
|
2443
2451
|
path = lng.split('.');
|
|
2444
2452
|
deep = resources;
|
|
2445
2453
|
resources = ns;
|
|
@@ -2517,10 +2525,18 @@ function keysFromSelector(selector, opts) {
|
|
|
2517
2525
|
const {
|
|
2518
2526
|
[PATH_KEY]: path
|
|
2519
2527
|
} = selector(createProxy());
|
|
2520
|
-
|
|
2528
|
+
const keySeparator = opts?.keySeparator ?? '.';
|
|
2529
|
+
const nsSeparator = opts?.nsSeparator ?? ':';
|
|
2530
|
+
if (path.length > 1 && nsSeparator) {
|
|
2531
|
+
const ns = opts?.ns;
|
|
2532
|
+
const nsArray = Array.isArray(ns) ? ns : null;
|
|
2533
|
+
if (nsArray && nsArray.length > 1 && nsArray.slice(1).includes(path[0])) {
|
|
2534
|
+
return `${path[0]}${nsSeparator}${path.slice(1).join(keySeparator)}`;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return path.join(keySeparator);
|
|
2521
2538
|
}
|
|
2522
2539
|
|
|
2523
|
-
const checkedLoadedFor = {};
|
|
2524
2540
|
const shouldHandleAsObject = res => !isString(res) && typeof res !== 'boolean' && typeof res !== 'number';
|
|
2525
2541
|
class Translator extends EventEmitter {
|
|
2526
2542
|
constructor(services, options = {}) {
|
|
@@ -2531,6 +2547,7 @@ class Translator extends EventEmitter {
|
|
|
2531
2547
|
this.options.keySeparator = '.';
|
|
2532
2548
|
}
|
|
2533
2549
|
this.logger = baseLogger.create('translator');
|
|
2550
|
+
this.checkedLoadedFor = {};
|
|
2534
2551
|
}
|
|
2535
2552
|
changeLanguage(lng) {
|
|
2536
2553
|
if (lng) this.language = lng;
|
|
@@ -2555,7 +2572,7 @@ class Translator extends EventEmitter {
|
|
|
2555
2572
|
if (nsSeparator === undefined) nsSeparator = ':';
|
|
2556
2573
|
const keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
|
|
2557
2574
|
let namespaces = opt.ns || this.options.defaultNS || [];
|
|
2558
|
-
const wouldCheckForNsInKey = nsSeparator && key.
|
|
2575
|
+
const wouldCheckForNsInKey = nsSeparator && key.includes(nsSeparator);
|
|
2559
2576
|
const seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !opt.keySeparator && !this.options.userDefinedNsSeparator && !opt.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator);
|
|
2560
2577
|
if (wouldCheckForNsInKey && !seemsNaturalLanguage) {
|
|
2561
2578
|
const m = key.match(this.interpolator.nestingRegexp);
|
|
@@ -2566,7 +2583,7 @@ class Translator extends EventEmitter {
|
|
|
2566
2583
|
};
|
|
2567
2584
|
}
|
|
2568
2585
|
const parts = key.split(nsSeparator);
|
|
2569
|
-
if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.
|
|
2586
|
+
if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.includes(parts[0])) namespaces = parts.shift();
|
|
2570
2587
|
key = parts.join(keySeparator);
|
|
2571
2588
|
}
|
|
2572
2589
|
return {
|
|
@@ -2591,6 +2608,10 @@ class Translator extends EventEmitter {
|
|
|
2591
2608
|
...opt
|
|
2592
2609
|
});
|
|
2593
2610
|
if (!Array.isArray(keys)) keys = [String(keys)];
|
|
2611
|
+
keys = keys.map(k => typeof k === 'function' ? keysFromSelector(k, {
|
|
2612
|
+
...this.options,
|
|
2613
|
+
...opt
|
|
2614
|
+
}) : String(k));
|
|
2594
2615
|
const returnDetails = opt.returnDetails !== undefined ? opt.returnDetails : this.options.returnDetails;
|
|
2595
2616
|
const keySeparator = opt.keySeparator !== undefined ? opt.keySeparator : this.options.keySeparator;
|
|
2596
2617
|
const {
|
|
@@ -2649,7 +2670,7 @@ class Translator extends EventEmitter {
|
|
|
2649
2670
|
}
|
|
2650
2671
|
const handleAsObject = shouldHandleAsObject(resForObjHndl);
|
|
2651
2672
|
const resType = Object.prototype.toString.apply(resForObjHndl);
|
|
2652
|
-
if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && noObject.
|
|
2673
|
+
if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && !noObject.includes(resType) && !(isString(joinArrays) && Array.isArray(resForObjHndl))) {
|
|
2653
2674
|
if (!opt.returnObjects && !this.options.returnObjects) {
|
|
2654
2675
|
if (!this.options.returnedObjectHandler) {
|
|
2655
2676
|
this.logger.warn('accessing an object - but returnObjects options is not enabled!');
|
|
@@ -2745,7 +2766,7 @@ class Translator extends EventEmitter {
|
|
|
2745
2766
|
if (this.options.saveMissingPlurals && needsPluralHandling) {
|
|
2746
2767
|
lngs.forEach(language => {
|
|
2747
2768
|
const suffixes = this.pluralResolver.getSuffixes(language, opt);
|
|
2748
|
-
if (needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.
|
|
2769
|
+
if (needsZeroSuffixLookup && opt[`defaultValue${this.options.pluralSeparator}zero`] && !suffixes.includes(`${this.options.pluralSeparator}zero`)) {
|
|
2749
2770
|
suffixes.push(`${this.options.pluralSeparator}zero`);
|
|
2750
2771
|
}
|
|
2751
2772
|
suffixes.forEach(suffix => {
|
|
@@ -2837,6 +2858,10 @@ class Translator extends EventEmitter {
|
|
|
2837
2858
|
let usedLng;
|
|
2838
2859
|
let usedNS;
|
|
2839
2860
|
if (isString(keys)) keys = [keys];
|
|
2861
|
+
if (Array.isArray(keys)) keys = keys.map(k => typeof k === 'function' ? keysFromSelector(k, {
|
|
2862
|
+
...this.options,
|
|
2863
|
+
...opt
|
|
2864
|
+
}) : k);
|
|
2840
2865
|
keys.forEach(k => {
|
|
2841
2866
|
if (this.isValidLookup(found)) return;
|
|
2842
2867
|
const extracted = this.extractFromKey(k, opt);
|
|
@@ -2851,8 +2876,8 @@ class Translator extends EventEmitter {
|
|
|
2851
2876
|
namespaces.forEach(ns => {
|
|
2852
2877
|
if (this.isValidLookup(found)) return;
|
|
2853
2878
|
usedNS = ns;
|
|
2854
|
-
if (!checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) {
|
|
2855
|
-
checkedLoadedFor[`${codes[0]}-${ns}`] = true;
|
|
2879
|
+
if (!this.checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) {
|
|
2880
|
+
this.checkedLoadedFor[`${codes[0]}-${ns}`] = true;
|
|
2856
2881
|
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!!!');
|
|
2857
2882
|
}
|
|
2858
2883
|
codes.forEach(code => {
|
|
@@ -2867,7 +2892,7 @@ class Translator extends EventEmitter {
|
|
|
2867
2892
|
const zeroSuffix = `${this.options.pluralSeparator}zero`;
|
|
2868
2893
|
const ordinalPrefix = `${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;
|
|
2869
2894
|
if (needsPluralHandling) {
|
|
2870
|
-
if (opt.ordinal && pluralSuffix.
|
|
2895
|
+
if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
|
|
2871
2896
|
finalKeys.push(key + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
|
|
2872
2897
|
}
|
|
2873
2898
|
finalKeys.push(key + pluralSuffix);
|
|
@@ -2879,7 +2904,7 @@ class Translator extends EventEmitter {
|
|
|
2879
2904
|
const contextKey = `${key}${this.options.contextSeparator || '_'}${opt.context}`;
|
|
2880
2905
|
finalKeys.push(contextKey);
|
|
2881
2906
|
if (needsPluralHandling) {
|
|
2882
|
-
if (opt.ordinal && pluralSuffix.
|
|
2907
|
+
if (opt.ordinal && pluralSuffix.startsWith(ordinalPrefix)) {
|
|
2883
2908
|
finalKeys.push(contextKey + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator));
|
|
2884
2909
|
}
|
|
2885
2910
|
finalKeys.push(contextKey + pluralSuffix);
|
|
@@ -2940,7 +2965,7 @@ class Translator extends EventEmitter {
|
|
|
2940
2965
|
static hasDefaultValue(options) {
|
|
2941
2966
|
const prefix = 'defaultValue';
|
|
2942
2967
|
for (const option in options) {
|
|
2943
|
-
if (Object.prototype.hasOwnProperty.call(options, option) &&
|
|
2968
|
+
if (Object.prototype.hasOwnProperty.call(options, option) && option.startsWith(prefix) && undefined !== options[option]) {
|
|
2944
2969
|
return true;
|
|
2945
2970
|
}
|
|
2946
2971
|
}
|
|
@@ -2956,7 +2981,7 @@ class LanguageUtil {
|
|
|
2956
2981
|
}
|
|
2957
2982
|
getScriptPartFromCode(code) {
|
|
2958
2983
|
code = getCleanedCode(code);
|
|
2959
|
-
if (!code || code.
|
|
2984
|
+
if (!code || !code.includes('-')) return null;
|
|
2960
2985
|
const p = code.split('-');
|
|
2961
2986
|
if (p.length === 2) return null;
|
|
2962
2987
|
p.pop();
|
|
@@ -2965,12 +2990,12 @@ class LanguageUtil {
|
|
|
2965
2990
|
}
|
|
2966
2991
|
getLanguagePartFromCode(code) {
|
|
2967
2992
|
code = getCleanedCode(code);
|
|
2968
|
-
if (!code || code.
|
|
2993
|
+
if (!code || !code.includes('-')) return code;
|
|
2969
2994
|
const p = code.split('-');
|
|
2970
2995
|
return this.formatLanguageCode(p[0]);
|
|
2971
2996
|
}
|
|
2972
2997
|
formatLanguageCode(code) {
|
|
2973
|
-
if (isString(code) && code.
|
|
2998
|
+
if (isString(code) && code.includes('-')) {
|
|
2974
2999
|
let formattedCode;
|
|
2975
3000
|
try {
|
|
2976
3001
|
formattedCode = Intl.getCanonicalLocales(code)[0];
|
|
@@ -2990,7 +3015,7 @@ class LanguageUtil {
|
|
|
2990
3015
|
if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) {
|
|
2991
3016
|
code = this.getLanguagePartFromCode(code);
|
|
2992
3017
|
}
|
|
2993
|
-
return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.
|
|
3018
|
+
return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.includes(code);
|
|
2994
3019
|
}
|
|
2995
3020
|
getBestMatchFromCodes(codes) {
|
|
2996
3021
|
if (!codes) return null;
|
|
@@ -3008,10 +3033,11 @@ class LanguageUtil {
|
|
|
3008
3033
|
const lngOnly = this.getLanguagePartFromCode(code);
|
|
3009
3034
|
if (this.isSupportedCode(lngOnly)) return found = lngOnly;
|
|
3010
3035
|
found = this.options.supportedLngs.find(supportedLng => {
|
|
3011
|
-
if (supportedLng === lngOnly) return
|
|
3012
|
-
if (supportedLng.
|
|
3013
|
-
if (supportedLng.
|
|
3014
|
-
if (supportedLng.
|
|
3036
|
+
if (supportedLng === lngOnly) return true;
|
|
3037
|
+
if (!supportedLng.includes('-') && !lngOnly.includes('-')) return false;
|
|
3038
|
+
if (supportedLng.includes('-') && !lngOnly.includes('-') && supportedLng.slice(0, supportedLng.indexOf('-')) === lngOnly) return true;
|
|
3039
|
+
if (supportedLng.startsWith(lngOnly) && lngOnly.length > 1) return true;
|
|
3040
|
+
return false;
|
|
3015
3041
|
});
|
|
3016
3042
|
});
|
|
3017
3043
|
}
|
|
@@ -3042,7 +3068,7 @@ class LanguageUtil {
|
|
|
3042
3068
|
this.logger.warn(`rejecting language code not found in supportedLngs: ${c}`);
|
|
3043
3069
|
}
|
|
3044
3070
|
};
|
|
3045
|
-
if (isString(code) && (code.
|
|
3071
|
+
if (isString(code) && (code.includes('-') || code.includes('_'))) {
|
|
3046
3072
|
if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code));
|
|
3047
3073
|
if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code));
|
|
3048
3074
|
if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code));
|
|
@@ -3050,7 +3076,7 @@ class LanguageUtil {
|
|
|
3050
3076
|
addCode(this.formatLanguageCode(code));
|
|
3051
3077
|
}
|
|
3052
3078
|
fallbackCodes.forEach(fc => {
|
|
3053
|
-
if (codes.
|
|
3079
|
+
if (!codes.includes(fc)) addCode(this.formatLanguageCode(fc));
|
|
3054
3080
|
});
|
|
3055
3081
|
return codes;
|
|
3056
3082
|
}
|
|
@@ -3206,7 +3232,7 @@ class Interpolator {
|
|
|
3206
3232
|
let replaces;
|
|
3207
3233
|
const defaultData = this.options && this.options.interpolation && this.options.interpolation.defaultVariables || {};
|
|
3208
3234
|
const handleFormat = key => {
|
|
3209
|
-
if (key.
|
|
3235
|
+
if (!key.includes(this.formatSeparator)) {
|
|
3210
3236
|
const path = deepFindWithDefaults(data, defaultData, key, this.options.keySeparator, this.options.ignoreJSONStructure);
|
|
3211
3237
|
return this.alwaysFormat ? this.format(path, undefined, lng, {
|
|
3212
3238
|
...options,
|
|
@@ -3276,7 +3302,7 @@ class Interpolator {
|
|
|
3276
3302
|
let clonedOptions;
|
|
3277
3303
|
const handleHasOptions = (key, inheritedOptions) => {
|
|
3278
3304
|
const sep = this.nestingOptionsSeparator;
|
|
3279
|
-
if (key.
|
|
3305
|
+
if (!key.includes(sep)) return key;
|
|
3280
3306
|
const c = key.split(new RegExp(`${regexEscape(sep)}[ ]*{`));
|
|
3281
3307
|
let optionsString = `{${c[1]}`;
|
|
3282
3308
|
key = c[0];
|
|
@@ -3296,7 +3322,7 @@ class Interpolator {
|
|
|
3296
3322
|
this.logger.warn(`failed parsing options string in nesting for key ${key}`, e);
|
|
3297
3323
|
return `${key}${sep}${optionsString}`;
|
|
3298
3324
|
}
|
|
3299
|
-
if (clonedOptions.defaultValue && clonedOptions.defaultValue.
|
|
3325
|
+
if (clonedOptions.defaultValue && clonedOptions.defaultValue.includes(this.prefix)) delete clonedOptions.defaultValue;
|
|
3300
3326
|
return key;
|
|
3301
3327
|
};
|
|
3302
3328
|
while (match = this.nestingRegexp.exec(str)) {
|
|
@@ -3335,13 +3361,13 @@ class Interpolator {
|
|
|
3335
3361
|
const parseFormatStr = formatStr => {
|
|
3336
3362
|
let formatName = formatStr.toLowerCase().trim();
|
|
3337
3363
|
const formatOptions = {};
|
|
3338
|
-
if (formatStr.
|
|
3364
|
+
if (formatStr.includes('(')) {
|
|
3339
3365
|
const p = formatStr.split('(');
|
|
3340
3366
|
formatName = p[0].toLowerCase().trim();
|
|
3341
|
-
const optStr = p[1].
|
|
3342
|
-
if (formatName === 'currency' && optStr.
|
|
3367
|
+
const optStr = p[1].slice(0, -1);
|
|
3368
|
+
if (formatName === 'currency' && !optStr.includes(':')) {
|
|
3343
3369
|
if (!formatOptions.currency) formatOptions.currency = optStr.trim();
|
|
3344
|
-
} else if (formatName === 'relativetime' && optStr.
|
|
3370
|
+
} else if (formatName === 'relativetime' && !optStr.includes(':')) {
|
|
3345
3371
|
if (!formatOptions.range) formatOptions.range = optStr.trim();
|
|
3346
3372
|
} else {
|
|
3347
3373
|
const opts = optStr.split(';');
|
|
@@ -3435,9 +3461,11 @@ class Formatter {
|
|
|
3435
3461
|
this.formats[name.toLowerCase().trim()] = createCachedFormatter(fc);
|
|
3436
3462
|
}
|
|
3437
3463
|
format(value, format, lng, options = {}) {
|
|
3464
|
+
if (!format) return value;
|
|
3465
|
+
if (value == null) return value;
|
|
3438
3466
|
const formats = format.split(this.formatSeparator);
|
|
3439
|
-
if (formats.length > 1 && formats[0].indexOf('(') > 1 && formats[0].
|
|
3440
|
-
const lastIndex = formats.findIndex(f => f.
|
|
3467
|
+
if (formats.length > 1 && formats[0].indexOf('(') > 1 && !formats[0].includes(')') && formats.find(f => f.includes(')'))) {
|
|
3468
|
+
const lastIndex = formats.findIndex(f => f.includes(')'));
|
|
3441
3469
|
formats[0] = [formats[0], ...formats.splice(1, lastIndex)].join(this.formatSeparator);
|
|
3442
3470
|
}
|
|
3443
3471
|
const result = formats.reduce((mem, f) => {
|
|
@@ -3591,7 +3619,7 @@ class Connector extends EventEmitter {
|
|
|
3591
3619
|
}
|
|
3592
3620
|
if (err && data && tried < this.maxRetries) {
|
|
3593
3621
|
setTimeout(() => {
|
|
3594
|
-
this.read
|
|
3622
|
+
this.read(lng, ns, fcName, tried + 1, wait * 2, callback);
|
|
3595
3623
|
}, wait);
|
|
3596
3624
|
return;
|
|
3597
3625
|
}
|
|
@@ -3695,7 +3723,6 @@ const get = () => ({
|
|
|
3695
3723
|
nonExplicitSupportedLngs: false,
|
|
3696
3724
|
load: 'all',
|
|
3697
3725
|
preload: false,
|
|
3698
|
-
simplifyPluralSuffix: true,
|
|
3699
3726
|
keySeparator: '.',
|
|
3700
3727
|
nsSeparator: ':',
|
|
3701
3728
|
pluralSeparator: '_',
|
|
@@ -3732,7 +3759,6 @@ const get = () => ({
|
|
|
3732
3759
|
},
|
|
3733
3760
|
interpolation: {
|
|
3734
3761
|
escapeValue: true,
|
|
3735
|
-
format: value => value,
|
|
3736
3762
|
prefix: '{{',
|
|
3737
3763
|
suffix: '}}',
|
|
3738
3764
|
formatSeparator: ',',
|
|
@@ -3749,10 +3775,9 @@ const transformOptions = options => {
|
|
|
3749
3775
|
if (isString(options.ns)) options.ns = [options.ns];
|
|
3750
3776
|
if (isString(options.fallbackLng)) options.fallbackLng = [options.fallbackLng];
|
|
3751
3777
|
if (isString(options.fallbackNS)) options.fallbackNS = [options.fallbackNS];
|
|
3752
|
-
if (options.supportedLngs
|
|
3778
|
+
if (options.supportedLngs && !options.supportedLngs.includes('cimode')) {
|
|
3753
3779
|
options.supportedLngs = options.supportedLngs.concat(['cimode']);
|
|
3754
3780
|
}
|
|
3755
|
-
if (typeof options.initImmediate === 'boolean') options.initAsync = options.initImmediate;
|
|
3756
3781
|
return options;
|
|
3757
3782
|
};
|
|
3758
3783
|
|
|
@@ -3765,23 +3790,6 @@ const bindMemberFunctions = inst => {
|
|
|
3765
3790
|
}
|
|
3766
3791
|
});
|
|
3767
3792
|
};
|
|
3768
|
-
const SUPPORT_NOTICE_KEY = '__i18next_supportNoticeShown';
|
|
3769
|
-
const getSupportNoticeShown = () => typeof globalThis !== 'undefined' && !!globalThis[SUPPORT_NOTICE_KEY];
|
|
3770
|
-
const setSupportNoticeShown = () => {
|
|
3771
|
-
if (typeof globalThis !== 'undefined') globalThis[SUPPORT_NOTICE_KEY] = true;
|
|
3772
|
-
};
|
|
3773
|
-
const usesLocize = inst => {
|
|
3774
|
-
if (inst?.modules?.backend?.name?.indexOf('Locize') > 0) return true;
|
|
3775
|
-
if (inst?.modules?.backend?.constructor?.name?.indexOf('Locize') > 0) return true;
|
|
3776
|
-
if (inst?.options?.backend?.backends) {
|
|
3777
|
-
if (inst.options.backend.backends.some(b => b?.name?.indexOf('Locize') > 0 || b?.constructor?.name?.indexOf('Locize') > 0)) return true;
|
|
3778
|
-
}
|
|
3779
|
-
if (inst?.options?.backend?.projectId) return true;
|
|
3780
|
-
if (inst?.options?.backend?.backendOptions) {
|
|
3781
|
-
if (inst.options.backend.backendOptions.some(b => b?.projectId)) return true;
|
|
3782
|
-
}
|
|
3783
|
-
return false;
|
|
3784
|
-
};
|
|
3785
3793
|
class I18n extends EventEmitter {
|
|
3786
3794
|
constructor(options = {}, callback) {
|
|
3787
3795
|
super();
|
|
@@ -3811,7 +3819,7 @@ class I18n extends EventEmitter {
|
|
|
3811
3819
|
if (options.defaultNS == null && options.ns) {
|
|
3812
3820
|
if (isString(options.ns)) {
|
|
3813
3821
|
options.defaultNS = options.ns;
|
|
3814
|
-
} else if (options.ns.
|
|
3822
|
+
} else if (!options.ns.includes('translation')) {
|
|
3815
3823
|
options.defaultNS = options.ns[0];
|
|
3816
3824
|
}
|
|
3817
3825
|
}
|
|
@@ -3834,10 +3842,6 @@ class I18n extends EventEmitter {
|
|
|
3834
3842
|
if (typeof this.options.overloadTranslationOptionHandler !== 'function') {
|
|
3835
3843
|
this.options.overloadTranslationOptionHandler = defOpts.overloadTranslationOptionHandler;
|
|
3836
3844
|
}
|
|
3837
|
-
if (this.options.showSupportNotice !== false && !usesLocize(this) && !getSupportNoticeShown()) {
|
|
3838
|
-
if (typeof console !== 'undefined' && typeof console.info !== 'undefined') console.info('🌐 i18next is maintained with support from Locize — consider powering your project with managed localization (AI, CDN, integrations): https://locize.com 💙');
|
|
3839
|
-
setSupportNoticeShown();
|
|
3840
|
-
}
|
|
3841
3845
|
const createClassOnDemand = ClassOrObject => {
|
|
3842
3846
|
if (!ClassOrObject) return null;
|
|
3843
3847
|
if (typeof ClassOrObject === 'function') return new ClassOrObject();
|
|
@@ -3862,14 +3866,9 @@ class I18n extends EventEmitter {
|
|
|
3862
3866
|
s.resourceStore = this.store;
|
|
3863
3867
|
s.languageUtils = lu;
|
|
3864
3868
|
s.pluralResolver = new PluralResolver(lu, {
|
|
3865
|
-
prepend: this.options.pluralSeparator
|
|
3866
|
-
simplifyPluralSuffix: this.options.simplifyPluralSuffix
|
|
3869
|
+
prepend: this.options.pluralSeparator
|
|
3867
3870
|
});
|
|
3868
|
-
|
|
3869
|
-
if (usingLegacyFormatFunction) {
|
|
3870
|
-
this.logger.deprecate(`init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting`);
|
|
3871
|
-
}
|
|
3872
|
-
if (formatter && (!this.options.interpolation.format || this.options.interpolation.format === defOpts.interpolation.format)) {
|
|
3871
|
+
if (formatter) {
|
|
3873
3872
|
s.formatter = createClassOnDemand(formatter);
|
|
3874
3873
|
if (s.formatter.init) s.formatter.init(s, this.options);
|
|
3875
3874
|
this.options.interpolation.format = s.formatter.format.bind(s.formatter);
|
|
@@ -3952,7 +3951,7 @@ class I18n extends EventEmitter {
|
|
|
3952
3951
|
const lngs = this.services.languageUtils.toResolveHierarchy(lng);
|
|
3953
3952
|
lngs.forEach(l => {
|
|
3954
3953
|
if (l === 'cimode') return;
|
|
3955
|
-
if (toLoad.
|
|
3954
|
+
if (!toLoad.includes(l)) toLoad.push(l);
|
|
3956
3955
|
});
|
|
3957
3956
|
};
|
|
3958
3957
|
if (!usedLng) {
|
|
@@ -4017,16 +4016,16 @@ class I18n extends EventEmitter {
|
|
|
4017
4016
|
}
|
|
4018
4017
|
setResolvedLanguage(l) {
|
|
4019
4018
|
if (!l || !this.languages) return;
|
|
4020
|
-
if (['cimode', 'dev'].
|
|
4019
|
+
if (['cimode', 'dev'].includes(l)) return;
|
|
4021
4020
|
for (let li = 0; li < this.languages.length; li++) {
|
|
4022
4021
|
const lngInLngs = this.languages[li];
|
|
4023
|
-
if (['cimode', 'dev'].
|
|
4022
|
+
if (['cimode', 'dev'].includes(lngInLngs)) continue;
|
|
4024
4023
|
if (this.store.hasLanguageSomeTranslations(lngInLngs)) {
|
|
4025
4024
|
this.resolvedLanguage = lngInLngs;
|
|
4026
4025
|
break;
|
|
4027
4026
|
}
|
|
4028
4027
|
}
|
|
4029
|
-
if (!this.resolvedLanguage && this.languages.
|
|
4028
|
+
if (!this.resolvedLanguage && !this.languages.includes(l) && this.store.hasLanguageSomeTranslations(l)) {
|
|
4030
4029
|
this.resolvedLanguage = l;
|
|
4031
4030
|
this.languages.unshift(l);
|
|
4032
4031
|
}
|
|
@@ -4098,21 +4097,20 @@ class I18n extends EventEmitter {
|
|
|
4098
4097
|
o.lngs = o.lngs || fixedT.lngs;
|
|
4099
4098
|
o.ns = o.ns || fixedT.ns;
|
|
4100
4099
|
if (o.keyPrefix !== '') o.keyPrefix = o.keyPrefix || keyPrefix || fixedT.keyPrefix;
|
|
4100
|
+
const selectorOpts = {
|
|
4101
|
+
...this.options,
|
|
4102
|
+
...o
|
|
4103
|
+
};
|
|
4104
|
+
if (typeof o.keyPrefix === 'function') o.keyPrefix = keysFromSelector(o.keyPrefix, selectorOpts);
|
|
4101
4105
|
const keySeparator = this.options.keySeparator || '.';
|
|
4102
4106
|
let resultKey;
|
|
4103
4107
|
if (o.keyPrefix && Array.isArray(key)) {
|
|
4104
4108
|
resultKey = key.map(k => {
|
|
4105
|
-
if (typeof k === 'function') k = keysFromSelector(k,
|
|
4106
|
-
...this.options,
|
|
4107
|
-
...opts
|
|
4108
|
-
});
|
|
4109
|
+
if (typeof k === 'function') k = keysFromSelector(k, selectorOpts);
|
|
4109
4110
|
return `${o.keyPrefix}${keySeparator}${k}`;
|
|
4110
4111
|
});
|
|
4111
4112
|
} else {
|
|
4112
|
-
if (typeof key === 'function') key = keysFromSelector(key,
|
|
4113
|
-
...this.options,
|
|
4114
|
-
...opts
|
|
4115
|
-
});
|
|
4113
|
+
if (typeof key === 'function') key = keysFromSelector(key, selectorOpts);
|
|
4116
4114
|
resultKey = o.keyPrefix ? `${o.keyPrefix}${keySeparator}${key}` : key;
|
|
4117
4115
|
}
|
|
4118
4116
|
return this.t(resultKey, o);
|
|
@@ -4169,7 +4167,7 @@ class I18n extends EventEmitter {
|
|
|
4169
4167
|
}
|
|
4170
4168
|
if (isString(ns)) ns = [ns];
|
|
4171
4169
|
ns.forEach(n => {
|
|
4172
|
-
if (this.options.ns.
|
|
4170
|
+
if (!this.options.ns.includes(n)) this.options.ns.push(n);
|
|
4173
4171
|
});
|
|
4174
4172
|
this.loadResources(err => {
|
|
4175
4173
|
deferred.resolve();
|
|
@@ -4181,7 +4179,7 @@ class I18n extends EventEmitter {
|
|
|
4181
4179
|
const deferred = defer();
|
|
4182
4180
|
if (isString(lngs)) lngs = [lngs];
|
|
4183
4181
|
const preloaded = this.options.preload || [];
|
|
4184
|
-
const newLngs = lngs.filter(lng => preloaded.
|
|
4182
|
+
const newLngs = lngs.filter(lng => !preloaded.includes(lng) && this.services.languageUtils.isSupportedCode(lng));
|
|
4185
4183
|
if (!newLngs.length) {
|
|
4186
4184
|
if (callback) callback();
|
|
4187
4185
|
return Promise.resolve();
|
|
@@ -4206,7 +4204,7 @@ class I18n extends EventEmitter {
|
|
|
4206
4204
|
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'];
|
|
4207
4205
|
const languageUtils = this.services?.languageUtils || new LanguageUtil(get());
|
|
4208
4206
|
if (lng.toLowerCase().indexOf('-latn') > 1) return 'ltr';
|
|
4209
|
-
return rtlLngs.
|
|
4207
|
+
return rtlLngs.includes(languageUtils.getLanguagePartFromCode(lng)) || lng.toLowerCase().indexOf('-arab') > 1 ? 'rtl' : 'ltr';
|
|
4210
4208
|
}
|
|
4211
4209
|
static createInstance(options = {}, callback) {
|
|
4212
4210
|
const instance = new I18n(options, callback);
|