@inline-i18n-multi/cli 0.8.0 → 0.10.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,100 @@ 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
+
139
+ ### Diff Command (v0.10.0)
140
+
141
+ Compare translations between two locales to find missing, extra, or differing keys:
142
+
143
+ ```bash
144
+ npx inline-i18n diff en ko
145
+ npx inline-i18n diff en ko --all
146
+ ```
147
+
148
+ By default, `diff` shows keys that exist in one locale but not the other. Use the `--all` flag to also show shared keys for a complete comparison.
149
+
150
+ Example output:
151
+
152
+ ```
153
+ Comparing en ↔ ko
154
+
155
+ Only in en:
156
+ - settings.theme
157
+ - settings.notifications
158
+
159
+ Only in ko:
160
+ - onboarding.welcome
161
+
162
+ Shared: 45 keys (use --all to show)
163
+ ```
164
+
165
+ ### Stats Command (v0.10.0)
166
+
167
+ Display a translation statistics dashboard with an overview of your project's translation coverage:
168
+
169
+ ```bash
170
+ npx inline-i18n stats
171
+ ```
172
+
173
+ Shows:
174
+ - **Overview** — Total keys, locales, and namespaces
175
+ - **Locale breakdown** — Per-locale key count and coverage percentage
176
+ - **Namespaces** — Key distribution across namespaces
177
+ - **Top files** — Files with the most translation calls
178
+ - **ICU usage** — Breakdown of ICU message types used (plural, select, date, number, etc.)
179
+
180
+ Example output:
181
+
182
+ ```
183
+ Translation Statistics
184
+ ======================
185
+
186
+ Overview
187
+ Total keys: 128
188
+ Locales: 3 (en, ko, ja)
189
+ Namespaces: 2 (default, common)
190
+
191
+ Locale Breakdown
192
+ en 128/128 100%
193
+ ko 120/128 94%
194
+ ja 115/128 90%
195
+
196
+ Top Files
197
+ src/components/Header.tsx 18 keys
198
+ src/pages/Dashboard.tsx 15 keys
199
+ src/pages/Settings.tsx 12 keys
200
+
201
+ ICU Usage
202
+ plural 23 occurrences
203
+ select 8 occurrences
204
+ date 5 occurrences
205
+ number 4 occurrences
206
+ ```
207
+
103
208
  ## Options
104
209
 
105
210
  ```
@@ -109,6 +214,8 @@ npx inline-i18n report
109
214
  --format, -f Output format: json, csv (default: json)
110
215
  --strict Enable strict mode (ICU type consistency check)
111
216
  --unused Detect unused translation keys (validate command)
217
+ --watch, -w Watch mode for validate/typegen (re-run on file changes)
218
+ --all Show shared keys in diff output (diff command)
112
219
  ```
113
220
 
114
221
  ## 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,274 @@ ${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/commands/diff.ts
723
+ var import_chalk7 = __toESM(require("chalk"));
724
+ async function diff(options) {
725
+ const { locale1, locale2, cwd, all } = options;
726
+ const basePath = cwd || process.cwd();
727
+ console.log(import_chalk7.default.blue(`
728
+ Comparing ${locale1} vs ${locale2}...
729
+ `));
730
+ const entries = await parseProject({ cwd });
731
+ if (entries.length === 0) {
732
+ console.log(import_chalk7.default.yellow("No translations found."));
733
+ return;
734
+ }
735
+ const onlyIn1 = [];
736
+ const onlyIn2 = [];
737
+ const shared = [];
738
+ for (const entry of entries) {
739
+ const has1 = !!entry.translations[locale1];
740
+ const has2 = !!entry.translations[locale2];
741
+ if (has1 && has2) shared.push(entry);
742
+ else if (has1 && !has2) onlyIn1.push(entry);
743
+ else if (!has1 && has2) onlyIn2.push(entry);
744
+ }
745
+ if (onlyIn1.length > 0) {
746
+ console.log(import_chalk7.default.red(`Only in ${locale1} (${onlyIn1.length}):
747
+ `));
748
+ for (const entry of onlyIn1) {
749
+ const relativePath = entry.file.replace(basePath + "/", "");
750
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
751
+ console.log(` ${import_chalk7.default.cyan(locale1)}: ${entry.translations[locale1]}`);
752
+ console.log();
753
+ }
754
+ }
755
+ if (onlyIn2.length > 0) {
756
+ console.log(import_chalk7.default.red(`Only in ${locale2} (${onlyIn2.length}):
757
+ `));
758
+ for (const entry of onlyIn2) {
759
+ const relativePath = entry.file.replace(basePath + "/", "");
760
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
761
+ console.log(` ${import_chalk7.default.cyan(locale2)}: ${entry.translations[locale2]}`);
762
+ console.log();
763
+ }
764
+ }
765
+ if (all && shared.length > 0) {
766
+ console.log(import_chalk7.default.green(`Shared (${shared.length}):
767
+ `));
768
+ for (const entry of shared) {
769
+ const relativePath = entry.file.replace(basePath + "/", "");
770
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
771
+ console.log(` ${import_chalk7.default.cyan(locale1)}: ${entry.translations[locale1]}`);
772
+ console.log(` ${import_chalk7.default.cyan(locale2)}: ${entry.translations[locale2]}`);
773
+ console.log();
774
+ }
775
+ }
776
+ console.log(import_chalk7.default.bold("Summary:"));
777
+ console.log(import_chalk7.default.green(` Shared: ${shared.length}`));
778
+ console.log(onlyIn1.length > 0 ? import_chalk7.default.red(` Only in ${locale1}: ${onlyIn1.length}`) : import_chalk7.default.gray(` Only in ${locale1}: 0`));
779
+ console.log(onlyIn2.length > 0 ? import_chalk7.default.red(` Only in ${locale2}: ${onlyIn2.length}`) : import_chalk7.default.gray(` Only in ${locale2}: 0`));
780
+ console.log();
781
+ }
782
+
783
+ // src/commands/stats.ts
784
+ var import_chalk8 = __toESM(require("chalk"));
785
+ async function stats(options = {}) {
786
+ const { cwd } = options;
787
+ const basePath = cwd || process.cwd();
788
+ console.log(import_chalk8.default.blue("\nGathering translation statistics...\n"));
789
+ const entries = await parseProject({ cwd });
790
+ const dictEntries = await extractProjectDictionaryKeys({ cwd });
791
+ const tCalls = await extractProjectTCalls({ cwd });
792
+ const totalDictKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0);
793
+ console.log(import_chalk8.default.bold("Overview:\n"));
794
+ console.log(` Inline translations (it): ${import_chalk8.default.cyan(String(entries.length))}`);
795
+ console.log(` Dictionary keys: ${import_chalk8.default.cyan(String(totalDictKeys))}`);
796
+ console.log(` t() call sites: ${import_chalk8.default.cyan(String(tCalls.length))}`);
797
+ console.log();
798
+ const localeCounts = {};
799
+ for (const entry of entries) {
800
+ for (const locale of Object.keys(entry.translations)) {
801
+ localeCounts[locale] = (localeCounts[locale] || 0) + 1;
802
+ }
803
+ }
804
+ if (Object.keys(localeCounts).length > 0) {
805
+ console.log(import_chalk8.default.bold("Locale Breakdown (inline):\n"));
806
+ const sortedLocales = Object.entries(localeCounts).sort((a, b) => b[1] - a[1]);
807
+ for (const [locale, count] of sortedLocales) {
808
+ console.log(` ${import_chalk8.default.cyan(locale.padEnd(10))} ${count} translations`);
809
+ }
810
+ console.log();
811
+ }
812
+ const namespaces = new Set(dictEntries.map((e) => e.namespace));
813
+ if (namespaces.size > 0) {
814
+ console.log(import_chalk8.default.bold("Namespaces:\n"));
815
+ for (const entry of dictEntries) {
816
+ console.log(` ${import_chalk8.default.yellow(entry.namespace.padEnd(15))} ${entry.keys.length} keys`);
817
+ }
818
+ console.log();
819
+ }
820
+ const fileCounts = {};
821
+ for (const entry of entries) {
822
+ const relativePath = entry.file.replace(basePath + "/", "");
823
+ fileCounts[relativePath] = (fileCounts[relativePath] || 0) + 1;
824
+ }
825
+ if (Object.keys(fileCounts).length > 0) {
826
+ console.log(import_chalk8.default.bold("Top Files:\n"));
827
+ const sortedFiles = Object.entries(fileCounts).sort((a, b) => b[1] - a[1]).slice(0, 10);
828
+ for (const [file, count] of sortedFiles) {
829
+ console.log(` ${import_chalk8.default.gray(file.padEnd(50))} ${import_chalk8.default.cyan(String(count))}`);
830
+ }
831
+ console.log();
832
+ }
833
+ const icuUsage = {};
834
+ for (const entry of entries) {
835
+ if (!entry.icuTypes) continue;
836
+ for (const types of Object.values(entry.icuTypes)) {
837
+ for (const info of types) {
838
+ icuUsage[info.type] = (icuUsage[info.type] || 0) + 1;
839
+ }
840
+ }
841
+ }
842
+ if (Object.keys(icuUsage).length > 0) {
843
+ console.log(import_chalk8.default.bold("ICU Pattern Usage:\n"));
844
+ const sortedICU = Object.entries(icuUsage).sort((a, b) => b[1] - a[1]);
845
+ for (const [type, count] of sortedICU) {
846
+ console.log(` ${import_chalk8.default.yellow(type.padEnd(20))} ${count} usage(s)`);
847
+ }
848
+ console.log();
849
+ }
850
+ }
851
+
852
+ // src/watch.ts
853
+ var import_chokidar = require("chokidar");
854
+ var import_chalk9 = __toESM(require("chalk"));
855
+ function startWatch(options) {
856
+ const { cwd, patterns, ignore, onChange, label } = options;
857
+ console.log(import_chalk9.default.blue(`
858
+ Watching for changes (${label})...
859
+ `));
860
+ console.log(import_chalk9.default.gray("Press Ctrl+C to stop\n"));
861
+ const watcher = (0, import_chokidar.watch)(patterns, {
862
+ cwd,
863
+ ignored: ignore,
864
+ ignoreInitial: true
865
+ });
866
+ let debounceTimer = null;
867
+ const handleChange = (filePath) => {
868
+ if (debounceTimer) clearTimeout(debounceTimer);
869
+ debounceTimer = setTimeout(async () => {
870
+ console.log(import_chalk9.default.gray(`
871
+ Change detected: ${filePath}`));
872
+ console.log(import_chalk9.default.gray("-".repeat(40)));
873
+ try {
874
+ await onChange();
875
+ } catch {
876
+ }
877
+ console.log(import_chalk9.default.gray(`
878
+ Watching for changes (${label})...`));
879
+ }, 300);
880
+ };
881
+ watcher.on("change", handleChange);
882
+ watcher.on("add", handleChange);
883
+ }
884
+
660
885
  // src/bin.ts
661
886
  var program = new import_commander.Command();
662
- program.name("inline-i18n").description("CLI tools for inline-i18n-multi").version("0.8.0");
887
+ program.name("inline-i18n").description("CLI tools for inline-i18n-multi").version("0.10.0");
663
888
  program.command("find <query>").description("Find translations containing the query text").option("-c, --cwd <path>", "Working directory").action(async (query, options) => {
664
889
  await find({ query, cwd: options.cwd });
665
890
  });
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);
891
+ 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) => {
892
+ await validate(options.watch ? { ...options, noExit: true } : options);
893
+ if (options.watch) {
894
+ const cwd = options.cwd || process.cwd();
895
+ startWatch({
896
+ cwd,
897
+ patterns: ["**/*.{ts,tsx,js,jsx}"],
898
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**"],
899
+ onChange: () => validate({ ...options, noExit: true }),
900
+ label: "validate"
901
+ });
902
+ }
668
903
  });
669
904
  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
905
  await coverage(options);
671
906
  });
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) => {
907
+ 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
908
  await typegen(options);
909
+ if (options.watch) {
910
+ const cwd = options.cwd || process.cwd();
911
+ startWatch({
912
+ cwd,
913
+ patterns: ["**/*.{ts,tsx,js,jsx}"],
914
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**"],
915
+ onChange: () => typegen(options),
916
+ label: "typegen"
917
+ });
918
+ }
919
+ });
920
+ 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) => {
921
+ await extract(options);
922
+ });
923
+ program.command("diff <locale1> <locale2>").description("Compare translations between two locales").option("-c, --cwd <path>", "Working directory").option("-a, --all", "Show all entries including shared translations").action(async (locale1, locale2, options) => {
924
+ await diff({ locale1, locale2, cwd: options.cwd, all: options.all });
925
+ });
926
+ program.command("stats").description("Show translation statistics overview").option("-c, --cwd <path>", "Working directory").action(async (options) => {
927
+ await stats(options);
674
928
  });
675
929
  program.parse();
676
930
  //# 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/commands/diff.ts","../src/commands/stats.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 { diff } from './commands/diff'\nimport { stats } from './commands/stats'\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.10.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\n .command('diff <locale1> <locale2>')\n .description('Compare translations between two locales')\n .option('-c, --cwd <path>', 'Working directory')\n .option('-a, --all', 'Show all entries including shared translations')\n .action(async (locale1: string, locale2: string, options: { cwd?: string; all?: boolean }) => {\n await diff({ locale1, locale2, cwd: options.cwd, all: options.all })\n })\n\nprogram\n .command('stats')\n .description('Show translation statistics overview')\n .option('-c, --cwd <path>', 'Working directory')\n .action(async (options: { cwd?: string }) => {\n await stats(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 chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface DiffOptions {\n locale1: string\n locale2: string\n cwd?: string\n all?: boolean\n}\n\nexport async function diff(options: DiffOptions): Promise<void> {\n const { locale1, locale2, cwd, all } = options\n const basePath = cwd || process.cwd()\n\n console.log(chalk.blue(`\\nComparing ${locale1} vs ${locale2}...\\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 onlyIn1: TranslationEntry[] = []\n const onlyIn2: TranslationEntry[] = []\n const shared: TranslationEntry[] = []\n\n for (const entry of entries) {\n const has1 = !!entry.translations[locale1]\n const has2 = !!entry.translations[locale2]\n\n if (has1 && has2) shared.push(entry)\n else if (has1 && !has2) onlyIn1.push(entry)\n else if (!has1 && has2) onlyIn2.push(entry)\n }\n\n if (onlyIn1.length > 0) {\n console.log(chalk.red(`Only in ${locale1} (${onlyIn1.length}):\\n`))\n for (const entry of onlyIn1) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale1)}: ${entry.translations[locale1]}`)\n console.log()\n }\n }\n\n if (onlyIn2.length > 0) {\n console.log(chalk.red(`Only in ${locale2} (${onlyIn2.length}):\\n`))\n for (const entry of onlyIn2) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale2)}: ${entry.translations[locale2]}`)\n console.log()\n }\n }\n\n if (all && shared.length > 0) {\n console.log(chalk.green(`Shared (${shared.length}):\\n`))\n for (const entry of shared) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale1)}: ${entry.translations[locale1]}`)\n console.log(` ${chalk.cyan(locale2)}: ${entry.translations[locale2]}`)\n console.log()\n }\n }\n\n console.log(chalk.bold('Summary:'))\n console.log(chalk.green(` Shared: ${shared.length}`))\n console.log(onlyIn1.length > 0\n ? chalk.red(` Only in ${locale1}: ${onlyIn1.length}`)\n : chalk.gray(` Only in ${locale1}: 0`))\n console.log(onlyIn2.length > 0\n ? chalk.red(` Only in ${locale2}: ${onlyIn2.length}`)\n : chalk.gray(` Only in ${locale2}: 0`))\n console.log()\n}\n","import chalk from 'chalk'\nimport { parseProject, extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface StatsOptions {\n cwd?: string\n}\n\nexport async function stats(options: StatsOptions = {}): Promise<void> {\n const { cwd } = options\n const basePath = cwd || process.cwd()\n\n console.log(chalk.blue('\\nGathering translation statistics...\\n'))\n\n const entries = await parseProject({ cwd })\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n const totalDictKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n\n // Overview\n console.log(chalk.bold('Overview:\\n'))\n console.log(` Inline translations (it): ${chalk.cyan(String(entries.length))}`)\n console.log(` Dictionary keys: ${chalk.cyan(String(totalDictKeys))}`)\n console.log(` t() call sites: ${chalk.cyan(String(tCalls.length))}`)\n console.log()\n\n // Locale breakdown\n const localeCounts: Record<string, number> = {}\n for (const entry of entries) {\n for (const locale of Object.keys(entry.translations)) {\n localeCounts[locale] = (localeCounts[locale] || 0) + 1\n }\n }\n\n if (Object.keys(localeCounts).length > 0) {\n console.log(chalk.bold('Locale Breakdown (inline):\\n'))\n const sortedLocales = Object.entries(localeCounts).sort((a, b) => b[1] - a[1])\n for (const [locale, count] of sortedLocales) {\n console.log(` ${chalk.cyan(locale.padEnd(10))} ${count} translations`)\n }\n console.log()\n }\n\n // Namespace summary\n const namespaces = new Set(dictEntries.map(e => e.namespace))\n if (namespaces.size > 0) {\n console.log(chalk.bold('Namespaces:\\n'))\n for (const entry of dictEntries) {\n console.log(` ${chalk.yellow(entry.namespace.padEnd(15))} ${entry.keys.length} keys`)\n }\n console.log()\n }\n\n // Top files\n const fileCounts: Record<string, number> = {}\n for (const entry of entries) {\n const relativePath = entry.file.replace(basePath + '/', '')\n fileCounts[relativePath] = (fileCounts[relativePath] || 0) + 1\n }\n\n if (Object.keys(fileCounts).length > 0) {\n console.log(chalk.bold('Top Files:\\n'))\n const sortedFiles = Object.entries(fileCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n for (const [file, count] of sortedFiles) {\n console.log(` ${chalk.gray(file.padEnd(50))} ${chalk.cyan(String(count))}`)\n }\n console.log()\n }\n\n // ICU pattern usage\n const icuUsage: Record<string, number> = {}\n for (const entry of entries) {\n if (!entry.icuTypes) continue\n for (const types of Object.values(entry.icuTypes)) {\n for (const info of types) {\n icuUsage[info.type] = (icuUsage[info.type] || 0) + 1\n }\n }\n }\n\n if (Object.keys(icuUsage).length > 0) {\n console.log(chalk.bold('ICU Pattern Usage:\\n'))\n const sortedICU = Object.entries(icuUsage).sort((a, b) => b[1] - a[1])\n for (const [type, count] of sortedICU) {\n console.log(` ${chalk.yellow(type.padEnd(20))} ${count} usage(s)`)\n }\n console.log()\n }\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","import_chalk","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,24 @@ 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
+ interface DiffOptions {
83
+ locale1: string;
84
+ locale2: string;
85
+ cwd?: string;
86
+ all?: boolean;
87
+ }
88
+ declare function diff(options: DiffOptions): Promise<void>;
89
+
90
+ interface StatsOptions {
91
+ cwd?: string;
92
+ }
93
+ declare function stats(options?: StatsOptions): Promise<void>;
94
+
95
+ export { type DictionaryKeyEntry, type TCallEntry, type TranslationEntry, coverage, diff, extract, extractProjectDictionaryKeys, extractProjectTCalls, find, parseDictionaryKeys, parseProject, parseTCalls, stats, typegen, unused, validate };
package/dist/index.js CHANGED
@@ -31,12 +31,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  coverage: () => coverage,
34
+ diff: () => diff,
35
+ extract: () => extract,
34
36
  extractProjectDictionaryKeys: () => extractProjectDictionaryKeys,
35
37
  extractProjectTCalls: () => extractProjectTCalls,
36
38
  find: () => find,
37
39
  parseDictionaryKeys: () => parseDictionaryKeys,
38
40
  parseProject: () => parseProject,
39
41
  parseTCalls: () => parseTCalls,
42
+ stats: () => stats,
40
43
  typegen: () => typegen,
41
44
  unused: () => unused,
42
45
  validate: () => validate
@@ -541,7 +544,7 @@ async function validate(options = {}) {
541
544
  }
542
545
  console.log();
543
546
  }
544
- if (issues.length > 0 || unusedCount > 0) {
547
+ if ((issues.length > 0 || unusedCount > 0) && !options.noExit) {
545
548
  process.exit(1);
546
549
  }
547
550
  }
@@ -671,15 +674,210 @@ ${keyUnion}
671
674
  console.log(import_chalk5.default.gray(` ... and ${sortedKeys.length - 5} more`));
672
675
  }
673
676
  }
677
+
678
+ // src/commands/extract.ts
679
+ var import_chalk6 = __toESM(require("chalk"));
680
+ var fs3 = __toESM(require("fs"));
681
+ var path2 = __toESM(require("path"));
682
+ async function extract(options = {}) {
683
+ const { cwd, output = "translations", format = "flat" } = options;
684
+ console.log(import_chalk6.default.blue("\nExtracting inline translations...\n"));
685
+ const entries = await parseProject({ cwd });
686
+ if (entries.length === 0) {
687
+ console.log(import_chalk6.default.yellow("No translations found."));
688
+ return;
689
+ }
690
+ const byLocale = {};
691
+ const basePath = cwd || process.cwd();
692
+ for (const entry of entries) {
693
+ for (const [locale, text] of Object.entries(entry.translations)) {
694
+ if (!byLocale[locale]) byLocale[locale] = {};
695
+ const relativePath = entry.file.replace(basePath + "/", "");
696
+ const key = `${relativePath}:${entry.line}`;
697
+ byLocale[locale][key] = text;
698
+ }
699
+ }
700
+ const outputDir = path2.resolve(basePath, output);
701
+ if (!fs3.existsSync(outputDir)) {
702
+ fs3.mkdirSync(outputDir, { recursive: true });
703
+ }
704
+ const locales = Object.keys(byLocale).sort();
705
+ for (const locale of locales) {
706
+ const translations = byLocale[locale];
707
+ let content;
708
+ if (format === "nested") {
709
+ const nested = buildNestedObject(translations);
710
+ content = JSON.stringify(nested, null, 2) + "\n";
711
+ } else {
712
+ content = JSON.stringify(translations, null, 2) + "\n";
713
+ }
714
+ const filePath = path2.join(outputDir, `${locale}.json`);
715
+ fs3.writeFileSync(filePath, content);
716
+ console.log(
717
+ import_chalk6.default.green(` ${locale}.json`) + import_chalk6.default.gray(` (${Object.keys(translations).length} keys)`)
718
+ );
719
+ }
720
+ console.log(import_chalk6.default.gray(`
721
+ Extracted ${entries.length} translation(s) to ${output}/`));
722
+ }
723
+ function buildNestedObject(flat) {
724
+ const result = {};
725
+ for (const [key, value] of Object.entries(flat)) {
726
+ const parts = key.split(".");
727
+ let current = result;
728
+ for (let i = 0; i < parts.length - 1; i++) {
729
+ const part = parts[i];
730
+ if (!current[part] || typeof current[part] !== "object") {
731
+ current[part] = {};
732
+ }
733
+ current = current[part];
734
+ }
735
+ current[parts[parts.length - 1]] = value;
736
+ }
737
+ return result;
738
+ }
739
+
740
+ // src/commands/diff.ts
741
+ var import_chalk7 = __toESM(require("chalk"));
742
+ async function diff(options) {
743
+ const { locale1, locale2, cwd, all } = options;
744
+ const basePath = cwd || process.cwd();
745
+ console.log(import_chalk7.default.blue(`
746
+ Comparing ${locale1} vs ${locale2}...
747
+ `));
748
+ const entries = await parseProject({ cwd });
749
+ if (entries.length === 0) {
750
+ console.log(import_chalk7.default.yellow("No translations found."));
751
+ return;
752
+ }
753
+ const onlyIn1 = [];
754
+ const onlyIn2 = [];
755
+ const shared = [];
756
+ for (const entry of entries) {
757
+ const has1 = !!entry.translations[locale1];
758
+ const has2 = !!entry.translations[locale2];
759
+ if (has1 && has2) shared.push(entry);
760
+ else if (has1 && !has2) onlyIn1.push(entry);
761
+ else if (!has1 && has2) onlyIn2.push(entry);
762
+ }
763
+ if (onlyIn1.length > 0) {
764
+ console.log(import_chalk7.default.red(`Only in ${locale1} (${onlyIn1.length}):
765
+ `));
766
+ for (const entry of onlyIn1) {
767
+ const relativePath = entry.file.replace(basePath + "/", "");
768
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
769
+ console.log(` ${import_chalk7.default.cyan(locale1)}: ${entry.translations[locale1]}`);
770
+ console.log();
771
+ }
772
+ }
773
+ if (onlyIn2.length > 0) {
774
+ console.log(import_chalk7.default.red(`Only in ${locale2} (${onlyIn2.length}):
775
+ `));
776
+ for (const entry of onlyIn2) {
777
+ const relativePath = entry.file.replace(basePath + "/", "");
778
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
779
+ console.log(` ${import_chalk7.default.cyan(locale2)}: ${entry.translations[locale2]}`);
780
+ console.log();
781
+ }
782
+ }
783
+ if (all && shared.length > 0) {
784
+ console.log(import_chalk7.default.green(`Shared (${shared.length}):
785
+ `));
786
+ for (const entry of shared) {
787
+ const relativePath = entry.file.replace(basePath + "/", "");
788
+ console.log(import_chalk7.default.gray(` ${relativePath}:${entry.line}`));
789
+ console.log(` ${import_chalk7.default.cyan(locale1)}: ${entry.translations[locale1]}`);
790
+ console.log(` ${import_chalk7.default.cyan(locale2)}: ${entry.translations[locale2]}`);
791
+ console.log();
792
+ }
793
+ }
794
+ console.log(import_chalk7.default.bold("Summary:"));
795
+ console.log(import_chalk7.default.green(` Shared: ${shared.length}`));
796
+ console.log(onlyIn1.length > 0 ? import_chalk7.default.red(` Only in ${locale1}: ${onlyIn1.length}`) : import_chalk7.default.gray(` Only in ${locale1}: 0`));
797
+ console.log(onlyIn2.length > 0 ? import_chalk7.default.red(` Only in ${locale2}: ${onlyIn2.length}`) : import_chalk7.default.gray(` Only in ${locale2}: 0`));
798
+ console.log();
799
+ }
800
+
801
+ // src/commands/stats.ts
802
+ var import_chalk8 = __toESM(require("chalk"));
803
+ async function stats(options = {}) {
804
+ const { cwd } = options;
805
+ const basePath = cwd || process.cwd();
806
+ console.log(import_chalk8.default.blue("\nGathering translation statistics...\n"));
807
+ const entries = await parseProject({ cwd });
808
+ const dictEntries = await extractProjectDictionaryKeys({ cwd });
809
+ const tCalls = await extractProjectTCalls({ cwd });
810
+ const totalDictKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0);
811
+ console.log(import_chalk8.default.bold("Overview:\n"));
812
+ console.log(` Inline translations (it): ${import_chalk8.default.cyan(String(entries.length))}`);
813
+ console.log(` Dictionary keys: ${import_chalk8.default.cyan(String(totalDictKeys))}`);
814
+ console.log(` t() call sites: ${import_chalk8.default.cyan(String(tCalls.length))}`);
815
+ console.log();
816
+ const localeCounts = {};
817
+ for (const entry of entries) {
818
+ for (const locale of Object.keys(entry.translations)) {
819
+ localeCounts[locale] = (localeCounts[locale] || 0) + 1;
820
+ }
821
+ }
822
+ if (Object.keys(localeCounts).length > 0) {
823
+ console.log(import_chalk8.default.bold("Locale Breakdown (inline):\n"));
824
+ const sortedLocales = Object.entries(localeCounts).sort((a, b) => b[1] - a[1]);
825
+ for (const [locale, count] of sortedLocales) {
826
+ console.log(` ${import_chalk8.default.cyan(locale.padEnd(10))} ${count} translations`);
827
+ }
828
+ console.log();
829
+ }
830
+ const namespaces = new Set(dictEntries.map((e) => e.namespace));
831
+ if (namespaces.size > 0) {
832
+ console.log(import_chalk8.default.bold("Namespaces:\n"));
833
+ for (const entry of dictEntries) {
834
+ console.log(` ${import_chalk8.default.yellow(entry.namespace.padEnd(15))} ${entry.keys.length} keys`);
835
+ }
836
+ console.log();
837
+ }
838
+ const fileCounts = {};
839
+ for (const entry of entries) {
840
+ const relativePath = entry.file.replace(basePath + "/", "");
841
+ fileCounts[relativePath] = (fileCounts[relativePath] || 0) + 1;
842
+ }
843
+ if (Object.keys(fileCounts).length > 0) {
844
+ console.log(import_chalk8.default.bold("Top Files:\n"));
845
+ const sortedFiles = Object.entries(fileCounts).sort((a, b) => b[1] - a[1]).slice(0, 10);
846
+ for (const [file, count] of sortedFiles) {
847
+ console.log(` ${import_chalk8.default.gray(file.padEnd(50))} ${import_chalk8.default.cyan(String(count))}`);
848
+ }
849
+ console.log();
850
+ }
851
+ const icuUsage = {};
852
+ for (const entry of entries) {
853
+ if (!entry.icuTypes) continue;
854
+ for (const types of Object.values(entry.icuTypes)) {
855
+ for (const info of types) {
856
+ icuUsage[info.type] = (icuUsage[info.type] || 0) + 1;
857
+ }
858
+ }
859
+ }
860
+ if (Object.keys(icuUsage).length > 0) {
861
+ console.log(import_chalk8.default.bold("ICU Pattern Usage:\n"));
862
+ const sortedICU = Object.entries(icuUsage).sort((a, b) => b[1] - a[1]);
863
+ for (const [type, count] of sortedICU) {
864
+ console.log(` ${import_chalk8.default.yellow(type.padEnd(20))} ${count} usage(s)`);
865
+ }
866
+ console.log();
867
+ }
868
+ }
674
869
  // Annotate the CommonJS export names for ESM import in node:
675
870
  0 && (module.exports = {
676
871
  coverage,
872
+ diff,
873
+ extract,
677
874
  extractProjectDictionaryKeys,
678
875
  extractProjectTCalls,
679
876
  find,
680
877
  parseDictionaryKeys,
681
878
  parseProject,
682
879
  parseTCalls,
880
+ stats,
683
881
  typegen,
684
882
  unused,
685
883
  validate
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":"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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/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","../src/commands/diff.ts","../src/commands/stats.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'\nexport { diff } from './commands/diff'\nexport { stats } from './commands/stats'\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","import chalk from 'chalk'\nimport { parseProject, type TranslationEntry } from '../parser'\n\ninterface DiffOptions {\n locale1: string\n locale2: string\n cwd?: string\n all?: boolean\n}\n\nexport async function diff(options: DiffOptions): Promise<void> {\n const { locale1, locale2, cwd, all } = options\n const basePath = cwd || process.cwd()\n\n console.log(chalk.blue(`\\nComparing ${locale1} vs ${locale2}...\\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 onlyIn1: TranslationEntry[] = []\n const onlyIn2: TranslationEntry[] = []\n const shared: TranslationEntry[] = []\n\n for (const entry of entries) {\n const has1 = !!entry.translations[locale1]\n const has2 = !!entry.translations[locale2]\n\n if (has1 && has2) shared.push(entry)\n else if (has1 && !has2) onlyIn1.push(entry)\n else if (!has1 && has2) onlyIn2.push(entry)\n }\n\n if (onlyIn1.length > 0) {\n console.log(chalk.red(`Only in ${locale1} (${onlyIn1.length}):\\n`))\n for (const entry of onlyIn1) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale1)}: ${entry.translations[locale1]}`)\n console.log()\n }\n }\n\n if (onlyIn2.length > 0) {\n console.log(chalk.red(`Only in ${locale2} (${onlyIn2.length}):\\n`))\n for (const entry of onlyIn2) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale2)}: ${entry.translations[locale2]}`)\n console.log()\n }\n }\n\n if (all && shared.length > 0) {\n console.log(chalk.green(`Shared (${shared.length}):\\n`))\n for (const entry of shared) {\n const relativePath = entry.file.replace(basePath + '/', '')\n console.log(chalk.gray(` ${relativePath}:${entry.line}`))\n console.log(` ${chalk.cyan(locale1)}: ${entry.translations[locale1]}`)\n console.log(` ${chalk.cyan(locale2)}: ${entry.translations[locale2]}`)\n console.log()\n }\n }\n\n console.log(chalk.bold('Summary:'))\n console.log(chalk.green(` Shared: ${shared.length}`))\n console.log(onlyIn1.length > 0\n ? chalk.red(` Only in ${locale1}: ${onlyIn1.length}`)\n : chalk.gray(` Only in ${locale1}: 0`))\n console.log(onlyIn2.length > 0\n ? chalk.red(` Only in ${locale2}: ${onlyIn2.length}`)\n : chalk.gray(` Only in ${locale2}: 0`))\n console.log()\n}\n","import chalk from 'chalk'\nimport { parseProject, extractProjectDictionaryKeys, extractProjectTCalls } from '../parser'\n\ninterface StatsOptions {\n cwd?: string\n}\n\nexport async function stats(options: StatsOptions = {}): Promise<void> {\n const { cwd } = options\n const basePath = cwd || process.cwd()\n\n console.log(chalk.blue('\\nGathering translation statistics...\\n'))\n\n const entries = await parseProject({ cwd })\n const dictEntries = await extractProjectDictionaryKeys({ cwd })\n const tCalls = await extractProjectTCalls({ cwd })\n\n const totalDictKeys = dictEntries.reduce((sum, e) => sum + e.keys.length, 0)\n\n // Overview\n console.log(chalk.bold('Overview:\\n'))\n console.log(` Inline translations (it): ${chalk.cyan(String(entries.length))}`)\n console.log(` Dictionary keys: ${chalk.cyan(String(totalDictKeys))}`)\n console.log(` t() call sites: ${chalk.cyan(String(tCalls.length))}`)\n console.log()\n\n // Locale breakdown\n const localeCounts: Record<string, number> = {}\n for (const entry of entries) {\n for (const locale of Object.keys(entry.translations)) {\n localeCounts[locale] = (localeCounts[locale] || 0) + 1\n }\n }\n\n if (Object.keys(localeCounts).length > 0) {\n console.log(chalk.bold('Locale Breakdown (inline):\\n'))\n const sortedLocales = Object.entries(localeCounts).sort((a, b) => b[1] - a[1])\n for (const [locale, count] of sortedLocales) {\n console.log(` ${chalk.cyan(locale.padEnd(10))} ${count} translations`)\n }\n console.log()\n }\n\n // Namespace summary\n const namespaces = new Set(dictEntries.map(e => e.namespace))\n if (namespaces.size > 0) {\n console.log(chalk.bold('Namespaces:\\n'))\n for (const entry of dictEntries) {\n console.log(` ${chalk.yellow(entry.namespace.padEnd(15))} ${entry.keys.length} keys`)\n }\n console.log()\n }\n\n // Top files\n const fileCounts: Record<string, number> = {}\n for (const entry of entries) {\n const relativePath = entry.file.replace(basePath + '/', '')\n fileCounts[relativePath] = (fileCounts[relativePath] || 0) + 1\n }\n\n if (Object.keys(fileCounts).length > 0) {\n console.log(chalk.bold('Top Files:\\n'))\n const sortedFiles = Object.entries(fileCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n for (const [file, count] of sortedFiles) {\n console.log(` ${chalk.gray(file.padEnd(50))} ${chalk.cyan(String(count))}`)\n }\n console.log()\n }\n\n // ICU pattern usage\n const icuUsage: Record<string, number> = {}\n for (const entry of entries) {\n if (!entry.icuTypes) continue\n for (const types of Object.values(entry.icuTypes)) {\n for (const info of types) {\n icuUsage[info.type] = (icuUsage[info.type] || 0) + 1\n }\n }\n }\n\n if (Object.keys(icuUsage).length > 0) {\n console.log(chalk.bold('ICU Pattern Usage:\\n'))\n const sortedICU = Object.entries(icuUsage).sort((a, b) => b[1] - a[1])\n for (const [type, count] of sortedICU) {\n console.log(` ${chalk.yellow(type.padEnd(20))} ${count} usage(s)`)\n }\n console.log()\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","import_chalk","fs","path","chalk","import_chalk","chalk","import_chalk","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.10.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
  },