Harness Integrations
The MCP server gives every host the same tools. What differs per host is
enforcement: a model that knows about write_translations will still reach for
its file editor under pressure, and nothing in the protocol stops it. Hosts with
a hook system can stop it. Hosts without one get the rules as context, and CI
stays the backstop.
Claude Code
The repository doubles as a plugin marketplace:
/plugin marketplace add fabkho/the-i18n-kit
/plugin install the-i18n-kit@the-i18n-kit
One plugin, four components:
| Component | What it does |
|---|---|
| MCP server | the-i18n-kit over stdio via npx @the-i18n-kit/mcp@latest — the same server Set Up the MCP Server configures by hand |
| PreToolUse hook | Denies Edit and Write on files inside a locale directory, and answers with the tools to use instead. One hand-edited locale silently drifts from its siblings; the tools keep every locale consistent |
| Stop hook | Runs check before the agent finishes. Keys referenced in code but defined in no consumed layer render as raw keys in production, so findings block the stop with the key names and the agent fixes them in-session instead of leaving them for CI |
| Skill | The workflow as guidance: orient with discover, read before writing, write through tools, verify with find_undefined_keys |
Both hooks decide by walking up from the working directory to the nearest
.i18n-mcp.json or i18n-kit.config.*. No config file, no opinion: outside a
kit project they exit silently, so the plugin is safe to keep enabled globally.
They resolve the-i18n-cli from the project's node_modules first, then a
global install, then npx — and on any infrastructure failure they allow rather
than block.
Two environment variables switch the enforcement off when you mean to bypass it:
| Variable | Effect |
|---|---|
I18N_KIT_ALLOW_DIRECT_EDITS=1 | The locale-file guard stands down |
I18N_KIT_SKIP_CHECK=1 | The stop gate stands down |
Status Line
Claude Code plugins cannot ship a status line, so coverage in the footer is one manual step. The plugin carries the script; point your user settings at it:
{
"statusLine": {
"type": "command",
"command": "bash /path/to/the-i18n-kit/integrations/claude-code/statusline/i18n-statusline.sh"
}
}
It prints per-locale coverage — 🌐 de 100% · es 75% · fr 92% · 4 missing —
cached for a minute per project, and prints nothing outside kit projects, so it
composes with a status line you already have.
pi
pi install npm:@the-i18n-kit/pi
An extension rather than hooks: a widget by the editor that shows change, never state.
🌐 4 keys missing · es-ES 3 · fr-FR 1
🌐 ⠹ ▕██████░░░░░░▏ es-ES: batch 1/1 3/6
🌐 es-ES +3 · fr-FR +1 · ⚠ fr-FR dropped {count}
🌐 2 undefined keys · checkout.payNow, cart.empty
A finished run is reported from its own result rather than from the totals:
which locales moved, which translation dropped a placeholder — a broken string
in front of a user — and which locales were left alone because they are
protected, since three fewer locales than you asked for reads as failure until
it is named. After a turn that edited source, check runs: keys the code calls
and no layer defines render raw in production, and the moment the edit lands is
the cheapest moment to hear about them.
Coverage is also published as a host status — 🌐 4 missing, 🌐 ✓ — which
hosts with a footer render there. That is the standing fact the widget will not
keep on screen: a transient line suits change, a footer suits state, and each
surface gets the half it is good at.
The same figure is readable in-process, so a theme or another extension can put it wherever that setup actually looks — an editor border, a tmux status line — without this package knowing anything about it.
Colours are the theme's own — warning while work is outstanding, success
once it is done — so the widget matches whatever theme you run rather than
introducing a palette. The bar tracks real progress notifications and the
spinner turns only while a tool is running; I18N_KIT_WIDGET_STYLE=plain turns
both off.
It mentions outstanding work when you sit down, follows a translate_missing
run batch by batch instead of leaving a spinner with nothing behind it, reports
what moved when the run ends — and then withdraws. A project with nothing
missing gets no widget at all.
The reason is that a permanent line is an unread line. "Complete" says the same
thing whether or not you have touched translations all day, and a missing count
that has not moved in a week is wallpaper; worse, a percentage in a large
project is pinned near 100 and moves in the third decimal, looking like a gauge
while behaving like a constant. So the widget reports counts, briefly, and
/i18n-coverage answers in full — percentages, per locale — when you actually
ask. Like every other piece here it is silent outside kit projects.
Codex and Other Hosts
Codex CLI has no hook system, so the same rules travel as context instead of
enforcement. The server block is on
Set Up the MCP Server; next to it, put the rules
where your host reads them — AGENTS.md for Codex:
## Translations
This project manages translations with the-i18n-kit (MCP server `the-i18n-kit`).
- Never edit locale files directly — one edited locale drifts from its
siblings. Use `write_translations`, `translate_missing`, `translate_key`,
`remove_translations`, `move_translation_key`.
- Start with `discover` to see locales, layers and the translation mode.
- Before finishing work that touched UI code, run `find_undefined_keys`;
undefined keys render raw in production.
- Respect protected locales and preserve `{placeholders}` exactly.
Context is advice, and advice gets ignored. What the Stop hook enforces
in-session, the pipeline enforces on every push: check exits non-zero on
findings, wired through the GitHub Action or the
GitLab CI template. A host without hooks loses the
in-session correction, never the gate.
Long-Running Tools
translate_missing reports progress over MCP progress notifications — batch by
batch, locale by locale — but only when the host asks for it, and hosts differ:
- Claude Code requests progress and uses it to keep long calls alive; how much of it reaches the screen depends on the Claude Code version.
- pi with pi-mcp-adapter's progress bridge renders each notification as a live partial result on the running tool call.
- Hosts that request no progress get none — the server sends nothing rather than degrading the call.
The server side is the same in every case; a host upgrade is all it takes for progress to appear.