@better-i18n/cli 0.1.2 → 0.1.4

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
@@ -101,13 +101,101 @@ better-i18n scan --staged # Only scan git staged files
101
101
  better-i18n scan --verbose # Show detailed output
102
102
  ```
103
103
 
104
+ ### `better-i18n extract-keys`
105
+
106
+ Extract all translation keys used in your codebase (t() function calls).
107
+
108
+ ```bash
109
+ # Extract all translation keys
110
+ better-i18n extract-keys
111
+
112
+ # Compare with remote keys from CDN
113
+ better-i18n extract-keys --compare
114
+
115
+ # Compare with specific locale
116
+ better-i18n extract-keys --compare --locale tr
117
+
118
+ # JSON output (default)
119
+ better-i18n extract-keys --format json
120
+
121
+ # Show detailed output
122
+ better-i18n extract-keys --verbose
123
+ ```
124
+
125
+ **Output format (JSON):**
126
+
127
+ ```json
128
+ {
129
+ "localKeys": {
130
+ "project": "better-i18n/landing",
131
+ "namespaces": {
132
+ "auth": ["auth.login", "auth.register", "auth.forgot"],
133
+ "nav": ["nav.home", "nav.about"],
134
+ "hero": ["hero.title", "hero.description"]
135
+ },
136
+ "totalCount": 6,
137
+ "filesScanned": 42
138
+ }
139
+ }
140
+ ```
141
+
142
+ **With `--compare`:**
143
+
144
+ ```json
145
+ {
146
+ "comparison": {
147
+ "localKeys": { ... },
148
+ "remoteKeys": {
149
+ "namespaces": { ... },
150
+ "totalCount": 150
151
+ },
152
+ "missingKeys": {
153
+ "hero": ["hero.cta", "hero.benefits"]
154
+ },
155
+ "unusedKeys": {
156
+ "old": ["old.section"]
157
+ },
158
+ "coverage": {
159
+ "local": 85,
160
+ "remote": 96
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ **Human-readable output with `--compare`:**
167
+
168
+ ```
169
+ ✓ Project: better-i18n/landing
170
+ ✓ Found 57 files
171
+ ✓ Fetched 12 namespaces from CDN
172
+
173
+ 📊 Translation Keys Comparison
174
+
175
+ Coverage:
176
+ Local → Remote: 85%
177
+ Remote Used: 96%
178
+
179
+ ❌ Missing in Remote (2 keys):
180
+ hero: 2 keys
181
+ • hero.cta
182
+ • hero.benefits
183
+
184
+ ⚠️ Unused in Code (1 key):
185
+ old: 1 key
186
+ • old.section
187
+
188
+ Scanned 57 files in 0.12s
189
+ ✓ Comparison complete
190
+ ```
191
+
104
192
  ## Detection Rules
105
193
 
106
- | Rule | Severity | What it catches | Example |
107
- |------|----------|-----------------|---------|
108
- | `jsx-text` | missing | Hardcoded text in JSX | `<h1>Hello</h1>` |
109
- | `jsx-attribute` | missing | Hardcoded attributes | `<img alt="Logo" />` |
110
- | `ternary-locale` | error | Locale-based ternaries | `locale === 'en' ? 'Hi' : 'Hola'` |
194
+ | Rule | Severity | What it catches | Example |
195
+ | ---------------- | -------- | ---------------------- | --------------------------------- |
196
+ | `jsx-text` | missing | Hardcoded text in JSX | `<h1>Hello</h1>` |
197
+ | `jsx-attribute` | missing | Hardcoded attributes | `<img alt="Logo" />` |
198
+ | `ternary-locale` | error | Locale-based ternaries | `locale === 'en' ? 'Hi' : 'Hola'` |
111
199
 
112
200
  ### Automatically Ignored
113
201
 
@@ -133,19 +221,19 @@ export const i18nWorkspaceConfig = {
133
221
  lint: {
134
222
  // Files to scan (defaults: ["src", "app", "components", "pages"])
135
223
  include: ["src/**/*.tsx", "app/**/*.tsx"],
136
-
224
+
137
225
  // Files to ignore (automatically merges with defaults)
138
226
  exclude: [
139
- "**/skeletons.tsx", // Mock/demo components
140
- "**/*.stories.tsx", // Storybook files
141
- "**/*.test.tsx", // Test files
142
- "**/components/ui/**", // UI library components
227
+ "**/skeletons.tsx", // Mock/demo components
228
+ "**/*.stories.tsx", // Storybook files
229
+ "**/*.test.tsx", // Test files
230
+ "**/components/ui/**", // UI library components
143
231
  ],
144
-
232
+
145
233
  // Rule configuration (optional)
146
234
  rules: {
147
235
  "jsx-text": "warning",
148
- "jsx-attribute": "warning",
236
+ "jsx-attribute": "warning",
149
237
  "ternary-locale": "error",
150
238
  },
151
239
  },
@@ -154,11 +242,11 @@ export const i18nWorkspaceConfig = {
154
242
 
155
243
  ### Config Options
156
244
 
157
- | Option | Type | Description |
158
- |--------|------|-------------|
245
+ | Option | Type | Description |
246
+ | --------- | ---------- | ---------------------------------------------------------------------------------- |
159
247
  | `include` | `string[]` | Glob patterns for files to scan (default: `["src", "app", "components", "pages"]`) |
160
- | `exclude` | `string[]` | Glob patterns to ignore (merges with defaults: `node_modules`, `.next`, etc.) |
161
- | `rules` | `object` | Set severity: `"error"` \| `"warning"` \| `"off"` |
248
+ | `exclude` | `string[]` | Glob patterns to ignore (merges with defaults: `node_modules`, `.next`, etc.) |
249
+ | `rules` | `object` | Set severity: `"error"` \| `"warning"` \| `"off"` |
162
250
 
163
251
  ## Usage Scenarios
164
252
 
@@ -176,6 +264,7 @@ Add to your `package.json`:
176
264
  ```
177
265
 
178
266
  Run before commits:
267
+
179
268
  ```bash
180
269
  npm run lint:i18n
181
270
  ```
@@ -214,7 +303,7 @@ jobs:
214
303
  - uses: actions/checkout@v4
215
304
  - uses: actions/setup-node@v4
216
305
  with:
217
- node-version: '20'
306
+ node-version: "20"
218
307
  - run: npx @better-i18n/cli scan --ci --format json
219
308
  ```
220
309
 
@@ -302,13 +391,13 @@ interface ScanResult {
302
391
  }
303
392
 
304
393
  interface Issue {
305
- file: string; // Relative path
306
- line: number; // Line number
307
- column: number; // Column number
308
- text: string; // Hardcoded text
394
+ file: string; // Relative path
395
+ line: number; // Line number
396
+ column: number; // Column number
397
+ text: string; // Hardcoded text
309
398
  type: "jsx-text" | "jsx-attribute" | "ternary-locale";
310
399
  severity: "error" | "warning";
311
- message: string; // Human-readable message
400
+ message: string; // Human-readable message
312
401
  suggestedKey?: string; // Auto-generated translation key
313
402
  }
314
403
  ```
@@ -346,32 +435,57 @@ npm-run-all --parallel typecheck lint:eslint lint:i18n
346
435
  ### Config not detected
347
436
 
348
437
  Make sure your `i18n.config.ts` exports either:
438
+
349
439
  - `export const project = "org/slug"`
350
440
  - `export const i18nWorkspaceConfig = { project: "org/slug" }`
351
441
 
352
442
  ### Too many false positives
353
443
 
354
444
  Add exclusions to your config:
445
+
355
446
  ```ts
356
- exclude: [
357
- "**/*.stories.tsx",
358
- "**/demo/**",
359
- "**/examples/**",
360
- ]
447
+ exclude: ["**/*.stories.tsx", "**/demo/**", "**/examples/**"];
361
448
  ```
362
449
 
363
450
  ### Clickable links not working
364
451
 
365
452
  Make sure you're using VS Code's integrated terminal. External terminals may not support clickable file paths.
366
453
 
367
- ## Part of Better i18n
454
+ ## Part of Better i18n Ecosystem
455
+
456
+ This CLI is one component of the **Better i18n translation management platform**:
457
+
458
+ ### Platform Components
368
459
 
369
- This CLI is part of the [Better i18n](https://better-i18n.com) ecosystem:
460
+ - **[@better-i18n/cli](https://www.npmjs.com/package/@better-i18n/cli)** - This CLI tool (detect hardcoded strings, extract keys)
461
+ - **[@better-i18n/next](https://www.npmjs.com/package/@better-i18n/next)** - Next.js SDK for runtime translation
462
+ - **[@better-i18n/app](https://dash.better-i18n.com)** - Web dashboard for translation management
463
+ - `@better-i18n/mcp`: Model Context Protocol server for AI assistants.
464
+
465
+ ### Platform Features
466
+
467
+ - **GitHub Integration** - Sync translations with your repositories
468
+ - **Real-time Collaboration** - Team workflows on translations
469
+ - **CDN Delivery** - Serve translations globally from edge locations
470
+ - **Multi-language Editor** - Manage all languages in one interface
471
+ - **REST API** - Programmatic access for CI/CD automation
472
+ - **AI Context Analysis** - Automatically extract terminology from websites
473
+ - **Namespace Organization** - Organize translations by feature/module
474
+
475
+ ### How This CLI Fits In
476
+
477
+ ```
478
+ Developer Workflow:
479
+ ├─ Write code with hardcoded strings
480
+ ├─ Run: better-i18n scan → Detect hardcoded strings ⚠️
481
+ ├─ Run: better-i18n extract-keys → Extract used keys
482
+ ├─ Review in Better i18n Dashboard
483
+ ├─ GitHub Hook: better-i18n scan --staged → Pre-commit check
484
+ ├─ CI/CD: better-i18n scan --ci → Fail build if strings found
485
+ └─ Dashboard: Manage translations, sync with GitHub
486
+ ```
370
487
 
371
- - **[@better-i18n/next](https://www.npmjs.com/package/@better-i18n/next)** - Next.js i18n SDK
372
- - **[@better-i18n/cli](https://www.npmjs.com/package/@better-i18n/cli)** - This CLI tool
373
- - **[Dashboard](https://better-i18n.com)** - Visual translation management
374
- - **[MCP Server](https://github.com/better-i18n/better-i18n)** - AI-powered translation assistant
488
+ The CLI works **in your local development** to catch issues before they ship, while the platform handles the translation management workflow.
375
489
 
376
490
  ## Contributing
377
491
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAEjE;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,KAAK,EAAE,CAAC,CAGlB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,GAClB,KAAK,EAAE,CA2CT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAEjE;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,KAAK,EAAE,CAAC,CAGlB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,GAClB,KAAK,EAAE,CAiDT"}
@@ -5,9 +5,7 @@
5
5
  */
6
6
  import { readFileSync } from "node:fs";
7
7
  import ts from "typescript";
8
- import { checkJsxAttribute } from "./rules/jsx-attribute.js";
9
- import { checkJsxText } from "./rules/jsx-text.js";
10
- import { checkTernaryLocale } from "./rules/ternary-locale.js";
8
+ import { checkJsxAttribute, checkJsxText, checkTernaryLocale, checkTranslationFunction, } from "./rules/index.js";
11
9
  /**
12
10
  * Analyze a single file for hardcoded strings
13
11
  */
@@ -46,6 +44,12 @@ export function analyzeSourceText(sourceText, filePath, config) {
46
44
  if (issue)
47
45
  issues.push(issue);
48
46
  }
47
+ // Translation function calls
48
+ if (ts.isCallExpression(node)) {
49
+ const issue = checkTranslationFunction(node, ctx);
50
+ if (issue)
51
+ issues.push(issue);
52
+ }
49
53
  ts.forEachChild(node, visit);
50
54
  }
51
55
  visit(sourceFile);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAG1B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,MAAmB;IAEnB,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,OAAO,iBAAiB,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,QAAgB,EAChB,MAAmB;IAEnB,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CACpC,QAAQ,EACR,UAAU,EACV,EAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,EACJ,aAAa,CAAC,QAAQ,CAAC,CACxB,CAAC;IAEF,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAElD,6BAA6B;IAC7B,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;IAClC,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,KAAK,CAAC;IACnD,MAAM,cAAc,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,KAAK,CAAC;IACxD,MAAM,cAAc,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK,KAAK,CAAC;IAEzD,SAAS,KAAK,CAAC,IAAa;QAC1B,WAAW;QACX,IAAI,cAAc,IAAI,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACtC,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,gBAAgB;QAChB,IAAI,cAAc,IAAI,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9C,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC3C,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,sBAAsB;QACtB,IAAI,cAAc,IAAI,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC5C,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,6BAA6B;QAC7B,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAClD,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,CAAC;IAElB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;IACxD,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;IACxD,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IACtD,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;AAC1B,CAAC"}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Rules index - exports all detection rules
3
3
  */
4
- export { checkJsxAttribute } from "./jsx-attribute.js";
5
- export { checkJsxText } from "./jsx-text.js";
6
- export { checkTernaryLocale } from "./ternary-locale.js";
4
+ export * from "./jsx-attribute.js";
5
+ export * from "./jsx-text.js";
6
+ export * from "./ternary-locale.js";
7
+ export * from "./translation-function.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC"}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Rules index - exports all detection rules
3
3
  */
4
- export { checkJsxAttribute } from "./jsx-attribute.js";
5
- export { checkJsxText } from "./jsx-text.js";
6
- export { checkTernaryLocale } from "./ternary-locale.js";
4
+ export * from "./jsx-attribute.js";
5
+ export * from "./jsx-text.js";
6
+ export * from "./ternary-locale.js";
7
+ export * from "./translation-function.js";
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzer/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyzer/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Translation function detection rule
3
+ *
4
+ * Detects t() function calls to extract translation keys used in code
5
+ */
6
+ import ts from "typescript";
7
+ import type { Issue, RuleContext } from "../types.js";
8
+ /**
9
+ * Check for translation function calls
10
+ */
11
+ export declare function checkTranslationFunction(node: ts.CallExpression, ctx: RuleContext): Issue | null;
12
+ //# sourceMappingURL=translation-function.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-function.d.ts","sourceRoot":"","sources":["../../../src/analyzer/rules/translation-function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOtD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,EAAE,CAAC,cAAc,EACvB,GAAG,EAAE,WAAW,GACf,KAAK,GAAG,IAAI,CAyCd"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Translation function detection rule
3
+ *
4
+ * Detects t() function calls to extract translation keys used in code
5
+ */
6
+ import ts from "typescript";
7
+ /**
8
+ * Translation function names to detect
9
+ */
10
+ const TRANSLATION_FUNCTIONS = new Set(["t", "useTranslation"]);
11
+ /**
12
+ * Check for translation function calls
13
+ */
14
+ export function checkTranslationFunction(node, ctx) {
15
+ // Check if it's a known translation function
16
+ const funcName = getFunctionName(node);
17
+ if (!funcName || !TRANSLATION_FUNCTIONS.has(funcName)) {
18
+ return null;
19
+ }
20
+ // Get the first argument (usually the translation key)
21
+ const args = node.arguments;
22
+ if (args.length === 0) {
23
+ return null;
24
+ }
25
+ const firstArg = args[0];
26
+ // Handle string literal: t("auth.login")
27
+ if (ts.isStringLiteral(firstArg)) {
28
+ const pos = ctx.sourceFile.getLineAndCharacterOfPosition(firstArg.getStart());
29
+ return {
30
+ file: ctx.filePath,
31
+ line: pos.line + 1,
32
+ column: pos.character + 1,
33
+ text: firstArg.text,
34
+ type: "string-variable",
35
+ severity: "info",
36
+ message: `Translation key: "${firstArg.text}"`,
37
+ key: firstArg.text,
38
+ };
39
+ }
40
+ // Handle template literal: t(`auth.${type}`)
41
+ if (ts.isTemplateExpression(firstArg)) {
42
+ // Skip dynamic keys - can't extract statically
43
+ return null;
44
+ }
45
+ // Handle identifier: t(keyVar) - can't extract statically
46
+ return null;
47
+ }
48
+ /**
49
+ * Extract function name from call expression
50
+ */
51
+ function getFunctionName(node) {
52
+ const expr = node.expression;
53
+ // Simple identifier: t()
54
+ if (ts.isIdentifier(expr)) {
55
+ return expr.text;
56
+ }
57
+ // Property access: obj.t()
58
+ if (ts.isPropertyAccessExpression(expr)) {
59
+ return expr.name.text;
60
+ }
61
+ // Hook destructuring: const { t } = useTranslation(); t()
62
+ // Already handled by Identifier case above
63
+ return null;
64
+ }
65
+ //# sourceMappingURL=translation-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-function.js","sourceRoot":"","sources":["../../../src/analyzer/rules/translation-function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,IAAuB,EACvB,GAAgB;IAEhB,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uDAAuD;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEzB,yCAAyC;IACzC,IAAI,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,6BAA6B,CACtD,QAAQ,CAAC,QAAQ,EAAE,CACpB,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,QAAQ;YAClB,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;YAClB,MAAM,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,qBAAqB,QAAQ,CAAC,IAAI,GAAG;YAC9C,GAAG,EAAE,QAAQ,CAAC,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,IAAI,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,+CAA+C;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,0DAA0D;IAC1D,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,IAAuB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;IAE7B,yBAAyB;IACzB,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,2BAA2B;IAC3B,IAAI,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,0DAA0D;IAC1D,2CAA2C;IAE3C,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -7,9 +7,10 @@ export interface Issue {
7
7
  column: number;
8
8
  text: string;
9
9
  type: "jsx-text" | "jsx-attribute" | "ternary-locale" | "string-variable";
10
- severity: "error" | "warning";
10
+ severity: "error" | "warning" | "info";
11
11
  message: string;
12
12
  suggestedKey?: string;
13
+ key?: string;
13
14
  }
14
15
  export interface RuleContext {
15
16
  filePath: string;
@@ -44,5 +45,40 @@ export interface ScanResult {
44
45
  files: number;
45
46
  issues: Issue[];
46
47
  duration: number;
48
+ localKeys?: any;
49
+ comparison?: {
50
+ localKeys: any;
51
+ remoteKeys: any;
52
+ missingKeys: Record<string, string[]>;
53
+ unusedKeys: Record<string, string[]>;
54
+ coverage: {
55
+ local: number;
56
+ remote: number;
57
+ };
58
+ };
59
+ }
60
+ /**
61
+ * CDN Manifest structure from Better i18n
62
+ */
63
+ export interface CdnManifest {
64
+ projectSlug: string;
65
+ sourceLanguage: string;
66
+ languages: CdnLanguage[];
67
+ files: Record<string, {
68
+ url: string;
69
+ size: number;
70
+ lastModified: string;
71
+ }>;
72
+ updatedAt: string;
73
+ }
74
+ export interface CdnLanguage {
75
+ code: string;
76
+ name: string;
77
+ nativeName: string;
78
+ isSource: boolean;
79
+ lastUpdated: string;
80
+ keyCount: number;
81
+ flagUrl: string;
82
+ countryCode: string;
47
83
  }
48
84
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analyzer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;IAC1E,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,YAAY,EAAE,UAAU,CAAC;CAC7C;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;IACpD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analyzer/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Extract translation keys command
3
+ *
4
+ * Extracts all t() function calls and compares with remote translations
5
+ */
6
+ import type { ScanOptions } from "../analyzer/types.js";
7
+ export interface ExtractKeysOptions extends ScanOptions {
8
+ compare?: boolean;
9
+ locale?: string;
10
+ format: "eslint" | "json";
11
+ }
12
+ export declare function extractKeysCommand(options: ExtractKeysOptions): Promise<void>;
13
+ //# sourceMappingURL=extract-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-keys.d.ts","sourceRoot":"","sources":["../../src/commands/extract-keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAI5E,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,iBAkMnE"}
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Extract translation keys command
3
+ *
4
+ * Extracts all t() function calls and compares with remote translations
5
+ */
6
+ import ora from "ora";
7
+ import { collectFiles } from "../analyzer/file-collector.js";
8
+ import { analyzeFile } from "../analyzer/index.js";
9
+ import { detectProjectContext } from "../context/detector.js";
10
+ import { bold, cyan, dim, green, red, yellow } from "../utils/colors.js";
11
+ export async function extractKeysCommand(options) {
12
+ const startTime = Date.now();
13
+ const isJson = options.format === "json";
14
+ // Create spinner (noop for JSON output)
15
+ const spinner = isJson
16
+ ? {
17
+ start: (_text) => { },
18
+ succeed: (_text) => { },
19
+ fail: (_text) => { },
20
+ warn: (_text) => { },
21
+ text: "",
22
+ }
23
+ : ora({ text: "Detecting project...", color: "cyan" }).start();
24
+ // Step 1: Detect project context
25
+ const rootDir = options.dir || process.cwd();
26
+ const context = await detectProjectContext(rootDir);
27
+ if (context) {
28
+ spinner.succeed(`Project: ${bold(context.workspaceId + "/" + context.projectSlug)}`);
29
+ }
30
+ else {
31
+ spinner.warn("No i18n.config.ts found, using defaults");
32
+ }
33
+ // Step 2: Fetch manifest to get source language
34
+ let manifest = null;
35
+ let sourceLocale = options.locale || context?.defaultLocale || "en";
36
+ if (context?.cdnBaseUrl) {
37
+ spinner.start("Fetching manifest...");
38
+ try {
39
+ manifest = await fetchManifest(context.cdnBaseUrl, context.workspaceId, context.projectSlug);
40
+ // Get source language from manifest
41
+ const sourceLanguage = manifest.languages.find((l) => l.isSource);
42
+ if (sourceLanguage) {
43
+ sourceLocale = sourceLanguage.code;
44
+ }
45
+ spinner.succeed(`Manifest loaded (source: ${bold(sourceLocale)}, ${manifest.languages.length} languages)`);
46
+ }
47
+ catch (error) {
48
+ spinner.warn(`Could not fetch manifest: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ }
51
+ // Step 3: Collect files
52
+ spinner.start("Collecting files...");
53
+ const files = await collectFiles({
54
+ rootDir,
55
+ include: context?.lint?.include,
56
+ exclude: context?.lint?.exclude,
57
+ });
58
+ if (files.length === 0) {
59
+ spinner.fail("No .tsx or .jsx files found");
60
+ return;
61
+ }
62
+ spinner.succeed(`Found ${files.length} files`);
63
+ // Step 4: Analyze files for t() calls with progress
64
+ const allIssues = [];
65
+ let processedFiles = 0;
66
+ for (const file of files) {
67
+ processedFiles++;
68
+ // Update spinner with progress every 10 files
69
+ if (!isJson && processedFiles % 10 === 0) {
70
+ spinner.text = `Extracting keys... (${processedFiles}/${files.length})`;
71
+ }
72
+ if (!isJson && processedFiles === 1) {
73
+ spinner.start(`Extracting keys... (${processedFiles}/${files.length})`);
74
+ }
75
+ try {
76
+ const issues = await analyzeFile(file, context?.lint);
77
+ // Filter only translation function calls
78
+ const translationKeys = issues.filter((i) => i.type === "string-variable");
79
+ allIssues.push(...translationKeys);
80
+ }
81
+ catch (error) {
82
+ if (options.verbose) {
83
+ console.error(`Error analyzing ${file}:`, error);
84
+ }
85
+ }
86
+ }
87
+ spinner.succeed(`Extracted ${allIssues.length} keys from ${files.length} files`);
88
+ // Step 5: Organize keys by namespace
89
+ const keysByNamespace = groupKeysByNamespace(allIssues);
90
+ const localKeys = {
91
+ project: context
92
+ ? `${context.workspaceId}/${context.projectSlug}`
93
+ : "unknown",
94
+ namespaces: keysByNamespace,
95
+ totalCount: allIssues.length,
96
+ filesScanned: files.length,
97
+ };
98
+ // Step 6: Compare with CDN (always if manifest available, or if --compare flag)
99
+ const shouldCompare = manifest || (options.compare && context?.cdnBaseUrl);
100
+ if (shouldCompare && context?.cdnBaseUrl) {
101
+ spinner.start(`Comparing with remote (${sourceLocale})...`);
102
+ try {
103
+ const remoteKeys = await fetchRemoteKeys(context.cdnBaseUrl, context.workspaceId, context.projectSlug, sourceLocale, manifest);
104
+ spinner.succeed(`Fetched ${countTotalKeys(remoteKeys)} keys from remote`);
105
+ // Compare
106
+ const comparison = compareKeys(localKeys.namespaces, remoteKeys);
107
+ const duration = Date.now() - startTime;
108
+ // Report comparison
109
+ if (isJson) {
110
+ const output = {
111
+ project: context
112
+ ? {
113
+ workspace: context.workspaceId,
114
+ slug: context.projectSlug,
115
+ sourceLocale,
116
+ }
117
+ : null,
118
+ localKeys: {
119
+ total: localKeys.totalCount,
120
+ namespaces: localKeys.namespaces,
121
+ },
122
+ remoteKeys: {
123
+ total: countTotalKeys(remoteKeys),
124
+ },
125
+ comparison: {
126
+ missingInRemote: comparison.missing,
127
+ unusedInCode: comparison.unused,
128
+ missingCount: countMissingKeys(comparison.missing),
129
+ unusedCount: countMissingKeys(comparison.unused),
130
+ },
131
+ coverage: {
132
+ local: calculateCoverage(localKeys.totalCount, comparison.missing),
133
+ remote: calculateRemoteCoverage(localKeys.namespaces, remoteKeys),
134
+ },
135
+ files: files.length,
136
+ duration,
137
+ };
138
+ console.log(JSON.stringify(output, null, 2));
139
+ }
140
+ else {
141
+ reportComparisonReport(localKeys, remoteKeys, comparison, duration, sourceLocale);
142
+ }
143
+ }
144
+ catch (error) {
145
+ spinner.fail(`Failed to fetch remote keys: ${error instanceof Error ? error.message : String(error)}`);
146
+ reportLocalKeys(localKeys, allIssues.length, Date.now() - startTime);
147
+ }
148
+ }
149
+ else {
150
+ // Just report local keys
151
+ const duration = Date.now() - startTime;
152
+ if (isJson) {
153
+ const output = {
154
+ localKeys,
155
+ files: files.length,
156
+ duration,
157
+ };
158
+ console.log(JSON.stringify(output, null, 2));
159
+ }
160
+ else {
161
+ reportLocalKeys(localKeys, allIssues.length, duration);
162
+ }
163
+ }
164
+ }
165
+ /**
166
+ * Fetch manifest from CDN
167
+ */
168
+ async function fetchManifest(cdnBaseUrl, workspaceId, projectSlug) {
169
+ const url = `${cdnBaseUrl}/${workspaceId}/${projectSlug}/manifest.json`;
170
+ const response = await fetch(url);
171
+ if (!response.ok) {
172
+ throw new Error(`Manifest fetch failed (${response.status})`);
173
+ }
174
+ return response.json();
175
+ }
176
+ /**
177
+ * Group keys by namespace
178
+ */
179
+ function groupKeysByNamespace(issues) {
180
+ const result = {};
181
+ for (const issue of issues) {
182
+ if (!issue.key)
183
+ continue;
184
+ const parts = issue.key.split(".");
185
+ const namespace = parts.length > 1 ? parts[0] : "default";
186
+ const fullKey = issue.key;
187
+ if (!result[namespace]) {
188
+ result[namespace] = new Set();
189
+ }
190
+ result[namespace].add(fullKey);
191
+ }
192
+ // Convert Sets to arrays
193
+ const output = {};
194
+ for (const [namespace, keys] of Object.entries(result)) {
195
+ output[namespace] = Array.from(keys).sort();
196
+ }
197
+ return output;
198
+ }
199
+ /**
200
+ * Fetch remote keys from CDN
201
+ */
202
+ async function fetchRemoteKeys(cdnBaseUrl, workspaceId, projectSlug, locale, manifest) {
203
+ // Use manifest URL if available, otherwise construct URL
204
+ let url;
205
+ if (manifest?.files[locale]?.url) {
206
+ url = manifest.files[locale].url;
207
+ }
208
+ else {
209
+ url = `${cdnBaseUrl}/${workspaceId}/${projectSlug}/translations/${locale}.json`;
210
+ }
211
+ const response = await fetch(url);
212
+ if (!response.ok) {
213
+ throw new Error(`CDN fetch failed (${response.status})`);
214
+ }
215
+ return response.json();
216
+ }
217
+ /**
218
+ * Compare local and remote keys
219
+ */
220
+ function compareKeys(localKeys, remoteKeys) {
221
+ const missing = {};
222
+ const unused = {};
223
+ // Flatten remote keys to get all key paths
224
+ const remoteFlattened = flattenKeys(remoteKeys);
225
+ const allRemoteKeys = new Set();
226
+ for (const keys of Object.values(remoteFlattened)) {
227
+ for (const key of keys) {
228
+ allRemoteKeys.add(key);
229
+ }
230
+ }
231
+ // Get all local keys
232
+ const allLocalKeys = new Set();
233
+ for (const keys of Object.values(localKeys)) {
234
+ for (const key of keys) {
235
+ allLocalKeys.add(key);
236
+ }
237
+ }
238
+ // Find missing in remote (in local but not in remote)
239
+ for (const [namespace, keys] of Object.entries(localKeys)) {
240
+ const missingKeys = keys.filter((k) => !allRemoteKeys.has(k));
241
+ if (missingKeys.length > 0) {
242
+ missing[namespace] = missingKeys;
243
+ }
244
+ }
245
+ // Find unused in code (in remote but not in local)
246
+ for (const [namespace, keys] of Object.entries(remoteFlattened)) {
247
+ const unusedKeys = keys.filter((k) => !allLocalKeys.has(k));
248
+ if (unusedKeys.length > 0) {
249
+ unused[namespace] = unusedKeys;
250
+ }
251
+ }
252
+ return { missing, unused };
253
+ }
254
+ /**
255
+ * Flatten remote keys to get all namespaces
256
+ */
257
+ function flattenKeys(remoteKeys) {
258
+ const result = {};
259
+ function traverse(obj, prefix = "") {
260
+ for (const [key, value] of Object.entries(obj)) {
261
+ const fullKey = prefix ? `${prefix}.${key}` : key;
262
+ if (typeof value === "string") {
263
+ const namespace = fullKey.split(".")[0] || "default";
264
+ if (!result[namespace])
265
+ result[namespace] = [];
266
+ result[namespace].push(fullKey);
267
+ }
268
+ else if (typeof value === "object" && value !== null) {
269
+ traverse(value, fullKey);
270
+ }
271
+ }
272
+ }
273
+ traverse(remoteKeys);
274
+ return result;
275
+ }
276
+ /**
277
+ * Count total keys in nested structure
278
+ */
279
+ function countTotalKeys(remoteKeys) {
280
+ let count = 0;
281
+ function traverse(obj) {
282
+ for (const value of Object.values(obj)) {
283
+ if (typeof value === "string") {
284
+ count++;
285
+ }
286
+ else if (typeof value === "object" && value !== null) {
287
+ traverse(value);
288
+ }
289
+ }
290
+ }
291
+ traverse(remoteKeys);
292
+ return count;
293
+ }
294
+ /**
295
+ * Count missing keys total
296
+ */
297
+ function countMissingKeys(keys) {
298
+ return Object.values(keys).reduce((sum, arr) => sum + arr.length, 0);
299
+ }
300
+ /**
301
+ * Calculate local coverage (what % of local keys exist in remote)
302
+ */
303
+ function calculateCoverage(localCount, missing) {
304
+ const missingCount = countMissingKeys(missing);
305
+ if (localCount === 0)
306
+ return 100;
307
+ return Math.round(((localCount - missingCount) / localCount) * 100);
308
+ }
309
+ /**
310
+ * Calculate remote coverage (what % of remote keys are used)
311
+ */
312
+ function calculateRemoteCoverage(localKeys, remoteKeys) {
313
+ const remoteFlattened = flattenKeys(remoteKeys);
314
+ let remoteUsedCount = 0;
315
+ let remoteTotalCount = 0;
316
+ const allLocalKeys = new Set();
317
+ for (const keys of Object.values(localKeys)) {
318
+ for (const key of keys) {
319
+ allLocalKeys.add(key);
320
+ }
321
+ }
322
+ for (const keys of Object.values(remoteFlattened)) {
323
+ for (const key of keys) {
324
+ remoteTotalCount++;
325
+ if (allLocalKeys.has(key)) {
326
+ remoteUsedCount++;
327
+ }
328
+ }
329
+ }
330
+ if (remoteTotalCount === 0)
331
+ return 0;
332
+ return Math.round((remoteUsedCount / remoteTotalCount) * 100);
333
+ }
334
+ /**
335
+ * Report local keys (human-readable)
336
+ */
337
+ function reportLocalKeys(localKeys, _issueCount, duration) {
338
+ console.log();
339
+ console.log(bold("📦 Local Translation Keys"));
340
+ console.log();
341
+ const sortedNamespaces = Object.keys(localKeys.namespaces).sort();
342
+ for (const namespace of sortedNamespaces) {
343
+ const keys = localKeys.namespaces[namespace];
344
+ console.log(`${dim(`${namespace}:`)} ${keys.length} keys`);
345
+ for (const key of keys) {
346
+ console.log(` ${dim("•")} ${key}`);
347
+ }
348
+ console.log();
349
+ }
350
+ console.log(green(bold(`✓ Found ${localKeys.totalCount} translation keys`)));
351
+ console.log(dim(`Scanned ${localKeys.filesScanned} files in ${(duration / 1000).toFixed(2)}s`));
352
+ }
353
+ /**
354
+ * Report comparison (human-readable)
355
+ */
356
+ function reportComparisonReport(localKeys, remoteKeys, comparison, duration, sourceLocale) {
357
+ console.log();
358
+ console.log(bold("📊 Translation Keys Comparison"));
359
+ console.log(dim(`Source locale: ${sourceLocale}`));
360
+ console.log();
361
+ // Coverage
362
+ const localCoverage = calculateCoverage(localKeys.totalCount, comparison.missing);
363
+ const remoteCoverage = calculateRemoteCoverage(localKeys.namespaces, remoteKeys);
364
+ console.log(`${dim("Coverage:")}`);
365
+ console.log(` Local → Remote: ${cyan(localCoverage + "%")}`);
366
+ console.log(` Remote Used: ${cyan(remoteCoverage + "%")}`);
367
+ console.log();
368
+ // Missing keys (in code but not in remote)
369
+ const totalMissing = countMissingKeys(comparison.missing);
370
+ if (totalMissing > 0) {
371
+ console.log(red(bold(`❌ Missing in Remote (${totalMissing} keys):`)));
372
+ console.log(dim(" Keys used in code but not uploaded to Better i18n"));
373
+ console.log();
374
+ for (const [namespace, keys] of Object.entries(comparison.missing)) {
375
+ console.log(`${dim(`${namespace}:`)} ${keys.length} keys`);
376
+ for (const key of keys.slice(0, 5)) {
377
+ console.log(` ${dim("+")} ${key}`);
378
+ }
379
+ if (keys.length > 5) {
380
+ console.log(` ${dim(` ... and ${keys.length - 5} more`)}`);
381
+ }
382
+ console.log();
383
+ }
384
+ }
385
+ else {
386
+ console.log(green(bold("✓ All local keys exist in remote!")));
387
+ console.log();
388
+ }
389
+ // Unused keys (in remote but not in code)
390
+ const totalUnused = countMissingKeys(comparison.unused);
391
+ if (totalUnused > 0) {
392
+ console.log(yellow(bold(`⚠️ Unused in Code (${totalUnused} keys):`)));
393
+ console.log(dim(" Keys in Better i18n but not used in code"));
394
+ console.log();
395
+ let shown = 0;
396
+ for (const [namespace, keys] of Object.entries(comparison.unused)) {
397
+ if (shown >= 3) {
398
+ const remaining = Object.keys(comparison.unused).length - 3;
399
+ console.log(dim(` ... and ${remaining} more namespaces`));
400
+ break;
401
+ }
402
+ console.log(`${dim(`${namespace}:`)} ${keys.length} keys`);
403
+ for (const key of keys.slice(0, 3)) {
404
+ console.log(` ${dim("-")} ${key}`);
405
+ }
406
+ if (keys.length > 3) {
407
+ console.log(` ${dim(` ... and ${keys.length - 3} more`)}`);
408
+ }
409
+ console.log();
410
+ shown++;
411
+ }
412
+ }
413
+ // Summary
414
+ console.log();
415
+ console.log(dim(`Scanned ${localKeys.filesScanned} files in ${(duration / 1000).toFixed(2)}s`));
416
+ console.log(green(bold(`✓ Comparison complete`)));
417
+ }
418
+ //# sourceMappingURL=extract-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-keys.js","sourceRoot":"","sources":["../../src/commands/extract-keys.ts"],"names":[],"mappings":"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"}
@@ -133,8 +133,8 @@ function parseI18nConfig(filePath) {
133
133
  const projectConstMatch = content.match(/(?:export\s+)?const\s+project\s*=\s*['"]([^'"]+\/[^'"]+)['"]/);
134
134
  if (projectConstMatch) {
135
135
  const [workspaceId, projectSlug] = projectConstMatch[1].split("/");
136
- const localeMatch = content.match(/defaultLocale[:\s]*['"]([^'"]+)['"]/);
137
- const cdnMatch = content.match(/cdnBaseUrl[:\s]*['"]([^'"]+)['"]/);
136
+ const localeMatch = content.match(/defaultLocale[:\s=]*['"]([^'"]+)['"]/);
137
+ const cdnMatch = content.match(/cdnBaseUrl[:\s=]*['"]([^'"]+)['"]/);
138
138
  const lint = parseLintConfig(content);
139
139
  return {
140
140
  workspaceId,
@@ -1 +1 @@
1
- {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/context/detector.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,11 +6,12 @@
6
6
  * Automatically reads i18n.config.ts for project context.
7
7
  */
8
8
  import { program } from "commander";
9
+ import { extractKeysCommand } from "./commands/extract-keys.js";
9
10
  import { scanCommand } from "./commands/scan.js";
10
11
  program
11
12
  .name("better-i18n")
12
- .description("Detect hardcoded strings in your React/Next.js app")
13
- .version("0.1.1");
13
+ .description("Detect hardcoded strings and extract translation keys in your React/Next.js app")
14
+ .version("0.1.2");
14
15
  program
15
16
  .command("scan")
16
17
  .description("Scan source files for untranslated strings")
@@ -22,5 +23,15 @@ program
22
23
  .option("--staged", "Only scan git staged files")
23
24
  .option("--verbose", "Show detailed output")
24
25
  .action(scanCommand);
26
+ program
27
+ .command("extract-keys")
28
+ .alias("extract")
29
+ .description("Extract all translation keys (t() calls) from codebase")
30
+ .option("-d, --dir <path>", "Directory to scan (default: current directory)")
31
+ .option("-f, --format <type>", "Output format: eslint, json", "eslint")
32
+ .option("--compare", "Compare with remote keys from CDN")
33
+ .option("--locale <code>", "Locale to fetch from CDN (default: en)")
34
+ .option("--verbose", "Show detailed output")
35
+ .action(extractKeysCommand);
25
36
  program.parse();
26
37
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CACL,uBAAuB,EACvB,oDAAoD,EACpD,QAAQ,CACT;KACA,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC;KACzD,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;KAC/D,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CACV,iFAAiF,CAClF;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4CAA4C,CAAC;KACzD,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CACL,uBAAuB,EACvB,oDAAoD,EACpD,QAAQ,CACT;KACA,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC;KACzD,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;KAC/D,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,KAAK,CAAC,SAAS,CAAC;KAChB,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,kBAAkB,EAAE,gDAAgD,CAAC;KAC5E,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,QAAQ,CAAC;KACtE,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;KACxD,MAAM,CAAC,iBAAiB,EAAE,wCAAwC,CAAC;KACnE,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,kBAAkB,CAAC,CAAC;AAE9B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA4BnD"}
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAS,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA2BnD"}
@@ -13,22 +13,21 @@ export function reportJson(result) {
13
13
  }
14
14
  : null,
15
15
  summary: {
16
- total: result.issues.length,
16
+ issues: result.issues.length,
17
17
  errors: result.issues.filter((i) => i.severity === "error").length,
18
18
  warnings: result.issues.filter((i) => i.severity === "warning").length,
19
- filesScanned: result.files,
20
- durationMs: result.duration,
19
+ duration: result.duration,
20
+ results: result.issues.map((issue) => ({
21
+ file: issue.file,
22
+ line: issue.line,
23
+ column: issue.column,
24
+ type: issue.type,
25
+ severity: issue.severity,
26
+ message: issue.message,
27
+ text: issue.text,
28
+ suggestedKey: issue.suggestedKey,
29
+ })),
21
30
  },
22
- issues: result.issues.map((issue) => ({
23
- file: issue.file,
24
- line: issue.line,
25
- column: issue.column,
26
- type: issue.type,
27
- severity: issue.severity,
28
- message: issue.message,
29
- text: issue.text,
30
- suggestedKey: issue.suggestedKey,
31
- })),
32
31
  };
33
32
  console.log(JSON.stringify(output, null, 2));
34
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACrB,CAAC,CAAC;gBACA,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW;gBACrC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW;aACjC;YACD,CAAC,CAAC,IAAI;QACR,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;YAClE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;YACtE,YAAY,EAAE,MAAM,CAAC,KAAK;YAC1B,UAAU,EAAE,MAAM,CAAC,QAAQ;SAC5B;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;KACJ,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/reporters/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACrB,CAAC,CAAC;gBACA,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW;gBACrC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW;aACjC;YACD,CAAC,CAAC,IAAI;QACR,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;YACzE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;YAC7E,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAY,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,YAAY,EAAE,KAAK,CAAC,YAAY;aACjC,CAAC,CAAC;SACJ;KACF,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-i18n/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI tool for detecting hardcoded strings in React/Next.js apps",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,7 +50,7 @@
50
50
  "typescript": "~5.9.2"
51
51
  },
52
52
  "devDependencies": {
53
- "@repo/typescript-config": "workspace:*",
53
+ "@better-i18n/typescript-config": "workspace:*",
54
54
  "@types/node": "^20.0.0"
55
55
  },
56
56
  "engines": {