i18next-cli 1.58.2 → 1.58.3

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
@@ -9,7 +9,7 @@ var node_util = require('node:util');
9
9
  var config = require('./config.js');
10
10
  var heuristicConfig = require('./heuristic-config.js');
11
11
  var extractor = require('./extractor/core/extractor.js');
12
- require('./extractor/parsers/jsx-parser.js');
12
+ require('node:module');
13
13
  require('node:path');
14
14
  var nestedObject = require('./utils/nested-object.js');
15
15
  require('node:fs/promises');
@@ -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.58.2'); // This string is replaced with the actual version at build time by rollup
35
+ .version('1.58.3'); // 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
@@ -1,8 +1,31 @@
1
1
  'use strict';
2
2
 
3
3
  var astUtils = require('./ast-utils.js');
4
- var reactI18next = require('react-i18next');
4
+ var node_module = require('node:module');
5
5
 
6
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
7
+ let cachedReactI18next;
8
+ function loadReactI18next() {
9
+ if (cachedReactI18next !== undefined)
10
+ return cachedReactI18next;
11
+ try {
12
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('extractor/parsers/jsx-parser.js', document.baseURI).href)));
13
+ cachedReactI18next = require$1('react-i18next');
14
+ }
15
+ catch {
16
+ cachedReactI18next = null;
17
+ }
18
+ return cachedReactI18next;
19
+ }
20
+ let warnedReactI18nextUnavailable = false;
21
+ function warnReactI18nextUnavailable() {
22
+ if (warnedReactI18nextUnavailable)
23
+ return;
24
+ warnedReactI18nextUnavailable = true;
25
+ console.warn("i18next-cli: could not load 'react-i18next' to serialize <Trans> children — " +
26
+ 'skipping their default-value extraction. This usually means the installed ' +
27
+ "'react-i18next' and 'i18next' versions are incompatible. Other functionality is unaffected.");
28
+ }
6
29
  /**
7
30
  * Detects which `$$typeof` symbol react-i18next's `nodesToString` expects
8
31
  * from React elements. This matters because npm hoisting can cause
@@ -11,11 +34,14 @@ var reactI18next = require('react-i18next');
11
34
  *
12
35
  * React 18 uses `Symbol.for('react.element')`, while React 19 uses
13
36
  * `Symbol.for('react.transitional.element')` for its element `$$typeof`.
14
- * By probing `nodesToString` at load time we ensure the fake elements we
15
- * build match its `isValidElement` check, regardless of which React it
16
- * resolved to.
37
+ * By probing `nodesToString` we ensure the fake elements we build match its
38
+ * `isValidElement` check, regardless of which React it resolved to. Resolved
39
+ * lazily (and cached) the first time we serialize a `<Trans>`.
17
40
  */
18
- const REACT_ELEMENT_TYPE = (() => {
41
+ let cachedReactElementType;
42
+ function resolveReactElementType(rt) {
43
+ if (cachedReactElementType !== undefined)
44
+ return cachedReactElementType;
19
45
  const candidates = [
20
46
  Symbol.for('react.element'), // React ≤ 18
21
47
  Symbol.for('react.transitional.element') // React 19
@@ -31,16 +57,19 @@ const REACT_ELEMENT_TYPE = (() => {
31
57
  key: null,
32
58
  ref: null
33
59
  };
34
- const result = reactI18next.nodesToString([testEl], { ...reactI18next.getDefaults() });
35
- if (result === '<0>x</0>')
60
+ const result = rt.nodesToString([testEl], { ...rt.getDefaults() });
61
+ if (result === '<0>x</0>') {
62
+ cachedReactElementType = sym;
36
63
  return sym;
64
+ }
37
65
  }
38
66
  }
39
67
  finally {
40
68
  console.warn = savedWarn;
41
69
  }
70
+ cachedReactElementType = candidates[0];
42
71
  return candidates[0];
43
- })();
72
+ }
44
73
  /** `React.Fragment` equivalent – same symbol across all React versions. */
45
74
  const REACT_FRAGMENT = Symbol.for('react.fragment');
46
75
  /**
@@ -57,7 +86,9 @@ function createElement(type, props, ...children) {
57
86
  finalProps.children = children;
58
87
  }
59
88
  return {
60
- $$typeof: REACT_ELEMENT_TYPE,
89
+ // serializeJSXChildren() resolves and caches this before any element is
90
+ // built; the fallback only applies if createElement is ever reached first.
91
+ $$typeof: cachedReactElementType ?? Symbol.for('react.transitional.element'),
61
92
  type,
62
93
  props: finalProps,
63
94
  key: null,
@@ -460,11 +491,19 @@ function childrenHaveInlineCount(children) {
460
491
  return false;
461
492
  }
462
493
  function serializeJSXChildren(children, config) {
463
- const i18nextOptions = { ...reactI18next.getDefaults() };
494
+ const rt = loadReactI18next();
495
+ if (!rt) {
496
+ warnReactI18nextUnavailable();
497
+ return '';
498
+ }
499
+ // Resolve the element `$$typeof` before swcChildrenToReactNodes() builds any
500
+ // elements via createElement().
501
+ resolveReactElementType(rt);
502
+ const i18nextOptions = { ...rt.getDefaults() };
464
503
  if (config.extract.transKeepBasicHtmlNodesFor) {
465
504
  i18nextOptions.transKeepBasicHtmlNodesFor = config.extract.transKeepBasicHtmlNodesFor;
466
505
  }
467
- return reactI18next.nodesToString(swcChildrenToReactNodes(children), i18nextOptions);
506
+ return rt.nodesToString(swcChildrenToReactNodes(children), i18nextOptions);
468
507
  }
469
508
 
470
509
  exports.extractFromTransComponent = extractFromTransComponent;
package/dist/cjs/index.js CHANGED
@@ -4,7 +4,7 @@ var config = require('./config.js');
4
4
  var extractor = require('./extractor/core/extractor.js');
5
5
  var keyFinder = require('./extractor/core/key-finder.js');
6
6
  var translationManager = require('./extractor/core/translation-manager.js');
7
- require('./extractor/parsers/jsx-parser.js');
7
+ require('node:module');
8
8
  var linter = require('./linter.js');
9
9
  var syncer = require('./syncer.js');
10
10
  var status = require('./status.js');
@@ -13,7 +13,7 @@ var pluralRules = require('./utils/plural-rules.js');
13
13
  var nesting = require('./utils/nesting.js');
14
14
  var contextVariants = require('./utils/context-variants.js');
15
15
  var funnelMsgTracker = require('./utils/funnel-msg-tracker.js');
16
- require('./extractor/parsers/jsx-parser.js');
16
+ require('node:module');
17
17
 
18
18
  function classifyValue(value) {
19
19
  if (value === undefined || value === null)
package/dist/esm/cli.js CHANGED
@@ -7,7 +7,7 @@ import { styleText } from 'node:util';
7
7
  import { ensureConfig, loadConfig } from './config.js';
8
8
  import { detectConfig } from './heuristic-config.js';
9
9
  import { runExtractor } from './extractor/core/extractor.js';
10
- import './extractor/parsers/jsx-parser.js';
10
+ import 'node:module';
11
11
  import 'node:path';
12
12
  import { getNestedKeys, getNestedValue } from './utils/nested-object.js';
13
13
  import 'node:fs/promises';
@@ -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.58.2'); // This string is replaced with the actual version at build time by rollup
33
+ .version('1.58.3'); // 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
@@ -1,6 +1,28 @@
1
1
  import { getObjectPropValueExpression, getObjectPropValue, isSimpleTemplateLiteral } from './ast-utils.js';
2
- import { nodesToString, getDefaults } from 'react-i18next';
2
+ import { createRequire } from 'node:module';
3
3
 
4
+ let cachedReactI18next;
5
+ function loadReactI18next() {
6
+ if (cachedReactI18next !== undefined)
7
+ return cachedReactI18next;
8
+ try {
9
+ const require = createRequire(import.meta.url);
10
+ cachedReactI18next = require('react-i18next');
11
+ }
12
+ catch {
13
+ cachedReactI18next = null;
14
+ }
15
+ return cachedReactI18next;
16
+ }
17
+ let warnedReactI18nextUnavailable = false;
18
+ function warnReactI18nextUnavailable() {
19
+ if (warnedReactI18nextUnavailable)
20
+ return;
21
+ warnedReactI18nextUnavailable = true;
22
+ console.warn("i18next-cli: could not load 'react-i18next' to serialize <Trans> children — " +
23
+ 'skipping their default-value extraction. This usually means the installed ' +
24
+ "'react-i18next' and 'i18next' versions are incompatible. Other functionality is unaffected.");
25
+ }
4
26
  /**
5
27
  * Detects which `$$typeof` symbol react-i18next's `nodesToString` expects
6
28
  * from React elements. This matters because npm hoisting can cause
@@ -9,11 +31,14 @@ import { nodesToString, getDefaults } from 'react-i18next';
9
31
  *
10
32
  * React 18 uses `Symbol.for('react.element')`, while React 19 uses
11
33
  * `Symbol.for('react.transitional.element')` for its element `$$typeof`.
12
- * By probing `nodesToString` at load time we ensure the fake elements we
13
- * build match its `isValidElement` check, regardless of which React it
14
- * resolved to.
34
+ * By probing `nodesToString` we ensure the fake elements we build match its
35
+ * `isValidElement` check, regardless of which React it resolved to. Resolved
36
+ * lazily (and cached) the first time we serialize a `<Trans>`.
15
37
  */
16
- const REACT_ELEMENT_TYPE = (() => {
38
+ let cachedReactElementType;
39
+ function resolveReactElementType(rt) {
40
+ if (cachedReactElementType !== undefined)
41
+ return cachedReactElementType;
17
42
  const candidates = [
18
43
  Symbol.for('react.element'), // React ≤ 18
19
44
  Symbol.for('react.transitional.element') // React 19
@@ -29,16 +54,19 @@ const REACT_ELEMENT_TYPE = (() => {
29
54
  key: null,
30
55
  ref: null
31
56
  };
32
- const result = nodesToString([testEl], { ...getDefaults() });
33
- if (result === '<0>x</0>')
57
+ const result = rt.nodesToString([testEl], { ...rt.getDefaults() });
58
+ if (result === '<0>x</0>') {
59
+ cachedReactElementType = sym;
34
60
  return sym;
61
+ }
35
62
  }
36
63
  }
37
64
  finally {
38
65
  console.warn = savedWarn;
39
66
  }
67
+ cachedReactElementType = candidates[0];
40
68
  return candidates[0];
41
- })();
69
+ }
42
70
  /** `React.Fragment` equivalent – same symbol across all React versions. */
43
71
  const REACT_FRAGMENT = Symbol.for('react.fragment');
44
72
  /**
@@ -55,7 +83,9 @@ function createElement(type, props, ...children) {
55
83
  finalProps.children = children;
56
84
  }
57
85
  return {
58
- $$typeof: REACT_ELEMENT_TYPE,
86
+ // serializeJSXChildren() resolves and caches this before any element is
87
+ // built; the fallback only applies if createElement is ever reached first.
88
+ $$typeof: cachedReactElementType ?? Symbol.for('react.transitional.element'),
59
89
  type,
60
90
  props: finalProps,
61
91
  key: null,
@@ -458,11 +488,19 @@ function childrenHaveInlineCount(children) {
458
488
  return false;
459
489
  }
460
490
  function serializeJSXChildren(children, config) {
461
- const i18nextOptions = { ...getDefaults() };
491
+ const rt = loadReactI18next();
492
+ if (!rt) {
493
+ warnReactI18nextUnavailable();
494
+ return '';
495
+ }
496
+ // Resolve the element `$$typeof` before swcChildrenToReactNodes() builds any
497
+ // elements via createElement().
498
+ resolveReactElementType(rt);
499
+ const i18nextOptions = { ...rt.getDefaults() };
462
500
  if (config.extract.transKeepBasicHtmlNodesFor) {
463
501
  i18nextOptions.transKeepBasicHtmlNodesFor = config.extract.transKeepBasicHtmlNodesFor;
464
502
  }
465
- return nodesToString(swcChildrenToReactNodes(children), i18nextOptions);
503
+ return rt.nodesToString(swcChildrenToReactNodes(children), i18nextOptions);
466
504
  }
467
505
 
468
506
  export { extractFromTransComponent };
package/dist/esm/index.js CHANGED
@@ -2,7 +2,7 @@ export { defineConfig } from './config.js';
2
2
  export { extract, runExtractor } from './extractor/core/extractor.js';
3
3
  export { findKeys } from './extractor/core/key-finder.js';
4
4
  export { getTranslations } from './extractor/core/translation-manager.js';
5
- import './extractor/parsers/jsx-parser.js';
5
+ import 'node:module';
6
6
  export { recommendedAcceptedAttributes, recommendedAcceptedTags, runLinter } from './linter.js';
7
7
  export { runSyncer } from './syncer.js';
8
8
  export { runStatus } from './status.js';
@@ -11,7 +11,7 @@ import { safePluralRules } from './utils/plural-rules.js';
11
11
  import { parseNestedReferences } from './utils/nesting.js';
12
12
  import { isContextVariantOfAcceptingKey } from './utils/context-variants.js';
13
13
  import { shouldShowFunnel, recordFunnelShown } from './utils/funnel-msg-tracker.js';
14
- import './extractor/parsers/jsx-parser.js';
14
+ import 'node:module';
15
15
 
16
16
  function classifyValue(value) {
17
17
  if (value === undefined || value === null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-cli",
3
- "version": "1.58.2",
3
+ "version": "1.58.3",
4
4
  "description": "A unified, high-performance i18next CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -59,16 +59,16 @@
59
59
  "@types/node": "^25.9.1",
60
60
  "@types/react": "^19.2.15",
61
61
  "@typescript-eslint/parser": "^8.60.0",
62
- "@vitest/coverage-v8": "^4.1.7",
62
+ "@vitest/coverage-v8": "^4.1.8",
63
63
  "eslint": "^9.39.4",
64
- "eslint-import-resolver-typescript": "^4.4.4",
64
+ "eslint-import-resolver-typescript": "^4.4.5",
65
65
  "eslint-plugin-import": "^2.32.0",
66
66
  "memfs": "^4.57.3",
67
67
  "neostandard": "^0.13.0",
68
- "rollup": "^4.60.4",
68
+ "rollup": "^4.61.0",
69
69
  "typescript": "^6.0.3",
70
70
  "unplugin-swc": "^1.5.9",
71
- "vitest": "^4.1.7"
71
+ "vitest": "^4.1.8"
72
72
  },
73
73
  "dependencies": {
74
74
  "@croct/json5-parser": "^0.2.2",
@@ -77,6 +77,7 @@
77
77
  "commander": "^14.0.3",
78
78
  "execa": "^9.6.1",
79
79
  "glob": "^13.0.6",
80
+ "i18next": "^26.3.0",
80
81
  "i18next-resources-for-ts": "^2.1.0",
81
82
  "inquirer": "^13.4.3",
82
83
  "jiti": "^2.7.0",
@@ -1 +1 @@
1
- {"version":3,"file":"jsx-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAsC,UAAU,EAAkD,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC7J,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAsE1D,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B,qDAAqD;IACrD,kBAAkB,EAAE,MAAM,CAAC;IAE3B,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,8DAA8D;IAC9D,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAE/B,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAE/B,kHAAkH;IAClH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,IAAI,CAkMxH"}
1
+ {"version":3,"file":"jsx-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAsC,UAAU,EAAkD,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC7J,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAkH1D,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,aAAa,CAAC,EAAE,UAAU,CAAC;IAE3B,qDAAqD;IACrD,kBAAkB,EAAE,MAAM,CAAC;IAE3B,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,8DAA8D;IAC9D,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAE/B,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAE/B,kHAAkH;IAClH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,IAAI,CAkMxH"}