react-i18next 17.0.5 → 17.0.7
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 +11 -2
- package/README.md +7 -7
- package/dist/amd/react-i18next.js +33 -19
- package/dist/amd/react-i18next.min.js +1 -1
- package/dist/commonjs/TransWithoutContext.js +18 -13
- package/dist/commonjs/useTranslation.js +3 -1
- package/dist/es/TransWithoutContext.js +18 -13
- package/dist/es/package.json +1 -1
- package/dist/es/useTranslation.js +3 -1
- package/dist/umd/react-i18next.js +33 -19
- package/dist/umd/react-i18next.min.js +1 -1
- package/package.json +3 -3
- package/react-i18next.js +33 -19
- package/react-i18next.min.js +1 -1
- package/src/TransWithoutContext.js +25 -30
- package/src/useTranslation.js +6 -0
|
@@ -26,17 +26,6 @@ const getChildren = node => {
|
|
|
26
26
|
};
|
|
27
27
|
const hasValidReactChildren = children => Array.isArray(children) && children.every(_react.isValidElement);
|
|
28
28
|
const getAsArray = data => Array.isArray(data) ? data : [data];
|
|
29
|
-
const hasNonKeepReactDescendant = (children, keepArray) => {
|
|
30
|
-
if (children == null) return false;
|
|
31
|
-
return getAsArray(children).some(child => {
|
|
32
|
-
if (!(0, _react.isValidElement)(child)) return false;
|
|
33
|
-
const props = child.props || {};
|
|
34
|
-
const propCount = Object.keys(props).length;
|
|
35
|
-
const isKeepEligible = keepArray.indexOf(child.type) > -1 && propCount <= 1 && !props.i18nIsDynamicList;
|
|
36
|
-
if (!isKeepEligible) return true;
|
|
37
|
-
return hasNonKeepReactDescendant(props.children, keepArray);
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
29
|
const mergeProps = (source, target) => {
|
|
41
30
|
const newTarget = {
|
|
42
31
|
...target
|
|
@@ -86,7 +75,7 @@ const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
|
|
|
86
75
|
stringNode += `<${childIndex}></${childIndex}>`;
|
|
87
76
|
return;
|
|
88
77
|
}
|
|
89
|
-
if (shouldKeepChild && childPropsCount <= 1
|
|
78
|
+
if (shouldKeepChild && childPropsCount <= 1) {
|
|
90
79
|
const cnt = (0, _utils.isString)(childChildren) ? childChildren : nodesToString(childChildren, i18nOptions, i18n, i18nKey);
|
|
91
80
|
stringNode += `<${type}>${cnt}</${type}>`;
|
|
92
81
|
return;
|
|
@@ -227,6 +216,7 @@ const renderNodes = (children, knownComponentsMap, targetString, i18n, i18nOptio
|
|
|
227
216
|
const mapAST = (reactNode, astNode, rootReactNode) => {
|
|
228
217
|
const reactNodes = getAsArray(reactNode);
|
|
229
218
|
const astNodes = getAsArray(astNode);
|
|
219
|
+
const keepTagOccurrence = {};
|
|
230
220
|
return astNodes.reduce((mem, node, i) => {
|
|
231
221
|
const translationContent = node.children?.[0]?.content && i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language);
|
|
232
222
|
if (node.type === 'tag') {
|
|
@@ -271,7 +261,22 @@ const renderNodes = (children, knownComponentsMap, targetString, i18n, i18nOptio
|
|
|
271
261
|
key: `${node.name}-${i}`
|
|
272
262
|
}));
|
|
273
263
|
} else {
|
|
274
|
-
const
|
|
264
|
+
const occurrence = keepTagOccurrence[node.name] || 0;
|
|
265
|
+
keepTagOccurrence[node.name] = occurrence + 1;
|
|
266
|
+
let matched;
|
|
267
|
+
let seen = 0;
|
|
268
|
+
for (let r = 0; r < reactNodes.length; r += 1) {
|
|
269
|
+
const rn = reactNodes[r];
|
|
270
|
+
if ((0, _react.isValidElement)(rn) && rn.type === node.name) {
|
|
271
|
+
if (seen === occurrence) {
|
|
272
|
+
matched = rn;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
seen += 1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const innerScope = matched ? getAsArray(getChildren(matched)) : reactNodes;
|
|
279
|
+
const inner = mapAST(innerScope, node.children, rootReactNode);
|
|
275
280
|
mem.push((0, _react.createElement)(node.name, {
|
|
276
281
|
key: `${node.name}-${i}`
|
|
277
282
|
}, inner));
|
|
@@ -79,7 +79,9 @@ const useTranslation = (ns, props = {}) => {
|
|
|
79
79
|
if (lastSnapshot && lastSnapshot.ready === calculatedReady && lastSnapshot.lng === currentLng && lastSnapshot.keyPrefix === keyPrefix && lastSnapshot.revision === currentRevision) {
|
|
80
80
|
return lastSnapshot;
|
|
81
81
|
}
|
|
82
|
-
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix
|
|
82
|
+
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix, {
|
|
83
|
+
scopeNs: namespaces
|
|
84
|
+
});
|
|
83
85
|
const newSnapshot = {
|
|
84
86
|
t: calculatedT,
|
|
85
87
|
ready: calculatedReady,
|
|
@@ -18,17 +18,6 @@ const getChildren = node => {
|
|
|
18
18
|
};
|
|
19
19
|
const hasValidReactChildren = children => Array.isArray(children) && children.every(isValidElement);
|
|
20
20
|
const getAsArray = data => Array.isArray(data) ? data : [data];
|
|
21
|
-
const hasNonKeepReactDescendant = (children, keepArray) => {
|
|
22
|
-
if (children == null) return false;
|
|
23
|
-
return getAsArray(children).some(child => {
|
|
24
|
-
if (!isValidElement(child)) return false;
|
|
25
|
-
const props = child.props || {};
|
|
26
|
-
const propCount = Object.keys(props).length;
|
|
27
|
-
const isKeepEligible = keepArray.indexOf(child.type) > -1 && propCount <= 1 && !props.i18nIsDynamicList;
|
|
28
|
-
if (!isKeepEligible) return true;
|
|
29
|
-
return hasNonKeepReactDescendant(props.children, keepArray);
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
21
|
const mergeProps = (source, target) => {
|
|
33
22
|
const newTarget = {
|
|
34
23
|
...target
|
|
@@ -78,7 +67,7 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
|
|
|
78
67
|
stringNode += `<${childIndex}></${childIndex}>`;
|
|
79
68
|
return;
|
|
80
69
|
}
|
|
81
|
-
if (shouldKeepChild && childPropsCount <= 1
|
|
70
|
+
if (shouldKeepChild && childPropsCount <= 1) {
|
|
82
71
|
const cnt = isString(childChildren) ? childChildren : nodesToString(childChildren, i18nOptions, i18n, i18nKey);
|
|
83
72
|
stringNode += `<${type}>${cnt}</${type}>`;
|
|
84
73
|
return;
|
|
@@ -218,6 +207,7 @@ const renderNodes = (children, knownComponentsMap, targetString, i18n, i18nOptio
|
|
|
218
207
|
const mapAST = (reactNode, astNode, rootReactNode) => {
|
|
219
208
|
const reactNodes = getAsArray(reactNode);
|
|
220
209
|
const astNodes = getAsArray(astNode);
|
|
210
|
+
const keepTagOccurrence = {};
|
|
221
211
|
return astNodes.reduce((mem, node, i) => {
|
|
222
212
|
const translationContent = node.children?.[0]?.content && i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language);
|
|
223
213
|
if (node.type === 'tag') {
|
|
@@ -262,7 +252,22 @@ const renderNodes = (children, knownComponentsMap, targetString, i18n, i18nOptio
|
|
|
262
252
|
key: `${node.name}-${i}`
|
|
263
253
|
}));
|
|
264
254
|
} else {
|
|
265
|
-
const
|
|
255
|
+
const occurrence = keepTagOccurrence[node.name] || 0;
|
|
256
|
+
keepTagOccurrence[node.name] = occurrence + 1;
|
|
257
|
+
let matched;
|
|
258
|
+
let seen = 0;
|
|
259
|
+
for (let r = 0; r < reactNodes.length; r += 1) {
|
|
260
|
+
const rn = reactNodes[r];
|
|
261
|
+
if (isValidElement(rn) && rn.type === node.name) {
|
|
262
|
+
if (seen === occurrence) {
|
|
263
|
+
matched = rn;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
seen += 1;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const innerScope = matched ? getAsArray(getChildren(matched)) : reactNodes;
|
|
270
|
+
const inner = mapAST(innerScope, node.children, rootReactNode);
|
|
266
271
|
mem.push(createElement(node.name, {
|
|
267
272
|
key: `${node.name}-${i}`
|
|
268
273
|
}, inner));
|
package/dist/es/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"17.0.
|
|
1
|
+
{"type":"module","version":"17.0.7"}
|
|
@@ -73,7 +73,9 @@ export const useTranslation = (ns, props = {}) => {
|
|
|
73
73
|
if (lastSnapshot && lastSnapshot.ready === calculatedReady && lastSnapshot.lng === currentLng && lastSnapshot.keyPrefix === keyPrefix && lastSnapshot.revision === currentRevision) {
|
|
74
74
|
return lastSnapshot;
|
|
75
75
|
}
|
|
76
|
-
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix
|
|
76
|
+
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix, {
|
|
77
|
+
scopeNs: namespaces
|
|
78
|
+
});
|
|
77
79
|
const newSnapshot = {
|
|
78
80
|
t: calculatedT,
|
|
79
81
|
ready: calculatedReady,
|
|
@@ -234,6 +234,7 @@
|
|
|
234
234
|
}
|
|
235
235
|
forward(args, lvl, prefix, debugOnly) {
|
|
236
236
|
if (debugOnly && !this.debug) return null;
|
|
237
|
+
args = args.map(a => isString$1(a) ? a.replace(/[\r\n\x00-\x1F\x7F]/g, ' ') : a);
|
|
237
238
|
if (isString$1(args[0])) args[0] = `${prefix}${this.prefix} ${args[0]}`;
|
|
238
239
|
return this.logger[lvl](args);
|
|
239
240
|
}
|
|
@@ -666,7 +667,7 @@
|
|
|
666
667
|
const resForMissing = missingKeyNoValueFallbackToKey && usedKey ? undefined : res;
|
|
667
668
|
const updateMissing = hasDefaultValue && defaultValue !== res && this.options.updateMissing;
|
|
668
669
|
if (usedKey || usedDefault || updateMissing) {
|
|
669
|
-
this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? defaultValue : res);
|
|
670
|
+
this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, needsPluralHandling && !updateMissing ? `${key}${this.pluralResolver.getSuffix(lng, opt.count, opt)}` : key, updateMissing ? defaultValue : res);
|
|
670
671
|
if (keySeparator) {
|
|
671
672
|
const fk = this.resolve(key, {
|
|
672
673
|
...opt,
|
|
@@ -1131,8 +1132,8 @@
|
|
|
1131
1132
|
this.prefix = prefix ? regexEscape(prefix) : prefixEscaped || '{{';
|
|
1132
1133
|
this.suffix = suffix ? regexEscape(suffix) : suffixEscaped || '}}';
|
|
1133
1134
|
this.formatSeparator = formatSeparator || ',';
|
|
1134
|
-
this.unescapePrefix = unescapeSuffix ? '' : unescapePrefix
|
|
1135
|
-
this.unescapeSuffix = this.unescapePrefix ? '' : unescapeSuffix
|
|
1135
|
+
this.unescapePrefix = unescapeSuffix ? '' : unescapePrefix ? regexEscape(unescapePrefix) : '-';
|
|
1136
|
+
this.unescapeSuffix = this.unescapePrefix ? '' : unescapeSuffix ? regexEscape(unescapeSuffix) : '';
|
|
1136
1137
|
this.nestingPrefix = nestingPrefix ? regexEscape(nestingPrefix) : nestingPrefixEscaped || regexEscape('$t(');
|
|
1137
1138
|
this.nestingSuffix = nestingSuffix ? regexEscape(nestingSuffix) : nestingSuffixEscaped || regexEscape(')');
|
|
1138
1139
|
this.nestingOptionsSeparator = nestingOptionsSeparator || ',';
|
|
@@ -1179,6 +1180,9 @@
|
|
|
1179
1180
|
});
|
|
1180
1181
|
};
|
|
1181
1182
|
this.resetRegExp();
|
|
1183
|
+
if (!this.escapeValue && typeof str === 'string' && /\$t\([^)]*\{[^}]*\{\{/.test(str)) {
|
|
1184
|
+
this.logger.warn('nesting options string contains interpolated variables with escapeValue: false — ' + 'if any of those values are attacker-controlled they can inject additional ' + 'nesting options (e.g. redirect lng/ns). Sanitise untrusted input before passing ' + 'it to t(), or keep escapeValue: true.');
|
|
1185
|
+
}
|
|
1182
1186
|
const missingInterpolationHandler = options?.missingInterpolationHandler || this.options.missingInterpolationHandler;
|
|
1183
1187
|
const skipOnVariables = options?.interpolation?.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables;
|
|
1184
1188
|
const todos = [{
|
|
@@ -1853,7 +1857,7 @@
|
|
|
1853
1857
|
deferred.resolve(t);
|
|
1854
1858
|
callback(err, t);
|
|
1855
1859
|
};
|
|
1856
|
-
if (this.languages && !this.isInitialized) return finish(null, this.t.bind(this));
|
|
1860
|
+
if ((this.languages || this.isLanguageChangingTo) && !this.isInitialized) return finish(null, this.t.bind(this));
|
|
1857
1861
|
this.changeLanguage(this.options.lng, finish);
|
|
1858
1862
|
};
|
|
1859
1863
|
if (this.options.resources || !this.options.initAsync) {
|
|
@@ -2008,7 +2012,8 @@
|
|
|
2008
2012
|
}
|
|
2009
2013
|
return deferred;
|
|
2010
2014
|
}
|
|
2011
|
-
getFixedT(lng, ns, keyPrefix) {
|
|
2015
|
+
getFixedT(lng, ns, keyPrefix, fixedOpts) {
|
|
2016
|
+
const scopeNs = fixedOpts?.scopeNs;
|
|
2012
2017
|
const fixedT = (key, opts, ...rest) => {
|
|
2013
2018
|
let o;
|
|
2014
2019
|
if (typeof opts !== 'object') {
|
|
@@ -2020,12 +2025,14 @@
|
|
|
2020
2025
|
}
|
|
2021
2026
|
o.lng = o.lng || fixedT.lng;
|
|
2022
2027
|
o.lngs = o.lngs || fixedT.lngs;
|
|
2028
|
+
const explicitCallNs = o.ns !== undefined && o.ns !== null;
|
|
2023
2029
|
o.ns = o.ns || fixedT.ns;
|
|
2024
2030
|
if (o.keyPrefix !== '') o.keyPrefix = o.keyPrefix || keyPrefix || fixedT.keyPrefix;
|
|
2025
2031
|
const selectorOpts = {
|
|
2026
2032
|
...this.options,
|
|
2027
2033
|
...o
|
|
2028
2034
|
};
|
|
2035
|
+
if (Array.isArray(scopeNs) && !explicitCallNs) selectorOpts.ns = scopeNs;
|
|
2029
2036
|
if (typeof o.keyPrefix === 'function') o.keyPrefix = keysFromSelector(o.keyPrefix, selectorOpts);
|
|
2030
2037
|
const keySeparator = this.options.keySeparator || '.';
|
|
2031
2038
|
let resultKey;
|
|
@@ -2476,17 +2483,6 @@
|
|
|
2476
2483
|
};
|
|
2477
2484
|
const hasValidReactChildren = children => Array.isArray(children) && children.every(React.isValidElement);
|
|
2478
2485
|
const getAsArray = data => Array.isArray(data) ? data : [data];
|
|
2479
|
-
const hasNonKeepReactDescendant = (children, keepArray) => {
|
|
2480
|
-
if (children == null) return false;
|
|
2481
|
-
return getAsArray(children).some(child => {
|
|
2482
|
-
if (!React.isValidElement(child)) return false;
|
|
2483
|
-
const props = child.props || {};
|
|
2484
|
-
const propCount = Object.keys(props).length;
|
|
2485
|
-
const isKeepEligible = keepArray.indexOf(child.type) > -1 && propCount <= 1 && !props.i18nIsDynamicList;
|
|
2486
|
-
if (!isKeepEligible) return true;
|
|
2487
|
-
return hasNonKeepReactDescendant(props.children, keepArray);
|
|
2488
|
-
});
|
|
2489
|
-
};
|
|
2490
2486
|
const mergeProps = (source, target) => {
|
|
2491
2487
|
const newTarget = {
|
|
2492
2488
|
...target
|
|
@@ -2536,7 +2532,7 @@
|
|
|
2536
2532
|
stringNode += `<${childIndex}></${childIndex}>`;
|
|
2537
2533
|
return;
|
|
2538
2534
|
}
|
|
2539
|
-
if (shouldKeepChild && childPropsCount <= 1
|
|
2535
|
+
if (shouldKeepChild && childPropsCount <= 1) {
|
|
2540
2536
|
const cnt = isString(childChildren) ? childChildren : nodesToString(childChildren, i18nOptions, i18n, i18nKey);
|
|
2541
2537
|
stringNode += `<${type}>${cnt}</${type}>`;
|
|
2542
2538
|
return;
|
|
@@ -2676,6 +2672,7 @@
|
|
|
2676
2672
|
const mapAST = (reactNode, astNode, rootReactNode) => {
|
|
2677
2673
|
const reactNodes = getAsArray(reactNode);
|
|
2678
2674
|
const astNodes = getAsArray(astNode);
|
|
2675
|
+
const keepTagOccurrence = {};
|
|
2679
2676
|
return astNodes.reduce((mem, node, i) => {
|
|
2680
2677
|
const translationContent = node.children?.[0]?.content && i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language);
|
|
2681
2678
|
if (node.type === 'tag') {
|
|
@@ -2720,7 +2717,22 @@
|
|
|
2720
2717
|
key: `${node.name}-${i}`
|
|
2721
2718
|
}));
|
|
2722
2719
|
} else {
|
|
2723
|
-
const
|
|
2720
|
+
const occurrence = keepTagOccurrence[node.name] || 0;
|
|
2721
|
+
keepTagOccurrence[node.name] = occurrence + 1;
|
|
2722
|
+
let matched;
|
|
2723
|
+
let seen = 0;
|
|
2724
|
+
for (let r = 0; r < reactNodes.length; r += 1) {
|
|
2725
|
+
const rn = reactNodes[r];
|
|
2726
|
+
if (React.isValidElement(rn) && rn.type === node.name) {
|
|
2727
|
+
if (seen === occurrence) {
|
|
2728
|
+
matched = rn;
|
|
2729
|
+
break;
|
|
2730
|
+
}
|
|
2731
|
+
seen += 1;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
const innerScope = matched ? getAsArray(getChildren(matched)) : reactNodes;
|
|
2735
|
+
const inner = mapAST(innerScope, node.children, rootReactNode);
|
|
2724
2736
|
mem.push(React.createElement(node.name, {
|
|
2725
2737
|
key: `${node.name}-${i}`
|
|
2726
2738
|
}, inner));
|
|
@@ -3612,7 +3624,9 @@
|
|
|
3612
3624
|
if (lastSnapshot && lastSnapshot.ready === calculatedReady && lastSnapshot.lng === currentLng && lastSnapshot.keyPrefix === keyPrefix && lastSnapshot.revision === currentRevision) {
|
|
3613
3625
|
return lastSnapshot;
|
|
3614
3626
|
}
|
|
3615
|
-
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix
|
|
3627
|
+
const calculatedT = i18n.getFixedT(currentLng, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix, {
|
|
3628
|
+
scopeNs: namespaces
|
|
3629
|
+
});
|
|
3616
3630
|
const newSnapshot = {
|
|
3617
3631
|
t: calculatedT,
|
|
3618
3632
|
ready: calculatedReady,
|