API 参考
本文档对应 api/app.js 中 Express 应用的行为,以及 api/routes/ 下的路由处理程序。
限制和行为
| 项目 | 值 |
|---|---|
| JSON 请求体大小 | 最高 2 MB (express.json({ limit: '2mb' })) |
| 每次请求目标数 | 1–36 语言代码 |
| 批量项目数 | 每个批量请求 1–100 项 |
| 模型 | standard(默认)或 advanced(仅付费层;见下文) |
每月令牌额度(免费层): 在调用模型前,API 估算令牌数大致为 ceil(content_length / 4) × (number_of_targets + 1),且仅对 free 层,如果估算超过剩余的月度额度(FREE_TIER_MONTHLY_TOKENS,默认 100000),则拒绝请求,返回 429 / token_limit_reached。付费层不受 enforceTokenCap 中此预检查的限制;使用情况仍会被记录。
速率限制: 当配置了 Upstash Redis(UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN,且 URL 不包含占位符 your-instance)时,按层级应用每分钟限制:免费 5,入门 30,成长 60,规模 120,企业无限制。达到限制时,响应为 429,错误为 error: "rate_limit_reached"。如果未配置 Redis,则跳过速率限制(见 rateLimit.js)。
成功的速率限制响应可能包含 X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset。
GET /health
无需认证。
响应 200
{
"status": "ok",
"timestamp": "2025-03-23T12:00:00.000Z"
}
GET /languages
无需认证。
返回支持语言的规范列表(代码、显示名称、RTL 标志)。共有 36 条目;代码是翻译端点中 targets 唯一接受的值。
响应 200
{
"languages": [
{ "code": "en", "name": "English", "rtl": false },
{ "code": "ar", "name": "Arabic", "rtl": true }
]
}
POST /translate
需要 Authorization: Bearer <api_key>。
将单个 content 字符串翻译成 targets 中列出的所有语言。模型返回一个 单一 JSON 对象,其键 完全 是请求的语言代码,值是翻译后的字符串(见 formatPrompts.js)。
请求体
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
content | string | 是 | 非空待翻译字符串。 |
targets | string[] | 是 | 非空有效语言代码数组(最多 36 个)。 |
format | string | 否 | plain、markdown、json、html 之一。若省略,则从 content 自动检测格式。 |
source | string | 否 | 模型的源语言提示;可选。 |
model | string | 否 | standard(默认)或 advanced。advanced 需付费层(免费层返回 403)。 |
响应 200
{
"translations": {
"es": "...",
"fr": "..."
},
"usage": {
"input_tokens": 120,
"output_tokens": 340,
"total_tokens": 460,
"model": "standard",
"detected_format": "markdown",
"detection_confidence": 0.95
}
}
仅当省略 format 并执行自动检测时,才会出现 detected_format 和 detection_confidence。
示例(cURL)
curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
-H "Authorization: Bearer $POLYLINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "{\"title\":\"Hello\"}",
"format": "json",
"targets": ["fr", "de"]
}'
示例(Python 3)
pip install requests
import os, requests
url = "https://api.usepolylingo.com/v1/translate"
headers = {
"Authorization": f"Bearer {os.environ['POLYLINGO_API_KEY']}",
"Content-Type": "application/json",
}
r = requests.post(url, json={
"content": "<p>Hello <strong>world</strong></p>",
"format": "html",
"targets": ["es"],
}, timeout=120)
r.raise_for_status()
print(r.json()["translations"]["es"])
POST /translate/batch
需要 Authorization: Bearer <api_key>。
依次处理每个项目(每个项目调用一次模型)。如果任何项目失败,API 返回 500,且不返回该请求的部分结果。
请求体
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
items | 数组 | 是 | 每个元素:id(字符串)、content(字符串)、可选 format。 |
targets | string[] | 是 | 与 /translate 相同规则。 |
source | string | 否 | 可选源语言提示。 |
model | string | 否 | standard 或 advanced(与 /translate 规则相同)。 |
响应 200
{
"results": [
{ "id": "welcome", "translations": { "fr": "...", "de": "..." } },
{ "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
],
"usage": {
"total_tokens": 900,
"input_tokens": 400,
"output_tokens": 500,
"model": "standard"
}
}
示例
curl -sS -X POST "https://api.usepolylingo.com/v1/translate/batch" \
-H "Authorization: Bearer $POLYLINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "id": "a", "content": "Hello", "format": "plain" },
{ "id": "b", "content": "## Title", "format": "markdown" }
],
"targets": ["es", "it"]
}'
POST /jobs
需要 Authorization: Bearer <api_key>。
将翻译任务入队,并立即返回 job_id。翻译在后台运行——无论内容大小,均无 HTTP 超时风险。轮询 GET /jobs/:id 获取结果。
当翻译大型文档(长 Markdown、多目标语言)且请求时间可能超过 HTTP 客户端或代理超时时,使用此端点替代 POST /translate。
请求体
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
content | string | 是 | 非空待翻译字符串。 |
targets | string[] | 是 | 非空有效语言代码数组(最多 36 个)。 |
format | string | 否 | plain、markdown、json、html 之一。省略时自动检测。 |
source | string | 否 | 源语言提示;可选。 |
model | string | 否 | standard(默认)或 advanced。 |
响应 202
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z"
}
GET /jobs/:id
需要 Authorization: Bearer <api_key>。
轮询通过 POST /jobs 提交的任务状态。每 5–10 秒轮询一次。任务归提交用户所有——其他用户返回 404。
响应(待处理 / 处理中)
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z",
"updated_at": "2025-03-23T12:00:00.000Z",
"completed_at": null,
"queue_position": 3
}
status 为 pending(等待工作者)或 processing(工作者已领取)。queue_position(从 1 开始)表示在此任务之前严格创建的待处理或处理中任务数——用于进度 UI。计数查询失败时省略。
响应(已完成)
{
"job_id": "a1b2c3d4-...",
"status": "completed",
"created_at": "2025-03-23T12:00:00.000Z",
"updated_at": "2025-03-23T12:00:02.000Z",
"completed_at": "2025-03-23T12:00:02.000Z",
"translations": {
"es": "...",
"fr": "..."
},
"usage": {
"input_tokens": 120,
"output_tokens": 340,
"total_tokens": 460,
"model": "standard"
}
}
响应(失败)
{
"job_id": "a1b2c3d4-...",
"status": "failed",
"error": "Model returned invalid JSON"
}
示例(JavaScript)
const API = 'https://api.usepolylingo.com/v1'
const headers = {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
}
// 1. 提交
const submit = await fetch(`${API}/jobs`, {
method: 'POST',
headers,
body: JSON.stringify({ content: longMarkdown, format: 'markdown', targets: ['de', 'fr'] }),
})
const { job_id } = await submit.json()
// 2. 轮询
while (true) {
await new Promise(r => setTimeout(r, 10_000))
const poll = await fetch(`${API}/jobs/${job_id}`, { headers })
const job = await poll.json()
if (job.status === 'completed') { console.log(job.translations); break }
if (job.status === 'failed') { throw new Error(job.error) }
// 可选:显示进度(queue_position 从 1 开始,未排队时省略)
if (job.queue_position != null) console.log(`队列位置: ${job.queue_position}`)
}
GET /usage
需要 Authorization: Bearer <api_key>(标准密钥查找——非内部绕过路径)。
返回已认证用户的当前日历月令牌使用情况。
响应 200
{
"period_start": "2025-03-01T00:00:00.000Z",
"period_end": "2025-03-31T23:59:59.000Z",
"tokens_used": 12000,
"tokens_included": 100000,
"tokens_remaining": 88000,
"overage_tokens": 0,
"tier": "free"
}
tokens_included 和 tokens_remaining 对于 enterprise 为 null(报告中无限额度)。
内容格式
支持的 format 值:plain、markdown、json、html。
| 格式 | 保留 | 翻译 |
|---|---|---|
plain | 换行 / 段落 | 所有可见文本 |
markdown | 语法、链接(URL 不变)、代码块(逐字) | 散文和链接文本 |
json | 键、结构、非字符串类型 | 仅字符串值 |
html | 标签和属性 | 文本节点和适当属性(见提示) |
应用中的 RTL 和方向
对于 plain 和 markdown 输出,API 仅返回翻译文本——不添加 dir="rtl" 或包装元素。显示阿拉伯语、希伯来语或波斯语时,请在 UI 中设置文本方向(CSS direction、父元素的 dir 属性或框架的国际化布局)。
对于 html 格式,翻译后的标记可能在适合 RTL 的目标语言中包含 dir="rtl";见 formatPrompts.js 和 scripts/test-translation.js 中的 HTML 测试。
错误响应
错误尽可能以 JSON 格式返回:
{
"error": "invalid_request",
"message": "人类可读的详细信息"
}
| HTTP | error | 何时 |
|---|---|---|
| 400 | invalid_request | 缺失/无效的请求体字段(如空 content、错误的 targets) |
| 400 | invalid_format | format 不在支持集合中 |
| 400 | invalid_language | targets 中未知代码 |
| 401 | invalid_api_key | 缺失/格式错误的 Authorization,未知密钥,被撤销密钥 |
| 403 | advanced_not_available | 免费层使用 model: "advanced" |
| 429 | token_limit_reached | 免费层月度上限超出(预检查) |
| 429 | rate_limit_reached | 每分钟 RPM 限制(启用 Redis 时) |
| 500 | translation_error | 模型/网络失败;可安全重试 |
| 404 | not_found | GET /jobs/:id — 任务不存在或属于其他用户 |
| 500 | server_error | POST /jobs — 入队失败;可安全重试 |
GET /usage 如果 Supabase 查询失败,可能返回带通用消息的 500。
底层模型(仅供参考)
API 仅暴露 standard 和 advanced。实际的 OpenAI 模型 ID 配置在 api/utils/modelRouter.js 中,且不会在 API 响应中返回。