i18next-cli 1.56.6 → 1.56.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/dist/cjs/cli.js +1 -1
- package/dist/cjs/extractor/core/translation-manager.js +15 -4
- package/dist/cjs/extractor/parsers/call-expression-handler.js +17 -15
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/core/translation-manager.js +15 -4
- package/dist/esm/extractor/parsers/call-expression-handler.js +17 -15
- package/package.json +2 -2
- package/types/extractor/core/translation-manager.d.ts.map +1 -1
- package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
package/dist/cjs/cli.js
CHANGED
|
@@ -32,7 +32,7 @@ const program = new commander.Command();
|
|
|
32
32
|
program
|
|
33
33
|
.name('i18next-cli')
|
|
34
34
|
.description('A unified, high-performance i18next CLI.')
|
|
35
|
-
.version('1.56.
|
|
35
|
+
.version('1.56.8'); // This string is replaced with the actual version at build time by rollup
|
|
36
36
|
// new: global config override option
|
|
37
37
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
38
38
|
program
|
|
@@ -749,11 +749,23 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
749
749
|
}
|
|
750
750
|
}
|
|
751
751
|
else {
|
|
752
|
+
// A key is a synthesized plural variant only when the extractor flagged it
|
|
753
|
+
// with `hasCount` AND its suffix matches a CLDR plural form. Relying purely
|
|
754
|
+
// on the presence of the separator misclassifies regular keys that happen to
|
|
755
|
+
// contain `_` (e.g. `abc_123`) — see issue #250. Context variants are caught
|
|
756
|
+
// by `isDerivedDefault` below (their synthesized default mirrors the base key).
|
|
757
|
+
const isVariantKey = (() => {
|
|
758
|
+
if (!hasCount)
|
|
759
|
+
return false;
|
|
760
|
+
const parts = key.split(pluralSeparator);
|
|
761
|
+
if (parts.length < 2)
|
|
762
|
+
return false;
|
|
763
|
+
return pluralForms.includes(parts[parts.length - 1]);
|
|
764
|
+
})();
|
|
752
765
|
// Existing value exists - decide whether to preserve, sync primary, or clear other locales when requested
|
|
753
766
|
if (locale === primaryLanguage && syncPrimaryWithDefaults) {
|
|
754
|
-
// If this key
|
|
755
|
-
//
|
|
756
|
-
const isVariantKey = key.includes(pluralSeparator) || key.includes(contextSeparator);
|
|
767
|
+
// If this key is a plural/context variant and the default wasn't explicitly
|
|
768
|
+
// provided in source code, preserve the existing value.
|
|
757
769
|
if (isVariantKey && !explicitDefault) {
|
|
758
770
|
valueToSet = existingValue;
|
|
759
771
|
}
|
|
@@ -766,7 +778,6 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
766
778
|
}
|
|
767
779
|
else {
|
|
768
780
|
// Non-primary locale behavior
|
|
769
|
-
const isVariantKey = key.includes(pluralSeparator) || key.includes(contextSeparator);
|
|
770
781
|
// A plural variant whose category exists in the current locale but not in the
|
|
771
782
|
// primary language (e.g. French `_many` vs English `one`/`other`) will always be
|
|
772
783
|
// absent from the primary file by CLDR design. Treat that absence as expected —
|
|
@@ -68,21 +68,6 @@ class CallExpressionHandler {
|
|
|
68
68
|
return;
|
|
69
69
|
// The scope lookup will only work for simple identifiers, which is okay for this fix.
|
|
70
70
|
let scopeInfo = getScopeInfo(functionName);
|
|
71
|
-
// For member expressions like `emailError.t`, also try the object part(s) as a
|
|
72
|
-
// fallback. This lets custom hooks that return an object with a `t` method
|
|
73
|
-
// (e.g. `const emailError = useTranslateKeyState('auth')`) propagate their
|
|
74
|
-
// namespace/keyPrefix to the inner `t` call.
|
|
75
|
-
if (!scopeInfo && functionName.includes('.')) {
|
|
76
|
-
const parts = functionName.split('.');
|
|
77
|
-
for (let i = parts.length - 1; i > 0; i--) {
|
|
78
|
-
const candidate = parts.slice(0, i).join('.');
|
|
79
|
-
const candidateScope = getScopeInfo(candidate);
|
|
80
|
-
if (candidateScope) {
|
|
81
|
-
scopeInfo = candidateScope;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
71
|
const configuredFunctions = this.config.extract.functions || ['t', '*.t'];
|
|
87
72
|
let isFunctionToParse = scopeInfo !== undefined; // A scoped variable (from useTranslation, etc.) is always parsed.
|
|
88
73
|
if (!isFunctionToParse) {
|
|
@@ -105,6 +90,23 @@ class CallExpressionHandler {
|
|
|
105
90
|
}
|
|
106
91
|
if (!isFunctionToParse || node.arguments.length === 0)
|
|
107
92
|
return;
|
|
93
|
+
// For member expressions like `emailError.t`, also try the object part(s) as a
|
|
94
|
+
// fallback. This lets custom hooks that return an object with a `t` method
|
|
95
|
+
// (e.g. `const emailError = useTranslateKeyState('auth')`) propagate their
|
|
96
|
+
// namespace/keyPrefix to the inner `t` call. This runs AFTER the pattern
|
|
97
|
+
// check so an in-scope prefix cannot by itself promote an arbitrary method
|
|
98
|
+
// call (e.g. `i18n.language.substring(...)`) into a translation call.
|
|
99
|
+
if (!scopeInfo && functionName.includes('.')) {
|
|
100
|
+
const parts = functionName.split('.');
|
|
101
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
102
|
+
const candidate = parts.slice(0, i).join('.');
|
|
103
|
+
const candidateScope = getScopeInfo(candidate);
|
|
104
|
+
if (candidateScope) {
|
|
105
|
+
scopeInfo = candidateScope;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
108
110
|
const { keysToProcess, isSelectorAPI } = this.handleCallExpressionArgument(node, 0);
|
|
109
111
|
if (keysToProcess.length === 0)
|
|
110
112
|
return;
|
package/dist/esm/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ const program = new Command();
|
|
|
30
30
|
program
|
|
31
31
|
.name('i18next-cli')
|
|
32
32
|
.description('A unified, high-performance i18next CLI.')
|
|
33
|
-
.version('1.56.
|
|
33
|
+
.version('1.56.8'); // This string is replaced with the actual version at build time by rollup
|
|
34
34
|
// new: global config override option
|
|
35
35
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
36
36
|
program
|
|
@@ -747,11 +747,23 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
747
747
|
}
|
|
748
748
|
}
|
|
749
749
|
else {
|
|
750
|
+
// A key is a synthesized plural variant only when the extractor flagged it
|
|
751
|
+
// with `hasCount` AND its suffix matches a CLDR plural form. Relying purely
|
|
752
|
+
// on the presence of the separator misclassifies regular keys that happen to
|
|
753
|
+
// contain `_` (e.g. `abc_123`) — see issue #250. Context variants are caught
|
|
754
|
+
// by `isDerivedDefault` below (their synthesized default mirrors the base key).
|
|
755
|
+
const isVariantKey = (() => {
|
|
756
|
+
if (!hasCount)
|
|
757
|
+
return false;
|
|
758
|
+
const parts = key.split(pluralSeparator);
|
|
759
|
+
if (parts.length < 2)
|
|
760
|
+
return false;
|
|
761
|
+
return pluralForms.includes(parts[parts.length - 1]);
|
|
762
|
+
})();
|
|
750
763
|
// Existing value exists - decide whether to preserve, sync primary, or clear other locales when requested
|
|
751
764
|
if (locale === primaryLanguage && syncPrimaryWithDefaults) {
|
|
752
|
-
// If this key
|
|
753
|
-
//
|
|
754
|
-
const isVariantKey = key.includes(pluralSeparator) || key.includes(contextSeparator);
|
|
765
|
+
// If this key is a plural/context variant and the default wasn't explicitly
|
|
766
|
+
// provided in source code, preserve the existing value.
|
|
755
767
|
if (isVariantKey && !explicitDefault) {
|
|
756
768
|
valueToSet = existingValue;
|
|
757
769
|
}
|
|
@@ -764,7 +776,6 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
764
776
|
}
|
|
765
777
|
else {
|
|
766
778
|
// Non-primary locale behavior
|
|
767
|
-
const isVariantKey = key.includes(pluralSeparator) || key.includes(contextSeparator);
|
|
768
779
|
// A plural variant whose category exists in the current locale but not in the
|
|
769
780
|
// primary language (e.g. French `_many` vs English `one`/`other`) will always be
|
|
770
781
|
// absent from the primary file by CLDR design. Treat that absence as expected —
|
|
@@ -66,21 +66,6 @@ class CallExpressionHandler {
|
|
|
66
66
|
return;
|
|
67
67
|
// The scope lookup will only work for simple identifiers, which is okay for this fix.
|
|
68
68
|
let scopeInfo = getScopeInfo(functionName);
|
|
69
|
-
// For member expressions like `emailError.t`, also try the object part(s) as a
|
|
70
|
-
// fallback. This lets custom hooks that return an object with a `t` method
|
|
71
|
-
// (e.g. `const emailError = useTranslateKeyState('auth')`) propagate their
|
|
72
|
-
// namespace/keyPrefix to the inner `t` call.
|
|
73
|
-
if (!scopeInfo && functionName.includes('.')) {
|
|
74
|
-
const parts = functionName.split('.');
|
|
75
|
-
for (let i = parts.length - 1; i > 0; i--) {
|
|
76
|
-
const candidate = parts.slice(0, i).join('.');
|
|
77
|
-
const candidateScope = getScopeInfo(candidate);
|
|
78
|
-
if (candidateScope) {
|
|
79
|
-
scopeInfo = candidateScope;
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
69
|
const configuredFunctions = this.config.extract.functions || ['t', '*.t'];
|
|
85
70
|
let isFunctionToParse = scopeInfo !== undefined; // A scoped variable (from useTranslation, etc.) is always parsed.
|
|
86
71
|
if (!isFunctionToParse) {
|
|
@@ -103,6 +88,23 @@ class CallExpressionHandler {
|
|
|
103
88
|
}
|
|
104
89
|
if (!isFunctionToParse || node.arguments.length === 0)
|
|
105
90
|
return;
|
|
91
|
+
// For member expressions like `emailError.t`, also try the object part(s) as a
|
|
92
|
+
// fallback. This lets custom hooks that return an object with a `t` method
|
|
93
|
+
// (e.g. `const emailError = useTranslateKeyState('auth')`) propagate their
|
|
94
|
+
// namespace/keyPrefix to the inner `t` call. This runs AFTER the pattern
|
|
95
|
+
// check so an in-scope prefix cannot by itself promote an arbitrary method
|
|
96
|
+
// call (e.g. `i18n.language.substring(...)`) into a translation call.
|
|
97
|
+
if (!scopeInfo && functionName.includes('.')) {
|
|
98
|
+
const parts = functionName.split('.');
|
|
99
|
+
for (let i = parts.length - 1; i > 0; i--) {
|
|
100
|
+
const candidate = parts.slice(0, i).join('.');
|
|
101
|
+
const candidateScope = getScopeInfo(candidate);
|
|
102
|
+
if (candidateScope) {
|
|
103
|
+
scopeInfo = candidateScope;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
106
108
|
const { keysToProcess, isSelectorAPI } = this.handleCallExpressionArgument(node, 0);
|
|
107
109
|
if (keysToProcess.length === 0)
|
|
108
110
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18next-cli",
|
|
3
|
-
"version": "1.56.
|
|
3
|
+
"version": "1.56.8",
|
|
4
4
|
"description": "A unified, high-performance i18next CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"minimatch": "^10.2.5",
|
|
86
86
|
"ora": "^9.3.0",
|
|
87
87
|
"react": "^19.2.5",
|
|
88
|
-
"react-i18next": "^17.0.
|
|
88
|
+
"react-i18next": "^17.0.6",
|
|
89
89
|
"yaml": "^2.8.3"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"translation-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/translation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAujC9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,MAAM,EAAE,oBAAoB,EAC5B,EACE,uBAA+B,EAC/B,OAAe,EACf,oBAA4B,EAC5B,MAA4B,EAC7B,GAAE;IACD,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;CACX,GACL,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiK9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAa7D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,iBAAiB,CAAsC;gBAG7D,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM,EAC5B,iBAAiB,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAA2B;IAW3E;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAa7D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,iBAAiB,CAAsC;gBAG7D,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM,EAC5B,iBAAiB,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAA2B;IAW3E;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IA4ZxG;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,wBAAwB;IAyEhC;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,uBAAuB;IAgB/B;;;;;;;;OAQG;IACH,OAAO,CAAC,iCAAiC;IAwFzC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IAyMxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
|