Translation Server 深度解析:开发与构建期按需翻译的 HTTP + WebSocket 本地服务)
ReplexicaLingo.dev 编译器Translation Server 深度解析开发与构建期按需翻译的 HTTP WebSocket 本地服务【免费下载链接】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包的 Translation Server 展开讲解其在开发与构建阶段如何通过本地 HTTP 端点按需生成翻译、利用 WebSocket 向开发控件实时推送进度以及磁盘缓存、端口探测、服务器复用等关键机制。读完本文你将掌握该翻译服务器的完整 API、三种翻译提供者Lingo.dev Engine / 自定义 LLM / 伪翻译器的配置方式、CLI 手动启动与调试方法并能从源码层面理解其工作流程与缓存策略。概述为什么需要一个本地翻译服务器在 Lingo.dev 的编译器架构中翻译服务器承担开发/构建期按需生成翻译的职责当 Vite、Webpack、Next.js 等打包器插件启动开发服务时会自动拉起一个本地的 Translation Server通过 HTTP 接口对外提供翻译能力并把翻译结果缓存到磁盘避免重复调用 AI 模型。项目描述中 Replexica 定位为开源本地化工程工具其编译器packages/new-compiler中的 Translation Server 是连接开发环境与翻译后端Lingo.dev 平台或各类 LLM Provider的关键中间层。从模块目录可以看到它的完整组成translation-server/ ├── translation-server.ts # 主 HTTP WebSocket 服务器实现 ├── cli.ts # 独立 CLI可手动启动服务器 ├── logger.ts # 服务器专用日志工具写文件 ├── ws-events.ts # WebSocket 事件类型定义 ├── translation-server.test.ts # stableStringify / hashConfig 单元测试 ├── index.ts # 模块统一出口 └── README.md三大关键特性自动端口检测从 60000或配置的起始端口开始向上探测可用端口最多尝试 100 个见 findAvailablePort服务器复用若目标端口已有运行中的翻译服务器且配置哈希一致则直接复用而非另起新进程见 startOrGetUrl实时更新翻译状态变化时通过 WebSocket 向已连接的客户端如开发控件 lingo-dev-widget推送事件。核心设计HTTP WebSocket 双协议服务器请求路由与 CORSTranslationServer基于 Node.js 原生http模块构建translation-server.ts并在同一端口上挂载 WebSocketServer。所有 HTTP 请求首先经过 handleRequest 统一处理CORS 预检服务器面向浏览器请求开放了 CORS响应头包括Access-Control-Allow-Origin: *、GET, POST, OPTIONS方法与Content-Type请求头并对OPTIONS请求直接返回 204源码位置路由分发GET /health→ 健康检查POST /translations/:locale→ 批量翻译GET /translations/:locale→ 全量字典其余路径返回 404且 404 响应体中会列出所有可用端点便于调试兜底错误处理异步处理器抛出异常时若响应头尚未发送则返回 500{ error: Internal Server Error }。WebSocket 事件模型服务器启动成功后会调用 initializeWebSocket 在同一个 HTTP 端口上初始化 WebSocketServer。客户端连接后立即收到connected事件携带serverUrl。全部事件类型定义在 ws-events.ts事件类型载荷字段含义connectedserverUrl连接建立translation:starthash、locale、sourceText单个条目开始翻译translation:completehash、locale、translatedText、duration单个条目翻译完成translation:errorhash、locale、error单个条目翻译失败batch:startlocale、total、hashes批量翻译开始batch:progresslocale、completed、total、percent批量翻译进度batch:completelocale、total、successful、failed、duration批量翻译完成metadata:updatenewEntries、totalEntries元数据更新发现新的可翻译文本cache:updatelocale、entriesCount缓存更新server:busyactiveTranslations服务器进入忙碌状态server:idle—服务器回到空闲状态其中server:busy/server:idle采用500ms 防抖机制常量BUSY_DEBOUNCE_MS 500只有当活跃翻译任务数归零且持续 500ms 后才广播idle避免快速连续的翻译请求造成 busy→idle→busy 抖动源码。所有事件统一由createEvent工厂函数生成自动附带timestamp字段。API 端点详解健康检查GET /health返回服务器状态与配置哈希{ port: http://127.0.0.1:60000, configHash: a1b2c3d4e5f6 }configHash由 hashConfig 生成它先用stableStringify对配置对象做递归规范化剔除函数与undefined值、对象键按字典序排序、数组顺序保留再取 MD5 的前 12 位十六进制。这样相同的语义配置必然得到相同哈希——这正是服务器复用机制能安全判断端口上的进程是不是我们的、配置是否一致的基础。相关行为由 translation-server.test.ts 完整覆盖键序无关、嵌套对象一致、值变化哈希不同等。全量字典GET /translations/:locale返回指定 locale 的全部翻译。该端点会先重新加载磁盘元数据reloadMetadata见 translateAll 中先 reload 再取Object.keys(metadata)的做法确保构建期新发现的条目也被纳入然后触发对缺失条目的翻译。{ locale: es, translations: { abc123: Hola Mundo, def456: Bienvenido }, errors: [] }响应头为Cache-Control: public, max-age3600允许浏览器/客户端缓存字典一小时。批量翻译POST /translations/:locale Content-Type: application/json { hashes: [abc123, def456] }针对指定哈希集合做翻译适用于只补缺失条目的精简请求。请求体必须包含hashes数组否则返回 400{error:Bad Request,message:Body must contain hashes array}。处理流程handleBatchTranslationRequest校验 locale 合法性parseLocaleOrThrow非法 locale 直接抛错读取请求体并 JSON 解析重新加载元数据保证新条目可见调用translationService.translate(locale, metadata, hashes)执行翻译通过startTranslationActivity()/endTranslationActivity()维护 busy/idle 状态返回{ locale, translations, errors }响应头为Cache-Control: no-cache。{ locale: es, translations: { abc123: Hola Mundo, def456: Bienvenido }, errors: [] }请求/响应中的errors数组是部分失败机制的一部分翻译服务会把成功与失败分开返回服务器随后将失败明细hash、sourceText、error逐条写入日志文件见下文服务器日志便于定位个别失败条目而不至于整体失败。启动、端口探测与服务器复用机制两种启动入口startTranslationServer(options)无条件新起一个服务器见 translation-server.tsstartOrGetTranslationServer(options)推荐入口先在首选端口上探测若端口被占则检查是否为我们的服务器并复用startOrGetUrl。startOrGetUrl的完整决策树若当前实例已在运行直接返回现有 URL首选端口空闲 → 直接start()新服务器端口被占 → 请求http://127.0.0.1:port/health2 秒超时返回 200 且configHash一致 →复用configHash不一致旧版本服务器或配置已变更→ 警告并另起新端口非 JSON / 非 200 / 连接失败 → 判定为其他服务占用另起新端口。设计动机在源码注释中说明得很清楚Next.js 的 dev server 可能在多个进程中启动async config 或 loader 各跑一份startOrGetTranslationServer让第一个进程抢占端口、后续进程发现并复用成为原子且自洽的操作避免多开服务器。优雅关闭stop()会依次清除 pending 的 busy 定时器 → 关闭所有 WebSocket 客户端与 WebSocketServer → destroy 所有活跃 HTTP socket → 关闭 HTTP servertranslation-server.ts。CLI 入口为SIGINT/SIGTERM注册了该关闭流程cli.ts。配置三种翻译提供者翻译能力最终由TranslationService提供translation-service.ts服务器通过构造函数注入或按需创建。其提供者选择优先级源码为开发环境且显式开启伪翻译 → 真实翻译器LingoTranslator→ 创建失败时开发环境自动回退伪翻译生产环境则直接抛错。1. Lingo.dev Engine推荐{ models: lingo.dev }需要环境变量LINGODOTDEV_API_KEY。由 LingoTranslator 负责校验与调用。2. 自定义 LLM 模型{ models: { en:es: google:gemini-2.0-flash, *:*: groq:llama3-8b-8192 } }键为源语言:目标语言的语言对映射*:*为兜底值为provider:model格式。需要对应的 Provider API KeyCLI 帮助中列出的环境变量包括LINGODOTDEV_API_KEY、GROQ_API_KEY、GOOGLE_API_KEY、OPENROUTER_API_KEY、MISTRAL_API_KEY。3. Pseudotranslator开发/测试{ dev: { usePseudotranslator: true } }无需 API Key产出伪本地化文本如 Hello → Ĥéĺĺó。从源码看其实现pseudotranslator/index.ts相当讲究输出格式为${locale}/${pseudolocalize(text)}即带 locale 前缀README 的示例为简化示意pseudolocalize会将 ASCII 字符映射为带注音字符a→á、e→é、h→ĥ等完整保留{变量}与组件标签占位符不被改写用于验证 i18n 变量与富文本结构是否被正确透传末尾追加约原文长度 30% 的空格填充模拟长文本翻译导致的布局溢出帮助测试 UI 弹性支持delayMedian参数模拟真实 AI 延迟默认 100ms实际在 50%–150% 区间随机。典型用途验证哪些元素被正确标记为可翻译、占位符是否被破坏而不消耗 AI token。缓存策略与性能设计TranslationServer 依赖的缓存策略README 概括为四点源码印证如下磁盘缓存.lingo/cache/{locale}.json由缓存工厂按配置创建createCacheTranslationCache抽象定义了get / update / set / has / clear / clearAll接口cache.tsCache-firsttranslate()第一步就是cache.get(locale)取出已缓存结果未命中缓存的哈希才进入翻译流程translation-service.ts懒加载只翻译缺失的哈希命中缓存时直接返回stats中会区分cached与translated数量元数据重载每次字典请求都会reloadMetadata()保证构建期新增条目不被遗漏。TranslationService.translate()的完整流水线还包括override 优先元数据中若存在某 locale 的手工覆盖翻译entry.overrides[locale]则直接采用而不调用 AI、复数化处理若开启pluralization先对条目做复数化、源语言直通locale 等于源语言时直接返回可能复数化后的原文而不翻译、部分失败归并PartialTranslationError时把已成功部分合并进结果失败哈希统一收集进errors。每次成功的翻译会写回缓存缓存写失败不会让请求失败最终响应 缓存 ∪ 新翻译 ∪ 覆盖项并按请求哈希集合裁剪返回。在构建期translateAll(locale)是推荐入口它总是先重载元数据、广播batch:start事件、翻译全部哈希、把错误逐条写入日志再广播batch:complete含成功数、失败数、耗时。开发实践本地手动启动服务器手动启动翻译服务器的核心价值在于把服务器进程从打包器启动流程中解耦——当打包器启动链路复杂、难以调试时可以独立拉起服务器再让项目接入。CLI 完整参数在演示项目根目录如demo/new-compiler-next16执行pnpm tsx ../../packages/new-compiler/src/translation-server/cli.ts --port 3456 --target-locales es,fr,de,ja --source-locale en --source-root app --lingo-dir .lingo完整的 CLI 参数源码定义于 cli.ts 及showHelp()参数说明默认值--port number服务器启动端口60000--source-locale string源语言en--target-locales string逗号分隔的目标语言列表es,fr,de--lingo-dir stringLingo 目录路径.lingo--source-root string源码根目录cwd--models string模型配置lingo.dev或locale:provider:model逗号分隔多组未设置--prompt string自定义翻译提示词未设置--timeout number请求超时毫秒30000--use-pseudo使用伪翻译器false--env string环境development/productiondevelopment--config path配置文件路径JSON未设置--help显示帮助—常用示例# 使用 Lingo.dev Engine LINGODOTDEV_API_KEYyour-key pnpm tsx ../../packages/new-compiler/src/translation-server/cli.ts --port 3456 --target-locales es,fr,de,ja --models lingo.dev # 使用自定义 LLM 模型多语言对各指定不同模型 pnpm tsx ../../packages/new-compiler/src/translation-server/cli.ts --port 3456 --target-locales es,fr,de,ja --models es:groq:llama3-70b,fr:google:gemini-pro # 伪翻译模式无需任何 API Key pnpm tsx ../../packages/new-compiler/src/translation-server/cli.ts --port 3456 --target-locales es,fr,de,ja --use-pseudo注意事项CLI 要求Node.js 18.3.0 及以上checkNodeVersion--lingo-dir必须与项目配置中的目录一致--source-root同理否则元数据与缓存将读写到错误位置--models的字符串格式为locale:provider:model例如es:groq:llama3-70b解析为{ es: groq:llama3-70b }parseModelsString。接入项目配置启动后把日志中打印的服务器 URL 写入项目配置export const config { // Other config options... dev: { usePseudotranslator: true, translationServerUrl: http://127.0.0.1:3456 } }dev.translationServerUrl类型定义于 types.ts语义为开发模式下手动启动翻译服务器时填入其 URL。此外Next.js 插件还支持通过环境变量LINGO_TRANSLATION_SERVER_URL直接指定已运行的服务器地址见 next.ts。服务器日志翻译服务器同时写入两处日志控制台输出标准 stdout/stderr日志文件.lingo/translation-server.log相对项目根目录即sourceRoot/lingoDir/translation-server.log见 logger.ts。日志文件包含带 ISO 时间戳的条目日志级别debug、info、warn、errordebug 模式下的完整请求/响应跟踪含批量翻译的哈希列表、错误明细等。底层由 createFileWriter 实现使用串行写队列避免并发写文件竞争每次写入带 1 秒超时保护写失败静默吞掉以免拖垮业务。查看日志# 实时跟踪日志文件 tail -f .lingo/translation-server.log # WindowsPowerShell Get-Content .lingo/translation-server.log -Wait -Tail 50故障排查端口被占用问题现象Error: listen EADDRINUSE: address already in use :::60000解决方案与原文档一致并有源码机制佐证自动跳过服务器默认从 60000 开始向上探测端口被占时自动尝试下一个可用端口显式指定端口使用 CLI 的--port选项指定其他端口检查残留进程# Unix lsof -i :60000 # Windows netstat -ano | findstr :60000复用而非冲突若占用者恰好是另一进程启动的 Lingo.dev 翻译服务器且configHash一致startOrGetUrl会直接复用该端口而不会报错只有配置不一致或端口被无关服务占用时才会转移到新端口checkIfTranslationServer。小结Translation Server 是 Lingo.dev 编译器在开发/构建期的翻译中继站插件自动拉起、端口自动探测、跨进程复用HTTP 端点提供全量字典与批量翻译两种按需能力WebSocket 实时回传进度与 busy/idle 状态磁盘缓存与只翻译缺失哈希的懒加载策略共同保证 AI 调用成本最小化。三种翻译提供者Lingo.dev Engine、自定义 LLM 语言对映射、伪翻译器让开发者既能在生产配置下获得高质量翻译也能在无 API Key 的开发环境下快速验证 i18n 标记正确性。关键源码路径速查服务器主体translation-server.ts独立 CLIcli.tsWebSocket 事件模型ws-events.ts日志写入logger.ts翻译编排与缓存策略translation-service.ts伪翻译器实现pseudotranslator/index.ts配置类型定义types.ts哈希稳定性测试translation-server.test.ts插件自动启动接入unplugin.ts、next.ts【免费下载链接】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),仅供参考