翻译能力
本项目不内置翻译引擎,也不绑定任何翻译厂商。运行时由服务端把文本转发到应用配置的 HTTP 翻译端点(环境变量 IM_TRANSLATE_ENDPOINT),控制台只负责保存与校验 provider / 语言码 / 端点配置。未配置端点时,翻译接口如实返回 1021,不会返回伪造的翻译结果。
运行时只认环境变量:控制台保存的 endpoint 仅做校验与展示,实际请求地址来自 IM_TRANSLATE_ENDPOINT,设置后需重启服务端。
客户端 SDK / IMKit 没有“翻译”菜单或 translate API;翻译必须由 App Server 调 Open API,客户端只负责展示结果。
没有厂商配额、没有计费、没有内置缓存与批量翻译;单次请求是同步代理,上游 5 秒超时。
工作方式
翻译是一次同步代理调用,不写库、不产生消息、不触发回调:
配置(控制台 / Admin API)
配置入口是 Admin API GET/POST /api/admin/apps/{appkey}/translation,对应控制台 翻译与机器人。配置是存储 + 校验,不是运行时开关。
| 字段 | 类型 | 规则(服务端实现) | 说明 |
|---|---|---|---|
enabled | bool | 启用时 provider 必须为 http;且 endpoint 或环境变量至少有一个 | 仅表示“配置意图”,运行时仍以环境变量为准 |
provider | string | none / http(mock 已弃用,传 mock 直接 400) | 未配置时为 none |
sourceLang | string | 可空;非空时 2–16 个字符,仅 [A-Za-z0-9_-] | 源语言;可省略,由上游自动识别 |
targetLangs | string[] | 最多 20 个;每个 2–16 字符;去重;大小写保留 | BCP-47 风格的语言码,不做厂商白名单校验 |
endpoint | string | http(s) URL;provider=http 且启用但为空时,要求环境变量已设置 | 仅保存/展示;运行时读环境变量 |
保存后 configured 仍可能是 false:它反映 IM_TRANSLATE_ENDPOINT 是否设置(runtimeSource=env|unconfigured)。用响应里的这两个字段判断运行时状态,不要只看 enabled。
保存并读回(curl)
curl -sS -X POST "http://127.0.0.1:8080/api/admin/apps/demo/translation" \
-H 'X-Admin-Secret: dev-admin' \
-H 'content-type: application/json' \
-d '{"enabled":true,"provider":"http","sourceLang":"zh-CN","targetLangs":["en-US","ja-JP"],"endpoint":""}'
curl -sS -X GET "http://127.0.0.1:8080/api/admin/apps/demo/translation" \
-H 'X-Admin-Secret: dev-admin'真实响应(未配置 IM_TRANSLATE_ENDPOINT)
{
"code": 0,
"data": {
"appkey": "smoke-1793059388884",
"configured": false,
"enabled": false,
"endpoint": "",
"mockDeprecated": true,
"provider": "none",
"runtimeSource": "unconfigured",
"sourceLang": "",
"storedConfigured": false,
"targetLangs": [],
"updatedAt": 0
}
}可以看到 provider=none、configured=false、runtimeSource=unconfigured、mockDeprecated=true。把服务端以 IM_TRANSLATE_ENDPOINT=https://translate.example.com/v1 重启后,configured=true、runtimeSource=env。
语言码
语言码采用 BCP-47 风格子集,服务端只做语法校验(2–16 字符,字母/数字/-/_),不校验某个语言是否被你的翻译厂商支持。常见写法:
| 语言 | 推荐码 | 语言 | 推荐码 |
|---|---|---|---|
| 简体中文 | zh-CN | 英语(美国) | en-US |
| 繁体中文 | zh-TW | 英语(英国) | en-GB |
| 日语 | ja-JP | 韩语 | ko-KR |
| 法语 | fr-FR | 德语 | de-DE |
| 西班牙语 | es-ES | 葡萄牙语(巴西) | pt-BR |
| 俄语 | ru-RU | 阿拉伯语 | ar-SA |
| 泰语 | th-TH | 越南语 | vi-VN |
| 印尼语 | id-ID | 马来语 | ms-MY |
约定:统一用“语言-地区”写法(zh-CN 而不是 zh_CN),全应用保持一致;sourceLang 省略时由上游识别。目标语言变更后,客户端展示逻辑要跟着改(不要硬编码「英文 = en」)。
翻译接口 message.translate
| 请求字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
text | string | 是 | 待翻译文本;服务端未做长度上限校验(受 HTTP 网关/JSON 体积约束) |
targetLang | string | 是 | 目标语言码,原样转发给上游 |
sourceLang | string | 否 | 源语言码;省略时由上游识别 |
| 响应字段(data) | 类型 | 说明 |
|---|---|---|
text | string | 译文;上游必须返回非空 text,否则按上游错误处理 |
sourceLang | string | 上游返回则透传;否则回落到请求的 sourceLang(可能缺省) |
targetLang | string | 上游返回则透传;否则回落到请求的 targetLang |
上游请求体固定为 { text, targetLang, sourceLang? };上游返回非 2xx、超时(5 秒)、非 JSON 或缺少 text 时,统一转为 1021,并在 msg 中带上上游原因摘要。
用 Node SDK 调用(未配置时的真实结果)
import { AppClient, ImApiError } from '@ni-paas-im/server-sdk';
const app = new AppClient({
appKey: process.env.IM_APP_KEY,
appSecret: process.env.IM_APP_SECRET,
baseUrl: 'http://127.0.0.1:8080',
});
try {
const result = await app.translate({ text: '你好,世界', targetLang: 'en-US' });
console.log(result); // { text: 'Hello, world', targetLang: 'en-US' }
} catch (error) {
if (error instanceof ImApiError && error.code === 1021) {
console.warn('翻译未配置:', error.msg); // translate service not configured (IM_TRANSLATE_ENDPOINT)
} else {
throw error;
}
}未配置端点的真实响应
{
"code": 1021,
"msg": "translate service not configured (IM_TRANSLATE_ENDPOINT)"
}这正是“诚实失败”的形态:没有 mock、没有伪译文。配置好端点并重启后,同一个调用返回真实译文。
限额与配额
| 项 | 值 | 来源 / 说明 |
|---|---|---|
| 目标语言数 | 每应用最多 20 个 | admin.translation.set 校验 |
| 单语言码长度 | 2–16 字符 | valid_lang_code() |
| 单次文本长度 | 未设上限 | 服务端代码无长度校验;实际受网关/JSON 体积限制,长文建议业务侧分片 |
| 上游超时 | 5 秒 | UPSTREAM_TIMEOUT;超时映射为 1021 |
| 请求频率 | 未实现限频/配额 | 没有供应商配额、没有计费;如需限流请在网关或业务侧实现 |
| 缓存 / 批量 | 均无 | 每次调用都真实请求上游;不支持一次多段文本或多目标语言 |
| 配置份数 | 每应用 1 份 | provider/语言码/端点各一份 |
客户端与 IMKit 的边界
当前客户端 SDK(Web / Android / Flutter / Electron / Native)的 IDL 与实现中没有翻译方法,IMKit 也没有「翻译」菜单项。因此不存在“长按消息 → 翻译”的内置交互。
- 推荐做法:客户端把消息文本发给自己的 App Server → App Server 调
message.translate→ 客户端把译文显示在气泡下方或替换视图。 - 不要在客户端持有 App-Secret;也不要把
message.translate直接暴露给浏览器/App。 - 需要“翻译后替换原消息”时,可用
message.modify或message.expansion.set保存译文,避免重复翻译;这属于业务选择,不是内置行为。
常见问题
控制台保存成功为什么还返回 1021?
运行时读 IM_TRANSLATE_ENDPOINT。保存只落配置;设置环境变量并重启后才生效(看 configured / runtimeSource)。
能直接用某厂商 SDK 吗?
可以,但要在你自己的服务端封装成 HTTP 端点,再让 IM Server 转发;本项目不内置任何厂商密钥或调用。
支持一次翻译多种语言吗?
不支持。每次一个 targetLang;需要多语言时由业务侧并发调用并自行限流。
译文会存进消息吗?
不会。翻译接口不写库;是否持久化由业务决定(消息修改/扩展)。
语言码写 zh_CN 可以吗?
语法校验能通过(下划线合法),但上游厂商未必识别;建议统一 BCP-47 连字符写法。
上游报错能看到原因吗?
会以 1021 返回,msg 含上游状态/摘要(最多 200 字符),完整报文不会透出。