Skip to content

Open source · MIT · Bring your own LLM key

Your agent localizes. Code guarantees.

Your coding agent moves hardcoded strings to keys and translates them. glot checks every LLM output with deterministic code and refuses anything broken or too long, with the exact reason, until the retry is valid.

Open the app

Detects your i18n stack, extracts strings, translates, checks. Run it again after every UI change.

Real glot binary. The LLM in this recording is scripted to get three strings wrong; the refusals are glot's.

Benchmark, October 18, 2026

Broken strings that reached the catalog

320 ICU messages per model and condition, 8 locales. Same prompts, same models.

Share of translated messages that were broken, by model and condition
ModelRaw promptWith glot
Claude Haiku 5.514.1%0%
Claude Sonnet 5.58.8%0%
With glot, 1.9% (Haiku) and 3.1% (Sonnet) of the strings were refused after retries and left untranslated instead of shipped broken. An independent judge (FormatJS + Intl.PluralRules) agrees. Read the full report

How it works

Three steps. Your agent can run them too.

Or all three at once, idempotent: npx glot-i18n localize.

  1. 1

    Detect

    Finds your i18n library and catalogs, writes glot.toml and the rules your coding agent reads.

    $ npx glot-i18n init

    next-intl · messages/{locale}.json

    wrote glot.toml, CLAUDE.md rules

  2. 2

    Extract

    Moves hardcoded UI strings to keys and rewrites the components for next-intl or react-i18next.

    $ npx glot-i18n i18nize

    42 strings → keys in 9 components

    app/checkout/page.tsx +12 −12

  3. 3

    Translate, validated

    Only the delta. Each output is checked; a refusal goes back to the model with the reason. Still invalid after retries: nothing is written.

    $ npx glot-i18n translate

    ✗ refused pl inbox.unread: missing few, many

    ✓ fixed pl attempt 2 · check passed

The guarantees

The LLM proposes. Code decides what gets written.

Every card shows a real refusal, word for word as glot prints it.

  • Placeholders and tags

    Same set as the source, none invented, none translated. ICU, i18next and MessageFormat 2.

    fr "Bon retour, {nom} !"

    Refused by glot: Placeholder `{nom}` does not exist in the source; remove it or fix its name (the source only has {name}).

  • CLDR plurals

    Every category the target locale needs: four for Polish, six for Arabic.

    pl "{count, plural, one {…} other {…}}"

    Refused by glot: `{count, plural, …}` is missing plural categories required by pl: few, many.

  • Glossary as code

    glossary.toml in your repo: required and forbidden translations, do-not-translate terms.

    fr "Ouvrez votre espace"

    Refused by glot: Glossary: `Workspace` must be translated as `Espace de travail` in fr.

  • Pixel width

    Measured with your app's real font and box. Too wide is refused, never truncated.

    de "Zahlungserinnerung an den Kunden senden"

    Refused by glot: Too wide for its box in the app: one line of 120px at Geist 14px/400; it renders 276px wide.

  • Lockfile

    glot.lock hashes source and target. Only the delta is translated; hand edits are never overwritten.

    $ glot translate --locales fr

    Refused by glot: 1 edited by hand

  • CI check

    glot check runs every rule offline on every catalog and exits 1 with PR annotations.

    $ glot check --format github

    Refused by glot: ::error file=messages/de.json,line=12,title=glot tag_mismatch::[de] home.cta: Markup tags differ from the source: missing `<b>`

Pixel budget

Translations that fit the button

German runs a third longer than English. glot fit renders your running app in each locale, measures every text against its box, asks for a shorter variant that keeps the meaning and placeholders, and renders again.

  • Measured in the browser, not guessed from a character count
  • Shorter variants still pass the validator and the glossary
  • A fixed number of passes, never an open-ended loop
Before · Overflows its 112 px button
Zahlungserinnerung sendenAls bezahlt markierenArchivieren

"Zahlungserinnerung senden"

After glot fit, 1 iteration · Fits
MahnungAls bezahlt markierenArchivieren

"Mahnung" · claude-haiku-5-5 · $0.0002

Real run on the demo app, German locale.

Try it, nothing to install

Can you break glot?

Edit the translation. The same validator that guards glot translate, compiled to WebAssembly, runs in your browser on every keystroke.

Start from a broken translation

Loading the validator…

No refusals yet. Try one of the challenges.

Pixel width and glossary need your app and your repo: try them with the CLI.

Agents

Works with the agent you already use

glot mcp gives your agent your keys, where they are used, and the glossary. Every string it adds goes through the same validator.

Setup for each agent

In-app editing

Alt+click any text in your app

The dev overlay finds the key behind the text you clicked, shows it in every locale with live validator issues, and saves to your catalog files.

  • Suggest, shorten, make more formal, translate all
  • Flags text that overflows its container
  • Dev only, about 6 kB gzipped
glot overlay popover showing a key, its source and its translations in five languages

Compare

Where glot differs from hosted translation platforms and other developer-first tools.

FeatureglotLokaliseCrowdinLingo.devTolgee
PriceFree (MIT) + your LLM usageFrom $149/mo, 14-day trialPaid plans after a 14-day trial, free for open sourceFree CLI with your own key, hosted engine $0 base + usageFree tier and free self-host, cloud from €58/mo
Open source
Bring your own LLM key
Deterministic validation of every string
Git as source of truth (lockfile)
MCP server for coding agents
In-context editing in your app
Rendered pixel-budget fitting

Checked against each vendor's public website and docs on October 18, 2026. Partial means limited, plan-dependent or through an integration. No means we found no such feature in public docs. Plans change: every cell is linked to its source.

Sources and dates for every cell

What does it cost?

glot is MIT and free. You pay your LLM provider with your own key: 850 strings cost $0.035 with the default model in our run. glot translate --dry-run estimates first, and a budget caps it.

Does it add a runtime dependency?

No. Your app keeps next-intl, i18next or FormatJS with plain JSON catalogs. glot works on the files, in your repo and in CI.

What if the model keeps getting a string wrong?

glot sends the exact reason back and retries twice, then tries the fallback model. If it still fails, nothing is written: the key is reported as rejected and stays untranslated.

Does my code leave my machine?

The strings to translate and their context go to your LLM provider. Not your source files. Nothing goes to glot's authors; there is no telemetry.

Do I need the web app?

No. The CLI and the MCP server do the whole job locally. The app adds a shared dashboard, review and GitHub sync for teams.

Ship every language with every release.

One command in your repo. Nothing broken reaches your catalogs.

Read the quickstart