i18next-cli 1.24.8 → 1.24.9
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 +4 -0
- package/dist/cjs/cli.js +1 -1
- package/dist/cjs/extractor/parsers/call-expression-handler.js +1 -1
- package/dist/cjs/extractor/parsers/scope-manager.js +1 -1
- package/dist/esm/cli.js +1 -1
- package/dist/esm/extractor/parsers/call-expression-handler.js +1 -1
- package/dist/esm/extractor/parsers/scope-manager.js +1 -1
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/extractor/parsers/call-expression-handler.ts +8 -1
- package/src/extractor/parsers/scope-manager.ts +66 -33
- package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
- package/types/extractor/parsers/scope-manager.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ 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.24.9](https://github.com/i18next/i18next-cli/compare/v1.24.8...v1.24.9) - 2025-11-16
|
|
9
|
+
|
|
10
|
+
- fix: a namespace prefix passed as an argument (e.g. to useTranslation or custom hooks) could be treated as part of the translation key, producing unexpected nested namespace objects in generated JSON files. [#112](https://github.com/i18next/i18next-cli/issues/112)
|
|
11
|
+
|
|
8
12
|
## [1.24.8](https://github.com/i18next/i18next-cli/compare/v1.24.7...v1.24.8) - 2025-11-14
|
|
9
13
|
|
|
10
14
|
- improved Trans component parsing further [#102](https://github.com/i18next/i18next-cli/issues/102)
|
package/dist/cjs/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var e=require("commander"),o=require("chokidar"),t=require("glob"),n=require("minimatch"),i=require("chalk"),r=require("./config.js"),a=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"),d=require("./init.js"),g=require("./linter.js"),f=require("./status.js"),p=require("./locize.js"),m=require("./rename-key.js");const y=new e.Command;y.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.24.
|
|
2
|
+
"use strict";var e=require("commander"),o=require("chokidar"),t=require("glob"),n=require("minimatch"),i=require("chalk"),r=require("./config.js"),a=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"),d=require("./init.js"),g=require("./linter.js"),f=require("./status.js"),p=require("./locize.js"),m=require("./rename-key.js");const y=new e.Command;y.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.24.9"),y.option("-c, --config <path>","Path to i18next-cli config file (overrides detection)"),y.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 t=y.opts().config,i=await r.ensureConfig(t),a=async()=>{const o=await c.runExtractor(i,{isWatchMode:!!e.watch,isDryRun:!!e.dryRun,syncPrimaryWithDefaults:!!e.syncPrimary});return e.ci&&!o?(console.log("✅ No files were updated."),process.exit(0)):e.ci&&o&&(console.error("❌ Some files were updated. This should not happen in CI mode."),process.exit(1)),o};if(await a(),e.watch){console.log("\nWatching for changes...");const e=await x(i.extract.input),t=h(i.extract.ignore),r=w(i.extract.output),c=[...t,...r].filter(Boolean),s=e.filter(e=>!c.some(o=>n.minimatch(e,o,{dot:!0})));o.watch(s,{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),a()})}}catch(e){console.error("Error running extractor:",e),process.exit(1)}}),y.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,o)=>{const t=y.opts().config;let n=await r.loadConfig(t);if(!n){console.log(i.blue("No config file found. Attempting to detect project structure..."));const e=await a.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 f.runStatus(n,{detail:e,namespace:o.namespace})}),y.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 t=y.opts().config,i=await r.ensureConfig(t),a=()=>s.runTypesGenerator(i);if(await a(),e.watch){console.log("\nWatching for changes...");const e=await x(i.types?.input||[]),t=[...h(i.extract?.ignore)].filter(Boolean),r=e.filter(e=>!t.some(o=>n.minimatch(e,o,{dot:!0})));o.watch(r,{persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),a()})}}),y.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const e=y.opts().config,o=await r.ensureConfig(e);await l.runSyncer(o)}),y.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async e=>{await u.runMigrator(e)}),y.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(d.runInit),y.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 t=y.opts().config,c=async()=>{let e=await r.loadConfig(t);if(!e){console.log(i.blue("No config file found. Attempting to detect project structure..."));const o=await a.detectConfig();o||(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=o}await g.runLinterCli(e)};if(await c(),e.watch){console.log("\nWatching for changes...");const e=await r.loadConfig(t);if(e?.extract?.input){const t=await x(e.extract.input),i=[...h(e.extract.ignore),...w(e.extract.output)].filter(Boolean),r=t.filter(e=>!i.some(o=>n.minimatch(e,o,{dot:!0})));o.watch(r,{ignored:/node_modules/,persistent:!0}).on("change",e=>{console.log(`\nFile changed: ${e}`),c()})}}}),y.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 o=y.opts().config,t=await r.ensureConfig(o);await p.runLocizeSync(t,e)}),y.command("locize-download").description("Download all translations from your locize project.").action(async e=>{const o=y.opts().config,t=await r.ensureConfig(o);await p.runLocizeDownload(t,e)}),y.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async e=>{const o=y.opts().config,t=await r.ensureConfig(o);await p.runLocizeMigrate(t,e)}),y.command("rename-key <oldKey> <newKey>").description("Rename a translation key across all source files and translation files.").option("--dry-run","Preview changes without modifying files").action(async(e,o,t)=>{try{const n=y.opts().config,a=await r.ensureConfig(n),c=await m.runRenameKey(a,e,o,t);c.success||(c.conflicts&&(console.error(i.red("\n❌ Conflicts detected:")),c.conflicts.forEach(e=>console.error(` - ${e}`))),c.error&&console.error(i.red(`\n❌ ${c.error}`)),process.exit(1));0===c.sourceFiles.reduce((e,o)=>e+o.changes,0)&&console.log(i.yellow(`\n⚠️ No usages found for "${e}"`))}catch(e){console.error(i.red("Error renaming key:"),e),process.exit(1)}}),y.parse(process.argv);const h=e=>Array.isArray(e)?e:e?[e]:[],w=e=>e&&"string"==typeof e?[e.replace(/\{\{[^}]+\}\}/g,"*")]:[],x=async(e=[])=>{const o=h(e),n=await Promise.all(o.map(e=>t.glob(e||"",{nodir:!0})));return Array.from(new Set(n.flat()))};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("./ast-utils.js");exports.CallExpressionHandler=class{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;lastSearchIndex=0;constructor(e,t,r,n,s,i){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n,this.getCurrentFile=s,this.getCurrentCode=i}resetSearchIndex(){this.lastSearchIndex=0}getLocationFromNode(e){const t=this.getCurrentCode();let r;if("CallExpression"===e.type&&e.arguments.length>0){const t=e.arguments[0].expression;"StringLiteral"===t.type?r=t.raw??`'${t.value}'`:"TemplateLiteral"===t.type&&(r="`")}if(!r)return;const n=t.indexOf(r,this.lastSearchIndex);if(-1===n)return;this.lastSearchIndex=n+r.length;const s=t.substring(0,n).split("\n");return{line:s.length,column:s[s.length-1].length}}handleCallExpression(t,r){const n=this.getFunctionName(t.callee);if(!n)return;const s=r(n),i=this.config.extract.functions||["t","*.t"];let o=void 0!==s;if(!o)for(const e of i)if(e.startsWith("*.")){if(n.endsWith(e.substring(1))){o=!0;break}}else if(e===n){o=!0;break}if(!o||0===t.arguments.length)return;const{keysToProcess:l,isSelectorAPI:a}=this.handleCallExpressionArgument(t,0);if(0===l.length)return;let u=!1;const c=this.config.extract.pluralSeparator??"_";for(let e=0;e<l.length;e++)l[e].endsWith(`${c}ordinal`)&&(u=!0,l[e]=l[e].slice(0,-8));let p,f;if(t.arguments.length>1){const r=t.arguments[1].expression;"ObjectExpression"===r.type?f=r:"StringLiteral"===r.type?p=r.value:"TemplateLiteral"===r.type&&e.isSimpleTemplateLiteral(r)&&(p=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:p,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($=g)&&/{{\s*count\s*}}/.test($)));var $;for(let r=0;r<l.length;r++){let
|
|
1
|
+
"use strict";var e=require("./ast-utils.js");exports.CallExpressionHandler=class{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;lastSearchIndex=0;constructor(e,t,r,n,s,i){this.config=e,this.pluginContext=t,this.logger=r,this.expressionResolver=n,this.getCurrentFile=s,this.getCurrentCode=i}resetSearchIndex(){this.lastSearchIndex=0}getLocationFromNode(e){const t=this.getCurrentCode();let r;if("CallExpression"===e.type&&e.arguments.length>0){const t=e.arguments[0].expression;"StringLiteral"===t.type?r=t.raw??`'${t.value}'`:"TemplateLiteral"===t.type&&(r="`")}if(!r)return;const n=t.indexOf(r,this.lastSearchIndex);if(-1===n)return;this.lastSearchIndex=n+r.length;const s=t.substring(0,n).split("\n");return{line:s.length,column:s[s.length-1].length}}handleCallExpression(t,r){const n=this.getFunctionName(t.callee);if(!n)return;const s=r(n),i=this.config.extract.functions||["t","*.t"];let o=void 0!==s;if(!o)for(const e of i)if(e.startsWith("*.")){if(n.endsWith(e.substring(1))){o=!0;break}}else if(e===n){o=!0;break}if(!o||0===t.arguments.length)return;const{keysToProcess:l,isSelectorAPI:a}=this.handleCallExpressionArgument(t,0);if(0===l.length)return;let u=!1;const c=this.config.extract.pluralSeparator??"_";for(let e=0;e<l.length;e++)l[e].endsWith(`${c}ordinal`)&&(u=!0,l[e]=l[e].slice(0,-8));let p,f;if(t.arguments.length>1){const r=t.arguments[1].expression;"ObjectExpression"===r.type?f=r:"StringLiteral"===r.type?p=r.value:"TemplateLiteral"===r.type&&e.isSimpleTemplateLiteral(r)&&(p=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:p,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($=g)&&/{{\s*count\s*}}/.test($)));var $;for(let r=0;r<l.length;r++){const n=l[r];let i,o=l[r];if(f){const t=e.getObjectPropValue(f,"ns");"string"==typeof t&&(i=t)}const c=this.config.extract.nsSeparator??":";if(!i&&c&&o.includes(c)){const e=o.split(c);if(i=e.shift(),o=e.join(c),!o||""===o.trim()){this.logger.warn(`Skipping key that became empty after namespace removal: '${i}${c}'`);continue}}!i&&s?.defaultNs&&(i=s.defaultNs),i||(i=this.config.extract.defaultNS);let p=o;if(s?.keyPrefix){const e=this.config.extract.keySeparator??".";if(p=!1!==e?s.keyPrefix.endsWith(e)?`${s.keyPrefix}${o}`:`${s.keyPrefix}${e}${o}`:`${s.keyPrefix}${o}`,!1!==e){if(p.split(e).some(e=>""===e.trim())){this.logger.warn(`Skipping key with empty segments: '${p}' (keyPrefix: '${s.keyPrefix}', key: '${o}')`);continue}}}const y=r===l.length-1?"string"==typeof g?g:c&&n.includes(c||":")?n:o:o;if(f){const t=e.getObjectPropValueExpression(f,"context"),r=[];if("StringLiteral"===t?.type||"NumericLiteral"===t?.type||"BooleanLiteral"===t?.type){const e=`${t.value}`,n=this.config.extract.contextSeparator??"_";""!==e&&r.push({key:`${p}${n}${e}`,ns:i,defaultValue:y,explicitDefault:d})}else if(t){const e=this.expressionResolver.resolvePossibleContextStringValues(t),n=this.config.extract.contextSeparator??"_";e.length>0&&e.forEach(e=>{r.push({key:`${p}${n}${e}`,ns:i,defaultValue:y,explicitDefault:d})}),r.push({key:p,ns:i,defaultValue:y,explicitDefault:d,keyAcceptingContext:p})}const n=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}},s=(()=>{if(!f||!Array.isArray(f.properties))return!1;for(const e of f.properties){if("count"===n(e))return!0}return!1})(),o=(()=>{if(!f||!Array.isArray(f.properties))return!1;for(const e of f.properties){if("ordinal"===n(e))return!("KeyValueProperty"!==e.type||!e.value||"BooleanLiteral"!==e.value.type)&&Boolean(e.value.value)}return!1})();if(s||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 n=!1;try{const r=new Intl.PluralRules(t,{type:e}).resolvedOptions().pluralCategories;1===r.length&&"other"===r[0]&&(n=!0)}catch{}if(!n){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]&&(n=!0)}if(n){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:i,defaultValue:y,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:i,defaultValue:y,explicitDefault:d}):this.handlePluralKeys(p,i,f,o||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=this.getLocationFromNode(t);this.pluginContext.addKey({key:p,ns:i,defaultValue:y,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 s=!1;if("ArrowFunctionExpression"===r.type){const e=this.extractKeyFromSelector(r);e&&(n.push(e),s=!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:s}}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,s,i,o){try{const l=s?"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(),c=this.config.extract.pluralSeparator??"_",p=e.getObjectPropValue(n,"defaultValue"),f=e.getObjectPropValue(n,`defaultValue${c}other`),y=e.getObjectPropValue(n,`defaultValue${c}ordinal${c}other`),g=e.getObjectPropValueExpression(n,"context"),h=[];if(g){const e=this.expressionResolver.resolvePossibleContextStringValues(g);if(e.length>0)if("StringLiteral"===g.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${c}other`);let u;u="string"==typeof a?a:"string"==typeof p?p:"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:s,explicitDefault:Boolean(o||"string"==typeof a)})}return}for(const{key:l,context:a}of h)for(const g of u){const u=s?`defaultValue${c}ordinal${c}${g}`:`defaultValue${c}${g}`,h=e.getObjectPropValue(n,u);let d,x;if(d="string"==typeof h?h:"one"===g&&"string"==typeof p?p:"one"===g&&"string"==typeof i?i:s&&"string"==typeof y?y:s||"string"!=typeof f?"string"==typeof p?p:"string"==typeof i?i:l:f,a){const e=this.config.extract.contextSeparator??"_";x=s?`${l}${e}${a}${c}ordinal${c}${g}`:`${l}${e}${a}${c}${g}`}else x=s?`${l}${c}ordinal${c}${g}`:`${l}${c}${g}`;this.pluginContext.addKey({key:x,ns:r,defaultValue:d,hasCount:!0,isOrdinal:s,explicitDefault:Boolean(o||"string"==typeof h||"string"==typeof f),keyAcceptingContext:void 0!==a?t:void 0})}}catch(s){this.logger.warn(`Could not determine plural rules for language "${this.config.extract?.primaryLanguage}". Falling back to simple key extraction.`);const o=i||e.getObjectPropValue(n,"defaultValue");this.pluginContext.addKey({key:t,ns:r,defaultValue:"string"==typeof o?o: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("./ast-utils.js");exports.ScopeManager=class{scopeStack=[];config;scope=new Map;simpleConstants=new Map;constructor(e){this.config=e}reset(){this.scopeStack=[],this.scope=new Map,this.simpleConstants.clear()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0?this.scopeStack[this.scopeStack.length-1].set(e,t):this.scope.set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e)){return this.scopeStack[t].get(e)}const t=this.scope.get(e);if(t)return t}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const i of t){if("string"==typeof i&&i===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof i&&i.name===e)return{name:i.name,nsArg:i.nsArg??0,keyPrefixArg:i.keyPrefixArg??1}}}resolveSimpleStringIdentifier(e){return this.simpleConstants.get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;"Identifier"===e.id.type&&"StringLiteral"===t.type&&this.simpleConstants.set(e.id.value,t.value);const i="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!i)return;const r=i.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return this.handleUseTranslationDeclarator(e,i,t),void this.handleUseTranslationForComments(e,i,t)}if("Identifier"===r.type){if(this.getVarFromScope(r.value))return void this.handleGetFixedTFromVariableDeclarator(e,i,r.value)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,i)}handleUseTranslationForComments(e,t,i){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)){r=t.key.value;break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const s
|
|
1
|
+
"use strict";var e=require("./ast-utils.js");exports.ScopeManager=class{scopeStack=[];config;scope=new Map;simpleConstants=new Map;constructor(e){this.config=e}reset(){this.scopeStack=[],this.scope=new Map,this.simpleConstants.clear()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0?this.scopeStack[this.scopeStack.length-1].set(e,t):this.scope.set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e)){return this.scopeStack[t].get(e)}const t=this.scope.get(e);if(t)return t}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const i of t){if("string"==typeof i&&i===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof i&&i.name===e)return{name:i.name,nsArg:i.nsArg??0,keyPrefixArg:i.keyPrefixArg??1}}}resolveSimpleStringIdentifier(e){return this.simpleConstants.get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;"Identifier"===e.id.type&&"StringLiteral"===t.type&&this.simpleConstants.set(e.id.value,t.value);const i="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!i)return;const r=i.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return this.handleUseTranslationDeclarator(e,i,t),void this.handleUseTranslationForComments(e,i,t)}if("Identifier"===r.type){if(this.getVarFromScope(r.value))return void this.handleGetFixedTFromVariableDeclarator(e,i,r.value)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,i)}handleUseTranslationForComments(e,t,i){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)){r=t.key.value;break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const s=t.arguments?.[0]?.expression,n=t.arguments?.[1]?.expression,a=t.arguments?.[2]?.expression;let o,l;const p=(void 0===i.nsArg||-1!==i.nsArg)&&"StringLiteral"===s?.type&&"StringLiteral"===n?.type&&(y=s.value,/^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(y));var y;p?o=n.value:-1!==i.nsArg&&"StringLiteral"===s?.type?o=s.value:-1!==i.nsArg&&"ArrayExpression"===s?.type&&"StringLiteral"===s.elements[0]?.expression.type&&(o=s.elements[0].expression.value);const u=p?a:t.arguments?.[i.keyPrefixArg??1]?.expression;if("ObjectExpression"===u?.type){const e=u.properties.find(e=>"KeyValueProperty"===e.type&&"Identifier"===e.key.type&&"keyPrefix"===e.key.value);"KeyValueProperty"===e?.type&&"StringLiteral"===e.value.type&&(l=e.value.value)}else if("StringLiteral"===u?.type)l=u.value;else if("Identifier"===u?.type)l=this.resolveSimpleStringIdentifier(u.value);else if("TemplateLiteral"===u?.type){const e=u;0===(e.expressions||[]).length&&(l=e.quasis?.[0]?.cooked??void 0)}(o||l)&&this.scope.set(r,{defaultNs:o,keyPrefix:l})}handleUseTranslationDeclarator(t,i,r){let s;if("Identifier"===t.id.type&&(s=t.id.value),"ArrayPattern"===t.id.type){const e=t.id.elements[0];"Identifier"===e?.type&&(s=e.value)}if("ObjectPattern"===t.id.type)for(const e of t.id.properties){if("AssignmentPatternProperty"===e.type&&"Identifier"===e.key.type&&("t"===e.key.value||"getFixedT"===e.key.value)){s=e.key.value;break}if("KeyValuePatternProperty"===e.type&&"Identifier"===e.key.type&&("t"===e.key.value||"getFixedT"===e.key.value)&&"Identifier"===e.value.type){s=e.value.value;break}}if(!s)return;const n=i.arguments?.[0]?.expression,a=i.arguments?.[1]?.expression,o=i.arguments?.[2]?.expression;let l,p;const y=(void 0===r.nsArg||-1!==r.nsArg)&&"StringLiteral"===n?.type&&"StringLiteral"===a?.type&&(u=n.value,/^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(u));var u;y?l=a.value:-1!==r.nsArg&&"StringLiteral"===n?.type?l=n.value:-1!==r.nsArg&&"ArrayExpression"===n?.type&&"StringLiteral"===n.elements[0]?.expression.type&&(l=n.elements[0].expression.value);const f=y?o:i.arguments?.[r.keyPrefixArg??1]?.expression;if("ObjectExpression"===f?.type){const t=e.getObjectPropValue(f,"keyPrefix");p="string"==typeof t?t:void 0}else if("StringLiteral"===f?.type)p=f.value;else if("Identifier"===f?.type)p=this.resolveSimpleStringIdentifier(f.value);else if("TemplateLiteral"===f?.type){const e=f;0===(e.expressions||[]).length&&(p=e.quasis?.[0]?.cooked??void 0)}this.setVarInScope(s,{defaultNs:l,keyPrefix:p})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const i=e.id.value,r=t.arguments,s=r[1]?.expression,n=r[2]?.expression,a="StringLiteral"===s?.type?s.value:void 0,o="StringLiteral"===n?.type?n.value:void 0;(a||o)&&this.setVarInScope(i,{defaultNs:a,keyPrefix:o})}handleGetFixedTFromVariableDeclarator(e,t,i){if("Identifier"!==e.id.type)return;const r=e.id.value,s=this.getVarFromScope(i);if(!s)return;const n=t.arguments,a=n[1]?.expression,o=n[2]?.expression,l="StringLiteral"===a?.type?a.value:void 0,p="StringLiteral"===o?.type?o.value:void 0,y=l??s.defaultNs,u=p??s.keyPrefix;(y||u)&&this.setVarInScope(r,{defaultNs:y,keyPrefix:u})}};
|
package/dist/esm/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as o}from"commander";import e from"chokidar";import{glob as t}from"glob";import{minimatch as n}from"minimatch";import i 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 f}from"./migrator.js";import{runInit as m}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";import{runRenameKey as w}from"./rename-key.js";const x=new o;x.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.24.
|
|
2
|
+
import{Command as o}from"commander";import e from"chokidar";import{glob as t}from"glob";import{minimatch as n}from"minimatch";import i 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 f}from"./migrator.js";import{runInit as m}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";import{runRenameKey as w}from"./rename-key.js";const x=new o;x.name("i18next-cli").description("A unified, high-performance i18next CLI.").version("1.24.9"),x.option("-c, --config <path>","Path to i18next-cli config file (overrides detection)"),x.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 o=>{try{const t=x.opts().config,i=await a(t),r=async()=>{const e=await s(i,{isWatchMode:!!o.watch,isDryRun:!!o.dryRun,syncPrimaryWithDefaults:!!o.syncPrimary});return o.ci&&!e?(console.log("✅ No files were updated."),process.exit(0)):o.ci&&e&&(console.error("❌ Some files were updated. This should not happen in CI mode."),process.exit(1)),e};if(await r(),o.watch){console.log("\nWatching for changes...");const o=await z(i.extract.input),t=j(i.extract.ignore),a=k(i.extract.output),c=[...t,...a].filter(Boolean),s=o.filter(o=>!c.some(e=>n(o,e,{dot:!0})));e.watch(s,{ignored:/node_modules/,persistent:!0}).on("change",o=>{console.log(`\nFile changed: ${o}`),r()})}}catch(o){console.error("Error running extractor:",o),process.exit(1)}}),x.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(o,e)=>{const t=x.opts().config;let n=await r(t);if(!n){console.log(i.blue("No config file found. Attempting to detect project structure..."));const o=await c();o||(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=o}await g(n,{detail:o,namespace:e.namespace})}),x.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 o=>{const t=x.opts().config,i=await a(t),r=()=>l(i);if(await r(),o.watch){console.log("\nWatching for changes...");const o=await z(i.types?.input||[]),t=[...j(i.extract?.ignore)].filter(Boolean),a=o.filter(o=>!t.some(e=>n(o,e,{dot:!0})));e.watch(a,{persistent:!0}).on("change",o=>{console.log(`\nFile changed: ${o}`),r()})}}),x.command("sync").description("Synchronize secondary language files with the primary language file.").action(async()=>{const o=x.opts().config,e=await a(o);await p(e)}),x.command("migrate-config [configPath]").description("Migrate a legacy i18next-parser.config.js to the new format.").action(async o=>{await f(o)}),x.command("init").description("Create a new i18next.config.ts/js file with an interactive setup wizard.").action(m),x.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 o=>{const t=x.opts().config,a=async()=>{let o=await r(t);if(!o){console.log(i.blue("No config file found. Attempting to detect project structure..."));const e=await c();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!")),o=e}await d(o)};if(await a(),o.watch){console.log("\nWatching for changes...");const o=await r(t);if(o?.extract?.input){const t=await z(o.extract.input),i=[...j(o.extract.ignore),...k(o.extract.output)].filter(Boolean),r=t.filter(o=>!i.some(e=>n(o,e,{dot:!0})));e.watch(r,{ignored:/node_modules/,persistent:!0}).on("change",o=>{console.log(`\nFile changed: ${o}`),a()})}}}),x.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 o=>{const e=x.opts().config,t=await a(e);await u(t,o)}),x.command("locize-download").description("Download all translations from your locize project.").action(async o=>{const e=x.opts().config,t=await a(e);await y(t,o)}),x.command("locize-migrate").description("Migrate local translation files to a new locize project.").action(async o=>{const e=x.opts().config,t=await a(e);await h(t,o)}),x.command("rename-key <oldKey> <newKey>").description("Rename a translation key across all source files and translation files.").option("--dry-run","Preview changes without modifying files").action(async(o,e,t)=>{try{const n=x.opts().config,r=await a(n),c=await w(r,o,e,t);c.success||(c.conflicts&&(console.error(i.red("\n❌ Conflicts detected:")),c.conflicts.forEach(o=>console.error(` - ${o}`))),c.error&&console.error(i.red(`\n❌ ${c.error}`)),process.exit(1));0===c.sourceFiles.reduce((o,e)=>o+e.changes,0)&&console.log(i.yellow(`\n⚠️ No usages found for "${o}"`))}catch(o){console.error(i.red("Error renaming key:"),o),process.exit(1)}}),x.parse(process.argv);const j=o=>Array.isArray(o)?o:o?[o]:[],k=o=>o&&"string"==typeof o?[o.replace(/\{\{[^}]+\}\}/g,"*")]:[],z=async(o=[])=>{const e=j(o),n=await Promise.all(e.map(o=>t(o||"",{nodir:!0})));return Array.from(new Set(n.flat()))};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isSimpleTemplateLiteral as e,getObjectPropValue as t,getObjectPropValueExpression as r}from"./ast-utils.js";class n{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;lastSearchIndex=0;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}resetSearchIndex(){this.lastSearchIndex=0}getLocationFromNode(e){const t=this.getCurrentCode();let r;if("CallExpression"===e.type&&e.arguments.length>0){const t=e.arguments[0].expression;"StringLiteral"===t.type?r=t.raw??`'${t.value}'`:"TemplateLiteral"===t.type&&(r="`")}if(!r)return;const n=t.indexOf(r,this.lastSearchIndex);if(-1===n)return;this.lastSearchIndex=n+r.length;const i=t.substring(0,n).split("\n");return{line:i.length,column:i[i.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 c=!1;const p=this.config.extract.pluralSeparator??"_";for(let e=0;e<u.length;e++)u[e].endsWith(`${p}ordinal`)&&(c=!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),$=x(g),m=Boolean($||"string"==typeof d&&!("string"==typeof(v=d)&&/{{\s*count\s*}}/.test(v)));var v;for(let e=0;e<u.length;e++){let
|
|
1
|
+
import{isSimpleTemplateLiteral as e,getObjectPropValue as t,getObjectPropValueExpression as r}from"./ast-utils.js";class n{pluginContext;config;logger;expressionResolver;objectKeys=new Set;getCurrentFile;getCurrentCode;lastSearchIndex=0;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}resetSearchIndex(){this.lastSearchIndex=0}getLocationFromNode(e){const t=this.getCurrentCode();let r;if("CallExpression"===e.type&&e.arguments.length>0){const t=e.arguments[0].expression;"StringLiteral"===t.type?r=t.raw??`'${t.value}'`:"TemplateLiteral"===t.type&&(r="`")}if(!r)return;const n=t.indexOf(r,this.lastSearchIndex);if(-1===n)return;this.lastSearchIndex=n+r.length;const i=t.substring(0,n).split("\n");return{line:i.length,column:i[i.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 c=!1;const p=this.config.extract.pluralSeparator??"_";for(let e=0;e<u.length;e++)u[e].endsWith(`${p}ordinal`)&&(c=!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),$=x(g),m=Boolean($||"string"==typeof d&&!("string"==typeof(v=d)&&/{{\s*count\s*}}/.test(v)));var v;for(let e=0;e<u.length;e++){const i=u[e];let s,l=u[e];if(g){const e=t(g,"ns");"string"==typeof e&&(s=e)}const a=this.config.extract.nsSeparator??":";if(!s&&a&&l.includes(a)){const e=l.split(a);if(s=e.shift(),l=e.join(a),!l||""===l.trim()){this.logger.warn(`Skipping key that became empty after namespace removal: '${s}${a}'`);continue}}!s&&o?.defaultNs&&(s=o.defaultNs),s||(s=this.config.extract.defaultNS);let p=l;if(o?.keyPrefix){const e=this.config.extract.keySeparator??".";if(p=!1!==e?o.keyPrefix.endsWith(e)?`${o.keyPrefix}${l}`:`${o.keyPrefix}${e}${l}`:`${o.keyPrefix}${l}`,!1!==e){if(p.split(e).some(e=>""===e.trim())){this.logger.warn(`Skipping key with empty segments: '${p}' (keyPrefix: '${o.keyPrefix}', key: '${l}')`);continue}}}const y=e===u.length-1?"string"==typeof d?d:a&&i.includes(a||":")?i:l:l;if(g){const e=r(g,"context"),n=[];if("StringLiteral"===e?.type||"NumericLiteral"===e?.type||"BooleanLiteral"===e?.type){const t=`${e.value}`,r=this.config.extract.contextSeparator??"_";""!==t&&n.push({key:`${p}${r}${t}`,ns:s,defaultValue:y,explicitDefault:k})}else if(e){const t=this.expressionResolver.resolvePossibleContextStringValues(e),r=this.config.extract.contextSeparator??"_";t.length>0&&t.forEach(e=>{n.push({key:`${p}${r}${e}`,ns:s,defaultValue:y,explicitDefault:k})}),n.push({key:p,ns:s,defaultValue:y,explicitDefault:k,keyAcceptingContext:p})}const i=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"===i(e))return!0}return!1})(),l=(()=>{if(!g||!Array.isArray(g.properties))return!1;for(const e of g.properties){if("ordinal"===i(e))return!("KeyValueProperty"!==e.type||!e.value||"BooleanLiteral"!==e.value.type)&&Boolean(e.value.value)}return!1})();if(o||c){try{const e=c?"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:c});else this.pluginContext.addKey({key:p,ns:s,defaultValue:y,hasCount:!0,isOrdinal:c});continue}}catch(e){}this.config.extract.disablePlurals?n.length>0?n.forEach(this.pluginContext.addKey):this.pluginContext.addKey({key:p,ns:s,defaultValue:y,explicitDefault:k}):this.handlePluralKeys(p,s,g,l||c,d,m);continue}if(n.length>0){n.forEach(this.pluginContext.addKey);continue}!0===t(g,"returnObjects")&&this.objectKeys.add(p)}f&&this.objectKeys.add(p);{const e=this.getLocationFromNode(n);this.pluginContext.addKey({key:p,ns:s,defaultValue:y,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(),c=this.config.extract.pluralSeparator??"_",p=t(i,"defaultValue"),y=t(i,`defaultValue${c}other`),g=t(i,`defaultValue${c}ordinal${c}other`),h=r(i,"context"),d=[];if(h){const t=this.expressionResolver.resolvePossibleContextStringValues(h);if(t.length>0)if("StringLiteral"===h.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${c}other`);let u;u="string"==typeof a?a:"string"==typeof p?p:"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:r,context:a}of d)for(const u of f){const f=t(i,s?`defaultValue${c}ordinal${c}${u}`:`defaultValue${c}${u}`);let h,d;if(h="string"==typeof f?f:"one"===u&&"string"==typeof p?p:"one"===u&&"string"==typeof o?o:s&&"string"==typeof g?g:s||"string"!=typeof y?"string"==typeof p?p:"string"==typeof o?o:r:y,a){const e=this.config.extract.contextSeparator??"_";d=s?`${r}${e}${a}${c}ordinal${c}${u}`:`${r}${e}${a}${c}${u}`}else d=s?`${r}${c}ordinal${c}${u}`:`${r}${c}${u}`;this.pluginContext.addKey({key:d,ns:n,defaultValue:h,hasCount:!0,isOrdinal:s,explicitDefault:Boolean(l||"string"==typeof f||"string"==typeof y),keyAcceptingContext:void 0!==a?e:void 0})}}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{getObjectPropValue as e}from"./ast-utils.js";class t{scopeStack=[];config;scope=new Map;simpleConstants=new Map;constructor(e){this.config=e}reset(){this.scopeStack=[],this.scope=new Map,this.simpleConstants.clear()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0?this.scopeStack[this.scopeStack.length-1].set(e,t):this.scope.set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e)){return this.scopeStack[t].get(e)}const t=this.scope.get(e);if(t)return t}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const i of t){if("string"==typeof i&&i===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof i&&i.name===e)return{name:i.name,nsArg:i.nsArg??0,keyPrefixArg:i.keyPrefixArg??1}}}resolveSimpleStringIdentifier(e){return this.simpleConstants.get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;"Identifier"===e.id.type&&"StringLiteral"===t.type&&this.simpleConstants.set(e.id.value,t.value);const i="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!i)return;const r=i.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return this.handleUseTranslationDeclarator(e,i,t),void this.handleUseTranslationForComments(e,i,t)}if("Identifier"===r.type){if(this.getVarFromScope(r.value))return void this.handleGetFixedTFromVariableDeclarator(e,i,r.value)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,i)}handleUseTranslationForComments(e,t,i){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)){r=t.key.value;break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const s
|
|
1
|
+
import{getObjectPropValue as e}from"./ast-utils.js";class t{scopeStack=[];config;scope=new Map;simpleConstants=new Map;constructor(e){this.config=e}reset(){this.scopeStack=[],this.scope=new Map,this.simpleConstants.clear()}enterScope(){this.scopeStack.push(new Map)}exitScope(){this.scopeStack.pop()}setVarInScope(e,t){this.scopeStack.length>0?this.scopeStack[this.scopeStack.length-1].set(e,t):this.scope.set(e,t)}getVarFromScope(e){for(let t=this.scopeStack.length-1;t>=0;t--)if(this.scopeStack[t].has(e)){return this.scopeStack[t].get(e)}const t=this.scope.get(e);if(t)return t}getUseTranslationConfig(e){const t=this.config.extract.useTranslationNames||["useTranslation"];for(const i of t){if("string"==typeof i&&i===e)return{name:e,nsArg:0,keyPrefixArg:1};if("object"==typeof i&&i.name===e)return{name:i.name,nsArg:i.nsArg??0,keyPrefixArg:i.keyPrefixArg??1}}}resolveSimpleStringIdentifier(e){return this.simpleConstants.get(e)}handleVariableDeclarator(e){const t=e.init;if(!t)return;"Identifier"===e.id.type&&"StringLiteral"===t.type&&this.simpleConstants.set(e.id.value,t.value);const i="AwaitExpression"===t.type&&"CallExpression"===t.argument.type?t.argument:"CallExpression"===t.type?t:null;if(!i)return;const r=i.callee;if("Identifier"===r.type){const t=this.getUseTranslationConfig(r.value);if(t)return this.handleUseTranslationDeclarator(e,i,t),void this.handleUseTranslationForComments(e,i,t)}if("Identifier"===r.type){if(this.getVarFromScope(r.value))return void this.handleGetFixedTFromVariableDeclarator(e,i,r.value)}"MemberExpression"===r.type&&"Identifier"===r.property.type&&"getFixedT"===r.property.value&&this.handleGetFixedTDeclarator(e,i)}handleUseTranslationForComments(e,t,i){let r;if("Identifier"===e.id.type&&(r=e.id.value),"ArrayPattern"===e.id.type){const t=e.id.elements[0];"Identifier"===t?.type&&(r=t.value)}if("ObjectPattern"===e.id.type)for(const t of e.id.properties){if("AssignmentPatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)){r=t.key.value;break}if("KeyValuePatternProperty"===t.type&&"Identifier"===t.key.type&&("t"===t.key.value||"getFixedT"===t.key.value)&&"Identifier"===t.value.type){r=t.value.value;break}}if(!r)return;const s=t.arguments?.[0]?.expression,n=t.arguments?.[1]?.expression,a=t.arguments?.[2]?.expression;let o,l;const p=(void 0===i.nsArg||-1!==i.nsArg)&&"StringLiteral"===s?.type&&"StringLiteral"===n?.type&&(y=s.value,/^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(y));var y;p?o=n.value:-1!==i.nsArg&&"StringLiteral"===s?.type?o=s.value:-1!==i.nsArg&&"ArrayExpression"===s?.type&&"StringLiteral"===s.elements[0]?.expression.type&&(o=s.elements[0].expression.value);const u=p?a:t.arguments?.[i.keyPrefixArg??1]?.expression;if("ObjectExpression"===u?.type){const e=u.properties.find(e=>"KeyValueProperty"===e.type&&"Identifier"===e.key.type&&"keyPrefix"===e.key.value);"KeyValueProperty"===e?.type&&"StringLiteral"===e.value.type&&(l=e.value.value)}else if("StringLiteral"===u?.type)l=u.value;else if("Identifier"===u?.type)l=this.resolveSimpleStringIdentifier(u.value);else if("TemplateLiteral"===u?.type){const e=u;0===(e.expressions||[]).length&&(l=e.quasis?.[0]?.cooked??void 0)}(o||l)&&this.scope.set(r,{defaultNs:o,keyPrefix:l})}handleUseTranslationDeclarator(t,i,r){let s;if("Identifier"===t.id.type&&(s=t.id.value),"ArrayPattern"===t.id.type){const e=t.id.elements[0];"Identifier"===e?.type&&(s=e.value)}if("ObjectPattern"===t.id.type)for(const e of t.id.properties){if("AssignmentPatternProperty"===e.type&&"Identifier"===e.key.type&&("t"===e.key.value||"getFixedT"===e.key.value)){s=e.key.value;break}if("KeyValuePatternProperty"===e.type&&"Identifier"===e.key.type&&("t"===e.key.value||"getFixedT"===e.key.value)&&"Identifier"===e.value.type){s=e.value.value;break}}if(!s)return;const n=i.arguments?.[0]?.expression,a=i.arguments?.[1]?.expression,o=i.arguments?.[2]?.expression;let l,p;const y=(void 0===r.nsArg||-1!==r.nsArg)&&"StringLiteral"===n?.type&&"StringLiteral"===a?.type&&(u=n.value,/^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(u));var u;y?l=a.value:-1!==r.nsArg&&"StringLiteral"===n?.type?l=n.value:-1!==r.nsArg&&"ArrayExpression"===n?.type&&"StringLiteral"===n.elements[0]?.expression.type&&(l=n.elements[0].expression.value);const f=y?o:i.arguments?.[r.keyPrefixArg??1]?.expression;if("ObjectExpression"===f?.type){const t=e(f,"keyPrefix");p="string"==typeof t?t:void 0}else if("StringLiteral"===f?.type)p=f.value;else if("Identifier"===f?.type)p=this.resolveSimpleStringIdentifier(f.value);else if("TemplateLiteral"===f?.type){const e=f;0===(e.expressions||[]).length&&(p=e.quasis?.[0]?.cooked??void 0)}this.setVarInScope(s,{defaultNs:l,keyPrefix:p})}handleGetFixedTDeclarator(e,t){if("Identifier"!==e.id.type||!e.init||"CallExpression"!==e.init.type)return;const i=e.id.value,r=t.arguments,s=r[1]?.expression,n=r[2]?.expression,a="StringLiteral"===s?.type?s.value:void 0,o="StringLiteral"===n?.type?n.value:void 0;(a||o)&&this.setVarInScope(i,{defaultNs:a,keyPrefix:o})}handleGetFixedTFromVariableDeclarator(e,t,i){if("Identifier"!==e.id.type)return;const r=e.id.value,s=this.getVarFromScope(i);if(!s)return;const n=t.arguments,a=n[1]?.expression,o=n[2]?.expression,l="StringLiteral"===a?.type?a.value:void 0,p="StringLiteral"===o?.type?o.value:void 0,y=l??s.defaultNs,u=p??s.keyPrefix;(y||u)&&this.setVarInScope(r,{defaultNs:y,keyPrefix:u})}}export{t as ScopeManager};
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -23,7 +23,7 @@ const program = new Command()
|
|
|
23
23
|
program
|
|
24
24
|
.name('i18next-cli')
|
|
25
25
|
.description('A unified, high-performance i18next CLI.')
|
|
26
|
-
.version('1.24.
|
|
26
|
+
.version('1.24.9')
|
|
27
27
|
|
|
28
28
|
// new: global config override option
|
|
29
29
|
program.option('-c, --config <path>', 'Path to i18next-cli config file (overrides detection)')
|
|
@@ -185,6 +185,7 @@ export class CallExpressionHandler {
|
|
|
185
185
|
|
|
186
186
|
// Loop through each key found (could be one or more) and process it
|
|
187
187
|
for (let i = 0; i < keysToProcess.length; i++) {
|
|
188
|
+
const originalKey = keysToProcess[i] // preserve original (possibly namespaced) form
|
|
188
189
|
let key = keysToProcess[i]
|
|
189
190
|
let ns: string | false | undefined
|
|
190
191
|
|
|
@@ -241,7 +242,13 @@ export class CallExpressionHandler {
|
|
|
241
242
|
}
|
|
242
243
|
|
|
243
244
|
const isLastKey = i === keysToProcess.length - 1
|
|
244
|
-
|
|
245
|
+
// Use the original (possibly namespaced) key as the default when no explicit
|
|
246
|
+
// default was provided and the source key contained a namespace prefix.
|
|
247
|
+
const dv = isLastKey
|
|
248
|
+
? (typeof finalDefaultValue === 'string'
|
|
249
|
+
? finalDefaultValue
|
|
250
|
+
: (nsSeparator && originalKey.includes(nsSeparator || ':') ? originalKey : key))
|
|
251
|
+
: key
|
|
245
252
|
|
|
246
253
|
// Handle plurals, context, and returnObjects
|
|
247
254
|
if (options) {
|
|
@@ -222,23 +222,40 @@ export class ScopeManager {
|
|
|
222
222
|
// If we couldn't find a `t` function being declared, exit
|
|
223
223
|
if (!variableName) return
|
|
224
224
|
|
|
225
|
-
// Extract namespace from useTranslation arguments
|
|
226
|
-
|
|
227
|
-
const
|
|
225
|
+
// Extract namespace from useTranslation arguments.
|
|
226
|
+
// Respect explicit hookConfig positions (nsArg === -1 means "no namespace arg").
|
|
227
|
+
const firstArg = callExpr.arguments?.[0]?.expression
|
|
228
|
+
const secondArg = callExpr.arguments?.[1]?.expression
|
|
229
|
+
const thirdArg = callExpr.arguments?.[2]?.expression
|
|
228
230
|
|
|
229
231
|
let defaultNs: string | undefined
|
|
230
232
|
let keyPrefix: string | undefined
|
|
231
233
|
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
// Helper: quick heuristic to detect language-like strings (e.g. "en", "en-US", "pt-BR")
|
|
235
|
+
const looksLikeLanguage = (s: string) => /^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(s)
|
|
236
|
+
|
|
237
|
+
// If the hook config explicitly disables ns arg, do NOT treat first/second args as namespace.
|
|
238
|
+
const isLngNs = (hookConfig.nsArg === undefined || hookConfig.nsArg !== -1) &&
|
|
239
|
+
firstArg?.type === 'StringLiteral' &&
|
|
240
|
+
secondArg?.type === 'StringLiteral' &&
|
|
241
|
+
looksLikeLanguage(firstArg.value)
|
|
242
|
+
|
|
243
|
+
if (isLngNs) {
|
|
244
|
+
// useTranslation(lng, ns)
|
|
245
|
+
defaultNs = secondArg.value
|
|
246
|
+
} else if (hookConfig.nsArg !== -1 && firstArg?.type === 'StringLiteral') {
|
|
247
|
+
// useTranslation(ns)
|
|
248
|
+
defaultNs = firstArg.value
|
|
249
|
+
} else if (hookConfig.nsArg !== -1 && firstArg?.type === 'ArrayExpression' && firstArg.elements[0]?.expression.type === 'StringLiteral') {
|
|
250
|
+
defaultNs = firstArg.elements[0].expression.value
|
|
237
251
|
}
|
|
238
252
|
|
|
239
253
|
// Parse keyPrefix: accept either { keyPrefix: 'x' } or a plain string arg or simple identifier/template literal
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
// When the call is useTranslation(lng, ns) prefer the 3rd arg for keyPrefix; otherwise use configured keyPrefixArg.
|
|
255
|
+
const possibleKeyPrefixArg = isLngNs ? thirdArg : callExpr.arguments?.[hookConfig.keyPrefixArg ?? 1]?.expression
|
|
256
|
+
const kpArg = possibleKeyPrefixArg
|
|
257
|
+
if (kpArg?.type === 'ObjectExpression') {
|
|
258
|
+
const keyPrefixProp = kpArg.properties.find(
|
|
242
259
|
prop => prop.type === 'KeyValueProperty' &&
|
|
243
260
|
prop.key.type === 'Identifier' &&
|
|
244
261
|
prop.key.value === 'keyPrefix'
|
|
@@ -246,13 +263,13 @@ export class ScopeManager {
|
|
|
246
263
|
if (keyPrefixProp?.type === 'KeyValueProperty' && keyPrefixProp.value.type === 'StringLiteral') {
|
|
247
264
|
keyPrefix = keyPrefixProp.value.value
|
|
248
265
|
}
|
|
249
|
-
} else if (
|
|
266
|
+
} else if (kpArg?.type === 'StringLiteral') {
|
|
250
267
|
// allow keyPrefix as direct string argument
|
|
251
|
-
keyPrefix =
|
|
252
|
-
} else if (
|
|
253
|
-
keyPrefix = this.resolveSimpleStringIdentifier(
|
|
254
|
-
} else if (
|
|
255
|
-
const tpl =
|
|
268
|
+
keyPrefix = kpArg.value
|
|
269
|
+
} else if (kpArg?.type === 'Identifier') {
|
|
270
|
+
keyPrefix = this.resolveSimpleStringIdentifier(kpArg.value)
|
|
271
|
+
} else if (kpArg?.type === 'TemplateLiteral') {
|
|
272
|
+
const tpl = kpArg as TemplateLiteral
|
|
256
273
|
if ((tpl.expressions || []).length === 0) {
|
|
257
274
|
keyPrefix = tpl.quasis?.[0]?.cooked ?? undefined
|
|
258
275
|
}
|
|
@@ -312,28 +329,44 @@ export class ScopeManager {
|
|
|
312
329
|
// If we couldn't find a `t` function being declared, exit
|
|
313
330
|
if (!variableName) return
|
|
314
331
|
|
|
315
|
-
|
|
316
|
-
const
|
|
332
|
+
const firstArg = callExpr.arguments?.[0]?.expression
|
|
333
|
+
const secondArg = callExpr.arguments?.[1]?.expression
|
|
334
|
+
const thirdArg = callExpr.arguments?.[2]?.expression
|
|
317
335
|
|
|
318
336
|
let defaultNs: string | undefined
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
337
|
+
let keyPrefix: string | undefined
|
|
338
|
+
// Heuristic to detect language-like strings (e.g. "en", "pt-BR")
|
|
339
|
+
const looksLikeLanguage = (s: string) => /^[a-z]{2,3}([-_][A-Za-z0-9-]+)?$/i.test(s)
|
|
340
|
+
|
|
341
|
+
// Respect explicit hook configuration. If nsArg === -1, do not treat first/second arg as namespace.
|
|
342
|
+
const isLngNs = (hookConfig.nsArg === undefined || hookConfig.nsArg !== -1) &&
|
|
343
|
+
firstArg?.type === 'StringLiteral' &&
|
|
344
|
+
secondArg?.type === 'StringLiteral' &&
|
|
345
|
+
looksLikeLanguage(firstArg.value)
|
|
346
|
+
|
|
347
|
+
if (isLngNs) {
|
|
348
|
+
// useTranslation(lng, ns)
|
|
349
|
+
defaultNs = secondArg.value
|
|
350
|
+
} else if (hookConfig.nsArg !== -1 && firstArg?.type === 'StringLiteral') {
|
|
351
|
+
// useTranslation(ns)
|
|
352
|
+
defaultNs = firstArg.value
|
|
353
|
+
} else if (hookConfig.nsArg !== -1 && firstArg?.type === 'ArrayExpression' && firstArg.elements[0]?.expression.type === 'StringLiteral') {
|
|
354
|
+
defaultNs = firstArg.elements[0].expression.value
|
|
323
355
|
}
|
|
324
356
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
357
|
+
// Determine keyPrefix: when using useTranslation(lng, ns) prefer the 3rd arg
|
|
358
|
+
// otherwise use the configured keyPrefixArg position.
|
|
359
|
+
const optionsArg = isLngNs ? thirdArg : callExpr.arguments?.[hookConfig.keyPrefixArg ?? 1]?.expression
|
|
360
|
+
const kpArg = optionsArg
|
|
361
|
+
if (kpArg?.type === 'ObjectExpression') {
|
|
362
|
+
const kp = getObjectPropValue(kpArg, 'keyPrefix')
|
|
329
363
|
keyPrefix = typeof kp === 'string' ? kp : undefined
|
|
330
|
-
} else if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const tpl = optionsArg as TemplateLiteral
|
|
364
|
+
} else if (kpArg?.type === 'StringLiteral') {
|
|
365
|
+
keyPrefix = kpArg.value
|
|
366
|
+
} else if (kpArg?.type === 'Identifier') {
|
|
367
|
+
keyPrefix = this.resolveSimpleStringIdentifier(kpArg.value)
|
|
368
|
+
} else if (kpArg?.type === 'TemplateLiteral') {
|
|
369
|
+
const tpl = kpArg as TemplateLiteral
|
|
337
370
|
if ((tpl.expressions || []).length === 0) {
|
|
338
371
|
keyPrefix = tpl.quasis?.[0]?.cooked ?? undefined
|
|
339
372
|
}
|
|
@@ -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;IACrC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,eAAe,CAAY;gBAGjC,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;IACI,gBAAgB,IAAK,IAAI;IAIhC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;
|
|
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;IACpC,OAAO,CAAC,eAAe,CAAY;gBAGjC,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;IACI,gBAAgB,IAAK,IAAI;IAIhC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI;IAyWxG;;;;;;OAMG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;IA2C9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA6LxB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/scope-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAmC,MAAM,WAAW,CAAA;AACpF,OAAO,KAAK,EAAE,SAAS,EAA4B,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAG5F,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,KAAK,CAAqE;IAGlF,OAAO,CAAC,eAAe,CAAiC;gBAE3C,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;IAI1D;;;;;;OAMG;IACI,KAAK,IAAK,IAAI;IAMrB;;;OAGG;IACH,UAAU,IAAK,IAAI;IAInB;;;OAGG;IACH,SAAS,IAAK,IAAI;IAIlB;;;;;;OAMG;IACH,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAUnD;;;;;;OAMG;IACH,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAkBrD,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAIrC;;;;;;;;;;OAUG;IACH,wBAAwB,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAwDzD;;;;;;;;OAQG;IACH,OAAO,CAAC,+BAA+B;
|
|
1
|
+
{"version":3,"file":"scope-manager.d.ts","sourceRoot":"","sources":["../../../src/extractor/parsers/scope-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAmC,MAAM,WAAW,CAAA;AACpF,OAAO,KAAK,EAAE,SAAS,EAA4B,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAG5F,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,KAAK,CAAqE;IAGlF,OAAO,CAAC,eAAe,CAAiC;gBAE3C,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC;IAI1D;;;;;;OAMG;IACI,KAAK,IAAK,IAAI;IAMrB;;;OAGG;IACH,UAAU,IAAK,IAAI;IAInB;;;OAGG;IACH,SAAS,IAAK,IAAI;IAIlB;;;;;;OAMG;IACH,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAUnD;;;;;;OAMG;IACH,eAAe,CAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAkBrD,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAIrC;;;;;;;;;;OAUG;IACH,wBAAwB,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAwDzD;;;;;;;;OAQG;IACH,OAAO,CAAC,+BAA+B;IA6FvC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,8BAA8B;IAiFtC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;;;OASG;IACH,OAAO,CAAC,qCAAqC;CAuB9C"}
|