Introduction

Architecture

There is one engine. Everything else is a way of reaching it.

One Engine, Five Surfaces

A surface is a way of invoking the engine. There are five:

SurfacePackageWho invokes it
CLI@the-i18n-kit/cliYou, in a terminal
MCP server@the-i18n-kit/mcpYour AI agent, over the Model Context Protocol
Nuxt module@the-i18n-kit/nuxtNuxt, at prepare / dev / build
ESLint plugin@the-i18n-kit/eslint-plugin-vueESLint, in your editor and in lint runs
CI integrationsGitHub Action, GitLab CI templatesYour pipeline

The engine itself lives in @the-i18n-kit/cli. That package ships two things: the the-i18n-cli binary and the core library behind it — config detection, the framework adapters, the scanner, the layer graph and the operations that read and write locale files.

What the Engine Does Before Any Command Runs

Every surface resolves the same project model first:

  1. An adapter detects the framework — Nuxt, Laravel, Vue, React/Next.js or generic. Set framework in your kit config to pin one when the wrong adapter is picked.
  2. The adapter resolves config. Some of it is derived config, read out of the framework's own files; the rest is declared config, written by you.
  3. The layer graph is built from that config — which apps consume which layers, and which layers more than one app consumes.

The graph is what makes usage evidence app-scoped. Where it has no app information to work from, it treats every canonical layer as globally visible, so a missing description makes the tooling more conservative rather than more confident.

The MCP Server and the CLI

@the-i18n-kit/mcp declares @the-i18n-kit/cli as a dependency and imports the operations from it directly — findOrphanKeys, checkUndefinedKeys, translateMissing, renameTranslationKey and the rest are the same functions the CLI commands call.

What that buys you: when your agent reports 1,103 orphan keys and you re-run the scan in your terminal to check, you get 1,103. Not approximately. The scan, the scope rules, the uncertain-key classification and the removal guard are one implementation, so the two surfaces cannot drift apart in behavior — only in how they present the result.

The surfaces do differ in ergonomics. The CLI adds CI gates and exit codes; the MCP server adds tool descriptions, prompts and resources for the agent. The operation underneath is the same call.

Command and Tool Names

A command you learn in the terminal tells you what to ask your agent for, and a tool your agent used tells you what to type.

OperationCLI commandMCP tool
Project setup and layersdetectdiscover
Read specific keysgetget_translations
Write exact valueswritewrite_translations
Missing translationsmissingget_missing_translations
Coverage per locale and layerstatusget_translation_status
Empty valuesemptyfind_empty_translations
Search keys and valuessearchsearch_translations
Delete keysremoveremove_translations
Rename across all localesrenamerename_translation_key
Fill missing localestranslate / translate-missingtranslate_missing
Refresh one keytranslate-keytranslate_key
Orphan keysremove-orphans (dry run by default)find_orphan_keys / remove_orphan_keys
Used but undefinedcheckfind_undefined_keys
Shadowed keys across layersfind-duplicatesfind_duplicate_keys
Add a localescaffoldscaffold_locale

the-i18n-cli translate-missing is an alias of translate, so the MCP tool name works in the terminal too.

The pairing is not total. Five commands are terminal-side only: init (write a .i18n-mcp.json from framework detection), list-dirs, scan (raw usage sites with file paths and line numbers), and add / update, which add skip-if-present and skip-if-absent semantics on top of the plain write that write_translations performs. list_namespaces has no command counterpart. Where the names differ, the table above is the mapping.

The Nuxt Module

Nuxt already resolves your layer graph and your locale table. Without the module, that information exists twice: once inside Nuxt, and once restated by hand in .i18n-mcp.json — with nothing that notices when the two disagree.

@the-i18n-kit/nuxt writes what Nuxt resolved to .nuxt/i18n-kit.json on prepare, dev and build. The CLI reads that artifact in preference to hand-written config, and falls back to loading the app through Nuxt when the artifact is absent, unparseable, of an unknown version, or older than a nuxt.config it describes. Adding the module changes where the facts come from; removing it degrades rather than breaks.

The module also fails the build on protectedLocales entries that resolve to no locale or to several — two mistakes that previously looked like they had taken effect and had not.

The CI Integrations

The GitHub Action and the GitLab CI templates run the same binary you run locally. They decide job outcomes from its exit code rather than by parsing counts out of the JSON result — reading result fields to decide pass or fail is what coupled earlier template versions to output shapes that were never a contract.

The exit codes carry the distinction a pipeline needs:

CodeMeaning
0The run succeeded and no gate tripped
1The run itself failed — bad API key, unreadable project, a translate run that translated nothing
2The run succeeded but a gate tripped

A gate is a flag that makes the CLI exit non-zero on findings (--fail-on-missing, --fail-on-orphans, --fail-on-failed, --fail-under). A tripped gate is not a failed run, and keeping them at different codes is what lets a job treat a missing API key differently from a project that has untranslated keys.

Limits

  • The CLI package is the dependency boundary. @the-i18n-kit/mcp version n is built against a specific @the-i18n-kit/cli; running a globally installed CLI of a different version alongside it means two engine versions on one machine. Pin both, or install neither globally.
  • The Nuxt artifact requires a build. Policy declared only in nuxt.config.tsprotectedLocales and orphanScan especially — does not apply to an unbuilt checkout. Keep those two in .i18n-mcp.json if a pipeline depends on them.
  • The layer graph is only as good as its input. It derives from resolved config; it does not inspect imports to discover consumption you have not declared.
Copyright © 2026