replexica new-compiler 翻译 API 实战指南:Translator 接口、批处理翻译与 Server Components 集成
【免费下载链接】replexicaOpen-source localization engineering tools. Connects to Lingo.dev localization engineering platform for consistent, quality translations.项目地址: https://gitcode.com/GitHub_Trending/re/replexica
本篇指南基于 replexica 仓库中packages/new-compiler(即@lingo.dev/compiler)的翻译模块使用文档展开,系统讲解重构后的Translator接口模型:如何使用PseudoTranslator做免 API 的伪本地化测试、如何用LingoTranslator接入 Lingo.dev 引擎或自定义 LLM 提供商完成真实 AI 翻译、如何为任意翻译器叠加磁盘缓存,以及在 React Server Components 中通过预加载、运行时翻译和开发翻译服务器三种方式消费翻译结果。读完本文,你将掌握这套统一翻译 API 的完整调用链、配置细节与源码级实现原理,能够直接在自己的 Next.js/React 项目中落地。
一、统一的Translator接口:重构后的核心抽象
翻译模块重构后,所有翻译组件(伪翻译器、AI 翻译器、自定义翻译器)都遵循同一个接口契约。该接口定义在 api.ts 中:
export type TranslatableEntry = { text: string; context: Record<string, any> }; export interface Translator<Config> { config: Config; translate: ( locale: LocaleCode, entriesMap: Record<string, TranslatableEntry>, ) => Promise<Record<string, string>>; }接口有三个要点:
- 泛型
Config:每个翻译器持有自己的配置对象,通过只读属性config暴露。LingoTranslator的配置是LingoTranslatorConfig(包含models、sourceLocale、prompt、aiTimeout),PseudoTranslator的配置是PseudoTranslatorConfig(包含delayMedian)。 - 批处理能力:
translate()接收Record<string, TranslatableEntry>——即"hash → 可翻译条目"的映射,一次调用可以翻译一条或多条。TranslatableEntry由text(原文)和context(上下文元数据)组成。 - 扁平返回:返回
Record<string, string>,即"hash → 译文"的映射,调用方可以按 hash 直接取译文,无需遍历嵌套结构。
与Translator接口配套的还有两个核心类型:DictionarySchema(翻译字典的扁平结构,含version、locale、entries字段)和PartialTranslationError。后者用于部分失败场景——当一次翻译运行中途失败时,会把已经成功返回的条目随异常一并带出,避免下次构建重新为相同源文本付费(见 api.ts 中的注释说明)。
所有公共类型与实现都从 index.ts 统一导出:
// Core API export type { Translator, TranslatableEntry } from "./api"; // Translators export { PseudoTranslator } from "./pseudotranslator"; export { LingoTranslator } from "./lingo"; export type { LingoTranslatorConfig } from "./lingo"; // Translation Service (orchestrator) export { TranslationService } from "./translation-service"; // Cache abstractions export type { TranslationCache, LocalCacheConfig } from "./cache"; export { createCache } from "./cache-factory";二、PseudoTranslator:零成本伪本地化测试
在开发与测试阶段,如果不想消耗真实翻译 API 的配额,可以使用伪翻译器。文档给出的用法如下:
import { PseudoTranslator } from "@lingo.dev/compiler-beta/translate"; const translator = new PseudoTranslator({}); // 单条翻译 const result = await translator.translate("es", { temp: { text: "Hello World", context: {} }, }); // 输出: { temp: "es/Ĥéĺĺó Ŵóŕĺḍ " } // 多条翻译 const batch = await translator.translate("fr", { hash1: { text: "Dashboard", context: {} }, hash2: { text: "Settings", context: {} }, }); // 输出: { hash1: "fr/Ḍáśĥḅóáŕḍ ", hash2: "fr/Śéţţíñĝś " }从源码实现看,pseudotranslator/index.ts 的机制非常精巧:
- 字符映射替换:内置
PSEUDO_MAP将每个 ASCII 字母映射为带变音符的字母(如H→Ĥ、e→é),模拟真实语言的字符扩展。 - 长度膨胀约 30%:输出末尾追加
Math.ceil(text.length * 0.3)个空格,用于测试界面布局在长文本下的表现,这正是伪本地化(pseudolocalization)的核心价值——提前暴露文本截断、换行错乱等 i18n 布局问题。 - 占位符与组件标签保护:正则
/(\{\w+}|<\/?\w+\/?>)/g匹配{varName}形式的变量占位符和<a0>、</a0>形式的组件标签,这些片段原样保留、不做字符替换,确保伪翻译不会破坏插值语法。 - 可选延迟模拟:
PseudoTranslatorConfig.delayMedian可配置中位延迟,实现会在median ± 50%区间内随机生成延迟(delayMedian: 0时不延迟),用于模拟真实 API 的响应节奏。
输出格式为${locale}/${pseudolocalize(text)},前缀带上目标语言代码,方便肉眼识别"这条字符串来自哪个语言的伪翻译"。
三、LingoTranslator:真实 AI 翻译的生产级翻译器
生产环境使用LingoTranslator。文档提供了两种配置形态:
import { lingoTranslator } from "@lingo.dev/compiler-beta/translate"; // 使用 Lingo.dev Engine const translator = new lingoTranslator({ models: "lingo.dev", sourceLocale: "en", }); // 使用自定义 LLM 提供商 const customTranslator = new lingoTranslator({ models: { "en:es": "google:gemini-2.0-flash", "en:fr": "groq:llama3-70b-8192", "*:*": "openrouter:anthropic/claude-3.5-sonnet", }, sourceLocale: "en", prompt: "Translate professionally for software UI", }); // 翻译 const result = await translator.translate("es", { hash1: { text: "Welcome", context: {} }, hash2: { text: "Sign In", context: {} }, });注意:文档中示例写作lingoTranslator,当前源码中的实际类名是LingoTranslator(见 lingo/translator.ts),两者是同一实现的命名变体,以你当前安装的包版本导出为准。
3.1 两种 models 模式
LingoTranslatorConfig.models支持两种取值(lingo/translator.ts):
"lingo.dev":走 Lingo.dev 引擎,通过LingoDotDevEngine.localizeObject()完成翻译,适合不想自己管理 LLM 提供商与提示词的场景。Record<string, string>:按"语言对 → provider:model"映射指定模型,例如"en:es": "google:gemini-2.0-flash"表示从英文翻译到西班牙文时使用 Gemini。
3.2 语言对模型的匹配优先级
当使用映射模式时,model-factory.ts 中的getLocaleModel()会按以下优先级匹配模型:
${sourceLocale}:${targetLocale}(精确语言对,如en:es)*:${targetLocale}(任意源语言 → 指定目标语言)${sourceLocale}:*(指定源语言 → 任意目标语言)*:*(兜底,任意语言对)
模型字符串格式为provider:model,解析时只在第一个冒号处切分,因此模型名内部可以包含冒号(parseModelString的实现,见 model-factory.ts)。
3.3 底层翻译流程
LingoTranslator.translate()的完整调用链体现了生产级设计的几个关键环节(lingo/translator.ts):
- 字典化:先把
entriesMap转成DictionarySchema(dictionaryFrom()构造,version字段当前固定为 0.1,源码注释中标注了后续与 hash 函数版本联动的计划)。 - 分块(chunking):
chunkDictionary()按每块最多100 条拆分字典,避免单次请求上下文过大。 - 逐块翻译:每个 chunk 单独调用 LLM,翻译完成后再由
mergeDictionaries()合并。 - 部分失败保护:若中途抛错,
translateDictionary()会抛出携带已译条目的PartialTranslationError,上层(如TranslationService)可据此保留已付费的翻译结果。 - 超时兜底:所有 AI 调用都包在
withTimeout()中,超时上限取config.aiTimeout ?? DEFAULT_TIMEOUTS.AI_API,防止模型无响应导致构建无限挂起。
LLM 分支的具体请求构造(lingo/translator.ts)值得注意:系统提示词由getSystemPrompt()生成(包含sourceLocale、targetLocale和自定义prompt),随后注入若干组 few-shot 示例(shots.flatMap生成 user/assistant 交替消息),最后把源字典经obj2xml()序列化为 XML 作为用户消息;响应文本再由parseXmlFromResponseText()解析回DictionarySchema。也就是说,翻译请求与响应都通过 XML 结构在模型与代码之间传递。
四、缓存:createCache与磁盘缓存实现
文档中"Adding Caching"一节展示的是用createCachedTranslator包装翻译器:
import { lingoTranslator, createCachedTranslator, } from "@lingo.dev/compiler-beta/translate"; const translator = new lingoTranslator({ models: "lingo.dev", sourceLocale: "en", }); // 添加磁盘缓存 const cachedTranslator = createCachedTranslator(translator, { cacheDir: ".lingo", sourceRoot: "./app", }); // 第一次调用触发真实翻译 await cachedTranslator.translate("es", entriesMap); // 第二次调用直接命中缓存,速度极快 await cachedTranslator.translate("es", entriesMap);在当前的编译器源码中,缓存抽象对应的是TranslationCache接口与createCache工厂(cache.ts、cache-factory.ts)。TranslationCache接口定义了完整的生命周期方法:
get(locale)/get(locale, hashes):按语言取缓存,可只取指定 hash 子集;update(locale, translations):合并式更新(不覆盖已有内容);set(locale, translations):整体替换;has(locale)/clear(locale)/clearAll():存在性检查与清理。
默认且当前唯一支持的实现是LocalTranslationCache(local-cache.ts):
- 存储位置:
<cacheDir>/<locale>.json,即文档与 README 中描述的.lingo/cache/{locale}.json; - 写入格式:
dictionaryFrom(locale, translations)序列化的 JSON(含version、locale、entries),格式化为两空格缩进便于人工检查; - IO 超时:所有文件读写都包在
withTimeout(..., DEFAULT_TIMEOUTS.FILE_IO)中,防止文件系统卡死; - 目录自动创建:写入前
fs.mkdir(cacheDir, { recursive: true }),无需手动建目录。
4.1 缓存与翻译的自动编排:TranslationService
如果你希望缓存判断、覆盖值(overrides)、复数处理与翻译失败恢复由框架自动完成,可以使用TranslationService(translation-service.ts)。它的translate()编排了完整的 8 步流程:
- 确定工作 hash 集(默认取 metadata 的全部键);
- 先查缓存,得到已缓存译文;
- 过滤出未缓存的 hash;
- 从 metadata 中筛选未缓存条目;
- 若配置了
pluralization,先对未缓存条目做复数处理; - 分离出带
overrides[locale]覆盖值的条目(直接采用,不翻译); - 对真正需要翻译的条目调用底层
translator.translate(),源语言则直接返回sourceText; - 合并缓存与新增译文、写入缓存、汇总
stats(total/cached/translated/failed)与逐条errors。
TranslationService还内置了开发模式回退策略:当environment === "development"且dev.usePseudotranslator开启时直接用内存缓存的伪翻译器;若真实翻译器创建失败(如缺少 API Key),开发模式自动回退到PseudoTranslator并告警,生产模式则直接抛错——这保证了开发流程永远不会被缺 Key 卡死。
五、在 React Server Components 中使用
文档给出了三种在 Server Components 中消费翻译的选项,三者都通过getServerTranslations(实现见 server-only/index.ts)获得t函数。
选项 1:预加载翻译(推荐)
构建期把metadata.json与各语言缓存文件随包导入,运行时零网络调用:
import { getServerTranslations } from "@lingo.dev/compiler-beta/react/server"; import metadata from "./.lingo/metadata.json"; import esTranslations from "./.lingo/cache/es.json"; export default async function Page() { const t = await getServerTranslations({ metadata, locale: "es", sourceLocale: "en", translations: extractTranslations(esTranslations), // 扁平 hash -> 译文映射 }); return <h1>{t("hash123")}</h1>; }选项 2:使用 Translator(运行时按需翻译)
把缓存包装后的翻译器传给getServerTranslations,未命中缓存的 hash 会在运行时实时翻译:
import { getServerTranslations } from "@lingo.dev/compiler-beta/react/server"; import { lingoTranslator, createCachedTranslator } from "@lingo.dev/compiler-beta/translate"; import metadata from "./.lingo/metadata.json"; const translator = createCachedTranslator( new lingoTranslator({ models: "lingo.dev", sourceLocale: "en", }), { cacheDir: ".lingo", sourceRoot: "./app", } ); export default async function Page() { const t = await getServerTranslations({ metadata, locale: "es", sourceLocale: "en", translator, // 按需翻译 }); return <h1>{t("hash123")}</h1>; }选项 3:翻译服务器(开发模式)
只传 metadata 与语言,由开发期的 Translation Server 提供翻译,组件代码最简洁:
import { getServerTranslations } from "@lingo.dev/compiler-beta/react/server"; import metadata from "./.lingo/metadata.json"; export default async function Page() { const t = await getServerTranslations({ metadata, locale: "es", sourceLocale: "en", }); return <h1>{t("hash123")}</h1>; }5.1 服务端翻译的底层获取逻辑
从源码看,getServerTranslations不直接调用翻译器,而是委托给 server-only/translations.ts 中的fetchTranslationsOnServer():
- 开发模式:若配置了
serverUrl,优先请求开发翻译服务器(fetchFromDevServer),失败则回退文件系统; - 生产模式(或开发回退):从文件系统读取,依次尝试
.lingo/cache/{locale}.json与.next/{locale}.json两个常见路径,解析出entries作为扁平译文映射; t函数行为:t(hash, sourceText, params?)在translations[hash]缺失时回退到sourceText;传入params时通过renderRichText渲染富文本。
另外注意:Server Components 中还有一个更贴合编译器工作流的useTranslation钩子(server/useTranslation.ts),它利用 React 的use()在不写 async/await的情况下消费 promise,且与客户端版本签名完全一致,实现了组件的同构(isomorphic)——编译器会在构建期把组件内使用的 hash 列表注入进来。
六、编写自定义 Translator
实现Translator接口即可接入整个缓存与编排体系:
import type { Translator, TranslatableEntry, } from "@lingo.dev/compiler-beta/translate"; class MyCustomTranslator implements Translator<MyConfig> { constructor(readonly config: MyConfig) {} async translate( locale: LocaleCode, entriesMap: Record<string, TranslatableEntry>, ): Promise<Record<string, string>> { // 批量翻译多条条目 const results: Record<string, string> = {}; for (const [hash, entry] of Object.entries(entriesMap)) { results[hash] = await myTranslationService(entry.text, locale); } return results; } } // 使用它 const translator = new MyCustomTranslator({ apiKey: "..." }); const cachedTranslator = createCachedTranslator(translator, { cacheDir: ".lingo", });自定义翻译器的三个约束与建议:
- 构造函数持有配置:通过
readonly config保存配置实例,供外部读取与调试; - 保持批处理语义:
translate()必须完整返回entriesMap中所有 key 的译文;若实现为逐条循环(如示例所示),注意这是文档演示写法,生产环境应优先并行或走真实 AI 批处理以控制成本(参考LingoTranslator的 100 条分块策略); - 可组合性:自定义翻译器同样可以被缓存包装器包裹,缓存层与翻译实现完全解耦。
七、从旧 API 迁移
重构前的翻译函数是一个裸的TranslateFunction,把模型、源字典、语言对、提示词全部作为参数传入:
// 重构前(TranslateFunction) const translateFn: TranslateFunction = async ( models, sourceDictionary, sourceLocale, targetLocale, prompt, ) => { // 翻译逻辑 return translatedDictionary; }; const cached = createCachedTranslator(translateFn, cacheConfig);重构后改为实例化翻译器对象,配置内聚到实例中:
// 重构后(Translator 接口) const translator = new lingoTranslator({ models, sourceLocale, prompt, }); const cached = createCachedTranslator(translator, cacheConfig);迁移要点:原来散落的 5 个位置参数收敛为models、sourceLocale、prompt三个配置字段(外加aiTimeout),语言对改为translate(locale, entriesMap)的方法调用形态;缓存包装的输入从函数变成实例,但包装器 API 形态保持一致,迁移成本集中在翻译逻辑的封装方式上。
八、重构收益
文档总结了本次重构带来的六个核心收益,结合源码可以进一步印证:
- 类型安全(Type Safety):
Translator<Config>泛型接口让每个翻译器的配置类型在编译期即被约束,LingoTranslatorConfig、PseudoTranslatorConfig各自独立(lingo/translator.ts、pseudotranslator/index.ts); - 一致性(Consistency):所有翻译器(伪翻译、Lingo.dev、自定义)遵循同一
translate(locale, entriesMap)签名,TranslationService无需感知具体实现即可编排(translation-service.ts); - 可组合性(Composability):翻译器可自由包裹缓存、超时、日志等增强层;
- 状态管理(State Management):配置与翻译逻辑内聚于实例,避免函数式 API 的参数漂移;
- 可测试性(Testing):伪翻译器与内存缓存让测试无需真实 API Key,仓库中 pseudotranslator/index.test.ts、lingo/translator.test.ts、translation-service.test.ts 均以此为基础;
- 统一缓存(Caching):
TranslationCache抽象(磁盘LocalTranslationCache、内存MemoryTranslationCache)对所有翻译器一视同仁,缓存命中逻辑集中在TranslationService一处。
九、环境变量与 API Key
使用LingoTranslator前必须配置对应提供商的 API Key,model-factory.ts 中的providerDetails表完整登记了各提供商的环境变量名:
# 推荐:Lingo.dev 引擎 LINGODOTDEV_API_KEY=your_key_here # 或直接对接 LLM 提供商 GOOGLE_API_KEY=your_key_here GROQ_API_KEY=your_key_here OPENROUTER_API_KEY=your_key_here MISTRAL_API_KEY=your_key_here # 其他受支持提供商 OPENAI_API_KEY=your_key_here ANTHROPIC_API_KEY=your_key_here # Ollama 本地模型无需 API Key几个关键行为值得注意:
- Key 读取顺序:
getKeyFromEnv()先读process.env,再依次尝试从项目根目录的.env、.env.local、.env.development加载(使用 dotenv); - 启动期一次性验证:
LingoTranslator构造函数即调用validateAndGetApiKeys(),按配置解析出所需的全部提供商并校验 Key,缺失时抛出带明确提示的错误;当models: "lingo.dev"时只校验LINGODOTDEV_API_KEY,映射模式则按模型中出现的 provider 集合逐一校验; - OpenAI 兼容端点:通过
OPENAI_BASE_URL可为 OpenAI 提供商自定义 base URL,兼容 Nebius 等第三方 OpenAI 兼容服务; - 未知提供商保护:
validateAndGetApiKeys会对未知 provider 抛出错误并列出受支持的提供商列表。
十、完整示例:缓存翻译器 + RootLayout
把以上全部能力组合成一个可运行的完整示例(文档原文):
// translator.ts import { LingoTranslator, createCachedTranslator, } from "@lingo.dev/compiler-beta/translate"; export const translator = createCachedTranslator( new LingoTranslator({ models: "lingo.dev", sourceLocale: "en", }), { cacheDir: ".lingo", sourceRoot: "./app", } ); // app/layout.tsx import { getServerTranslations } from "@lingo.dev/compiler-beta/react/server"; import { translator } from "./translator"; import metadata from "./.lingo/metadata.json"; export default async function RootLayout({ children }) { const t = await getServerTranslations({ metadata, translator, }); return ( <html> <body> <nav> <a href="/">{t("home_link")}</a> <a href="/about">{t("about_link")}</a> </nav> {children} </body> </html> ); }运行流程拆解:
- 首次渲染时
translator.translate("es", entriesMap)调用 Lingo.dev 引擎翻译,结果写入./app/.lingo/cache/es.json; - 后续渲染或重新构建时,缓存层先命中,翻译请求被跳过(磁盘缓存的合并更新逻辑见 local-cache.ts 的
update()); getServerTranslations在生产模式直接从.lingo/cache/{locale}.json读取(server-only/translations.ts),开发模式则优先走 Translation Server 热更新。
十一、进一步阅读
- 模块导出总览:translators/index.ts 与 translators/README.md(含
translator: "pseudo"的配置式伪翻译、缓存目录结构说明) - 接口与异常定义:translators/api.ts
- 生产翻译器实现:translators/lingo/translator.ts(分块、超时、XML 往返)
- 提供商注册与 Key 校验:translators/lingo/model-factory.ts
- 缓存抽象与实现:translators/cache.ts、translators/local-cache.ts、translators/cache-factory.ts
- 翻译编排器:translators/translation-service.ts
- Server Components 集成:react/server-only/index.ts、react/server/useTranslation.ts、react/server-only/translations.ts
- 包导出配置:new-compiler/package.json(
@lingo.dev/compiler的./react/server、./react/next等条件导出)
说明:文档示例中的
lingoTranslator、createCachedTranslator与当前源码中的LingoTranslator、createCache/TranslationCache为同一抽象的不同命名/封装形态,具体导入名以你使用的@lingo.dev/compiler版本为准;Translator接口本身(config+translate(locale, entriesMap))是各版本一致的核心契约。
【免费下载链接】replexicaOpen-source localization engineering tools. Connects to Lingo.dev localization engineering platform for consistent, quality translations.项目地址: https://gitcode.com/GitHub_Trending/re/replexica
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考