读取某个 locale 的翻译结果,以及它是如何一步步产出的完整阶段记录。
当你手里已经有一个 jobId 时,就该调用这个接口了——它可能来自 create 返回的 202、由 webhook 带来,或列在某个 作业组 下。组接口告诉你有_多少个_ locale 已完成;这个接口则会告诉你某一个 locale 具体产出了_什么_,以及过程中都发生了什么。
GET /jobs/localization/:jobId如果你刚接触异步本地化,建议先看 概览。
这正是本页要讲清楚的区别。组响应更像记分板——给你计数和每个作业的状态,作业组页面 已有说明。单个作业则是某个 locale 的完整档案:翻译后的 outputData、最终的 status、可能出现的 warnings,以及一条 steps[] 运行过每个阶段的 pipeline 轨迹。当你准备把德语文案写进数据库时,真正把这份德语文案交到你手里的,就是这个调用。
身份验证#
请在 X-API-Key 请求头中传入你的 API key。Key 的作用域是组织级,能够访问该组织下的所有引擎。详见 身份验证。
响应#
outputData 字段会完整映射输入 data 的结构:所有字符串值都会被翻译,所有非字符串值(数字、布尔值、null)都会原样保留。键不变、嵌套不变、数组顺序不变——变的只有字符串。
{
"id": "ljb_A1b2C3d4E5f6G7h8",
"groupId": "ljg_A1b2C3d4E5f6G7h8",
"targetLocale": "de",
"status": "completed",
"outputData": {
"id": "course_101",
"title": "Einführung in maschinelles Lernen",
"steps": [
{ "heading": "Was ist ML?", "body": "Maschinelles Lernen ist ein Teilbereich der künstlichen Intelligenz." },
{ "heading": "Überwachtes Lernen", "body": "Trainieren eines Modells mit gelabelten Daten." }
],
"metadata": { "author": "Dr. Smith", "difficulty": "beginner" }
},
"errorMessage": null,
"warnings": [],
"callbackStatus": "delivered",
"createdAt": "2026-03-16T10:30:00.000Z",
"startedAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:04.000Z",
"steps": [
{
"stepId": "localize",
"type": "action",
"status": "completed",
"errorMessage": null,
"externalRefType": null,
"externalRefId": null,
"externalRefUrl": null,
"createdAt": "2026-03-16T10:30:01.000Z",
"startedAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:04.000Z"
}
]
}上面的 metadata 代码块保持原样不动——Dr. Smith 和 beginner 都是非字符串叶子节点,引擎不会改写。你读回来的 outputData 与提交时的结构完全一致,所以构造 payload 的同一套代码,也能直接消费翻译结果。
| 字段 | 说明 |
|---|---|
id | 该作业本身的 ID(ljb_…),也就是你在路径中传入的值。 |
groupId | 该作业所属的父作业组(ljg_…)。把它传给 作业组接口,即可一次查看所有同组 locale。 |
targetLocale | 该作业的目标 BCP-47 locale——每个目标 locale 对应一个作业。你可以据此分支,把 outputData 路由到正确的列或文件。 |
status | queued、processing、completed、completed_with_warnings 或 failed。 |
outputData | 与输入结构一致的翻译内容。当 status 为 completed 或 completed_with_warnings 时会返回。 |
errorMessage | 错误描述。当 status 为 failed 时返回,否则为 null。 |
warnings | 非关键 pipeline 阶段的失败记录。每个条目都是 { step, message }。除非 status 为 completed_with_warnings,否则为空。 |
callbackStatus | Webhook 投递状态:pending、delivered 或 failed。如果未配置回调 URL,则为 null。 |
createdAt | 作业被接受的时间(即创建它的 202 上的时间戳)。 |
startedAt | 引擎开始翻译该 locale 的时间。作业一旦离开 queued,就会设置该值。 |
completedAt | 作业进入最终状态的时间。当 status 变为 completed、completed_with_warnings 或 failed 后设置。 |
steps | 各阶段的执行记录。始终包含 localize 这一步,另外每启用一个可选 pipeline 阶段,就会多一条记录。完整记录结构见 观察 pipeline 运行。 |
作业完成前,outputData 一直是 null
当 status 还是 queued 或 processing 时,outputData 为空,errorMessage 为 null——此时还没有可读内容。只有在 status 进入 completed 或 completed_with_warnings 后,才去读取 outputData;如果状态是 failed,则应改为读取 errorMessage。先按 status 分支,再访问 payload。
作业状态值#
作业会从 queued 进入 processing,然后落到且只会落到一个最终状态。在读取其他任何字段前,先根据 status 分支——它会告诉你哪些字段已经有值。
| 状态 | 含义 | 该读取什么 |
|---|---|---|
queued | 已接受,尚未开始。 | 暂时没有——继续轮询,或等待 webhook。 |
processing | 引擎正在翻译这个 locale。 | 暂时没有。 |
completed | 翻译已完成,所有已启用阶段均执行成功。 | outputData。 |
completed_with_warnings | 翻译已完成,且 outputData 完整可用,但某个非关键 pipeline 阶段未能完成。 | 先读 outputData,再读 warnings。 |
failed | 该作业没有产出翻译结果。 | errorMessage。 |
completed_with_warnings 仍然会交付翻译结果
completed_with_warnings 不是“软失败”。你仍会拿到完整的 outputData——说明核心翻译步骤已经成功。变化只在于某个非关键阶段(例如 pre-edit 或 back-translation)没有完成,且每一次失败都会以 { step, message } 的形式记录在 warnings 中。你应将输出视为可用,同时把 warnings 当作一个值得展示给翻译审核者的质量信号。只有 failed 才意味着没有翻译可读。
处理未知状态值
以上五种状态值,是当前的契约。Pipeline 阶段会持续演进,因此请把 status 视为开放集合:对已知值正常分支处理,对任何意外值都走默认分支——如果 outputData 存在就读取,不存在就记日志。没有兜底处理的 switch,等到新状态上线那天就会出问题。
steps 数组#
steps[] 记录的是单个作业背后的阶段轨迹——按顺序列出引擎实际运行过的每一个阶段。每个作业至少都会有 localize 这一步,因为核心翻译一定会执行。你每启用一个可选 pipeline 阶段,就会多出一条记录。所以,没有额外阶段的作业只会显示一个 localize 步骤;如果启用了 pre-edit 和 back-translation,就会显示三步。
这正是作业可审计、而不是黑盒的关键。你不需要“相信”某个阶段运行过——你可以直接读取它的记录:是哪一个阶段(stepId)、它是 completed、failed 还是 skipped、花费是多少(costUsd),以及它何时开始、何时结束。对于人工审核阶段,externalRef* 会指向外部记录。
"steps": [
{
"stepId": "preEdit",
"type": "action",
"status": "completed",
"errorMessage": null,
"costUsd": 0.0012,
"createdAt": "2026-03-16T10:30:01.000Z",
"completedAt": "2026-03-16T10:30:02.000Z"
},
{
"stepId": "localize",
"type": "action",
"status": "completed",
"errorMessage": null,
"costUsd": 0.0184,
"createdAt": "2026-03-16T10:30:02.000Z",
"completedAt": "2026-03-16T10:30:05.000Z"
}
]这里出现某个 failed 条目,并不一定意味着整个作业失败。当某个非关键阶段失败时,它对应的 steps[] 记录会显示为 failed,同样的失败也会反映在作业顶层的 warnings 中,而作业仍然会带着完整的 outputData 进入 completed_with_warnings。完整记录结构——每个字段、每个 stepId,以及 completed/failed/skipped 的语义——都统一定义在权威页面:观察 pipeline 运行。本页告诉你在作业里去哪里找;那一页则定义它本身。
读取已完成的作业#
典型的消费方会先根据 status 分支:成功时写入 outputData,失败时记录 errorMessage。下面这个可直接复制粘贴的调用,会返回上方展示的 payload。
const jobId = "ljb_A1b2C3d4E5f6G7h8";
const response = await fetch(`https://api.lingo.dev/jobs/localization/${jobId}`, {
headers: { "X-API-Key": process.env.LINGO_API_KEY },
});
const job = await response.json();
switch (job.status) {
case "completed":
case "completed_with_warnings":
// outputData is populated; warnings may carry non-critical stage failures
await db.content.update({
where: { id: job.outputData.id },
data: { [`content_${job.targetLocale}`]: job.outputData },
});
if (job.warnings.length) console.warn(job.targetLocale, job.warnings);
break;
case "failed":
console.error(`${job.targetLocale} failed: ${job.errorMessage}`);
break;
default:
// queued or processing - nothing to read yet; also catches future states
break;
}如果这个接口返回错误——例如未知的 jobId 或缺失的 key——它会遵循标准 JSON 错误模型。详见 错误与状态码。
