i18next-cli 1.34.0 → 1.35.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.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/cli.js +271 -1
  3. package/dist/cjs/config.js +211 -1
  4. package/dist/cjs/extractor/core/ast-visitors.js +372 -1
  5. package/dist/cjs/extractor/core/extractor.js +245 -1
  6. package/dist/cjs/extractor/core/key-finder.js +132 -1
  7. package/dist/cjs/extractor/core/translation-manager.js +745 -1
  8. package/dist/cjs/extractor/parsers/ast-utils.js +85 -1
  9. package/dist/cjs/extractor/parsers/call-expression-handler.js +942 -1
  10. package/dist/cjs/extractor/parsers/comment-parser.js +375 -1
  11. package/dist/cjs/extractor/parsers/expression-resolver.js +362 -1
  12. package/dist/cjs/extractor/parsers/jsx-handler.js +492 -1
  13. package/dist/cjs/extractor/parsers/jsx-parser.js +355 -1
  14. package/dist/cjs/extractor/parsers/scope-manager.js +408 -1
  15. package/dist/cjs/extractor/plugin-manager.js +106 -1
  16. package/dist/cjs/heuristic-config.js +99 -1
  17. package/dist/cjs/index.js +28 -1
  18. package/dist/cjs/init.js +174 -1
  19. package/dist/cjs/linter.js +431 -1
  20. package/dist/cjs/locize.js +269 -1
  21. package/dist/cjs/migrator.js +196 -1
  22. package/dist/cjs/rename-key.js +354 -1
  23. package/dist/cjs/status.js +336 -1
  24. package/dist/cjs/syncer.js +120 -1
  25. package/dist/cjs/types-generator.js +165 -1
  26. package/dist/cjs/utils/default-value.js +43 -1
  27. package/dist/cjs/utils/file-utils.js +136 -1
  28. package/dist/cjs/utils/funnel-msg-tracker.js +75 -1
  29. package/dist/cjs/utils/logger.js +36 -1
  30. package/dist/cjs/utils/nested-object.js +124 -1
  31. package/dist/cjs/utils/validation.js +71 -1
  32. package/dist/esm/cli.js +269 -1
  33. package/dist/esm/config.js +206 -1
  34. package/dist/esm/extractor/core/ast-visitors.js +370 -1
  35. package/dist/esm/extractor/core/extractor.js +241 -1
  36. package/dist/esm/extractor/core/key-finder.js +130 -1
  37. package/dist/esm/extractor/core/translation-manager.js +743 -1
  38. package/dist/esm/extractor/parsers/ast-utils.js +80 -1
  39. package/dist/esm/extractor/parsers/call-expression-handler.js +940 -1
  40. package/dist/esm/extractor/parsers/comment-parser.js +373 -1
  41. package/dist/esm/extractor/parsers/expression-resolver.js +360 -1
  42. package/dist/esm/extractor/parsers/jsx-handler.js +490 -1
  43. package/dist/esm/extractor/parsers/jsx-parser.js +334 -1
  44. package/dist/esm/extractor/parsers/scope-manager.js +406 -1
  45. package/dist/esm/extractor/plugin-manager.js +103 -1
  46. package/dist/esm/heuristic-config.js +97 -1
  47. package/dist/esm/index.js +11 -1
  48. package/dist/esm/init.js +172 -1
  49. package/dist/esm/linter.js +425 -1
  50. package/dist/esm/locize.js +265 -1
  51. package/dist/esm/migrator.js +194 -1
  52. package/dist/esm/rename-key.js +352 -1
  53. package/dist/esm/status.js +334 -1
  54. package/dist/esm/syncer.js +118 -1
  55. package/dist/esm/types-generator.js +163 -1
  56. package/dist/esm/utils/default-value.js +41 -1
  57. package/dist/esm/utils/file-utils.js +131 -1
  58. package/dist/esm/utils/funnel-msg-tracker.js +72 -1
  59. package/dist/esm/utils/logger.js +34 -1
  60. package/dist/esm/utils/nested-object.js +120 -1
  61. package/dist/esm/utils/validation.js +68 -1
  62. package/package.json +2 -2
  63. package/types/extractor/core/ast-visitors.d.ts.map +1 -1
  64. package/types/extractor/parsers/call-expression-handler.d.ts +3 -2
  65. package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
  66. package/types/locize.d.ts.map +1 -1
@@ -1 +1,130 @@
1
- import{glob as r}from"glob";import{processFile as e}from"./extractor.js";import{ConsoleLogger as t}from"../../utils/logger.js";import{createPluginContext as o,initializePlugins as n}from"../plugin-manager.js";import{ASTVisitors as a}from"./ast-visitors.js";import{ExpressionResolver as s}from"../parsers/expression-resolver.js";async function i(i,c=new t){const{plugins:l,...p}=i,m=l||[],f=await async function(e){const t=["node_modules/**"],o=Array.isArray(e.extract.ignore)?e.extract.ignore:e.extract.ignore?[e.extract.ignore]:[];return await r(e.extract.input,{ignore:[...t,...o],cwd:process.cwd()})}(i),u=new Map,g=o(u,m,p,c),x={onBeforeVisitNode:r=>{for(const e of m)try{e.onVisitNode?.(r,g)}catch(r){c.warn(`Plugin ${e.name} onVisitNode failed:`,r)}},resolvePossibleKeyStringValues:r=>m.flatMap(e=>{try{return e.extractKeysFromExpression?.(r,i,c)??[]}catch(r){return c.warn(`Plugin ${e.name} extractKeysFromExpression failed:`,r),[]}}),resolvePossibleContextStringValues:r=>m.flatMap(e=>{try{return e.extractContextFromExpression?.(r,i,c)??[]}catch(r){return c.warn(`Plugin ${e.name} extractContextFromExpression failed:`,r),[]}})},d=new s(x),w=new a(p,g,c,x,d);g.getVarFromScope=w.getVarFromScope.bind(w),await n(m);for(const r of f)await e(r,m,w,g,p,c);for(const r of m)await(r.onEnd?.(u));const y=p.extract?.pluralSeparator??"_",h=["zero","one","two","few","many","other"];for(const r of u.values()){const e=String(r.key).split(y),t=e[e.length-1],o=e.length>=3&&"ordinal"===e[e.length-2];(h.includes(t)||o&&h.includes(t))&&(r.isExpandedPlural=!0)}return{allKeys:u,objectKeys:w.objectKeys}}export{i as findKeys};
1
+ import { glob } from 'glob';
2
+ import { processFile } from './extractor.js';
3
+ import { ConsoleLogger } from '../../utils/logger.js';
4
+ import { createPluginContext, initializePlugins } from '../plugin-manager.js';
5
+ import { ASTVisitors } from './ast-visitors.js';
6
+ import { ExpressionResolver } from '../parsers/expression-resolver.js';
7
+
8
+ /**
9
+ * Main function for finding translation keys across all source files in a project.
10
+ *
11
+ * This function orchestrates the key extraction process:
12
+ * 1. Processes source files based on input patterns
13
+ * 2. Initializes and manages plugins
14
+ * 3. Processes each file through AST parsing and key extraction
15
+ * 4. Runs plugin lifecycle hooks
16
+ * 5. Returns a deduplicated map of all found keys
17
+ *
18
+ * @param config - The i18next toolkit configuration object
19
+ * @param logger - Logger instance for output (defaults to ConsoleLogger)
20
+ * @returns Promise resolving to a Map of unique translation keys with metadata
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const config = {
25
+ * extract: {
26
+ * input: ['src/**\/*.{ts,tsx}'],
27
+ * functions: ['t', '*.t'],
28
+ * transComponents: ['Trans']
29
+ * }
30
+ * }
31
+ *
32
+ * const keys = await findKeys(config)
33
+ * console.log(`Found ${keys.size} unique translation keys`)
34
+ * ```
35
+ */
36
+ async function findKeys(config, logger = new ConsoleLogger()) {
37
+ const { plugins: pluginsOrUndefined, ...otherConfig } = config;
38
+ const plugins = pluginsOrUndefined || [];
39
+ const sourceFiles = await processSourceFiles(config);
40
+ const allKeys = new Map();
41
+ // 1. Create the base context with config and logger.
42
+ const pluginContext = createPluginContext(allKeys, plugins, otherConfig, logger);
43
+ // 2. Create hooks for plugins to hook into AST
44
+ const hooks = {
45
+ onBeforeVisitNode: (node) => {
46
+ for (const plugin of plugins) {
47
+ try {
48
+ plugin.onVisitNode?.(node, pluginContext);
49
+ }
50
+ catch (err) {
51
+ logger.warn(`Plugin ${plugin.name} onVisitNode failed:`, err);
52
+ }
53
+ }
54
+ },
55
+ resolvePossibleKeyStringValues: (expression) => {
56
+ return plugins.flatMap(plugin => {
57
+ try {
58
+ return plugin.extractKeysFromExpression?.(expression, config, logger) ?? [];
59
+ }
60
+ catch (err) {
61
+ logger.warn(`Plugin ${plugin.name} extractKeysFromExpression failed:`, err);
62
+ return [];
63
+ }
64
+ });
65
+ },
66
+ resolvePossibleContextStringValues: (expression) => {
67
+ return plugins.flatMap(plugin => {
68
+ try {
69
+ return plugin.extractContextFromExpression?.(expression, config, logger) ?? [];
70
+ }
71
+ catch (err) {
72
+ logger.warn(`Plugin ${plugin.name} extractContextFromExpression failed:`, err);
73
+ return [];
74
+ }
75
+ });
76
+ },
77
+ };
78
+ // 3. Create the visitor instance, passing it the context.
79
+ // Use a shared ExpressionResolver so captured enums/objects in one file are available when resolving MemberExpressions
80
+ const sharedExpressionResolver = new ExpressionResolver(hooks);
81
+ const astVisitors = new ASTVisitors(otherConfig, pluginContext, logger, hooks, sharedExpressionResolver);
82
+ // 4. "Wire up" the visitor's scope method to the context.
83
+ // This avoids a circular dependency while giving plugins access to the scope.
84
+ pluginContext.getVarFromScope = astVisitors.getVarFromScope.bind(astVisitors);
85
+ // 5. Initialize plugins
86
+ await initializePlugins(plugins);
87
+ // 6. Process each file
88
+ for (const file of sourceFiles) {
89
+ await processFile(file, plugins, astVisitors, pluginContext, otherConfig, logger);
90
+ }
91
+ // 7. Run onEnd hooks
92
+ for (const plugin of plugins) {
93
+ await plugin.onEnd?.(allKeys);
94
+ }
95
+ // Normalization: mark already-expanded plural keys
96
+ const pluralSeparator = otherConfig.extract?.pluralSeparator ?? '_';
97
+ const categories = ['zero', 'one', 'two', 'few', 'many', 'other'];
98
+ for (const ek of allKeys.values()) {
99
+ const parts = String(ek.key).split(pluralSeparator);
100
+ const last = parts[parts.length - 1];
101
+ const isOrdinal = parts.length >= 3 && parts[parts.length - 2] === 'ordinal';
102
+ if (categories.includes(last) || (isOrdinal && categories.includes(last))) {
103
+ ek.isExpandedPlural = true;
104
+ }
105
+ }
106
+ return { allKeys, objectKeys: astVisitors.objectKeys };
107
+ }
108
+ /**
109
+ * Processes source files using glob patterns from configuration.
110
+ * Excludes node_modules by default and resolves relative to current working directory.
111
+ *
112
+ * @param config - The i18next toolkit configuration object
113
+ * @returns Promise resolving to array of file paths to process
114
+ *
115
+ * @internal
116
+ */
117
+ async function processSourceFiles(config) {
118
+ const defaultIgnore = ['node_modules/**'];
119
+ // Normalize the user's ignore option into an array
120
+ const userIgnore = Array.isArray(config.extract.ignore)
121
+ ? config.extract.ignore
122
+ : config.extract.ignore ? [config.extract.ignore] : [];
123
+ return await glob(config.extract.input, {
124
+ // Combine default ignore patterns with user-configured ones
125
+ ignore: [...defaultIgnore, ...userIgnore],
126
+ cwd: process.cwd(),
127
+ });
128
+ }
129
+
130
+ export { findKeys };