the-i18n-mcp 2.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fabian Kirchhoff
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,298 @@
1
+ # the-i18n-mcp
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+ [![CI][ci-src]][ci-href]
7
+
8
+ MCP server for managing i18n translations in **Nuxt** and **Laravel** projects. Provides 14 tools for the full translation lifecycle: read, write, search, rename, remove, find missing, auto-translate, and detect unused keys — all without loading entire locale files into context. Auto-detects your framework, supports monorepos and layers, and works with any MCP host (VS Code, Cursor, Zed, Claude Desktop).
9
+
10
+ > **Migrating from `nuxt-i18n-mcp`?** The old package name still works — both `npx the-i18n-mcp` and `npx nuxt-i18n-mcp` point to the same server. No breaking changes for existing Nuxt users.
11
+
12
+ ## Supported Frameworks
13
+
14
+ | Framework | Locale Format | Auto-Detection | Config Source |
15
+ |-----------|--------------|----------------|---------------|
16
+ | **Nuxt** (v3+) | JSON | `nuxt.config.ts` with `@nuxtjs/i18n` | `@nuxt/kit` (optional peer dep) |
17
+ | **Laravel** (9+) | PHP arrays | `artisan`, `composer.json`, `lang/` directory | Built-in |
18
+
19
+ The server detects your framework automatically based on project structure. You can also force it via `"framework": "laravel"` or `"framework": "nuxt"` in `.i18n-mcp.json`.
20
+
21
+ ## Quick Start
22
+
23
+ ### 1. Configure your MCP host
24
+
25
+ No install needed — your MCP host runs the server via `npx`.
26
+
27
+ <details>
28
+ <summary><strong>VS Code / Cursor</strong></summary>
29
+
30
+ Add to `.vscode/mcp.json`:
31
+
32
+ ```json
33
+ {
34
+ "servers": {
35
+ "the-i18n-mcp": {
36
+ "type": "stdio",
37
+ "command": "npx",
38
+ "args": ["the-i18n-mcp@latest"]
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ </details>
45
+
46
+ <details>
47
+ <summary><strong>Zed</strong></summary>
48
+
49
+ Add to `.zed/settings.json`:
50
+
51
+ ```json
52
+ {
53
+ "context_servers": {
54
+ "the-i18n-mcp": {
55
+ "command": "npx",
56
+ "args": ["the-i18n-mcp@latest"]
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ </details>
63
+
64
+ <details>
65
+ <summary><strong>Claude Desktop</strong></summary>
66
+
67
+ Add to `claude_desktop_config.json`:
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "the-i18n-mcp": {
73
+ "command": "npx",
74
+ "args": ["the-i18n-mcp@latest"]
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ </details>
81
+
82
+ ### 2. Ask your agent
83
+
84
+ That's it — no configuration needed. The server auto-detects your project structure, locales, and layers. Just ask:
85
+
86
+ > *"Add a 'save changes' button translation in all locales"*
87
+ >
88
+ > *"Find and fix all missing translations in the admin layer"*
89
+ >
90
+ > *"Rename `common.actions.delete` to `common.actions.remove` across all locales"*
91
+
92
+ ## Typical Workflow
93
+
94
+ ```
95
+ 1. detect_i18n_config → understand project structure, locales, layers
96
+ 2. list_locale_dirs → see available layers with file counts and key namespaces
97
+ 3. get_missing_translations → find gaps between reference locale and targets
98
+ 4. add_translations → add new keys (requires layer param)
99
+ translate_missing → auto-translate missing keys via MCP sampling
100
+ 5. find_orphan_keys → find keys not referenced in source code
101
+ cleanup_unused_translations → remove orphan keys in one step
102
+ ```
103
+
104
+ Always call `detect_i18n_config` first — all other tools depend on the detected config.
105
+
106
+ ## Tools
107
+
108
+ Every write tool requires a `layer` parameter (e.g., `"root"`, `"app-admin"`, `"lang"`). Use `list_locale_dirs` to discover available layers.
109
+
110
+ | Tool | Description |
111
+ |------|-------------|
112
+ | `detect_i18n_config` | Auto-detects framework (Nuxt or Laravel), returns locales, layers, directories, and project config. **Call first.** |
113
+ | `list_locale_dirs` | Lists locale directories grouped by layer, with file counts and top-level key namespaces |
114
+ | `get_translations` | Reads values for dot-path keys from a locale/layer. Use `"*"` as locale for all locales |
115
+ | `add_translations` | Adds new keys to a **layer** across locales. Fails if key already exists. Supports `dryRun` |
116
+ | `update_translations` | Updates existing keys in a **layer**. Fails if key doesn't exist. Supports `dryRun` |
117
+ | `remove_translations` | Removes keys from ALL locale files in a **layer**. Supports `dryRun` |
118
+ | `rename_translation_key` | Renames/moves a key across all locales in a **layer**. Conflict detection + `dryRun` |
119
+ | `get_missing_translations` | Finds keys present in reference locale but missing/empty in targets. `""` counts as missing |
120
+ | `find_empty_translations` | Finds keys with empty string values. Checks each locale independently |
121
+ | `search_translations` | Searches by key pattern or value substring across layers and locales |
122
+ | `translate_missing` | Auto-translates via MCP sampling, or returns context for inline translation when sampling unavailable |
123
+ | `find_orphan_keys` | Finds keys not referenced in source code. Scans Vue/TS for Nuxt, Blade/PHP for Laravel |
124
+ | `scan_code_usage` | Shows where keys are used — file paths, line numbers, call patterns |
125
+ | `cleanup_unused_translations` | Finds orphan keys + removes them in one step. Dry-run by default |
126
+
127
+ ### Prompts
128
+
129
+ | Prompt | Description |
130
+ |--------|-------------|
131
+ | `add-feature-translations` | Guided workflow for adding translations when building a new feature. Accepts optional `layer` and `namespace` |
132
+ | `fix-missing-translations` | Find and fix all missing translations across the project. Accepts optional `layer` |
133
+
134
+ ### Resources
135
+
136
+ | Resource | Description |
137
+ |----------|-------------|
138
+ | `i18n:///{layer}/{file}` | Browse locale files directly (e.g., `i18n:///root/en-US.json`) |
139
+
140
+ ## Framework-Specific Details
141
+
142
+ ### Nuxt
143
+
144
+ - Auto-detects `nuxt.config.ts` with `@nuxtjs/i18n` via `@nuxt/kit`
145
+ - Supports monorepos: discovers all Nuxt apps under the given `projectDir`
146
+ - Supports Nuxt layers: each layer's locale directory becomes a separate layer
147
+ - Requires `@nuxt/kit` as a peer dependency (already present in Nuxt projects)
148
+ - Scans `.vue`, `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.mts` for `$t()`, `t()`, `this.$t()`
149
+
150
+ ### Laravel
151
+
152
+ - Auto-detects Laravel projects via `artisan`, `composer.json`, or `lang/` directory
153
+ - Supports both `lang/` (Laravel 9+) and `resources/lang/` (legacy) layouts
154
+ - Reads and writes PHP array locale files (`return ['key' => 'value'];`)
155
+ - No additional dependencies required — works out of the box
156
+ - Scans `.blade.php` and `.php` for `__()`, `trans()`, `trans_choice()`, `Lang::get()`, `@lang()`
157
+
158
+ ## Monorepo Support (Nuxt)
159
+
160
+ The server discovers all Nuxt apps with i18n configuration under the given `projectDir`. Pass the monorepo root and it walks the directory tree, finds every `nuxt.config.ts` with i18n settings, loads each app via `@nuxt/kit`, and merges the results. Each app's locale directories become separate layers.
161
+
162
+ ```
163
+ monorepo/
164
+ ├── apps/
165
+ │ ├── shop/ ← discovered, becomes "shop" layer
166
+ │ │ └── nuxt.config.ts (has i18n)
167
+ │ └── admin/ ← discovered, becomes "admin" layer
168
+ │ └── nuxt.config.ts (has i18n)
169
+ ├── packages/
170
+ │ └── shared/ ← skipped, no nuxt.config with i18n
171
+ └── package.json
172
+ ```
173
+
174
+ Discovery stops descending into a directory once it finds a `nuxt.config` — nested Nuxt layers are loaded by `@nuxt/kit` automatically.
175
+
176
+ ## Project Config
177
+
178
+ Optionally drop a `.i18n-mcp.json` at your project root to give the agent project-specific context. Everything is optional — the server passes them to the agent, which interprets the natural-language rules. The server walks up from `projectDir` to find the nearest config file (like ESLint or tsconfig resolution).
179
+
180
+ For IDE autocompletion, point to the schema:
181
+
182
+ ```json
183
+ {
184
+ "$schema": "node_modules/the-i18n-mcp/schema.json"
185
+ }
186
+ ```
187
+
188
+ | Field | Purpose |
189
+ |-------|---------|
190
+ | `context` | Free-form project background (business domain, user base, brand voice) |
191
+ | `layerRules` | Rules for which layer a new key belongs to, with natural-language `when` conditions |
192
+ | `glossary` | Term dictionary for consistent translations |
193
+ | `translationPrompt` | System prompt prepended to all translation requests |
194
+ | `localeNotes` | Per-locale instructions (e.g., `"de-DE-formal": "Use 'Sie', not 'du'"`) |
195
+ | `examples` | Few-shot translation examples demonstrating project style |
196
+ | `orphanScan` | Per-layer config for orphan detection: `scanDirs` (overrides auto-discovered dirs) and `ignorePatterns` (glob) |
197
+ | `reportOutput` | `true` for default `.i18n-reports/` dir, or a string for a custom path. Diagnostic tools write full output to disk and return only a summary in the MCP response |
198
+
199
+ ### Full example
200
+
201
+ ```json
202
+ {
203
+ "$schema": "node_modules/the-i18n-mcp/schema.json",
204
+ "context": "B2B SaaS booking platform. Professional but approachable tone.",
205
+ "layerRules": [
206
+ {
207
+ "layer": "shared",
208
+ "description": "Shared translations: common.actions.*, common.messages.*",
209
+ "when": "The key is generic enough to be used in multiple apps"
210
+ },
211
+ {
212
+ "layer": "app-admin",
213
+ "description": "Admin dashboard translations",
214
+ "when": "The key is only relevant to admin functionality"
215
+ }
216
+ ],
217
+ "glossary": {
218
+ "Buchung": "Booking (never 'Reservation')",
219
+ "Ressource": "Resource (a bookable entity like a room, desk, or person)",
220
+ "Termin": "Appointment"
221
+ },
222
+ "translationPrompt": "Use professional but approachable tone. Preserve all {placeholders}. Keep translations concise.",
223
+ "localeNotes": {
224
+ "de-DE-formal": "Formal German using 'Sie'. Used by enterprise customers.",
225
+ "en-US": "American English.",
226
+ "en-GB": "British English. Use 'colour' not 'color'."
227
+ },
228
+ "examples": [
229
+ {
230
+ "key": "common.actions.save",
231
+ "de-DE": "Speichern",
232
+ "en-US": "Save",
233
+ "note": "Concise, imperative"
234
+ }
235
+ ],
236
+ "orphanScan": {
237
+ "shared": {
238
+ "scanDirs": ["apps/shop", "apps/admin", "packages/shared"],
239
+ "ignorePatterns": ["common.datetime.**", "common.countries.*"]
240
+ },
241
+ "app-admin": {
242
+ "scanDirs": ["apps/admin"]
243
+ }
244
+ },
245
+ "reportOutput": true
246
+ }
247
+ ```
248
+
249
+ See [`playground/nuxt/.i18n-mcp.json`](playground/nuxt/.i18n-mcp.json) for a working example.
250
+
251
+ ## Features
252
+
253
+ - **Multi-framework** — auto-detects Nuxt and Laravel projects. `@nuxt/kit` is only needed for Nuxt.
254
+ - **Zero config** — reads `nuxt.config.ts` or Laravel `lang/` directory automatically. Works in monorepos.
255
+ - **Safe writes** — atomic file I/O (temp file + rename), indentation preservation, alphabetical key sorting, `{placeholder}` and `@:linked` ref validation.
256
+ - **Full lifecycle** — add, update, remove, rename, search, find missing, auto-translate, and clean up unused keys.
257
+ - **Code analysis** — find orphan keys not referenced in source (Vue/TS for Nuxt, Blade/PHP for Laravel), scan usage locations, bulk cleanup.
258
+ - **Project-aware** — optional `.i18n-mcp.json` for glossary, tone, layer rules, locale-specific instructions, and few-shot examples.
259
+ - **Caching** — config detection and file reads are cached (mtime-based). Writes invalidate automatically.
260
+ - **Sampling support** — `translate_missing` uses MCP sampling when available (VS Code). Falls back to returning context for inline translation (Zed, others).
261
+
262
+ ## Roadmap
263
+
264
+ - [ ] `find_hardcoded_strings` — detect user-facing strings not wrapped in translation calls
265
+ - [ ] `move_translations` — move keys between layers (e.g., promote to shared)
266
+ - [ ] Glossary validation — check translations against glossary terms
267
+ - [ ] Flat JSON support — `flatJson: true` in vue-i18n config
268
+ - [ ] Pluralization support — vue-i18n plural forms and Laravel `trans_choice`
269
+ - [ ] Plain vue-i18n support (without Nuxt)
270
+
271
+ ## Development
272
+
273
+ ```bash
274
+ pnpm build # Build via tsdown → dist/index.js
275
+ pnpm test # Run all tests
276
+ pnpm test:perf # Run performance benchmarks
277
+ pnpm lint # ESLint
278
+ pnpm typecheck # tsc --noEmit
279
+ pnpm start # Start the server on stdio
280
+ pnpm inspect # Open MCP Inspector for manual testing
281
+ ```
282
+
283
+ ## License
284
+
285
+ [MIT](./LICENSE)
286
+
287
+ <!-- Badges -->
288
+ [npm-version-src]: https://img.shields.io/npm/v/the-i18n-mcp?style=flat&colorA=18181b&colorB=4fc08d
289
+ [npm-version-href]: https://npmjs.com/package/the-i18n-mcp
290
+
291
+ [npm-downloads-src]: https://img.shields.io/npm/dm/the-i18n-mcp?style=flat&colorA=18181b&colorB=4fc08d
292
+ [npm-downloads-href]: https://npmjs.com/package/the-i18n-mcp
293
+
294
+ [license-src]: https://img.shields.io/npm/l/the-i18n-mcp?style=flat&colorA=18181b&colorB=4fc08d
295
+ [license-href]: https://github.com/fabkho/the-i18n-mcp/blob/main/LICENSE
296
+
297
+ [ci-src]: https://github.com/fabkho/the-i18n-mcp/actions/workflows/ci.yml/badge.svg
298
+ [ci-href]: https://github.com/fabkho/the-i18n-mcp/actions/workflows/ci.yml
@@ -0,0 +1 @@
1
+ export {};