i18n-sharpen 0.2.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 ADDED
@@ -0,0 +1,270 @@
1
+ # i18n-sharpen ⚡️
2
+
3
+ A lightning-fast, zero-dependency, and configuration-driven CLI tool & library to **validate**, **extract**, and **prune** i18n translation keys in JS/TS codebases.
4
+
5
+ Keep your locale files clean, synchronized, and type-safe with ease.
6
+
7
+ ---
8
+
9
+ ## Key Features
10
+
11
+ 1. **Strict Quality Validation (`validate`)**:
12
+ * Detects missing translation keys used in source code.
13
+ * **Active Placeholder Detection**: Catches keys whose value is equal to their dot-notation path (meaning they are still untranslated placeholders).
14
+ * **Cross-Locale Key Alignment**: Ensures that all translation JSON files have the exact same keys as the default language file.
15
+ 2. **Automatic Key Extraction (`extract`)**:
16
+ * Scans codebase for translation patterns and automatically appends missing keys to all JSON files while maintaining formatting.
17
+ 3. **Safe Key Pruning (`prune`)**:
18
+ * Detects unused keys in JSON files and safely removes them to reduce bundle size.
19
+ 4. **CI/CD Markdown Reports**:
20
+ * Generates a clean quality and coverage report (`i18n-coverage.md`) ideal for PR comments and CI dashboards.
21
+ 5. **Programmatic API**:
22
+ * Can be imported and run dynamically in Node.js scripts.
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ Install as a devDependency using your package manager:
29
+
30
+ ```bash
31
+ pnpm add -D i18n-sharpen
32
+ # or
33
+ npm install -D i18n-sharpen
34
+ # or
35
+ yarn add -D i18n-sharpen
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Configuration
41
+
42
+ Create an `i18n-sharpen.json` file in the root of your project:
43
+
44
+ ```json
45
+ {
46
+ "scanDirs": ["src", "packages/shared/src"],
47
+ "localesDir": "src/locales",
48
+ "defaultLanguage": "en",
49
+ "supportedLanguages": ["en", "ja", "vi"],
50
+ "matchFunctions": ["t", "getTranslation"],
51
+ "outputReport": "i18n-coverage.md"
52
+ }
53
+ ```
54
+
55
+ Alternatively, you can add an `"i18nSharpen"` field to your `package.json`:
56
+
57
+ ```json
58
+ {
59
+ "name": "my-app",
60
+ "i18nSharpen": {
61
+ "scanDirs": ["src"],
62
+ "localesDir": "src/locales",
63
+ "defaultLanguage": "en",
64
+ "supportedLanguages": ["en", "ja"]
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### Config Options
70
+
71
+ | Option | Type | Default | Description |
72
+ | :--- | :--- | :--- | :--- |
73
+ | `scanDirs` | `string[]` | `["src"]` | Folders to scan for translation keys. |
74
+ | `localesDir` | `string` | `"src/locales"` | Directory containing your locale `.json` files. |
75
+ | `defaultLanguage` | `string` | `"en"` | The default/fallback locale language. |
76
+ | `supportedLanguages` | `string[]` | `["en"]` | List of supported languages. |
77
+ | `excludeDirs` | `string[]` | `["node_modules", ...]` | Directories to ignore during source scan. |
78
+ | `fileExtensions` | `string[]` | `[".ts", ".tsx", ...]` | File extensions to scan. |
79
+ | `matchFunctions` | `string[]` | `["t", "getTranslation"]` | Function names used for translation in code. |
80
+ | `matchAttributes` | `string[]` | `["i18nKey", "id", ...]` | HTML/JSX/Vue/Astro attribute names that carry translation keys. |
81
+ | `outputReport` | `string \| null` | `"i18n-coverage.md"` | Path to save quality report (`""` to disable). |
82
+ | `localesLayout` | `"flat" \| "namespaced"` | `"flat"` | Locale file layout — see [Locale Layouts](#locale-layouts). |
83
+ | `prune.force` | `boolean` | `false` | Make `prune` write by default. CLI `--force` overrides per invocation. |
84
+ | `looseKeyMatch` | `boolean` | `false` | Opt-in fuzzy match: any quoted occurrence of a locale key counts as "used". |
85
+ | `ignoreKeys` | `string[]` | `[]` | Key patterns (supports wildcards like `status.*`) to ignore during checks and pruning. |
86
+ | `pluralSuffixes` | `string[]` | `["_zero", "_one", ...]` | Custom suffixes used for plural keys (which are automatically resolved). |
87
+
88
+ ---
89
+
90
+ ## CLI Usage
91
+
92
+ Run commands with `npx` or configure scripts in `package.json`:
93
+
94
+ ```bash
95
+ # Validate translation keys and alignment
96
+ npx i18n-sharpen validate
97
+
98
+ # Extract new keys from code into json files
99
+ npx i18n-sharpen extract
100
+
101
+ # Prune unused keys from json files
102
+ npx i18n-sharpen prune
103
+ ```
104
+
105
+ ### Options
106
+
107
+ * `-c, --config <path>`: Specify a custom path to your configuration file (Phase 5).
108
+ * `-d, --cwd <path>`: Set custom working directory (defaults to `process.cwd()`).
109
+
110
+ `prune` accepts two additional flags:
111
+
112
+ * `--dry-run`: Preview only — never write. The default behavior; the
113
+ flag exists for explicit CI scripts.
114
+ * `--force`: Actually write the pruned locale files to disk.
115
+
116
+ ```bash
117
+ npx i18n-sharpen validate --config configs/i18n.json --cwd ./packages/app
118
+ npx i18n-sharpen prune --force
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Locale Layouts
124
+
125
+ Two layouts are supported under `localesDir`:
126
+
127
+ **Flat (default)** — one file per language:
128
+
129
+ ```
130
+ src/locales/
131
+ ├── en.json
132
+ ├── ja.json
133
+ └── vi.json
134
+ ```
135
+
136
+ **Namespaced** — one directory per language, one file per namespace, with
137
+ keys referenced as `t("namespace:key.path")`:
138
+
139
+ ```
140
+ src/locales/
141
+ ├── en/
142
+ │ ├── common.json // → keys load as "common:greeting" etc
143
+ │ └── auth.json // → keys load as "auth:login.title" etc
144
+ └── ja/
145
+ ├── common.json
146
+ └── auth.json
147
+ ```
148
+
149
+ ```json
150
+ { "localesLayout": "namespaced" }
151
+ ```
152
+
153
+ Note for 0.2.x: `validate`, `extract`, and `prune` fully support both flat and namespaced layouts end-to-end.
154
+
155
+ ---
156
+
157
+ ## Framework Coverage
158
+
159
+ Out of the box, `i18n-sharpen` scans `.ts`, `.tsx`, `.js`, `.jsx`,
160
+ `.vue`, `.svelte`, and `.astro`. The default `matchAttributes` covers
161
+ `i18nKey`, `id`, `i18n`, `:label`, `v-t`, and `t:`. Override either list
162
+ in your config to suit framework-specific conventions.
163
+
164
+ ---
165
+
166
+ ## Programmatic API
167
+
168
+ You can import `i18n-sharpen` to run tasks programmatically:
169
+
170
+ ```typescript
171
+ import {
172
+ loadConfig,
173
+ validate,
174
+ extract,
175
+ prune,
176
+ I18nSharpenError,
177
+ type I18nSharpenConfig,
178
+ type PruneResult
179
+ } from "i18n-sharpen"
180
+
181
+ const config: I18nSharpenConfig = loadConfig(process.cwd())
182
+
183
+ const results = validate(config, process.cwd())
184
+ console.log(`Coverage: ${results.codeKeyCoverage}%`)
185
+
186
+ extract(config, process.cwd())
187
+
188
+ // prune is dry-run by default — pass { force: true } to actually write.
189
+ const result: PruneResult = prune(config, process.cwd(), { force: true })
190
+ console.log(`Pruned ${result.totalPruned} keys`)
191
+
192
+ // Structured error handling
193
+ try {
194
+ prune(config)
195
+ } catch (err) {
196
+ if (err instanceof I18nSharpenError) {
197
+ if (err.error.kind === "parse") {
198
+ console.error(`Locale file ${err.error.path} is malformed`)
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Migration from 0.0.x / 0.1.x
207
+
208
+ * Rename `I18nCopConfig` → `I18nSharpenConfig` (the old name is a
209
+ deprecated alias, removal scheduled for 0.3.0).
210
+ * `prune()` is now dry-run by default. Pass `{ force: true }` or set
211
+ `config.prune.force: true` to write.
212
+ * `looseKeyMatch` is opt-in. Add `"looseKeyMatch": true` if you relied on
213
+ the previous default-on behaviour.
214
+ * All thrown errors are `I18nSharpenError` instances — `instanceof Error`
215
+ still works.
216
+
217
+ See [CHANGELOG.md](./CHANGELOG.md) for the full breakdown.
218
+
219
+ ---
220
+
221
+ ## CLI Exit Codes
222
+
223
+ `i18n-sharpen` respects standard exit codes to seamlessly integrate into CI/CD pipelines:
224
+ - **`0`**: Success. For `validate`, this means 0 missing keys, 0 active placeholders, and perfect key alignment across all languages.
225
+ - **`1`**: Failure. Occurs when there are filesystem/parse/configuration errors, or when a quality check in `validate` fails.
226
+
227
+ ---
228
+
229
+ ## GitHub Actions CI Integration
230
+
231
+ You can easily run quality checks on every Pull Request and automatically comment the generated markdown report on the PR:
232
+
233
+ ```yaml
234
+ name: i18n Quality Check
235
+
236
+ on:
237
+ pull_request:
238
+ branches: [ main ]
239
+
240
+ jobs:
241
+ i18n-check:
242
+ runs-on: ubuntu-latest
243
+ steps:
244
+ - name: Checkout repository
245
+ uses: actions/checkout@v4
246
+
247
+ - name: Setup Node.js
248
+ uses: actions/setup-node@v4
249
+ with:
250
+ node-version: 20
251
+
252
+ - name: Install dependencies
253
+ run: npm ci
254
+
255
+ - name: Run i18n Validation
256
+ run: npx i18n-sharpen validate
257
+
258
+ - name: Post Quality Report to PR
259
+ if: always() && hashFiles('i18n-coverage.md') != ''
260
+ uses: tholene/pr-comment-by-file-recreated@v1
261
+ with:
262
+ filePath: i18n-coverage.md
263
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
264
+ ```
265
+
266
+ ---
267
+
268
+ ## License
269
+
270
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node