Translate Starter
受众:开发者 摘要:统一翻译 Facade。LibreTranslate / Google / 腾讯云 / AI Model provider,占位符保护,文本 / HTML / JSON / 批量翻译,后台翻译协作。
何时使用
| 场景 | 建议 |
|---|---|
| 单条文本翻译 | Translate.text(src, fromLocale, toLocale) |
| 批量文本翻译 | Translate.texts(list, fromLocale, toLocale) |
| HTML 翻译(保留标签) | Translate.html(...) / Translate.htmls(...) |
| JSON 翻译(只翻字符串值,不翻 key) | Translate.json(...) |
| 后台批量补译 i18n 文案 | 用 i18n starter 的 /translate-batch API |
| 需要详细失败原因 | Translate.translateWithDetails(...) 返回 Outcome |
| 多 provider 自动切换 | default-provider: auto |
Translate 默认启用,但默认 default-provider: none,不会在未配置 provider 时访问真实翻译服务。需要实际翻译时,显式选择并启用 provider。
I18n 负责「拿到正确文案」,Translate 负责「把文案翻译成另一种语言」。配套使用见 i18n.md。
快速开始
spring:
open:
translate:
enabled: true
default-provider: tencent-cloud
providers:
tencent-cloud:
enabled: true
secret-id: ${TENCENT_TRANSLATE_SECRET_ID:}
secret-key: ${TENCENT_TRANSLATE_SECRET_KEY:}var result = Translate.text("你好,世界", Locale.SIMPLIFIED_CHINESE, Locale.ENGLISH);Facade API
// 单条文本
Translate.text(text, fromLocale, toLocale);
// 批量文本
Translate.texts(List.of("文本1", "文本2"), fromLocale, toLocale);
// HTML(保留标签结构)
Translate.html("<p>你好 {name}</p>", fromLocale, toLocale);
Translate.htmls(List.of("<p>...</p>", "<strong>...</strong>"), fromLocale, toLocale);
// JSON(只翻译字符串值,不翻 key / 不动数字 / 布尔 / null / 数组结构)
Translate.json("{\"title\":\"你好\",\"items\":[\"用户名\",\"密码\"]}", fromLocale, toLocale);
// 详细结果(含失败原因)
TranslateOutcome outcome = Translate.translateWithDetails(
TranslateRequest.of(text, fromLocale, toLocale));TranslateOutcome 用于后台维护场景,可识别失败原因:翻译未启用、provider 未配置、provider 不存在、provider 异常、空结果。
配置项
通用配置
spring:
open:
translate:
enabled: true # 默认启用;provider 未配置时不调用外部服务
default-provider: none # none / auto / libre-translate / google-translate / tencent-cloud / ai-model
preserve-placeholders: true # 保护 {0} / {name} / ${APP_NAME} / %s 等占位符
placeholder-patterns: [] # 自定义占位符正则| 配置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 启用开关;显式设为 false 时关闭翻译能力 |
default-provider | none | 默认 provider |
preserve-placeholders | true | 占位符保护 |
placeholder-patterns | 内置规则 | 占位符保护正则(顺序敏感) |
default-provider: auto 适合开发和兜底;生产建议显式配置 provider,便于排查成本、限流、错误。
LibreTranslate
spring:
open:
translate:
providers:
libre-translate:
enabled: true
provider: libre-translate
endpoint: ${TRANSLATE_LIBRE_ENDPOINT:https://libretranslate.example.com/translate}
api-key: ${TRANSLATE_LIBRE_API_KEY:}
api-key-header: "" # 可选 header 名(默认走 body)
format: text # text / html
timeout: 10s
locale-mapping:
zh-CN: zhGoogle Translate
spring:
open:
translate:
providers:
google-translate:
enabled: true
provider: google-translate
endpoint: https://translation.googleapis.com/language/translate/v2
api-key: ${GOOGLE_TRANSLATE_API_KEY:}
format: text
model: "" # 空 = 默认模型
timeout: 10s
locale-mapping:
zh-CN: zh-CN
zh-TW: zh-TW腾讯云翻译
spring:
open:
translate:
providers:
tencent-cloud:
enabled: true
provider: tencent-cloud
endpoint: https://tmt.tencentcloudapi.com
secret-id: ${TENCENT_TRANSLATE_SECRET_ID:}
secret-key: ${TENCENT_TRANSLATE_SECRET_KEY:}
token: "" # 可选临时密钥
region: ap-guangzhou
project-id: 0
timeout: 10s
locale-mapping:
zh-CN: zh
zh-TW: zh-TW配置优先级:数据库配置同名 key > 环境变量 / .env > application.yml 默认值。
AI Model
ai-model Provider 通过 spring-open-starter-ai-model 的 AiModelManager 调用统一模型底座,不直接绑定 OpenAI、通义、Claude 或 DeepSeek SDK。它默认关闭,只有应用同时引入 AI Model starter 并显式启用 provider 时才会参与路由。
spring:
open:
translate:
enabled: true
default-provider: ai-model
providers:
ai-model:
enabled: true
model-provider: deepseek # 对应 spring.open.ai.model.providers.<name>
model: deepseek-chat
temperature: 0.1
max-tokens: 1024
prompt: |-
Translate the following {format} content from {sourceLocale} to {targetLocale}.
Return only the translated content. Preserve placeholders, variables, HTML tags and JSON keys.
{text}prompt 支持 {text}、{sourceLocale}、{targetLocale} 和 {format} 占位。返回的 TranslateResult.metadata() 会带上 aiModelProvider、aiModelModel、finishReason、inputTokens、outputTokens 和 totalTokens,便于后台预览、审计和后续计量归集。
Provider
| Provider | 说明 | 适用 |
|---|---|---|
none | 不选 provider | 默认 |
auto | 依次尝试已启用 provider | 开发 / 兜底 |
libre-translate | LibreTranslate 或兼容接口 | 自建 / 私有部署 |
google-translate | Google Cloud Translation Basic v2 | 海外业务 |
tencent-cloud | 腾讯云机器翻译 TMT | 国内业务 |
ai-model | 统一 AI Model starter | 运营文案、长文本和需要模型质量的翻译 |
ai-model 只依赖统一 AI Model 抽象,不在 Translate starter 内引入具体模型 SDK。
扩展点与源码骨架
| 层级 | 主要类型 | 责任 |
|---|---|---|
| 业务 Facade | Translate | 面向业务代码提供短名静态 API,转交给 TranslateManager |
| 编排层 | TranslateManager / DefaultTranslateManager | 启用开关、provider 路由、auto 兜底、占位符保护、失败原因归一化 |
| 请求 / 结果 | TranslateRequest / TranslateResult / TranslateOutcome | 统一文本、语言、格式、实际 provider、失败原因 |
| Provider SPI | TranslateProvider | 封装单个厂商或兼容接口的协议调用 |
| Provider 贡献者 | TranslateProviderContributor / DefaultTranslateProviderContributor | 通过 ServiceLoader 注册内置或外部 provider |
| 运行时配置 | TranslateRuntimeConfig / TranslateRuntimeConfigSource | 读取 spring.open.translate.*,支持配置中心覆盖本地配置 |
| 占位符保护 | TranslatePlaceholderProtector | 翻译前保护模板变量,翻译后还原 |
| JSON 支持 | TranslateJsonSupport | 只翻译 JSON 字符串值,保持结构和 key 不变 |
分层原则:
- 业务模块只调用
Translate或注入TranslateManager,不要直接拼 provider 客户端。 - I18n 负责文案查询、落库和翻译批处理入口,Translate 只负责“把文本翻译成目标语言”。
- Manager 负责路由、兜底和错误语义;Provider 只负责具体厂商协议。
- 配置中心覆盖、本地配置兜底和 provider-specific 语言映射都统一放在
TranslateRuntimeConfig。 - 新增厂商优先实现
TranslateProvider,复杂外部扩展包再提供TranslateProviderContributor。
文本 / HTML / JSON
| 内容类型 | 推荐方法 | 行为 |
|---|---|---|
| 纯文本 | Translate.text / texts | 按 provider format 配置 |
| HTML | Translate.html / htmls | provider 的 format=html |
| JSON | Translate.json | 解析 JSON,只翻译字符串值,不翻 key |
JSON 翻译特性:
- 输出仍是合法 JSON
- 不动数字 / 布尔 /
null/ 数组结构 / 对象 key - 适合前端文案包、配置说明、通知 payload 样板、后台元数据
- 非法 JSON 返回空结果
- 单字符串翻译失败保留原值;整批失败返回空结果
- HTML 片段优先用
Translate.html(...),不要包在 JSON 字符串里
腾讯云 TMT 当前按普通文本 API 处理,复杂富文本建议先拆分文本节点或用支持 HTML format 的 provider。
占位符保护
preserve-placeholders=true 时翻译前保护常见占位符,翻译后还原,避免第三方翻译把模板变量改坏。
默认保护:
- Spring i18n / MessageFormat:
{0}/{name}/{app.name} - 配置或前端变量:
${APP_NAME} - Java formatter:
%s/%1$s - 模板变量:
{{ user.name }}
示例:
messages.welcome.text=Hello! Welcome {0} to my [ {1} ] website.自定义占位符正则(覆盖 placeholder-patterns):
spring:
open:
translate:
placeholder-patterns:
- "\\{\\{\\s*[^{}]+\\s*}}"
- "\\{\\s*[A-Za-z0-9_.-]+(?:\\s*,\\s*[^{}]+){0,2}\\s*}"
- "\\$\\{[^{}]+}"
- "%\\d*\\$?[A-Za-z]"
- "<%\\s*[^%]+\\s*%>"建议业务文案、Validation 文案和通知模板都保留明确占位符,不要把变量拼接进待翻译文本。
扩展自定义 Provider
实现 TranslateProvider 并注册为 Spring Bean:
@Component
public class MyProvider implements TranslateProvider {
@Override public String name() { return "my-provider"; }
@Override public Optional<TranslateResult> translate(TranslateRequest request) { ... }
}外部扩展包可用 TranslateProviderContributor + Java ServiceLoader,让 provider 不直接侵入应用模块。
后台协作
I18n 后台的 /api/v1/admin/i18n/messages/translate-batch 复用 Translate provider:
- 在
zh-CN写入或收集源文案 - 配置 Translate provider
- 调用 batch 翻译 API 预览
save=true保存目标语言文案到i18n_message
保存后 source 记录为 translation:<provider>(例 translation:google-translate)。
AI 模型翻译
详见 .ai/decisions/adr-030-ai-translate-provider.md。
设计边界:
- Translate 只依赖
TranslateProvider和统一 AI Model 抽象,不直接依赖 OpenAI / 通义 / Claude SDK ai-model默认关闭;缺失翻译收集默认只记录待翻译项,不自动调用模型- 后台预览和批量补译可显式选择
ai-model,保存结果时来源记录为translation:ai-model - 翻译前继续保护
{0}/{name}/${APP_NAME}/%s等占位符 - Provider 通过 AI Model starter 承接模型选择、超时、重试、限流和 token usage,Translate 侧保留占位符保护、格式提示和来源元数据
注意事项
- 生产环境密钥放数据库配置或环境变量,不写
application.yml - Translate 模块默认启用;真实翻译仍需要选择并启用至少一个 provider
default-provider: auto多 provider 切换时按声明顺序,第一个成功的返回- 不在低延迟链路(订单创建 / 支付回调)实时调用第三方翻译,建议异步 + 缓存
验证命令
./mvnw -pl spring-open-starters/spring-open-starter-translate -am test -DskipITs相关
- I18n(多语言文案):i18n.md
- AI 模型翻译:
.ai/decisions/adr-030-ai-translate-provider.md - 动态业务元数据本地化:
.ai/decisions/adr-029-dynamic-metadata-i18n.md - 配置中心(数据库配置覆盖):config.md
- Provider 扩展模型:provider.md