the-i18n-mcp
The-i18n-mcp is an MCP server that lets AI agents inspect, audit, translate, and refactor i18n translation files across every locale and layer of a (often monorepo/Nuxt) project.
Discover the setup —
discoverreturns project config (locales, default locale, layers, fallback chain, glossary, translation style), per-layer directory listings, key namespaces, the layer graph (including shared layers), and the active translation mode (provider vs agent).Explore keys —
list_namespacesgives a hierarchical key tree with counts;search_translationsdoes case-insensitive substring search over keys and/or values;get_translationsreads values for given keys, a layer, and one, many, or all (*) locales.Read/write translations —
write_translationsupserts/adds/updates key-value pairs (locale maps) with dry-run support;remove_translationsdeletes keys from all locale files in a layer.Audit coverage —
get_translation_statusreports per-locale/per-layer totals of translated, missing, and empty keys plus completion %;get_missing_translationsfinds keys absent in target locales;find_empty_translationsfinds keys whose value is an empty string.Translate with AI —
translate_missingandtranslate_keyfill in missing (or overwrite stale) translations, either by calling a configured LLM provider directly (provider mode) or by returning fallback contexts for the agent to translate inline (agent mode), honoring glossary, prompts, locale notes, and examples.Refactor keys and layers —
rename_translation_keyrenames within a layer;move_translation_keypromotes/demotes a key between layers, carrying all locales and refusing conflicting overwrites.Find code-level problems —
find_orphan_keys(defined but unused),find_undefined_keys(used in code but undefined), andfind_duplicate_keys(collisions across shared and app layers, optionally grouped by value with reuse/promote/consolidate advice), all scope-aware per app/layer with uncertain/dynamic key reporting.Clean up —
remove_orphan_keysfinds and deletes unused keys (dry-run first, never touching misplaced usages).Add new languages —
scaffold_localecreates empty JSON (Nuxt) or PHP (Laravel) locale files mirroring the default locale's key structure.Work at scale — most tools accept
layer,projectDir,outputFile(to avoid flooding context),dryRun, andexcludeDirs/scanDirsoptions for big monorepos.
the-i18n-kit
The i18n toolkit for AI agents and large monorepos. Find missing keys, remove dead ones, and rename across every locale and layer at once — from your agent, your terminal, or your pipeline.
📖 Documentation
Packages
Package | Version | What it is |
The CLI, and the library every other surface is built on | ||
MCP server, for AI coding agents | ||
Publishes the layer graph Nuxt already resolved |
A GitHub Action and a GitLab CI template ship from this repository too.
Related MCP server: @langapi/mcp-server
Quick Start
npm install -g @the-i18n-kit/cli
the-i18n-cli init # write a config from what it detects
the-i18n-cli status # coverage per locale and per layer
the-i18n-cli missing # what is not translated yetFor an AI agent, point your MCP host at the server:
{
"mcpServers": {
"the-i18n-mcp": {
"command": "npx",
"args": ["@the-i18n-kit/mcp@latest"]
}
}
}→ Getting started · MCP setup · CLI reference
Documentation
Everything lives on the documentation site. The reference sections are generated from the source they describe, so they cannot drift from it.
Who it is for, and who it is not | |
The consumer graph, shared libraries, misplaced usages | |
Nuxt, Laravel, Vue, React/Next, generic | |
Where it lives, precedence, every field | |
The Action and the GitLab template | |
Generated reference |
Development
pnpm install
pnpm build
pnpm test
pnpm lint
pnpm typecheckDEBUG=1 enables verbose logging to stderr. See CONTRIBUTING.md.
License
Available Tools
15 toolsdiscoverDiscover i18n SetupARead-only
Describe the project: detected config, locale directories per layer with file counts and top-level namespaces, the layer graph, and the hand-maintained locales. Call this first to understand the project before reading or writing translations. The result also names the active translation mode ("provider" when the server has an env-configured LLM provider, "agent" otherwise). layerGraph answers where a new key belongs: a key used by more than one app belongs in a layer those apps share, and layerGraph.shared names those layers.
Inputs: projectDir, includeTranslationGuidance. Returns: apps, layers, locales, rootDir, +12 more
find_duplicate_keysFind Duplicate Translation Keys Across LayersARead-only
Find translation keys defined in BOTH a shared layer and an app layer that consumes it. For example the same key in a monorepo root layer and in app-shop. At runtime the app layer's value shadows the shared one, so a collision with divergent values is the dangerous case: the shared value silently never shows. Compares one reference locale and reports each collision with both values and a divergent flag. Fix by deleting one side, never by moving.
Inputs: locale, byValue, outputFile, projectDir, +1 more. Returns: object
find_orphan_keysFind Orphan Translation KeysADestructiveIdempotent
Report translation keys that no source code references. Nothing is deleted unless remove is set. Scans a specific layer or all layers, and also detects dynamic key patterns and uncertain matches. Scope-aware: each layer is checked only against the code of the apps that consume it (summary.scanScope shows each layer's effective scope), and keys referenced only from non-consuming apps are reported separately as misplacedUsages rather than as orphans. With remove the orphan keys are deleted from every locale file of their layer — uncertain keys and misplaced usages are never deleted, in any mode.
Inputs: layer, locale, remove, scanDirs, +3 more. Returns: object
find_undefined_keysFind Used-But-Undefined Translation KeysAIdempotent
Find keys referenced in source code but defined in NO locale layer the using app consumes — the direction that ships raw keys to production. The inverse of find_orphan_keys. Scope-aware: each scan unit (app) is checked against the layers it consumes (summary.searchedLayersByApp), so a key defined only in a layer the using app does not consume is still undefined for that app. Known limitation: extraction is line-based and static — dynamically built keys (template literals, concatenation) cannot be verified and are reported as uncertainKeys, never as hard findings. With write, the hard findings are also added to a locale file as empty translations, which is the first half of the fix; uncertain findings are never written.
Inputs: layer, write, locale, scanDirs, +3 more. Returns: object
get_missing_translationsGet Missing TranslationsARead-only
Find translation keys that exist in the reference locale but are missing in other locales. Scans a specific layer or all layers. summary.totalMissingKeys counts every missing key in the project; limit caps only how many of them are listed under missing, over the nested map flattened to one entry per locale, layer and key.
Inputs: layer, limit, offset, outputFile, +3 more. Returns: object
get_translationsGet TranslationsARead-only
Get translation values by key path or by key prefix, from one layer or from every layer that defines them. Use "*" as the locale to read from all locales. Pass keys for an explicit list, or keyPrefix to read a whole namespace at once — one of the two is required, and a call with neither fails with EARG. With layer, the result is locale → key → value, exactly as it always was — unless limit cut it short, in which case it answers in the { byLayer } shape below, which has room for truncated and nextOffset. Without layer, every non-alias layer is read and the result is { byLayer, layersSearched }: byLayer holds that same shape per layer and names only the layers defining at least one of the keys, which is what answers where a key lives. limit counts one key per layer read, so a prefix read of seven layers is capped across all of them rather than per layer.
Inputs: locale (required), keys, layer, limit, +4 more. Returns: With a layer: locale → key → value. Without one: the same per layer that define…
get_translation_statusGet Translation StatusARead-only
Translation coverage in one call: per-locale and per-layer counts of total, translated, missing and empty keys, plus an overall completion percentage. Use this instead of calling get_missing_translations per layer and counting keys yourself. Empty-string values count as untranslated; set listEmpty to get the keys behind that count — they exist in the locale file, so they are never reported as missing, and they render as nothing in the UI. Locales listed in protectedLocales are reported but excluded from the overall figure, since they are maintained by hand. Where a translation memory lockfile exists, each locale and layer also carries stale — keys whose target was written from source text that has changed since — and the summary carries staleCount; translate with overwriteStale refreshes them.
Inputs: layer, listEmpty, outputFile, projectDir, +1 more. Returns: object
list_namespacesList NamespacesARead-only
List the translation key tree grouped by namespace prefix, with a count per namespace node. Use this to explore the available keys without guessing path prefixes. limit counts top-level namespace nodes across the scanned layers, each of which brings its whole subtree; totalNamespaces counts them all, whatever the limit let through.
Inputs: layer, limit, locale, offset, +1 more. Returns: layers, message, truncated, nextOffset, +1 more
move_translation_keyMove or Rename a Translation KeyADestructive
Move a translation key to another layer, to another key path, or both, carrying every locale that defines it. Pass toLayer to promote an app-layer key to a shared layer once a second app needs it (or to demote a shared key that turned out to be app-specific); call discover first, layerGraph.shared names the layers more than one app consumes. Pass newKey alone to rename the key in place across every locale file of its layer. Writes nothing at all if the destination already holds the key with a different value in any locale; if it holds the same value, that locale is deduplicated instead. Use dryRun to preview the plan.
Inputs: key (required), layer (required), dryRun, newKey, +2 more. Returns: object
remove_translationsRemove TranslationsADestructiveIdempotent
Remove one or more translation keys from ALL locale files in the given layer. Use dryRun to preview the changes before applying them.
Inputs: keys (required), layer (required), dryRun, projectDir. Returns: dryRun, message, removed, summary, +4 more
scaffold_localeScaffold LocaleAIdempotent
Create empty locale files for new languages, copying the key structure of the default locale with every value set to an empty string. Supports both JSON (Nuxt) and PHP (Laravel) formats. Does NOT modify the framework configuration — add the locale there first, then call this.
Inputs: layer, dryRun, locales, projectDir. Returns: dryRun, created, skipped
search_translationsSearch TranslationsARead-only
Search translation files by key path or value, one compact row per matching key rather than one per key and locale. Useful for finding an existing translation before adding a duplicate of it. A key that seven layers and thirty locales define comes back as a single row: layers names every layer that defines it, which is what tells reuse from duplication, and value is the one the reference locale holds. Pass includeLocales for the detail rows — one per key and locale — when what each locale holds is the question. Matching is a case-insensitive substring unless matchMode says otherwise.
Inputs: query (required), layer, limit, locale, +6 more. Returns: object
translate_keyTranslate KeyADestructiveIdempotent
Add or update one source translation key and translate it into the target locales. Unlike translate_missing, this can overwrite an existing but stale target translation. Same two modes as translate_missing: provider mode (the server env-configured) translates directly; agent mode returns a fallbackContext — translate it inline and persist via write_translations.
Inputs: key (required), layer (required), sourceLocale (required), dryRun, +5 more. Returns: key, mode, model, dryRun, +11 more
translate_missingTranslate MissingAIdempotent
Find the keys missing in the target locales and translate them. Without a translation backend nothing is written: the result carries per-locale fallback contexts to translate by hand instead. Two modes: in provider mode (the server env-configured with I18N_PROVIDER, I18N_MODEL and an API key) it calls the LLM provider directly and writes the results; in agent mode it returns those fallbackContexts — translate them inline and persist via write_translations. Check the discover output for the active mode. Uses the project config (glossary, translation prompt, locale notes, examples) where there is one. Translates all locales concurrently, so pass every target locale at once.
Inputs: keys, layer, dryRun, compact, +5 more. Returns: object
write_translationsWrite TranslationsADestructiveIdempotent
Write translation key-value pairs to a layer. Keys are inserted in alphabetical order. Mode "upsert" adds new keys and updates existing ones (default, most common). Mode "add" only creates new keys, skipping existing ones. Mode "update" only modifies existing keys, skipping missing ones. Use dryRun to preview without writing.
Inputs: layer (required), translations (required), mode, dryRun, +1 more. Returns: dryRun, message, skipped, summary, +8 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Each tool targets a distinct i18n operation: discovery, listing, reading, writing, removing, moving, translating, scaffolding, and four different key-health checks. The only mild overlap is get_translations vs search_translations, but their descriptions clearly separate exact/prefix retrieval from value-based search. No two tools appear to do the same thing.
The set is predominantly verb_noun snake_case (list_namespaces, get_translations, write_translations, find_undefined_keys). Minor deviations: 'discover' is a bare verb, and pluralization varies (translations vs translation_key/status). The verb-led convention is still clear and predictable overall.
15 tools is well within the ideal 3-15 range and each one maps to a distinct operation in translation management. The set feels purpose-built rather than padded or thin.
Covers the full lifecycle: discover, list/search/get, write/remove, move/rename, translate, scaffold, and comprehensive health checks (missing, undefined, orphan, duplicate, status). No obvious dead ends for the stated i18n management purpose; framework config edits are intentionally left out.
Maintenance
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that provides LLM agents with full access to the Texterify translation management API. It enables users to search, create, update, and delete translation keys and their values directly through natural language within their development environment.34 npm1ISC
- AlicenseAqualityDmaintenanceMCP server for AI-powered translation management in i18n projects, enabling automated locale detection, translation status checks, and sync via LangAPI.420 npm1MIT
- AlicenseAqualityCmaintenanceMCP server for managing i18n JSON translation files. Provides Claude with structured read/write access to translation files for adding keys, checking coverage, and finding duplicates.1234 npm1MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that lets AI agents read and write locale JSON translation files directly from the conversation without loading the whole catalog into context.14 npm1ISC