OpenRouter 如何搭建自校正本地化系统
How We Built a Self-Correcting Localization System for OpenRouter
OpenRouter 上线简体中文、西班牙语、葡萄牙语(巴西)、德语、法语、日语和韩语共 7 种语言,本地化处于 beta 阶段。其流水线每天扫描变更字符串,用 GPT-6.1 Sol 分批翻译,再由代码校验占位符与术语、同一模型二次核验语义,失败则带原因重试,最终以 pull request 形式由人合并。

OpenRouter now speaks 简体中文, Español, Português (Brasil), Deutsch, Français, 日本語, and 한국어, alongside English. Localization is in beta, starting today. To switch, pick a language from the account menu, or go straight to an address like openrouter.ai/ja or openrouter.ai/ko/models.

Translating a website and keeping that translation up-to-date is hard, especially true for us. OpenRouter’s site has 16,918 English strings, and we change some of them every day, so a one-time translation would be out of date within a week. We built a loop to help us do this at scale. Every day, it finds the strings that changed, translates them, checks them in code, and has a second model verify the meaning against the English. When a translation fails a check, or the verifier rejects it, the loop sends it back with the reason attached and tries again. That retry loop is the part of the system that corrects itself.
Some mistakes still get past it, and people catch those. When reviewers and readers report a mistake, we turn it into a glossary rule, a style note, or an override, and mistakes the daily review catches also become test cases that every future model has to pass. The whole pipeline runs on OpenRouter.
Translations live in Git next to the code
Before any model gets involved, the translations need a home. We use the open-source General Translation runtime to wrap strings in our React code. We commit translations as JSON catalogs next to the code and load them locally at runtime, so no translation service sits in the request path. A string gets picked up for translation within a day of it merging. Until then, the page shows the English source. Each translated entry also stores a fingerprint of the English it came from. When someone edits the English, the fingerprint stops matching, and the entry goes back in the queue. This rule lets the daily run find every stale entry without retranslating the whole catalog.
The pipeline
Every string in that queue goes through five stages before it reaches the site.

A script scans the frontend and writes every wrapped English string to a source catalog. Each entry records its file and its UI role, such as button, heading, or table header. The role matters because the same English word can need a different translation in a different place. “Queue” on a button is an instruction, and one of the defects later in this post is a model translating it as a noun.
2. Translate
We send new and changed strings to GPT-6.1 Sol in batches of up to 40, and use Structured Outputs to hold the reply to a strict JSON schema. Each request carries our global and per-language style notes, the glossary rules for any product term in the batch, and the UI role of each string.
Here is a simplified example of a translator request for one Japanese batch, with the style notes and glossary rules cut short.
{
"model": "openai/gpt-6.1-sol",
"messages": [
{
"role": "system",
"content": "Translate OpenRouter UI strings into Japanese. ..."
},
{
"role": "user",
"content": "[{\"id\":\"q1\",\"role\":\"button\",\"text\":\"Queue\"}]"
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "translations",
"strict": true,
"schema": {
"type": "object",
"properties": {
"translations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"text": { "type": "string" }
},
"required": ["id", "text"],
"additionalProperties": false
}
}
},
"required": ["translations"],
"additionalProperties": false
}
}
}
}Because every model on OpenRouter takes the same request, trying a different translator means changing only the model slug. That is how we ran the model comparison later in this post.
3. Check
Code rejects a reply that breaks an ICU placeholder, a plural branch, a rich-text tag, or leading or trailing whitespace, or that renders a product term in a form the glossary forbids. We resend a rejected batch in smaller pieces, naming the failure, for up to 4 passes by default. The limit is a setting that goes up to 20. A string that still fails after the last pass stays in English and is flagged in the pull request.
4. Verify
A second call to the same model, acting as verifier, reads each translation against the English and lists errors by severity. Any critical or major error, such as a dropped clause or a reversed meaning, sends the string back to the translator with every objection so far attached. The translator gets up to 3 retries after its first attempt, and the last retry uses more reasoning effort. Spend per string has no separate cap, because the retry limits already bound it. Counting the check resends, a string can take up to four translation attempts with up to four check passes each, plus a verifier call after each attempt. That puts the worst case at about 20 model calls per string per language. If the verifier is down, the pipeline writes nothing and the string stays in English. A reader who sees English for a day is better off than one who sees an unchecked translation.
5. Review
Each daily batch lands as a pull request. An AI reviewer reads the diff and posts findings, and a person merges the pull request.
How we measure
The rest of this post leans on three eval suites, so it helps to know what each one tests before the numbers start.
- The model comparison (254 cases) runs the pipeline with different translator models and scores each reply with the production verifier. We used it to choose the translator.
- The pipeline comparison (454 cases) runs one model twice, once through the full pipeline and once with a bare two-line prompt. Code checks, the verifier, judges from three other model families, and a back-translation check all score it.
- The defects suite (22 cases) holds real mistakes the daily review caught after the verifier passed them. Each case forbids the mistake that shipped.
What we tried and threw away
The pipeline looks simple now because we removed three parts of the first design once the evals measured them.
A cheaper translator
We first tested a smaller, cheaper model, GPT-6 Luna (openai/gpt-6-luna). In the model comparison, it passed 91.7% of cases on the first try, against 99.2% for GPT-6.1 Sol. Its weakest languages were Korean and Japanese. Its hardest failures were replies that General Translation, our translation framework, couldn’t compile, such as its translation of “Legacy alias of {value}”. Those failures persisted through every retry.
The heavier model cost about 3.4 times as much, $1.94 against $0.57 for those 254 cases. We pay the difference because a wrong string that never converges takes more time and effort to fix than just getting it right off the bat.
A separate judge model
Before the verifier existed, a separate judge model scored every translation, and we retranslated anything it flagged or marked uncertain. To see how well it worked, we labeled a benchmark with three kinds of strings: known errors, corrected translations (hand-fixed versions of earlier errors, which should pass), and a clean sample. The judge did catch real problems. In one benchmark run, it marked 91% of that run’s real defects as uncertain. It also flagged 11 of the 14 corrected translations and 42 of the 150 clean ones, so it sent a lot of good work back for retranslation.
With the verifier in place, turning the judge off lowered first-pass accuracy from 99.2% to 98.8% and left the final result unchanged. The judge had been sending about 45% of first drafts back for retranslation. We now leave it off by default.
Leaving hard strings for a person
At first, a string the verifier rejected on every retry stayed untranslated until someone fixed it by hand. A full retranslation of the catalog, 16,274 strings into 7 languages, left 97 such strings (0.09%). Now the pipeline ranks the rejected drafts by the verifier’s findings, commits the least-wrong one, and flags it in the pull request for review. The loop always ends in a translation, even when that translation still carries a flagged error, and the flag puts it in front of the person who merges the pull request.
What the pipeline adds over the bare model
Most of what the pipeline adds is fewer outright mistakes. To measure it, our eval runs the same model over 454 cases twice, once through the full pipeline and once with a two-line prompt and no style notes, glossary, or retries. The bare model returned one malformed reply, which leaves 453 pairs to compare.
| Measure | Bare model | Full pipeline |
|---|---|---|
| Failed a glossary or authored check | 147 of 453 | 4 of 454 |
| Accepted by the verifier on the first pass | 263 of the 306 that passed checks (85.9%) | 448 of all 454 (98.7%) |
| Critical errors, summed across three judges from other model families | 203 | 109 |
| Pairs each side won on overall preference | 117 | 139 |
| Meaning survived back-translation | 90.8% | 89.3% |
An authored check is a handwritten rule on one eval case. For example, “Queue” in Chinese must not be translated as 队列, the noun form that shipped. The check failures fell from 147 to 4, which is the glossary and the retries doing their job.
The verifier’s first-pass figures use different bases. For the bare model it’s the 306 strings that passed the code checks, and for the pipeline it’s all 454. The verifier comes from the same model family as the translator, so its pass rate tells us how often the model agrees with itself. We use GPT-6.1 Sol for both jobs because it was the more accurate of the two translators we tested. For an outside view, the eval also sends each pair of translations, unlabeled, to three judges from other model families, Claude Opus 5.5, Gemini 4 Argon, and DeepSeek V4 Pro. Across the three judges, they found 109 critical errors in the pipeline’s output and 203 in the bare model’s. Each judge’s errors count separately, so a string that all three judges flag adds three to the total.
On overall preference across the 453 pairs, the judges picked the pipeline in 139 and the bare model in 117, with 61 ties and 136 pairs where the two translations were identical. That margin is much narrower than the check failures and critical errors show, so the pipeline’s value sits mostly in the specific mistakes it removes.
The last row back-translates every reply to English and asks whether the meaning survived. It scored the bare model 90.8% and the pipeline 89.3%. Back-translation cannot see terminology or register, which is most of what the pipeline changes, so we read this result as a tie.
The feedback loop
The verifier catches most errors before they ship, and readers catch some of the rest.

Turn on select-to-report in the Language dialog, then highlight any translated text, add a note, and send it. Each report arrives with the language, the page, and the exact text. A model triages it first, picks one of four fixes, and puts the fix up within minutes. Our AI reviewer checks the fix, and a person does the final merge.
- Wrong meaning. The string reverts to English the same day, then gets a corrected translation.
- Wrong term. We add the term to the glossary with the accepted form and the forms to reject for that language. We pin compliance and protocol names such as HIPAA, SOC 2, OAuth, and SAML so the pipeline leaves them in English.
- Wrong tone or punctuation. The rule goes into that language’s style notes.
- One bad string. An exact override pins the approved wording, and no later run can change it.
Mistakes the daily review catches after the verifier passed them go into the defects suite. It has 22 cases so far. They include “Queue” translated as a noun on a button that needed a verb, “shadow traffic” rendered as road traffic, and a HIPAA setting whose meaning was inverted. Each case forbids the mistake that shipped, so any future model, prompt, or glossary change that brings it back fails the eval.
What it costs
When we first priced it, a full retranslation of all 16,274 strings into 7 languages, 113,918 translations in total, came to about $430 with translation and verification included. We arrived at that figure by pricing production-sized batches in each language and scaling up. It works out to under half a cent per string per language. Verification is slightly more than half, about $228, or $0.002 per string per language. The catalog has since grown to 16,918 strings, and a full retranslation of it today costs about $460. The daily loop only sends what changed, and a day with 677 changed strings across 7 languages costs roughly $18.
Both figures cover the translation and verification calls only. They leave out the engineering time to build the pipeline, the calls made by the AI reviewer and the triage model, and the person who merges each daily pull request.
Today’s 16,918 strings hold 136,429 words of English, so 7 languages total 955,003 words, which puts our cost at about $0.0005 per word. Here is the same full retranslation at the per-word starting rates Smartling and Gengo publish, as of November 10, 2026.
| Option | Rate | Full site, 7 languages |
|---|---|---|
| Our pipeline, translation and verification | about $0.0005 per word | about $460 |
| Smartling Machine Translation | $0.0075 per word | about $7,200 |
| Smartling AI Translation | $0.06 per word | about $57,300 |
| Gengo Standard | $0.09 per word | about $86,000 |
| Smartling AI Human Translation | $0.12 per word | about $114,600 |
| Gengo Advanced | $0.18 per word | about $171,900 |
| Smartling Human Translation | $0.20 per word | about $191,000 |
These are list prices; enterprise contracts are negotiated, and every row above machine translation includes human review or project management that our figure leaves out. The closest like-for-like option is Smartling’s machine translation, and our pipeline costs about 6% as much.
What you can reuse
If you are localizing your own product, four parts of this design carry over directly.
- Fingerprint every translation against its English source, so stale entries requeue themselves.
- Let code reject broken placeholders, plural branches, tags, and forbidden terms before any model reviews the meaning.
- Use a verifier that names each error and its severity, and send those objections back to the translator.
- Turn every mistake a person catches into a glossary rule, a style note, an override, or an eval case.
Send us your feedback
Some wording will be off while we’re in beta, and the quickest way to fix it is to report it with select-to-report in the Language dialog. We review every report and turn it into a glossary rule, a style note, or an override.
Frequently asked questions
Which languages does OpenRouter support?
OpenRouter is available in English, Simplified Chinese, Spanish, Brazilian Portuguese, German, French, Japanese, and Korean. Localization is in beta.
How do I change the language on OpenRouter?
Pick a language from the account menu, or open a localized address such as openrouter.ai/ja.
Which models translate OpenRouter?
GPT-6.1 Sol (openai/gpt-6.1-sol) translates each string, and a second call to the same model verifies it against the English. Both run through the OpenRouter API.
How much does it cost to translate the whole site?
A full retranslation of today's 16,918 strings into 7 languages costs about $460, translation and verification included, which is under half a cent per string per language. The same job costs about $7,200 at Smartling's published machine translation rate and about $57,300 to $191,000 at published AI and human translation rates.
How do I report a bad translation?
Turn on select-to-report in the Language dialog, highlight the text that reads wrong, add a note, and submit it.
来源:OpenRouter Announcements · openrouter.ai