i18next-cli 1.21.1 → 1.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +107 -0
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/extractor/core/ast-visitors.js +1 -1
- package/dist/cjs/extractor/core/extractor.js +1 -1
- package/dist/cjs/extractor/parsers/call-expression-handler.js +1 -1
- package/dist/cjs/extractor/parsers/jsx-handler.js +1 -1
- package/dist/cjs/extractor/plugin-manager.js +1 -1
- package/dist/cjs/types-generator.js +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/core/ast-visitors.js +1 -1
- package/dist/esm/extractor/core/extractor.js +1 -1
- package/dist/esm/extractor/parsers/call-expression-handler.js +1 -1
- package/dist/esm/extractor/parsers/jsx-handler.js +1 -1
- package/dist/esm/extractor/plugin-manager.js +1 -1
- package/dist/esm/types-generator.js +1 -1
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/extractor/core/ast-visitors.ts +48 -2
- package/src/extractor/core/extractor.ts +3 -0
- package/src/extractor/parsers/call-expression-handler.ts +45 -2
- package/src/extractor/parsers/jsx-handler.ts +93 -19
- package/src/extractor/plugin-manager.ts +27 -3
- package/src/types-generator.ts +3 -1
- package/src/types.ts +7 -0
- package/types/extractor/core/ast-visitors.d.ts +23 -0
- package/types/extractor/core/ast-visitors.d.ts.map +1 -1
- package/types/extractor/core/extractor.d.ts.map +1 -1
- package/types/extractor/parsers/call-expression-handler.d.ts +8 -1
- package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
- package/types/extractor/parsers/jsx-handler.d.ts +9 -1
- package/types/extractor/parsers/jsx-handler.d.ts.map +1 -1
- package/types/extractor/plugin-manager.d.ts.map +1 -1
- package/types/types-generator.d.ts.map +1 -1
- package/types/types.d.ts +6 -0
- package/types/types.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ 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.22.1](https://github.com/i18next/i18next-cli/compare/v1.22.0...v1.22.1) - 2025-11-06
|
|
9
|
+
|
|
10
|
+
- **Types-Generator:** Add a comment to the start of the types file to note it is auto-generated [#97](https://github.com/i18next/i18next-cli/pull/97)
|
|
11
|
+
|
|
12
|
+
## [1.22.0](https://github.com/i18next/i18next-cli/compare/v1.21.1...v1.22.0) - 2025-11-06
|
|
13
|
+
|
|
14
|
+
- **Plugin System:** Enhanced `ExtractedKey` type and plugin hooks to support location metadata tracking. Plugins can now access file paths, etc. for each extracted translation key via the `locations` array property. [#95](https://github.com/i18next/i18next-cli/issues/95)
|
|
15
|
+
|
|
8
16
|
## [1.21.1](https://github.com/i18next/i18next-cli/compare/v1.21.0...v1.21.1) - 2025-11-05
|
|
9
17
|
|
|
10
18
|
- **Extractor (`--sync-primary`):** Fixed a bug where `<Trans i18nKey='namespace:key' />` components with namespaced keys were having their existing primary language translations overwritten with the full namespaced key string (e.g., `'translation:app.preservedTrans'`) when using the `--sync-primary` flag. The extractor now correctly identifies namespaced keys in defaultValue as derived (auto-generated) defaults rather than explicit developer-provided values, preserving existing translations when no explicit defaultValue is provided. This ensures that `<Trans>` components without explicit defaults behave consistently with `t()` calls under `--sync-primary`. [#92](https://github.com/i18next/i18next-cli/issues/92)
|
package/README.md
CHANGED
|
@@ -581,6 +581,113 @@ export default defineConfig({
|
|
|
581
581
|
});
|
|
582
582
|
```
|
|
583
583
|
|
|
584
|
+
### Location Metadata Tracking
|
|
585
|
+
|
|
586
|
+
Track where each translation key is used in your codebase with a custom metadata plugin.
|
|
587
|
+
|
|
588
|
+
**Example Plugin Implementation:**
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
592
|
+
import { dirname } from 'node:path';
|
|
593
|
+
import type { Plugin } from 'i18next-cli';
|
|
594
|
+
|
|
595
|
+
interface LocationMetadataOptions {
|
|
596
|
+
/** Output path for the metadata file (default: 'locales/metadata.json') */
|
|
597
|
+
output?: string;
|
|
598
|
+
/** Include line and column numbers (default: true) */
|
|
599
|
+
includePosition?: boolean;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export const locationMetadataPlugin = (options: LocationMetadataOptions = {}): Plugin => {
|
|
603
|
+
const {
|
|
604
|
+
output = 'locales/metadata.json',
|
|
605
|
+
includePosition = true,
|
|
606
|
+
} = options;
|
|
607
|
+
|
|
608
|
+
return {
|
|
609
|
+
name: 'location-metadata',
|
|
610
|
+
|
|
611
|
+
async onEnd(keys) {
|
|
612
|
+
const metadata: Record<string, any> = {};
|
|
613
|
+
|
|
614
|
+
for (const [uniqueKey, extractedKey] of keys.entries()) {
|
|
615
|
+
const { key, ns, locations } = extractedKey;
|
|
616
|
+
|
|
617
|
+
// Skip keys without location data
|
|
618
|
+
if (!locations || locations.length === 0) {
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Format location data
|
|
623
|
+
const locationData = locations.map(loc => {
|
|
624
|
+
if (includePosition && loc.line !== undefined) {
|
|
625
|
+
return `${loc.file}:${loc.line}:${loc.column ?? 0}`;
|
|
626
|
+
}
|
|
627
|
+
return loc.file;
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// Organize metadata
|
|
631
|
+
const namespace = ns || 'translation';
|
|
632
|
+
if (!metadata[namespace]) {
|
|
633
|
+
metadata[namespace] = {};
|
|
634
|
+
}
|
|
635
|
+
metadata[namespace][key] = locationData;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Write metadata file
|
|
639
|
+
await mkdir(dirname(output), { recursive: true });
|
|
640
|
+
await writeFile(output, JSON.stringify(metadata, null, 2), 'utf-8');
|
|
641
|
+
|
|
642
|
+
console.log(`📍 Location metadata written to ${output}`);
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
};
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Configuration:**
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
// i18next.config.ts
|
|
652
|
+
import { defineConfig } from 'i18next-cli';
|
|
653
|
+
import { locationMetadataPlugin } from './plugins/location-metadata.mjs';
|
|
654
|
+
|
|
655
|
+
export default defineConfig({
|
|
656
|
+
locales: ['en', 'de'],
|
|
657
|
+
extract: {
|
|
658
|
+
input: ['src/**/*.{ts,tsx}'],
|
|
659
|
+
output: 'locales/{{language}}/{{namespace}}.json',
|
|
660
|
+
},
|
|
661
|
+
plugins: [
|
|
662
|
+
locationMetadataPlugin({
|
|
663
|
+
output: 'locales/metadata.json'
|
|
664
|
+
})
|
|
665
|
+
]
|
|
666
|
+
});
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**Example Output (`locales/metadata.json`):**
|
|
670
|
+
|
|
671
|
+
```json
|
|
672
|
+
{
|
|
673
|
+
"translation": {
|
|
674
|
+
"app.title": [
|
|
675
|
+
"src/App.tsx:12:15",
|
|
676
|
+
"src/components/Header.tsx:8:22"
|
|
677
|
+
],
|
|
678
|
+
"user.greeting": [
|
|
679
|
+
"src/pages/Profile.tsx:45:10"
|
|
680
|
+
]
|
|
681
|
+
},
|
|
682
|
+
"common": {
|
|
683
|
+
"button.save": [
|
|
684
|
+
"src/components/SaveButton.tsx:18:7",
|
|
685
|
+
"src/forms/UserForm.tsx:92:5"
|
|
686
|
+
]
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
584
691
|
### Dynamic Key Preservation
|
|
585
692
|
|
|
586
693
|
Use `preservePatterns` to maintain dynamically generated keys:
|
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"),o=require("glob"),n=require("minimatch"),i=require("chalk"),a=require("./config.js"),r=require("./heuristic-config.js"),c=require("./extractor/core/extractor.js");require("node:path"),require("node:fs/promises"),require("jiti");var s=require("./types-generator.js"),l=require("./syncer.js"),u=require("./migrator.js"),g=require("./init.js"),d=require("./linter.js"),p=require("./status.js"),f=require("./locize.js");const m=new e.Command;m.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.
|
|
2
|
+
"use strict";var e=require("commander"),t=require("chokidar"),o=require("glob"),n=require("minimatch"),i=require("chalk"),a=require("./config.js"),r=require("./heuristic-config.js"),c=require("./extractor/core/extractor.js");require("node:path"),require("node:fs/promises"),require("jiti");var s=require("./types-generator.js"),l=require("./syncer.js"),u=require("./migrator.js"),g=require("./init.js"),d=require("./linter.js"),p=require("./status.js"),f=require("./locize.js");const m=new e.Command;m.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.22.1"),m.option("-c, --config <path>","Path to i18next-cli config file (overrides detection)"),m.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.").option("--sync-primary","Sync primary language values with default values from code.").action(async e=>{try{const o=m.opts().config,i=await a.ensureConfig(o),r=async()=>{const t=await c.runExtractor(i,{isWatchMode:!!e.watch,isDryRun:!!e.dryRun,syncPrimaryWithDefaults:!!e.syncPrimary});return e.ci&&!t?(console.log("✅ No files were updated."),process.exit(0)):e.ci&&t&&(console.error("❌ Some files were updated. This should not happen in CI mode."),process.exit(1)),t};if(await r(),e.watch){console.log("\nWatching for changes...");const e=await w(i.extract.input),o=y(i.extract.ignore),a=h(i.extract.output),c=[...o,...a].filter(Boolean),s=e.filter(e=>!c.some(t=>n.minimatch(e,t,{dot:!0})));t.watch(s,{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),r()})}}catch(e){console.error("Error running extractor:",e),process.exit(1)}}),m.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)=>{const o=m.opts().config;let n=await a.loadConfig(o);if(!n){console.log(i.blue("No config file found. Attempting to detect project structure..."));const e=await r.detectConfig();e||(console.error(i.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${i.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(i.green("Project structure detected successfully!")),n=e}await p.runStatus(n,{detail:e,namespace:t.namespace})}),m.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=m.opts().config,i=await a.ensureConfig(o),r=()=>s.runTypesGenerator(i);if(await r(),e.watch){console.log("\nWatching for changes...");const e=await w(i.types?.input||[]),o=[...y(i.extract?.ignore)].filter(Boolean),a=e.filter(e=>!o.some(t=>n.minimatch(e,t,{dot:!0})));t.watch(a,{persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),r()})}}),m.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const e=m.opts().config,t=await a.ensureConfig(e);await l.runSyncer(t)}),m.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async e=>{await u.runMigrator(e)}),m.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(g.runInit),m.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 o=m.opts().config,c=async()=>{let e=await a.loadConfig(o);if(!e){console.log(i.blue("No config file found. Attempting to detect project structure..."));const t=await r.detectConfig();t||(console.error(i.red("Could not automatically detect your project structure.")),console.log(`Please create a config file first by running: ${i.cyan("npx i18next-cli init")}`),process.exit(1)),console.log(i.green("Project structure detected successfully!")),e=t}await d.runLinterCli(e)};if(await c(),e.watch){console.log("\nWatching for changes...");const e=await a.loadConfig(o);if(e?.extract?.input){const o=await w(e.extract.input),i=[...y(e.extract.ignore),...h(e.extract.output)].filter(Boolean),a=o.filter(e=>!i.some(t=>n.minimatch(e,t,{dot:!0})));t.watch(a,{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),c()})}}}),m.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=m.opts().config,o=await a.ensureConfig(t);await f.runLocizeSync(o,e)}),m.command("locize-download").description("Download all translations from your locize project.").action(async e=>{const t=m.opts().config,o=await a.ensureConfig(t);await f.runLocizeDownload(o,e)}),m.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async e=>{const t=m.opts().config,o=await a.ensureConfig(t);await f.runLocizeMigrate(o,e)}),m.parse(process.argv);const y=e=>Array.isArray(e)?e:e?[e]:[],h=e=>e&&"string"==typeof e?[e.replace(/\{\{[^}]+\}\}/g,"*")]:[],w=async(e=[])=>{const t=y(e),n=await Promise.all(t.map(e=>o.glob(e||"",{nodir:!0})));return Array.from(new Set(n.flat()))};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("../parsers/scope-manager.js"),
|
|
1
|
+
"use strict";var e=require("../parsers/scope-manager.js"),r=require("../parsers/expression-resolver.js"),s=require("../parsers/call-expression-handler.js"),t=require("../parsers/jsx-handler.js");exports.ASTVisitors=class{pluginContext;config;logger;hooks;get objectKeys(){return this.callExpressionHandler.objectKeys}scopeManager;expressionResolver;callExpressionHandler;jsxHandler;currentFile="";currentCode="";constructor(o,a,i,n,l){this.pluginContext=a,this.config=o,this.logger=i,this.hooks={onBeforeVisitNode:n?.onBeforeVisitNode,onAfterVisitNode:n?.onAfterVisitNode,resolvePossibleKeyStringValues:n?.resolvePossibleKeyStringValues,resolvePossibleContextStringValues:n?.resolvePossibleContextStringValues},this.scopeManager=new e.ScopeManager(o),this.expressionResolver=l??new r.ExpressionResolver(this.hooks),this.callExpressionHandler=new s.CallExpressionHandler(o,a,i,this.expressionResolver,()=>this.getCurrentFile(),()=>this.getCurrentCode()),this.jsxHandler=new t.JSXHandler(o,a,this.expressionResolver,()=>this.getCurrentFile(),()=>this.getCurrentCode())}visit(e){this.scopeManager.reset(),this.expressionResolver.resetFileSymbols(),this.scopeManager.enterScope(),this.walk(e),this.scopeManager.exitScope()}walk(e){if(!e)return;let r=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.scopeManager.enterScope(),r=!0),this.hooks.onBeforeVisitNode?.(e),e.type){case"VariableDeclarator":this.scopeManager.handleVariableDeclarator(e),this.expressionResolver.captureVariableDeclarator(e);break;case"TSEnumDeclaration":case"TsEnumDeclaration":case"TsEnumDecl":this.expressionResolver.captureEnumDeclaration(e);break;case"CallExpression":this.callExpressionHandler.handleCallExpression(e,this.scopeManager.getVarFromScope.bind(this.scopeManager));break;case"JSXElement":this.jsxHandler.handleJSXElement(e,this.scopeManager.getVarFromScope.bind(this.scopeManager))}this.hooks.onAfterVisitNode?.(e);for(const r in e){if("span"===r)continue;const s=e[r];if(Array.isArray(s)){for(const e of s)if(e&&"object"==typeof e)if("VariableDeclarator"!==e.type){if(e&&e.id&&Array.isArray(e.members)&&this.expressionResolver.captureEnumDeclaration(e),"VariableDeclaration"===e.type&&Array.isArray(e.declarations))for(const r of e.declarations)r&&"object"==typeof r&&"VariableDeclarator"===r.type&&(this.scopeManager.handleVariableDeclarator(r),this.expressionResolver.captureVariableDeclarator(r))}else this.scopeManager.handleVariableDeclarator(e),this.expressionResolver.captureVariableDeclarator(e);for(const e of s)e&&"object"==typeof e&&this.walk(e)}else s&&"object"==typeof s&&this.walk(s)}r&&this.scopeManager.exitScope()}getVarFromScope(e){return this.scopeManager.getVarFromScope(e)}setCurrentFile(e,r){this.currentFile=e,this.currentCode=r}getCurrentFile(){return this.currentFile}getCurrentCode(){return this.currentCode}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=require("ora"),e=require("chalk"),r=require("@swc/core"),a=require("node:fs/promises"),o=require("node:path"),n=require("./key-finder.js"),s=require("./translation-manager.js"),i=require("../../utils/validation.js"),c=require("../parsers/comment-parser.js"),l=require("../../utils/logger.js"),u=require("../../utils/file-utils.js"),y=require("../../utils/funnel-msg-tracker.js");exports.extract=async function(t,{syncPrimaryWithDefaults:e=!1}={}){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(e=>e!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:r,objectKeys:a}=await n.findKeys(t);return s.getTranslations(r,a,t,{syncPrimaryWithDefaults:e})},exports.processFile=async function(t,e,n,s,u,y=new l.ConsoleLogger){try{let l=await a.readFile(t,"utf-8");for(const r of e)try{const e=await(r.onLoad?.(l,t));void 0!==e&&(l=e)}catch(t){y.warn(`Plugin ${r.name} onLoad failed:`,t)}const d=o.extname(t).toLowerCase(),g=".ts"===d||".tsx"===d||".mts"===d||".cts"===d,m=".tsx"===d;let p;try{p=await r.parse(l,{syntax:g?"typescript":"ecmascript",tsx:m,decorators:!0,dynamicImport:!0,comments:!0})}catch(e){if(".ts"!==d||m)throw new i.ExtractorError("Failed to process file",t,e);try{p=await r.parse(l,{syntax:"typescript",tsx:!0,decorators:!0,dynamicImport:!0,comments:!0}),y.info?.(`Parsed ${t} using TSX fallback`)}catch(e){throw new i.ExtractorError("Failed to process file",t,e)}}s.getVarFromScope=n.getVarFromScope.bind(n),n.visit(p),c.extractKeysFromComments(l,s,u,n.getVarFromScope.bind(n))}catch(e){throw new i.ExtractorError("Failed to process file",t,e)}},exports.runExtractor=async function(r,{isWatchMode:c=!1,isDryRun:d=!1,syncPrimaryWithDefaults:g=!1}={},m=new l.ConsoleLogger){r.extract.primaryLanguage||=r.locales[0]||"en",r.extract.secondaryLanguages||=r.locales.filter(t=>t!==r?.extract?.primaryLanguage),r.extract.functions||=["t","*.t"],r.extract.transComponents||=["Trans"],i.validateExtractorConfig(r);const p=r.plugins||[],f=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:i}=await n.findKeys(r,m);f.text=`Found ${t.size} unique keys. Updating translation files...`;const c=await s.getTranslations(t,i,r,{syncPrimaryWithDefaults:g});let l=!1;for(const t of c)if(t.updated&&(l=!0,!d)){const n=u.serializeTranslationFile(t.newTranslations,r.extract.outputFormat,r.extract.indentation);await a.mkdir(o.dirname(t.path),{recursive:!0}),await a.writeFile(t.path,n),m.info(e.green(`Updated: ${t.path}`))}if(p.length>0){f.text="Running post-extraction plugins...";for(const t of p)await(t.afterSync?.(c,r))}return f.succeed(e.bold("Extraction complete!")),l&&await async function(){if(!await y.shouldShowFunnel("extract"))return;return console.log(e.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: ${e.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${e.cyan("https://youtu.be/joPsZghT3wM")}`),y.recordFunnelShown("extract")}(),l}catch(t){throw f.fail(e.red("Extraction failed.")),t}};
|
|
1
|
+
"use strict";var t=require("ora"),e=require("chalk"),r=require("@swc/core"),a=require("node:fs/promises"),o=require("node:path"),n=require("./key-finder.js"),s=require("./translation-manager.js"),i=require("../../utils/validation.js"),c=require("../parsers/comment-parser.js"),l=require("../../utils/logger.js"),u=require("../../utils/file-utils.js"),y=require("../../utils/funnel-msg-tracker.js");exports.extract=async function(t,{syncPrimaryWithDefaults:e=!1}={}){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(e=>e!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:r,objectKeys:a}=await n.findKeys(t);return s.getTranslations(r,a,t,{syncPrimaryWithDefaults:e})},exports.processFile=async function(t,e,n,s,u,y=new l.ConsoleLogger){try{let l=await a.readFile(t,"utf-8");for(const r of e)try{const e=await(r.onLoad?.(l,t));void 0!==e&&(l=e)}catch(t){y.warn(`Plugin ${r.name} onLoad failed:`,t)}const d=o.extname(t).toLowerCase(),g=".ts"===d||".tsx"===d||".mts"===d||".cts"===d,m=".tsx"===d;let p;try{p=await r.parse(l,{syntax:g?"typescript":"ecmascript",tsx:m,decorators:!0,dynamicImport:!0,comments:!0})}catch(e){if(".ts"!==d||m)throw new i.ExtractorError("Failed to process file",t,e);try{p=await r.parse(l,{syntax:"typescript",tsx:!0,decorators:!0,dynamicImport:!0,comments:!0}),y.info?.(`Parsed ${t} using TSX fallback`)}catch(e){throw new i.ExtractorError("Failed to process file",t,e)}}s.getVarFromScope=n.getVarFromScope.bind(n),n.setCurrentFile(t,l),n.visit(p),c.extractKeysFromComments(l,s,u,n.getVarFromScope.bind(n))}catch(e){throw new i.ExtractorError("Failed to process file",t,e)}},exports.runExtractor=async function(r,{isWatchMode:c=!1,isDryRun:d=!1,syncPrimaryWithDefaults:g=!1}={},m=new l.ConsoleLogger){r.extract.primaryLanguage||=r.locales[0]||"en",r.extract.secondaryLanguages||=r.locales.filter(t=>t!==r?.extract?.primaryLanguage),r.extract.functions||=["t","*.t"],r.extract.transComponents||=["Trans"],i.validateExtractorConfig(r);const p=r.plugins||[],f=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:i}=await n.findKeys(r,m);f.text=`Found ${t.size} unique keys. Updating translation files...`;const c=await s.getTranslations(t,i,r,{syncPrimaryWithDefaults:g});let l=!1;for(const t of c)if(t.updated&&(l=!0,!d)){const n=u.serializeTranslationFile(t.newTranslations,r.extract.outputFormat,r.extract.indentation);await a.mkdir(o.dirname(t.path),{recursive:!0}),await a.writeFile(t.path,n),m.info(e.green(`Updated: ${t.path}`))}if(p.length>0){f.text="Running post-extraction plugins...";for(const t of p)await(t.afterSync?.(c,r))}return f.succeed(e.bold("Extraction complete!")),l&&await async function(){if(!await y.shouldShowFunnel("extract"))return;return console.log(e.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: ${e.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${e.cyan("https://youtu.be/joPsZghT3wM")}`),y.recordFunnelShown("extract")}(),l}catch(t){throw f.fail(e.red("Extraction failed.")),t}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./ast-utils.js");exports.CallExpressionHandler=class{pluginContext;config;logger;expressionResolver;objectKeys=new Set;constructor(e,t,r,n){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n}handleCallExpression(t,r){const n=this.getFunctionName(t.callee);if(!n)return;const
|
|
1
|
+
"use strict";var e=require("./ast-utils.js");exports.CallExpressionHandler=class{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;constructor(e,t,r,n,o,i){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n,this.getCurrentFile=o,this.getCurrentCode=i}getLocationFromSpan(e){if(!e||"number"!=typeof e.start)return;const t=this.getCurrentCode(),r=e.start,n=t.substring(0,r).split("\n");return{line:n.length,column:n[n.length-1].length}}handleCallExpression(t,r){const n=this.getFunctionName(t.callee);if(!n)return;const o=r(n),i=this.config.extract.functions||["t","*.t"];let s=void 0!==o;if(!s)for(const e of i)if(e.startsWith("*.")){if(n.endsWith(e.substring(1))){s=!0;break}}else if(e===n){s=!0;break}if(!s||0===t.arguments.length)return;const{keysToProcess:l,isSelectorAPI:a}=this.handleCallExpressionArgument(t,0);if(0===l.length)return;let u=!1;const p=this.config.extract.pluralSeparator??"_";for(let e=0;e<l.length;e++)l[e].endsWith(`${p}ordinal`)&&(u=!0,l[e]=l[e].slice(0,-8));let c,f;if(t.arguments.length>1){const r=t.arguments[1].expression;"ObjectExpression"===r.type?f=r:"StringLiteral"===r.type?c=r.value:"TemplateLiteral"===r.type&&e.isSimpleTemplateLiteral(r)&&(c=r.quasis[0].cooked)}if(t.arguments.length>2){const e=t.arguments[2].expression;"ObjectExpression"===e.type&&(f=e)}const y=f?e.getObjectPropValue(f,"defaultValue"):void 0,g="string"==typeof y?y:c,h=e=>{if(!e||!Array.isArray(e.properties))return!1;for(const t of e.properties)if(t&&"KeyValueProperty"===t.type&&t.key){const e="Identifier"===t.key.type&&t.key.value||"StringLiteral"===t.key.type&&t.key.value;if("string"==typeof e&&e.startsWith("defaultValue"))return!0}return!1},d="string"==typeof g||h(f),x=h(f),k=Boolean(x||"string"==typeof g&&!("string"==typeof(v=g)&&/{{\s*count\s*}}/.test(v)));var v;for(let r=0;r<l.length;r++){let n,i=l[r];if(f){const t=e.getObjectPropValue(f,"ns");"string"==typeof t&&(n=t)}const s=this.config.extract.nsSeparator??":";if(!n&&s&&i.includes(s)){const e=i.split(s);if(n=e.shift(),i=e.join(s),!i||""===i.trim()){this.logger.warn(`Skipping key that became empty after namespace removal: '${n}${s}'`);continue}}!n&&o?.defaultNs&&(n=o.defaultNs),n||(n=this.config.extract.defaultNS);let p=i;if(o?.keyPrefix){const e=this.config.extract.keySeparator??".";if(p=!1!==e?o.keyPrefix.endsWith(e)?`${o.keyPrefix}${i}`:`${o.keyPrefix}${e}${i}`:`${o.keyPrefix}${i}`,!1!==e){if(p.split(e).some(e=>""===e.trim())){this.logger.warn(`Skipping key with empty segments: '${p}' (keyPrefix: '${o.keyPrefix}', key: '${i}')`);continue}}}const c=r===l.length-1&&g||i;if(f){const t=e.getObjectProperty(f,"context"),r=[];if("StringLiteral"===t?.value?.type||"NumericLiteral"===t?.value.type||"BooleanLiteral"===t?.value.type){const e=`${t.value.value}`,o=this.config.extract.contextSeparator??"_";""!==e&&r.push({key:`${p}${o}${e}`,ns:n,defaultValue:c,explicitDefault:d})}else if(t?.value){const e=this.expressionResolver.resolvePossibleContextStringValues(t.value),o=this.config.extract.contextSeparator??"_";e.length>0&&(e.forEach(e=>{r.push({key:`${p}${o}${e}`,ns:n,defaultValue:c,explicitDefault:d})}),r.push({key:p,ns:n,defaultValue:c,explicitDefault:d}))}const o=e=>{if(e){if("KeyValueProperty"===e.type&&e.key){if("Identifier"===e.key.type)return e.key.value;if("StringLiteral"===e.key.type)return e.key.value}return"KeyValueProperty"===e.type&&e.value&&"Identifier"===e.value.type?e.key&&"Identifier"===e.key.type?e.key.value:void 0:"ShorthandProperty"!==e.type&&"Identifier"!==e.type||!e.value?e.key&&"string"==typeof e.key?e.key:void 0:e.value}},i=(()=>{if(!f||!Array.isArray(f.properties))return!1;for(const e of f.properties){if("count"===o(e))return!0}return!1})(),s=(()=>{if(!f||!Array.isArray(f.properties))return!1;for(const e of f.properties){if("ordinal"===o(e))return!("KeyValueProperty"!==e.type||!e.value||"BooleanLiteral"!==e.value.type)&&Boolean(e.value.value)}return!1})();if(i||u){try{const e=u?"ordinal":"cardinal",t=this.config.extract?.primaryLanguage||(Array.isArray(this.config.locales)?this.config.locales[0]:void 0)||"en";let o=!1;try{const r=new Intl.PluralRules(t,{type:e}).resolvedOptions().pluralCategories;1===r.length&&"other"===r[0]&&(o=!0)}catch{}if(!o){const t=new Set;for(const r of this.config.locales)try{new Intl.PluralRules(r,{type:e}).resolvedOptions().pluralCategories.forEach(e=>t.add(e))}catch{new Intl.PluralRules("en",{type:e}).resolvedOptions().pluralCategories.forEach(e=>t.add(e))}const r=Array.from(t).sort();1===r.length&&"other"===r[0]&&(o=!0)}if(o){if(r.length>0)for(const e of r)this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,hasCount:!0,isOrdinal:u});else this.pluginContext.addKey({key:p,ns:n,defaultValue:c,hasCount:!0,isOrdinal:u});continue}}catch(e){}this.config.extract.disablePlurals?r.length>0?r.forEach(this.pluginContext.addKey):this.pluginContext.addKey({key:p,ns:n,defaultValue:c,explicitDefault:d}):this.handlePluralKeys(p,n,f,s||u,g,k);continue}if(r.length>0){r.forEach(this.pluginContext.addKey);continue}!0===e.getObjectPropValue(f,"returnObjects")&&this.objectKeys.add(p)}a&&this.objectKeys.add(p);{const e=t.span?this.getLocationFromSpan(t.span):void 0;this.pluginContext.addKey({key:p,ns:n,defaultValue:c,explicitDefault:d,locations:e?[{file:this.getCurrentFile(),line:e.line,column:e.column}]:void 0})}}}handleCallExpressionArgument(e,t){const r=e.arguments[t].expression,n=[];let o=!1;if("ArrowFunctionExpression"===r.type){const e=this.extractKeyFromSelector(r);e&&(n.push(e),o=!0)}else if("ArrayExpression"===r.type)for(const e of r.elements)e?.expression&&n.push(...this.expressionResolver.resolvePossibleKeyStringValues(e.expression));else n.push(...this.expressionResolver.resolvePossibleKeyStringValues(r));return{keysToProcess:n.filter(e=>!!e),isSelectorAPI:o}}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 r=t;const n=[];for(;"MemberExpression"===r.type;){const e=r.property;if("Identifier"===e.type)n.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;n.unshift(e.expression.value)}r=r.object}if(n.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return n.join(t)}return null}handlePluralKeys(t,r,n,o,i,s){try{const l=o?"ordinal":"cardinal",a=new Set;for(const e of this.config.locales)try{const t=new Intl.PluralRules(e,{type:l});t.resolvedOptions().pluralCategories.forEach(e=>a.add(e))}catch(e){const t=new Intl.PluralRules("en",{type:l});t.resolvedOptions().pluralCategories.forEach(e=>a.add(e))}const u=Array.from(a).sort(),p=this.config.extract.pluralSeparator??"_",c=e.getObjectPropValue(n,"defaultValue"),f=e.getObjectPropValue(n,`defaultValue${p}other`),y=e.getObjectPropValue(n,`defaultValue${p}ordinal${p}other`),g=e.getObjectProperty(n,"context"),h=[];if(g?.value){const e=this.expressionResolver.resolvePossibleContextStringValues(g.value);if(e.length>0)if("StringLiteral"===g.value.type)for(const r of e)r.length>0&&h.push({key:t,context:r});else{for(const r of e)r.length>0&&h.push({key:t,context:r});!1!==this.config.extract?.generateBasePluralForms&&h.push({key:t})}else h.push({key:t})}else h.push({key:t});const d=this.config.extract?.primaryLanguage||(Array.isArray(this.config.locales)?this.config.locales[0]:void 0)||"en";let x=!1;try{const e=new Intl.PluralRules(d,{type:l}).resolvedOptions().pluralCategories;1===e.length&&"other"===e[0]&&(x=!0)}catch{x=!1}if(x||1===u.length&&"other"===u[0]){for(const{key:t,context:l}of h){const a=e.getObjectPropValue(n,`defaultValue${p}other`);let u;u="string"==typeof a?a:"string"==typeof c?c:"string"==typeof i?i:l?`${t}_${l}`:t;const f=this.config.extract.contextSeparator??"_",y=l?`${t}${f}${l}`:t;this.pluginContext.addKey({key:y,ns:r,defaultValue:u,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(s||"string"==typeof a)})}return}for(const{key:t,context:l}of h)for(const a of u){const u=o?`defaultValue${p}ordinal${p}${a}`:`defaultValue${p}${a}`,g=e.getObjectPropValue(n,u);let h,d;if(h="string"==typeof g?g:"one"===a&&"string"==typeof c?c:"one"===a&&"string"==typeof i?i:o&&"string"==typeof y?y:o||"string"!=typeof f?"string"==typeof c?c:"string"==typeof i?i:t:f,l){const e=this.config.extract.contextSeparator??"_";d=o?`${t}${e}${l}${p}ordinal${p}${a}`:`${t}${e}${l}${p}${a}`}else d=o?`${t}${p}ordinal${p}${a}`:`${t}${p}${a}`;this.pluginContext.addKey({key:d,ns:r,defaultValue:h,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(s||"string"==typeof g||"string"==typeof f)})}}catch(o){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const s=i||e.getObjectPropValue(n,"defaultValue");this.pluginContext.addKey({key:t,ns:r,defaultValue:"string"==typeof s?s:t})}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let r=e;for(;"MemberExpression"===r.type;){if("Identifier"!==r.property.type)return null;t.unshift(r.property.value),r=r.object}if("ThisExpression"===r.type)t.unshift("this");else{if("Identifier"!==r.type)return null;t.unshift(r.value)}return t.join(".")}return null}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./jsx-parser.js"),t=require("./ast-utils.js");exports.JSXHandler=class{config;pluginContext;expressionResolver;constructor(e,t,n){this.config=e,this.pluginContext=t,this.expressionResolver=n}handleJSXElement(t,n){const s=this.getElementName(t);if(s&&(this.config.extract.transComponents||["Trans"]).includes(s)){const s=e.extractFromTransComponent(t,this.config),
|
|
1
|
+
"use strict";var e=require("./jsx-parser.js"),t=require("./ast-utils.js");exports.JSXHandler=class{config;pluginContext;expressionResolver;getCurrentFile;getCurrentCode;constructor(e,t,n,s,o){this.config=e,this.pluginContext=t,this.expressionResolver=n,this.getCurrentFile=s,this.getCurrentCode=o}getLocationFromSpan(e){if(!e||"number"!=typeof e.start)return;const t=this.getCurrentCode(),n=e.start,s=t.substring(0,n).split("\n");return{line:s.length,column:s[s.length-1].length}}handleJSXElement(t,n){const s=this.getElementName(t);if(s&&(this.config.extract.transComponents||["Trans"]).includes(s)){const s=e.extractFromTransComponent(t,this.config),o=[];if(s){if(s.keyExpression){const e=this.expressionResolver.resolvePossibleKeyStringValues(s.keyExpression);o.push(...e)}else o.push(s.serializedChildren);let e;const{contextExpression:i,optionsNode:a,defaultValue:l,hasCount:r,isOrdinal:u,serializedChildren:f}=s,c=t.span?this.getLocationFromSpan(t.span):void 0,d=c?[{file:this.getCurrentFile(),line:c.line,column:c.column}]:void 0;if(s.ns){const{ns:t}=s;e=o.map(e=>({key:e,ns:t,defaultValue:l||f,hasCount:r,isOrdinal:u,locations:d}))}else{e=o.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:l||f,hasCount:r,isOrdinal:u,explicitDefault:s.explicitDefault,locations:d}});const i=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===i?.type&&"JSXExpressionContainer"===i.value?.type&&"Identifier"===i.value.expression.type){const t=n(i.value.expression.value);t?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=t.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),i&&r)if(this.config.extract.disablePlurals){const t=this.expressionResolver.resolvePossibleContextStringValues(i),n=this.config.extract.contextSeparator??"_";if(t.length>0)if("StringLiteral"===i.type)for(const s of t)for(const t of e){const e=`${t.key}${n}${s}`;this.pluginContext.addKey({key:e,ns:t.ns,defaultValue:t.defaultValue,locations:t.locations})}else{e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})});for(const s of t)for(const t of e){const e=`${t.key}${n}${s}`;this.pluginContext.addKey({key:e,ns:t.ns,defaultValue:t.defaultValue,locations:t.locations})}}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else{const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n,o=this.expressionResolver.resolvePossibleContextStringValues(i),l=this.config.extract.contextSeparator??"_";if(o.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,a,void 0,e.locations));for(const t of o)for(const n of e){const e=`${n.key}${l}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,s,a,n.explicitDefault,n.locations)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,a,e.explicitDefault,e.locations))}else if(i){const t=this.expressionResolver.resolvePossibleContextStringValues(i),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const s of t)for(const{key:t,ns:o,defaultValue:i,locations:a}of e)this.pluginContext.addKey({key:`${t}${n}${s}`,ns:o,defaultValue:i,locations:a});"StringLiteral"!==i.type&&e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else if(r)if(this.config.extract.disablePlurals)e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})});else{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,a,e.explicitDefault,e.locations))}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}}}generatePluralKeysForTrans(e,n,s,o,i,a,l){try{const r=o?"ordinal":"cardinal",u=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:r}).resolvedOptions().pluralCategories,f=this.config.extract.pluralSeparator??"_";let c,d;if(i&&(c=t.getObjectPropValue(i,`defaultValue${f}other`),d=t.getObjectPropValue(i,`defaultValue${f}ordinal${f}other`)),1===u.length&&"other"===u[0]){const r=i?t.getObjectPropValue(i,`defaultValue${f}other`):void 0,u="string"==typeof r?r:"string"==typeof n?n:e;return void this.pluginContext.addKey({key:e,ns:s,defaultValue:u,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(a||"string"==typeof r||"string"==typeof c),locations:l})}for(const r of u){const u=o?`defaultValue${f}ordinal${f}${r}`:`defaultValue${f}${r}`,p=i?t.getObjectPropValue(i,u):void 0;let g;g="string"==typeof p?p:"one"===r&&"string"==typeof n?n:o&&"string"==typeof d?d:o||"string"!=typeof c?"string"==typeof n?n:e:c;const y=o?`${e}${f}ordinal${f}${r}`:`${e}${f}${r}`;this.pluginContext.addKey({key:y,ns:s,defaultValue:g,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(a||"string"==typeof p||"string"==typeof c),locations:l})}}catch(t){this.pluginContext.addKey({key:e,ns:s,defaultValue:n,locations:l})}}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(".")}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";exports.createPluginContext=function(t,e,a,n){return{addKey:e=>{const n=!1===e.ns?void 0:e.ns,s=n??a.extract?.defaultNS??"translation",l=void 0===n,
|
|
1
|
+
"use strict";exports.createPluginContext=function(t,e,a,n){return{addKey:e=>{const n=!1===e.ns?void 0:e.ns,s=n??a.extract?.defaultNS??"translation",l=void 0===n,o=`${String(s)}:${e.key}`,i=e.defaultValue??e.key,u=t.get(o);if(u){const n=u.defaultValue===u.key||u.hasCount&&u.defaultValue&&u.key.includes("_")&&u.key.startsWith(u.defaultValue),c=i===e.key;e.locations&&(u.locations=[...u.locations||[],...e.locations]),n&&!c&&t.set(o,{...e,ns:s||a.extract?.defaultNS||"translation",nsIsImplicit:l,defaultValue:i,locations:u.locations})}else t.set(o,{...e,ns:s||a.extract?.defaultNS||"translation",nsIsImplicit:l,defaultValue:i})},config:Object.freeze({...a,plugins:[...e]}),logger:n,getVarFromScope:()=>{}}},exports.initializePlugins=async function(t){for(const e of t)await(e.setup?.())};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("i18next-resources-for-ts"),t=require("glob"),r=require("ora"),s=require("chalk"),i=require("node:fs/promises"),n=require("node:path"),
|
|
1
|
+
"use strict";var e=require("i18next-resources-for-ts"),t=require("glob"),r=require("ora"),s=require("chalk"),i=require("node:fs/promises"),n=require("node:path"),a=require("./utils/file-utils.js");exports.runTypesGenerator=async function(o){const c=r("Generating TypeScript types for translations...\n").start();try{o.extract.primaryLanguage||=o.locales[0]||"en";let r=o.extract.output||`locales/${o.extract.primaryLanguage}/*.json`;if(r=a.getOutputPath(r,o.extract.primaryLanguage||"en","*"),o.types||(o.types={input:r,output:"src/@types/i18next.d.ts"}),void 0===o.types.input&&(o.types.input=r),o.types.output||(o.types.output="src/@types/i18next.d.ts"),o.types.resourcesFile||(o.types.resourcesFile=n.join(n.dirname(o.types?.output),"resources.d.ts")),!o.types?.input||o.types?.input.length<0)return void console.log("No input defined!");const u=await t.glob(o.types?.input||[],{cwd:process.cwd()}),p=[];for(const e of u){const t=n.basename(e,n.extname(e)),r=await i.readFile(e,"utf-8"),s=JSON.parse(r);p.push({name:t,resources:s})}const l=[],y=o.types?.enableSelector||!1,d=` // This file is automatically generated by i18next-cli. Do not edit manually.\n${e.mergeResourcesAsInterface(p,{optimize:!!y})}`,f=n.resolve(process.cwd(),o.types?.output||""),m=n.resolve(process.cwd(),o.types.resourcesFile);let g;await i.mkdir(n.dirname(m),{recursive:!0}),await i.writeFile(m,d),l.push(` ${s.green("✓")} Resources interface written to ${o.types.resourcesFile}`);try{await i.access(f),g=!0}catch(e){g=!1}if(!g){const e=`// This file is automatically generated by i18next-cli. Do not edit manually.\nimport Resources from './${n.relative(n.dirname(f),m).replace(/\\/g,"/").replace(/\.d\.ts$/,"")}';\n\ndeclare module 'i18next' {\n interface CustomTypeOptions {\n enableSelector: ${"string"==typeof y?`"${y}"`:y};\n defaultNS: '${o.extract.defaultNS||"translation"}';\n resources: Resources;\n }\n}`;await i.mkdir(n.dirname(f),{recursive:!0}),await i.writeFile(f,e),l.push(` ${s.green("✓")} TypeScript definitions written to ${o.types.output||""}`)}c.succeed(s.bold("TypeScript definitions generated successfully.")),l.forEach(e=>console.log(e))}catch(e){c.fail(s.red("Failed to generate TypeScript definitions.")),console.error(e)}};
|
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{minimatch as i}from"minimatch";import n from"chalk";import{ensureConfig as a,loadConfig as r}from"./config.js";import{detectConfig as c}from"./heuristic-config.js";import{runExtractor as s}from"./extractor/core/extractor.js";import"node:path";import"node:fs/promises";import"jiti";import{runTypesGenerator as l}from"./types-generator.js";import{runSyncer as p}from"./syncer.js";import{runMigrator as m}from"./migrator.js";import{runInit as f}from"./init.js";import{runLinterCli as d}from"./linter.js";import{runStatus as g}from"./status.js";import{runLocizeSync as u,runLocizeDownload as y,runLocizeMigrate as h}from"./locize.js";const w=new t;w.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.
|
|
2
|
+
import{Command as t}from"commander";import o from"chokidar";import{glob as e}from"glob";import{minimatch as i}from"minimatch";import n from"chalk";import{ensureConfig as a,loadConfig as r}from"./config.js";import{detectConfig as c}from"./heuristic-config.js";import{runExtractor as s}from"./extractor/core/extractor.js";import"node:path";import"node:fs/promises";import"jiti";import{runTypesGenerator as l}from"./types-generator.js";import{runSyncer as p}from"./syncer.js";import{runMigrator as m}from"./migrator.js";import{runInit as f}from"./init.js";import{runLinterCli as d}from"./linter.js";import{runStatus as g}from"./status.js";import{runLocizeSync as u,runLocizeDownload as y,runLocizeMigrate as h}from"./locize.js";const w=new t;w.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.22.1"),w.option("-c, --config <path>","Path to i18next-cli config file (overrides detection)"),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.").option("--sync-primary","Sync primary language values with default values from code.").action(async t=>{try{const e=w.opts().config,n=await a(e),r=async()=>{const o=await s(n,{isWatchMode:!!t.watch,isDryRun:!!t.dryRun,syncPrimaryWithDefaults:!!t.syncPrimary});return t.ci&&!o?(console.log("✅ No files were updated."),process.exit(0)):t.ci&&o&&(console.error("❌ Some files were updated. This should not happen in CI mode."),process.exit(1)),o};if(await r(),t.watch){console.log("\nWatching for changes...");const t=await z(n.extract.input),e=x(n.extract.ignore),a=j(n.extract.output),c=[...e,...a].filter(Boolean),s=t.filter(t=>!c.some(o=>i(t,o,{dot:!0})));o.watch(s,{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),r()})}}catch(t){console.error("Error running extractor:",t),process.exit(1)}}),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)=>{const e=w.opts().config;let i=await r(e);if(!i){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!")),i=t}await g(i,{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 e=w.opts().config,n=await a(e),r=()=>l(n);if(await r(),t.watch){console.log("\nWatching for changes...");const t=await z(n.types?.input||[]),e=[...x(n.extract?.ignore)].filter(Boolean),a=t.filter(t=>!e.some(o=>i(t,o,{dot:!0})));o.watch(a,{persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),r()})}}),w.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const t=w.opts().config,o=await a(t);await p(o)}),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(f),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 e=w.opts().config,a=async()=>{let t=await r(e);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 a(),t.watch){console.log("\nWatching for changes...");const t=await r(e);if(t?.extract?.input){const e=await z(t.extract.input),n=[...x(t.extract.ignore),...j(t.extract.output)].filter(Boolean),r=e.filter(t=>!n.some(o=>i(t,o,{dot:!0})));o.watch(r,{ignored:/node_modules/,persistent:!0}).on("change",t=>{console.log(`\nFile changed: ${t}`),a()})}}}),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=w.opts().config,e=await a(o);await u(e,t)}),w.command("locize-download").description("Download all translations from your locize project.").action(async t=>{const o=w.opts().config,e=await a(o);await y(e,t)}),w.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async t=>{const o=w.opts().config,e=await a(o);await h(e,t)}),w.parse(process.argv);const x=t=>Array.isArray(t)?t:t?[t]:[],j=t=>t&&"string"==typeof t?[t.replace(/\{\{[^}]+\}\}/g,"*")]:[],z=async(t=[])=>{const o=x(t),i=await Promise.all(o.map(t=>e(t||"",{nodir:!0})));return Array.from(new Set(i.flat()))};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ScopeManager as e}from"../parsers/scope-manager.js";import{ExpressionResolver as
|
|
1
|
+
import{ScopeManager as e}from"../parsers/scope-manager.js";import{ExpressionResolver as r}from"../parsers/expression-resolver.js";import{CallExpressionHandler as s}from"../parsers/call-expression-handler.js";import{JSXHandler as t}from"../parsers/jsx-handler.js";class o{pluginContext;config;logger;hooks;get objectKeys(){return this.callExpressionHandler.objectKeys}scopeManager;expressionResolver;callExpressionHandler;jsxHandler;currentFile="";currentCode="";constructor(o,a,i,n,l){this.pluginContext=a,this.config=o,this.logger=i,this.hooks={onBeforeVisitNode:n?.onBeforeVisitNode,onAfterVisitNode:n?.onAfterVisitNode,resolvePossibleKeyStringValues:n?.resolvePossibleKeyStringValues,resolvePossibleContextStringValues:n?.resolvePossibleContextStringValues},this.scopeManager=new e(o),this.expressionResolver=l??new r(this.hooks),this.callExpressionHandler=new s(o,a,i,this.expressionResolver,()=>this.getCurrentFile(),()=>this.getCurrentCode()),this.jsxHandler=new t(o,a,this.expressionResolver,()=>this.getCurrentFile(),()=>this.getCurrentCode())}visit(e){this.scopeManager.reset(),this.expressionResolver.resetFileSymbols(),this.scopeManager.enterScope(),this.walk(e),this.scopeManager.exitScope()}walk(e){if(!e)return;let r=!1;switch("Function"!==e.type&&"ArrowFunctionExpression"!==e.type&&"FunctionExpression"!==e.type||(this.scopeManager.enterScope(),r=!0),this.hooks.onBeforeVisitNode?.(e),e.type){case"VariableDeclarator":this.scopeManager.handleVariableDeclarator(e),this.expressionResolver.captureVariableDeclarator(e);break;case"TSEnumDeclaration":case"TsEnumDeclaration":case"TsEnumDecl":this.expressionResolver.captureEnumDeclaration(e);break;case"CallExpression":this.callExpressionHandler.handleCallExpression(e,this.scopeManager.getVarFromScope.bind(this.scopeManager));break;case"JSXElement":this.jsxHandler.handleJSXElement(e,this.scopeManager.getVarFromScope.bind(this.scopeManager))}this.hooks.onAfterVisitNode?.(e);for(const r in e){if("span"===r)continue;const s=e[r];if(Array.isArray(s)){for(const e of s)if(e&&"object"==typeof e)if("VariableDeclarator"!==e.type){if(e&&e.id&&Array.isArray(e.members)&&this.expressionResolver.captureEnumDeclaration(e),"VariableDeclaration"===e.type&&Array.isArray(e.declarations))for(const r of e.declarations)r&&"object"==typeof r&&"VariableDeclarator"===r.type&&(this.scopeManager.handleVariableDeclarator(r),this.expressionResolver.captureVariableDeclarator(r))}else this.scopeManager.handleVariableDeclarator(e),this.expressionResolver.captureVariableDeclarator(e);for(const e of s)e&&"object"==typeof e&&this.walk(e)}else s&&"object"==typeof s&&this.walk(s)}r&&this.scopeManager.exitScope()}getVarFromScope(e){return this.scopeManager.getVarFromScope(e)}setCurrentFile(e,r){this.currentFile=e,this.currentCode=r}getCurrentFile(){return this.currentFile}getCurrentCode(){return this.currentCode}}export{o as ASTVisitors};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"ora";import a from"chalk";import{parse as e}from"@swc/core";import{mkdir as o,writeFile as r,readFile as n}from"node:fs/promises";import{dirname as s,extname as i}from"node:path";import{findKeys as c}from"./key-finder.js";import{getTranslations as l}from"./translation-manager.js";import{validateExtractorConfig as m,ExtractorError as f}from"../../utils/validation.js";import{extractKeysFromComments as p}from"../parsers/comment-parser.js";import{ConsoleLogger as u}from"../../utils/logger.js";import{serializeTranslationFile as y}from"../../utils/file-utils.js";import{shouldShowFunnel as d,recordFunnelShown as g}from"../../utils/funnel-msg-tracker.js";async function w(e,{isWatchMode:n=!1,isDryRun:i=!1,syncPrimaryWithDefaults:f=!1}={},p=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"],m(e);const w=e.plugins||[],x=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:n}=await c(e,p);x.text=`Found ${t.size} unique keys. Updating translation files...`;const m=await l(t,n,e,{syncPrimaryWithDefaults:f});let u=!1;for(const t of m)if(t.updated&&(u=!0,!i)){const n=y(t.newTranslations,e.extract.outputFormat,e.extract.indentation);await o(s(t.path),{recursive:!0}),await r(t.path,n),p.info(a.green(`Updated: ${t.path}`))}if(w.length>0){x.text="Running post-extraction plugins...";for(const t of w)await(t.afterSync?.(m,e))}return x.succeed(a.bold("Extraction complete!")),u&&await async function(){if(!await d("extract"))return;return console.log(a.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: ${a.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${a.cyan("https://youtu.be/joPsZghT3wM")}`),g("extract")}(),u}catch(t){throw x.fail(a.red("Extraction failed.")),t}}async function x(t,a,o,r,s,c=new u){try{let l=await n(t,"utf-8");for(const e of a)try{const a=await(e.onLoad?.(l,t));void 0!==a&&(l=a)}catch(t){c.warn(`Plugin ${e.name} onLoad failed:`,t)}const m=i(t).toLowerCase(),u=".ts"===m||".tsx"===m||".mts"===m||".cts"===m,y=".tsx"===m;let d;try{d=await e(l,{syntax:u?"typescript":"ecmascript",tsx:y,decorators:!0,dynamicImport:!0,comments:!0})}catch(a){if(".ts"!==m||y)throw new f("Failed to process file",t,a);try{d=await e(l,{syntax:"typescript",tsx:!0,decorators:!0,dynamicImport:!0,comments:!0}),c.info?.(`Parsed ${t} using TSX fallback`)}catch(a){throw new f("Failed to process file",t,a)}}r.getVarFromScope=o.getVarFromScope.bind(o),o.visit(d),p(l,r,s,o.getVarFromScope.bind(o))}catch(a){throw new f("Failed to process file",t,a)}}async function h(t,{syncPrimaryWithDefaults:a=!1}={}){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(a=>a!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:e,objectKeys:o}=await c(t);return l(e,o,t,{syncPrimaryWithDefaults:a})}export{h as extract,x as processFile,w as runExtractor};
|
|
1
|
+
import t from"ora";import a from"chalk";import{parse as e}from"@swc/core";import{mkdir as o,writeFile as r,readFile as n}from"node:fs/promises";import{dirname as s,extname as i}from"node:path";import{findKeys as c}from"./key-finder.js";import{getTranslations as l}from"./translation-manager.js";import{validateExtractorConfig as m,ExtractorError as f}from"../../utils/validation.js";import{extractKeysFromComments as p}from"../parsers/comment-parser.js";import{ConsoleLogger as u}from"../../utils/logger.js";import{serializeTranslationFile as y}from"../../utils/file-utils.js";import{shouldShowFunnel as d,recordFunnelShown as g}from"../../utils/funnel-msg-tracker.js";async function w(e,{isWatchMode:n=!1,isDryRun:i=!1,syncPrimaryWithDefaults:f=!1}={},p=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"],m(e);const w=e.plugins||[],x=t("Running i18next key extractor...\n").start();try{const{allKeys:t,objectKeys:n}=await c(e,p);x.text=`Found ${t.size} unique keys. Updating translation files...`;const m=await l(t,n,e,{syncPrimaryWithDefaults:f});let u=!1;for(const t of m)if(t.updated&&(u=!0,!i)){const n=y(t.newTranslations,e.extract.outputFormat,e.extract.indentation);await o(s(t.path),{recursive:!0}),await r(t.path,n),p.info(a.green(`Updated: ${t.path}`))}if(w.length>0){x.text="Running post-extraction plugins...";for(const t of w)await(t.afterSync?.(m,e))}return x.succeed(a.bold("Extraction complete!")),u&&await async function(){if(!await d("extract"))return;return console.log(a.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: ${a.cyan("https://www.locize.com/blog/i18next-savemissing-ai-automation")}`),console.log(` Watch the video: ${a.cyan("https://youtu.be/joPsZghT3wM")}`),g("extract")}(),u}catch(t){throw x.fail(a.red("Extraction failed.")),t}}async function x(t,a,o,r,s,c=new u){try{let l=await n(t,"utf-8");for(const e of a)try{const a=await(e.onLoad?.(l,t));void 0!==a&&(l=a)}catch(t){c.warn(`Plugin ${e.name} onLoad failed:`,t)}const m=i(t).toLowerCase(),u=".ts"===m||".tsx"===m||".mts"===m||".cts"===m,y=".tsx"===m;let d;try{d=await e(l,{syntax:u?"typescript":"ecmascript",tsx:y,decorators:!0,dynamicImport:!0,comments:!0})}catch(a){if(".ts"!==m||y)throw new f("Failed to process file",t,a);try{d=await e(l,{syntax:"typescript",tsx:!0,decorators:!0,dynamicImport:!0,comments:!0}),c.info?.(`Parsed ${t} using TSX fallback`)}catch(a){throw new f("Failed to process file",t,a)}}r.getVarFromScope=o.getVarFromScope.bind(o),o.setCurrentFile(t,l),o.visit(d),p(l,r,s,o.getVarFromScope.bind(o))}catch(a){throw new f("Failed to process file",t,a)}}async function h(t,{syncPrimaryWithDefaults:a=!1}={}){t.extract.primaryLanguage||=t.locales[0]||"en",t.extract.secondaryLanguages||=t.locales.filter(a=>a!==t?.extract?.primaryLanguage),t.extract.functions||=["t","*.t"],t.extract.transComponents||=["Trans"];const{allKeys:e,objectKeys:o}=await c(t);return l(e,o,t,{syncPrimaryWithDefaults:a})}export{h as extract,x as processFile,w as runExtractor};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isSimpleTemplateLiteral as e,getObjectPropValue as t,getObjectProperty as r}from"./ast-utils.js";class n{pluginContext;config;logger;expressionResolver;objectKeys=new Set;constructor(e,t,r,n){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n}handleCallExpression(n,
|
|
1
|
+
import{isSimpleTemplateLiteral as e,getObjectPropValue as t,getObjectProperty as r}from"./ast-utils.js";class n{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;constructor(e,t,r,n,i,s){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n,this.getCurrentFile=i,this.getCurrentCode=s}getLocationFromSpan(e){if(!e||"number"!=typeof e.start)return;const t=this.getCurrentCode(),r=e.start,n=t.substring(0,r).split("\n");return{line:n.length,column:n[n.length-1].length}}handleCallExpression(n,i){const s=this.getFunctionName(n.callee);if(!s)return;const o=i(s),l=this.config.extract.functions||["t","*.t"];let a=void 0!==o;if(!a)for(const e of l)if(e.startsWith("*.")){if(s.endsWith(e.substring(1))){a=!0;break}}else if(e===s){a=!0;break}if(!a||0===n.arguments.length)return;const{keysToProcess:u,isSelectorAPI:f}=this.handleCallExpressionArgument(n,0);if(0===u.length)return;let p=!1;const c=this.config.extract.pluralSeparator??"_";for(let e=0;e<u.length;e++)u[e].endsWith(`${c}ordinal`)&&(p=!0,u[e]=u[e].slice(0,-8));let y,g;if(n.arguments.length>1){const t=n.arguments[1].expression;"ObjectExpression"===t.type?g=t:"StringLiteral"===t.type?y=t.value:"TemplateLiteral"===t.type&&e(t)&&(y=t.quasis[0].cooked)}if(n.arguments.length>2){const e=n.arguments[2].expression;"ObjectExpression"===e.type&&(g=e)}const h=g?t(g,"defaultValue"):void 0,d="string"==typeof h?h:y,x=e=>{if(!e||!Array.isArray(e.properties))return!1;for(const t of e.properties)if(t&&"KeyValueProperty"===t.type&&t.key){const e="Identifier"===t.key.type&&t.key.value||"StringLiteral"===t.key.type&&t.key.value;if("string"==typeof e&&e.startsWith("defaultValue"))return!0}return!1},k="string"==typeof d||x(g),v=x(g),$=Boolean(v||"string"==typeof d&&!("string"==typeof(m=d)&&/{{\s*count\s*}}/.test(m)));var m;for(let e=0;e<u.length;e++){let i,s=u[e];if(g){const e=t(g,"ns");"string"==typeof e&&(i=e)}const l=this.config.extract.nsSeparator??":";if(!i&&l&&s.includes(l)){const e=s.split(l);if(i=e.shift(),s=e.join(l),!s||""===s.trim()){this.logger.warn(`Skipping key that became empty after namespace removal: '${i}${l}'`);continue}}!i&&o?.defaultNs&&(i=o.defaultNs),i||(i=this.config.extract.defaultNS);let a=s;if(o?.keyPrefix){const e=this.config.extract.keySeparator??".";if(a=!1!==e?o.keyPrefix.endsWith(e)?`${o.keyPrefix}${s}`:`${o.keyPrefix}${e}${s}`:`${o.keyPrefix}${s}`,!1!==e){if(a.split(e).some(e=>""===e.trim())){this.logger.warn(`Skipping key with empty segments: '${a}' (keyPrefix: '${o.keyPrefix}', key: '${s}')`);continue}}}const c=e===u.length-1&&d||s;if(g){const e=r(g,"context"),n=[];if("StringLiteral"===e?.value?.type||"NumericLiteral"===e?.value.type||"BooleanLiteral"===e?.value.type){const t=`${e.value.value}`,r=this.config.extract.contextSeparator??"_";""!==t&&n.push({key:`${a}${r}${t}`,ns:i,defaultValue:c,explicitDefault:k})}else if(e?.value){const t=this.expressionResolver.resolvePossibleContextStringValues(e.value),r=this.config.extract.contextSeparator??"_";t.length>0&&(t.forEach(e=>{n.push({key:`${a}${r}${e}`,ns:i,defaultValue:c,explicitDefault:k})}),n.push({key:a,ns:i,defaultValue:c,explicitDefault:k}))}const s=e=>{if(e){if("KeyValueProperty"===e.type&&e.key){if("Identifier"===e.key.type)return e.key.value;if("StringLiteral"===e.key.type)return e.key.value}return"KeyValueProperty"===e.type&&e.value&&"Identifier"===e.value.type?e.key&&"Identifier"===e.key.type?e.key.value:void 0:"ShorthandProperty"!==e.type&&"Identifier"!==e.type||!e.value?e.key&&"string"==typeof e.key?e.key:void 0:e.value}},o=(()=>{if(!g||!Array.isArray(g.properties))return!1;for(const e of g.properties){if("count"===s(e))return!0}return!1})(),l=(()=>{if(!g||!Array.isArray(g.properties))return!1;for(const e of g.properties){if("ordinal"===s(e))return!("KeyValueProperty"!==e.type||!e.value||"BooleanLiteral"!==e.value.type)&&Boolean(e.value.value)}return!1})();if(o||p){try{const e=p?"ordinal":"cardinal",t=this.config.extract?.primaryLanguage||(Array.isArray(this.config.locales)?this.config.locales[0]:void 0)||"en";let r=!1;try{const n=new Intl.PluralRules(t,{type:e}).resolvedOptions().pluralCategories;1===n.length&&"other"===n[0]&&(r=!0)}catch{}if(!r){const t=new Set;for(const r of this.config.locales)try{new Intl.PluralRules(r,{type:e}).resolvedOptions().pluralCategories.forEach(e=>t.add(e))}catch{new Intl.PluralRules("en",{type:e}).resolvedOptions().pluralCategories.forEach(e=>t.add(e))}const n=Array.from(t).sort();1===n.length&&"other"===n[0]&&(r=!0)}if(r){if(n.length>0)for(const e of n)this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,hasCount:!0,isOrdinal:p});else this.pluginContext.addKey({key:a,ns:i,defaultValue:c,hasCount:!0,isOrdinal:p});continue}}catch(e){}this.config.extract.disablePlurals?n.length>0?n.forEach(this.pluginContext.addKey):this.pluginContext.addKey({key:a,ns:i,defaultValue:c,explicitDefault:k}):this.handlePluralKeys(a,i,g,l||p,d,$);continue}if(n.length>0){n.forEach(this.pluginContext.addKey);continue}!0===t(g,"returnObjects")&&this.objectKeys.add(a)}f&&this.objectKeys.add(a);{const e=n.span?this.getLocationFromSpan(n.span):void 0;this.pluginContext.addKey({key:a,ns:i,defaultValue:c,explicitDefault:k,locations:e?[{file:this.getCurrentFile(),line:e.line,column:e.column}]:void 0})}}}handleCallExpressionArgument(e,t){const r=e.arguments[t].expression,n=[];let i=!1;if("ArrowFunctionExpression"===r.type){const e=this.extractKeyFromSelector(r);e&&(n.push(e),i=!0)}else if("ArrayExpression"===r.type)for(const e of r.elements)e?.expression&&n.push(...this.expressionResolver.resolvePossibleKeyStringValues(e.expression));else n.push(...this.expressionResolver.resolvePossibleKeyStringValues(r));return{keysToProcess:n.filter(e=>!!e),isSelectorAPI:i}}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 r=t;const n=[];for(;"MemberExpression"===r.type;){const e=r.property;if("Identifier"===e.type)n.unshift(e.value);else{if("Computed"!==e.type||"StringLiteral"!==e.expression.type)return null;n.unshift(e.expression.value)}r=r.object}if(n.length>0){const e=this.config.extract.keySeparator,t="string"==typeof e?e:".";return n.join(t)}return null}handlePluralKeys(e,n,i,s,o,l){try{const a=s?"ordinal":"cardinal",u=new Set;for(const e of this.config.locales)try{const t=new Intl.PluralRules(e,{type:a});t.resolvedOptions().pluralCategories.forEach(e=>u.add(e))}catch(e){const t=new Intl.PluralRules("en",{type:a});t.resolvedOptions().pluralCategories.forEach(e=>u.add(e))}const f=Array.from(u).sort(),p=this.config.extract.pluralSeparator??"_",c=t(i,"defaultValue"),y=t(i,`defaultValue${p}other`),g=t(i,`defaultValue${p}ordinal${p}other`),h=r(i,"context"),d=[];if(h?.value){const t=this.expressionResolver.resolvePossibleContextStringValues(h.value);if(t.length>0)if("StringLiteral"===h.value.type)for(const r of t)r.length>0&&d.push({key:e,context:r});else{for(const r of t)r.length>0&&d.push({key:e,context:r});!1!==this.config.extract?.generateBasePluralForms&&d.push({key:e})}else d.push({key:e})}else d.push({key:e});const x=this.config.extract?.primaryLanguage||(Array.isArray(this.config.locales)?this.config.locales[0]:void 0)||"en";let k=!1;try{const e=new Intl.PluralRules(x,{type:a}).resolvedOptions().pluralCategories;1===e.length&&"other"===e[0]&&(k=!0)}catch{k=!1}if(k||1===f.length&&"other"===f[0]){for(const{key:e,context:r}of d){const a=t(i,`defaultValue${p}other`);let u;u="string"==typeof a?a:"string"==typeof c?c:"string"==typeof o?o:r?`${e}_${r}`:e;const f=this.config.extract.contextSeparator??"_",y=r?`${e}${f}${r}`:e;this.pluginContext.addKey({key:y,ns:n,defaultValue:u,hasCount:!0,isOrdinal:s,explicitDefault:Boolean(l||"string"==typeof a)})}return}for(const{key:e,context:r}of d)for(const a of f){const u=t(i,s?`defaultValue${p}ordinal${p}${a}`:`defaultValue${p}${a}`);let f,h;if(f="string"==typeof u?u:"one"===a&&"string"==typeof c?c:"one"===a&&"string"==typeof o?o:s&&"string"==typeof g?g:s||"string"!=typeof y?"string"==typeof c?c:"string"==typeof o?o:e:y,r){const t=this.config.extract.contextSeparator??"_";h=s?`${e}${t}${r}${p}ordinal${p}${a}`:`${e}${t}${r}${p}${a}`}else h=s?`${e}${p}ordinal${p}${a}`:`${e}${p}${a}`;this.pluginContext.addKey({key:h,ns:n,defaultValue:f,hasCount:!0,isOrdinal:s,explicitDefault:Boolean(l||"string"==typeof u||"string"==typeof y)})}}catch(r){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const s=o||t(i,"defaultValue");this.pluginContext.addKey({key:e,ns:n,defaultValue:"string"==typeof s?s:e})}}getFunctionName(e){if("Identifier"===e.type)return e.value;if("MemberExpression"===e.type){const t=[];let r=e;for(;"MemberExpression"===r.type;){if("Identifier"!==r.property.type)return null;t.unshift(r.property.value),r=r.object}if("ThisExpression"===r.type)t.unshift("this");else{if("Identifier"!==r.type)return null;t.unshift(r.value)}return t.join(".")}return null}}export{n as CallExpressionHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{extractFromTransComponent as e}from"./jsx-parser.js";import{getObjectPropValue as t}from"./ast-utils.js";class n{config;pluginContext;expressionResolver;constructor(e,t,n){this.config=e,this.pluginContext=t,this.expressionResolver=n}handleJSXElement(t,n){const s=this.getElementName(t);if(s&&(this.config.extract.transComponents||["Trans"]).includes(s)){const s=e(t,this.config),
|
|
1
|
+
import{extractFromTransComponent as e}from"./jsx-parser.js";import{getObjectPropValue as t}from"./ast-utils.js";class n{config;pluginContext;expressionResolver;getCurrentFile;getCurrentCode;constructor(e,t,n,s,o){this.config=e,this.pluginContext=t,this.expressionResolver=n,this.getCurrentFile=s,this.getCurrentCode=o}getLocationFromSpan(e){if(!e||"number"!=typeof e.start)return;const t=this.getCurrentCode(),n=e.start,s=t.substring(0,n).split("\n");return{line:s.length,column:s[s.length-1].length}}handleJSXElement(t,n){const s=this.getElementName(t);if(s&&(this.config.extract.transComponents||["Trans"]).includes(s)){const s=e(t,this.config),o=[];if(s){if(s.keyExpression){const e=this.expressionResolver.resolvePossibleKeyStringValues(s.keyExpression);o.push(...e)}else o.push(s.serializedChildren);let e;const{contextExpression:i,optionsNode:a,defaultValue:l,hasCount:r,isOrdinal:u,serializedChildren:f}=s,c=t.span?this.getLocationFromSpan(t.span):void 0,d=c?[{file:this.getCurrentFile(),line:c.line,column:c.column}]:void 0;if(s.ns){const{ns:t}=s;e=o.map(e=>({key:e,ns:t,defaultValue:l||f,hasCount:r,isOrdinal:u,locations:d}))}else{e=o.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:l||f,hasCount:r,isOrdinal:u,explicitDefault:s.explicitDefault,locations:d}});const i=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"t"===e.name.value);if("JSXAttribute"===i?.type&&"JSXExpressionContainer"===i.value?.type&&"Identifier"===i.value.expression.type){const t=n(i.value.expression.value);t?.defaultNs&&e.forEach(e=>{e.ns||(e.ns=t.defaultNs)})}}if(e.forEach(e=>{e.ns||(e.ns=this.config.extract.defaultNS)}),i&&r)if(this.config.extract.disablePlurals){const t=this.expressionResolver.resolvePossibleContextStringValues(i),n=this.config.extract.contextSeparator??"_";if(t.length>0)if("StringLiteral"===i.type)for(const s of t)for(const t of e){const e=`${t.key}${n}${s}`;this.pluginContext.addKey({key:e,ns:t.ns,defaultValue:t.defaultValue,locations:t.locations})}else{e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})});for(const s of t)for(const t of e){const e=`${t.key}${n}${s}`;this.pluginContext.addKey({key:e,ns:t.ns,defaultValue:t.defaultValue,locations:t.locations})}}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else{const n=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),s=!!n,o=this.expressionResolver.resolvePossibleContextStringValues(i),l=this.config.extract.contextSeparator??"_";if(o.length>0){e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,a,void 0,e.locations));for(const t of o)for(const n of e){const e=`${n.key}${l}${t}`;this.generatePluralKeysForTrans(e,n.defaultValue,n.ns,s,a,n.explicitDefault,n.locations)}}else e.forEach(e=>this.generatePluralKeysForTrans(e.key,e.defaultValue,e.ns,s,a,e.explicitDefault,e.locations))}else if(i){const t=this.expressionResolver.resolvePossibleContextStringValues(i),n=this.config.extract.contextSeparator??"_";if(t.length>0){for(const s of t)for(const{key:t,ns:o,defaultValue:i,locations:a}of e)this.pluginContext.addKey({key:`${t}${n}${s}`,ns:o,defaultValue:i,locations:a});"StringLiteral"!==i.type&&e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}else if(r)if(this.config.extract.disablePlurals)e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})});else{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,a,e.explicitDefault,e.locations))}else e.forEach(e=>{this.pluginContext.addKey({key:e.key,ns:e.ns,defaultValue:e.defaultValue,locations:e.locations})})}}}generatePluralKeysForTrans(e,n,s,o,i,a,l){try{const r=o?"ordinal":"cardinal",u=new Intl.PluralRules(this.config.extract?.primaryLanguage,{type:r}).resolvedOptions().pluralCategories,f=this.config.extract.pluralSeparator??"_";let c,d;if(i&&(c=t(i,`defaultValue${f}other`),d=t(i,`defaultValue${f}ordinal${f}other`)),1===u.length&&"other"===u[0]){const r=i?t(i,`defaultValue${f}other`):void 0,u="string"==typeof r?r:"string"==typeof n?n:e;return void this.pluginContext.addKey({key:e,ns:s,defaultValue:u,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(a||"string"==typeof r||"string"==typeof c),locations:l})}for(const r of u){const u=i?t(i,o?`defaultValue${f}ordinal${f}${r}`:`defaultValue${f}${r}`):void 0;let p;p="string"==typeof u?u:"one"===r&&"string"==typeof n?n:o&&"string"==typeof d?d:o||"string"!=typeof c?"string"==typeof n?n:e:c;const y=o?`${e}${f}ordinal${f}${r}`:`${e}${f}${r}`;this.pluginContext.addKey({key:y,ns:s,defaultValue:p,hasCount:!0,isOrdinal:o,explicitDefault:Boolean(a||"string"==typeof u||"string"==typeof c),locations:l})}}catch(t){this.pluginContext.addKey({key:e,ns:s,defaultValue:n,locations:l})}}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(".")}}}export{n as JSXHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
async function t(t){for(const e of t)await(e.setup?.())}function e(t,e,a,n){return{addKey:e=>{const n=!1===e.ns?void 0:e.ns,l=n??a.extract?.defaultNS??"translation",
|
|
1
|
+
async function t(t){for(const e of t)await(e.setup?.())}function e(t,e,a,n){return{addKey:e=>{const n=!1===e.ns?void 0:e.ns,l=n??a.extract?.defaultNS??"translation",o=void 0===n,s=`${String(l)}:${e.key}`,i=e.defaultValue??e.key,u=t.get(s);if(u){const n=u.defaultValue===u.key||u.hasCount&&u.defaultValue&&u.key.includes("_")&&u.key.startsWith(u.defaultValue),c=i===e.key;e.locations&&(u.locations=[...u.locations||[],...e.locations]),n&&!c&&t.set(s,{...e,ns:l||a.extract?.defaultNS||"translation",nsIsImplicit:o,defaultValue:i,locations:u.locations})}else t.set(s,{...e,ns:l||a.extract?.defaultNS||"translation",nsIsImplicit:o,defaultValue:i})},config:Object.freeze({...a,plugins:[...e]}),logger:n,getVarFromScope:()=>{}}}export{e as createPluginContext,t as initializePlugins};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mergeResourcesAsInterface as e}from"i18next-resources-for-ts";import{glob as t}from"glob";import s from"ora";import r from"chalk";import{readFile as o,mkdir as i,writeFile as n,access as
|
|
1
|
+
import{mergeResourcesAsInterface as e}from"i18next-resources-for-ts";import{glob as t}from"glob";import s from"ora";import r from"chalk";import{readFile as o,mkdir as i,writeFile as n,access as a}from"node:fs/promises";import{join as p,dirname as c,basename as u,extname as l,resolve as y,relative as f}from"node:path";import{getOutputPath as d}from"./utils/file-utils.js";async function m(m){const g=s("Generating TypeScript types for translations...\n").start();try{m.extract.primaryLanguage||=m.locales[0]||"en";let s=m.extract.output||`locales/${m.extract.primaryLanguage}/*.json`;if(s=d(s,m.extract.primaryLanguage||"en","*"),m.types||(m.types={input:s,output:"src/@types/i18next.d.ts"}),void 0===m.types.input&&(m.types.input=s),m.types.output||(m.types.output="src/@types/i18next.d.ts"),m.types.resourcesFile||(m.types.resourcesFile=p(c(m.types?.output),"resources.d.ts")),!m.types?.input||m.types?.input.length<0)return void console.log("No input defined!");const w=await t(m.types?.input||[],{cwd:process.cwd()}),x=[];for(const e of w){const t=u(e,l(e)),s=await o(e,"utf-8"),r=JSON.parse(s);x.push({name:t,resources:r})}const h=[],$=m.types?.enableSelector||!1,S=` // This file is automatically generated by i18next-cli. Do not edit manually.\n${e(x,{optimize:!!$})}`,T=y(process.cwd(),m.types?.output||""),b=y(process.cwd(),m.types.resourcesFile);let F;await i(c(b),{recursive:!0}),await n(b,S),h.push(` ${r.green("✓")} Resources interface written to ${m.types.resourcesFile}`);try{await a(T),F=!0}catch(e){F=!1}if(!F){const e=`// This file is automatically generated by i18next-cli. Do not edit manually.\nimport Resources from './${f(c(T),b).replace(/\\/g,"/").replace(/\.d\.ts$/,"")}';\n\ndeclare module 'i18next' {\n interface CustomTypeOptions {\n enableSelector: ${"string"==typeof $?`"${$}"`:$};\n defaultNS: '${m.extract.defaultNS||"translation"}';\n resources: Resources;\n }\n}`;await i(c(T),{recursive:!0}),await n(T,e),h.push(` ${r.green("✓")} TypeScript definitions written to ${m.types.output||""}`)}g.succeed(r.bold("TypeScript definitions generated successfully.")),h.forEach(e=>console.log(e))}catch(e){g.fail(r.red("Failed to generate TypeScript definitions.")),console.error(e)}}export{m as runTypesGenerator};
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -22,7 +22,7 @@ const program = new Command()
|
|
|
22
22
|
program
|
|
23
23
|
.name('i18next-cli')
|
|
24
24
|
.description('A unified, high-performance i18next CLI.')
|
|
25
|
-
.version('1.
|
|
25
|
+
.version('1.22.1')
|
|
26
26
|
|
|
27
27
|
// new: global config override option
|
|
28
28
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)')
|
|
@@ -41,6 +41,8 @@ export class ASTVisitors {
|
|
|
41
41
|
private readonly expressionResolver: ExpressionResolver
|
|
42
42
|
private readonly callExpressionHandler: CallExpressionHandler
|
|
43
43
|
private readonly jsxHandler: JSXHandler
|
|
44
|
+
private currentFile: string = ''
|
|
45
|
+
private currentCode: string = ''
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Creates a new AST visitor instance.
|
|
@@ -69,8 +71,21 @@ export class ASTVisitors {
|
|
|
69
71
|
this.scopeManager = new ScopeManager(config)
|
|
70
72
|
// use shared resolver when provided so captured enums/objects are visible across files
|
|
71
73
|
this.expressionResolver = expressionResolver ?? new ExpressionResolver(this.hooks)
|
|
72
|
-
this.callExpressionHandler = new CallExpressionHandler(
|
|
73
|
-
|
|
74
|
+
this.callExpressionHandler = new CallExpressionHandler(
|
|
75
|
+
config,
|
|
76
|
+
pluginContext,
|
|
77
|
+
logger,
|
|
78
|
+
this.expressionResolver,
|
|
79
|
+
() => this.getCurrentFile(),
|
|
80
|
+
() => this.getCurrentCode()
|
|
81
|
+
)
|
|
82
|
+
this.jsxHandler = new JSXHandler(
|
|
83
|
+
config,
|
|
84
|
+
pluginContext,
|
|
85
|
+
this.expressionResolver,
|
|
86
|
+
() => this.getCurrentFile(),
|
|
87
|
+
() => this.getCurrentCode()
|
|
88
|
+
)
|
|
74
89
|
}
|
|
75
90
|
|
|
76
91
|
/**
|
|
@@ -211,4 +226,35 @@ export class ASTVisitors {
|
|
|
211
226
|
public getVarFromScope (name: string): ScopeInfo | undefined {
|
|
212
227
|
return this.scopeManager.getVarFromScope(name)
|
|
213
228
|
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Sets the current file path used by the extractor.
|
|
232
|
+
*
|
|
233
|
+
* @param file - The file path (absolute or relative) to set as the current processing context.
|
|
234
|
+
* @remarks
|
|
235
|
+
* Updating the current file allows subsequent AST visitors and extraction logic to
|
|
236
|
+
* associate nodes, messages, and errors with the correct source file.
|
|
237
|
+
*/
|
|
238
|
+
public setCurrentFile (file: string, code: string): void {
|
|
239
|
+
this.currentFile = file
|
|
240
|
+
this.currentCode = code
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Returns the currently set file path.
|
|
245
|
+
*
|
|
246
|
+
* @returns The current file path as a string, or `undefined` if no file has been set.
|
|
247
|
+
* @remarks
|
|
248
|
+
* Use this to retrieve the file context that was previously set via `setCurrentFile`.
|
|
249
|
+
*/
|
|
250
|
+
public getCurrentFile (): string {
|
|
251
|
+
return this.currentFile
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @returns The full source code string for the file currently under processing.
|
|
256
|
+
*/
|
|
257
|
+
public getCurrentCode (): string {
|
|
258
|
+
return this.currentCode
|
|
259
|
+
}
|
|
214
260
|
}
|
|
@@ -194,6 +194,9 @@ export async function processFile (
|
|
|
194
194
|
// This avoids a circular dependency while giving plugins access to the scope.
|
|
195
195
|
pluginContext.getVarFromScope = astVisitors.getVarFromScope.bind(astVisitors)
|
|
196
196
|
|
|
197
|
+
// Pass BOTH file and code
|
|
198
|
+
astVisitors.setCurrentFile(file, code)
|
|
199
|
+
|
|
197
200
|
// 3. FIRST: Visit the AST to build scope information
|
|
198
201
|
astVisitors.visit(ast)
|
|
199
202
|
|
|
@@ -9,17 +9,43 @@ export class CallExpressionHandler {
|
|
|
9
9
|
private logger: Logger
|
|
10
10
|
private expressionResolver: ExpressionResolver
|
|
11
11
|
public objectKeys = new Set<string>()
|
|
12
|
+
private getCurrentFile: () => string
|
|
13
|
+
private getCurrentCode: () => string
|
|
12
14
|
|
|
13
15
|
constructor (
|
|
14
16
|
config: Omit<I18nextToolkitConfig, 'plugins'>,
|
|
15
17
|
pluginContext: PluginContext,
|
|
16
18
|
logger: Logger,
|
|
17
|
-
expressionResolver: ExpressionResolver
|
|
19
|
+
expressionResolver: ExpressionResolver,
|
|
20
|
+
getCurrentFile: () => string,
|
|
21
|
+
getCurrentCode: () => string
|
|
18
22
|
) {
|
|
19
23
|
this.config = config
|
|
20
24
|
this.pluginContext = pluginContext
|
|
21
25
|
this.logger = logger
|
|
22
26
|
this.expressionResolver = expressionResolver
|
|
27
|
+
this.getCurrentFile = getCurrentFile
|
|
28
|
+
this.getCurrentCode = getCurrentCode
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper method to calculate line and column from byte offset.
|
|
33
|
+
* SWC provides byte offsets in span.start, not line/column directly.
|
|
34
|
+
*/
|
|
35
|
+
private getLocationFromSpan (span: any): { line: number, column: number } | undefined {
|
|
36
|
+
if (!span || typeof span.start !== 'number') return undefined
|
|
37
|
+
|
|
38
|
+
const code = this.getCurrentCode()
|
|
39
|
+
const offset = span.start
|
|
40
|
+
|
|
41
|
+
// Calculate line and column from byte offset
|
|
42
|
+
const upToOffset = code.substring(0, offset)
|
|
43
|
+
const lines = upToOffset.split('\n')
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
line: lines.length,
|
|
47
|
+
column: lines[lines.length - 1].length
|
|
48
|
+
}
|
|
23
49
|
}
|
|
24
50
|
|
|
25
51
|
/**
|
|
@@ -363,7 +389,24 @@ export class CallExpressionHandler {
|
|
|
363
389
|
}
|
|
364
390
|
|
|
365
391
|
// 5. Default case: Add the simple key
|
|
366
|
-
|
|
392
|
+
{
|
|
393
|
+
// ✅ Use the helper method to calculate proper line/column
|
|
394
|
+
const location = node.span ? this.getLocationFromSpan(node.span) : undefined
|
|
395
|
+
|
|
396
|
+
this.pluginContext.addKey({
|
|
397
|
+
key: finalKey,
|
|
398
|
+
ns,
|
|
399
|
+
defaultValue: dv,
|
|
400
|
+
explicitDefault: explicitDefaultForBase,
|
|
401
|
+
locations: location
|
|
402
|
+
? [{
|
|
403
|
+
file: this.getCurrentFile(),
|
|
404
|
+
line: location.line,
|
|
405
|
+
column: location.column
|
|
406
|
+
}]
|
|
407
|
+
: undefined
|
|
408
|
+
})
|
|
409
|
+
}
|
|
367
410
|
}
|
|
368
411
|
}
|
|
369
412
|
|
|
@@ -8,15 +8,39 @@ export class JSXHandler {
|
|
|
8
8
|
private config: Omit<I18nextToolkitConfig, 'plugins'>
|
|
9
9
|
private pluginContext: PluginContext
|
|
10
10
|
private expressionResolver: ExpressionResolver
|
|
11
|
+
private getCurrentFile: () => string
|
|
12
|
+
private getCurrentCode: () => string // ✅ Add this
|
|
11
13
|
|
|
12
14
|
constructor (
|
|
13
15
|
config: Omit<I18nextToolkitConfig, 'plugins'>,
|
|
14
16
|
pluginContext: PluginContext,
|
|
15
|
-
expressionResolver: ExpressionResolver
|
|
17
|
+
expressionResolver: ExpressionResolver,
|
|
18
|
+
getCurrentFile: () => string,
|
|
19
|
+
getCurrentCode: () => string // ✅ Add parameter
|
|
16
20
|
) {
|
|
17
21
|
this.config = config
|
|
18
22
|
this.pluginContext = pluginContext
|
|
19
23
|
this.expressionResolver = expressionResolver
|
|
24
|
+
this.getCurrentFile = getCurrentFile
|
|
25
|
+
this.getCurrentCode = getCurrentCode // ✅ Store it
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Helper method to calculate line and column from byte offset.
|
|
30
|
+
*/
|
|
31
|
+
private getLocationFromSpan (span: any): { line: number, column: number } | undefined {
|
|
32
|
+
if (!span || typeof span.start !== 'number') return undefined
|
|
33
|
+
|
|
34
|
+
const code = this.getCurrentCode()
|
|
35
|
+
const offset = span.start
|
|
36
|
+
|
|
37
|
+
const upToOffset = code.substring(0, offset)
|
|
38
|
+
const lines = upToOffset.split('\n')
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
line: lines.length,
|
|
42
|
+
column: lines[lines.length - 1].length
|
|
43
|
+
}
|
|
20
44
|
}
|
|
21
45
|
|
|
22
46
|
/**
|
|
@@ -48,6 +72,16 @@ export class JSXHandler {
|
|
|
48
72
|
|
|
49
73
|
const { contextExpression, optionsNode, defaultValue, hasCount, isOrdinal, serializedChildren } = extractedAttributes
|
|
50
74
|
|
|
75
|
+
// ✅ Extract location information using the helper method
|
|
76
|
+
const location = node.span ? this.getLocationFromSpan(node.span) : undefined
|
|
77
|
+
const locations = location
|
|
78
|
+
? [{
|
|
79
|
+
file: this.getCurrentFile(),
|
|
80
|
+
line: location.line,
|
|
81
|
+
column: location.column
|
|
82
|
+
}]
|
|
83
|
+
: undefined
|
|
84
|
+
|
|
51
85
|
// If ns is not explicitly set on the component, try to find it from the key
|
|
52
86
|
// or the `t` prop
|
|
53
87
|
if (!extractedAttributes.ns) {
|
|
@@ -71,6 +105,7 @@ export class JSXHandler {
|
|
|
71
105
|
hasCount,
|
|
72
106
|
isOrdinal,
|
|
73
107
|
explicitDefault: extractedAttributes.explicitDefault,
|
|
108
|
+
locations
|
|
74
109
|
}
|
|
75
110
|
})
|
|
76
111
|
|
|
@@ -106,6 +141,7 @@ export class JSXHandler {
|
|
|
106
141
|
defaultValue: defaultValue || serializedChildren,
|
|
107
142
|
hasCount,
|
|
108
143
|
isOrdinal,
|
|
144
|
+
locations
|
|
109
145
|
}
|
|
110
146
|
})
|
|
111
147
|
}
|
|
@@ -133,7 +169,12 @@ export class JSXHandler {
|
|
|
133
169
|
for (const context of contextValues) {
|
|
134
170
|
for (const extractedKey of extractedKeys) {
|
|
135
171
|
const contextKey = `${extractedKey.key}${contextSeparator}${context}`
|
|
136
|
-
this.pluginContext.addKey({
|
|
172
|
+
this.pluginContext.addKey({
|
|
173
|
+
key: contextKey,
|
|
174
|
+
ns: extractedKey.ns,
|
|
175
|
+
defaultValue: extractedKey.defaultValue,
|
|
176
|
+
locations: extractedKey.locations
|
|
177
|
+
})
|
|
137
178
|
}
|
|
138
179
|
}
|
|
139
180
|
} else {
|
|
@@ -142,13 +183,19 @@ export class JSXHandler {
|
|
|
142
183
|
this.pluginContext.addKey({
|
|
143
184
|
key: extractedKey.key,
|
|
144
185
|
ns: extractedKey.ns,
|
|
145
|
-
defaultValue: extractedKey.defaultValue
|
|
186
|
+
defaultValue: extractedKey.defaultValue,
|
|
187
|
+
locations: extractedKey.locations
|
|
146
188
|
})
|
|
147
189
|
})
|
|
148
190
|
for (const context of contextValues) {
|
|
149
191
|
for (const extractedKey of extractedKeys) {
|
|
150
192
|
const contextKey = `${extractedKey.key}${contextSeparator}${context}`
|
|
151
|
-
this.pluginContext.addKey({
|
|
193
|
+
this.pluginContext.addKey({
|
|
194
|
+
key: contextKey,
|
|
195
|
+
ns: extractedKey.ns,
|
|
196
|
+
defaultValue: extractedKey.defaultValue,
|
|
197
|
+
locations: extractedKey.locations
|
|
198
|
+
})
|
|
152
199
|
}
|
|
153
200
|
}
|
|
154
201
|
}
|
|
@@ -158,7 +205,8 @@ export class JSXHandler {
|
|
|
158
205
|
this.pluginContext.addKey({
|
|
159
206
|
key: extractedKey.key,
|
|
160
207
|
ns: extractedKey.ns,
|
|
161
|
-
defaultValue: extractedKey.defaultValue
|
|
208
|
+
defaultValue: extractedKey.defaultValue,
|
|
209
|
+
locations: extractedKey.locations
|
|
162
210
|
})
|
|
163
211
|
})
|
|
164
212
|
}
|
|
@@ -179,18 +227,18 @@ export class JSXHandler {
|
|
|
179
227
|
// Generate all combinations of context and plural forms
|
|
180
228
|
if (contextValues.length > 0) {
|
|
181
229
|
// Generate base plural forms (no context)
|
|
182
|
-
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode))
|
|
230
|
+
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, undefined, extractedKey.locations))
|
|
183
231
|
|
|
184
232
|
// Generate context + plural combinations
|
|
185
233
|
for (const context of contextValues) {
|
|
186
234
|
for (const extractedKey of extractedKeys) {
|
|
187
235
|
const contextKey = `${extractedKey.key}${contextSeparator}${context}`
|
|
188
|
-
this.generatePluralKeysForTrans(contextKey, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault)
|
|
236
|
+
this.generatePluralKeysForTrans(contextKey, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault, extractedKey.locations)
|
|
189
237
|
}
|
|
190
238
|
}
|
|
191
239
|
} else {
|
|
192
240
|
// Fallback to just plural forms if context resolution fails
|
|
193
|
-
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault))
|
|
241
|
+
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault, extractedKey.locations))
|
|
194
242
|
}
|
|
195
243
|
}
|
|
196
244
|
} else if (contextExpression) {
|
|
@@ -200,8 +248,13 @@ export class JSXHandler {
|
|
|
200
248
|
if (contextValues.length > 0) {
|
|
201
249
|
// Add context variants
|
|
202
250
|
for (const context of contextValues) {
|
|
203
|
-
for (const { key, ns, defaultValue } of extractedKeys) {
|
|
204
|
-
this.pluginContext.addKey({
|
|
251
|
+
for (const { key, ns, defaultValue, locations } of extractedKeys) {
|
|
252
|
+
this.pluginContext.addKey({
|
|
253
|
+
key: `${key}${contextSeparator}${context}`,
|
|
254
|
+
ns,
|
|
255
|
+
defaultValue,
|
|
256
|
+
locations
|
|
257
|
+
})
|
|
205
258
|
}
|
|
206
259
|
}
|
|
207
260
|
// Only add the base key as a fallback if the context is dynamic (i.e., not a simple string).
|
|
@@ -210,7 +263,8 @@ export class JSXHandler {
|
|
|
210
263
|
this.pluginContext.addKey({
|
|
211
264
|
key: extractedKey.key,
|
|
212
265
|
ns: extractedKey.ns,
|
|
213
|
-
defaultValue: extractedKey.defaultValue
|
|
266
|
+
defaultValue: extractedKey.defaultValue,
|
|
267
|
+
locations: extractedKey.locations
|
|
214
268
|
})
|
|
215
269
|
})
|
|
216
270
|
}
|
|
@@ -220,7 +274,8 @@ export class JSXHandler {
|
|
|
220
274
|
this.pluginContext.addKey({
|
|
221
275
|
key: extractedKey.key,
|
|
222
276
|
ns: extractedKey.ns,
|
|
223
|
-
defaultValue: extractedKey.defaultValue
|
|
277
|
+
defaultValue: extractedKey.defaultValue,
|
|
278
|
+
locations: extractedKey.locations
|
|
224
279
|
})
|
|
225
280
|
})
|
|
226
281
|
}
|
|
@@ -232,7 +287,8 @@ export class JSXHandler {
|
|
|
232
287
|
this.pluginContext.addKey({
|
|
233
288
|
key: extractedKey.key,
|
|
234
289
|
ns: extractedKey.ns,
|
|
235
|
-
defaultValue: extractedKey.defaultValue
|
|
290
|
+
defaultValue: extractedKey.defaultValue,
|
|
291
|
+
locations: extractedKey.locations
|
|
236
292
|
})
|
|
237
293
|
})
|
|
238
294
|
} else {
|
|
@@ -246,7 +302,7 @@ export class JSXHandler {
|
|
|
246
302
|
)
|
|
247
303
|
const isOrdinal = !!ordinalAttr
|
|
248
304
|
|
|
249
|
-
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault))
|
|
305
|
+
extractedKeys.forEach(extractedKey => this.generatePluralKeysForTrans(extractedKey.key, extractedKey.defaultValue, extractedKey.ns, isOrdinal, optionsNode, extractedKey.explicitDefault, extractedKey.locations))
|
|
250
306
|
}
|
|
251
307
|
} else {
|
|
252
308
|
// No count or context - just add the base keys
|
|
@@ -254,7 +310,8 @@ export class JSXHandler {
|
|
|
254
310
|
this.pluginContext.addKey({
|
|
255
311
|
key: extractedKey.key,
|
|
256
312
|
ns: extractedKey.ns,
|
|
257
|
-
defaultValue: extractedKey.defaultValue
|
|
313
|
+
defaultValue: extractedKey.defaultValue,
|
|
314
|
+
locations: extractedKey.locations
|
|
258
315
|
})
|
|
259
316
|
})
|
|
260
317
|
}
|
|
@@ -270,8 +327,18 @@ export class JSXHandler {
|
|
|
270
327
|
* @param ns - Namespace for the keys
|
|
271
328
|
* @param isOrdinal - Whether to generate ordinal plural forms
|
|
272
329
|
* @param optionsNode - Optional tOptions object expression for plural-specific defaults
|
|
330
|
+
* @param explicitDefaultFromSource - Whether the default was explicitly provided in source
|
|
331
|
+
* @param locations - Source location information for this key
|
|
273
332
|
*/
|
|
274
|
-
private generatePluralKeysForTrans (
|
|
333
|
+
private generatePluralKeysForTrans (
|
|
334
|
+
key: string,
|
|
335
|
+
defaultValue: string | undefined,
|
|
336
|
+
ns: string | false | undefined,
|
|
337
|
+
isOrdinal: boolean,
|
|
338
|
+
optionsNode?: ObjectExpression,
|
|
339
|
+
explicitDefaultFromSource?: boolean,
|
|
340
|
+
locations?: Array<{ file: string, line?: number, column?: number }>
|
|
341
|
+
): void {
|
|
275
342
|
try {
|
|
276
343
|
const type = isOrdinal ? 'ordinal' : 'cardinal'
|
|
277
344
|
const pluralCategories = new Intl.PluralRules(this.config.extract?.primaryLanguage, { type }).resolvedOptions().pluralCategories
|
|
@@ -299,7 +366,8 @@ export class JSXHandler {
|
|
|
299
366
|
defaultValue: finalDefault,
|
|
300
367
|
hasCount: true,
|
|
301
368
|
isOrdinal,
|
|
302
|
-
explicitDefault: Boolean(explicitDefaultFromSource || typeof specificDefault === 'string' || typeof otherDefault === 'string')
|
|
369
|
+
explicitDefault: Boolean(explicitDefaultFromSource || typeof specificDefault === 'string' || typeof otherDefault === 'string'),
|
|
370
|
+
locations
|
|
303
371
|
})
|
|
304
372
|
return
|
|
305
373
|
}
|
|
@@ -344,12 +412,18 @@ export class JSXHandler {
|
|
|
344
412
|
// Only treat plural/context variant as explicit when:
|
|
345
413
|
// - the extractor indicated the default was explicit on the source element
|
|
346
414
|
// - OR a plural-specific default was provided in tOptions (specificDefault/otherDefault)
|
|
347
|
-
explicitDefault: Boolean(explicitDefaultFromSource || typeof specificDefault === 'string' || typeof otherDefault === 'string')
|
|
415
|
+
explicitDefault: Boolean(explicitDefaultFromSource || typeof specificDefault === 'string' || typeof otherDefault === 'string'),
|
|
416
|
+
locations
|
|
348
417
|
})
|
|
349
418
|
}
|
|
350
419
|
} catch (e) {
|
|
351
420
|
// Fallback to a simple key if Intl API fails
|
|
352
|
-
this.pluginContext.addKey({
|
|
421
|
+
this.pluginContext.addKey({
|
|
422
|
+
key,
|
|
423
|
+
ns,
|
|
424
|
+
defaultValue,
|
|
425
|
+
locations
|
|
426
|
+
})
|
|
353
427
|
}
|
|
354
428
|
}
|
|
355
429
|
|
|
@@ -39,7 +39,12 @@ export async function initializePlugins (plugins: any[]): Promise<void> {
|
|
|
39
39
|
* })
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
export function createPluginContext (
|
|
42
|
+
export function createPluginContext (
|
|
43
|
+
allKeys: Map<string, ExtractedKey>,
|
|
44
|
+
plugins: Plugin[],
|
|
45
|
+
config: Omit<I18nextToolkitConfig, 'plugins'>,
|
|
46
|
+
logger: Logger
|
|
47
|
+
): PluginContext {
|
|
43
48
|
const pluginContextConfig = Object.freeze({
|
|
44
49
|
...config,
|
|
45
50
|
plugins: [...plugins],
|
|
@@ -74,14 +79,33 @@ export function createPluginContext (allKeys: Map<string, ExtractedKey>, plugins
|
|
|
74
79
|
|
|
75
80
|
const isNewGenericFallback = defaultValue === keyInfo.key
|
|
76
81
|
|
|
82
|
+
// Merge locations
|
|
83
|
+
if (keyInfo.locations) {
|
|
84
|
+
existingKey.locations = [
|
|
85
|
+
...(existingKey.locations || []),
|
|
86
|
+
...keyInfo.locations
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
// If existing value is a generic fallback and new value is specific, replace it
|
|
78
91
|
if (isExistingGenericFallback && !isNewGenericFallback) {
|
|
79
|
-
allKeys.set(uniqueKey, {
|
|
92
|
+
allKeys.set(uniqueKey, {
|
|
93
|
+
...keyInfo,
|
|
94
|
+
ns: storedNs || config.extract?.defaultNS || 'translation',
|
|
95
|
+
nsIsImplicit,
|
|
96
|
+
defaultValue,
|
|
97
|
+
locations: existingKey.locations // Preserve merged locations
|
|
98
|
+
})
|
|
80
99
|
}
|
|
81
100
|
// Otherwise keep the existing one
|
|
82
101
|
} else {
|
|
83
102
|
// New key, just add it
|
|
84
|
-
allKeys.set(uniqueKey, {
|
|
103
|
+
allKeys.set(uniqueKey, {
|
|
104
|
+
...keyInfo,
|
|
105
|
+
ns: storedNs || config.extract?.defaultNS || 'translation',
|
|
106
|
+
nsIsImplicit,
|
|
107
|
+
defaultValue
|
|
108
|
+
})
|
|
85
109
|
}
|
|
86
110
|
},
|
|
87
111
|
config: pluginContextConfig,
|
package/src/types-generator.ts
CHANGED
|
@@ -77,7 +77,9 @@ export async function runTypesGenerator (config: I18nextToolkitConfig) {
|
|
|
77
77
|
const logMessages: string[] = []
|
|
78
78
|
|
|
79
79
|
const enableSelector = config.types?.enableSelector || false
|
|
80
|
-
const interfaceDefinition =
|
|
80
|
+
const interfaceDefinition = ` // This file is automatically generated by i18next-cli. Do not edit manually.
|
|
81
|
+
${mergeResourcesAsInterface(resources, { optimize: !!enableSelector })}`
|
|
82
|
+
|
|
81
83
|
const outputPath = resolve(process.cwd(), config.types?.output || '')
|
|
82
84
|
const resourcesOutputPath = resolve(process.cwd(), config.types.resourcesFile)
|
|
83
85
|
await mkdir(dirname(resourcesOutputPath), { recursive: true })
|
package/src/types.ts
CHANGED
|
@@ -322,6 +322,13 @@ export interface ExtractedKey {
|
|
|
322
322
|
|
|
323
323
|
/** True when the extractor returned an already-expanded plural form (e.g. "key_one") */
|
|
324
324
|
isExpandedPlural?: boolean
|
|
325
|
+
|
|
326
|
+
/** Source locations where this key was found (optional, populated by plugins) */
|
|
327
|
+
locations?: Array<{
|
|
328
|
+
file: string
|
|
329
|
+
line?: number
|
|
330
|
+
column?: number
|
|
331
|
+
}>
|
|
325
332
|
}
|
|
326
333
|
|
|
327
334
|
/**
|
|
@@ -33,6 +33,8 @@ export declare class ASTVisitors {
|
|
|
33
33
|
private readonly expressionResolver;
|
|
34
34
|
private readonly callExpressionHandler;
|
|
35
35
|
private readonly jsxHandler;
|
|
36
|
+
private currentFile;
|
|
37
|
+
private currentCode;
|
|
36
38
|
/**
|
|
37
39
|
* Creates a new AST visitor instance.
|
|
38
40
|
*
|
|
@@ -72,5 +74,26 @@ export declare class ASTVisitors {
|
|
|
72
74
|
* @private
|
|
73
75
|
*/
|
|
74
76
|
getVarFromScope(name: string): ScopeInfo | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Sets the current file path used by the extractor.
|
|
79
|
+
*
|
|
80
|
+
* @param file - The file path (absolute or relative) to set as the current processing context.
|
|
81
|
+
* @remarks
|
|
82
|
+
* Updating the current file allows subsequent AST visitors and extraction logic to
|
|
83
|
+
* associate nodes, messages, and errors with the correct source file.
|
|
84
|
+
*/
|
|
85
|
+
setCurrentFile(file: string, code: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Returns the currently set file path.
|
|
88
|
+
*
|
|
89
|
+
* @returns The current file path as a string, or `undefined` if no file has been set.
|
|
90
|
+
* @remarks
|
|
91
|
+
* Use this to retrieve the file context that was previously set via `setCurrentFile`.
|
|
92
|
+
*/
|
|
93
|
+
getCurrentFile(): string;
|
|
94
|
+
/**
|
|
95
|
+
* @returns The full source code string for the file currently under processing.
|
|
96
|
+
*/
|
|
97
|
+
getCurrentCode(): string;
|
|
75
98
|
}
|
|
76
99
|
//# sourceMappingURL=ast-visitors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAQ,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAInE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,KAAK,CAAiB;IAE9B,IAAW,UAAU,gBAEpB;IAED,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAuB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;
|
|
1
|
+
{"version":3,"file":"ast-visitors.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/ast-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAQ,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE1G,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAInE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,KAAK,CAAiB;IAE9B,IAAW,UAAU,gBAEpB;IAED,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAuB;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAa;IAEhC;;;;;;OAMG;gBAED,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,eAAe,EACvB,kBAAkB,CAAC,EAAE,kBAAkB;IAgCzC;;;;;OAKG;IACI,KAAK,CAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAUjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,IAAI;IAiGZ;;;;;;;;OAQG;IACI,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI5D;;;;;;;OAOG;IACI,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxD;;;;;;OAMG;IACI,cAAc,IAAK,MAAM;IAIhC;;OAEG;IACI,cAAc,IAAK,MAAM;CAGjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAK5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EAChB,uBAA+B,EAChC,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC9B,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAyDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/extractor/core/extractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAK5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,oBAAoB,EAC5B,EACE,WAAmB,EACnB,QAAgB,EAChB,uBAA+B,EAChC,GAAE;IACD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC9B,EACN,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,OAAO,CAAC,CAyDlB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,GAAE,MAA4B,GACnC,OAAO,CAAC,IAAI,CAAC,CAoEf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,OAAO,CAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,uBAA+B,EAAE,GAAE;IAAE,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAAO,sDAO3I"}
|
|
@@ -7,7 +7,14 @@ export declare class CallExpressionHandler {
|
|
|
7
7
|
private logger;
|
|
8
8
|
private expressionResolver;
|
|
9
9
|
objectKeys: Set<string>;
|
|
10
|
-
|
|
10
|
+
private getCurrentFile;
|
|
11
|
+
private getCurrentCode;
|
|
12
|
+
constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, logger: Logger, expressionResolver: ExpressionResolver, getCurrentFile: () => string, getCurrentCode: () => string);
|
|
13
|
+
/**
|
|
14
|
+
* Helper method to calculate line and column from byte offset.
|
|
15
|
+
* SWC provides byte offsets in span.start, not line/column directly.
|
|
16
|
+
*/
|
|
17
|
+
private getLocationFromSpan;
|
|
11
18
|
/**
|
|
12
19
|
* Processes function call expressions to extract translation keys.
|
|
13
20
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAG1D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;
|
|
1
|
+
{"version":3,"file":"call-expression-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/call-expression-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA6C,MAAM,WAAW,CAAA;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,EAAgB,SAAS,EAAE,MAAM,aAAa,CAAA;AACvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAG1D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,kBAAkB,CAAoB;IACvC,UAAU,cAAoB;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;gBAGlC,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM;IAU9B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IA4VxG;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA2LxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
|
|
@@ -5,7 +5,13 @@ export declare class JSXHandler {
|
|
|
5
5
|
private config;
|
|
6
6
|
private pluginContext;
|
|
7
7
|
private expressionResolver;
|
|
8
|
-
|
|
8
|
+
private getCurrentFile;
|
|
9
|
+
private getCurrentCode;
|
|
10
|
+
constructor(config: Omit<I18nextToolkitConfig, 'plugins'>, pluginContext: PluginContext, expressionResolver: ExpressionResolver, getCurrentFile: () => string, getCurrentCode: () => string);
|
|
11
|
+
/**
|
|
12
|
+
* Helper method to calculate line and column from byte offset.
|
|
13
|
+
*/
|
|
14
|
+
private getLocationFromSpan;
|
|
9
15
|
/**
|
|
10
16
|
* Processes JSX elements to extract translation keys from Trans components.
|
|
11
17
|
*
|
|
@@ -27,6 +33,8 @@ export declare class JSXHandler {
|
|
|
27
33
|
* @param ns - Namespace for the keys
|
|
28
34
|
* @param isOrdinal - Whether to generate ordinal plural forms
|
|
29
35
|
* @param optionsNode - Optional tOptions object expression for plural-specific defaults
|
|
36
|
+
* @param explicitDefaultFromSource - Whether the default was explicitly provided in source
|
|
37
|
+
* @param locations - Source location information for this key
|
|
30
38
|
*/
|
|
31
39
|
private generatePluralKeysForTrans;
|
|
32
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsx-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAgB,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI1D,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,kBAAkB,CAAoB;
|
|
1
|
+
{"version":3,"file":"jsx-handler.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/jsx-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAoB,MAAM,WAAW,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAgB,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAI1D,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;gBAGlC,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,MAAM,EAC5B,cAAc,EAAE,MAAM,MAAM;IAS9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;;;;;;;OAQG;IACH,gBAAgB,CAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,GAAG,IAAI;IA2QjI;;;;;;;;;;OAUG;IACH,OAAO,CAAC,0BAA0B;IAiGlC;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;CAevB"}
|
|
@@ -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,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjG;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,
|
|
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,EAAE,MAAM,UAAU,CAAA;AAEjG;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EAClC,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,EAC7C,MAAM,EAAE,MAAM,GACb,aAAa,CAqEf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-generator.d.ts","sourceRoot":"","sources":["../src/types-generator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAanD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,iBAAiB,CAAE,MAAM,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"types-generator.d.ts","sourceRoot":"","sources":["../src/types-generator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAanD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,iBAAiB,CAAE,MAAM,EAAE,oBAAoB,iBA4EpE"}
|
package/types/types.d.ts
CHANGED
|
@@ -264,6 +264,12 @@ export interface ExtractedKey {
|
|
|
264
264
|
explicitDefault?: boolean;
|
|
265
265
|
/** True when the extractor returned an already-expanded plural form (e.g. "key_one") */
|
|
266
266
|
isExpandedPlural?: boolean;
|
|
267
|
+
/** Source locations where this key was found (optional, populated by plugins) */
|
|
268
|
+
locations?: Array<{
|
|
269
|
+
file: string;
|
|
270
|
+
line?: number;
|
|
271
|
+
column?: number;
|
|
272
|
+
}>;
|
|
267
273
|
}
|
|
268
274
|
/**
|
|
269
275
|
* Result of processing translation files for a specific locale and namespace.
|
package/types/types.d.ts.map
CHANGED
|
@@ -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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"}
|