i18next-cli 1.71.1 → 1.71.2
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
CHANGED
|
@@ -37,7 +37,7 @@ const program = new commander.Command();
|
|
|
37
37
|
program
|
|
38
38
|
.name('i18next-cli')
|
|
39
39
|
.description('A unified, high-performance i18next CLI.')
|
|
40
|
-
.version('1.71.
|
|
40
|
+
.version('1.71.2'); // This string is replaced with the actual version at build time by rollup
|
|
41
41
|
// new: global config override option
|
|
42
42
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
43
43
|
program
|
|
@@ -342,13 +342,31 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
342
342
|
: nsKeys;
|
|
343
343
|
// Prepare namespace pattern checking helpers
|
|
344
344
|
const rawPreserve = config.extract.preservePatterns || [];
|
|
345
|
+
// Fast equivalent of matching a `${objectKey}.*` glob per object key: instead of
|
|
346
|
+
// testing O(objectKeys) regexes per key, walk the key's '.' boundaries and look
|
|
347
|
+
// each ancestor prefix up in the Set — O(key depth). See issue #286.
|
|
348
|
+
const isUnderObjectKey = (key) => {
|
|
349
|
+
if (objectKeys.size === 0)
|
|
350
|
+
return false;
|
|
351
|
+
let i = key.indexOf('.');
|
|
352
|
+
while (i !== -1) {
|
|
353
|
+
if (objectKeys.has(key.slice(0, i)))
|
|
354
|
+
return true;
|
|
355
|
+
i = key.indexOf('.', i + 1);
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
};
|
|
345
359
|
// Helper to check if a key should be filtered out during extraction
|
|
346
360
|
const shouldFilterKey = (key) => {
|
|
347
|
-
// 1)
|
|
361
|
+
// 1) keys nested under a returnObjects / selector-API base key
|
|
362
|
+
if (isUnderObjectKey(key)) {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
// 2) regex based patterns (existing behavior)
|
|
348
366
|
if (preservePatterns.some(re => re.test(key))) {
|
|
349
367
|
return true;
|
|
350
368
|
}
|
|
351
|
-
//
|
|
369
|
+
// 3) namespace:* style patterns (respect nsSeparator)
|
|
352
370
|
for (const rp of rawPreserve) {
|
|
353
371
|
if (typeof rp !== 'string')
|
|
354
372
|
continue;
|
|
@@ -365,11 +383,15 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
365
383
|
};
|
|
366
384
|
// Helper to check if an existing key should be preserved
|
|
367
385
|
const shouldPreserveExistingKey = (key) => {
|
|
368
|
-
// 1)
|
|
386
|
+
// 1) keys nested under a returnObjects / selector-API base key
|
|
387
|
+
if (isUnderObjectKey(key)) {
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
// 2) regex-style patterns
|
|
369
391
|
if (preservePatterns.some(re => re.test(key))) {
|
|
370
392
|
return true;
|
|
371
393
|
}
|
|
372
|
-
//
|
|
394
|
+
// 3) namespace:key patterns - check if pattern matches this namespace:key combination
|
|
373
395
|
for (const rp of rawPreserve) {
|
|
374
396
|
if (typeof rp !== 'string')
|
|
375
397
|
continue;
|
|
@@ -575,6 +597,19 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
575
597
|
}
|
|
576
598
|
}
|
|
577
599
|
}
|
|
600
|
+
// Precompute every proper ancestor prefix (up to each keySeparator boundary) of the
|
|
601
|
+
// extracted keys, so the per-key "is this a leaf?" check below is a single Set lookup
|
|
602
|
+
// instead of an O(keys) scan per key. See issue #286.
|
|
603
|
+
const parentPrefixesInNewKeys = new Set();
|
|
604
|
+
if (typeof keySeparator === 'string') {
|
|
605
|
+
for (const { key } of filteredKeys) {
|
|
606
|
+
let i = key.indexOf(keySeparator);
|
|
607
|
+
while (i !== -1 && i < key.length) {
|
|
608
|
+
parentPrefixesInNewKeys.add(key.slice(0, i));
|
|
609
|
+
i = key.indexOf(keySeparator, i + 1);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
578
613
|
// 1. Build the object first, without any sorting.
|
|
579
614
|
for (const { key, defaultValue: defaultValue$1, explicitDefault, hasCount, isExpandedPlural, isOrdinal } of filteredKeys) {
|
|
580
615
|
// If this is a base plural key (hasCount true but not an already-expanded variant)
|
|
@@ -717,7 +752,7 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
717
752
|
// For flat keys there cannot be nested children, so treat them as leaves.
|
|
718
753
|
const isLeafInNewKeys = keySeparator === false
|
|
719
754
|
? true
|
|
720
|
-
: !
|
|
755
|
+
: !parentPrefixesInNewKeys.has(key);
|
|
721
756
|
const isDerivedDefault = isDerivedFromKey(key, defaultValue$1, explicitDefault);
|
|
722
757
|
// Determine if we should preserve an existing object
|
|
723
758
|
const shouldPreserveObject = typeof existingValue === 'object' && existingValue !== null && (objectKeys.has(key) || // Explicit returnObjects
|
|
@@ -1099,8 +1134,12 @@ async function getTranslations(keys, objectKeys, config, { syncPrimaryWithDefaul
|
|
|
1099
1134
|
const patternsToPreserve = [...(config.extract.preservePatterns || [])];
|
|
1100
1135
|
const indentation = config.extract.indentation ?? 2;
|
|
1101
1136
|
for (const key of objectKeys) {
|
|
1102
|
-
//
|
|
1103
|
-
|
|
1137
|
+
// Object keys are matched directly (and cheaply) against the objectKeys Set in
|
|
1138
|
+
// buildNewTranslationsForNs (see isUnderObjectKey). Only a key that itself
|
|
1139
|
+
// contains a wildcard still needs the glob-to-regex path.
|
|
1140
|
+
if (key.includes('*')) {
|
|
1141
|
+
patternsToPreserve.push(`${key}.*`);
|
|
1142
|
+
}
|
|
1104
1143
|
}
|
|
1105
1144
|
const preservePatterns = patternsToPreserve.map(globToRegex);
|
|
1106
1145
|
// Group keys by namespace. If the plugin recorded the namespace as implicit
|
package/dist/esm/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ const program = new Command();
|
|
|
31
31
|
program
|
|
32
32
|
.name('i18next-cli')
|
|
33
33
|
.description('A unified, high-performance i18next CLI.')
|
|
34
|
-
.version('1.71.
|
|
34
|
+
.version('1.71.2'); // This string is replaced with the actual version at build time by rollup
|
|
35
35
|
// new: global config override option
|
|
36
36
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)');
|
|
37
37
|
program
|
|
@@ -340,13 +340,31 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
340
340
|
: nsKeys;
|
|
341
341
|
// Prepare namespace pattern checking helpers
|
|
342
342
|
const rawPreserve = config.extract.preservePatterns || [];
|
|
343
|
+
// Fast equivalent of matching a `${objectKey}.*` glob per object key: instead of
|
|
344
|
+
// testing O(objectKeys) regexes per key, walk the key's '.' boundaries and look
|
|
345
|
+
// each ancestor prefix up in the Set — O(key depth). See issue #286.
|
|
346
|
+
const isUnderObjectKey = (key) => {
|
|
347
|
+
if (objectKeys.size === 0)
|
|
348
|
+
return false;
|
|
349
|
+
let i = key.indexOf('.');
|
|
350
|
+
while (i !== -1) {
|
|
351
|
+
if (objectKeys.has(key.slice(0, i)))
|
|
352
|
+
return true;
|
|
353
|
+
i = key.indexOf('.', i + 1);
|
|
354
|
+
}
|
|
355
|
+
return false;
|
|
356
|
+
};
|
|
343
357
|
// Helper to check if a key should be filtered out during extraction
|
|
344
358
|
const shouldFilterKey = (key) => {
|
|
345
|
-
// 1)
|
|
359
|
+
// 1) keys nested under a returnObjects / selector-API base key
|
|
360
|
+
if (isUnderObjectKey(key)) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
// 2) regex based patterns (existing behavior)
|
|
346
364
|
if (preservePatterns.some(re => re.test(key))) {
|
|
347
365
|
return true;
|
|
348
366
|
}
|
|
349
|
-
//
|
|
367
|
+
// 3) namespace:* style patterns (respect nsSeparator)
|
|
350
368
|
for (const rp of rawPreserve) {
|
|
351
369
|
if (typeof rp !== 'string')
|
|
352
370
|
continue;
|
|
@@ -363,11 +381,15 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
363
381
|
};
|
|
364
382
|
// Helper to check if an existing key should be preserved
|
|
365
383
|
const shouldPreserveExistingKey = (key) => {
|
|
366
|
-
// 1)
|
|
384
|
+
// 1) keys nested under a returnObjects / selector-API base key
|
|
385
|
+
if (isUnderObjectKey(key)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
// 2) regex-style patterns
|
|
367
389
|
if (preservePatterns.some(re => re.test(key))) {
|
|
368
390
|
return true;
|
|
369
391
|
}
|
|
370
|
-
//
|
|
392
|
+
// 3) namespace:key patterns - check if pattern matches this namespace:key combination
|
|
371
393
|
for (const rp of rawPreserve) {
|
|
372
394
|
if (typeof rp !== 'string')
|
|
373
395
|
continue;
|
|
@@ -573,6 +595,19 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
573
595
|
}
|
|
574
596
|
}
|
|
575
597
|
}
|
|
598
|
+
// Precompute every proper ancestor prefix (up to each keySeparator boundary) of the
|
|
599
|
+
// extracted keys, so the per-key "is this a leaf?" check below is a single Set lookup
|
|
600
|
+
// instead of an O(keys) scan per key. See issue #286.
|
|
601
|
+
const parentPrefixesInNewKeys = new Set();
|
|
602
|
+
if (typeof keySeparator === 'string') {
|
|
603
|
+
for (const { key } of filteredKeys) {
|
|
604
|
+
let i = key.indexOf(keySeparator);
|
|
605
|
+
while (i !== -1 && i < key.length) {
|
|
606
|
+
parentPrefixesInNewKeys.add(key.slice(0, i));
|
|
607
|
+
i = key.indexOf(keySeparator, i + 1);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
576
611
|
// 1. Build the object first, without any sorting.
|
|
577
612
|
for (const { key, defaultValue, explicitDefault, hasCount, isExpandedPlural, isOrdinal } of filteredKeys) {
|
|
578
613
|
// If this is a base plural key (hasCount true but not an already-expanded variant)
|
|
@@ -715,7 +750,7 @@ function buildNewTranslationsForNs(nsKeys, existingTranslations, config, locale,
|
|
|
715
750
|
// For flat keys there cannot be nested children, so treat them as leaves.
|
|
716
751
|
const isLeafInNewKeys = keySeparator === false
|
|
717
752
|
? true
|
|
718
|
-
: !
|
|
753
|
+
: !parentPrefixesInNewKeys.has(key);
|
|
719
754
|
const isDerivedDefault = isDerivedFromKey(key, defaultValue, explicitDefault);
|
|
720
755
|
// Determine if we should preserve an existing object
|
|
721
756
|
const shouldPreserveObject = typeof existingValue === 'object' && existingValue !== null && (objectKeys.has(key) || // Explicit returnObjects
|
|
@@ -1097,8 +1132,12 @@ async function getTranslations(keys, objectKeys, config, { syncPrimaryWithDefaul
|
|
|
1097
1132
|
const patternsToPreserve = [...(config.extract.preservePatterns || [])];
|
|
1098
1133
|
const indentation = config.extract.indentation ?? 2;
|
|
1099
1134
|
for (const key of objectKeys) {
|
|
1100
|
-
//
|
|
1101
|
-
|
|
1135
|
+
// Object keys are matched directly (and cheaply) against the objectKeys Set in
|
|
1136
|
+
// buildNewTranslationsForNs (see isUnderObjectKey). Only a key that itself
|
|
1137
|
+
// contains a wildcard still needs the glob-to-regex path.
|
|
1138
|
+
if (key.includes('*')) {
|
|
1139
|
+
patternsToPreserve.push(`${key}.*`);
|
|
1140
|
+
}
|
|
1102
1141
|
}
|
|
1103
1142
|
const preservePatterns = patternsToPreserve.map(globToRegex);
|
|
1104
1143
|
// Group keys by namespace. If the plugin recorded the namespace as implicit
|
package/package.json
CHANGED
|
@@ -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;AA8tC9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,CA6K9B"}
|