v1.0.0-beta.3 · MIT · no account

Localization you run yourself.

A free, open-source alternative to Lingo.dev. Edit your source strings, run rosetta push, and every locale gets the new and changed strings, translated with your own LLM key and validated before anything is written.

Get started

Paste it into Claude Code, Cursor, Codex, or opencode from your project root.

~/acme

Why Rosetta

No daily token cap

Rosetta sends requests straight to your model provider, so the only limits are your provider's. Translate a whole site in one run.

No platform fee, no subscription

There's no base price, no per-engine charge, and no markup per million tokens. You pay your LLM provider for the tokens you use, and nothing else.

Any model, your key

OpenRouter by default, or any OpenAI-compatible endpoint: OpenAI, a gateway, or Ollama on your own machine. Switch models with one line of config.

Everything lives in your repo

Config, lockfile, brand voice, and glossary are plain files in .rosetta/. Translations are reviewable diffs with git history, not rows in a dashboard.

Built for coding agents

--json on every command, stable exit codes, no prompts in CI, and a skill your agent can install. "Add a German string for this" just works.

Open source, MIT

Read it, fork it, run it anywhere. No account to create, nothing to cancel, and no vendor between you and your translations.

The math

Lingo.dev's published plans next to Rosetta. With Rosetta you still pay for tokens, but directly to your model provider, with no cap and no markup.

Lingo.dev SandboxLingo.dev ProductionRosetta
Monthly base price$0$99$0
Throughput100K tokens / day5M tokens / dayYour provider's limits
LLM tokensPassed throughPassed throughPaid to your provider
Platform fee$2 / million tokens$2 / million tokensNone
Engines$0.50 / engine / month$0.50 / engine / monthFree (it's a config file)
Bring your own model keyEnterprise onlyEnterprise onlyAlways
Where your config livesTheir platformTheir platformYour repo

Lingo.dev figures are from lingo.dev/pricing as of September 2026. Enterprise pricing is custom.

Get started

Works with any JSON/JSONC locale files (next-intl, i18next, vue-i18n, …) and Node 20+. Hand it to your coding agent, or set it up yourself in a few minutes.

Paste this into Claude Code, Cursor, Codex, or opencode from your project root. Your agent reads the Rosetta skill and does the whole setup, then opens one PR for you to review.

Set up Rosetta (npm: rosetta-i18n) for translations in this repo. Follow https://raw.githubusercontent.com/ian/rosetta/main/skills/rosetta/SKILL.md step by step: discover our locale files and current translation setup and report back, configure .rosetta/config.json, adopt our existing translations with `rosetta status` + `rosetta push` (list any translations it flags as broken), add tests and CI, remove the old translation tooling, document the workflow in AGENTS.md, and open one PR. Ask me before running `push --force`, before any large translation run, and before choosing how translations land if it's unclear.

What your agent will do

  1. Discover. Finds your i18n runtime, locale files, locale list, and current translation setup, then reports back.
  2. Configure. Writes .rosetta/config.json and carries over your brand voice, context, and do-not-translate terms.
  3. Adopt. Records your existing translations for free, and lists any that are broken today.
  4. Guard. Adds tests that keep the config in sync with your app's locale list.
  5. Wire up CI. Keeps your existing flow, or proposes check, commit, or PR mode.
  6. Clean up. Removes the old tooling, documents the workflow in AGENTS.md, and opens one PR.

It asks before anything expensive: push --force, large translation runs, or choosing how translations land.

Keep your agent fluent

Install the Rosetta skill so everyday requests ("add a German string", "why is the i18n job red?") just work. For agents that can't fetch URLs, use the self-contained prompt.

# Claude Code (other agents: see docs/agent-prompt.md)
mkdir -p .claude/skills/rosetta && curl -fsSL https://raw.githubusercontent.com/ian/rosetta/main/skills/rosetta/SKILL.md -o .claude/skills/rosetta/SKILL.md

How it works

Rosetta keeps a lockfile, .rosetta/lock.json, that records a fingerprint of the source string behind every translation. On each push, every key is translated, retranslated, kept, adopted, copied, or removed, and nothing else is touched.

Only changed strings cost tokens

The lockfile records the source text behind every translation. Edit one string and only that string is retranslated, in every locale.

Existing translations adopted free

Switching from another tool? The first push records what you already have without calling a model.

Broken translations caught

Dropped {placeholders}, mangled ICU plurals, and broken <tags> are flagged and retranslated, including ones already in your files.

Never a partial file

A locale with a key that still fails after retries isn't written, and the error is reported. Every other locale still lands.

Key controls

lockedKeys copy URLs and prices verbatim, preservedKeys protect reviewed copy, and ignoredKeys keep internal strings out of targets.

Brand voice, rules, glossary

Per-locale voice (inline or in Markdown files), linguistic rules, exact term renderings, and a never-translate list.

Questions

Is there a hosted version or an account?

No. Rosetta is a CLI and a library. It runs on your machine or CI runner and talks directly to your model provider. The only credential is that provider's API key.

What does it cost to run?

Only your model provider's tokens, and only for new, changed, or broken strings. Run rosetta push --estimate to see key counts and a token estimate before anything is sent.

Which file formats are supported?

JSON and JSONC today: next-intl, i18next, vue-i18n, and any key-value catalog. In JSONC files, comments become translator notes. Markdown/MDX is next (#1).

Which models work?

Any chat model behind an OpenAI-compatible endpoint. Rosetta asks for JSON output, strips code fences, and validates every value, so most instruction-following models do fine.

I'm on Lingo.dev. How do I move over?

Run rosetta init --from-lingo. It imports .lingo/config.json (or the legacy i18n.json), and the first push adopts your existing translations for free. The vocabulary is the same: lockedKeys, push --key, check, purge. See the migration guide.

How do translations get into my repo?

However you like: run push locally or from an agent, gate PRs with check, or let the GitHub Action commit or open a rolling PR after merges. See CI & delivery.

Is it production-ready?

It's in beta (v1.0.0-beta.3). The spec is stable, and it's covered by tests and a CI end-to-end run of the GitHub Action. Pin the version, and please open issues.

Try it on your project

One prompt, one PR. Or three commands, if you'd rather do it yourself.

View on GitHub