i18next-cli 1.5.10 → 1.6.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 (36) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +6 -6
  3. package/dist/cjs/cli.js +1 -1
  4. package/dist/cjs/extractor/core/extractor.js +1 -1
  5. package/dist/cjs/extractor/core/key-finder.js +1 -1
  6. package/dist/cjs/extractor/parsers/ast-visitors.js +1 -1
  7. package/dist/cjs/extractor/parsers/comment-parser.js +1 -1
  8. package/dist/cjs/extractor/parsers/jsx-parser.js +1 -1
  9. package/dist/cjs/extractor/plugin-manager.js +1 -1
  10. package/dist/esm/cli.js +1 -1
  11. package/dist/esm/extractor/core/extractor.js +1 -1
  12. package/dist/esm/extractor/core/key-finder.js +1 -1
  13. package/dist/esm/extractor/parsers/ast-visitors.js +1 -1
  14. package/dist/esm/extractor/parsers/comment-parser.js +1 -1
  15. package/dist/esm/extractor/parsers/jsx-parser.js +1 -1
  16. package/dist/esm/extractor/plugin-manager.js +1 -1
  17. package/package.json +4 -1
  18. package/src/cli.ts +1 -1
  19. package/src/extractor/core/extractor.ts +18 -5
  20. package/src/extractor/core/key-finder.ts +9 -2
  21. package/src/extractor/parsers/ast-visitors.ts +12 -22
  22. package/src/extractor/parsers/comment-parser.ts +16 -3
  23. package/src/extractor/parsers/jsx-parser.ts +27 -0
  24. package/src/extractor/plugin-manager.ts +6 -2
  25. package/src/types.ts +25 -0
  26. package/types/extractor/core/extractor.d.ts.map +1 -1
  27. package/types/extractor/core/key-finder.d.ts.map +1 -1
  28. package/types/extractor/parsers/ast-visitors.d.ts +3 -2
  29. package/types/extractor/parsers/ast-visitors.d.ts.map +1 -1
  30. package/types/extractor/parsers/comment-parser.d.ts +6 -3
  31. package/types/extractor/parsers/comment-parser.d.ts.map +1 -1
  32. package/types/extractor/parsers/jsx-parser.d.ts.map +1 -1
  33. package/types/extractor/plugin-manager.d.ts +2 -2
  34. package/types/extractor/plugin-manager.d.ts.map +1 -1
  35. package/types/types.d.ts +21 -0
  36. package/types/types.d.ts.map +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.6.0](https://github.com/i18next/i18next-cli/compare/v1.5.11...v1.6.0) - 2025-10-05
9
+
10
+ ### Added
11
+ - **Plugin System:** Enhanced plugin capabilities with improved context access and error handling. Plugins now receive richer context objects including:
12
+ - `getVarFromScope(name)`: Access to variable scope information for understanding `useTranslation` hooks, `getFixedT` calls, and namespace context
13
+ - Full configuration access via `context.config`
14
+ - Enhanced logging utilities via `context.logger`
15
+ - **Plugin System:** Added robust error handling for plugin hooks. Plugin failures (in `onLoad` and `onVisitNode`) no longer crash the extraction process but are logged as warnings, allowing extraction to continue gracefully
16
+ - **Plugin System:** Improved TypeScript support in plugins with better AST node access, enabling plugins to handle TypeScript-specific syntax like `satisfies` and `as` operators for advanced extraction patterns
17
+
18
+ ### Enhanced
19
+ - **Extractor:** The `processFile` function now provides plugins with comprehensive access to the parsing context, enabling sophisticated custom extraction logic that can leverage variable scope analysis and TypeScript-aware parsing
20
+ - **Extractor (`<Trans>`):** Fixed namespace prefix duplication when both `ns` prop and namespace prefix in `i18nKey` are specified. When a `<Trans>` component has both `ns="form"` and `i18nKey="form:cost_question.description"`, the extractor now correctly removes the redundant namespace prefix and extracts `cost_question.description` to the `form.json` file, matching i18next and i18next-parser behavior. [#45](https://github.com/i18next/i18next-cli/issues/45)
21
+ - **Extractor (Comments):** Fixed namespace scope resolution for `t()` calls in comments. Commented translation calls like `// t("Private")` now correctly inherit the namespace from the surrounding `useTranslation('access')` scope instead of defaulting to the default namespace, matching i18next-parser behavior. This ensures consistency between commented and actual translation calls within the same component scope. [#44](https://github.com/i18next/i18next-cli/issues/44)
22
+
23
+ ## [1.5.11](https://github.com/i18next/i18next-cli/compare/v1.5.10...v1.5.11) - 2025-10-05
24
+
25
+ - **Extractor:** Fixed handling of empty strings in template literals where conditional expressions could result in empty string concatenation (e.g., `` t(`key${condition ? '.suffix' : ''}`) ``). Empty strings are now properly filtered out during template literal resolution, ensuring only valid key variants are generated. [#41](https://github.com/i18next/i18next-cli/pull/41)
26
+
8
27
  ## [1.5.10](https://github.com/i18next/i18next-cli/compare/v1.5.9...v1.5.10) - 2025-10-05
9
28
 
10
29
  - **Extractor:** Added support for template literals as translation keys in both `t()` functions and `<Trans>` components. The extractor can now resolve complex template strings with nested expressions, ternary operators, and mixed data types to extract all possible key variants (e.g., `` t(`state.${isDone ? 'done' : 'notDone'}.title`) `` generates both `state.done.title` and `state.notDone.title`). [#39](https://github.com/i18next/i18next-cli/pull/39)
package/README.md CHANGED
@@ -383,15 +383,15 @@ export default defineConfig({
383
383
 
384
384
  ### Plugin System
385
385
 
386
- Create custom plugins to extend the capabilities of `i18next-cli`. The plugin system provides several hooks that allow you to tap into different stages of the extraction process.
386
+ Create custom plugins to extend the capabilities of `i18next-cli`. The plugin system provides several hooks that allow you to tap into different stages of the extraction process, with full access to the AST parsing context and variable scope information.
387
387
 
388
388
  **Available Hooks:**
389
389
 
390
- - `setup`: Runs once when the CLI is initialized. Use it for any setup tasks.
391
- - `onLoad`: Runs for each file *before* it is parsed. You can use this to transform code (e.g., transpile a custom language to JavaScript).
392
- - `onVisitNode`: Runs for every node in the Abstract Syntax Tree (AST) of a parsed JavaScript/TypeScript file. This is useful for finding custom translation patterns in your code.
393
- - `onEnd`: Runs after all JS/TS files have been parsed but *before* the final keys are compared with existing translation files. This is the ideal hook for parsing non-JavaScript files (like `.html`, `.vue`, or `.svelte`) and adding their keys to the collection.
394
- - `afterSync`: Runs after the extractor has compared the found keys with your translation files and generated the final results. This is perfect for post-processing tasks, like generating a report of newly added keys.
390
+ - `setup`: Runs once when the CLI is initialized. Use it for any setup tasks.
391
+ - `onLoad`: Runs for each file *before* it is parsed. You can use this to transform code (e.g., transpile a custom language to JavaScript).
392
+ - `onVisitNode`: Runs for every node in the Abstract Syntax Tree (AST) of a parsed JavaScript/TypeScript file. This provides access to the full parsing context, including variable scope and TypeScript-specific syntax like `satisfies` and `as` operators.
393
+ - `onEnd`: Runs after all JS/TS files have been parsed but *before* the final keys are compared with existing translation files. This is the ideal hook for parsing non-JavaScript files (like `.html`, `.vue`, or `.svelte`) and adding their keys to the collection.
394
+ - `afterSync`: Runs after the extractor has compared the found keys with your translation files and generated the final results. This is perfect for post-processing tasks, like generating a report of newly added keys.
395
395
 
396
396
  **Example Plugin (`my-custom-plugin.mjs`):**
397
397
 
package/dist/cjs/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var e=require("commander"),t=require("chokidar"),n=require("glob"),o=require("chalk"),i=require("./config.js"),a=require("./heuristic-config.js"),r=require("./extractor/core/extractor.js");require("node:path"),require("node:fs/promises"),require("jiti");var c=require("./types-generator.js"),s=require("./syncer.js"),l=require("./migrator.js"),u=require("./init.js"),d=require("./linter.js"),g=require("./status.js"),p=require("./locize.js");const f=new e.Command;f.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.5.10"),f.command("extract").description("Extract translation keys from source files and update resource files.").option("-w, --watch","Watch for file changes and re-run the extractor.").option("--ci","Exit with a non-zero status code if any files are updated.").option("--dry-run","Run the extractor without writing any files to disk.").action(async e=>{const a=await i.ensureConfig(),c=async()=>{const t=await r.runExtractor(a,{isWatchMode:e.watch,isDryRun:e.dryRun});e.ci&&t&&(console.error(o.red.bold("\n[CI Mode] Error: Translation files were updated. Please commit the changes.")),console.log(o.yellow("💡 Tip: Tired of committing JSON files? locize syncs your team automatically => https://www.locize.com/docs/getting-started")),console.log(` Learn more: ${o.cyan("npx i18next-cli locize-sync")}`),process.exit(1))};if(await c(),e.watch){console.log("\nWatching for changes...");t.watch(await n.glob(a.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),c()})}}),f.command("status [locale]").description("Display translation status. Provide a locale for a detailed key-by-key view.").option("-n, --namespace <ns>","Filter the status report by a specific namespace").action(async(e,t)=>{let n=await i.loadConfig();if(!n){console.log(o.blue("No config file found. Attempting to detect project structure..."));const e=await a.detectConfig();e||(console.error(o.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${o.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(o.green("Project structure detected successfully!")),n=e}await g.runStatus(n,{detail:e,namespace:t.namespace})}),f.command("types").description("Generate TypeScript definitions from translation resource files.").option("-w, --watch","Watch for file changes and re-run the type generator.").action(async e=>{const o=await i.ensureConfig(),a=()=>c.runTypesGenerator(o);if(await a(),e.watch){console.log("\nWatching for changes...");t.watch(await n.glob(o.types?.input||[]),{persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),a()})}}),f.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const e=await i.ensureConfig();await s.runSyncer(e)}),f.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async e=>{await l.runMigrator(e)}),f.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(u.runInit),f.command("lint").description("Find potential issues like hardcoded strings in your codebase.").option("-w, --watch","Watch for file changes and re-run the linter.").action(async e=>{const r=async()=>{let e=await i.loadConfig();if(!e){console.log(o.blue("No config file found. Attempting to detect project structure..."));const t=await a.detectConfig();t||(console.error(o.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${o.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(o.green("Project structure detected successfully!")),e=t}await d.runLinter(e)};if(await r(),e.watch){console.log("\nWatching for changes...");const e=await i.loadConfig();if(e?.extract?.input){t.watch(await n.glob(e.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),r()})}}}),f.command("locize-sync").description("Synchronize local translations with your locize project.").option("--update-values","Update values of existing translations on locize.").option("--src-lng-only","Check for changes in source language only.").option("--compare-mtime","Compare modification times when syncing.").option("--dry-run","Run the command without making any changes.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeSync(t,e)}),f.command("locize-download").description("Download all translations from your locize project.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeDownload(t,e)}),f.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeMigrate(t,e)}),f.parse(process.argv);
2
+ "use strict";var e=require("commander"),t=require("chokidar"),n=require("glob"),o=require("chalk"),i=require("./config.js"),a=require("./heuristic-config.js"),r=require("./extractor/core/extractor.js");require("node:path"),require("node:fs/promises"),require("jiti");var c=require("./types-generator.js"),s=require("./syncer.js"),l=require("./migrator.js"),u=require("./init.js"),d=require("./linter.js"),g=require("./status.js"),p=require("./locize.js");const f=new e.Command;f.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.6.0"),f.command("extract").description("Extract translation keys from source files and update resource files.").option("-w, --watch","Watch for file changes and re-run the extractor.").option("--ci","Exit with a non-zero status code if any files are updated.").option("--dry-run","Run the extractor without writing any files to disk.").action(async e=>{const a=await i.ensureConfig(),c=async()=>{const t=await r.runExtractor(a,{isWatchMode:e.watch,isDryRun:e.dryRun});e.ci&&t&&(console.error(o.red.bold("\n[CI Mode] Error: Translation files were updated. Please commit the changes.")),console.log(o.yellow("💡 Tip: Tired of committing JSON files? locize syncs your team automatically => https://www.locize.com/docs/getting-started")),console.log(` Learn more: ${o.cyan("npx i18next-cli locize-sync")}`),process.exit(1))};if(await c(),e.watch){console.log("\nWatching for changes...");t.watch(await n.glob(a.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),c()})}}),f.command("status [locale]").description("Display translation status. Provide a locale for a detailed key-by-key view.").option("-n, --namespace <ns>","Filter the status report by a specific namespace").action(async(e,t)=>{let n=await i.loadConfig();if(!n){console.log(o.blue("No config file found. Attempting to detect project structure..."));const e=await a.detectConfig();e||(console.error(o.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${o.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(o.green("Project structure detected successfully!")),n=e}await g.runStatus(n,{detail:e,namespace:t.namespace})}),f.command("types").description("Generate TypeScript definitions from translation resource files.").option("-w, --watch","Watch for file changes and re-run the type generator.").action(async e=>{const o=await i.ensureConfig(),a=()=>c.runTypesGenerator(o);if(await a(),e.watch){console.log("\nWatching for changes...");t.watch(await n.glob(o.types?.input||[]),{persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),a()})}}),f.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const e=await i.ensureConfig();await s.runSyncer(e)}),f.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async e=>{await l.runMigrator(e)}),f.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(u.runInit),f.command("lint").description("Find potential issues like hardcoded strings in your codebase.").option("-w, --watch","Watch for file changes and re-run the linter.").action(async e=>{const r=async()=>{let e=await i.loadConfig();if(!e){console.log(o.blue("No config file found. Attempting to detect project structure..."));const t=await a.detectConfig();t||(console.error(o.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${o.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(o.green("Project structure detected successfully!")),e=t}await d.runLinter(e)};if(await r(),e.watch){console.log("\nWatching for changes...");const e=await i.loadConfig();if(e?.extract?.input){t.watch(await n.glob(e.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),r()})}}}),f.command("locize-sync").description("Synchronize local translations with your locize project.").option("--update-values","Update values of existing translations on locize.").option("--src-lng-only","Check for changes in source language only.").option("--compare-mtime","Compare modification times when syncing.").option("--dry-run","Run the command without making any changes.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeSync(t,e)}),f.command("locize-download").description("Download all translations from your locize project.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeDownload(t,e)}),f.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async e=>{const t=await i.ensureConfig();await p.runLocizeMigrate(t,e)}),f.parse(process.argv);
@@ -1 +1 @@
1
- "use strict";var e=require("ora"),t=require("chalk"),r=require("@swc/core"),a=require("node:fs/promises"),n=require("node:path"),o=require("./key-finder.js"),s=require("./translation-manager.js"),i=require("../../utils/validation.js"),c=require("../plugin-manager.js"),l=require("../parsers/comment-parser.js"),u=require("../../utils/logger.js"),g=require("../../utils/file-utils.js"),f=require("../../utils/funnel-msg-tracker.js");function p(e,t,r,a=new u.ConsoleLogger){if(e&&"object"==typeof e){for(const n of t)try{n.onVisitNode?.(e,r)}catch(e){a.warn(`Plugin ${n.name} onVisitNode failed:`,e)}for(const n of Object.keys(e)){const o=e[n];if(Array.isArray(o))for(const e of o)e&&"object"==typeof e&&p(e,t,r,a);else o&&"object"==typeof o&&p(o,t,r,a)}}}exports.extract=async function(e){e.extract.primaryLanguage||=e.locales[0]||"en",e.extract.secondaryLanguages||=e.locales.filter(t=>t!==e?.extract?.primaryLanguage),e.extract.functions||=["t","*.t"],e.extract.transComponents||=["Trans"];const{allKeys:t,objectKeys:r}=await o.findKeys(e);return s.getTranslations(t,r,e)},exports.processFile=async function(e,t,n,o,s=new u.ConsoleLogger){try{let i=await a.readFile(e,"utf-8");for(const r of t.plugins||[])i=await(r.onLoad?.(i,e))??i;const u=await r.parse(i,{syntax:"typescript",tsx:!0,decorators:!0,comments:!0}),g=c.createPluginContext(n);l.extractKeysFromComments(i,g,t),o.visit(u),(t.plugins||[]).length>0&&p(u,t.plugins||[],g,s)}catch(t){throw new i.ExtractorError("Failed to process file",e,t)}},exports.runExtractor=async function(r,{isWatchMode:c=!1,isDryRun:l=!1}={},p=new u.ConsoleLogger){r.extract.primaryLanguage||=r.locales[0]||"en",r.extract.secondaryLanguages||=r.locales.filter(e=>e!==r?.extract?.primaryLanguage),r.extract.functions||=["t","*.t"],r.extract.transComponents||=["Trans"],i.validateExtractorConfig(r);const y=e("Running i18next key extractor...\n").start();try{const{allKeys:e,objectKeys:i}=await o.findKeys(r,p);y.text=`Found ${e.size} unique keys. Updating translation files...`;const c=await s.getTranslations(e,i,r);let u=!1;for(const e of c)if(e.updated&&(u=!0,!l)){const o=g.serializeTranslationFile(e.newTranslations,r.extract.outputFormat,r.extract.indentation);await a.mkdir(n.dirname(e.path),{recursive:!0}),await a.writeFile(e.path,o),p.info(t.green(`Updated: ${e.path}`))}if((r.plugins||[]).length>0){y.text="Running post-extraction plugins...";for(const e of r.plugins||[])await(e.afterSync?.(c,r))}return y.succeed(t.bold("Extraction complete!")),u&&await async function(){if(!await f.shouldShowFunnel("extract"))return;return console.log(t.yellow.bold("\n💡 Tip: Tired of running the extractor manually?")),console.log(' Discover a real-time "push" workflow with `saveMissing` and Locize AI,'),console.log(" where keys are created and translated automatically as you code."),console.log(` Learn more: ${t.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${t.cyan("https://youtu.be/joPsZghT3wM")}`),f.recordFunnelShown("extract")}(),u}catch(e){throw y.fail(t.red("Extraction failed.")),e}};
1
+ "use strict";var e=require("ora"),t=require("chalk"),r=require("@swc/core"),a=require("node:fs/promises"),n=require("node:path"),o=require("./key-finder.js"),i=require("./translation-manager.js"),s=require("../../utils/validation.js"),c=require("../plugin-manager.js"),l=require("../parsers/comment-parser.js"),u=require("../../utils/logger.js"),g=require("../../utils/file-utils.js"),f=require("../../utils/funnel-msg-tracker.js");function d(e,t,r,a=new u.ConsoleLogger){if(e&&"object"==typeof e){for(const n of t)try{n.onVisitNode?.(e,r)}catch(e){a.warn(`Plugin ${n.name} onVisitNode failed:`,e)}for(const n of Object.keys(e)){const o=e[n];if(Array.isArray(o))for(const e of o)e&&"object"==typeof e&&d(e,t,r,a);else o&&"object"==typeof o&&d(o,t,r,a)}}}exports.extract=async function(e){e.extract.primaryLanguage||=e.locales[0]||"en",e.extract.secondaryLanguages||=e.locales.filter(t=>t!==e?.extract?.primaryLanguage),e.extract.functions||=["t","*.t"],e.extract.transComponents||=["Trans"];const{allKeys:t,objectKeys:r}=await o.findKeys(e);return i.getTranslations(t,r,e)},exports.processFile=async function(e,t,n,o,i=new u.ConsoleLogger){try{let s=await a.readFile(e,"utf-8");for(const r of t.plugins||[])try{const t=await(r.onLoad?.(s,e));void 0!==t&&(s=t)}catch(e){i.warn(`Plugin ${r.name} onLoad failed:`,e)}const u=await r.parse(s,{syntax:"typescript",tsx:!0,decorators:!0,comments:!0}),g=c.createPluginContext(n,t,i);g.getVarFromScope=o.getVarFromScope.bind(o),l.extractKeysFromComments(s,g,t,o.getVarFromScope.bind(o)),o.visit(u),(t.plugins||[]).length>0&&d(u,t.plugins||[],g,i)}catch(t){throw new s.ExtractorError("Failed to process file",e,t)}},exports.runExtractor=async function(r,{isWatchMode:c=!1,isDryRun:l=!1}={},d=new u.ConsoleLogger){r.extract.primaryLanguage||=r.locales[0]||"en",r.extract.secondaryLanguages||=r.locales.filter(e=>e!==r?.extract?.primaryLanguage),r.extract.functions||=["t","*.t"],r.extract.transComponents||=["Trans"],s.validateExtractorConfig(r);const p=e("Running i18next key extractor...\n").start();try{const{allKeys:e,objectKeys:s}=await o.findKeys(r,d);p.text=`Found ${e.size} unique keys. Updating translation files...`;const c=await i.getTranslations(e,s,r);let u=!1;for(const e of c)if(e.updated&&(u=!0,!l)){const o=g.serializeTranslationFile(e.newTranslations,r.extract.outputFormat,r.extract.indentation);await a.mkdir(n.dirname(e.path),{recursive:!0}),await a.writeFile(e.path,o),d.info(t.green(`Updated: ${e.path}`))}if((r.plugins||[]).length>0){p.text="Running post-extraction plugins...";for(const e of r.plugins||[])await(e.afterSync?.(c,r))}return p.succeed(t.bold("Extraction complete!")),u&&await async function(){if(!await f.shouldShowFunnel("extract"))return;return console.log(t.yellow.bold("\n💡 Tip: Tired of running the extractor manually?")),console.log(' Discover a real-time "push" workflow with `saveMissing` and Locize AI,'),console.log(" where keys are created and translated automatically as you code."),console.log(` Learn more: ${t.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${t.cyan("https://youtu.be/joPsZghT3wM")}`),f.recordFunnelShown("extract")}(),u}catch(e){throw p.fail(t.red("Extraction failed.")),e}};
@@ -1 +1 @@
1
- "use strict";var e=require("glob"),r=require("./extractor.js"),t=require("../../utils/logger.js"),i=require("../plugin-manager.js"),s=require("../parsers/ast-visitors.js");exports.findKeys=async function(n,o=new t.ConsoleLogger){const a=await async function(r){const t=["node_modules/**"],i=Array.isArray(r.extract.ignore)?r.extract.ignore:r.extract.ignore?[r.extract.ignore]:[];return await e.glob(r.extract.input,{ignore:[...t,...i],cwd:process.cwd()})}(n),c=new Map,u=new s.ASTVisitors(n,i.createPluginContext(c),o);await i.initializePlugins(n.plugins||[]);for(const e of a)await r.processFile(e,n,c,u,o);for(const e of n.plugins||[])await(e.onEnd?.(c));return{allKeys:c,objectKeys:u.objectKeys}};
1
+ "use strict";var e=require("glob"),r=require("./extractor.js"),t=require("../../utils/logger.js"),i=require("../plugin-manager.js"),o=require("../parsers/ast-visitors.js");exports.findKeys=async function(n,s=new t.ConsoleLogger){const a=await async function(r){const t=["node_modules/**"],i=Array.isArray(r.extract.ignore)?r.extract.ignore:r.extract.ignore?[r.extract.ignore]:[];return await e.glob(r.extract.input,{ignore:[...t,...i],cwd:process.cwd()})}(n),c=new Map,g=i.createPluginContext(c,n,s),u=new o.ASTVisitors(n,g,s);g.getVarFromScope=u.getVarFromScope.bind(u),await i.initializePlugins(n.plugins||[]);for(const e of a)await r.processFile(e,n,c,u,s);for(const e of n.plugins||[])await(e.onEnd?.(c));return{allKeys:c,objectKeys:u.objectKeys}};
@@ -1 +1 @@
1
- "use strict";var e=require("./jsx-parser.js"),t=require("./ast-utils.js");exports.ASTVisitors=class{pluginContext;config;logger;scopeStack=[];objectKeys=new Set;constructor(e,t,n){this.pluginContext=t,this.config=e,this.logger=n}visit(e){this.enterScope(),this.walk(e),this.exitScope()}walk(e){if(!e)return;let t=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.enterScope(),t=!0),e.type){case"VariableDeclarator":this.handleVariableDeclarator(e);break;case"CallExpression":this.handleCallExpression(e);break;case"JSXElement":this.handleJSXElement(e)}for(const t in e){if("span"===t)continue;const n=e[t];if(Array.isArray(n))for(const e of n)e&&"object"==typeof e&&this.walk(e);else n&&"object"==typeof n&&this.walk(n)}t&&this.exitScope()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0&&this.scopeStack[this.scopeStack.length-1].set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e))return this.scopeStack[t].get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;const n="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!n)return;const r=n.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return void this.handleUseTranslationDeclarator(e,n,t)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,n)}handleUseTranslationDeclarator(e,n,r){let s;if("Identifier"===e.id.type&&(s=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(s=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value){s="t";break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value&&"Identifier"===t.value.type){s=t.value.value;break}}if(!s)return;const i=n.arguments?.[r.nsArg]?.expression;let a;"StringLiteral"===i?.type?a=i.value:"ArrayExpression"===i?.type&&"StringLiteral"===i.elements[0]?.expression.type&&(a=i.elements[0].expression.value);const o=n.arguments?.[r.keyPrefixArg]?.expression;let l;if("ObjectExpression"===o?.type){const e=t.getObjectPropValue(o,"keyPrefix");l="string"==typeof e?e:void 0}this.setVarInScope(s,{defaultNs:a,keyPrefix:l})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const n=e.id.value,r=t.arguments,s=r[1]?.expression,i=r[2]?.expression,a="StringLiteral"===s?.type?s.value:void 0,o="StringLiteral"===i?.type?i.value:void 0;(a||o)&&this.setVarInScope(n,{defaultNs:a,keyPrefix:o})}handleCallExpression(e){const n=this.getFunctionName(e.callee);if(!n)return;const r=this.getVarFromScope(n),s=this.config.extract.functions||["t","*.t"];let i=void 0!==r;if(!i)for(const e of s)if(e.startsWith("*.")){if(n.endsWith(e.substring(1))){i=!0;break}}else if(e===n){i=!0;break}if(!i||0===e.arguments.length)return;const{keysToProcess:a,isSelectorAPI:o}=this.handleCallExpressionArgument(e,0);if(0===a.length)return;let l=!1;const u=this.config.extract.pluralSeparator??"_";for(let e=0;e<a.length;e++)a[e].endsWith(`${u}ordinal`)&&(l=!0,a[e]=a[e].slice(0,-8));let p,c;if(e.arguments.length>1){const t=e.arguments[1].expression;"ObjectExpression"===t.type?c=t:"StringLiteral"===t.type&&(p=t.value)}if(e.arguments.length>2){const t=e.arguments[2].expression;"ObjectExpression"===t.type&&(c=t)}const f=c?t.getObjectPropValue(c,"defaultValue"):void 0,g="string"==typeof f?f:p;for(let e=0;e<a.length;e++){let n,s=a[e];if(c){const e=t.getObjectPropValue(c,"ns");"string"==typeof e&&(n=e)}const i=this.config.extract.nsSeparator??":";if(!n&&i&&s.includes(i)){const e=s.split(i);n=e.shift(),s=e.join(i)}!n&&r?.defaultNs&&(n=r.defaultNs),n||(n=this.config.extract.defaultNS);let u=s;if(r?.keyPrefix){const e=this.config.extract.keySeparator??".";u=`${r.keyPrefix}${e}${s}`}const p=e===a.length-1&&g||s;if(c){const e=t.getObjectProperty(c,"context"),r=[];if("ConditionalExpression"===e?.value?.type){const t=this.resolvePossibleStringValues(e.value),s=this.config.extract.contextSeparator??"_";t.length>0&&(t.forEach(e=>{r.push({key:`${u}${s}${e}`,ns:n,defaultValue:p})}),r.push({key:u,ns:n,defaultValue:p}))}else if("StringLiteral"===e?.value?.type){const t=e.value.value,s=this.config.extract.contextSeparator??"_";r.push({key:`${u}${s}${t}`,ns:n,defaultValue:p})}const s=void 0!==t.getObjectPropValue(c,"count"),i=!0===t.getObjectPropValue(c,"ordinal");if(s||l){if(r.length>0)for(const{key:e,ns:t}of r)this.handlePluralKeys(e,t,c,i||l);else this.handlePluralKeys(u,n,c,i||l);continue}if(r.length>0){r.forEach(this.pluginContext.addKey);continue}!0===t.getObjectPropValue(c,"returnObjects")&&this.objectKeys.add(u)}o&&this.objectKeys.add(u),this.pluginContext.addKey({key:u,ns:n,defaultValue:p})}}handleCallExpressionArgument(e,t){const n=e.arguments[t].expression,r=[];let s=!1;if("ArrowFunctionExpression"===n.type){const e=this.extractKeyFromSelector(n);e&&(r.push(e),s=!0)}else if("ArrayExpression"===n.type)for(const e of n.elements)e?.expression&&r.push(...this.resolvePossibleStringValues(e.expression));else r.push(...this.resolvePossibleStringValues(n));return{keysToProcess:r.filter(e=>!!e),isSelectorAPI:s}}handlePluralKeys(e,n,r,s){try{const i=s?"ordinal":"cardinal",a=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:i}).resolvedOptions().pluralCategories,o=this.config.extract.pluralSeparator??"_",l=t.getObjectPropValue(r,"defaultValue"),u=t.getObjectPropValue(r,`defaultValue${o}other`),p=t.getObjectPropValue(r,`defaultValue${o}ordinal${o}other`);for(const i of a){const a=s?`defaultValue${o}ordinal${o}${i}`:`defaultValue${o}${i}`,c=t.getObjectPropValue(r,a);let f;f="string"==typeof c?c:"one"===i&&"string"==typeof l?l:s&&"string"==typeof p?p:s||"string"!=typeof u?"string"==typeof l?l:e:u;const g=s?`${e}${o}ordinal${o}${i}`:`${e}${o}${i}`;this.pluginContext.addKey({key:g,ns:n,defaultValue:f,hasCount:!0,isOrdinal:s})}}catch(s){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const i=t.getObjectPropValue(r,"defaultValue");this.pluginContext.addKey({key:e,ns:n,defaultValue:"string"==typeof i?i:e})}}handleSimplePluralKeys(e,t,n){try{const r=new Intl.PluralRules(this.config.extract?.primaryLanguage).resolvedOptions().pluralCategories,s=this.config.extract.pluralSeparator??"_";for(const i of r)this.pluginContext.addKey({key:`${e}${s}${i}`,ns:n,defaultValue:t,hasCount:!0})}catch(r){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}".`),this.pluginContext.addKey({key:e,ns:n,defaultValue:t})}}handleJSXElement(t){const n=this.getElementName(t);if(n&&(this.config.extract.transComponents||["Trans"]).includes(n)){const n=e.extractFromTransComponent(t,this.config),r=[];if(n){if(n.keyExpression){const e=this.resolvePossibleStringValues(n.keyExpression);r.push(...e)}else r.push(n.serializedChildren);let e;const{contextExpression:s,optionsNode:i,defaultValue:a,hasCount:o,isOrdinal:l,serializedChildren:u}=n;if(n.ns){const{ns:t}=n;e=r.map(e=>({key:e,ns:t,defaultValue:a||u,hasCount:o,isOrdinal:l}))}else{e=r.map(e=>{const t=this.config.extract.nsSeparator??":";let n;if(t&&e.includes(t)){let r;[n,...r]=e.split(t),e=r.join(t)}return{key:e,ns:n,defaultValue:a||u,hasCount:o,isOrdinal:l}});const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===n?.type&&"JSXExpressionContainer"===n.value?.type&&"Identifier"===n.value.expression.type){const t=n.value.expression.value,r=this.getVarFromScope(t);r?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=r.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),s&&o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),r=!!n,a=this.resolvePossibleStringValues(s),o=this.config.extract.contextSeparator??"_";if(a.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i));for(const t of a)for(const n of e){const e=`${n.key}${o}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,r,i)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i))}else if(s){const t=this.resolvePossibleStringValues(s),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const r of t)for(const{key:t,ns:s,defaultValue:i}of e)this.pluginContext.addKey({key:`${t}${n}${r}`,ns:s,defaultValue:i});"StringLiteral"!==s.type&&e.forEach(this.pluginContext.addKey)}}else if(o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),r=!!n;e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i))}else e.forEach(this.pluginContext.addKey)}}}generatePluralKeysForTrans(e,n,r,s,i){try{const a=s?"ordinal":"cardinal",o=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:a}).resolvedOptions().pluralCategories,l=this.config.extract.pluralSeparator??"_";let u,p;i&&(u=t.getObjectPropValue(i,`defaultValue${l}other`),p=t.getObjectPropValue(i,`defaultValue${l}ordinal${l}other`));for(const a of o){const o=s?`defaultValue${l}ordinal${l}${a}`:`defaultValue${l}${a}`,c=i?t.getObjectPropValue(i,o):void 0;let f;f="string"==typeof c?c:"one"===a&&"string"==typeof n?n:s&&"string"==typeof p?p:s||"string"!=typeof u?"string"==typeof n?n:e:u;const g=s?`${e}${l}ordinal${l}${a}`:`${e}${l}${a}`;this.pluginContext.addKey({key:g,ns:r,defaultValue:f,hasCount:!0,isOrdinal:s})}}catch(t){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`),this.pluginContext.addKey({key:e,ns:r,defaultValue:n})}}getElementName(e){if("Identifier"===e.opening.name.type)return e.opening.name.value;if("JSXMemberExpression"===e.opening.name.type){let t=e.opening.name;const n=[];for(;"JSXMemberExpression"===t.type;)"Identifier"===t.property.type&&n.unshift(t.property.value),t=t.object;return"Identifier"===t.type&&n.unshift(t.value),n.join(".")}}extractKeyFromSelector(e){let t=e.body;if("BlockStatement"===t.type){const e=t.stmts.find(e=>"ReturnStatement"===e.type);if("ReturnStatement"!==e?.type||!e.argument)return null;t=e.argument}let n=t;const r=[];for(;"MemberExpression"===n.type;){const e=n.property;if("Identifier"===e.type)r.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;r.unshift(e.expression.value)}n=n.object}if(r.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return r.join(t)}return null}resolvePossibleStringValues(e){if("StringLiteral"===e.type)return e.value?[e.value]:[];if("ConditionalExpression"===e.type){return[...this.resolvePossibleStringValues(e.consequent),...this.resolvePossibleStringValues(e.alternate)]}return"Identifier"===e.type&&"undefined"===e.value?[]:"TemplateLiteral"===e.type?this.resolvePossibleStringValuesFromTemplateString(e):"NumericLiteral"===e.type||"BooleanLiteral"===e.type?[`${e.value}`]:[]}resolvePossibleStringValuesFromTemplateString(e){if(1===e.quasis.length&&0===e.expressions.length)return[e.quasis[0].cooked||""];const[t,...n]=e.quasis;return e.expressions.reduce((e,t,r)=>e.flatMap(e=>{const s=n[r]?.cooked??"";return this.resolvePossibleStringValues(t).map(t=>`${e}${t}${s}`)}),[t.cooked??""])}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const n of t){if("string"==typeof n&&n===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof n&&n.name===e)return{name:n.name,nsArg:n.nsArg??0,keyPrefixArg:n.keyPrefixArg??1}}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let n=e;for(;"MemberExpression"===n.type;){if("Identifier"!==n.property.type)return null;t.unshift(n.property.value),n=n.object}if("ThisExpression"===n.type)t.unshift("this");else{if("Identifier"!==n.type)return null;t.unshift(n.value)}return t.join(".")}return null}};
1
+ "use strict";var e=require("./jsx-parser.js"),t=require("./ast-utils.js");exports.ASTVisitors=class{pluginContext;config;logger;scopeStack=[];objectKeys=new Set;constructor(e,t,n){this.pluginContext=t,this.config=e,this.logger=n}visit(e){this.enterScope(),this.walk(e),this.exitScope()}walk(e){if(!e)return;let t=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.enterScope(),t=!0),e.type){case"VariableDeclarator":this.handleVariableDeclarator(e);break;case"CallExpression":this.handleCallExpression(e);break;case"JSXElement":this.handleJSXElement(e)}for(const t in e){if("span"===t)continue;const n=e[t];if(Array.isArray(n))for(const e of n)e&&"object"==typeof e&&this.walk(e);else n&&"object"==typeof n&&this.walk(n)}t&&this.exitScope()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0&&this.scopeStack[this.scopeStack.length-1].set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e))return this.scopeStack[t].get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;const n="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!n)return;const r=n.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return void this.handleUseTranslationDeclarator(e,n,t)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,n)}handleUseTranslationDeclarator(e,n,r){let s;if("Identifier"===e.id.type&&(s=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(s=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value){s="t";break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value&&"Identifier"===t.value.type){s=t.value.value;break}}if(!s)return;const i=n.arguments?.[r.nsArg]?.expression;let a;"StringLiteral"===i?.type?a=i.value:"ArrayExpression"===i?.type&&"StringLiteral"===i.elements[0]?.expression.type&&(a=i.elements[0].expression.value);const o=n.arguments?.[r.keyPrefixArg]?.expression;let l;if("ObjectExpression"===o?.type){const e=t.getObjectPropValue(o,"keyPrefix");l="string"==typeof e?e:void 0}this.setVarInScope(s,{defaultNs:a,keyPrefix:l})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const n=e.id.value,r=t.arguments,s=r[1]?.expression,i=r[2]?.expression,a="StringLiteral"===s?.type?s.value:void 0,o="StringLiteral"===i?.type?i.value:void 0;(a||o)&&this.setVarInScope(n,{defaultNs:a,keyPrefix:o})}handleCallExpression(e){const n=this.getFunctionName(e.callee);if(!n)return;const r=this.getVarFromScope(n),s=this.config.extract.functions||["t","*.t"];let i=void 0!==r;if(!i)for(const e of s)if(e.startsWith("*.")){if(n.endsWith(e.substring(1))){i=!0;break}}else if(e===n){i=!0;break}if(!i||0===e.arguments.length)return;const{keysToProcess:a,isSelectorAPI:o}=this.handleCallExpressionArgument(e,0);if(0===a.length)return;let l=!1;const u=this.config.extract.pluralSeparator??"_";for(let e=0;e<a.length;e++)a[e].endsWith(`${u}ordinal`)&&(l=!0,a[e]=a[e].slice(0,-8));let p,c;if(e.arguments.length>1){const t=e.arguments[1].expression;"ObjectExpression"===t.type?c=t:"StringLiteral"===t.type&&(p=t.value)}if(e.arguments.length>2){const t=e.arguments[2].expression;"ObjectExpression"===t.type&&(c=t)}const f=c?t.getObjectPropValue(c,"defaultValue"):void 0,g="string"==typeof f?f:p;for(let e=0;e<a.length;e++){let n,s=a[e];if(c){const e=t.getObjectPropValue(c,"ns");"string"==typeof e&&(n=e)}const i=this.config.extract.nsSeparator??":";if(!n&&i&&s.includes(i)){const e=s.split(i);n=e.shift(),s=e.join(i)}!n&&r?.defaultNs&&(n=r.defaultNs),n||(n=this.config.extract.defaultNS);let u=s;if(r?.keyPrefix){const e=this.config.extract.keySeparator??".";u=`${r.keyPrefix}${e}${s}`}const p=e===a.length-1&&g||s;if(c){const e=t.getObjectProperty(c,"context"),r=[];if("ConditionalExpression"===e?.value?.type){const t=this.resolvePossibleStringValues(e.value),s=this.config.extract.contextSeparator??"_";t.length>0&&(t.forEach(e=>{r.push({key:`${u}${s}${e}`,ns:n,defaultValue:p})}),r.push({key:u,ns:n,defaultValue:p}))}else if("StringLiteral"===e?.value?.type){const t=e.value.value,s=this.config.extract.contextSeparator??"_";r.push({key:`${u}${s}${t}`,ns:n,defaultValue:p})}const s=void 0!==t.getObjectPropValue(c,"count"),i=!0===t.getObjectPropValue(c,"ordinal");if(s||l){if(r.length>0)for(const{key:e,ns:t}of r)this.handlePluralKeys(e,t,c,i||l);else this.handlePluralKeys(u,n,c,i||l);continue}if(r.length>0){r.forEach(this.pluginContext.addKey);continue}!0===t.getObjectPropValue(c,"returnObjects")&&this.objectKeys.add(u)}o&&this.objectKeys.add(u),this.pluginContext.addKey({key:u,ns:n,defaultValue:p})}}handleCallExpressionArgument(e,t){const n=e.arguments[t].expression,r=[];let s=!1;if("ArrowFunctionExpression"===n.type){const e=this.extractKeyFromSelector(n);e&&(r.push(e),s=!0)}else if("ArrayExpression"===n.type)for(const e of n.elements)e?.expression&&r.push(...this.resolvePossibleStringValues(e.expression));else r.push(...this.resolvePossibleStringValues(n));return{keysToProcess:r.filter(e=>!!e),isSelectorAPI:s}}handlePluralKeys(e,n,r,s){try{const i=s?"ordinal":"cardinal",a=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:i}).resolvedOptions().pluralCategories,o=this.config.extract.pluralSeparator??"_",l=t.getObjectPropValue(r,"defaultValue"),u=t.getObjectPropValue(r,`defaultValue${o}other`),p=t.getObjectPropValue(r,`defaultValue${o}ordinal${o}other`);for(const i of a){const a=s?`defaultValue${o}ordinal${o}${i}`:`defaultValue${o}${i}`,c=t.getObjectPropValue(r,a);let f;f="string"==typeof c?c:"one"===i&&"string"==typeof l?l:s&&"string"==typeof p?p:s||"string"!=typeof u?"string"==typeof l?l:e:u;const g=s?`${e}${o}ordinal${o}${i}`:`${e}${o}${i}`;this.pluginContext.addKey({key:g,ns:n,defaultValue:f,hasCount:!0,isOrdinal:s})}}catch(s){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const i=t.getObjectPropValue(r,"defaultValue");this.pluginContext.addKey({key:e,ns:n,defaultValue:"string"==typeof i?i:e})}}handleSimplePluralKeys(e,t,n){try{const r=new Intl.PluralRules(this.config.extract?.primaryLanguage).resolvedOptions().pluralCategories,s=this.config.extract.pluralSeparator??"_";for(const i of r)this.pluginContext.addKey({key:`${e}${s}${i}`,ns:n,defaultValue:t,hasCount:!0})}catch(r){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}".`),this.pluginContext.addKey({key:e,ns:n,defaultValue:t})}}handleJSXElement(t){const n=this.getElementName(t);if(n&&(this.config.extract.transComponents||["Trans"]).includes(n)){const n=e.extractFromTransComponent(t,this.config),r=[];if(n){if(n.keyExpression){const e=this.resolvePossibleStringValues(n.keyExpression);r.push(...e)}else r.push(n.serializedChildren);let e;const{contextExpression:s,optionsNode:i,defaultValue:a,hasCount:o,isOrdinal:l,serializedChildren:u}=n;if(n.ns){const{ns:t}=n;e=r.map(e=>({key:e,ns:t,defaultValue:a||u,hasCount:o,isOrdinal:l}))}else{e=r.map(e=>{const t=this.config.extract.nsSeparator??":";let n;if(t&&e.includes(t)){let r;[n,...r]=e.split(t),e=r.join(t)}return{key:e,ns:n,defaultValue:a||u,hasCount:o,isOrdinal:l}});const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===n?.type&&"JSXExpressionContainer"===n.value?.type&&"Identifier"===n.value.expression.type){const t=n.value.expression.value,r=this.getVarFromScope(t);r?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=r.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),s&&o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),r=!!n,a=this.resolvePossibleStringValues(s),o=this.config.extract.contextSeparator??"_";if(a.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i));for(const t of a)for(const n of e){const e=`${n.key}${o}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,r,i)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i))}else if(s){const t=this.resolvePossibleStringValues(s),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const r of t)for(const{key:t,ns:s,defaultValue:i}of e)this.pluginContext.addKey({key:`${t}${n}${r}`,ns:s,defaultValue:i});"StringLiteral"!==s.type&&e.forEach(this.pluginContext.addKey)}}else if(o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),r=!!n;e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,r,i))}else e.forEach(this.pluginContext.addKey)}}}generatePluralKeysForTrans(e,n,r,s,i){try{const a=s?"ordinal":"cardinal",o=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:a}).resolvedOptions().pluralCategories,l=this.config.extract.pluralSeparator??"_";let u,p;i&&(u=t.getObjectPropValue(i,`defaultValue${l}other`),p=t.getObjectPropValue(i,`defaultValue${l}ordinal${l}other`));for(const a of o){const o=s?`defaultValue${l}ordinal${l}${a}`:`defaultValue${l}${a}`,c=i?t.getObjectPropValue(i,o):void 0;let f;f="string"==typeof c?c:"one"===a&&"string"==typeof n?n:s&&"string"==typeof p?p:s||"string"!=typeof u?"string"==typeof n?n:e:u;const g=s?`${e}${l}ordinal${l}${a}`:`${e}${l}${a}`;this.pluginContext.addKey({key:g,ns:r,defaultValue:f,hasCount:!0,isOrdinal:s})}}catch(t){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`),this.pluginContext.addKey({key:e,ns:r,defaultValue:n})}}getElementName(e){if("Identifier"===e.opening.name.type)return e.opening.name.value;if("JSXMemberExpression"===e.opening.name.type){let t=e.opening.name;const n=[];for(;"JSXMemberExpression"===t.type;)"Identifier"===t.property.type&&n.unshift(t.property.value),t=t.object;return"Identifier"===t.type&&n.unshift(t.value),n.join(".")}}extractKeyFromSelector(e){let t=e.body;if("BlockStatement"===t.type){const e=t.stmts.find(e=>"ReturnStatement"===e.type);if("ReturnStatement"!==e?.type||!e.argument)return null;t=e.argument}let n=t;const r=[];for(;"MemberExpression"===n.type;){const e=n.property;if("Identifier"===e.type)r.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;r.unshift(e.expression.value)}n=n.object}if(r.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return r.join(t)}return null}resolvePossibleStringValues(e,t=!1){if("StringLiteral"===e.type)return e.value||t?[e.value]:[];if("ConditionalExpression"===e.type){return[...this.resolvePossibleStringValues(e.consequent,t),...this.resolvePossibleStringValues(e.alternate,t)]}return"Identifier"===e.type&&"undefined"===e.value?[]:"TemplateLiteral"===e.type?this.resolvePossibleStringValuesFromTemplateString(e):"NumericLiteral"===e.type||"BooleanLiteral"===e.type?[`${e.value}`]:[]}resolvePossibleStringValuesFromTemplateString(e){if(1===e.quasis.length&&0===e.expressions.length)return[e.quasis[0].cooked||""];const[t,...n]=e.quasis;return e.expressions.reduce((e,t,r)=>e.flatMap(e=>{const s=n[r]?.cooked??"";return this.resolvePossibleStringValues(t,!0).map(t=>`${e}${t}${s}`)}),[t.cooked??""])}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const n of t){if("string"==typeof n&&n===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof n&&n.name===e)return{name:n.name,nsArg:n.nsArg??0,keyPrefixArg:n.keyPrefixArg??1}}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let n=e;for(;"MemberExpression"===n.type;){if("Identifier"!==n.property.type)return null;t.unshift(n.property.value),n=n.object}if("ThisExpression"===n.type)t.unshift("this");else{if("Identifier"!==n.type)return null;t.unshift(n.value)}return t.join(".")}return null}};
@@ -1 +1 @@
1
- "use strict";function t(t){const e=/^\s*,\s*(['"])(.*?)\1/.exec(t);if(e)return e[2];const s=/^\s*,\s*\{[^}]*defaultValue\s*:\s*(['"])(.*?)\1/.exec(t);return s?s[2]:void 0}function e(t){const e=/^\s*,\s*\{[^}]*ns\s*:\s*(['"])(.*?)\1/.exec(t);if(e)return e[2]}exports.extractKeysFromComments=function(s,n,c){const o=new RegExp("\\bt\\s*\\(\\s*(['\"])([^'\"]+)\\1","g"),r=function(t){const e=[],s=new Set,n=/\/\/(.*)|\/\*([\s\S]*?)\*\//g;let c;for(;null!==(c=n.exec(t));){const t=(c[1]??c[2]).trim();t&&!s.has(t)&&(s.add(t),e.push(t))}return e}(s);for(const s of r){let r;for(;null!==(r=o.exec(s));){let o,u=r[2];const i=s.slice(r.index+r[0].length),l=t(i);o=e(i);const f=c.extract.nsSeparator??":";if(!o&&f&&u.includes(f)){const t=u.split(f);o=t.shift(),u=t.join(f)}o||(o=c.extract.defaultNS),n.addKey({key:u,ns:o,defaultValue:l??u})}}};
1
+ "use strict";function t(t){const e=/^\s*,\s*(['"])(.*?)\1/.exec(t);if(e)return e[2];const s=/^\s*,\s*\{[^}]*defaultValue\s*:\s*(['"])(.*?)\1/.exec(t);return s?s[2]:void 0}function e(t){const e=/^\s*,\s*\{[^}]*ns\s*:\s*(['"])(.*?)\1/.exec(t);if(e)return e[2]}exports.extractKeysFromComments=function(s,n,c,o){const r=new RegExp("\\bt\\s*\\(\\s*(['\"])([^'\"]+)\\1","g"),u=function(t){const e=[],s=new Set,n=/\/\/(.*)|\/\*([\s\S]*?)\*\//g;let c;for(;null!==(c=n.exec(t));){const t=(c[1]??c[2]).trim();t&&!s.has(t)&&(s.add(t),e.push(t))}return e}(s);for(const s of u){let u;for(;null!==(u=r.exec(s));){let r,f=u[2];const l=s.slice(u.index+u[0].length),i=t(l);r=e(l);const a=c.extract.nsSeparator??":";if(!r&&a&&f.includes(a)){const t=f.split(a);r=t.shift(),f=t.join(a)}if(!r&&o){const t=o("t");t?.defaultNs&&(r=t.defaultNs)}r||(r=c.extract.defaultNS),n.addKey({key:f,ns:r,defaultValue:i??f})}}};
@@ -1 +1 @@
1
- "use strict";var e=require("./ast-utils.js");exports.extractFromTransComponent=function(t,n){const i=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"i18nKey"===e.name.value),r=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"defaults"===e.name.value),a=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"count"===e.name.value),s=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"values"===e.name.value);let p;a||"JSXAttribute"!==s?.type||"JSXExpressionContainer"!==s.value?.type||"ObjectExpression"!==s.value.expression.type||(p=e.getObjectProperty(s.value.expression,"count"));const u=!!a||!!p,o=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"tOptions"===e.name.value),l="JSXAttribute"===o?.type&&"JSXExpressionContainer"===o.value?.type&&"ObjectExpression"===o.value.expression.type?o.value.expression:void 0,y=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),v=!!y,d=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"context"===e.name.value);let c="JSXAttribute"===d?.type&&"JSXExpressionContainer"===d.value?.type?d.value.expression:void 0;const f=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ns"===e.name.value);let b;if(b="JSXAttribute"===f?.type&&"StringLiteral"===f.value?.type?f.value.value:void 0,l&&(void 0===b&&(b=e.getObjectPropValue(l,"ns")),void 0===c)){const t=e.getObjectProperty(l,"context");t?.value&&(c=t.value)}const S=function(e,t){const n=new Set(t.extract.transKeepBasicHtmlNodesFor??["br","strong","i","p"]);function i(e){let t="";return e.forEach((e,r)=>{if("JSXText"===e.type)t+=e.value;else if("JSXExpressionContainer"===e.type){const n=e.expression;if("StringLiteral"===n.type)t+=n.value;else if("Identifier"===n.type)t+=`{{${n.value}}}`;else if("ObjectExpression"===n.type){const e=n.properties[0];e&&"Identifier"===e.type&&(t+=`{{${e.value}}}`)}}else if("JSXElement"===e.type){let a;"Identifier"===e.opening.name.type&&(a=e.opening.name.value);const s=i(e.children);a&&n.has(a)?t+=`<${a}>${s}</${a}>`:t+=`<${r}>${s}</${r}>`}else"JSXFragment"===e.type&&(t+=i(e.children))}),t}return i(e).trim().replace(/\s{2,}/g," ")}(t.children,n);let x,m=n.extract.defaultValue||"";return"JSXAttribute"===r?.type&&"StringLiteral"===r.value?.type&&(m=r.value.value),"JSXAttribute"!==i?.type||("StringLiteral"===i.value?.type?x=i.value:"JSXExpressionContainer"===i.value?.type&&"JSXEmptyExpression"!==i.value.expression.type&&(x=i.value.expression),x)?{keyExpression:x,serializedChildren:S,ns:b,defaultValue:m,hasCount:u,isOrdinal:v,contextExpression:c,optionsNode:l}:null};
1
+ "use strict";var e=require("./ast-utils.js");exports.extractFromTransComponent=function(t,n){const i=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"i18nKey"===e.name.value),r=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"defaults"===e.name.value),a=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"count"===e.name.value),s=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"values"===e.name.value);let p;a||"JSXAttribute"!==s?.type||"JSXExpressionContainer"!==s.value?.type||"ObjectExpression"!==s.value.expression.type||(p=e.getObjectProperty(s.value.expression,"count"));const u=!!a||!!p,l=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"tOptions"===e.name.value),o="JSXAttribute"===l?.type&&"JSXExpressionContainer"===l.value?.type&&"ObjectExpression"===l.value.expression.type?l.value.expression:void 0,y=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),v=!!y,f=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"context"===e.name.value);let c="JSXAttribute"===f?.type&&"JSXExpressionContainer"===f.value?.type?f.value.expression:void 0;const d=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ns"===e.name.value);let S;if(S="JSXAttribute"===d?.type&&"StringLiteral"===d.value?.type?d.value.value:void 0,o&&(void 0===S&&(S=e.getObjectPropValue(o,"ns")),void 0===c)){const t=e.getObjectProperty(o,"context");t?.value&&(c=t.value)}const b=function(e,t){const n=new Set(t.extract.transKeepBasicHtmlNodesFor??["br","strong","i","p"]);function i(e){let t="";return e.forEach((e,r)=>{if("JSXText"===e.type)t+=e.value;else if("JSXExpressionContainer"===e.type){const n=e.expression;if("StringLiteral"===n.type)t+=n.value;else if("Identifier"===n.type)t+=`{{${n.value}}}`;else if("ObjectExpression"===n.type){const e=n.properties[0];e&&"Identifier"===e.type&&(t+=`{{${e.value}}}`)}}else if("JSXElement"===e.type){let a;"Identifier"===e.opening.name.type&&(a=e.opening.name.value);const s=i(e.children);a&&n.has(a)?t+=`<${a}>${s}</${a}>`:t+=`<${r}>${s}</${r}>`}else"JSXFragment"===e.type&&(t+=i(e.children))}),t}return i(e).trim().replace(/\s{2,}/g," ")}(t.children,n);let x,m,J=n.extract.defaultValue||"";if("JSXAttribute"===r?.type&&"StringLiteral"===r.value?.type&&(J=r.value.value),"JSXAttribute"===i?.type){if("StringLiteral"===i.value?.type){if(x=i.value,m=x.value,S&&"StringLiteral"===x.type){const e=n.extract.nsSeparator??":",t=x.value;e&&t.startsWith(`${S}${e}`)&&(m=t.slice(`${S}${e}`.length),x={...x,value:m})}}else"JSXExpressionContainer"===i.value?.type&&"JSXEmptyExpression"!==i.value.expression.type&&(x=i.value.expression);if(!x)return null}return r||!m||b.trim()?!r&&b.trim()&&(J=b):J=m,{keyExpression:x,serializedChildren:b,ns:S,defaultValue:J,hasCount:u,isOrdinal:v,contextExpression:c,optionsNode:o}};
@@ -1 +1 @@
1
- "use strict";exports.createPluginContext=function(t){return{addKey:e=>{const n=`${e.ns??"translation"}:${e.key}`;if(!t.has(n)){const s=e.defaultValue??e.key;t.set(n,{...e,defaultValue:s})}}}},exports.initializePlugins=async function(t){for(const e of t)await(e.setup?.())};
1
+ "use strict";exports.createPluginContext=function(t,e,n){return{addKey:e=>{const n=`${e.ns??"translation"}:${e.key}`;if(!t.has(n)){const o=e.defaultValue??e.key;t.set(n,{...e,defaultValue:o})}},config:e,logger:n,getVarFromScope:()=>{}}},exports.initializePlugins=async function(t){for(const e of t)await(e.setup?.())};
package/dist/esm/cli.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{Command as t}from"commander";import o from"chokidar";import{glob as e}from"glob";import n from"chalk";import{ensureConfig as i,loadConfig as a}from"./config.js";import{detectConfig as c}from"./heuristic-config.js";import{runExtractor as r}from"./extractor/core/extractor.js";import"node:path";import"node:fs/promises";import"jiti";import{runTypesGenerator as s}from"./types-generator.js";import{runSyncer as l}from"./syncer.js";import{runMigrator as m}from"./migrator.js";import{runInit as p}from"./init.js";import{runLinter as d}from"./linter.js";import{runStatus as g}from"./status.js";import{runLocizeSync as f,runLocizeDownload as u,runLocizeMigrate as h}from"./locize.js";const w=new t;w.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.5.10"),w.command("extract").description("Extract translation keys from source files and update resource files.").option("-w, --watch","Watch for file changes and re-run the extractor.").option("--ci","Exit with a non-zero status code if any files are updated.").option("--dry-run","Run the extractor without writing any files to disk.").action(async t=>{const a=await i(),c=async()=>{const o=await r(a,{isWatchMode:t.watch,isDryRun:t.dryRun});t.ci&&o&&(console.error(n.red.bold("\n[CI Mode] Error: Translation files were updated. Please commit the changes.")),console.log(n.yellow("💡 Tip: Tired of committing JSON files? locize syncs your team automatically => https://www.locize.com/docs/getting-started")),console.log(` Learn more: ${n.cyan("npx i18next-cli locize-sync")}`),process.exit(1))};if(await c(),t.watch){console.log("\nWatching for changes...");o.watch(await e(a.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),c()})}}),w.command("status [locale]").description("Display translation status. Provide a locale for a detailed key-by-key view.").option("-n, --namespace <ns>","Filter the status report by a specific namespace").action(async(t,o)=>{let e=await a();if(!e){console.log(n.blue("No config file found. Attempting to detect project structure..."));const t=await c();t||(console.error(n.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${n.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(n.green("Project structure detected successfully!")),e=t}await g(e,{detail:t,namespace:o.namespace})}),w.command("types").description("Generate TypeScript definitions from translation resource files.").option("-w, --watch","Watch for file changes and re-run the type generator.").action(async t=>{const n=await i(),a=()=>s(n);if(await a(),t.watch){console.log("\nWatching for changes...");o.watch(await e(n.types?.input||[]),{persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),a()})}}),w.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const t=await i();await l(t)}),w.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async t=>{await m(t)}),w.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(p),w.command("lint").description("Find potential issues like hardcoded strings in your codebase.").option("-w, --watch","Watch for file changes and re-run the linter.").action(async t=>{const i=async()=>{let t=await a();if(!t){console.log(n.blue("No config file found. Attempting to detect project structure..."));const o=await c();o||(console.error(n.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${n.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(n.green("Project structure detected successfully!")),t=o}await d(t)};if(await i(),t.watch){console.log("\nWatching for changes...");const t=await a();if(t?.extract?.input){o.watch(await e(t.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),i()})}}}),w.command("locize-sync").description("Synchronize local translations with your locize project.").option("--update-values","Update values of existing translations on locize.").option("--src-lng-only","Check for changes in source language only.").option("--compare-mtime","Compare modification times when syncing.").option("--dry-run","Run the command without making any changes.").action(async t=>{const o=await i();await f(o,t)}),w.command("locize-download").description("Download all translations from your locize project.").action(async t=>{const o=await i();await u(o,t)}),w.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async t=>{const o=await i();await h(o,t)}),w.parse(process.argv);
2
+ import{Command as t}from"commander";import o from"chokidar";import{glob as e}from"glob";import n from"chalk";import{ensureConfig as i,loadConfig as a}from"./config.js";import{detectConfig as c}from"./heuristic-config.js";import{runExtractor as r}from"./extractor/core/extractor.js";import"node:path";import"node:fs/promises";import"jiti";import{runTypesGenerator as s}from"./types-generator.js";import{runSyncer as l}from"./syncer.js";import{runMigrator as m}from"./migrator.js";import{runInit as p}from"./init.js";import{runLinter as d}from"./linter.js";import{runStatus as g}from"./status.js";import{runLocizeSync as f,runLocizeDownload as u,runLocizeMigrate as h}from"./locize.js";const w=new t;w.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.6.0"),w.command("extract").description("Extract translation keys from source files and update resource files.").option("-w, --watch","Watch for file changes and re-run the extractor.").option("--ci","Exit with a non-zero status code if any files are updated.").option("--dry-run","Run the extractor without writing any files to disk.").action(async t=>{const a=await i(),c=async()=>{const o=await r(a,{isWatchMode:t.watch,isDryRun:t.dryRun});t.ci&&o&&(console.error(n.red.bold("\n[CI Mode] Error: Translation files were updated. Please commit the changes.")),console.log(n.yellow("💡 Tip: Tired of committing JSON files? locize syncs your team automatically => https://www.locize.com/docs/getting-started")),console.log(` Learn more: ${n.cyan("npx i18next-cli locize-sync")}`),process.exit(1))};if(await c(),t.watch){console.log("\nWatching for changes...");o.watch(await e(a.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),c()})}}),w.command("status [locale]").description("Display translation status. Provide a locale for a detailed key-by-key view.").option("-n, --namespace <ns>","Filter the status report by a specific namespace").action(async(t,o)=>{let e=await a();if(!e){console.log(n.blue("No config file found. Attempting to detect project structure..."));const t=await c();t||(console.error(n.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${n.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(n.green("Project structure detected successfully!")),e=t}await g(e,{detail:t,namespace:o.namespace})}),w.command("types").description("Generate TypeScript definitions from translation resource files.").option("-w, --watch","Watch for file changes and re-run the type generator.").action(async t=>{const n=await i(),a=()=>s(n);if(await a(),t.watch){console.log("\nWatching for changes...");o.watch(await e(n.types?.input||[]),{persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),a()})}}),w.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const t=await i();await l(t)}),w.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async t=>{await m(t)}),w.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(p),w.command("lint").description("Find potential issues like hardcoded strings in your codebase.").option("-w, --watch","Watch for file changes and re-run the linter.").action(async t=>{const i=async()=>{let t=await a();if(!t){console.log(n.blue("No config file found. Attempting to detect project structure..."));const o=await c();o||(console.error(n.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${n.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(n.green("Project structure detected successfully!")),t=o}await d(t)};if(await i(),t.watch){console.log("\nWatching for changes...");const t=await a();if(t?.extract?.input){o.watch(await e(t.extract.input),{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),i()})}}}),w.command("locize-sync").description("Synchronize local translations with your locize project.").option("--update-values","Update values of existing translations on locize.").option("--src-lng-only","Check for changes in source language only.").option("--compare-mtime","Compare modification times when syncing.").option("--dry-run","Run the command without making any changes.").action(async t=>{const o=await i();await f(o,t)}),w.command("locize-download").description("Download all translations from your locize project.").action(async t=>{const o=await i();await u(o,t)}),w.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async t=>{const o=await i();await h(o,t)}),w.parse(process.argv);
@@ -1 +1 @@
1
- import t from"ora";import o from"chalk";import{parse as e}from"@swc/core";import{mkdir as a,writeFile as n,readFile as r}from"node:fs/promises";import{dirname as i}from"node:path";import{findKeys as s}from"./key-finder.js";import{getTranslations as c}from"./translation-manager.js";import{validateExtractorConfig as l,ExtractorError as f}from"../../utils/validation.js";import{createPluginContext as u}from"../plugin-manager.js";import{extractKeysFromComments as m}from"../parsers/comment-parser.js";import{ConsoleLogger as p}from"../../utils/logger.js";import{serializeTranslationFile as g}from"../../utils/file-utils.js";import{shouldShowFunnel as y,recordFunnelShown as d}from"../../utils/funnel-msg-tracker.js";async function w(e,{isWatchMode:r=!1,isDryRun:f=!1}={},u=new p){e.extract.primaryLanguage||=e.locales[0]||"en",e.extract.secondaryLanguages||=e.locales.filter(t=>t!==e?.extract?.primaryLanguage),e.extract.functions||=["t","*.t"],e.extract.transComponents||=["Trans"],l(e);const m=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:r}=await s(e,u);m.text=`Found ${t.size} unique keys. Updating translation files...`;const l=await c(t,r,e);let p=!1;for(const t of l)if(t.updated&&(p=!0,!f)){const r=g(t.newTranslations,e.extract.outputFormat,e.extract.indentation);await a(i(t.path),{recursive:!0}),await n(t.path,r),u.info(o.green(`Updated: ${t.path}`))}if((e.plugins||[]).length>0){m.text="Running post-extraction plugins...";for(const t of e.plugins||[])await(t.afterSync?.(l,e))}return m.succeed(o.bold("Extraction complete!")),p&&await async function(){if(!await y("extract"))return;return console.log(o.yellow.bold("\n💡 Tip: Tired of running the extractor manually?")),console.log(' Discover a real-time "push" workflow with `saveMissing` and Locize AI,'),console.log(" where keys are created and translated automatically as you code."),console.log(` Learn more: ${o.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${o.cyan("https://youtu.be/joPsZghT3wM")}`),d("extract")}(),p}catch(t){throw m.fail(o.red("Extraction failed.")),t}}async function x(t,o,a,n,i=new p){try{let s=await r(t,"utf-8");for(const e of o.plugins||[])s=await(e.onLoad?.(s,t))??s;const c=await e(s,{syntax:"typescript",tsx:!0,decorators:!0,comments:!0}),l=u(a);m(s,l,o),n.visit(c),(o.plugins||[]).length>0&&h(c,o.plugins||[],l,i)}catch(o){throw new f("Failed to process file",t,o)}}function h(t,o,e,a=new p){if(t&&"object"==typeof t){for(const n of o)try{n.onVisitNode?.(t,e)}catch(t){a.warn(`Plugin ${n.name} onVisitNode failed:`,t)}for(const n of Object.keys(t)){const r=t[n];if(Array.isArray(r))for(const t of r)t&&"object"==typeof t&&h(t,o,e,a);else r&&"object"==typeof r&&h(r,o,e,a)}}}async function j(t){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(o=>o!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:o,objectKeys:e}=await s(t);return c(o,e,t)}export{j as extract,x as processFile,w as runExtractor};
1
+ import t from"ora";import o from"chalk";import{parse as e}from"@swc/core";import{mkdir as a,writeFile as n,readFile as r}from"node:fs/promises";import{dirname as i}from"node:path";import{findKeys as s}from"./key-finder.js";import{getTranslations as c}from"./translation-manager.js";import{validateExtractorConfig as l,ExtractorError as f}from"../../utils/validation.js";import{createPluginContext as m}from"../plugin-manager.js";import{extractKeysFromComments as p}from"../parsers/comment-parser.js";import{ConsoleLogger as u}from"../../utils/logger.js";import{serializeTranslationFile as g}from"../../utils/file-utils.js";import{shouldShowFunnel as y,recordFunnelShown as d}from"../../utils/funnel-msg-tracker.js";async function w(e,{isWatchMode:r=!1,isDryRun:f=!1}={},m=new u){e.extract.primaryLanguage||=e.locales[0]||"en",e.extract.secondaryLanguages||=e.locales.filter(t=>t!==e?.extract?.primaryLanguage),e.extract.functions||=["t","*.t"],e.extract.transComponents||=["Trans"],l(e);const p=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:r}=await s(e,m);p.text=`Found ${t.size} unique keys. Updating translation files...`;const l=await c(t,r,e);let u=!1;for(const t of l)if(t.updated&&(u=!0,!f)){const r=g(t.newTranslations,e.extract.outputFormat,e.extract.indentation);await a(i(t.path),{recursive:!0}),await n(t.path,r),m.info(o.green(`Updated: ${t.path}`))}if((e.plugins||[]).length>0){p.text="Running post-extraction plugins...";for(const t of e.plugins||[])await(t.afterSync?.(l,e))}return p.succeed(o.bold("Extraction complete!")),u&&await async function(){if(!await y("extract"))return;return console.log(o.yellow.bold("\n💡 Tip: Tired of running the extractor manually?")),console.log(' Discover a real-time "push" workflow with `saveMissing` and Locize AI,'),console.log(" where keys are created and translated automatically as you code."),console.log(` Learn more: ${o.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${o.cyan("https://youtu.be/joPsZghT3wM")}`),d("extract")}(),u}catch(t){throw p.fail(o.red("Extraction failed.")),t}}async function x(t,o,a,n,i=new u){try{let s=await r(t,"utf-8");for(const e of o.plugins||[])try{const o=await(e.onLoad?.(s,t));void 0!==o&&(s=o)}catch(t){i.warn(`Plugin ${e.name} onLoad failed:`,t)}const c=await e(s,{syntax:"typescript",tsx:!0,decorators:!0,comments:!0}),l=m(a,o,i);l.getVarFromScope=n.getVarFromScope.bind(n),p(s,l,o,n.getVarFromScope.bind(n)),n.visit(c),(o.plugins||[]).length>0&&h(c,o.plugins||[],l,i)}catch(o){throw new f("Failed to process file",t,o)}}function h(t,o,e,a=new u){if(t&&"object"==typeof t){for(const n of o)try{n.onVisitNode?.(t,e)}catch(t){a.warn(`Plugin ${n.name} onVisitNode failed:`,t)}for(const n of Object.keys(t)){const r=t[n];if(Array.isArray(r))for(const t of r)t&&"object"==typeof t&&h(t,o,e,a);else r&&"object"==typeof r&&h(r,o,e,a)}}}async function j(t){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(o=>o!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:o,objectKeys:e}=await s(t);return c(o,e,t)}export{j as extract,x as processFile,w as runExtractor};
@@ -1 +1 @@
1
- import{glob as r}from"glob";import{processFile as t}from"./extractor.js";import{ConsoleLogger as o}from"../../utils/logger.js";import{initializePlugins as e,createPluginContext as n}from"../plugin-manager.js";import{ASTVisitors as a}from"../parsers/ast-visitors.js";async function i(i,s=new o){const c=await async function(t){const o=["node_modules/**"],e=Array.isArray(t.extract.ignore)?t.extract.ignore:t.extract.ignore?[t.extract.ignore]:[];return await r(t.extract.input,{ignore:[...o,...e],cwd:process.cwd()})}(i),p=new Map,g=new a(i,n(p),s);await e(i.plugins||[]);for(const r of c)await t(r,i,p,g,s);for(const r of i.plugins||[])await(r.onEnd?.(p));return{allKeys:p,objectKeys:g.objectKeys}}export{i as findKeys};
1
+ import{glob as r}from"glob";import{processFile as o}from"./extractor.js";import{ConsoleLogger as t}from"../../utils/logger.js";import{createPluginContext as e,initializePlugins as n}from"../plugin-manager.js";import{ASTVisitors as a}from"../parsers/ast-visitors.js";async function i(i,s=new t){const c=await async function(o){const t=["node_modules/**"],e=Array.isArray(o.extract.ignore)?o.extract.ignore:o.extract.ignore?[o.extract.ignore]:[];return await r(o.extract.input,{ignore:[...t,...e],cwd:process.cwd()})}(i),p=new Map,g=e(p,i,s),m=new a(i,g,s);g.getVarFromScope=m.getVarFromScope.bind(m),await n(i.plugins||[]);for(const r of c)await o(r,i,p,m,s);for(const r of i.plugins||[])await(r.onEnd?.(p));return{allKeys:p,objectKeys:m.objectKeys}}export{i as findKeys};
@@ -1 +1 @@
1
- import{extractFromTransComponent as e}from"./jsx-parser.js";import{getObjectPropValue as t,getObjectProperty as n}from"./ast-utils.js";class s{pluginContext;config;logger;scopeStack=[];objectKeys=new Set;constructor(e,t,n){this.pluginContext=t,this.config=e,this.logger=n}visit(e){this.enterScope(),this.walk(e),this.exitScope()}walk(e){if(!e)return;let t=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.enterScope(),t=!0),e.type){case"VariableDeclarator":this.handleVariableDeclarator(e);break;case"CallExpression":this.handleCallExpression(e);break;case"JSXElement":this.handleJSXElement(e)}for(const t in e){if("span"===t)continue;const n=e[t];if(Array.isArray(n))for(const e of n)e&&"object"==typeof e&&this.walk(e);else n&&"object"==typeof n&&this.walk(n)}t&&this.exitScope()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0&&this.scopeStack[this.scopeStack.length-1].set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e))return this.scopeStack[t].get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;const n="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!n)return;const s=n.callee;if("Identifier"===s.type){const t=this.getUseTranslationConfig(s.value);if(t)return void this.handleUseTranslationDeclarator(e,n,t)}"MemberExpression"===s.type&&"Identifier"===s.property.type&&"getFixedT"===s.property.value&&this.handleGetFixedTDeclarator(e,n)}handleUseTranslationDeclarator(e,n,s){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value){r="t";break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const i=n.arguments?.[s.nsArg]?.expression;let a;"StringLiteral"===i?.type?a=i.value:"ArrayExpression"===i?.type&&"StringLiteral"===i.elements[0]?.expression.type&&(a=i.elements[0].expression.value);const o=n.arguments?.[s.keyPrefixArg]?.expression;let l;if("ObjectExpression"===o?.type){const e=t(o,"keyPrefix");l="string"==typeof e?e:void 0}this.setVarInScope(r,{defaultNs:a,keyPrefix:l})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const n=e.id.value,s=t.arguments,r=s[1]?.expression,i=s[2]?.expression,a="StringLiteral"===r?.type?r.value:void 0,o="StringLiteral"===i?.type?i.value:void 0;(a||o)&&this.setVarInScope(n,{defaultNs:a,keyPrefix:o})}handleCallExpression(e){const s=this.getFunctionName(e.callee);if(!s)return;const r=this.getVarFromScope(s),i=this.config.extract.functions||["t","*.t"];let a=void 0!==r;if(!a)for(const e of i)if(e.startsWith("*.")){if(s.endsWith(e.substring(1))){a=!0;break}}else if(e===s){a=!0;break}if(!a||0===e.arguments.length)return;const{keysToProcess:o,isSelectorAPI:l}=this.handleCallExpressionArgument(e,0);if(0===o.length)return;let u=!1;const p=this.config.extract.pluralSeparator??"_";for(let e=0;e<o.length;e++)o[e].endsWith(`${p}ordinal`)&&(u=!0,o[e]=o[e].slice(0,-8));let f,c;if(e.arguments.length>1){const t=e.arguments[1].expression;"ObjectExpression"===t.type?c=t:"StringLiteral"===t.type&&(f=t.value)}if(e.arguments.length>2){const t=e.arguments[2].expression;"ObjectExpression"===t.type&&(c=t)}const g=c?t(c,"defaultValue"):void 0,y="string"==typeof g?g:f;for(let e=0;e<o.length;e++){let s,i=o[e];if(c){const e=t(c,"ns");"string"==typeof e&&(s=e)}const a=this.config.extract.nsSeparator??":";if(!s&&a&&i.includes(a)){const e=i.split(a);s=e.shift(),i=e.join(a)}!s&&r?.defaultNs&&(s=r.defaultNs),s||(s=this.config.extract.defaultNS);let p=i;if(r?.keyPrefix){const e=this.config.extract.keySeparator??".";p=`${r.keyPrefix}${e}${i}`}const f=e===o.length-1&&y||i;if(c){const e=n(c,"context"),r=[];if("ConditionalExpression"===e?.value?.type){const t=this.resolvePossibleStringValues(e.value),n=this.config.extract.contextSeparator??"_";t.length>0&&(t.forEach(e=>{r.push({key:`${p}${n}${e}`,ns:s,defaultValue:f})}),r.push({key:p,ns:s,defaultValue:f}))}else if("StringLiteral"===e?.value?.type){const t=e.value.value,n=this.config.extract.contextSeparator??"_";r.push({key:`${p}${n}${t}`,ns:s,defaultValue:f})}const i=void 0!==t(c,"count"),a=!0===t(c,"ordinal");if(i||u){if(r.length>0)for(const{key:e,ns:t}of r)this.handlePluralKeys(e,t,c,a||u);else this.handlePluralKeys(p,s,c,a||u);continue}if(r.length>0){r.forEach(this.pluginContext.addKey);continue}!0===t(c,"returnObjects")&&this.objectKeys.add(p)}l&&this.objectKeys.add(p),this.pluginContext.addKey({key:p,ns:s,defaultValue:f})}}handleCallExpressionArgument(e,t){const n=e.arguments[t].expression,s=[];let r=!1;if("ArrowFunctionExpression"===n.type){const e=this.extractKeyFromSelector(n);e&&(s.push(e),r=!0)}else if("ArrayExpression"===n.type)for(const e of n.elements)e?.expression&&s.push(...this.resolvePossibleStringValues(e.expression));else s.push(...this.resolvePossibleStringValues(n));return{keysToProcess:s.filter(e=>!!e),isSelectorAPI:r}}handlePluralKeys(e,n,s,r){try{const i=r?"ordinal":"cardinal",a=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:i}).resolvedOptions().pluralCategories,o=this.config.extract.pluralSeparator??"_",l=t(s,"defaultValue"),u=t(s,`defaultValue${o}other`),p=t(s,`defaultValue${o}ordinal${o}other`);for(const i of a){const a=t(s,r?`defaultValue${o}ordinal${o}${i}`:`defaultValue${o}${i}`);let f;f="string"==typeof a?a:"one"===i&&"string"==typeof l?l:r&&"string"==typeof p?p:r||"string"!=typeof u?"string"==typeof l?l:e:u;const c=r?`${e}${o}ordinal${o}${i}`:`${e}${o}${i}`;this.pluginContext.addKey({key:c,ns:n,defaultValue:f,hasCount:!0,isOrdinal:r})}}catch(r){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const i=t(s,"defaultValue");this.pluginContext.addKey({key:e,ns:n,defaultValue:"string"==typeof i?i:e})}}handleSimplePluralKeys(e,t,n){try{const s=new Intl.PluralRules(this.config.extract?.primaryLanguage).resolvedOptions().pluralCategories,r=this.config.extract.pluralSeparator??"_";for(const i of s)this.pluginContext.addKey({key:`${e}${r}${i}`,ns:n,defaultValue:t,hasCount:!0})}catch(s){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}".`),this.pluginContext.addKey({key:e,ns:n,defaultValue:t})}}handleJSXElement(t){const n=this.getElementName(t);if(n&&(this.config.extract.transComponents||["Trans"]).includes(n)){const n=e(t,this.config),s=[];if(n){if(n.keyExpression){const e=this.resolvePossibleStringValues(n.keyExpression);s.push(...e)}else s.push(n.serializedChildren);let e;const{contextExpression:r,optionsNode:i,defaultValue:a,hasCount:o,isOrdinal:l,serializedChildren:u}=n;if(n.ns){const{ns:t}=n;e=s.map(e=>({key:e,ns:t,defaultValue:a||u,hasCount:o,isOrdinal:l}))}else{e=s.map(e=>{const t=this.config.extract.nsSeparator??":";let n;if(t&&e.includes(t)){let s;[n,...s]=e.split(t),e=s.join(t)}return{key:e,ns:n,defaultValue:a||u,hasCount:o,isOrdinal:l}});const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===n?.type&&"JSXExpressionContainer"===n.value?.type&&"Identifier"===n.value.expression.type){const t=n.value.expression.value,s=this.getVarFromScope(t);s?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=s.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),r&&o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n,a=this.resolvePossibleStringValues(r),o=this.config.extract.contextSeparator??"_";if(a.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i));for(const t of a)for(const n of e){const e=`${n.key}${o}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,s,i)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i))}else if(r){const t=this.resolvePossibleStringValues(r),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const s of t)for(const{key:t,ns:r,defaultValue:i}of e)this.pluginContext.addKey({key:`${t}${n}${s}`,ns:r,defaultValue:i});"StringLiteral"!==r.type&&e.forEach(this.pluginContext.addKey)}}else if(o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n;e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i))}else e.forEach(this.pluginContext.addKey)}}}generatePluralKeysForTrans(e,n,s,r,i){try{const a=r?"ordinal":"cardinal",o=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:a}).resolvedOptions().pluralCategories,l=this.config.extract.pluralSeparator??"_";let u,p;i&&(u=t(i,`defaultValue${l}other`),p=t(i,`defaultValue${l}ordinal${l}other`));for(const a of o){const o=i?t(i,r?`defaultValue${l}ordinal${l}${a}`:`defaultValue${l}${a}`):void 0;let f;f="string"==typeof o?o:"one"===a&&"string"==typeof n?n:r&&"string"==typeof p?p:r||"string"!=typeof u?"string"==typeof n?n:e:u;const c=r?`${e}${l}ordinal${l}${a}`:`${e}${l}${a}`;this.pluginContext.addKey({key:c,ns:s,defaultValue:f,hasCount:!0,isOrdinal:r})}}catch(t){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`),this.pluginContext.addKey({key:e,ns:s,defaultValue:n})}}getElementName(e){if("Identifier"===e.opening.name.type)return e.opening.name.value;if("JSXMemberExpression"===e.opening.name.type){let t=e.opening.name;const n=[];for(;"JSXMemberExpression"===t.type;)"Identifier"===t.property.type&&n.unshift(t.property.value),t=t.object;return"Identifier"===t.type&&n.unshift(t.value),n.join(".")}}extractKeyFromSelector(e){let t=e.body;if("BlockStatement"===t.type){const e=t.stmts.find(e=>"ReturnStatement"===e.type);if("ReturnStatement"!==e?.type||!e.argument)return null;t=e.argument}let n=t;const s=[];for(;"MemberExpression"===n.type;){const e=n.property;if("Identifier"===e.type)s.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;s.unshift(e.expression.value)}n=n.object}if(s.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return s.join(t)}return null}resolvePossibleStringValues(e){if("StringLiteral"===e.type)return e.value?[e.value]:[];if("ConditionalExpression"===e.type){return[...this.resolvePossibleStringValues(e.consequent),...this.resolvePossibleStringValues(e.alternate)]}return"Identifier"===e.type&&"undefined"===e.value?[]:"TemplateLiteral"===e.type?this.resolvePossibleStringValuesFromTemplateString(e):"NumericLiteral"===e.type||"BooleanLiteral"===e.type?[`${e.value}`]:[]}resolvePossibleStringValuesFromTemplateString(e){if(1===e.quasis.length&&0===e.expressions.length)return[e.quasis[0].cooked||""];const[t,...n]=e.quasis;return e.expressions.reduce((e,t,s)=>e.flatMap(e=>{const r=n[s]?.cooked??"";return this.resolvePossibleStringValues(t).map(t=>`${e}${t}${r}`)}),[t.cooked??""])}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const n of t){if("string"==typeof n&&n===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof n&&n.name===e)return{name:n.name,nsArg:n.nsArg??0,keyPrefixArg:n.keyPrefixArg??1}}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let n=e;for(;"MemberExpression"===n.type;){if("Identifier"!==n.property.type)return null;t.unshift(n.property.value),n=n.object}if("ThisExpression"===n.type)t.unshift("this");else{if("Identifier"!==n.type)return null;t.unshift(n.value)}return t.join(".")}return null}}export{s as ASTVisitors};
1
+ import{extractFromTransComponent as e}from"./jsx-parser.js";import{getObjectPropValue as t,getObjectProperty as n}from"./ast-utils.js";class s{pluginContext;config;logger;scopeStack=[];objectKeys=new Set;constructor(e,t,n){this.pluginContext=t,this.config=e,this.logger=n}visit(e){this.enterScope(),this.walk(e),this.exitScope()}walk(e){if(!e)return;let t=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.enterScope(),t=!0),e.type){case"VariableDeclarator":this.handleVariableDeclarator(e);break;case"CallExpression":this.handleCallExpression(e);break;case"JSXElement":this.handleJSXElement(e)}for(const t in e){if("span"===t)continue;const n=e[t];if(Array.isArray(n))for(const e of n)e&&"object"==typeof e&&this.walk(e);else n&&"object"==typeof n&&this.walk(n)}t&&this.exitScope()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0&&this.scopeStack[this.scopeStack.length-1].set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e))return this.scopeStack[t].get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;const n="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!n)return;const s=n.callee;if("Identifier"===s.type){const t=this.getUseTranslationConfig(s.value);if(t)return void this.handleUseTranslationDeclarator(e,n,t)}"MemberExpression"===s.type&&"Identifier"===s.property.type&&"getFixedT"===s.property.value&&this.handleGetFixedTDeclarator(e,n)}handleUseTranslationDeclarator(e,n,s){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value){r="t";break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&"t"===t.key.value&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const i=n.arguments?.[s.nsArg]?.expression;let a;"StringLiteral"===i?.type?a=i.value:"ArrayExpression"===i?.type&&"StringLiteral"===i.elements[0]?.expression.type&&(a=i.elements[0].expression.value);const o=n.arguments?.[s.keyPrefixArg]?.expression;let l;if("ObjectExpression"===o?.type){const e=t(o,"keyPrefix");l="string"==typeof e?e:void 0}this.setVarInScope(r,{defaultNs:a,keyPrefix:l})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const n=e.id.value,s=t.arguments,r=s[1]?.expression,i=s[2]?.expression,a="StringLiteral"===r?.type?r.value:void 0,o="StringLiteral"===i?.type?i.value:void 0;(a||o)&&this.setVarInScope(n,{defaultNs:a,keyPrefix:o})}handleCallExpression(e){const s=this.getFunctionName(e.callee);if(!s)return;const r=this.getVarFromScope(s),i=this.config.extract.functions||["t","*.t"];let a=void 0!==r;if(!a)for(const e of i)if(e.startsWith("*.")){if(s.endsWith(e.substring(1))){a=!0;break}}else if(e===s){a=!0;break}if(!a||0===e.arguments.length)return;const{keysToProcess:o,isSelectorAPI:l}=this.handleCallExpressionArgument(e,0);if(0===o.length)return;let u=!1;const p=this.config.extract.pluralSeparator??"_";for(let e=0;e<o.length;e++)o[e].endsWith(`${p}ordinal`)&&(u=!0,o[e]=o[e].slice(0,-8));let f,c;if(e.arguments.length>1){const t=e.arguments[1].expression;"ObjectExpression"===t.type?c=t:"StringLiteral"===t.type&&(f=t.value)}if(e.arguments.length>2){const t=e.arguments[2].expression;"ObjectExpression"===t.type&&(c=t)}const g=c?t(c,"defaultValue"):void 0,y="string"==typeof g?g:f;for(let e=0;e<o.length;e++){let s,i=o[e];if(c){const e=t(c,"ns");"string"==typeof e&&(s=e)}const a=this.config.extract.nsSeparator??":";if(!s&&a&&i.includes(a)){const e=i.split(a);s=e.shift(),i=e.join(a)}!s&&r?.defaultNs&&(s=r.defaultNs),s||(s=this.config.extract.defaultNS);let p=i;if(r?.keyPrefix){const e=this.config.extract.keySeparator??".";p=`${r.keyPrefix}${e}${i}`}const f=e===o.length-1&&y||i;if(c){const e=n(c,"context"),r=[];if("ConditionalExpression"===e?.value?.type){const t=this.resolvePossibleStringValues(e.value),n=this.config.extract.contextSeparator??"_";t.length>0&&(t.forEach(e=>{r.push({key:`${p}${n}${e}`,ns:s,defaultValue:f})}),r.push({key:p,ns:s,defaultValue:f}))}else if("StringLiteral"===e?.value?.type){const t=e.value.value,n=this.config.extract.contextSeparator??"_";r.push({key:`${p}${n}${t}`,ns:s,defaultValue:f})}const i=void 0!==t(c,"count"),a=!0===t(c,"ordinal");if(i||u){if(r.length>0)for(const{key:e,ns:t}of r)this.handlePluralKeys(e,t,c,a||u);else this.handlePluralKeys(p,s,c,a||u);continue}if(r.length>0){r.forEach(this.pluginContext.addKey);continue}!0===t(c,"returnObjects")&&this.objectKeys.add(p)}l&&this.objectKeys.add(p),this.pluginContext.addKey({key:p,ns:s,defaultValue:f})}}handleCallExpressionArgument(e,t){const n=e.arguments[t].expression,s=[];let r=!1;if("ArrowFunctionExpression"===n.type){const e=this.extractKeyFromSelector(n);e&&(s.push(e),r=!0)}else if("ArrayExpression"===n.type)for(const e of n.elements)e?.expression&&s.push(...this.resolvePossibleStringValues(e.expression));else s.push(...this.resolvePossibleStringValues(n));return{keysToProcess:s.filter(e=>!!e),isSelectorAPI:r}}handlePluralKeys(e,n,s,r){try{const i=r?"ordinal":"cardinal",a=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:i}).resolvedOptions().pluralCategories,o=this.config.extract.pluralSeparator??"_",l=t(s,"defaultValue"),u=t(s,`defaultValue${o}other`),p=t(s,`defaultValue${o}ordinal${o}other`);for(const i of a){const a=t(s,r?`defaultValue${o}ordinal${o}${i}`:`defaultValue${o}${i}`);let f;f="string"==typeof a?a:"one"===i&&"string"==typeof l?l:r&&"string"==typeof p?p:r||"string"!=typeof u?"string"==typeof l?l:e:u;const c=r?`${e}${o}ordinal${o}${i}`:`${e}${o}${i}`;this.pluginContext.addKey({key:c,ns:n,defaultValue:f,hasCount:!0,isOrdinal:r})}}catch(r){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const i=t(s,"defaultValue");this.pluginContext.addKey({key:e,ns:n,defaultValue:"string"==typeof i?i:e})}}handleSimplePluralKeys(e,t,n){try{const s=new Intl.PluralRules(this.config.extract?.primaryLanguage).resolvedOptions().pluralCategories,r=this.config.extract.pluralSeparator??"_";for(const i of s)this.pluginContext.addKey({key:`${e}${r}${i}`,ns:n,defaultValue:t,hasCount:!0})}catch(s){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}".`),this.pluginContext.addKey({key:e,ns:n,defaultValue:t})}}handleJSXElement(t){const n=this.getElementName(t);if(n&&(this.config.extract.transComponents||["Trans"]).includes(n)){const n=e(t,this.config),s=[];if(n){if(n.keyExpression){const e=this.resolvePossibleStringValues(n.keyExpression);s.push(...e)}else s.push(n.serializedChildren);let e;const{contextExpression:r,optionsNode:i,defaultValue:a,hasCount:o,isOrdinal:l,serializedChildren:u}=n;if(n.ns){const{ns:t}=n;e=s.map(e=>({key:e,ns:t,defaultValue:a||u,hasCount:o,isOrdinal:l}))}else{e=s.map(e=>{const t=this.config.extract.nsSeparator??":";let n;if(t&&e.includes(t)){let s;[n,...s]=e.split(t),e=s.join(t)}return{key:e,ns:n,defaultValue:a||u,hasCount:o,isOrdinal:l}});const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===n?.type&&"JSXExpressionContainer"===n.value?.type&&"Identifier"===n.value.expression.type){const t=n.value.expression.value,s=this.getVarFromScope(t);s?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=s.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),r&&o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n,a=this.resolvePossibleStringValues(r),o=this.config.extract.contextSeparator??"_";if(a.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i));for(const t of a)for(const n of e){const e=`${n.key}${o}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,s,i)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i))}else if(r){const t=this.resolvePossibleStringValues(r),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const s of t)for(const{key:t,ns:r,defaultValue:i}of e)this.pluginContext.addKey({key:`${t}${n}${s}`,ns:r,defaultValue:i});"StringLiteral"!==r.type&&e.forEach(this.pluginContext.addKey)}}else if(o){const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n;e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,i))}else e.forEach(this.pluginContext.addKey)}}}generatePluralKeysForTrans(e,n,s,r,i){try{const a=r?"ordinal":"cardinal",o=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:a}).resolvedOptions().pluralCategories,l=this.config.extract.pluralSeparator??"_";let u,p;i&&(u=t(i,`defaultValue${l}other`),p=t(i,`defaultValue${l}ordinal${l}other`));for(const a of o){const o=i?t(i,r?`defaultValue${l}ordinal${l}${a}`:`defaultValue${l}${a}`):void 0;let f;f="string"==typeof o?o:"one"===a&&"string"==typeof n?n:r&&"string"==typeof p?p:r||"string"!=typeof u?"string"==typeof n?n:e:u;const c=r?`${e}${l}ordinal${l}${a}`:`${e}${l}${a}`;this.pluginContext.addKey({key:c,ns:s,defaultValue:f,hasCount:!0,isOrdinal:r})}}catch(t){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`),this.pluginContext.addKey({key:e,ns:s,defaultValue:n})}}getElementName(e){if("Identifier"===e.opening.name.type)return e.opening.name.value;if("JSXMemberExpression"===e.opening.name.type){let t=e.opening.name;const n=[];for(;"JSXMemberExpression"===t.type;)"Identifier"===t.property.type&&n.unshift(t.property.value),t=t.object;return"Identifier"===t.type&&n.unshift(t.value),n.join(".")}}extractKeyFromSelector(e){let t=e.body;if("BlockStatement"===t.type){const e=t.stmts.find(e=>"ReturnStatement"===e.type);if("ReturnStatement"!==e?.type||!e.argument)return null;t=e.argument}let n=t;const s=[];for(;"MemberExpression"===n.type;){const e=n.property;if("Identifier"===e.type)s.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;s.unshift(e.expression.value)}n=n.object}if(s.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return s.join(t)}return null}resolvePossibleStringValues(e,t=!1){if("StringLiteral"===e.type)return e.value||t?[e.value]:[];if("ConditionalExpression"===e.type){return[...this.resolvePossibleStringValues(e.consequent,t),...this.resolvePossibleStringValues(e.alternate,t)]}return"Identifier"===e.type&&"undefined"===e.value?[]:"TemplateLiteral"===e.type?this.resolvePossibleStringValuesFromTemplateString(e):"NumericLiteral"===e.type||"BooleanLiteral"===e.type?[`${e.value}`]:[]}resolvePossibleStringValuesFromTemplateString(e){if(1===e.quasis.length&&0===e.expressions.length)return[e.quasis[0].cooked||""];const[t,...n]=e.quasis;return e.expressions.reduce((e,t,s)=>e.flatMap(e=>{const r=n[s]?.cooked??"";return this.resolvePossibleStringValues(t,!0).map(t=>`${e}${t}${r}`)}),[t.cooked??""])}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const n of t){if("string"==typeof n&&n===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof n&&n.name===e)return{name:n.name,nsArg:n.nsArg??0,keyPrefixArg:n.keyPrefixArg??1}}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let n=e;for(;"MemberExpression"===n.type;){if("Identifier"!==n.property.type)return null;t.unshift(n.property.value),n=n.object}if("ThisExpression"===n.type)t.unshift("this");else{if("Identifier"!==n.type)return null;t.unshift(n.value)}return t.join(".")}return null}}export{s as ASTVisitors};
@@ -1 +1 @@
1
- function e(e,s,c){const o=new RegExp("\\bt\\s*\\(\\s*(['\"])([^'\"]+)\\1","g"),r=function(e){const t=[],n=new Set,s=/\/\/(.*)|\/\*([\s\S]*?)\*\//g;let c;for(;null!==(c=s.exec(e));){const e=(c[1]??c[2]).trim();e&&!n.has(e)&&(n.add(e),t.push(e))}return t}(e);for(const e of r){let r;for(;null!==(r=o.exec(e));){let o,u=r[2];const l=e.slice(r.index+r[0].length),f=t(l);o=n(l);const i=c.extract.nsSeparator??":";if(!o&&i&&u.includes(i)){const e=u.split(i);o=e.shift(),u=e.join(i)}o||(o=c.extract.defaultNS),s.addKey({key:u,ns:o,defaultValue:f??u})}}}function t(e){const t=/^\s*,\s*(['"])(.*?)\1/.exec(e);if(t)return t[2];const n=/^\s*,\s*\{[^}]*defaultValue\s*:\s*(['"])(.*?)\1/.exec(e);return n?n[2]:void 0}function n(e){const t=/^\s*,\s*\{[^}]*ns\s*:\s*(['"])(.*?)\1/.exec(e);if(t)return t[2]}export{e as extractKeysFromComments};
1
+ function t(t,n,c,o){const u=new RegExp("\\bt\\s*\\(\\s*(['\"])([^'\"]+)\\1","g"),f=function(t){const e=[],s=new Set,n=/\/\/(.*)|\/\*([\s\S]*?)\*\//g;let c;for(;null!==(c=n.exec(t));){const t=(c[1]??c[2]).trim();t&&!s.has(t)&&(s.add(t),e.push(t))}return e}(t);for(const t of f){let f;for(;null!==(f=u.exec(t));){let u,l=f[2];const r=t.slice(f.index+f[0].length),i=e(r);u=s(r);const a=c.extract.nsSeparator??":";if(!u&&a&&l.includes(a)){const t=l.split(a);u=t.shift(),l=t.join(a)}if(!u&&o){const t=o("t");t?.defaultNs&&(u=t.defaultNs)}u||(u=c.extract.defaultNS),n.addKey({key:l,ns:u,defaultValue:i??l})}}}function e(t){const e=/^\s*,\s*(['"])(.*?)\1/.exec(t);if(e)return e[2];const s=/^\s*,\s*\{[^}]*defaultValue\s*:\s*(['"])(.*?)\1/.exec(t);return s?s[2]:void 0}function s(t){const e=/^\s*,\s*\{[^}]*ns\s*:\s*(['"])(.*?)\1/.exec(t);if(e)return e[2]}export{t as extractKeysFromComments};
@@ -1 +1 @@
1
- import{getObjectProperty as e,getObjectPropValue as t}from"./ast-utils.js";function n(n,i){const r=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"i18nKey"===e.name.value),a=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"defaults"===e.name.value),p=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"count"===e.name.value),s=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"values"===e.name.value);let u;p||"JSXAttribute"!==s?.type||"JSXExpressionContainer"!==s.value?.type||"ObjectExpression"!==s.value.expression.type||(u=e(s.value.expression,"count"));const o=!!p||!!u,l=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"tOptions"===e.name.value),y="JSXAttribute"===l?.type&&"JSXExpressionContainer"===l.value?.type&&"ObjectExpression"===l.value.expression.type?l.value.expression:void 0,v=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),d=!!v,f=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"context"===e.name.value);let c="JSXAttribute"===f?.type&&"JSXExpressionContainer"===f.value?.type?f.value.expression:void 0;const S=n.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ns"===e.name.value);let b;if(b="JSXAttribute"===S?.type&&"StringLiteral"===S.value?.type?S.value.value:void 0,y&&(void 0===b&&(b=t(y,"ns")),void 0===c)){const t=e(y,"context");t?.value&&(c=t.value)}const x=function(e,t){const n=new Set(t.extract.transKeepBasicHtmlNodesFor??["br","strong","i","p"]);function i(e){let t="";return e.forEach((e,r)=>{if("JSXText"===e.type)t+=e.value;else if("JSXExpressionContainer"===e.type){const n=e.expression;if("StringLiteral"===n.type)t+=n.value;else if("Identifier"===n.type)t+=`{{${n.value}}}`;else if("ObjectExpression"===n.type){const e=n.properties[0];e&&"Identifier"===e.type&&(t+=`{{${e.value}}}`)}}else if("JSXElement"===e.type){let a;"Identifier"===e.opening.name.type&&(a=e.opening.name.value);const p=i(e.children);a&&n.has(a)?t+=`<${a}>${p}</${a}>`:t+=`<${r}>${p}</${r}>`}else"JSXFragment"===e.type&&(t+=i(e.children))}),t}return i(e).trim().replace(/\s{2,}/g," ")}(n.children,i);let m,J=i.extract.defaultValue||"";return"JSXAttribute"===a?.type&&"StringLiteral"===a.value?.type&&(J=a.value.value),"JSXAttribute"!==r?.type||("StringLiteral"===r.value?.type?m=r.value:"JSXExpressionContainer"===r.value?.type&&"JSXEmptyExpression"!==r.value.expression.type&&(m=r.value.expression),m)?{keyExpression:m,serializedChildren:x,ns:b,defaultValue:J,hasCount:o,isOrdinal:d,contextExpression:c,optionsNode:y}:null}export{n as extractFromTransComponent};
1
+ import{getObjectProperty as e,getObjectPropValue as t}from"./ast-utils.js";function i(i,n){const r=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"i18nKey"===e.name.value),a=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"defaults"===e.name.value),s=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"count"===e.name.value),p=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"values"===e.name.value);let u;s||"JSXAttribute"!==p?.type||"JSXExpressionContainer"!==p.value?.type||"ObjectExpression"!==p.value.expression.type||(u=e(p.value.expression,"count"));const l=!!s||!!u,o=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"tOptions"===e.name.value),y="JSXAttribute"===o?.type&&"JSXExpressionContainer"===o.value?.type&&"ObjectExpression"===o.value.expression.type?o.value.expression:void 0,v=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),f=!!v,d=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"context"===e.name.value);let c="JSXAttribute"===d?.type&&"JSXExpressionContainer"===d.value?.type?d.value.expression:void 0;const S=i.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ns"===e.name.value);let m;if(m="JSXAttribute"===S?.type&&"StringLiteral"===S.value?.type?S.value.value:void 0,y&&(void 0===m&&(m=t(y,"ns")),void 0===c)){const t=e(y,"context");t?.value&&(c=t.value)}const x=function(e,t){const i=new Set(t.extract.transKeepBasicHtmlNodesFor??["br","strong","i","p"]);function n(e){let t="";return e.forEach((e,r)=>{if("JSXText"===e.type)t+=e.value;else if("JSXExpressionContainer"===e.type){const i=e.expression;if("StringLiteral"===i.type)t+=i.value;else if("Identifier"===i.type)t+=`{{${i.value}}}`;else if("ObjectExpression"===i.type){const e=i.properties[0];e&&"Identifier"===e.type&&(t+=`{{${e.value}}}`)}}else if("JSXElement"===e.type){let a;"Identifier"===e.opening.name.type&&(a=e.opening.name.value);const s=n(e.children);a&&i.has(a)?t+=`<${a}>${s}</${a}>`:t+=`<${r}>${s}</${r}>`}else"JSXFragment"===e.type&&(t+=n(e.children))}),t}return n(e).trim().replace(/\s{2,}/g," ")}(i.children,n);let b,J,X=n.extract.defaultValue||"";if("JSXAttribute"===a?.type&&"StringLiteral"===a.value?.type&&(X=a.value.value),"JSXAttribute"===r?.type){if("StringLiteral"===r.value?.type){if(b=r.value,J=b.value,m&&"StringLiteral"===b.type){const e=n.extract.nsSeparator??":",t=b.value;e&&t.startsWith(`${m}${e}`)&&(J=t.slice(`${m}${e}`.length),b={...b,value:J})}}else"JSXExpressionContainer"===r.value?.type&&"JSXEmptyExpression"!==r.value.expression.type&&(b=r.value.expression);if(!b)return null}return a||!J||x.trim()?!a&&x.trim()&&(X=x):X=J,{keyExpression:b,serializedChildren:x,ns:m,defaultValue:X,hasCount:l,isOrdinal:f,contextExpression:c,optionsNode:y}}export{i as extractFromTransComponent};
@@ -1 +1 @@
1
- async function t(t){for(const n of t)await(n.setup?.())}function n(t){return{addKey:n=>{const a=`${n.ns??"translation"}:${n.key}`;if(!t.has(a)){const e=n.defaultValue??n.key;t.set(a,{...n,defaultValue:e})}}}}export{n as createPluginContext,t as initializePlugins};
1
+ async function t(t){for(const e of t)await(e.setup?.())}function e(t,e,n){return{addKey:e=>{const n=`${e.ns??"translation"}:${e.key}`;if(!t.has(n)){const o=e.defaultValue??e.key;t.set(n,{...e,defaultValue:o})}},config:e,logger:n,getVarFromScope:()=>{}}}export{e as createPluginContext,t as initializePlugins};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-cli",
3
- "version": "1.5.10",
3
+ "version": "1.6.0",
4
4
  "description": "A unified, high-performance i18next CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,9 @@
9
9
  "main": "./dist/cjs/index.js",
10
10
  "module": "./dist/esm/index.js",
11
11
  "types": "./types/index.d.ts",
12
+ "engines": {
13
+ "node": ">=22"
14
+ },
12
15
  "exports": {
13
16
  "./package.json": "./package.json",
14
17
  ".": {
package/src/cli.ts CHANGED
@@ -21,7 +21,7 @@ const program = new Command()
21
21
  program
22
22
  .name('i18next-cli')
23
23
  .description('A unified, high-performance i18next CLI.')
24
- .version('1.5.10')
24
+ .version('1.6.0')
25
25
 
26
26
  program
27
27
  .command('extract')
@@ -137,9 +137,17 @@ export async function processFile (
137
137
  try {
138
138
  let code = await readFile(file, 'utf-8')
139
139
 
140
- // Run onLoad hooks from plugins
140
+ // Run onLoad hooks from plugins with error handling
141
141
  for (const plugin of (config.plugins || [])) {
142
- code = (await plugin.onLoad?.(code, file)) ?? code
142
+ try {
143
+ const result = await plugin.onLoad?.(code, file)
144
+ if (result !== undefined) {
145
+ code = result
146
+ }
147
+ } catch (err) {
148
+ logger.warn(`Plugin ${plugin.name} onLoad failed:`, err)
149
+ // Continue with the original code if the plugin fails
150
+ }
143
151
  }
144
152
 
145
153
  const ast = await parse(code, {
@@ -149,10 +157,15 @@ export async function processFile (
149
157
  comments: true
150
158
  })
151
159
 
152
- const pluginContext = createPluginContext(allKeys)
160
+ // 1. Create the base context with config and logger.
161
+ const pluginContext = createPluginContext(allKeys, config, logger)
162
+
163
+ // 2. "Wire up" the visitor's scope method to the context.
164
+ // This avoids a circular dependency while giving plugins access to the scope.
165
+ pluginContext.getVarFromScope = astVisitors.getVarFromScope.bind(astVisitors)
153
166
 
154
- // Extract keys from comments
155
- extractKeysFromComments(code, pluginContext, config)
167
+ // Extract keys from comments with scope resolution
168
+ extractKeysFromComments(code, pluginContext, config, astVisitors.getVarFromScope.bind(astVisitors))
156
169
 
157
170
  astVisitors.visit(ast)
158
171
 
@@ -40,8 +40,15 @@ export async function findKeys (
40
40
  const sourceFiles = await processSourceFiles(config)
41
41
  const allKeys = new Map<string, ExtractedKey>()
42
42
 
43
- // Create a single visitors instance to accumulate data across all files
44
- const astVisitors = new ASTVisitors(config, createPluginContext(allKeys), logger)
43
+ // 1. Create the base context with config and logger.
44
+ const pluginContext = createPluginContext(allKeys, config, logger)
45
+
46
+ // 2. Create the visitor instance, passing it the context.
47
+ const astVisitors = new ASTVisitors(config, pluginContext, logger)
48
+
49
+ // 3. "Wire up" the visitor's scope method to the context.
50
+ // This avoids a circular dependency while giving plugins access to the scope.
51
+ pluginContext.getVarFromScope = astVisitors.getVarFromScope.bind(astVisitors)
45
52
 
46
53
  await initializePlugins(config.plugins || [])
47
54
 
@@ -1,19 +1,8 @@
1
1
  import type { Module, Node, CallExpression, VariableDeclarator, JSXElement, ArrowFunctionExpression, ObjectExpression, Expression, TemplateLiteral } from '@swc/core'
2
- import type { PluginContext, I18nextToolkitConfig, Logger, ExtractedKey } from '../../types'
2
+ import type { PluginContext, I18nextToolkitConfig, Logger, ExtractedKey, ScopeInfo } from '../../types'
3
3
  import { extractFromTransComponent } from './jsx-parser'
4
4
  import { getObjectProperty, getObjectPropValue } from './ast-utils'
5
5
 
6
- /**
7
- * Represents variable scope information tracked during AST traversal.
8
- * Used to maintain context about translation functions and their configuration.
9
- */
10
- interface ScopeInfo {
11
- /** Default namespace for translation calls in this scope */
12
- defaultNs?: string;
13
- /** Key prefix to prepend to all translation keys in this scope */
14
- keyPrefix?: string;
15
- }
16
-
17
6
  interface UseTranslationHookConfig {
18
7
  name: string;
19
8
  nsArg: number;
@@ -190,7 +179,7 @@ export class ASTVisitors {
190
179
  *
191
180
  * @private
192
181
  */
193
- private getVarFromScope (name: string): ScopeInfo | undefined {
182
+ public getVarFromScope (name: string): ScopeInfo | undefined {
194
183
  for (let i = this.scopeStack.length - 1; i >= 0; i--) {
195
184
  if (this.scopeStack[i].has(name)) {
196
185
  return this.scopeStack[i].get(name)
@@ -758,8 +747,8 @@ export class ASTVisitors {
758
747
  const ordinalAttr = node.opening.attributes?.find(
759
748
  (attr) =>
760
749
  attr.type === 'JSXAttribute' &&
761
- attr.name.type === 'Identifier' &&
762
- attr.name.value === 'ordinal'
750
+ attr.name.type === 'Identifier' &&
751
+ attr.name.value === 'ordinal'
763
752
  )
764
753
  const isOrdinal = !!ordinalAttr
765
754
 
@@ -802,8 +791,8 @@ export class ASTVisitors {
802
791
  const ordinalAttr = node.opening.attributes?.find(
803
792
  (attr) =>
804
793
  attr.type === 'JSXAttribute' &&
805
- attr.name.type === 'Identifier' &&
806
- attr.name.value === 'ordinal'
794
+ attr.name.type === 'Identifier' &&
795
+ attr.name.value === 'ordinal'
807
796
  )
808
797
  const isOrdinal = !!ordinalAttr
809
798
 
@@ -988,17 +977,18 @@ export class ASTVisitors {
988
977
  *
989
978
  * @private
990
979
  * @param expression - The SWC AST expression node to resolve
980
+ * @param returnEmptyStrings - Whether to include empty strings in the result
991
981
  * @returns An array of possible string values that the expression may produce.
992
982
  */
993
- private resolvePossibleStringValues (expression: Expression): string[] {
983
+ private resolvePossibleStringValues (expression: Expression, returnEmptyStrings = false): string[] {
994
984
  if (expression.type === 'StringLiteral') {
995
985
  // Filter out empty strings as they should be treated as "no context" like i18next does
996
- return expression.value ? [expression.value] : []
986
+ return expression.value || returnEmptyStrings ? [expression.value] : []
997
987
  }
998
988
 
999
989
  if (expression.type === 'ConditionalExpression') { // This is a ternary operator
1000
- const consequentValues = this.resolvePossibleStringValues(expression.consequent)
1001
- const alternateValues = this.resolvePossibleStringValues(expression.alternate)
990
+ const consequentValues = this.resolvePossibleStringValues(expression.consequent, returnEmptyStrings)
991
+ const alternateValues = this.resolvePossibleStringValues(expression.alternate, returnEmptyStrings)
1002
992
  return [...consequentValues, ...alternateValues]
1003
993
  }
1004
994
 
@@ -1040,7 +1030,7 @@ export class ASTVisitors {
1040
1030
  (heads, expression, i) => {
1041
1031
  return heads.flatMap((head) => {
1042
1032
  const tail = tails[i]?.cooked ?? ''
1043
- return this.resolvePossibleStringValues(expression).map(
1033
+ return this.resolvePossibleStringValues(expression, true).map(
1044
1034
  (expressionValue) => `${head}${expressionValue}${tail}`
1045
1035
  )
1046
1036
  })
@@ -5,9 +5,9 @@ import type { PluginContext, I18nextToolkitConfig } from '../../types'
5
5
  * Supports extraction from single-line (//) and multi-line comments.
6
6
  *
7
7
  * @param code - The source code to analyze
8
- * @param functionNames - Array of function names to look for (e.g., ['t', 'i18n.t'])
9
8
  * @param pluginContext - Context object with helper methods to add found keys
10
9
  * @param config - Configuration object containing extraction settings
10
+ * @param scopeResolver - Function to resolve scope information for variables (optional)
11
11
  *
12
12
  * @example
13
13
  * ```typescript
@@ -17,14 +17,15 @@ import type { PluginContext, I18nextToolkitConfig } from '../../types'
17
17
  * `
18
18
  *
19
19
  * const context = createPluginContext(allKeys)
20
- * extractKeysFromComments(code, ['t'], context, config)
20
+ * extractKeysFromComments(code, context, config, scopeResolver)
21
21
  * // Extracts: user.name and app.title with their respective settings
22
22
  * ```
23
23
  */
24
24
  export function extractKeysFromComments (
25
25
  code: string,
26
26
  pluginContext: PluginContext,
27
- config: I18nextToolkitConfig
27
+ config: I18nextToolkitConfig,
28
+ scopeResolver?: (varName: string) => { defaultNs?: string; keyPrefix?: string } | undefined
28
29
  ): void {
29
30
  // Hardcode the function name to 't' to prevent parsing other functions like 'test()'.
30
31
  const functionNameToFind = 't'
@@ -42,6 +43,7 @@ export function extractKeysFromComments (
42
43
  const remainder = text.slice(match.index + match[0].length)
43
44
 
44
45
  const defaultValue = parseDefaultValueFromComment(remainder)
46
+
45
47
  // 1. Check for namespace in options object first (e.g., { ns: 'common' })
46
48
  ns = parseNsFromComment(remainder)
47
49
 
@@ -52,6 +54,17 @@ export function extractKeysFromComments (
52
54
  ns = parts.shift()
53
55
  key = parts.join(nsSeparator)
54
56
  }
57
+
58
+ // 3. NEW: If no explicit namespace found, try to resolve from scope
59
+ // This allows commented t() calls to inherit namespace from useTranslation scope
60
+ if (!ns && scopeResolver) {
61
+ const scopeInfo = scopeResolver('t')
62
+ if (scopeInfo?.defaultNs) {
63
+ ns = scopeInfo.defaultNs
64
+ }
65
+ }
66
+
67
+ // 4. Final fallback to configured default namespace
55
68
  if (!ns) ns = config.extract.defaultNS
56
69
 
57
70
  pluginContext.addKey({ key, ns, defaultValue: defaultValue ?? key })
@@ -158,9 +158,28 @@ export function extractFromTransComponent (node: JSXElement, config: I18nextTool
158
158
  }
159
159
 
160
160
  let keyExpression: Expression | undefined
161
+ let processedKeyValue: string | undefined
162
+
161
163
  if (i18nKeyAttr?.type === 'JSXAttribute') {
162
164
  if (i18nKeyAttr.value?.type === 'StringLiteral') {
163
165
  keyExpression = i18nKeyAttr.value
166
+ processedKeyValue = keyExpression.value
167
+
168
+ // Handle namespace prefix removal when both ns and i18nKey are provided
169
+ if (ns && keyExpression.type === 'StringLiteral') {
170
+ const nsSeparator = config.extract.nsSeparator ?? ':'
171
+ const keyValue = keyExpression.value
172
+
173
+ // If the key starts with the namespace followed by the separator, remove the prefix
174
+ if (nsSeparator && keyValue.startsWith(`${ns}${nsSeparator}`)) {
175
+ processedKeyValue = keyValue.slice(`${ns}${nsSeparator}`.length)
176
+ // Create a new StringLiteral with the namespace prefix removed
177
+ keyExpression = {
178
+ ...keyExpression,
179
+ value: processedKeyValue
180
+ }
181
+ }
182
+ }
164
183
  } else if (
165
184
  i18nKeyAttr.value?.type === 'JSXExpressionContainer' &&
166
185
  i18nKeyAttr.value.expression.type !== 'JSXEmptyExpression'
@@ -171,6 +190,14 @@ export function extractFromTransComponent (node: JSXElement, config: I18nextTool
171
190
  if (!keyExpression) return null
172
191
  }
173
192
 
193
+ // If no explicit defaults provided and we have a processed key, use it as default value
194
+ // This matches the behavior of other similar tests in the codebase
195
+ if (!defaultsAttr && processedKeyValue && !serialized.trim()) {
196
+ defaultValue = processedKeyValue
197
+ } else if (!defaultsAttr && serialized.trim()) {
198
+ defaultValue = serialized
199
+ }
200
+
174
201
  return {
175
202
  keyExpression,
176
203
  serializedChildren: serialized,
@@ -1,4 +1,4 @@
1
- import type { ExtractedKey, PluginContext } from '../types'
1
+ import type { ExtractedKey, PluginContext, I18nextToolkitConfig, Logger } from '../types'
2
2
 
3
3
  /**
4
4
  * Initializes an array of plugins by calling their setup hooks.
@@ -39,7 +39,7 @@ export async function initializePlugins (plugins: any[]): Promise<void> {
39
39
  * })
40
40
  * ```
41
41
  */
42
- export function createPluginContext (allKeys: Map<string, ExtractedKey>): PluginContext {
42
+ export function createPluginContext (allKeys: Map<string, ExtractedKey>, config: I18nextToolkitConfig, logger: Logger): PluginContext {
43
43
  return {
44
44
  addKey: (keyInfo: ExtractedKey) => {
45
45
  // Use namespace in the unique map key to avoid collisions across namespaces
@@ -50,5 +50,9 @@ export function createPluginContext (allKeys: Map<string, ExtractedKey>): Plugin
50
50
  allKeys.set(uniqueKey, { ...keyInfo, defaultValue })
51
51
  }
52
52
  },
53
+ config,
54
+ logger,
55
+ // This will be attached later, so we provide a placeholder
56
+ getVarFromScope: () => undefined,
53
57
  }
54
58
  }
package/src/types.ts CHANGED
@@ -363,4 +363,29 @@ export interface PluginContext {
363
363
  * @param keyInfo - The extracted key information
364
364
  */
365
365
  addKey: (keyInfo: ExtractedKey) => void;
366
+
367
+ /** The fully resolved i18next-cli configuration. */
368
+ config: I18nextToolkitConfig;
369
+
370
+ /** The shared logger instance. */
371
+ logger: Logger;
372
+
373
+ /**
374
+ * Retrieves variable information from the current scope chain.
375
+ * Searches from the innermost scope outwards.
376
+ * @param name - The variable name to look up (e.g., 't').
377
+ * @returns Scope information if found, otherwise undefined.
378
+ */
379
+ getVarFromScope: (name: string) => ScopeInfo | undefined;
380
+ }
381
+
382
+ /**
383
+ * Represents variable scope information tracked during AST traversal.
384
+ * Used to maintain context about translation functions and their configuration.
385
+ */
386
+ export interface ScopeInfo {
387
+ /** Default namespace for translation calls in this scope */
388
+ defaultNs?: string;
389
+ /** Key prefix to prepend to all translation keys in this scope */
390
+ keyPrefix?: string;
366
391
  }
@@ -1 +1 @@
1
- {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAiB,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAM5F,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EACjB,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAuDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAClC,WAAW,EAAE,WAAW,EACxB,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,sDAO1D"}
1
+ {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAiB,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAM5F,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EACjB,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAuDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAClC,WAAW,EAAE,WAAW,EACxB,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,CA2Cf;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,sDAO1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"key-finder.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/key-finder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAM7E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAmB1E"}
1
+ {"version":3,"file":"key-finder.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/key-finder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAM7E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CA0B1E"}
@@ -1,5 +1,5 @@
1
1
  import type { Module } from '@swc/core';
2
- import type { PluginContext, I18nextToolkitConfig, Logger } from '../../types';
2
+ import type { PluginContext, I18nextToolkitConfig, Logger, ScopeInfo } from '../../types';
3
3
  /**
4
4
  * AST visitor class that traverses JavaScript/TypeScript syntax trees to extract translation keys.
5
5
  *
@@ -90,7 +90,7 @@ export declare class ASTVisitors {
90
90
  *
91
91
  * @private
92
92
  */
93
- private getVarFromScope;
93
+ getVarFromScope(name: string): ScopeInfo | undefined;
94
94
  /**
95
95
  * Handles variable declarations that might define translation functions.
96
96
  *
@@ -252,6 +252,7 @@ export declare class ASTVisitors {
252
252
  *
253
253
  * @private
254
254
  * @param expression - The SWC AST expression node to resolve
255
+ * @param returnEmptyStrings - Whether to include empty strings in the result
255
256
  * @returns An array of possible string values that the expression may produce.
256
257
  */
257
258
  private resolvePossibleStringValues;
@@ -1 +1 @@
1
- {"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAgI,MAAM,WAAW,CAAA;AACrK,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,MAAM,aAAa,CAAA;AAqB5F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,UAAU,CAAoC;IAE/C,UAAU,cAAoB;IAErC;;;;;;OAMG;gBAED,MAAM,EAAE,oBAAoB,EAC5B,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM;IAOhB;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAsDZ;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAIjB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAMrB;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IASvB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,wBAAwB;IAmChC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,8BAA8B;IAwDtC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,oBAAoB;IAgK5B;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,gBAAgB;IA4DxB;;;;;;;;OAQG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IA4IxB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IA6DlC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,2BAA2B;IA4BnC;;;;;;;OAOG;IACH,OAAO,CAAC,6CAA6C;IAyBrD;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
1
+ {"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAgI,MAAM,WAAW,CAAA;AACrK,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,aAAa,CAAA;AAUvG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,UAAU,CAAoC;IAE/C,UAAU,cAAoB;IAErC;;;;;;OAMG;gBAED,MAAM,EAAE,oBAAoB,EAC5B,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM;IAOhB;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAsDZ;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAIjB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAMrB;;;;;;;;OAQG;IACI,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAS5D;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,wBAAwB;IAmChC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,8BAA8B;IAwDtC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,oBAAoB;IAgK5B;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,gBAAgB;IA4DxB;;;;;;;;OAQG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;;;;;;;;OASG;IACH,OAAO,CAAC,gBAAgB;IA4IxB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IA6DlC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,2BAA2B;IA4BnC;;;;;;;OAOG;IACH,OAAO,CAAC,6CAA6C;IAyBrD;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
@@ -4,9 +4,9 @@ import type { PluginContext, I18nextToolkitConfig } from '../../types';
4
4
  * Supports extraction from single-line (//) and multi-line comments.
5
5
  *
6
6
  * @param code - The source code to analyze
7
- * @param functionNames - Array of function names to look for (e.g., ['t', 'i18n.t'])
8
7
  * @param pluginContext - Context object with helper methods to add found keys
9
8
  * @param config - Configuration object containing extraction settings
9
+ * @param scopeResolver - Function to resolve scope information for variables (optional)
10
10
  *
11
11
  * @example
12
12
  * ```typescript
@@ -16,9 +16,12 @@ import type { PluginContext, I18nextToolkitConfig } from '../../types';
16
16
  * `
17
17
  *
18
18
  * const context = createPluginContext(allKeys)
19
- * extractKeysFromComments(code, ['t'], context, config)
19
+ * extractKeysFromComments(code, context, config, scopeResolver)
20
20
  * // Extracts: user.name and app.title with their respective settings
21
21
  * ```
22
22
  */
23
- export declare function extractKeysFromComments(code: string, pluginContext: PluginContext, config: I18nextToolkitConfig): void;
23
+ export declare function extractKeysFromComments(code: string, pluginContext: PluginContext, config: I18nextToolkitConfig, scopeResolver?: (varName: string) => {
24
+ defaultNs?: string;
25
+ keyPrefix?: string;
26
+ } | undefined): void;
24
27
  //# sourceMappingURL=comment-parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/comment-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEtE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,oBAAoB,GAC3B,IAAI,CAgCN"}
1
+ {"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/comment-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEtE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,oBAAoB,EAC5B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC1F,IAAI,CA4CN"}
@@ -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,EAAE,UAAU,EAAE,gBAAgB,EAAY,MAAM,WAAW,CAAA;AACnF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAGvD,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;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,IAAI,CAyHxH"}
1
+ {"version":3,"file":"jsx-parser.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAY,MAAM,WAAW,CAAA;AACnF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAGvD,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;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,IAAI,CAoJxH"}
@@ -1,4 +1,4 @@
1
- import type { ExtractedKey, PluginContext } from '../types';
1
+ import type { ExtractedKey, PluginContext, I18nextToolkitConfig, Logger } from '../types';
2
2
  /**
3
3
  * Initializes an array of plugins by calling their setup hooks.
4
4
  * This function should be called before starting the extraction process.
@@ -33,5 +33,5 @@ export declare function initializePlugins(plugins: any[]): Promise<void>;
33
33
  * })
34
34
  * ```
35
35
  */
36
- export declare function createPluginContext(allKeys: Map<string, ExtractedKey>): PluginContext;
36
+ export declare function createPluginContext(allKeys: Map<string, ExtractedKey>, config: I18nextToolkitConfig, logger: Logger): PluginContext;
37
37
  //# sourceMappingURL=plugin-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-manager.d.ts","sourceRoot":"","sources":["../../src/extractor/plugin-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE3D;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,aAAa,CAYtF"}
1
+ {"version":3,"file":"plugin-manager.d.ts","sourceRoot":"","sources":["../../src/extractor/plugin-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEzF;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAgBpI"}
package/types/types.d.ts CHANGED
@@ -309,5 +309,26 @@ export interface PluginContext {
309
309
  * @param keyInfo - The extracted key information
310
310
  */
311
311
  addKey: (keyInfo: ExtractedKey) => void;
312
+ /** The fully resolved i18next-cli configuration. */
313
+ config: I18nextToolkitConfig;
314
+ /** The shared logger instance. */
315
+ logger: Logger;
316
+ /**
317
+ * Retrieves variable information from the current scope chain.
318
+ * Searches from the innermost scope outwards.
319
+ * @param name - The variable name to look up (e.g., 't').
320
+ * @returns Scope information if found, otherwise undefined.
321
+ */
322
+ getVarFromScope: (name: string) => ScopeInfo | undefined;
323
+ }
324
+ /**
325
+ * Represents variable scope information tracked during AST traversal.
326
+ * Used to maintain context about translation functions and their configuration.
327
+ */
328
+ export interface ScopeInfo {
329
+ /** Default namespace for translation calls in this scope */
330
+ defaultNs?: string;
331
+ /** Key prefix to prepend to all translation keys in this scope */
332
+ keyPrefix?: string;
312
333
  }
313
334
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}