Skip to main content
Glama
the-i18n-mcp
by fabkho

the-i18n-kit

CI License Glama score

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-i18n-kit/cli

npm

The CLI, and the library every other surface is built on

@the-i18n-kit/mcp

npm

MCP server, for AI coding agents

@the-i18n-kit/nuxt

npm

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 yet

For 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.

Why this toolkit

Who it is for, and who it is not

Monorepos and layers

The consumer graph, shared libraries, misplaced usages

Frameworks

Nuxt, Laravel, Vue, React/Next, generic

Configuration

Where it lives, precedence, every field

CI/CD

The Action and the GitLab template

CLI · MCP tools

Generated reference

Development

pnpm install
pnpm build
pnpm test
pnpm lint
pnpm typecheck

DEBUG=1 enables verbose logging to stderr. See CONTRIBUTING.md.

License

MIT

Available Tools

15 tools
discoverDiscover i18n SetupA
Read-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 LayersA
Read-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 KeysA
DestructiveIdempotent

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 KeysA
Idempotent

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 TranslationsA
Read-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 TranslationsA
Read-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 StatusA
Read-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 NamespacesA
Read-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 KeyA
Destructive

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 TranslationsA
DestructiveIdempotent

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 LocaleA
Idempotent

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 TranslationsA
Read-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 KeyA
DestructiveIdempotent

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 MissingA
Idempotent

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 TranslationsA
DestructiveIdempotent

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

    A4.3/5.0

    Scored across 15 tools

    Disambiguation5/5

    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.

    Naming Consistency4/5

    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.

    Tool Count5/5

    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.

    Completeness5/5

    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

    ActivityStale
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      An 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 npm
      1
      ISC
    • A
      license
      A
      quality
      C
      maintenance
      MCP 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.
      12
      34 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An 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 npm
      1
      ISC