@inline-i18n-multi/cli 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,12 +14,23 @@ npm install -g @inline-i18n-multi/cli
14
14
 
15
15
  ## Commands
16
16
 
17
- ### Extract Translations
17
+ ### Extract Translations (v0.9.0)
18
18
 
19
- Extract all translations from your codebase:
19
+ Extract all inline translations from your codebase into a structured JSON file:
20
20
 
21
21
  ```bash
22
22
  npx inline-i18n extract --output translations.json
23
+ npx inline-i18n extract --src ./src --output i18n/translations.json
24
+ ```
25
+
26
+ The extracted file contains all `it()`, `T`, and key-based translations found in source files, grouped by file path:
27
+
28
+ ```json
29
+ {
30
+ "src/Header.tsx": [
31
+ { "key": "greeting", "translations": { "en": "Hello", "ko": "안녕하세요" } }
32
+ ]
33
+ }
23
34
  ```
24
35
 
25
36
  ### Check Missing Translations
@@ -100,6 +111,31 @@ Generate a translation coverage report:
100
111
  npx inline-i18n report
101
112
  ```
102
113
 
114
+ ### Watch Mode (v0.9.0)
115
+
116
+ Run `validate` or `typegen` in watch mode to automatically re-run on file changes:
117
+
118
+ ```bash
119
+ npx inline-i18n validate --watch
120
+ npx inline-i18n typegen --output src/i18n.d.ts --watch
121
+ ```
122
+
123
+ Watch mode monitors your source directory for changes and re-executes the command on each save. Useful during development to catch translation issues or regenerate types in real time.
124
+
125
+ ### Context System Support (v0.9.0)
126
+
127
+ The CLI commands (`extract`, `validate`, `typegen`) recognize contextual translation keys using the `key#context` convention:
128
+
129
+ ```json
130
+ {
131
+ "greeting": "Hello",
132
+ "greeting#formal": "Good day",
133
+ "greeting#casual": "Hey"
134
+ }
135
+ ```
136
+
137
+ Validation checks context variants for completeness across locales. Type generation includes context-aware overloads for `t()`.
138
+
103
139
  ## Options
104
140
 
105
141
  ```
@@ -109,6 +145,7 @@ npx inline-i18n report
109
145
  --format, -f Output format: json, csv (default: json)
110
146
  --strict Enable strict mode (ICU type consistency check)
111
147
  --unused Detect unused translation keys (validate command)
148
+ --watch, -w Watch mode for validate/typegen (re-run on file changes)
112
149
  ```
113
150
 
114
151
  ## Documentation
package/dist/bin.js CHANGED
@@ -526,7 +526,7 @@ async function validate(options = {}) {
526
526
  }
527
527
  console.log();
528
528
  }
529
- if (issues.length > 0 || unusedCount > 0) {
529
+ if ((issues.length > 0 || unusedCount > 0) && !options.noExit) {
530
530
  process.exit(1);
531
531
  }
532
532
  }
@@ -657,20 +657,138 @@ ${keyUnion}
657
657
  }
658
658
  }
659
659
 
660
+ // src/commands/extract.ts
661
+ var import_chalk6 = __toESM(require("chalk"));
662
+ var fs3 = __toESM(require("fs"));
663
+ var path2 = __toESM(require("path"));
664
+ async function extract(options = {}) {
665
+ const { cwd, output = "translations", format = "flat" } = options;
666
+ console.log(import_chalk6.default.blue("\nExtracting inline translations...\n"));
667
+ const entries = await parseProject({ cwd });
668
+ if (entries.length === 0) {
669
+ console.log(import_chalk6.default.yellow("No translations found."));
670
+ return;
671
+ }
672
+ const byLocale = {};
673
+ const basePath = cwd || process.cwd();
674
+ for (const entry of entries) {
675
+ for (const [locale, text] of Object.entries(entry.translations)) {
676
+ if (!byLocale[locale]) byLocale[locale] = {};
677
+ const relativePath = entry.file.replace(basePath + "/", "");
678
+ const key = `${relativePath}:${entry.line}`;
679
+ byLocale[locale][key] = text;
680
+ }
681
+ }
682
+ const outputDir = path2.resolve(basePath, output);
683
+ if (!fs3.existsSync(outputDir)) {
684
+ fs3.mkdirSync(outputDir, { recursive: true });
685
+ }
686
+ const locales = Object.keys(byLocale).sort();
687
+ for (const locale of locales) {
688
+ const translations = byLocale[locale];
689
+ let content;
690
+ if (format === "nested") {
691
+ const nested = buildNestedObject(translations);
692
+ content = JSON.stringify(nested, null, 2) + "\n";
693
+ } else {
694
+ content = JSON.stringify(translations, null, 2) + "\n";
695
+ }
696
+ const filePath = path2.join(outputDir, `${locale}.json`);
697
+ fs3.writeFileSync(filePath, content);
698
+ console.log(
699
+ import_chalk6.default.green(` ${locale}.json`) + import_chalk6.default.gray(` (${Object.keys(translations).length} keys)`)
700
+ );
701
+ }
702
+ console.log(import_chalk6.default.gray(`
703
+ Extracted ${entries.length} translation(s) to ${output}/`));
704
+ }
705
+ function buildNestedObject(flat) {
706
+ const result = {};
707
+ for (const [key, value] of Object.entries(flat)) {
708
+ const parts = key.split(".");
709
+ let current = result;
710
+ for (let i = 0; i < parts.length - 1; i++) {
711
+ const part = parts[i];
712
+ if (!current[part] || typeof current[part] !== "object") {
713
+ current[part] = {};
714
+ }
715
+ current = current[part];
716
+ }
717
+ current[parts[parts.length - 1]] = value;
718
+ }
719
+ return result;
720
+ }
721
+
722
+ // src/watch.ts
723
+ var import_chokidar = require("chokidar");
724
+ var import_chalk7 = __toESM(require("chalk"));
725
+ function startWatch(options) {
726
+ const { cwd, patterns, ignore, onChange, label } = options;
727
+ console.log(import_chalk7.default.blue(`
728
+ Watching for changes (${label})...
729
+ `));
730
+ console.log(import_chalk7.default.gray("Press Ctrl+C to stop\n"));
731
+ const watcher = (0, import_chokidar.watch)(patterns, {
732
+ cwd,
733
+ ignored: ignore,
734
+ ignoreInitial: true
735
+ });
736
+ let debounceTimer = null;
737
+ const handleChange = (filePath) => {
738
+ if (debounceTimer) clearTimeout(debounceTimer);
739
+ debounceTimer = setTimeout(async () => {
740
+ console.log(import_chalk7.default.gray(`
741
+ Change detected: ${filePath}`));
742
+ console.log(import_chalk7.default.gray("-".repeat(40)));
743
+ try {
744
+ await onChange();
745
+ } catch {
746
+ }
747
+ console.log(import_chalk7.default.gray(`
748
+ Watching for changes (${label})...`));
749
+ }, 300);
750
+ };
751
+ watcher.on("change", handleChange);
752
+ watcher.on("add", handleChange);
753
+ }
754
+
660
755
  // src/bin.ts
661
756
  var program = new import_commander.Command();
662
- program.name("inline-i18n").description("CLI tools for inline-i18n-multi").version("0.8.0");
757
+ program.name("inline-i18n").description("CLI tools for inline-i18n-multi").version("0.9.0");
663
758
  program.command("find <query>").description("Find translations containing the query text").option("-c, --cwd <path>", "Working directory").action(async (query, options) => {
664
759
  await find({ query, cwd: options.cwd });
665
760
  });
666
- program.command("validate").description("Validate translation consistency").option("-c, --cwd <path>", "Working directory").option("-l, --locales <locales...>", "Required locales to check").option("-s, --strict", "Enable strict mode (ICU type consistency check)").option("-u, --unused", "Detect unused dictionary keys").action(async (options) => {
667
- await validate(options);
761
+ program.command("validate").description("Validate translation consistency").option("-c, --cwd <path>", "Working directory").option("-l, --locales <locales...>", "Required locales to check").option("-s, --strict", "Enable strict mode (ICU type consistency check)").option("-u, --unused", "Detect unused dictionary keys").option("-w, --watch", "Watch mode - re-validate on file changes").action(async (options) => {
762
+ await validate(options.watch ? { ...options, noExit: true } : options);
763
+ if (options.watch) {
764
+ const cwd = options.cwd || process.cwd();
765
+ startWatch({
766
+ cwd,
767
+ patterns: ["**/*.{ts,tsx,js,jsx}"],
768
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**"],
769
+ onChange: () => validate({ ...options, noExit: true }),
770
+ label: "validate"
771
+ });
772
+ }
668
773
  });
669
774
  program.command("coverage").description("Show translation coverage by locale").option("-c, --cwd <path>", "Working directory").option("-l, --locales <locales...>", "Locales to check", ["ko", "en"]).action(async (options) => {
670
775
  await coverage(options);
671
776
  });
672
- program.command("typegen").description("Generate TypeScript types for translation keys").option("-c, --cwd <path>", "Working directory").option("-o, --output <path>", "Output file path", "src/i18n.d.ts").action(async (options) => {
777
+ program.command("typegen").description("Generate TypeScript types for translation keys").option("-c, --cwd <path>", "Working directory").option("-o, --output <path>", "Output file path", "src/i18n.d.ts").option("-w, --watch", "Watch mode - regenerate types on file changes").action(async (options) => {
673
778
  await typegen(options);
779
+ if (options.watch) {
780
+ const cwd = options.cwd || process.cwd();
781
+ startWatch({
782
+ cwd,
783
+ patterns: ["**/*.{ts,tsx,js,jsx}"],
784
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**"],
785
+ onChange: () => typegen(options),
786
+ label: "typegen"
787
+ });
788
+ }
789
+ });
790
+ program.command("extract").description("Extract inline translations to JSON files").option("-c, --cwd <path>", "Working directory").option("-o, --output <path>", "Output directory", "translations").option("-f, --format <format>", "Output format (flat|nested)", "flat").action(async (options) => {
791
+ await extract(options);
674
792
  });
675
793
  program.parse();
676
794
  //# sourceMappingURL=bin.js.map
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/commands/find.ts","../src/parser.ts","../src/commands/validate.ts","../src/commands/unused.ts","../src/commands/coverage.ts","../src/commands/typegen.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { find } from './commands/find'\nimport { validate } from './commands/validate'\nimport { coverage } from './commands/coverage'\nimport { typegen } from './commands/typegen'\n\nconst program = new Command()\n\nprogram\n .name('inline-i18n')\n .description('CLI tools for inline-i18n-multi')\n .version('0.8.0')\n\nprogram\n .command('find <query>')\n .description('Find translations containing the query text')\n .option('-c, --cwd <path>', 'Working directory')\n .action(async (query: string, options: { cwd?: string }) => {\n await find({ query, cwd: options.cwd })\n })\n\nprogram\n .command('validate')\n .description('Validate translation consistency')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-l, --locales <locales...>', 'Required locales to check')\n .option('-s, --strict', 'Enable strict mode (ICU type consistency check)')\n .option('-u, --unused', 'Detect unused dictionary keys')\n .action(async (options: { cwd?: string; locales?: string[]; strict?: boolean; unused?: boolean }) => {\n await validate(options)\n })\n\nprogram\n .command('coverage')\n .description('Show translation coverage by locale')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-l, --locales <locales...>', 'Locales to check', ['ko', 'en'])\n .action(async (options: { cwd?: string; locales: string[] }) => {\n await coverage(options)\n })\n\nprogram\n .command('typegen')\n .description('Generate TypeScript types for translation keys')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-o, --output <path>', 'Output file path', 'src/i18n.d.ts')\n .action(async (options: { cwd?: string; output?: string }) => {\n await typegen(options)\n })\n\nprogram.parse()\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface FindOptions {\n query: string\n cwd?: string\n}\n\nexport async function find(options: FindOptions): Promise<void> {\n const { query, cwd } = options\n\n console.log(chalk.blue(`\\nSearching for: \"${query}\"\\n`))\n\n const entries = await parseProject({ cwd })\n const results: TranslationEntry[] = []\n\n const lowerQuery = query.toLowerCase()\n\n for (const entry of entries) {\n const values = Object.values(entry.translations)\n const matches = values.some((v) => v.toLowerCase().includes(lowerQuery))\n\n if (matches) {\n results.push(entry)\n }\n }\n\n if (results.length === 0) {\n console.log(chalk.yellow('No results found.'))\n return\n }\n\n console.log(chalk.green(`Found ${results.length} occurrence(s):\\n`))\n\n for (const result of results) {\n const relativePath = result.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(`${relativePath}:${result.line}:${result.column}`))\n\n for (const [locale, text] of Object.entries(result.translations)) {\n const highlighted = text.replace(\n new RegExp(`(${query})`, 'gi'),\n chalk.yellow('$1')\n )\n console.log(` ${chalk.cyan(locale)}: ${highlighted}`)\n }\n console.log()\n }\n}\n","import { parse } from '@babel/parser'\nimport traverse from '@babel/traverse'\nimport * as fs from 'fs'\nimport fg from 'fast-glob'\n\n// v0.8.0: Dictionary key and t() call extraction\n\nexport interface DictionaryKeyEntry {\n file: string\n line: number\n namespace: string\n keys: string[]\n}\n\nexport interface TCallEntry {\n file: string\n line: number\n key: string\n}\n\nexport interface ICUTypeInfo {\n variable: string\n type: string\n}\n\nexport interface TranslationEntry {\n file: string\n line: number\n column: number\n translations: Record<string, string>\n variables: string[]\n /** ICU type information per locale (v0.7.0) */\n icuTypes?: Record<string, ICUTypeInfo[]>\n}\n\ninterface ParseOptions {\n cwd?: string\n include?: string[]\n exclude?: string[]\n}\n\nconst IT_FUNCTION_NAMES = [\n 'it',\n 'it_ja', 'it_zh', 'it_es', 'it_fr', 'it_de',\n 'en_ja', 'en_zh', 'en_es', 'en_fr', 'en_de',\n 'ja_zh', 'ja_es', 'zh_es',\n]\n\nconst PAIR_MAPPING: Record<string, [string, string]> = {\n it: ['ko', 'en'],\n it_ja: ['ko', 'ja'],\n it_zh: ['ko', 'zh'],\n it_es: ['ko', 'es'],\n it_fr: ['ko', 'fr'],\n it_de: ['ko', 'de'],\n en_ja: ['en', 'ja'],\n en_zh: ['en', 'zh'],\n en_es: ['en', 'es'],\n en_fr: ['en', 'fr'],\n en_de: ['en', 'de'],\n ja_zh: ['ja', 'zh'],\n ja_es: ['ja', 'es'],\n zh_es: ['zh', 'es'],\n}\n\nfunction extractVariables(text: string): string[] {\n const matches = text.match(/\\{(\\w+)\\}/g)\n if (!matches) return []\n return matches.map((m) => m.slice(1, -1))\n}\n\nconst ICU_TYPE_PATTERN = /\\{(\\w+),\\s*(\\w+)/g\n\nfunction extractICUTypes(text: string): ICUTypeInfo[] {\n const types: ICUTypeInfo[] = []\n let match: RegExpExecArray | null\n ICU_TYPE_PATTERN.lastIndex = 0\n while ((match = ICU_TYPE_PATTERN.exec(text)) !== null) {\n types.push({ variable: match[1]!, type: match[2]! })\n }\n return types\n}\n\nfunction parseFile(filePath: string): TranslationEntry[] {\n const entries: TranslationEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier') return\n if (!IT_FUNCTION_NAMES.includes(callee.name)) return\n\n const funcName = callee.name\n const args = node.arguments\n const loc = node.loc\n\n if (!loc) return\n\n const entry: TranslationEntry = {\n file: filePath,\n line: loc.start.line,\n column: loc.start.column,\n translations: {},\n variables: [],\n }\n\n if (args[0]?.type === 'ObjectExpression') {\n const obj = args[0]\n for (const prop of obj.properties) {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.value.type === 'StringLiteral'\n ) {\n entry.translations[prop.key.name] = prop.value.value\n entry.variables.push(...extractVariables(prop.value.value))\n // Extract ICU type info (v0.7.0)\n const types = extractICUTypes(prop.value.value)\n if (types.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[prop.key.name] = types\n }\n }\n }\n } else if (\n args[0]?.type === 'StringLiteral' &&\n args[1]?.type === 'StringLiteral'\n ) {\n const [lang1, lang2] = PAIR_MAPPING[funcName] || ['ko', 'en']\n entry.translations[lang1] = args[0].value\n entry.translations[lang2] = args[1].value\n entry.variables.push(...extractVariables(args[0].value))\n entry.variables.push(...extractVariables(args[1].value))\n // Extract ICU type info (v0.7.0)\n const types1 = extractICUTypes(args[0].value)\n if (types1.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang1] = types1\n }\n const types2 = extractICUTypes(args[1].value)\n if (types2.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang2] = types2\n }\n }\n\n entry.variables = [...new Set(entry.variables)]\n\n if (Object.keys(entry.translations).length > 0) {\n entries.push(entry)\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Flatten nested ObjectExpression to dot-notation keys\nfunction flattenObjectKeys(\n node: { type: string; properties?: unknown[] },\n prefix: string = '',\n): string[] {\n const keys: string[] = []\n if (node.type !== 'ObjectExpression' || !node.properties) return keys\n\n for (const prop of node.properties as Array<{\n type: string\n key: { type: string; name?: string; value?: string }\n value: { type: string; properties?: unknown[] }\n }>) {\n if (prop.type !== 'ObjectProperty') continue\n\n let propName: string | undefined\n if (prop.key.type === 'Identifier') propName = prop.key.name\n else if (prop.key.type === 'StringLiteral') propName = prop.key.value\n\n if (!propName) continue\n\n const fullKey = prefix ? `${prefix}.${propName}` : propName\n\n if (prop.value.type === 'StringLiteral') {\n keys.push(fullKey)\n } else if (prop.value.type === 'ObjectExpression') {\n keys.push(...flattenObjectKeys(prop.value, fullKey))\n }\n }\n return keys\n}\n\n// v0.8.0: Extract dictionary keys from loadDictionaries() calls\nexport function parseDictionaryKeys(filePath: string): DictionaryKeyEntry[] {\n const entries: DictionaryKeyEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 'loadDictionaries') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'ObjectExpression') return\n\n // Second argument is optional namespace\n let namespace = 'default'\n if (args[1]?.type === 'StringLiteral') {\n namespace = args[1].value\n }\n\n // First argument: { locale: { key: value } }\n // Collect keys from the first locale's dict (all locales should have same keys)\n const dictObj = args[0]\n const allKeys = new Set<string>()\n\n for (const localeProp of dictObj.properties as Array<{\n type: string\n value: { type: string; properties?: unknown[] }\n }>) {\n if (localeProp.type !== 'ObjectProperty') continue\n if (localeProp.value.type !== 'ObjectExpression') continue\n\n const localeKeys = flattenObjectKeys(localeProp.value)\n for (const key of localeKeys) {\n allKeys.add(key)\n }\n }\n\n if (allKeys.size > 0) {\n entries.push({\n file: filePath,\n line: loc.start.line,\n namespace,\n keys: [...allKeys],\n })\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Extract t() call sites\nexport function parseTCalls(filePath: string): TCallEntry[] {\n const entries: TCallEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 't') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'StringLiteral') return\n\n entries.push({\n file: filePath,\n line: loc.start.line,\n key: args[0].value,\n })\n },\n })\n\n return entries\n}\n\nexport async function extractProjectDictionaryKeys(options: ParseOptions = {}): Promise<DictionaryKeyEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: DictionaryKeyEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseDictionaryKeys(file))\n }\n\n return allEntries\n}\n\nexport async function extractProjectTCalls(options: ParseOptions = {}): Promise<TCallEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: TCallEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseTCalls(file))\n }\n\n return allEntries\n}\n\nexport async function parseProject(options: ParseOptions = {}): Promise<TranslationEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, {\n cwd,\n ignore: exclude,\n absolute: true,\n })\n\n const allEntries: TranslationEntry[] = []\n\n for (const file of files) {\n const entries = parseFile(file)\n allEntries.push(...entries)\n }\n\n return allEntries\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\nimport { unused } from './unused'\n\ninterface ValidateOptions {\n cwd?: string\n locales?: string[]\n strict?: boolean\n unused?: boolean\n}\n\ninterface Issue {\n type: 'inconsistent' | 'missing' | 'variable_mismatch' | 'icu_type_mismatch'\n message: string\n entries: TranslationEntry[]\n details?: string[]\n}\n\nfunction checkVariableConsistency(entry: TranslationEntry): Issue | null {\n const varsByLocale: { locale: string; vars: string[] }[] = []\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n const matches = text.match(/\\{(\\w+)\\}/g) || []\n const varNames = [...new Set(matches.map((v) => v.slice(1, -1)))].sort()\n varsByLocale.push({ locale, vars: varNames })\n }\n\n if (varsByLocale.length < 2) return null\n\n const reference = varsByLocale[0]!\n const details: string[] = []\n\n for (let i = 1; i < varsByLocale.length; i++) {\n const current = varsByLocale[i]!\n const refSet = new Set(reference.vars)\n const curSet = new Set(current.vars)\n\n const onlyInRef = reference.vars.filter((v) => !curSet.has(v))\n const onlyInCur = current.vars.filter((v) => !refSet.has(v))\n\n if (onlyInRef.length > 0) {\n details.push(\n `${reference.locale} has {${onlyInRef.join('}, {')}} missing in ${current.locale}`,\n )\n }\n if (onlyInCur.length > 0) {\n details.push(\n `${current.locale} has {${onlyInCur.join('}, {')}} missing in ${reference.locale}`,\n )\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'variable_mismatch',\n message: 'Variable mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nfunction checkICUTypeConsistency(entry: TranslationEntry): Issue | null {\n if (!entry.icuTypes) return null\n\n const locales = Object.keys(entry.icuTypes)\n if (locales.length < 2) return null\n\n const details: string[] = []\n const reference = locales[0]!\n const refTypes = entry.icuTypes[reference]!\n\n for (let i = 1; i < locales.length; i++) {\n const locale = locales[i]!\n const curTypes = entry.icuTypes[locale]!\n\n for (const refType of refTypes) {\n const match = curTypes.find((t: { variable: string; type: string }) => t.variable === refType.variable)\n if (match && match.type !== refType.type) {\n details.push(\n `{${refType.variable}} is \"${refType.type}\" in ${reference} but \"${match.type}\" in ${locale}`,\n )\n }\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'icu_type_mismatch',\n message: 'ICU type mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nexport async function validate(options: ValidateOptions = {}): Promise<void> {\n const { cwd, locales, strict, unused: checkUnused } = options\n\n console.log(chalk.blue('\\nValidating translations...\\n'))\n\n const entries = await parseProject({ cwd })\n const issues: Issue[] = []\n\n // group by first language text (usually ko)\n const groups = new Map<string, TranslationEntry[]>()\n\n for (const entry of entries) {\n const key = Object.values(entry.translations)[0] || ''\n if (!groups.has(key)) {\n groups.set(key, [])\n }\n groups.get(key)!.push(entry)\n }\n\n // check for inconsistent translations\n for (const [key, group] of groups) {\n if (group.length < 2) continue\n\n const translationSets = group.map((e) => JSON.stringify(e.translations))\n const uniqueSets = [...new Set(translationSets)]\n\n if (uniqueSets.length > 1) {\n issues.push({\n type: 'inconsistent',\n message: `Inconsistent translations for \"${key}\"`,\n entries: group,\n })\n }\n }\n\n // check for missing locales\n if (locales && locales.length > 0) {\n for (const entry of entries) {\n const missing = locales.filter((l) => !entry.translations[l])\n\n if (missing.length > 0) {\n issues.push({\n type: 'missing',\n message: `Missing locales: ${missing.join(', ')}`,\n entries: [entry],\n })\n }\n }\n }\n\n // check for variable name consistency (enhanced in v0.7.0)\n for (const entry of entries) {\n const issue = checkVariableConsistency(entry)\n if (issue) issues.push(issue)\n }\n\n // check for ICU type consistency (strict mode, v0.7.0)\n if (strict) {\n for (const entry of entries) {\n const issue = checkICUTypeConsistency(entry)\n if (issue) issues.push(issue)\n }\n }\n\n // unused key detection (v0.8.0)\n let unusedCount = 0\n if (checkUnused) {\n const result = await unused({ cwd })\n unusedCount = result.unusedKeys.length\n }\n\n // print results\n if (issues.length === 0 && unusedCount === 0) {\n console.log(chalk.green('All translations are valid!\\n'))\n console.log(chalk.gray(`Checked ${entries.length} translation(s)`))\n if (strict) {\n console.log(chalk.gray('(strict mode enabled)'))\n }\n if (checkUnused) {\n console.log(chalk.gray('(unused key detection enabled)'))\n }\n return\n }\n\n console.log(chalk.red(`Found ${issues.length} issue(s):\\n`))\n\n for (const issue of issues) {\n console.log(` ${chalk.yellow(issue.message)}`)\n\n for (const entry of issue.entries) {\n const relativePath = entry.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n console.log(` ${chalk.cyan(locale)}: ${text}`)\n }\n }\n\n if (issue.details && issue.details.length > 0) {\n for (const detail of issue.details) {\n console.log(chalk.gray(` → ${detail}`))\n }\n }\n\n console.log()\n }\n\n if (issues.length > 0 || unusedCount > 0) {\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface UnusedKey {\n namespace: string\n key: string\n definedIn: string\n line: number\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function unused(options: { cwd?: string } = {}): Promise<{ unusedKeys: UnusedKey[] }> {\n const { cwd } = options\n\n console.log(chalk.blue('\\nDetecting unused translations...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n // Build set of used keys (normalized: namespace:key or key for default)\n const usedKeys = new Set<string>()\n for (const call of tCalls) {\n usedKeys.add(call.key)\n // Also add with default namespace if no namespace prefix\n if (!call.key.includes(':')) {\n usedKeys.add(call.key)\n }\n }\n\n // Check each dictionary key against used keys\n const unusedKeys: UnusedKey[] = []\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n\n // Check if key is directly used\n if (usedKeys.has(fullKey)) continue\n\n // Check if this is a plural suffix variant (e.g. count_one, count_other)\n // and the base key is used via t('items.count', { count: N })\n let isPluralVariant = false\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n if (usedKeys.has(fullBaseKey)) {\n isPluralVariant = true\n break\n }\n }\n }\n if (isPluralVariant) continue\n\n unusedKeys.push({\n namespace: entry.namespace,\n key: fullKey,\n definedIn: entry.file,\n line: entry.line,\n })\n }\n }\n\n // Report results\n if (unusedKeys.length === 0) {\n const totalKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n console.log(chalk.green('No unused translations found!\\n'))\n console.log(chalk.gray(`Checked ${totalKeys} dictionary key(s) against ${tCalls.length} t() call(s)`))\n return { unusedKeys }\n }\n\n console.log(chalk.yellow(`Found ${unusedKeys.length} unused translation key(s):\\n`))\n for (const item of unusedKeys) {\n const relativePath = item.definedIn.replace(process.cwd() + '/', '')\n console.log(` ${chalk.red('-')} ${chalk.cyan(item.key)}`)\n console.log(chalk.gray(` defined in ${relativePath}:${item.line}`))\n }\n\n console.log()\n return { unusedKeys }\n}\n","import chalk from 'chalk'\nimport { parseProject } from '../parser'\n\ninterface CoverageOptions {\n cwd?: string\n locales: string[]\n}\n\ninterface LocaleCoverage {\n locale: string\n total: number\n translated: number\n percentage: number\n}\n\nexport async function coverage(options: CoverageOptions): Promise<void> {\n const { cwd, locales } = options\n\n console.log(chalk.blue('\\nAnalyzing translation coverage...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n const coverageData: LocaleCoverage[] = []\n\n for (const locale of locales) {\n let translated = 0\n\n for (const entry of entries) {\n if (entry.translations[locale]) {\n translated++\n }\n }\n\n const percentage = Math.round((translated / entries.length) * 100)\n\n coverageData.push({\n locale,\n total: entries.length,\n translated,\n percentage,\n })\n }\n\n // print coverage table\n console.log(chalk.bold('Translation Coverage:\\n'))\n\n const maxLocaleLen = Math.max(...locales.map((l) => l.length), 6)\n\n console.log(\n chalk.gray(\n `${'Locale'.padEnd(maxLocaleLen)} ${'Coverage'.padStart(10)} ${'Translated'.padStart(12)}`\n )\n )\n console.log(chalk.gray('─'.repeat(maxLocaleLen + 26)))\n\n for (const data of coverageData) {\n const color =\n data.percentage === 100 ? chalk.green :\n data.percentage >= 80 ? chalk.yellow : chalk.red\n\n const bar = createProgressBar(data.percentage, 10)\n const percentStr = `${data.percentage}%`.padStart(4)\n\n console.log(\n `${data.locale.padEnd(maxLocaleLen)} ${color(bar)} ${color(percentStr)} ${chalk.gray(`${data.translated}/${data.total}`)}`\n )\n }\n\n console.log()\n\n // summary\n const fullyCovered = coverageData.filter((d) => d.percentage === 100).length\n const partiallyCovered = coverageData.filter((d) => d.percentage > 0 && d.percentage < 100).length\n const notCovered = coverageData.filter((d) => d.percentage === 0).length\n\n if (fullyCovered === locales.length) {\n console.log(chalk.green('All locales are fully translated!'))\n } else {\n console.log(chalk.gray(`Full: ${fullyCovered}, Partial: ${partiallyCovered}, Empty: ${notCovered}`))\n }\n}\n\nfunction createProgressBar(percentage: number, width: number): string {\n const filled = Math.round((percentage / 100) * width)\n const empty = width - filled\n\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport chalk from 'chalk'\nimport { extractProjectDictionaryKeys } from '../parser'\n\ninterface TypegenOptions {\n cwd?: string\n output?: string\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function typegen(options: TypegenOptions = {}): Promise<void> {\n const { cwd, output = 'src/i18n.d.ts' } = options\n\n console.log(chalk.blue('\\nGenerating TypeScript types...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n\n // Collect all unique full keys (namespace:key or key)\n const allKeys = new Set<string>()\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n allKeys.add(fullKey)\n\n // Also add plural base keys (strip _one, _other, etc.)\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n allKeys.add(fullBaseKey)\n }\n }\n }\n }\n\n if (allKeys.size === 0) {\n console.log(chalk.yellow('No dictionary keys found. Make sure loadDictionaries() calls are present.'))\n return\n }\n\n const sortedKeys = [...allKeys].sort()\n\n // Generate the .d.ts content\n const keyUnion = sortedKeys.map(k => ` | '${k}'`).join('\\n')\n\n const content = `// Auto-generated by inline-i18n typegen\n// Do not edit manually. Re-run: npx inline-i18n typegen\n\nimport 'inline-i18n-multi'\n\ndeclare module 'inline-i18n-multi' {\n export type TranslationKey =\n${keyUnion}\n\n export function t(\n key: TranslationKey,\n vars?: TranslationVars,\n locale?: string\n ): string\n\n export function hasTranslation(\n key: TranslationKey,\n locale?: string\n ): boolean\n}\n`\n\n const outputPath = path.resolve(cwd || process.cwd(), output)\n const outputDir = path.dirname(outputPath)\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8')\n\n console.log(chalk.green(`Generated ${sortedKeys.length} translation key types`))\n console.log(chalk.gray(`Output: ${outputPath}\\n`))\n\n // Show sample\n const sample = sortedKeys.slice(0, 5)\n for (const key of sample) {\n console.log(` ${chalk.cyan(key)}`)\n }\n if (sortedKeys.length > 5) {\n console.log(chalk.gray(` ... and ${sortedKeys.length - 5} more`))\n }\n}\n"],"mappings":"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","names":["traverse","fg","chalk","import_chalk","import_chalk","chalk","chalk","import_chalk","chalk","fs","import_chalk","PLURAL_SUFFIXES","chalk"]}
1
+ {"version":3,"sources":["../src/bin.ts","../src/commands/find.ts","../src/parser.ts","../src/commands/validate.ts","../src/commands/unused.ts","../src/commands/coverage.ts","../src/commands/typegen.ts","../src/commands/extract.ts","../src/watch.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { find } from './commands/find'\nimport { validate } from './commands/validate'\nimport { coverage } from './commands/coverage'\nimport { typegen } from './commands/typegen'\nimport { extract } from './commands/extract'\nimport { startWatch } from './watch'\n\nconst program = new Command()\n\nprogram\n .name('inline-i18n')\n .description('CLI tools for inline-i18n-multi')\n .version('0.9.0')\n\nprogram\n .command('find <query>')\n .description('Find translations containing the query text')\n .option('-c, --cwd <path>', 'Working directory')\n .action(async (query: string, options: { cwd?: string }) => {\n await find({ query, cwd: options.cwd })\n })\n\nprogram\n .command('validate')\n .description('Validate translation consistency')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-l, --locales <locales...>', 'Required locales to check')\n .option('-s, --strict', 'Enable strict mode (ICU type consistency check)')\n .option('-u, --unused', 'Detect unused dictionary keys')\n .option('-w, --watch', 'Watch mode - re-validate on file changes')\n .action(async (options: { cwd?: string; locales?: string[]; strict?: boolean; unused?: boolean; watch?: boolean }) => {\n await validate(options.watch ? { ...options, noExit: true } : options)\n if (options.watch) {\n const cwd = options.cwd || process.cwd()\n startWatch({\n cwd,\n patterns: ['**/*.{ts,tsx,js,jsx}'],\n ignore: ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n onChange: () => validate({ ...options, noExit: true }),\n label: 'validate',\n })\n }\n })\n\nprogram\n .command('coverage')\n .description('Show translation coverage by locale')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-l, --locales <locales...>', 'Locales to check', ['ko', 'en'])\n .action(async (options: { cwd?: string; locales: string[] }) => {\n await coverage(options)\n })\n\nprogram\n .command('typegen')\n .description('Generate TypeScript types for translation keys')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-o, --output <path>', 'Output file path', 'src/i18n.d.ts')\n .option('-w, --watch', 'Watch mode - regenerate types on file changes')\n .action(async (options: { cwd?: string; output?: string; watch?: boolean }) => {\n await typegen(options)\n if (options.watch) {\n const cwd = options.cwd || process.cwd()\n startWatch({\n cwd,\n patterns: ['**/*.{ts,tsx,js,jsx}'],\n ignore: ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n onChange: () => typegen(options),\n label: 'typegen',\n })\n }\n })\n\nprogram\n .command('extract')\n .description('Extract inline translations to JSON files')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-o, --output <path>', 'Output directory', 'translations')\n .option('-f, --format <format>', 'Output format (flat|nested)', 'flat')\n .action(async (options: { cwd?: string; output?: string; format?: 'flat' | 'nested' }) => {\n await extract(options)\n })\n\nprogram.parse()\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface FindOptions {\n query: string\n cwd?: string\n}\n\nexport async function find(options: FindOptions): Promise<void> {\n const { query, cwd } = options\n\n console.log(chalk.blue(`\\nSearching for: \"${query}\"\\n`))\n\n const entries = await parseProject({ cwd })\n const results: TranslationEntry[] = []\n\n const lowerQuery = query.toLowerCase()\n\n for (const entry of entries) {\n const values = Object.values(entry.translations)\n const matches = values.some((v) => v.toLowerCase().includes(lowerQuery))\n\n if (matches) {\n results.push(entry)\n }\n }\n\n if (results.length === 0) {\n console.log(chalk.yellow('No results found.'))\n return\n }\n\n console.log(chalk.green(`Found ${results.length} occurrence(s):\\n`))\n\n for (const result of results) {\n const relativePath = result.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(`${relativePath}:${result.line}:${result.column}`))\n\n for (const [locale, text] of Object.entries(result.translations)) {\n const highlighted = text.replace(\n new RegExp(`(${query})`, 'gi'),\n chalk.yellow('$1')\n )\n console.log(` ${chalk.cyan(locale)}: ${highlighted}`)\n }\n console.log()\n }\n}\n","import { parse } from '@babel/parser'\nimport traverse from '@babel/traverse'\nimport * as fs from 'fs'\nimport fg from 'fast-glob'\n\n// v0.8.0: Dictionary key and t() call extraction\n\nexport interface DictionaryKeyEntry {\n file: string\n line: number\n namespace: string\n keys: string[]\n}\n\nexport interface TCallEntry {\n file: string\n line: number\n key: string\n}\n\nexport interface ICUTypeInfo {\n variable: string\n type: string\n}\n\nexport interface TranslationEntry {\n file: string\n line: number\n column: number\n translations: Record<string, string>\n variables: string[]\n /** ICU type information per locale (v0.7.0) */\n icuTypes?: Record<string, ICUTypeInfo[]>\n}\n\ninterface ParseOptions {\n cwd?: string\n include?: string[]\n exclude?: string[]\n}\n\nconst IT_FUNCTION_NAMES = [\n 'it',\n 'it_ja', 'it_zh', 'it_es', 'it_fr', 'it_de',\n 'en_ja', 'en_zh', 'en_es', 'en_fr', 'en_de',\n 'ja_zh', 'ja_es', 'zh_es',\n]\n\nconst PAIR_MAPPING: Record<string, [string, string]> = {\n it: ['ko', 'en'],\n it_ja: ['ko', 'ja'],\n it_zh: ['ko', 'zh'],\n it_es: ['ko', 'es'],\n it_fr: ['ko', 'fr'],\n it_de: ['ko', 'de'],\n en_ja: ['en', 'ja'],\n en_zh: ['en', 'zh'],\n en_es: ['en', 'es'],\n en_fr: ['en', 'fr'],\n en_de: ['en', 'de'],\n ja_zh: ['ja', 'zh'],\n ja_es: ['ja', 'es'],\n zh_es: ['zh', 'es'],\n}\n\nfunction extractVariables(text: string): string[] {\n const matches = text.match(/\\{(\\w+)\\}/g)\n if (!matches) return []\n return matches.map((m) => m.slice(1, -1))\n}\n\nconst ICU_TYPE_PATTERN = /\\{(\\w+),\\s*(\\w+)/g\n\nfunction extractICUTypes(text: string): ICUTypeInfo[] {\n const types: ICUTypeInfo[] = []\n let match: RegExpExecArray | null\n ICU_TYPE_PATTERN.lastIndex = 0\n while ((match = ICU_TYPE_PATTERN.exec(text)) !== null) {\n types.push({ variable: match[1]!, type: match[2]! })\n }\n return types\n}\n\nfunction parseFile(filePath: string): TranslationEntry[] {\n const entries: TranslationEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier') return\n if (!IT_FUNCTION_NAMES.includes(callee.name)) return\n\n const funcName = callee.name\n const args = node.arguments\n const loc = node.loc\n\n if (!loc) return\n\n const entry: TranslationEntry = {\n file: filePath,\n line: loc.start.line,\n column: loc.start.column,\n translations: {},\n variables: [],\n }\n\n if (args[0]?.type === 'ObjectExpression') {\n const obj = args[0]\n for (const prop of obj.properties) {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.value.type === 'StringLiteral'\n ) {\n entry.translations[prop.key.name] = prop.value.value\n entry.variables.push(...extractVariables(prop.value.value))\n // Extract ICU type info (v0.7.0)\n const types = extractICUTypes(prop.value.value)\n if (types.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[prop.key.name] = types\n }\n }\n }\n } else if (\n args[0]?.type === 'StringLiteral' &&\n args[1]?.type === 'StringLiteral'\n ) {\n const [lang1, lang2] = PAIR_MAPPING[funcName] || ['ko', 'en']\n entry.translations[lang1] = args[0].value\n entry.translations[lang2] = args[1].value\n entry.variables.push(...extractVariables(args[0].value))\n entry.variables.push(...extractVariables(args[1].value))\n // Extract ICU type info (v0.7.0)\n const types1 = extractICUTypes(args[0].value)\n if (types1.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang1] = types1\n }\n const types2 = extractICUTypes(args[1].value)\n if (types2.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang2] = types2\n }\n }\n\n entry.variables = [...new Set(entry.variables)]\n\n if (Object.keys(entry.translations).length > 0) {\n entries.push(entry)\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Flatten nested ObjectExpression to dot-notation keys\nfunction flattenObjectKeys(\n node: { type: string; properties?: unknown[] },\n prefix: string = '',\n): string[] {\n const keys: string[] = []\n if (node.type !== 'ObjectExpression' || !node.properties) return keys\n\n for (const prop of node.properties as Array<{\n type: string\n key: { type: string; name?: string; value?: string }\n value: { type: string; properties?: unknown[] }\n }>) {\n if (prop.type !== 'ObjectProperty') continue\n\n let propName: string | undefined\n if (prop.key.type === 'Identifier') propName = prop.key.name\n else if (prop.key.type === 'StringLiteral') propName = prop.key.value\n\n if (!propName) continue\n\n const fullKey = prefix ? `${prefix}.${propName}` : propName\n\n if (prop.value.type === 'StringLiteral') {\n keys.push(fullKey)\n } else if (prop.value.type === 'ObjectExpression') {\n keys.push(...flattenObjectKeys(prop.value, fullKey))\n }\n }\n return keys\n}\n\n// v0.8.0: Extract dictionary keys from loadDictionaries() calls\nexport function parseDictionaryKeys(filePath: string): DictionaryKeyEntry[] {\n const entries: DictionaryKeyEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 'loadDictionaries') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'ObjectExpression') return\n\n // Second argument is optional namespace\n let namespace = 'default'\n if (args[1]?.type === 'StringLiteral') {\n namespace = args[1].value\n }\n\n // First argument: { locale: { key: value } }\n // Collect keys from the first locale's dict (all locales should have same keys)\n const dictObj = args[0]\n const allKeys = new Set<string>()\n\n for (const localeProp of dictObj.properties as Array<{\n type: string\n value: { type: string; properties?: unknown[] }\n }>) {\n if (localeProp.type !== 'ObjectProperty') continue\n if (localeProp.value.type !== 'ObjectExpression') continue\n\n const localeKeys = flattenObjectKeys(localeProp.value)\n for (const key of localeKeys) {\n allKeys.add(key)\n }\n }\n\n if (allKeys.size > 0) {\n entries.push({\n file: filePath,\n line: loc.start.line,\n namespace,\n keys: [...allKeys],\n })\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Extract t() call sites\nexport function parseTCalls(filePath: string): TCallEntry[] {\n const entries: TCallEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 't') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'StringLiteral') return\n\n entries.push({\n file: filePath,\n line: loc.start.line,\n key: args[0].value,\n })\n },\n })\n\n return entries\n}\n\nexport async function extractProjectDictionaryKeys(options: ParseOptions = {}): Promise<DictionaryKeyEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: DictionaryKeyEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseDictionaryKeys(file))\n }\n\n return allEntries\n}\n\nexport async function extractProjectTCalls(options: ParseOptions = {}): Promise<TCallEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: TCallEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseTCalls(file))\n }\n\n return allEntries\n}\n\nexport async function parseProject(options: ParseOptions = {}): Promise<TranslationEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, {\n cwd,\n ignore: exclude,\n absolute: true,\n })\n\n const allEntries: TranslationEntry[] = []\n\n for (const file of files) {\n const entries = parseFile(file)\n allEntries.push(...entries)\n }\n\n return allEntries\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\nimport { unused } from './unused'\n\ninterface ValidateOptions {\n cwd?: string\n locales?: string[]\n strict?: boolean\n unused?: boolean\n noExit?: boolean\n}\n\ninterface Issue {\n type: 'inconsistent' | 'missing' | 'variable_mismatch' | 'icu_type_mismatch'\n message: string\n entries: TranslationEntry[]\n details?: string[]\n}\n\nfunction checkVariableConsistency(entry: TranslationEntry): Issue | null {\n const varsByLocale: { locale: string; vars: string[] }[] = []\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n const matches = text.match(/\\{(\\w+)\\}/g) || []\n const varNames = [...new Set(matches.map((v) => v.slice(1, -1)))].sort()\n varsByLocale.push({ locale, vars: varNames })\n }\n\n if (varsByLocale.length < 2) return null\n\n const reference = varsByLocale[0]!\n const details: string[] = []\n\n for (let i = 1; i < varsByLocale.length; i++) {\n const current = varsByLocale[i]!\n const refSet = new Set(reference.vars)\n const curSet = new Set(current.vars)\n\n const onlyInRef = reference.vars.filter((v) => !curSet.has(v))\n const onlyInCur = current.vars.filter((v) => !refSet.has(v))\n\n if (onlyInRef.length > 0) {\n details.push(\n `${reference.locale} has {${onlyInRef.join('}, {')}} missing in ${current.locale}`,\n )\n }\n if (onlyInCur.length > 0) {\n details.push(\n `${current.locale} has {${onlyInCur.join('}, {')}} missing in ${reference.locale}`,\n )\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'variable_mismatch',\n message: 'Variable mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nfunction checkICUTypeConsistency(entry: TranslationEntry): Issue | null {\n if (!entry.icuTypes) return null\n\n const locales = Object.keys(entry.icuTypes)\n if (locales.length < 2) return null\n\n const details: string[] = []\n const reference = locales[0]!\n const refTypes = entry.icuTypes[reference]!\n\n for (let i = 1; i < locales.length; i++) {\n const locale = locales[i]!\n const curTypes = entry.icuTypes[locale]!\n\n for (const refType of refTypes) {\n const match = curTypes.find((t: { variable: string; type: string }) => t.variable === refType.variable)\n if (match && match.type !== refType.type) {\n details.push(\n `{${refType.variable}} is \"${refType.type}\" in ${reference} but \"${match.type}\" in ${locale}`,\n )\n }\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'icu_type_mismatch',\n message: 'ICU type mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nexport async function validate(options: ValidateOptions = {}): Promise<void> {\n const { cwd, locales, strict, unused: checkUnused } = options\n\n console.log(chalk.blue('\\nValidating translations...\\n'))\n\n const entries = await parseProject({ cwd })\n const issues: Issue[] = []\n\n // group by first language text (usually ko)\n const groups = new Map<string, TranslationEntry[]>()\n\n for (const entry of entries) {\n const key = Object.values(entry.translations)[0] || ''\n if (!groups.has(key)) {\n groups.set(key, [])\n }\n groups.get(key)!.push(entry)\n }\n\n // check for inconsistent translations\n for (const [key, group] of groups) {\n if (group.length < 2) continue\n\n const translationSets = group.map((e) => JSON.stringify(e.translations))\n const uniqueSets = [...new Set(translationSets)]\n\n if (uniqueSets.length > 1) {\n issues.push({\n type: 'inconsistent',\n message: `Inconsistent translations for \"${key}\"`,\n entries: group,\n })\n }\n }\n\n // check for missing locales\n if (locales && locales.length > 0) {\n for (const entry of entries) {\n const missing = locales.filter((l) => !entry.translations[l])\n\n if (missing.length > 0) {\n issues.push({\n type: 'missing',\n message: `Missing locales: ${missing.join(', ')}`,\n entries: [entry],\n })\n }\n }\n }\n\n // check for variable name consistency (enhanced in v0.7.0)\n for (const entry of entries) {\n const issue = checkVariableConsistency(entry)\n if (issue) issues.push(issue)\n }\n\n // check for ICU type consistency (strict mode, v0.7.0)\n if (strict) {\n for (const entry of entries) {\n const issue = checkICUTypeConsistency(entry)\n if (issue) issues.push(issue)\n }\n }\n\n // unused key detection (v0.8.0)\n let unusedCount = 0\n if (checkUnused) {\n const result = await unused({ cwd })\n unusedCount = result.unusedKeys.length\n }\n\n // print results\n if (issues.length === 0 && unusedCount === 0) {\n console.log(chalk.green('All translations are valid!\\n'))\n console.log(chalk.gray(`Checked ${entries.length} translation(s)`))\n if (strict) {\n console.log(chalk.gray('(strict mode enabled)'))\n }\n if (checkUnused) {\n console.log(chalk.gray('(unused key detection enabled)'))\n }\n return\n }\n\n console.log(chalk.red(`Found ${issues.length} issue(s):\\n`))\n\n for (const issue of issues) {\n console.log(` ${chalk.yellow(issue.message)}`)\n\n for (const entry of issue.entries) {\n const relativePath = entry.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n console.log(` ${chalk.cyan(locale)}: ${text}`)\n }\n }\n\n if (issue.details && issue.details.length > 0) {\n for (const detail of issue.details) {\n console.log(chalk.gray(` → ${detail}`))\n }\n }\n\n console.log()\n }\n\n if ((issues.length > 0 || unusedCount > 0) && !options.noExit) {\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface UnusedKey {\n namespace: string\n key: string\n definedIn: string\n line: number\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function unused(options: { cwd?: string } = {}): Promise<{ unusedKeys: UnusedKey[] }> {\n const { cwd } = options\n\n console.log(chalk.blue('\\nDetecting unused translations...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n // Build set of used keys (normalized: namespace:key or key for default)\n const usedKeys = new Set<string>()\n for (const call of tCalls) {\n usedKeys.add(call.key)\n // Also add with default namespace if no namespace prefix\n if (!call.key.includes(':')) {\n usedKeys.add(call.key)\n }\n }\n\n // Check each dictionary key against used keys\n const unusedKeys: UnusedKey[] = []\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n\n // Check if key is directly used\n if (usedKeys.has(fullKey)) continue\n\n // Check if this is a plural suffix variant (e.g. count_one, count_other)\n // and the base key is used via t('items.count', { count: N })\n let isPluralVariant = false\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n if (usedKeys.has(fullBaseKey)) {\n isPluralVariant = true\n break\n }\n }\n }\n if (isPluralVariant) continue\n\n unusedKeys.push({\n namespace: entry.namespace,\n key: fullKey,\n definedIn: entry.file,\n line: entry.line,\n })\n }\n }\n\n // Report results\n if (unusedKeys.length === 0) {\n const totalKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n console.log(chalk.green('No unused translations found!\\n'))\n console.log(chalk.gray(`Checked ${totalKeys} dictionary key(s) against ${tCalls.length} t() call(s)`))\n return { unusedKeys }\n }\n\n console.log(chalk.yellow(`Found ${unusedKeys.length} unused translation key(s):\\n`))\n for (const item of unusedKeys) {\n const relativePath = item.definedIn.replace(process.cwd() + '/', '')\n console.log(` ${chalk.red('-')} ${chalk.cyan(item.key)}`)\n console.log(chalk.gray(` defined in ${relativePath}:${item.line}`))\n }\n\n console.log()\n return { unusedKeys }\n}\n","import chalk from 'chalk'\nimport { parseProject } from '../parser'\n\ninterface CoverageOptions {\n cwd?: string\n locales: string[]\n}\n\ninterface LocaleCoverage {\n locale: string\n total: number\n translated: number\n percentage: number\n}\n\nexport async function coverage(options: CoverageOptions): Promise<void> {\n const { cwd, locales } = options\n\n console.log(chalk.blue('\\nAnalyzing translation coverage...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n const coverageData: LocaleCoverage[] = []\n\n for (const locale of locales) {\n let translated = 0\n\n for (const entry of entries) {\n if (entry.translations[locale]) {\n translated++\n }\n }\n\n const percentage = Math.round((translated / entries.length) * 100)\n\n coverageData.push({\n locale,\n total: entries.length,\n translated,\n percentage,\n })\n }\n\n // print coverage table\n console.log(chalk.bold('Translation Coverage:\\n'))\n\n const maxLocaleLen = Math.max(...locales.map((l) => l.length), 6)\n\n console.log(\n chalk.gray(\n `${'Locale'.padEnd(maxLocaleLen)} ${'Coverage'.padStart(10)} ${'Translated'.padStart(12)}`\n )\n )\n console.log(chalk.gray('─'.repeat(maxLocaleLen + 26)))\n\n for (const data of coverageData) {\n const color =\n data.percentage === 100 ? chalk.green :\n data.percentage >= 80 ? chalk.yellow : chalk.red\n\n const bar = createProgressBar(data.percentage, 10)\n const percentStr = `${data.percentage}%`.padStart(4)\n\n console.log(\n `${data.locale.padEnd(maxLocaleLen)} ${color(bar)} ${color(percentStr)} ${chalk.gray(`${data.translated}/${data.total}`)}`\n )\n }\n\n console.log()\n\n // summary\n const fullyCovered = coverageData.filter((d) => d.percentage === 100).length\n const partiallyCovered = coverageData.filter((d) => d.percentage > 0 && d.percentage < 100).length\n const notCovered = coverageData.filter((d) => d.percentage === 0).length\n\n if (fullyCovered === locales.length) {\n console.log(chalk.green('All locales are fully translated!'))\n } else {\n console.log(chalk.gray(`Full: ${fullyCovered}, Partial: ${partiallyCovered}, Empty: ${notCovered}`))\n }\n}\n\nfunction createProgressBar(percentage: number, width: number): string {\n const filled = Math.round((percentage / 100) * width)\n const empty = width - filled\n\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport chalk from 'chalk'\nimport { extractProjectDictionaryKeys } from '../parser'\n\ninterface TypegenOptions {\n cwd?: string\n output?: string\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function typegen(options: TypegenOptions = {}): Promise<void> {\n const { cwd, output = 'src/i18n.d.ts' } = options\n\n console.log(chalk.blue('\\nGenerating TypeScript types...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n\n // Collect all unique full keys (namespace:key or key)\n const allKeys = new Set<string>()\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n allKeys.add(fullKey)\n\n // Also add plural base keys (strip _one, _other, etc.)\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n allKeys.add(fullBaseKey)\n }\n }\n }\n }\n\n if (allKeys.size === 0) {\n console.log(chalk.yellow('No dictionary keys found. Make sure loadDictionaries() calls are present.'))\n return\n }\n\n const sortedKeys = [...allKeys].sort()\n\n // Generate the .d.ts content\n const keyUnion = sortedKeys.map(k => ` | '${k}'`).join('\\n')\n\n const content = `// Auto-generated by inline-i18n typegen\n// Do not edit manually. Re-run: npx inline-i18n typegen\n\nimport 'inline-i18n-multi'\n\ndeclare module 'inline-i18n-multi' {\n export type TranslationKey =\n${keyUnion}\n\n export function t(\n key: TranslationKey,\n vars?: TranslationVars,\n locale?: string\n ): string\n\n export function hasTranslation(\n key: TranslationKey,\n locale?: string\n ): boolean\n}\n`\n\n const outputPath = path.resolve(cwd || process.cwd(), output)\n const outputDir = path.dirname(outputPath)\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8')\n\n console.log(chalk.green(`Generated ${sortedKeys.length} translation key types`))\n console.log(chalk.gray(`Output: ${outputPath}\\n`))\n\n // Show sample\n const sample = sortedKeys.slice(0, 5)\n for (const key of sample) {\n console.log(` ${chalk.cyan(key)}`)\n }\n if (sortedKeys.length > 5) {\n console.log(chalk.gray(` ... and ${sortedKeys.length - 5} more`))\n }\n}\n","import chalk from 'chalk'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { parseProject } from '../parser'\n\ninterface ExtractOptions {\n cwd?: string\n output?: string\n format?: 'flat' | 'nested'\n}\n\nexport async function extract(options: ExtractOptions = {}): Promise<void> {\n const { cwd, output = 'translations', format = 'flat' } = options\n\n console.log(chalk.blue('\\nExtracting inline translations...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n // Group translations by locale\n const byLocale: Record<string, Record<string, string>> = {}\n const basePath = cwd || process.cwd()\n\n for (const entry of entries) {\n for (const [locale, text] of Object.entries(entry.translations)) {\n if (!byLocale[locale]) byLocale[locale] = {}\n\n const relativePath = entry.file.replace(basePath + '/', '')\n const key = `${relativePath}:${entry.line}`\n byLocale[locale][key] = text\n }\n }\n\n // Write output files\n const outputDir = path.resolve(basePath, output)\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n const locales = Object.keys(byLocale).sort()\n for (const locale of locales) {\n const translations = byLocale[locale]!\n let content: string\n\n if (format === 'nested') {\n const nested = buildNestedObject(translations)\n content = JSON.stringify(nested, null, 2) + '\\n'\n } else {\n content = JSON.stringify(translations, null, 2) + '\\n'\n }\n\n const filePath = path.join(outputDir, `${locale}.json`)\n fs.writeFileSync(filePath, content)\n console.log(\n chalk.green(` ${locale}.json`) +\n chalk.gray(` (${Object.keys(translations).length} keys)`)\n )\n }\n\n console.log(chalk.gray(`\\nExtracted ${entries.length} translation(s) to ${output}/`))\n}\n\n/**\n * Build a nested object from flat dot-notation keys\n */\nfunction buildNestedObject(flat: Record<string, string>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(flat)) {\n const parts = key.split('.')\n let current: Record<string, unknown> = result\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!current[part] || typeof current[part] !== 'object') {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n\n current[parts[parts.length - 1]!] = value\n }\n\n return result\n}\n","import { watch } from 'chokidar'\nimport chalk from 'chalk'\n\ninterface WatchOptions {\n cwd: string\n patterns: string[]\n ignore: string[]\n onChange: () => Promise<void>\n label: string\n}\n\nexport function startWatch(options: WatchOptions): void {\n const { cwd, patterns, ignore, onChange, label } = options\n\n console.log(chalk.blue(`\\nWatching for changes (${label})...\\n`))\n console.log(chalk.gray('Press Ctrl+C to stop\\n'))\n\n const watcher = watch(patterns, {\n cwd,\n ignored: ignore,\n ignoreInitial: true,\n })\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n const handleChange = (filePath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(async () => {\n console.log(chalk.gray(`\\nChange detected: ${filePath}`))\n console.log(chalk.gray('-'.repeat(40)))\n try {\n await onChange()\n } catch {\n // Error already printed by the command\n }\n console.log(chalk.gray(`\\nWatching for changes (${label})...`))\n }, 300)\n }\n\n watcher.on('change', handleChange)\n watcher.on('add', handleChange)\n}\n"],"mappings":"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","names":["traverse","fg","chalk","import_chalk","import_chalk","chalk","chalk","import_chalk","chalk","fs","import_chalk","PLURAL_SUFFIXES","chalk","import_chalk","fs","path","chalk","import_chalk","chalk"]}
package/dist/index.d.ts CHANGED
@@ -44,6 +44,7 @@ interface ValidateOptions {
44
44
  locales?: string[];
45
45
  strict?: boolean;
46
46
  unused?: boolean;
47
+ noExit?: boolean;
47
48
  }
48
49
  declare function validate(options?: ValidateOptions): Promise<void>;
49
50
 
@@ -71,4 +72,11 @@ interface TypegenOptions {
71
72
  }
72
73
  declare function typegen(options?: TypegenOptions): Promise<void>;
73
74
 
74
- export { type DictionaryKeyEntry, type TCallEntry, type TranslationEntry, coverage, extractProjectDictionaryKeys, extractProjectTCalls, find, parseDictionaryKeys, parseProject, parseTCalls, typegen, unused, validate };
75
+ interface ExtractOptions {
76
+ cwd?: string;
77
+ output?: string;
78
+ format?: 'flat' | 'nested';
79
+ }
80
+ declare function extract(options?: ExtractOptions): Promise<void>;
81
+
82
+ export { type DictionaryKeyEntry, type TCallEntry, type TranslationEntry, coverage, extract, extractProjectDictionaryKeys, extractProjectTCalls, find, parseDictionaryKeys, parseProject, parseTCalls, typegen, unused, validate };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  coverage: () => coverage,
34
+ extract: () => extract,
34
35
  extractProjectDictionaryKeys: () => extractProjectDictionaryKeys,
35
36
  extractProjectTCalls: () => extractProjectTCalls,
36
37
  find: () => find,
@@ -541,7 +542,7 @@ async function validate(options = {}) {
541
542
  }
542
543
  console.log();
543
544
  }
544
- if (issues.length > 0 || unusedCount > 0) {
545
+ if ((issues.length > 0 || unusedCount > 0) && !options.noExit) {
545
546
  process.exit(1);
546
547
  }
547
548
  }
@@ -671,9 +672,72 @@ ${keyUnion}
671
672
  console.log(import_chalk5.default.gray(` ... and ${sortedKeys.length - 5} more`));
672
673
  }
673
674
  }
675
+
676
+ // src/commands/extract.ts
677
+ var import_chalk6 = __toESM(require("chalk"));
678
+ var fs3 = __toESM(require("fs"));
679
+ var path2 = __toESM(require("path"));
680
+ async function extract(options = {}) {
681
+ const { cwd, output = "translations", format = "flat" } = options;
682
+ console.log(import_chalk6.default.blue("\nExtracting inline translations...\n"));
683
+ const entries = await parseProject({ cwd });
684
+ if (entries.length === 0) {
685
+ console.log(import_chalk6.default.yellow("No translations found."));
686
+ return;
687
+ }
688
+ const byLocale = {};
689
+ const basePath = cwd || process.cwd();
690
+ for (const entry of entries) {
691
+ for (const [locale, text] of Object.entries(entry.translations)) {
692
+ if (!byLocale[locale]) byLocale[locale] = {};
693
+ const relativePath = entry.file.replace(basePath + "/", "");
694
+ const key = `${relativePath}:${entry.line}`;
695
+ byLocale[locale][key] = text;
696
+ }
697
+ }
698
+ const outputDir = path2.resolve(basePath, output);
699
+ if (!fs3.existsSync(outputDir)) {
700
+ fs3.mkdirSync(outputDir, { recursive: true });
701
+ }
702
+ const locales = Object.keys(byLocale).sort();
703
+ for (const locale of locales) {
704
+ const translations = byLocale[locale];
705
+ let content;
706
+ if (format === "nested") {
707
+ const nested = buildNestedObject(translations);
708
+ content = JSON.stringify(nested, null, 2) + "\n";
709
+ } else {
710
+ content = JSON.stringify(translations, null, 2) + "\n";
711
+ }
712
+ const filePath = path2.join(outputDir, `${locale}.json`);
713
+ fs3.writeFileSync(filePath, content);
714
+ console.log(
715
+ import_chalk6.default.green(` ${locale}.json`) + import_chalk6.default.gray(` (${Object.keys(translations).length} keys)`)
716
+ );
717
+ }
718
+ console.log(import_chalk6.default.gray(`
719
+ Extracted ${entries.length} translation(s) to ${output}/`));
720
+ }
721
+ function buildNestedObject(flat) {
722
+ const result = {};
723
+ for (const [key, value] of Object.entries(flat)) {
724
+ const parts = key.split(".");
725
+ let current = result;
726
+ for (let i = 0; i < parts.length - 1; i++) {
727
+ const part = parts[i];
728
+ if (!current[part] || typeof current[part] !== "object") {
729
+ current[part] = {};
730
+ }
731
+ current = current[part];
732
+ }
733
+ current[parts[parts.length - 1]] = value;
734
+ }
735
+ return result;
736
+ }
674
737
  // Annotate the CommonJS export names for ESM import in node:
675
738
  0 && (module.exports = {
676
739
  coverage,
740
+ extract,
677
741
  extractProjectDictionaryKeys,
678
742
  extractProjectTCalls,
679
743
  find,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/parser.ts","../src/commands/find.ts","../src/commands/validate.ts","../src/commands/unused.ts","../src/commands/coverage.ts","../src/commands/typegen.ts"],"sourcesContent":["export {\n parseProject,\n parseDictionaryKeys,\n parseTCalls,\n extractProjectDictionaryKeys,\n extractProjectTCalls,\n type TranslationEntry,\n type DictionaryKeyEntry,\n type TCallEntry,\n} from './parser'\nexport { find } from './commands/find'\nexport { validate } from './commands/validate'\nexport { coverage } from './commands/coverage'\nexport { unused } from './commands/unused'\nexport { typegen } from './commands/typegen'\n","import { parse } from '@babel/parser'\nimport traverse from '@babel/traverse'\nimport * as fs from 'fs'\nimport fg from 'fast-glob'\n\n// v0.8.0: Dictionary key and t() call extraction\n\nexport interface DictionaryKeyEntry {\n file: string\n line: number\n namespace: string\n keys: string[]\n}\n\nexport interface TCallEntry {\n file: string\n line: number\n key: string\n}\n\nexport interface ICUTypeInfo {\n variable: string\n type: string\n}\n\nexport interface TranslationEntry {\n file: string\n line: number\n column: number\n translations: Record<string, string>\n variables: string[]\n /** ICU type information per locale (v0.7.0) */\n icuTypes?: Record<string, ICUTypeInfo[]>\n}\n\ninterface ParseOptions {\n cwd?: string\n include?: string[]\n exclude?: string[]\n}\n\nconst IT_FUNCTION_NAMES = [\n 'it',\n 'it_ja', 'it_zh', 'it_es', 'it_fr', 'it_de',\n 'en_ja', 'en_zh', 'en_es', 'en_fr', 'en_de',\n 'ja_zh', 'ja_es', 'zh_es',\n]\n\nconst PAIR_MAPPING: Record<string, [string, string]> = {\n it: ['ko', 'en'],\n it_ja: ['ko', 'ja'],\n it_zh: ['ko', 'zh'],\n it_es: ['ko', 'es'],\n it_fr: ['ko', 'fr'],\n it_de: ['ko', 'de'],\n en_ja: ['en', 'ja'],\n en_zh: ['en', 'zh'],\n en_es: ['en', 'es'],\n en_fr: ['en', 'fr'],\n en_de: ['en', 'de'],\n ja_zh: ['ja', 'zh'],\n ja_es: ['ja', 'es'],\n zh_es: ['zh', 'es'],\n}\n\nfunction extractVariables(text: string): string[] {\n const matches = text.match(/\\{(\\w+)\\}/g)\n if (!matches) return []\n return matches.map((m) => m.slice(1, -1))\n}\n\nconst ICU_TYPE_PATTERN = /\\{(\\w+),\\s*(\\w+)/g\n\nfunction extractICUTypes(text: string): ICUTypeInfo[] {\n const types: ICUTypeInfo[] = []\n let match: RegExpExecArray | null\n ICU_TYPE_PATTERN.lastIndex = 0\n while ((match = ICU_TYPE_PATTERN.exec(text)) !== null) {\n types.push({ variable: match[1]!, type: match[2]! })\n }\n return types\n}\n\nfunction parseFile(filePath: string): TranslationEntry[] {\n const entries: TranslationEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier') return\n if (!IT_FUNCTION_NAMES.includes(callee.name)) return\n\n const funcName = callee.name\n const args = node.arguments\n const loc = node.loc\n\n if (!loc) return\n\n const entry: TranslationEntry = {\n file: filePath,\n line: loc.start.line,\n column: loc.start.column,\n translations: {},\n variables: [],\n }\n\n if (args[0]?.type === 'ObjectExpression') {\n const obj = args[0]\n for (const prop of obj.properties) {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.value.type === 'StringLiteral'\n ) {\n entry.translations[prop.key.name] = prop.value.value\n entry.variables.push(...extractVariables(prop.value.value))\n // Extract ICU type info (v0.7.0)\n const types = extractICUTypes(prop.value.value)\n if (types.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[prop.key.name] = types\n }\n }\n }\n } else if (\n args[0]?.type === 'StringLiteral' &&\n args[1]?.type === 'StringLiteral'\n ) {\n const [lang1, lang2] = PAIR_MAPPING[funcName] || ['ko', 'en']\n entry.translations[lang1] = args[0].value\n entry.translations[lang2] = args[1].value\n entry.variables.push(...extractVariables(args[0].value))\n entry.variables.push(...extractVariables(args[1].value))\n // Extract ICU type info (v0.7.0)\n const types1 = extractICUTypes(args[0].value)\n if (types1.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang1] = types1\n }\n const types2 = extractICUTypes(args[1].value)\n if (types2.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang2] = types2\n }\n }\n\n entry.variables = [...new Set(entry.variables)]\n\n if (Object.keys(entry.translations).length > 0) {\n entries.push(entry)\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Flatten nested ObjectExpression to dot-notation keys\nfunction flattenObjectKeys(\n node: { type: string; properties?: unknown[] },\n prefix: string = '',\n): string[] {\n const keys: string[] = []\n if (node.type !== 'ObjectExpression' || !node.properties) return keys\n\n for (const prop of node.properties as Array<{\n type: string\n key: { type: string; name?: string; value?: string }\n value: { type: string; properties?: unknown[] }\n }>) {\n if (prop.type !== 'ObjectProperty') continue\n\n let propName: string | undefined\n if (prop.key.type === 'Identifier') propName = prop.key.name\n else if (prop.key.type === 'StringLiteral') propName = prop.key.value\n\n if (!propName) continue\n\n const fullKey = prefix ? `${prefix}.${propName}` : propName\n\n if (prop.value.type === 'StringLiteral') {\n keys.push(fullKey)\n } else if (prop.value.type === 'ObjectExpression') {\n keys.push(...flattenObjectKeys(prop.value, fullKey))\n }\n }\n return keys\n}\n\n// v0.8.0: Extract dictionary keys from loadDictionaries() calls\nexport function parseDictionaryKeys(filePath: string): DictionaryKeyEntry[] {\n const entries: DictionaryKeyEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 'loadDictionaries') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'ObjectExpression') return\n\n // Second argument is optional namespace\n let namespace = 'default'\n if (args[1]?.type === 'StringLiteral') {\n namespace = args[1].value\n }\n\n // First argument: { locale: { key: value } }\n // Collect keys from the first locale's dict (all locales should have same keys)\n const dictObj = args[0]\n const allKeys = new Set<string>()\n\n for (const localeProp of dictObj.properties as Array<{\n type: string\n value: { type: string; properties?: unknown[] }\n }>) {\n if (localeProp.type !== 'ObjectProperty') continue\n if (localeProp.value.type !== 'ObjectExpression') continue\n\n const localeKeys = flattenObjectKeys(localeProp.value)\n for (const key of localeKeys) {\n allKeys.add(key)\n }\n }\n\n if (allKeys.size > 0) {\n entries.push({\n file: filePath,\n line: loc.start.line,\n namespace,\n keys: [...allKeys],\n })\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Extract t() call sites\nexport function parseTCalls(filePath: string): TCallEntry[] {\n const entries: TCallEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 't') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'StringLiteral') return\n\n entries.push({\n file: filePath,\n line: loc.start.line,\n key: args[0].value,\n })\n },\n })\n\n return entries\n}\n\nexport async function extractProjectDictionaryKeys(options: ParseOptions = {}): Promise<DictionaryKeyEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: DictionaryKeyEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseDictionaryKeys(file))\n }\n\n return allEntries\n}\n\nexport async function extractProjectTCalls(options: ParseOptions = {}): Promise<TCallEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: TCallEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseTCalls(file))\n }\n\n return allEntries\n}\n\nexport async function parseProject(options: ParseOptions = {}): Promise<TranslationEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, {\n cwd,\n ignore: exclude,\n absolute: true,\n })\n\n const allEntries: TranslationEntry[] = []\n\n for (const file of files) {\n const entries = parseFile(file)\n allEntries.push(...entries)\n }\n\n return allEntries\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface FindOptions {\n query: string\n cwd?: string\n}\n\nexport async function find(options: FindOptions): Promise<void> {\n const { query, cwd } = options\n\n console.log(chalk.blue(`\\nSearching for: \"${query}\"\\n`))\n\n const entries = await parseProject({ cwd })\n const results: TranslationEntry[] = []\n\n const lowerQuery = query.toLowerCase()\n\n for (const entry of entries) {\n const values = Object.values(entry.translations)\n const matches = values.some((v) => v.toLowerCase().includes(lowerQuery))\n\n if (matches) {\n results.push(entry)\n }\n }\n\n if (results.length === 0) {\n console.log(chalk.yellow('No results found.'))\n return\n }\n\n console.log(chalk.green(`Found ${results.length} occurrence(s):\\n`))\n\n for (const result of results) {\n const relativePath = result.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(`${relativePath}:${result.line}:${result.column}`))\n\n for (const [locale, text] of Object.entries(result.translations)) {\n const highlighted = text.replace(\n new RegExp(`(${query})`, 'gi'),\n chalk.yellow('$1')\n )\n console.log(` ${chalk.cyan(locale)}: ${highlighted}`)\n }\n console.log()\n }\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\nimport { unused } from './unused'\n\ninterface ValidateOptions {\n cwd?: string\n locales?: string[]\n strict?: boolean\n unused?: boolean\n}\n\ninterface Issue {\n type: 'inconsistent' | 'missing' | 'variable_mismatch' | 'icu_type_mismatch'\n message: string\n entries: TranslationEntry[]\n details?: string[]\n}\n\nfunction checkVariableConsistency(entry: TranslationEntry): Issue | null {\n const varsByLocale: { locale: string; vars: string[] }[] = []\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n const matches = text.match(/\\{(\\w+)\\}/g) || []\n const varNames = [...new Set(matches.map((v) => v.slice(1, -1)))].sort()\n varsByLocale.push({ locale, vars: varNames })\n }\n\n if (varsByLocale.length < 2) return null\n\n const reference = varsByLocale[0]!\n const details: string[] = []\n\n for (let i = 1; i < varsByLocale.length; i++) {\n const current = varsByLocale[i]!\n const refSet = new Set(reference.vars)\n const curSet = new Set(current.vars)\n\n const onlyInRef = reference.vars.filter((v) => !curSet.has(v))\n const onlyInCur = current.vars.filter((v) => !refSet.has(v))\n\n if (onlyInRef.length > 0) {\n details.push(\n `${reference.locale} has {${onlyInRef.join('}, {')}} missing in ${current.locale}`,\n )\n }\n if (onlyInCur.length > 0) {\n details.push(\n `${current.locale} has {${onlyInCur.join('}, {')}} missing in ${reference.locale}`,\n )\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'variable_mismatch',\n message: 'Variable mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nfunction checkICUTypeConsistency(entry: TranslationEntry): Issue | null {\n if (!entry.icuTypes) return null\n\n const locales = Object.keys(entry.icuTypes)\n if (locales.length < 2) return null\n\n const details: string[] = []\n const reference = locales[0]!\n const refTypes = entry.icuTypes[reference]!\n\n for (let i = 1; i < locales.length; i++) {\n const locale = locales[i]!\n const curTypes = entry.icuTypes[locale]!\n\n for (const refType of refTypes) {\n const match = curTypes.find((t: { variable: string; type: string }) => t.variable === refType.variable)\n if (match && match.type !== refType.type) {\n details.push(\n `{${refType.variable}} is \"${refType.type}\" in ${reference} but \"${match.type}\" in ${locale}`,\n )\n }\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'icu_type_mismatch',\n message: 'ICU type mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nexport async function validate(options: ValidateOptions = {}): Promise<void> {\n const { cwd, locales, strict, unused: checkUnused } = options\n\n console.log(chalk.blue('\\nValidating translations...\\n'))\n\n const entries = await parseProject({ cwd })\n const issues: Issue[] = []\n\n // group by first language text (usually ko)\n const groups = new Map<string, TranslationEntry[]>()\n\n for (const entry of entries) {\n const key = Object.values(entry.translations)[0] || ''\n if (!groups.has(key)) {\n groups.set(key, [])\n }\n groups.get(key)!.push(entry)\n }\n\n // check for inconsistent translations\n for (const [key, group] of groups) {\n if (group.length < 2) continue\n\n const translationSets = group.map((e) => JSON.stringify(e.translations))\n const uniqueSets = [...new Set(translationSets)]\n\n if (uniqueSets.length > 1) {\n issues.push({\n type: 'inconsistent',\n message: `Inconsistent translations for \"${key}\"`,\n entries: group,\n })\n }\n }\n\n // check for missing locales\n if (locales && locales.length > 0) {\n for (const entry of entries) {\n const missing = locales.filter((l) => !entry.translations[l])\n\n if (missing.length > 0) {\n issues.push({\n type: 'missing',\n message: `Missing locales: ${missing.join(', ')}`,\n entries: [entry],\n })\n }\n }\n }\n\n // check for variable name consistency (enhanced in v0.7.0)\n for (const entry of entries) {\n const issue = checkVariableConsistency(entry)\n if (issue) issues.push(issue)\n }\n\n // check for ICU type consistency (strict mode, v0.7.0)\n if (strict) {\n for (const entry of entries) {\n const issue = checkICUTypeConsistency(entry)\n if (issue) issues.push(issue)\n }\n }\n\n // unused key detection (v0.8.0)\n let unusedCount = 0\n if (checkUnused) {\n const result = await unused({ cwd })\n unusedCount = result.unusedKeys.length\n }\n\n // print results\n if (issues.length === 0 && unusedCount === 0) {\n console.log(chalk.green('All translations are valid!\\n'))\n console.log(chalk.gray(`Checked ${entries.length} translation(s)`))\n if (strict) {\n console.log(chalk.gray('(strict mode enabled)'))\n }\n if (checkUnused) {\n console.log(chalk.gray('(unused key detection enabled)'))\n }\n return\n }\n\n console.log(chalk.red(`Found ${issues.length} issue(s):\\n`))\n\n for (const issue of issues) {\n console.log(` ${chalk.yellow(issue.message)}`)\n\n for (const entry of issue.entries) {\n const relativePath = entry.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n console.log(` ${chalk.cyan(locale)}: ${text}`)\n }\n }\n\n if (issue.details && issue.details.length > 0) {\n for (const detail of issue.details) {\n console.log(chalk.gray(` → ${detail}`))\n }\n }\n\n console.log()\n }\n\n if (issues.length > 0 || unusedCount > 0) {\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface UnusedKey {\n namespace: string\n key: string\n definedIn: string\n line: number\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function unused(options: { cwd?: string } = {}): Promise<{ unusedKeys: UnusedKey[] }> {\n const { cwd } = options\n\n console.log(chalk.blue('\\nDetecting unused translations...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n // Build set of used keys (normalized: namespace:key or key for default)\n const usedKeys = new Set<string>()\n for (const call of tCalls) {\n usedKeys.add(call.key)\n // Also add with default namespace if no namespace prefix\n if (!call.key.includes(':')) {\n usedKeys.add(call.key)\n }\n }\n\n // Check each dictionary key against used keys\n const unusedKeys: UnusedKey[] = []\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n\n // Check if key is directly used\n if (usedKeys.has(fullKey)) continue\n\n // Check if this is a plural suffix variant (e.g. count_one, count_other)\n // and the base key is used via t('items.count', { count: N })\n let isPluralVariant = false\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n if (usedKeys.has(fullBaseKey)) {\n isPluralVariant = true\n break\n }\n }\n }\n if (isPluralVariant) continue\n\n unusedKeys.push({\n namespace: entry.namespace,\n key: fullKey,\n definedIn: entry.file,\n line: entry.line,\n })\n }\n }\n\n // Report results\n if (unusedKeys.length === 0) {\n const totalKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n console.log(chalk.green('No unused translations found!\\n'))\n console.log(chalk.gray(`Checked ${totalKeys} dictionary key(s) against ${tCalls.length} t() call(s)`))\n return { unusedKeys }\n }\n\n console.log(chalk.yellow(`Found ${unusedKeys.length} unused translation key(s):\\n`))\n for (const item of unusedKeys) {\n const relativePath = item.definedIn.replace(process.cwd() + '/', '')\n console.log(` ${chalk.red('-')} ${chalk.cyan(item.key)}`)\n console.log(chalk.gray(` defined in ${relativePath}:${item.line}`))\n }\n\n console.log()\n return { unusedKeys }\n}\n","import chalk from 'chalk'\nimport { parseProject } from '../parser'\n\ninterface CoverageOptions {\n cwd?: string\n locales: string[]\n}\n\ninterface LocaleCoverage {\n locale: string\n total: number\n translated: number\n percentage: number\n}\n\nexport async function coverage(options: CoverageOptions): Promise<void> {\n const { cwd, locales } = options\n\n console.log(chalk.blue('\\nAnalyzing translation coverage...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n const coverageData: LocaleCoverage[] = []\n\n for (const locale of locales) {\n let translated = 0\n\n for (const entry of entries) {\n if (entry.translations[locale]) {\n translated++\n }\n }\n\n const percentage = Math.round((translated / entries.length) * 100)\n\n coverageData.push({\n locale,\n total: entries.length,\n translated,\n percentage,\n })\n }\n\n // print coverage table\n console.log(chalk.bold('Translation Coverage:\\n'))\n\n const maxLocaleLen = Math.max(...locales.map((l) => l.length), 6)\n\n console.log(\n chalk.gray(\n `${'Locale'.padEnd(maxLocaleLen)} ${'Coverage'.padStart(10)} ${'Translated'.padStart(12)}`\n )\n )\n console.log(chalk.gray('─'.repeat(maxLocaleLen + 26)))\n\n for (const data of coverageData) {\n const color =\n data.percentage === 100 ? chalk.green :\n data.percentage >= 80 ? chalk.yellow : chalk.red\n\n const bar = createProgressBar(data.percentage, 10)\n const percentStr = `${data.percentage}%`.padStart(4)\n\n console.log(\n `${data.locale.padEnd(maxLocaleLen)} ${color(bar)} ${color(percentStr)} ${chalk.gray(`${data.translated}/${data.total}`)}`\n )\n }\n\n console.log()\n\n // summary\n const fullyCovered = coverageData.filter((d) => d.percentage === 100).length\n const partiallyCovered = coverageData.filter((d) => d.percentage > 0 && d.percentage < 100).length\n const notCovered = coverageData.filter((d) => d.percentage === 0).length\n\n if (fullyCovered === locales.length) {\n console.log(chalk.green('All locales are fully translated!'))\n } else {\n console.log(chalk.gray(`Full: ${fullyCovered}, Partial: ${partiallyCovered}, Empty: ${notCovered}`))\n }\n}\n\nfunction createProgressBar(percentage: number, width: number): string {\n const filled = Math.round((percentage / 100) * width)\n const empty = width - filled\n\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport chalk from 'chalk'\nimport { extractProjectDictionaryKeys } from '../parser'\n\ninterface TypegenOptions {\n cwd?: string\n output?: string\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function typegen(options: TypegenOptions = {}): Promise<void> {\n const { cwd, output = 'src/i18n.d.ts' } = options\n\n console.log(chalk.blue('\\nGenerating TypeScript types...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n\n // Collect all unique full keys (namespace:key or key)\n const allKeys = new Set<string>()\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n allKeys.add(fullKey)\n\n // Also add plural base keys (strip _one, _other, etc.)\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n allKeys.add(fullBaseKey)\n }\n }\n }\n }\n\n if (allKeys.size === 0) {\n console.log(chalk.yellow('No dictionary keys found. Make sure loadDictionaries() calls are present.'))\n return\n }\n\n const sortedKeys = [...allKeys].sort()\n\n // Generate the .d.ts content\n const keyUnion = sortedKeys.map(k => ` | '${k}'`).join('\\n')\n\n const content = `// Auto-generated by inline-i18n typegen\n// Do not edit manually. Re-run: npx inline-i18n typegen\n\nimport 'inline-i18n-multi'\n\ndeclare module 'inline-i18n-multi' {\n export type TranslationKey =\n${keyUnion}\n\n export function t(\n key: TranslationKey,\n vars?: TranslationVars,\n locale?: string\n ): string\n\n export function hasTranslation(\n key: TranslationKey,\n locale?: string\n ): boolean\n}\n`\n\n const outputPath = path.resolve(cwd || process.cwd(), output)\n const outputDir = path.dirname(outputPath)\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8')\n\n console.log(chalk.green(`Generated ${sortedKeys.length} translation key types`))\n console.log(chalk.gray(`Output: ${outputPath}\\n`))\n\n // Show sample\n const sample = sortedKeys.slice(0, 5)\n for (const key of sample) {\n console.log(` ${chalk.cyan(key)}`)\n }\n if (sortedKeys.length > 5) {\n console.log(chalk.gray(` ... and ${sortedKeys.length - 5} more`))\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,oBAAsB;AACtB,sBAAqB;AACrB,SAAoB;AACpB,uBAAe;AAsCf,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EACpC;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EACpC;AAAA,EAAS;AAAA,EAAS;AACpB;AAEA,IAAM,eAAiD;AAAA,EACrD,IAAI,CAAC,MAAM,IAAI;AAAA,EACf,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AAAA,EAClB,OAAO,CAAC,MAAM,IAAI;AACpB;AAEA,SAAS,iBAAiB,MAAwB;AAChD,QAAM,UAAU,KAAK,MAAM,YAAY;AACvC,MAAI,CAAC,QAAS,QAAO,CAAC;AACtB,SAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;AAC1C;AAEA,IAAM,mBAAmB;AAEzB,SAAS,gBAAgB,MAA6B;AACpD,QAAM,QAAuB,CAAC;AAC9B,MAAI;AACJ,mBAAiB,YAAY;AAC7B,UAAQ,QAAQ,iBAAiB,KAAK,IAAI,OAAO,MAAM;AACrD,UAAM,KAAK,EAAE,UAAU,MAAM,CAAC,GAAI,MAAM,MAAM,CAAC,EAAG,CAAC;AAAA,EACrD;AACA,SAAO;AACT;AAEA,SAAS,UAAU,UAAsC;AACvD,QAAM,UAA8B,CAAC;AACrC,QAAM,OAAU,gBAAa,UAAU,OAAO;AAE9C,MAAI;AACJ,MAAI;AACF,cAAM,qBAAM,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,SAAS,CAAC,cAAc,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,sBAAAA,SAAS,KAAK;AAAA,IACZ,eAAe,UAAU;AACvB,YAAM,EAAE,KAAK,IAAI;AACjB,YAAM,EAAE,OAAO,IAAI;AAEnB,UAAI,OAAO,SAAS,aAAc;AAClC,UAAI,CAAC,kBAAkB,SAAS,OAAO,IAAI,EAAG;AAE9C,YAAM,WAAW,OAAO;AACxB,YAAM,OAAO,KAAK;AAClB,YAAM,MAAM,KAAK;AAEjB,UAAI,CAAC,IAAK;AAEV,YAAM,QAA0B;AAAA,QAC9B,MAAM;AAAA,QACN,MAAM,IAAI,MAAM;AAAA,QAChB,QAAQ,IAAI,MAAM;AAAA,QAClB,cAAc,CAAC;AAAA,QACf,WAAW,CAAC;AAAA,MACd;AAEA,UAAI,KAAK,CAAC,GAAG,SAAS,oBAAoB;AACxC,cAAM,MAAM,KAAK,CAAC;AAClB,mBAAW,QAAQ,IAAI,YAAY;AACjC,cACE,KAAK,SAAS,oBACd,KAAK,IAAI,SAAS,gBAClB,KAAK,MAAM,SAAS,iBACpB;AACA,kBAAM,aAAa,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM;AAC/C,kBAAM,UAAU,KAAK,GAAG,iBAAiB,KAAK,MAAM,KAAK,CAAC;AAE1D,kBAAM,QAAQ,gBAAgB,KAAK,MAAM,KAAK;AAC9C,gBAAI,MAAM,SAAS,GAAG;AACpB,kBAAI,CAAC,MAAM,SAAU,OAAM,WAAW,CAAC;AACvC,oBAAM,SAAS,KAAK,IAAI,IAAI,IAAI;AAAA,YAClC;AAAA,UACF;AAAA,QACF;AAAA,MACF,WACE,KAAK,CAAC,GAAG,SAAS,mBAClB,KAAK,CAAC,GAAG,SAAS,iBAClB;AACA,cAAM,CAAC,OAAO,KAAK,IAAI,aAAa,QAAQ,KAAK,CAAC,MAAM,IAAI;AAC5D,cAAM,aAAa,KAAK,IAAI,KAAK,CAAC,EAAE;AACpC,cAAM,aAAa,KAAK,IAAI,KAAK,CAAC,EAAE;AACpC,cAAM,UAAU,KAAK,GAAG,iBAAiB,KAAK,CAAC,EAAE,KAAK,CAAC;AACvD,cAAM,UAAU,KAAK,GAAG,iBAAiB,KAAK,CAAC,EAAE,KAAK,CAAC;AAEvD,cAAM,SAAS,gBAAgB,KAAK,CAAC,EAAE,KAAK;AAC5C,YAAI,OAAO,SAAS,GAAG;AACrB,cAAI,CAAC,MAAM,SAAU,OAAM,WAAW,CAAC;AACvC,gBAAM,SAAS,KAAK,IAAI;AAAA,QAC1B;AACA,cAAM,SAAS,gBAAgB,KAAK,CAAC,EAAE,KAAK;AAC5C,YAAI,OAAO,SAAS,GAAG;AACrB,cAAI,CAAC,MAAM,SAAU,OAAM,WAAW,CAAC;AACvC,gBAAM,SAAS,KAAK,IAAI;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,YAAY,CAAC,GAAG,IAAI,IAAI,MAAM,SAAS,CAAC;AAE9C,UAAI,OAAO,KAAK,MAAM,YAAY,EAAE,SAAS,GAAG;AAC9C,gBAAQ,KAAK,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAGA,SAAS,kBACP,MACA,SAAiB,IACP;AACV,QAAM,OAAiB,CAAC;AACxB,MAAI,KAAK,SAAS,sBAAsB,CAAC,KAAK,WAAY,QAAO;AAEjE,aAAW,QAAQ,KAAK,YAIpB;AACF,QAAI,KAAK,SAAS,iBAAkB;AAEpC,QAAI;AACJ,QAAI,KAAK,IAAI,SAAS,aAAc,YAAW,KAAK,IAAI;AAAA,aAC/C,KAAK,IAAI,SAAS,gBAAiB,YAAW,KAAK,IAAI;AAEhE,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,SAAS,GAAG,MAAM,IAAI,QAAQ,KAAK;AAEnD,QAAI,KAAK,MAAM,SAAS,iBAAiB;AACvC,WAAK,KAAK,OAAO;AAAA,IACnB,WAAW,KAAK,MAAM,SAAS,oBAAoB;AACjD,WAAK,KAAK,GAAG,kBAAkB,KAAK,OAAO,OAAO,CAAC;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,oBAAoB,UAAwC;AAC1E,QAAM,UAAgC,CAAC;AACvC,QAAM,OAAU,gBAAa,UAAU,OAAO;AAE9C,MAAI;AACJ,MAAI;AACF,cAAM,qBAAM,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,SAAS,CAAC,cAAc,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,sBAAAA,SAAS,KAAK;AAAA,IACZ,eAAe,UAAU;AACvB,YAAM,EAAE,KAAK,IAAI;AACjB,YAAM,EAAE,OAAO,IAAI;AAEnB,UAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,mBAAoB;AAExE,YAAM,OAAO,KAAK;AAClB,YAAM,MAAM,KAAK;AACjB,UAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,EAAE,SAAS,mBAAoB;AAG7D,UAAI,YAAY;AAChB,UAAI,KAAK,CAAC,GAAG,SAAS,iBAAiB;AACrC,oBAAY,KAAK,CAAC,EAAE;AAAA,MACtB;AAIA,YAAM,UAAU,KAAK,CAAC;AACtB,YAAM,UAAU,oBAAI,IAAY;AAEhC,iBAAW,cAAc,QAAQ,YAG7B;AACF,YAAI,WAAW,SAAS,iBAAkB;AAC1C,YAAI,WAAW,MAAM,SAAS,mBAAoB;AAElD,cAAM,aAAa,kBAAkB,WAAW,KAAK;AACrD,mBAAW,OAAO,YAAY;AAC5B,kBAAQ,IAAI,GAAG;AAAA,QACjB;AAAA,MACF;AAEA,UAAI,QAAQ,OAAO,GAAG;AACpB,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,MAAM,IAAI,MAAM;AAAA,UAChB;AAAA,UACA,MAAM,CAAC,GAAG,OAAO;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAGO,SAAS,YAAY,UAAgC;AAC1D,QAAM,UAAwB,CAAC;AAC/B,QAAM,OAAU,gBAAa,UAAU,OAAO;AAE9C,MAAI;AACJ,MAAI;AACF,cAAM,qBAAM,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,SAAS,CAAC,cAAc,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,sBAAAA,SAAS,KAAK;AAAA,IACZ,eAAe,UAAU;AACvB,YAAM,EAAE,KAAK,IAAI;AACjB,YAAM,EAAE,OAAO,IAAI;AAEnB,UAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,IAAK;AAEzD,YAAM,OAAO,KAAK;AAClB,YAAM,MAAM,KAAK;AACjB,UAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,EAAE,SAAS,gBAAiB;AAE1D,cAAQ,KAAK;AAAA,QACX,MAAM;AAAA,QACN,MAAM,IAAI,MAAM;AAAA,QAChB,KAAK,KAAK,CAAC,EAAE;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,eAAsB,6BAA6B,UAAwB,CAAC,GAAkC;AAC5G,QAAM;AAAA,IACJ,MAAM,QAAQ,IAAI;AAAA,IAClB,UAAU,CAAC,sBAAsB;AAAA,IACjC,UAAU,CAAC,sBAAsB,cAAc,aAAa;AAAA,EAC9D,IAAI;AAEJ,QAAM,QAAQ,UAAM,iBAAAC,SAAG,SAAS,EAAE,KAAK,QAAQ,SAAS,UAAU,KAAK,CAAC;AACxE,QAAM,aAAmC,CAAC;AAE1C,aAAW,QAAQ,OAAO;AACxB,eAAW,KAAK,GAAG,oBAAoB,IAAI,CAAC;AAAA,EAC9C;AAEA,SAAO;AACT;AAEA,eAAsB,qBAAqB,UAAwB,CAAC,GAA0B;AAC5F,QAAM;AAAA,IACJ,MAAM,QAAQ,IAAI;AAAA,IAClB,UAAU,CAAC,sBAAsB;AAAA,IACjC,UAAU,CAAC,sBAAsB,cAAc,aAAa;AAAA,EAC9D,IAAI;AAEJ,QAAM,QAAQ,UAAM,iBAAAA,SAAG,SAAS,EAAE,KAAK,QAAQ,SAAS,UAAU,KAAK,CAAC;AACxE,QAAM,aAA2B,CAAC;AAElC,aAAW,QAAQ,OAAO;AACxB,eAAW,KAAK,GAAG,YAAY,IAAI,CAAC;AAAA,EACtC;AAEA,SAAO;AACT;AAEA,eAAsB,aAAa,UAAwB,CAAC,GAAgC;AAC1F,QAAM;AAAA,IACJ,MAAM,QAAQ,IAAI;AAAA,IAClB,UAAU,CAAC,sBAAsB;AAAA,IACjC,UAAU,CAAC,sBAAsB,cAAc,aAAa;AAAA,EAC9D,IAAI;AAEJ,QAAM,QAAQ,UAAM,iBAAAA,SAAG,SAAS;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,aAAiC,CAAC;AAExC,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,UAAU,IAAI;AAC9B,eAAW,KAAK,GAAG,OAAO;AAAA,EAC5B;AAEA,SAAO;AACT;;;ACtWA,mBAAkB;AAQlB,eAAsB,KAAK,SAAqC;AAC9D,QAAM,EAAE,OAAO,IAAI,IAAI;AAEvB,UAAQ,IAAI,aAAAC,QAAM,KAAK;AAAA,kBAAqB,KAAK;AAAA,CAAK,CAAC;AAEvD,QAAM,UAAU,MAAM,aAAa,EAAE,IAAI,CAAC;AAC1C,QAAM,UAA8B,CAAC;AAErC,QAAM,aAAa,MAAM,YAAY;AAErC,aAAW,SAAS,SAAS;AAC3B,UAAM,SAAS,OAAO,OAAO,MAAM,YAAY;AAC/C,UAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,UAAU,CAAC;AAEvE,QAAI,SAAS;AACX,cAAQ,KAAK,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,IAAI,aAAAA,QAAM,OAAO,mBAAmB,CAAC;AAC7C;AAAA,EACF;AAEA,UAAQ,IAAI,aAAAA,QAAM,MAAM,SAAS,QAAQ,MAAM;AAAA,CAAmB,CAAC;AAEnE,aAAW,UAAU,SAAS;AAC5B,UAAM,eAAe,OAAO,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK,EAAE;AAChE,YAAQ,IAAI,aAAAA,QAAM,KAAK,GAAG,YAAY,IAAI,OAAO,IAAI,IAAI,OAAO,MAAM,EAAE,CAAC;AAEzE,eAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,OAAO,YAAY,GAAG;AAChE,YAAM,cAAc,KAAK;AAAA,QACvB,IAAI,OAAO,IAAI,KAAK,KAAK,IAAI;AAAA,QAC7B,aAAAA,QAAM,OAAO,IAAI;AAAA,MACnB;AACA,cAAQ,IAAI,KAAK,aAAAA,QAAM,KAAK,MAAM,CAAC,KAAK,WAAW,EAAE;AAAA,IACvD;AACA,YAAQ,IAAI;AAAA,EACd;AACF;;;AC/CA,IAAAC,gBAAkB;;;ACAlB,IAAAC,gBAAkB;AAUlB,IAAM,kBAAkB,CAAC,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ;AAE3E,eAAsB,OAAO,UAA4B,CAAC,GAAyC;AACjG,QAAM,EAAE,IAAI,IAAI;AAEhB,UAAQ,IAAI,cAAAC,QAAM,KAAK,sCAAsC,CAAC;AAE9D,QAAM,cAAc,MAAM,6BAA6B,EAAE,IAAI,CAAC;AAC9D,QAAM,SAAS,MAAM,qBAAqB,EAAE,IAAI,CAAC;AAGjD,QAAM,WAAW,oBAAI,IAAY;AACjC,aAAW,QAAQ,QAAQ;AACzB,aAAS,IAAI,KAAK,GAAG;AAErB,QAAI,CAAC,KAAK,IAAI,SAAS,GAAG,GAAG;AAC3B,eAAS,IAAI,KAAK,GAAG;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,aAA0B,CAAC;AAEjC,aAAW,SAAS,aAAa;AAC/B,eAAW,OAAO,MAAM,MAAM;AAC5B,YAAM,UAAU,MAAM,cAAc,YAAY,MAAM,GAAG,MAAM,SAAS,IAAI,GAAG;AAG/E,UAAI,SAAS,IAAI,OAAO,EAAG;AAI3B,UAAI,kBAAkB;AACtB,iBAAW,UAAU,iBAAiB;AACpC,YAAI,IAAI,SAAS,MAAM,GAAG;AACxB,gBAAM,UAAU,IAAI,MAAM,GAAG,CAAC,OAAO,MAAM;AAC3C,gBAAM,cAAc,MAAM,cAAc,YAAY,UAAU,GAAG,MAAM,SAAS,IAAI,OAAO;AAC3F,cAAI,SAAS,IAAI,WAAW,GAAG;AAC7B,8BAAkB;AAClB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,gBAAiB;AAErB,iBAAW,KAAK;AAAA,QACd,WAAW,MAAM;AAAA,QACjB,KAAK;AAAA,QACL,WAAW,MAAM;AAAA,QACjB,MAAM,MAAM;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,YAAY,YAAY,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,QAAQ,CAAC;AACvE,YAAQ,IAAI,cAAAA,QAAM,MAAM,iCAAiC,CAAC;AAC1D,YAAQ,IAAI,cAAAA,QAAM,KAAK,WAAW,SAAS,8BAA8B,OAAO,MAAM,cAAc,CAAC;AACrG,WAAO,EAAE,WAAW;AAAA,EACtB;AAEA,UAAQ,IAAI,cAAAA,QAAM,OAAO,SAAS,WAAW,MAAM;AAAA,CAA+B,CAAC;AACnF,aAAW,QAAQ,YAAY;AAC7B,UAAM,eAAe,KAAK,UAAU,QAAQ,QAAQ,IAAI,IAAI,KAAK,EAAE;AACnE,YAAQ,IAAI,KAAK,cAAAA,QAAM,IAAI,GAAG,CAAC,IAAI,cAAAA,QAAM,KAAK,KAAK,GAAG,CAAC,EAAE;AACzD,YAAQ,IAAI,cAAAA,QAAM,KAAK,kBAAkB,YAAY,IAAI,KAAK,IAAI,EAAE,CAAC;AAAA,EACvE;AAEA,UAAQ,IAAI;AACZ,SAAO,EAAE,WAAW;AACtB;;;AD/DA,SAAS,yBAAyB,OAAuC;AACvE,QAAM,eAAqD,CAAC;AAE5D,aAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,MAAM,YAAY,GAAG;AAC/D,UAAM,UAAU,KAAK,MAAM,YAAY,KAAK,CAAC;AAC7C,UAAM,WAAW,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK;AACvE,iBAAa,KAAK,EAAE,QAAQ,MAAM,SAAS,CAAC;AAAA,EAC9C;AAEA,MAAI,aAAa,SAAS,EAAG,QAAO;AAEpC,QAAM,YAAY,aAAa,CAAC;AAChC,QAAM,UAAoB,CAAC;AAE3B,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,UAAM,UAAU,aAAa,CAAC;AAC9B,UAAM,SAAS,IAAI,IAAI,UAAU,IAAI;AACrC,UAAM,SAAS,IAAI,IAAI,QAAQ,IAAI;AAEnC,UAAM,YAAY,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;AAC7D,UAAM,YAAY,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;AAE3D,QAAI,UAAU,SAAS,GAAG;AACxB,cAAQ;AAAA,QACN,GAAG,UAAU,MAAM,SAAS,UAAU,KAAK,MAAM,CAAC,gBAAgB,QAAQ,MAAM;AAAA,MAClF;AAAA,IACF;AACA,QAAI,UAAU,SAAS,GAAG;AACxB,cAAQ;AAAA,QACN,GAAG,QAAQ,MAAM,SAAS,UAAU,KAAK,MAAM,CAAC,gBAAgB,UAAU,MAAM;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,CAAC,KAAK;AAAA,IACf;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,OAAuC;AACtE,MAAI,CAAC,MAAM,SAAU,QAAO;AAE5B,QAAM,UAAU,OAAO,KAAK,MAAM,QAAQ;AAC1C,MAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,QAAM,UAAoB,CAAC;AAC3B,QAAM,YAAY,QAAQ,CAAC;AAC3B,QAAM,WAAW,MAAM,SAAS,SAAS;AAEzC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC;AACxB,UAAM,WAAW,MAAM,SAAS,MAAM;AAEtC,eAAW,WAAW,UAAU;AAC9B,YAAM,QAAQ,SAAS,KAAK,CAAC,MAA0C,EAAE,aAAa,QAAQ,QAAQ;AACtG,UAAI,SAAS,MAAM,SAAS,QAAQ,MAAM;AACxC,gBAAQ;AAAA,UACN,IAAI,QAAQ,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS,MAAM,IAAI,QAAQ,MAAM;AAAA,QAC7F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,CAAC,KAAK;AAAA,IACf;AAAA,EACF;AACF;AAEA,eAAsB,SAAS,UAA2B,CAAC,GAAkB;AAC3E,QAAM,EAAE,KAAK,SAAS,QAAQ,QAAQ,YAAY,IAAI;AAEtD,UAAQ,IAAI,cAAAC,QAAM,KAAK,gCAAgC,CAAC;AAExD,QAAM,UAAU,MAAM,aAAa,EAAE,IAAI,CAAC;AAC1C,QAAM,SAAkB,CAAC;AAGzB,QAAM,SAAS,oBAAI,IAAgC;AAEnD,aAAW,SAAS,SAAS;AAC3B,UAAM,MAAM,OAAO,OAAO,MAAM,YAAY,EAAE,CAAC,KAAK;AACpD,QAAI,CAAC,OAAO,IAAI,GAAG,GAAG;AACpB,aAAO,IAAI,KAAK,CAAC,CAAC;AAAA,IACpB;AACA,WAAO,IAAI,GAAG,EAAG,KAAK,KAAK;AAAA,EAC7B;AAGA,aAAW,CAAC,KAAK,KAAK,KAAK,QAAQ;AACjC,QAAI,MAAM,SAAS,EAAG;AAEtB,UAAM,kBAAkB,MAAM,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,YAAY,CAAC;AACvE,UAAM,aAAa,CAAC,GAAG,IAAI,IAAI,eAAe,CAAC;AAE/C,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SAAS,kCAAkC,GAAG;AAAA,QAC9C,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,CAAC,MAAM,aAAa,CAAC,CAAC;AAE5D,UAAI,QAAQ,SAAS,GAAG;AACtB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,oBAAoB,QAAQ,KAAK,IAAI,CAAC;AAAA,UAC/C,SAAS,CAAC,KAAK;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,aAAW,SAAS,SAAS;AAC3B,UAAM,QAAQ,yBAAyB,KAAK;AAC5C,QAAI,MAAO,QAAO,KAAK,KAAK;AAAA,EAC9B;AAGA,MAAI,QAAQ;AACV,eAAW,SAAS,SAAS;AAC3B,YAAM,QAAQ,wBAAwB,KAAK;AAC3C,UAAI,MAAO,QAAO,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AAGA,MAAI,cAAc;AAClB,MAAI,aAAa;AACf,UAAM,SAAS,MAAM,OAAO,EAAE,IAAI,CAAC;AACnC,kBAAc,OAAO,WAAW;AAAA,EAClC;AAGA,MAAI,OAAO,WAAW,KAAK,gBAAgB,GAAG;AAC5C,YAAQ,IAAI,cAAAA,QAAM,MAAM,+BAA+B,CAAC;AACxD,YAAQ,IAAI,cAAAA,QAAM,KAAK,WAAW,QAAQ,MAAM,iBAAiB,CAAC;AAClE,QAAI,QAAQ;AACV,cAAQ,IAAI,cAAAA,QAAM,KAAK,uBAAuB,CAAC;AAAA,IACjD;AACA,QAAI,aAAa;AACf,cAAQ,IAAI,cAAAA,QAAM,KAAK,gCAAgC,CAAC;AAAA,IAC1D;AACA;AAAA,EACF;AAEA,UAAQ,IAAI,cAAAA,QAAM,IAAI,SAAS,OAAO,MAAM;AAAA,CAAc,CAAC;AAE3D,aAAW,SAAS,QAAQ;AAC1B,YAAQ,IAAI,KAAK,cAAAA,QAAM,OAAO,MAAM,OAAO,CAAC,EAAE;AAE9C,eAAW,SAAS,MAAM,SAAS;AACjC,YAAM,eAAe,MAAM,KAAK,QAAQ,QAAQ,IAAI,IAAI,KAAK,EAAE;AAC/D,cAAQ,IAAI,cAAAA,QAAM,KAAK,MAAM,YAAY,IAAI,MAAM,IAAI,EAAE,CAAC;AAE1D,iBAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,MAAM,YAAY,GAAG;AAC/D,gBAAQ,IAAI,QAAQ,cAAAA,QAAM,KAAK,MAAM,CAAC,KAAK,IAAI,EAAE;AAAA,MACnD;AAAA,IACF;AAEA,QAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,iBAAW,UAAU,MAAM,SAAS;AAClC,gBAAQ,IAAI,cAAAA,QAAM,KAAK,eAAU,MAAM,EAAE,CAAC;AAAA,MAC5C;AAAA,IACF;AAEA,YAAQ,IAAI;AAAA,EACd;AAEA,MAAI,OAAO,SAAS,KAAK,cAAc,GAAG;AACxC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;AE9MA,IAAAC,gBAAkB;AAelB,eAAsB,SAAS,SAAyC;AACtE,QAAM,EAAE,KAAK,QAAQ,IAAI;AAEzB,UAAQ,IAAI,cAAAC,QAAM,KAAK,uCAAuC,CAAC;AAE/D,QAAM,UAAU,MAAM,aAAa,EAAE,IAAI,CAAC;AAE1C,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,IAAI,cAAAA,QAAM,OAAO,wBAAwB,CAAC;AAClD;AAAA,EACF;AAEA,QAAM,eAAiC,CAAC;AAExC,aAAW,UAAU,SAAS;AAC5B,QAAI,aAAa;AAEjB,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,aAAa,MAAM,GAAG;AAC9B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,KAAK,MAAO,aAAa,QAAQ,SAAU,GAAG;AAEjE,iBAAa,KAAK;AAAA,MAChB;AAAA,MACA,OAAO,QAAQ;AAAA,MACf;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAGA,UAAQ,IAAI,cAAAA,QAAM,KAAK,yBAAyB,CAAC;AAEjD,QAAM,eAAe,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC;AAEhE,UAAQ;AAAA,IACN,cAAAA,QAAM;AAAA,MACJ,GAAG,SAAS,OAAO,YAAY,CAAC,KAAK,WAAW,SAAS,EAAE,CAAC,KAAK,aAAa,SAAS,EAAE,CAAC;AAAA,IAC5F;AAAA,EACF;AACA,UAAQ,IAAI,cAAAA,QAAM,KAAK,SAAI,OAAO,eAAe,EAAE,CAAC,CAAC;AAErD,aAAW,QAAQ,cAAc;AAC/B,UAAM,QACJ,KAAK,eAAe,MAAM,cAAAA,QAAM,QAChC,KAAK,cAAc,KAAK,cAAAA,QAAM,SAAS,cAAAA,QAAM;AAE/C,UAAM,MAAM,kBAAkB,KAAK,YAAY,EAAE;AACjD,UAAM,aAAa,GAAG,KAAK,UAAU,IAAI,SAAS,CAAC;AAEnD,YAAQ;AAAA,MACN,GAAG,KAAK,OAAO,OAAO,YAAY,CAAC,KAAK,MAAM,GAAG,CAAC,IAAI,MAAM,UAAU,CAAC,KAAK,cAAAA,QAAM,KAAK,GAAG,KAAK,UAAU,IAAI,KAAK,KAAK,EAAE,CAAC;AAAA,IAC5H;AAAA,EACF;AAEA,UAAQ,IAAI;AAGZ,QAAM,eAAe,aAAa,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,EAAE;AACtE,QAAM,mBAAmB,aAAa,OAAO,CAAC,MAAM,EAAE,aAAa,KAAK,EAAE,aAAa,GAAG,EAAE;AAC5F,QAAM,aAAa,aAAa,OAAO,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE;AAElE,MAAI,iBAAiB,QAAQ,QAAQ;AACnC,YAAQ,IAAI,cAAAA,QAAM,MAAM,mCAAmC,CAAC;AAAA,EAC9D,OAAO;AACL,YAAQ,IAAI,cAAAA,QAAM,KAAK,SAAS,YAAY,cAAc,gBAAgB,YAAY,UAAU,EAAE,CAAC;AAAA,EACrG;AACF;AAEA,SAAS,kBAAkB,YAAoB,OAAuB;AACpE,QAAM,SAAS,KAAK,MAAO,aAAa,MAAO,KAAK;AACpD,QAAM,QAAQ,QAAQ;AAEtB,SAAO,SAAI,OAAO,MAAM,IAAI,SAAI,OAAO,KAAK;AAC9C;;;AC5FA,IAAAC,MAAoB;AACpB,WAAsB;AACtB,IAAAC,gBAAkB;AAQlB,IAAMC,mBAAkB,CAAC,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ;AAE3E,eAAsB,QAAQ,UAA0B,CAAC,GAAkB;AACzE,QAAM,EAAE,KAAK,SAAS,gBAAgB,IAAI;AAE1C,UAAQ,IAAI,cAAAC,QAAM,KAAK,oCAAoC,CAAC;AAE5D,QAAM,cAAc,MAAM,6BAA6B,EAAE,IAAI,CAAC;AAG9D,QAAM,UAAU,oBAAI,IAAY;AAEhC,aAAW,SAAS,aAAa;AAC/B,eAAW,OAAO,MAAM,MAAM;AAC5B,YAAM,UAAU,MAAM,cAAc,YAAY,MAAM,GAAG,MAAM,SAAS,IAAI,GAAG;AAC/E,cAAQ,IAAI,OAAO;AAGnB,iBAAW,UAAUD,kBAAiB;AACpC,YAAI,IAAI,SAAS,MAAM,GAAG;AACxB,gBAAM,UAAU,IAAI,MAAM,GAAG,CAAC,OAAO,MAAM;AAC3C,gBAAM,cAAc,MAAM,cAAc,YAAY,UAAU,GAAG,MAAM,SAAS,IAAI,OAAO;AAC3F,kBAAQ,IAAI,WAAW;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,IAAI,cAAAC,QAAM,OAAO,2EAA2E,CAAC;AACrG;AAAA,EACF;AAEA,QAAM,aAAa,CAAC,GAAG,OAAO,EAAE,KAAK;AAGrC,QAAM,WAAW,WAAW,IAAI,OAAK,UAAU,CAAC,GAAG,EAAE,KAAK,IAAI;AAE9D,QAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeR,QAAM,aAAkB,aAAQ,OAAO,QAAQ,IAAI,GAAG,MAAM;AAC5D,QAAM,YAAiB,aAAQ,UAAU;AAEzC,MAAI,CAAI,eAAW,SAAS,GAAG;AAC7B,IAAG,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC7C;AAEA,EAAG,kBAAc,YAAY,SAAS,OAAO;AAE7C,UAAQ,IAAI,cAAAA,QAAM,MAAM,aAAa,WAAW,MAAM,wBAAwB,CAAC;AAC/E,UAAQ,IAAI,cAAAA,QAAM,KAAK,WAAW,UAAU;AAAA,CAAI,CAAC;AAGjD,QAAM,SAAS,WAAW,MAAM,GAAG,CAAC;AACpC,aAAW,OAAO,QAAQ;AACxB,YAAQ,IAAI,KAAK,cAAAA,QAAM,KAAK,GAAG,CAAC,EAAE;AAAA,EACpC;AACA,MAAI,WAAW,SAAS,GAAG;AACzB,YAAQ,IAAI,cAAAA,QAAM,KAAK,aAAa,WAAW,SAAS,CAAC,OAAO,CAAC;AAAA,EACnE;AACF;","names":["traverse","fg","chalk","import_chalk","import_chalk","chalk","chalk","import_chalk","chalk","fs","import_chalk","PLURAL_SUFFIXES","chalk"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/parser.ts","../src/commands/find.ts","../src/commands/validate.ts","../src/commands/unused.ts","../src/commands/coverage.ts","../src/commands/typegen.ts","../src/commands/extract.ts"],"sourcesContent":["export {\n parseProject,\n parseDictionaryKeys,\n parseTCalls,\n extractProjectDictionaryKeys,\n extractProjectTCalls,\n type TranslationEntry,\n type DictionaryKeyEntry,\n type TCallEntry,\n} from './parser'\nexport { find } from './commands/find'\nexport { validate } from './commands/validate'\nexport { coverage } from './commands/coverage'\nexport { unused } from './commands/unused'\nexport { typegen } from './commands/typegen'\nexport { extract } from './commands/extract'\n","import { parse } from '@babel/parser'\nimport traverse from '@babel/traverse'\nimport * as fs from 'fs'\nimport fg from 'fast-glob'\n\n// v0.8.0: Dictionary key and t() call extraction\n\nexport interface DictionaryKeyEntry {\n file: string\n line: number\n namespace: string\n keys: string[]\n}\n\nexport interface TCallEntry {\n file: string\n line: number\n key: string\n}\n\nexport interface ICUTypeInfo {\n variable: string\n type: string\n}\n\nexport interface TranslationEntry {\n file: string\n line: number\n column: number\n translations: Record<string, string>\n variables: string[]\n /** ICU type information per locale (v0.7.0) */\n icuTypes?: Record<string, ICUTypeInfo[]>\n}\n\ninterface ParseOptions {\n cwd?: string\n include?: string[]\n exclude?: string[]\n}\n\nconst IT_FUNCTION_NAMES = [\n 'it',\n 'it_ja', 'it_zh', 'it_es', 'it_fr', 'it_de',\n 'en_ja', 'en_zh', 'en_es', 'en_fr', 'en_de',\n 'ja_zh', 'ja_es', 'zh_es',\n]\n\nconst PAIR_MAPPING: Record<string, [string, string]> = {\n it: ['ko', 'en'],\n it_ja: ['ko', 'ja'],\n it_zh: ['ko', 'zh'],\n it_es: ['ko', 'es'],\n it_fr: ['ko', 'fr'],\n it_de: ['ko', 'de'],\n en_ja: ['en', 'ja'],\n en_zh: ['en', 'zh'],\n en_es: ['en', 'es'],\n en_fr: ['en', 'fr'],\n en_de: ['en', 'de'],\n ja_zh: ['ja', 'zh'],\n ja_es: ['ja', 'es'],\n zh_es: ['zh', 'es'],\n}\n\nfunction extractVariables(text: string): string[] {\n const matches = text.match(/\\{(\\w+)\\}/g)\n if (!matches) return []\n return matches.map((m) => m.slice(1, -1))\n}\n\nconst ICU_TYPE_PATTERN = /\\{(\\w+),\\s*(\\w+)/g\n\nfunction extractICUTypes(text: string): ICUTypeInfo[] {\n const types: ICUTypeInfo[] = []\n let match: RegExpExecArray | null\n ICU_TYPE_PATTERN.lastIndex = 0\n while ((match = ICU_TYPE_PATTERN.exec(text)) !== null) {\n types.push({ variable: match[1]!, type: match[2]! })\n }\n return types\n}\n\nfunction parseFile(filePath: string): TranslationEntry[] {\n const entries: TranslationEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier') return\n if (!IT_FUNCTION_NAMES.includes(callee.name)) return\n\n const funcName = callee.name\n const args = node.arguments\n const loc = node.loc\n\n if (!loc) return\n\n const entry: TranslationEntry = {\n file: filePath,\n line: loc.start.line,\n column: loc.start.column,\n translations: {},\n variables: [],\n }\n\n if (args[0]?.type === 'ObjectExpression') {\n const obj = args[0]\n for (const prop of obj.properties) {\n if (\n prop.type === 'ObjectProperty' &&\n prop.key.type === 'Identifier' &&\n prop.value.type === 'StringLiteral'\n ) {\n entry.translations[prop.key.name] = prop.value.value\n entry.variables.push(...extractVariables(prop.value.value))\n // Extract ICU type info (v0.7.0)\n const types = extractICUTypes(prop.value.value)\n if (types.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[prop.key.name] = types\n }\n }\n }\n } else if (\n args[0]?.type === 'StringLiteral' &&\n args[1]?.type === 'StringLiteral'\n ) {\n const [lang1, lang2] = PAIR_MAPPING[funcName] || ['ko', 'en']\n entry.translations[lang1] = args[0].value\n entry.translations[lang2] = args[1].value\n entry.variables.push(...extractVariables(args[0].value))\n entry.variables.push(...extractVariables(args[1].value))\n // Extract ICU type info (v0.7.0)\n const types1 = extractICUTypes(args[0].value)\n if (types1.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang1] = types1\n }\n const types2 = extractICUTypes(args[1].value)\n if (types2.length > 0) {\n if (!entry.icuTypes) entry.icuTypes = {}\n entry.icuTypes[lang2] = types2\n }\n }\n\n entry.variables = [...new Set(entry.variables)]\n\n if (Object.keys(entry.translations).length > 0) {\n entries.push(entry)\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Flatten nested ObjectExpression to dot-notation keys\nfunction flattenObjectKeys(\n node: { type: string; properties?: unknown[] },\n prefix: string = '',\n): string[] {\n const keys: string[] = []\n if (node.type !== 'ObjectExpression' || !node.properties) return keys\n\n for (const prop of node.properties as Array<{\n type: string\n key: { type: string; name?: string; value?: string }\n value: { type: string; properties?: unknown[] }\n }>) {\n if (prop.type !== 'ObjectProperty') continue\n\n let propName: string | undefined\n if (prop.key.type === 'Identifier') propName = prop.key.name\n else if (prop.key.type === 'StringLiteral') propName = prop.key.value\n\n if (!propName) continue\n\n const fullKey = prefix ? `${prefix}.${propName}` : propName\n\n if (prop.value.type === 'StringLiteral') {\n keys.push(fullKey)\n } else if (prop.value.type === 'ObjectExpression') {\n keys.push(...flattenObjectKeys(prop.value, fullKey))\n }\n }\n return keys\n}\n\n// v0.8.0: Extract dictionary keys from loadDictionaries() calls\nexport function parseDictionaryKeys(filePath: string): DictionaryKeyEntry[] {\n const entries: DictionaryKeyEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 'loadDictionaries') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'ObjectExpression') return\n\n // Second argument is optional namespace\n let namespace = 'default'\n if (args[1]?.type === 'StringLiteral') {\n namespace = args[1].value\n }\n\n // First argument: { locale: { key: value } }\n // Collect keys from the first locale's dict (all locales should have same keys)\n const dictObj = args[0]\n const allKeys = new Set<string>()\n\n for (const localeProp of dictObj.properties as Array<{\n type: string\n value: { type: string; properties?: unknown[] }\n }>) {\n if (localeProp.type !== 'ObjectProperty') continue\n if (localeProp.value.type !== 'ObjectExpression') continue\n\n const localeKeys = flattenObjectKeys(localeProp.value)\n for (const key of localeKeys) {\n allKeys.add(key)\n }\n }\n\n if (allKeys.size > 0) {\n entries.push({\n file: filePath,\n line: loc.start.line,\n namespace,\n keys: [...allKeys],\n })\n }\n },\n })\n\n return entries\n}\n\n// v0.8.0: Extract t() call sites\nexport function parseTCalls(filePath: string): TCallEntry[] {\n const entries: TCallEntry[] = []\n const code = fs.readFileSync(filePath, 'utf-8')\n\n let ast\n try {\n ast = parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n })\n } catch {\n return []\n }\n\n traverse(ast, {\n CallExpression(nodePath) {\n const { node } = nodePath\n const { callee } = node\n\n if (callee.type !== 'Identifier' || callee.name !== 't') return\n\n const args = node.arguments\n const loc = node.loc\n if (!loc || !args[0] || args[0].type !== 'StringLiteral') return\n\n entries.push({\n file: filePath,\n line: loc.start.line,\n key: args[0].value,\n })\n },\n })\n\n return entries\n}\n\nexport async function extractProjectDictionaryKeys(options: ParseOptions = {}): Promise<DictionaryKeyEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: DictionaryKeyEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseDictionaryKeys(file))\n }\n\n return allEntries\n}\n\nexport async function extractProjectTCalls(options: ParseOptions = {}): Promise<TCallEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, { cwd, ignore: exclude, absolute: true })\n const allEntries: TCallEntry[] = []\n\n for (const file of files) {\n allEntries.push(...parseTCalls(file))\n }\n\n return allEntries\n}\n\nexport async function parseProject(options: ParseOptions = {}): Promise<TranslationEntry[]> {\n const {\n cwd = process.cwd(),\n include = ['**/*.{ts,tsx,js,jsx}'],\n exclude = ['**/node_modules/**', '**/dist/**', '**/.next/**'],\n } = options\n\n const files = await fg(include, {\n cwd,\n ignore: exclude,\n absolute: true,\n })\n\n const allEntries: TranslationEntry[] = []\n\n for (const file of files) {\n const entries = parseFile(file)\n allEntries.push(...entries)\n }\n\n return allEntries\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface FindOptions {\n query: string\n cwd?: string\n}\n\nexport async function find(options: FindOptions): Promise<void> {\n const { query, cwd } = options\n\n console.log(chalk.blue(`\\nSearching for: \"${query}\"\\n`))\n\n const entries = await parseProject({ cwd })\n const results: TranslationEntry[] = []\n\n const lowerQuery = query.toLowerCase()\n\n for (const entry of entries) {\n const values = Object.values(entry.translations)\n const matches = values.some((v) => v.toLowerCase().includes(lowerQuery))\n\n if (matches) {\n results.push(entry)\n }\n }\n\n if (results.length === 0) {\n console.log(chalk.yellow('No results found.'))\n return\n }\n\n console.log(chalk.green(`Found ${results.length} occurrence(s):\\n`))\n\n for (const result of results) {\n const relativePath = result.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(`${relativePath}:${result.line}:${result.column}`))\n\n for (const [locale, text] of Object.entries(result.translations)) {\n const highlighted = text.replace(\n new RegExp(`(${query})`, 'gi'),\n chalk.yellow('$1')\n )\n console.log(` ${chalk.cyan(locale)}: ${highlighted}`)\n }\n console.log()\n }\n}\n","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\nimport { unused } from './unused'\n\ninterface ValidateOptions {\n cwd?: string\n locales?: string[]\n strict?: boolean\n unused?: boolean\n noExit?: boolean\n}\n\ninterface Issue {\n type: 'inconsistent' | 'missing' | 'variable_mismatch' | 'icu_type_mismatch'\n message: string\n entries: TranslationEntry[]\n details?: string[]\n}\n\nfunction checkVariableConsistency(entry: TranslationEntry): Issue | null {\n const varsByLocale: { locale: string; vars: string[] }[] = []\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n const matches = text.match(/\\{(\\w+)\\}/g) || []\n const varNames = [...new Set(matches.map((v) => v.slice(1, -1)))].sort()\n varsByLocale.push({ locale, vars: varNames })\n }\n\n if (varsByLocale.length < 2) return null\n\n const reference = varsByLocale[0]!\n const details: string[] = []\n\n for (let i = 1; i < varsByLocale.length; i++) {\n const current = varsByLocale[i]!\n const refSet = new Set(reference.vars)\n const curSet = new Set(current.vars)\n\n const onlyInRef = reference.vars.filter((v) => !curSet.has(v))\n const onlyInCur = current.vars.filter((v) => !refSet.has(v))\n\n if (onlyInRef.length > 0) {\n details.push(\n `${reference.locale} has {${onlyInRef.join('}, {')}} missing in ${current.locale}`,\n )\n }\n if (onlyInCur.length > 0) {\n details.push(\n `${current.locale} has {${onlyInCur.join('}, {')}} missing in ${reference.locale}`,\n )\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'variable_mismatch',\n message: 'Variable mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nfunction checkICUTypeConsistency(entry: TranslationEntry): Issue | null {\n if (!entry.icuTypes) return null\n\n const locales = Object.keys(entry.icuTypes)\n if (locales.length < 2) return null\n\n const details: string[] = []\n const reference = locales[0]!\n const refTypes = entry.icuTypes[reference]!\n\n for (let i = 1; i < locales.length; i++) {\n const locale = locales[i]!\n const curTypes = entry.icuTypes[locale]!\n\n for (const refType of refTypes) {\n const match = curTypes.find((t: { variable: string; type: string }) => t.variable === refType.variable)\n if (match && match.type !== refType.type) {\n details.push(\n `{${refType.variable}} is \"${refType.type}\" in ${reference} but \"${match.type}\" in ${locale}`,\n )\n }\n }\n }\n\n if (details.length === 0) return null\n\n return {\n type: 'icu_type_mismatch',\n message: 'ICU type mismatch between translations',\n entries: [entry],\n details,\n }\n}\n\nexport async function validate(options: ValidateOptions = {}): Promise<void> {\n const { cwd, locales, strict, unused: checkUnused } = options\n\n console.log(chalk.blue('\\nValidating translations...\\n'))\n\n const entries = await parseProject({ cwd })\n const issues: Issue[] = []\n\n // group by first language text (usually ko)\n const groups = new Map<string, TranslationEntry[]>()\n\n for (const entry of entries) {\n const key = Object.values(entry.translations)[0] || ''\n if (!groups.has(key)) {\n groups.set(key, [])\n }\n groups.get(key)!.push(entry)\n }\n\n // check for inconsistent translations\n for (const [key, group] of groups) {\n if (group.length < 2) continue\n\n const translationSets = group.map((e) => JSON.stringify(e.translations))\n const uniqueSets = [...new Set(translationSets)]\n\n if (uniqueSets.length > 1) {\n issues.push({\n type: 'inconsistent',\n message: `Inconsistent translations for \"${key}\"`,\n entries: group,\n })\n }\n }\n\n // check for missing locales\n if (locales && locales.length > 0) {\n for (const entry of entries) {\n const missing = locales.filter((l) => !entry.translations[l])\n\n if (missing.length > 0) {\n issues.push({\n type: 'missing',\n message: `Missing locales: ${missing.join(', ')}`,\n entries: [entry],\n })\n }\n }\n }\n\n // check for variable name consistency (enhanced in v0.7.0)\n for (const entry of entries) {\n const issue = checkVariableConsistency(entry)\n if (issue) issues.push(issue)\n }\n\n // check for ICU type consistency (strict mode, v0.7.0)\n if (strict) {\n for (const entry of entries) {\n const issue = checkICUTypeConsistency(entry)\n if (issue) issues.push(issue)\n }\n }\n\n // unused key detection (v0.8.0)\n let unusedCount = 0\n if (checkUnused) {\n const result = await unused({ cwd })\n unusedCount = result.unusedKeys.length\n }\n\n // print results\n if (issues.length === 0 && unusedCount === 0) {\n console.log(chalk.green('All translations are valid!\\n'))\n console.log(chalk.gray(`Checked ${entries.length} translation(s)`))\n if (strict) {\n console.log(chalk.gray('(strict mode enabled)'))\n }\n if (checkUnused) {\n console.log(chalk.gray('(unused key detection enabled)'))\n }\n return\n }\n\n console.log(chalk.red(`Found ${issues.length} issue(s):\\n`))\n\n for (const issue of issues) {\n console.log(` ${chalk.yellow(issue.message)}`)\n\n for (const entry of issue.entries) {\n const relativePath = entry.file.replace(process.cwd() + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n\n for (const [locale, text] of Object.entries(entry.translations)) {\n console.log(` ${chalk.cyan(locale)}: ${text}`)\n }\n }\n\n if (issue.details && issue.details.length > 0) {\n for (const detail of issue.details) {\n console.log(chalk.gray(` → ${detail}`))\n }\n }\n\n console.log()\n }\n\n if ((issues.length > 0 || unusedCount > 0) && !options.noExit) {\n process.exit(1)\n }\n}\n","import chalk from 'chalk'\nimport { extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface UnusedKey {\n namespace: string\n key: string\n definedIn: string\n line: number\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function unused(options: { cwd?: string } = {}): Promise<{ unusedKeys: UnusedKey[] }> {\n const { cwd } = options\n\n console.log(chalk.blue('\\nDetecting unused translations...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n // Build set of used keys (normalized: namespace:key or key for default)\n const usedKeys = new Set<string>()\n for (const call of tCalls) {\n usedKeys.add(call.key)\n // Also add with default namespace if no namespace prefix\n if (!call.key.includes(':')) {\n usedKeys.add(call.key)\n }\n }\n\n // Check each dictionary key against used keys\n const unusedKeys: UnusedKey[] = []\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n\n // Check if key is directly used\n if (usedKeys.has(fullKey)) continue\n\n // Check if this is a plural suffix variant (e.g. count_one, count_other)\n // and the base key is used via t('items.count', { count: N })\n let isPluralVariant = false\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n if (usedKeys.has(fullBaseKey)) {\n isPluralVariant = true\n break\n }\n }\n }\n if (isPluralVariant) continue\n\n unusedKeys.push({\n namespace: entry.namespace,\n key: fullKey,\n definedIn: entry.file,\n line: entry.line,\n })\n }\n }\n\n // Report results\n if (unusedKeys.length === 0) {\n const totalKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n console.log(chalk.green('No unused translations found!\\n'))\n console.log(chalk.gray(`Checked ${totalKeys} dictionary key(s) against ${tCalls.length} t() call(s)`))\n return { unusedKeys }\n }\n\n console.log(chalk.yellow(`Found ${unusedKeys.length} unused translation key(s):\\n`))\n for (const item of unusedKeys) {\n const relativePath = item.definedIn.replace(process.cwd() + '/', '')\n console.log(` ${chalk.red('-')} ${chalk.cyan(item.key)}`)\n console.log(chalk.gray(` defined in ${relativePath}:${item.line}`))\n }\n\n console.log()\n return { unusedKeys }\n}\n","import chalk from 'chalk'\nimport { parseProject } from '../parser'\n\ninterface CoverageOptions {\n cwd?: string\n locales: string[]\n}\n\ninterface LocaleCoverage {\n locale: string\n total: number\n translated: number\n percentage: number\n}\n\nexport async function coverage(options: CoverageOptions): Promise<void> {\n const { cwd, locales } = options\n\n console.log(chalk.blue('\\nAnalyzing translation coverage...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n const coverageData: LocaleCoverage[] = []\n\n for (const locale of locales) {\n let translated = 0\n\n for (const entry of entries) {\n if (entry.translations[locale]) {\n translated++\n }\n }\n\n const percentage = Math.round((translated / entries.length) * 100)\n\n coverageData.push({\n locale,\n total: entries.length,\n translated,\n percentage,\n })\n }\n\n // print coverage table\n console.log(chalk.bold('Translation Coverage:\\n'))\n\n const maxLocaleLen = Math.max(...locales.map((l) => l.length), 6)\n\n console.log(\n chalk.gray(\n `${'Locale'.padEnd(maxLocaleLen)} ${'Coverage'.padStart(10)} ${'Translated'.padStart(12)}`\n )\n )\n console.log(chalk.gray('─'.repeat(maxLocaleLen + 26)))\n\n for (const data of coverageData) {\n const color =\n data.percentage === 100 ? chalk.green :\n data.percentage >= 80 ? chalk.yellow : chalk.red\n\n const bar = createProgressBar(data.percentage, 10)\n const percentStr = `${data.percentage}%`.padStart(4)\n\n console.log(\n `${data.locale.padEnd(maxLocaleLen)} ${color(bar)} ${color(percentStr)} ${chalk.gray(`${data.translated}/${data.total}`)}`\n )\n }\n\n console.log()\n\n // summary\n const fullyCovered = coverageData.filter((d) => d.percentage === 100).length\n const partiallyCovered = coverageData.filter((d) => d.percentage > 0 && d.percentage < 100).length\n const notCovered = coverageData.filter((d) => d.percentage === 0).length\n\n if (fullyCovered === locales.length) {\n console.log(chalk.green('All locales are fully translated!'))\n } else {\n console.log(chalk.gray(`Full: ${fullyCovered}, Partial: ${partiallyCovered}, Empty: ${notCovered}`))\n }\n}\n\nfunction createProgressBar(percentage: number, width: number): string {\n const filled = Math.round((percentage / 100) * width)\n const empty = width - filled\n\n return '█'.repeat(filled) + '░'.repeat(empty)\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport chalk from 'chalk'\nimport { extractProjectDictionaryKeys } from '../parser'\n\ninterface TypegenOptions {\n cwd?: string\n output?: string\n}\n\nconst PLURAL_SUFFIXES = ['_zero', '_one', '_two', '_few', '_many', '_other']\n\nexport async function typegen(options: TypegenOptions = {}): Promise<void> {\n const { cwd, output = 'src/i18n.d.ts' } = options\n\n console.log(chalk.blue('\\nGenerating TypeScript types...\\n'))\n\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n\n // Collect all unique full keys (namespace:key or key)\n const allKeys = new Set<string>()\n\n for (const entry of dictEntries) {\n for (const key of entry.keys) {\n const fullKey = entry.namespace === 'default' ? key : `${entry.namespace}:${key}`\n allKeys.add(fullKey)\n\n // Also add plural base keys (strip _one, _other, etc.)\n for (const suffix of PLURAL_SUFFIXES) {\n if (key.endsWith(suffix)) {\n const baseKey = key.slice(0, -suffix.length)\n const fullBaseKey = entry.namespace === 'default' ? baseKey : `${entry.namespace}:${baseKey}`\n allKeys.add(fullBaseKey)\n }\n }\n }\n }\n\n if (allKeys.size === 0) {\n console.log(chalk.yellow('No dictionary keys found. Make sure loadDictionaries() calls are present.'))\n return\n }\n\n const sortedKeys = [...allKeys].sort()\n\n // Generate the .d.ts content\n const keyUnion = sortedKeys.map(k => ` | '${k}'`).join('\\n')\n\n const content = `// Auto-generated by inline-i18n typegen\n// Do not edit manually. Re-run: npx inline-i18n typegen\n\nimport 'inline-i18n-multi'\n\ndeclare module 'inline-i18n-multi' {\n export type TranslationKey =\n${keyUnion}\n\n export function t(\n key: TranslationKey,\n vars?: TranslationVars,\n locale?: string\n ): string\n\n export function hasTranslation(\n key: TranslationKey,\n locale?: string\n ): boolean\n}\n`\n\n const outputPath = path.resolve(cwd || process.cwd(), output)\n const outputDir = path.dirname(outputPath)\n\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8')\n\n console.log(chalk.green(`Generated ${sortedKeys.length} translation key types`))\n console.log(chalk.gray(`Output: ${outputPath}\\n`))\n\n // Show sample\n const sample = sortedKeys.slice(0, 5)\n for (const key of sample) {\n console.log(` ${chalk.cyan(key)}`)\n }\n if (sortedKeys.length > 5) {\n console.log(chalk.gray(` ... and ${sortedKeys.length - 5} more`))\n }\n}\n","import chalk from 'chalk'\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { parseProject } from '../parser'\n\ninterface ExtractOptions {\n cwd?: string\n output?: string\n format?: 'flat' | 'nested'\n}\n\nexport async function extract(options: ExtractOptions = {}): Promise<void> {\n const { cwd, output = 'translations', format = 'flat' } = options\n\n console.log(chalk.blue('\\nExtracting inline translations...\\n'))\n\n const entries = await parseProject({ cwd })\n\n if (entries.length === 0) {\n console.log(chalk.yellow('No translations found.'))\n return\n }\n\n // Group translations by locale\n const byLocale: Record<string, Record<string, string>> = {}\n const basePath = cwd || process.cwd()\n\n for (const entry of entries) {\n for (const [locale, text] of Object.entries(entry.translations)) {\n if (!byLocale[locale]) byLocale[locale] = {}\n\n const relativePath = entry.file.replace(basePath + '/', '')\n const key = `${relativePath}:${entry.line}`\n byLocale[locale][key] = text\n }\n }\n\n // Write output files\n const outputDir = path.resolve(basePath, output)\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true })\n }\n\n const locales = Object.keys(byLocale).sort()\n for (const locale of locales) {\n const translations = byLocale[locale]!\n let content: string\n\n if (format === 'nested') {\n const nested = buildNestedObject(translations)\n content = JSON.stringify(nested, null, 2) + '\\n'\n } else {\n content = JSON.stringify(translations, null, 2) + '\\n'\n }\n\n const filePath = path.join(outputDir, `${locale}.json`)\n fs.writeFileSync(filePath, content)\n console.log(\n chalk.green(` ${locale}.json`) +\n chalk.gray(` (${Object.keys(translations).length} keys)`)\n )\n }\n\n console.log(chalk.gray(`\\nExtracted ${entries.length} translation(s) to ${output}/`))\n}\n\n/**\n * Build a nested object from flat dot-notation keys\n */\nfunction buildNestedObject(flat: Record<string, string>): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(flat)) {\n const parts = key.split('.')\n let current: Record<string, unknown> = result\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!\n if (!current[part] || typeof current[part] !== 'object') {\n current[part] = {}\n }\n current = current[part] as Record<string, unknown>\n }\n\n current[parts[parts.length - 1]!] = value\n }\n\n return result\n}\n"],"mappings":"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","names":["traverse","fg","chalk","import_chalk","import_chalk","chalk","chalk","import_chalk","chalk","fs","import_chalk","PLURAL_SUFFIXES","chalk","import_chalk","fs","path","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inline-i18n-multi/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "CLI tools for inline-i18n-multi",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -27,6 +27,7 @@
27
27
  "@babel/parser": "^7.26.3",
28
28
  "@babel/traverse": "^7.26.4",
29
29
  "chalk": "^5.4.1",
30
+ "chokidar": "^5.0.0",
30
31
  "commander": "^13.0.0",
31
32
  "fast-glob": "^3.3.3"
32
33
  },