翻译能力

本项目不内置翻译引擎,也不绑定任何翻译厂商。运行时由服务端把文本转发到应用配置的 HTTP 翻译端点(环境变量 IM_TRANSLATE_ENDPOINT),控制台只负责保存与校验 provider / 语言码 / 端点配置。未配置端点时,翻译接口如实返回 1021,不会返回伪造的翻译结果。

三条必须先知道的事实

运行时只认环境变量:控制台保存的 endpoint 仅做校验与展示,实际请求地址来自 IM_TRANSLATE_ENDPOINT,设置后需重启服务端。

客户端 SDK / IMKit 没有“翻译”菜单或 translate API;翻译必须由 App Server 调 Open API,客户端只负责展示结果。

没有厂商配额、没有计费、没有内置缓存与批量翻译;单次请求是同步代理,上游 5 秒超时。

工作方式​

翻译是一次同步代理调用,不写库、不产生消息、不触发回调:

客户端 / App 只展示译文,不持有密钥 App Server message.translate(Open API 签名) IM Server 读取 IM_TRANSLATE_ENDPOINT HTTP POST {text,targetLang,sourceLang?} → {text,...}

配置(控制台 / Admin API)​

配置入口是 Admin API GET/POST /api/admin/apps/{appkey}/translation,对应控制台 翻译与机器人。配置是存储 + 校验,不是运行时开关。

字段类型规则(服务端实现)说明
enabledbool启用时 provider 必须为 http;且 endpoint 或环境变量至少有一个仅表示“配置意图”,运行时仍以环境变量为准
providerstringnone / http(mock 已弃用,传 mock 直接 400)未配置时为 none
sourceLangstring可空;非空时 2–16 个字符,仅 [A-Za-z0-9_-]源语言;可省略,由上游自动识别
targetLangsstring[]最多 20 个;每个 2–16 字符;去重;大小写保留BCP-47 风格的语言码,不做厂商白名单校验
endpointstringhttp(s) URL;provider=http 且启用但为空时,要求环境变量已设置仅保存/展示;运行时读环境变量
保存成功 ≠ 已生效

保存后 configured 仍可能是 false:它反映 IM_TRANSLATE_ENDPOINT 是否设置(runtimeSource=env|unconfigured)。用响应里的这两个字段判断运行时状态,不要只看 enabled。

保存并读回(curl)​

Shell
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)​

JSON
{
  "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​

POST/im/v2/message/translateOpen API同步
请求字段类型必填说明
textstring是待翻译文本;服务端未做长度上限校验(受 HTTP 网关/JSON 体积约束)
targetLangstring是目标语言码,原样转发给上游
sourceLangstring否源语言码;省略时由上游识别
响应字段(data)类型说明
textstring译文;上游必须返回非空 text,否则按上游错误处理
sourceLangstring上游返回则透传;否则回落到请求的 sourceLang(可能缺省)
targetLangstring上游返回则透传;否则回落到请求的 targetLang

上游请求体固定为 { text, targetLang, sourceLang? };上游返回非 2xx、超时(5 秒)、非 JSON 或缺少 text 时,统一转为 1021,并在 msg 中带上上游原因摘要。

用 Node SDK 调用(未配置时的真实结果)​

JavaScript
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;
  }
}

未配置端点的真实响应​

JSON
{
  "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 字符),完整报文不会透出。

相关页面​