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 +270 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1599 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +191 -0
- package/dist/index.js +1513 -0
- package/dist/index.js.map +1 -0
- package/package.json +71 -0
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
|