跳到正文
原文
OpenRouter:Blog(Announcements)·· 16 小时前精选AI 评分71

OpenRouter 如何搭建可自我纠错的本地化系统并上线 8 种语言

How We Built a Self-Correcting Localization System for OpenRouter

文章要点
  • 1OpenRouter 上线简体中文等 7 种外语版本,本地化功能即日起进入 beta
  • 2系统每日用 GPT-6.1 Sol 翻译变更文案,同一模型二次校验,未通过则附原因自动重试
  • 3官方称全站 16,918 条字符串译成 7 种语言约 $460,约为 Smartling 机翻标价的 6%
  • 4454 例对比中规则类错误从 147 降到 4,三个外部模型判定严重错误从 203 降到 109
决策要点

本地化流水线的实质变化在质检而非翻译,代码校验加模型互审让整站翻译成本降到供应商机翻标价的约 6%(官方口径)。

  • 影响:出海或多语言产品的本地化预算量级可重算,整站翻译从供应商数万美元级报价进入数百美元级;人工从翻译转向合并与复核残余错误,仍有漏检错误会直接上线,需预留用户反馈渠道。
  • 参考:可考虑复用其四条设计,即给译文存指纹、代码先拦截占位符与术语错误、校验模型回传具体错误、把人工发现的错误沉淀为术语规则或测试用例;值得先按自家文案词量乘以约 $0.0005 每词测算预算,再与供应商标价对比。
  • 依据:成本、准确率与 6% 对比均为 OpenRouter 官方口径,暂无独立验证;严重错误数由 Claude Opus 5.5、Gemini 4 Argon、DeepSeek V4 Pro 三个模型分别判定,供应商价格为公开标价。
正文

The OpenRouter homepage in Japanese.

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.

The OpenRouter models page in Korean, with filters, tabs, and model metadata translated.

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.

How a string gets translated: new text goes to a translator model, then code checks, then a verifier model, then review, then live. Failed checks and verifier rejections go back to the translator, and fixes flagged by reviewers or readers go into the glossary.

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.

MeasureBare modelFull pipeline
Failed a glossary or authored check147 of 4534 of 454
Accepted by the verifier on the first pass263 of the 306 that passed checks (85.9%)448 of all 454 (98.7%)
Critical errors, summed across three judges from other model families203109
Pairs each side won on overall preference117139
Meaning survived back-translation90.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.

Highlighted text on the Japanese homepage with the popover for sending feedback on it.

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.

OptionRateFull site, 7 languages
Our pipeline, translation and verificationabout $0.0005 per wordabout $460
Smartling Machine Translation$0.0075 per wordabout $7,200
Smartling AI Translation$0.06 per wordabout $57,300
Gengo Standard$0.09 per wordabout $86,000
Smartling AI Human Translation$0.12 per wordabout $114,600
Gengo Advanced$0.18 per wordabout $171,900
Smartling Human Translation$0.20 per wordabout $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:Blog(Announcements) · openrouter.ai