BUILD WITH BUGGCRAFT

给你的启动器,接上中文资源介绍。

按资源 ID 和原文哈希查询共享译文。缓存未命中时,保留原文、异步生成;内容更新后,明确提示用户正在翻译新版本。

当前支持

Modrinth / CurseForge · 模组 / 资源包 / 光影 / 整合包 · 简体中文 zh-Hans · 策略 minecraft-v1。标题保留原名;简介和正文翻译。游戏内文本、文件翻译、更新日志和账号计费尚未开放。

获取原站资源→计算原文哈希→批量 resolve→命中立即显示
未命中显示原文→ensure 排队→轮询 / SSE→替换为新版译文
01 / QUICK START

快速开始

API 根地址:https://translate.bugg.icu/v1。读取公开译文无需密钥;申请生成使用短时匿名会话。大模型凭据只存放在平台服务端。

先检查服务能力

curl https://translate.bugg.icu/v1/capabilities

读取 generation_available、目标语言和批量上限;生成关闭时,已有译文仍可查询。示例使用已收录的 Sodium 项目 AANobbMI。

准备一份可核验的原文

curl https://translate.bugg.icu/v1/projects/modrinth/AANobbMI/source

实际启动器通常已经从原站拿到 description / body,可直接计算哈希。此接口主要用于平台 Web 和接入调试;它不会在读取时访问原站。若返回 project_not_indexed,先申请匿名会话,再 POST /projects/{provider}/{project_id}/refresh,等待返回的任务完成。

把翻译与浏览解耦

搜索、滚动、详情和下载先正常完成。在后台读取本地译文缓存,再批量查询平台;任何网络错误都保留原文。以下命令行示例为便于理解会等待翻译,接入 GUI 时放到后台任务中。

02 / IDENTITY

稳定身份与原文哈希

项目主键是 provider + project_id。创建时间、作者、标签均为可变元数据,不能拼进项目主键。第一版实体固定为 project,entity_id 必须等于 project_id。

字段输入来源format
title项目原名plain
summaryModrinth description / CurseForge summaryplain
bodyModrinth 原始 bodymarkdown
bodyCurseForge 原始 description HTMLhtml
  1. 仅把 CRLF、CR 规范成 LF。
  2. 构造下列五个字符串字段,键按 ASCII 升序排列,不添加空白。
  3. 输出原生 Unicode 的 UTF-8 JSON 字节,计算 SHA-256,添加 sha256: 前缀。
{"field":"summary","format":"plain","schema":"mc-text-v1","source_language":"und","text":"Original summary"}
哈希使用原始数据;页面使用清洗后的渲染结果。

不要先剥除 HTML、裁剪长度、去首尾空白或做 Unicode NFC/NFD 转换。中文和 emoji 不应变成 \uXXXX 后再参与哈希。未知语言固定 und;不能自行换成 en。请跑通全部公开测试向量再接入。

03 / TRANSLATION

先查译文,缺失时自动排队

3.1 批量查询 · POST /translations:resolve

{
  "target_language": "zh-Hans", "profile": "minecraft-v1",
  "items": [{
    "request_id": "visible-row-1",
    "resource": {"provider":"modrinth","project_id":"AANobbMI","entity_type":"project","entity_id":"AANobbMI"},
    "fields": [{"field":"summary","source_hash":"sha256:这里替换为实际的64位小写十六进制值"}]
  }]
}

每批最多 50 个项目、每项最多 3 个字段。服务只读本地数据库,不在此接口调用原站或模型。仅在 state=ready 且 matches_request=true 时使用 translation;还需读取 is_current 和 update 判断版本提示。

3.2 创建短时会话

POST /v1/sessions/anonymous
Content-Type: application/json

{"client_id":"your-launcher"}

// 成功响应(access_token 仅示意)
{"access_token":"…","token_type":"Bearer","expires_in":3600,"scopes":["translations:ensure","jobs:read","feedback:write"]}

只在需要生成时创建会话,内存复用到过期前;不要每次轮询申请。会话属于当前调用者,任务票据不能跨会话共享。

3.3 请求生成 · POST /translations:ensure

Authorization: Bearer <access_token>
Idempotency-Key: <本次逻辑请求唯一的 UUID>
Content-Type: application/json

// 在 resolve 请求体基础上添加:
"purpose": "visible_list"

请求体仍是完整 JSON 对象;上面只展示新增字段。每批最多 20 项;详情使用 purpose=detail。服务从可信原站核验哈希,只翻译公开资源,不能提交任意文本。HTTP 202 表示接受排队,不表示译文完成。同一个逻辑请求的网络重试复用幂等键;更换请求体必须更换键,否则返回 409。

3.4 完成后替换,不打断操作

用 resolve 每 2–5 秒批量查询当前可见资源,或订阅任务事件。滚动离开的资源停止轮询;详情切换后丢弃旧页面返回的结果。后台生成仍会继续,其他启动器也能复用结果。

正文 artifact

简介直接位于 translation.text。正文通过 translation.artifact.artifact_sha256 下载:

GET /v1/artifacts/{artifact_sha256}

用响应的原始字节校验 SHA-256(此处路径里的哈希不带 sha256:),再验证 resource、field、source_hash、target_language 和 profile。artifact 不可变,支持 ETag 与一年缓存;不要在校验前重新序列化 JSON。自己拼接可信服务源下的 artifact 路径,避免跟随不可信 URL。

04 / UPDATES

原文更新时,告诉用户发生了什么

state 描述请求哈希的译文状态;update 描述它与平台当前原文的关系。两者一起使用,不能把“有历史译文”解释成“已经是最新版”。

update.code含义建议界面行为
up_to_date请求与当前原文一致,译文就绪显示译文
translation_pending首次翻译未完成显示原文和“正在准备译文”
source_updated客户端持有旧原文,新版译文可用刷新原站内容,重算哈希
update_pending原文已更新,新译文尚未排队显示原文,自动 ensure
update_queued新版译文排队或延后重试提示“原文已更新,新版本译文正在排队”
update_running新版翻译正在执行提示“原文已更新,正在翻译新版本”
update_failed新版翻译暂时失败保留原文并提示失败
{
  "field": "summary",
  "state": "running", "matches_request": false, "is_current": true,
  "requested_source_hash": "sha256:…", "current_source_hash": "sha256:…",
  "update": {
    "code": "update_running", "source_changed": true,
    "previous_translation_available": true,
    "current_translation_state": "running",
    "notice": "原文已更新,正在翻译新版本", "action": "ensure"
  }
}

action=refresh_source:刷新客户端原文再查询,不能继续用旧哈希提交新版翻译。action=ensure:按当前请求哈希申请生成,已有任务会去重。action=none:无需操作。可直接显示 notice,或按 code 自行本地化;不要用提示文案当程序判断条件。

旧译文必须明确标识

默认缺失时返回原文,不自动把旧译文放入 translation。只有请求 allow_stale=true 才可能返回 fallback_translation 与 fallback_source_hash;使用时持续显示“旧版译文,新版本翻译中”。即使 state=ready,若 is_current=false,它也只是与请求的历史哈希一致。

发现更新的时效

客户端从原站拿到新原文后,其新哈希会触发 ensure 的版本核验。平台后台默认按五分钟过期时间检查,每轮最多八个项目,拥塞或原站限流会延长实际延迟,不承诺五分钟内全库同步。freshness 只代表最近核验时间,不能作为原站绝未变化的保证。需要时可主动 refresh,受独立限额约束。

05 / PRESENTATION

内容结构保留,原文与译文一致呈现

正文的 format 可能为 markdown 或 html,以实际响应为准。平台保留作者介绍中的标题层级、段落、列表、表格、链接和图片结构,翻译文字;代码、技术版本和 URL 使用占位符保护。不要直接展示原始标签文本,也不要把整个 HTML 文档当纯文本拼到页面上。

  1. Markdown 先解析为 HTML;HTML 使用内容片段。
  2. 原文与译文使用同一套 HTML 清洗规则,移除脚本、事件属性、iframe 和危险 URL。
  3. 再渲染到相同正文样式中;图片延迟加载,外链使用 noopener/noreferrer。

平台 Web 使用本地打包的 markdown-it 与 DOMPurify,不从第三方 CDN 加载脚本。保留介绍内容结构,不复制原站导航、广告或整站 CSS。客户端必须独立清洗,不能因为内容来自翻译平台就跳过防护。未经审查的原文与模型输出都不能直接注入 WebView。

06 / RESOURCE DATA

项目资料、版本和依赖

GET /v1/projects/{provider}/{project_id}/source
GET /v1/projects/{provider}/{project_id}/manifest
GET /v1/projects/{provider}/{project_id}/history

source 返回完整原始字段与 metadata;manifest 返回字段哈希、译文状态、更新时间和项目资料;history 提供原文、元数据变动和译文发布记录。只读接口不请求原站。

metadata 字段用途
authors / created_at / updated_at作者、创建及原站更新时间,时间采用 ISO 8601
tags / game_versions / loaders分类、支持的 Minecraft 版本、加载器
icon_url / downloads / license图标、下载量和许可证,原站未提供则为空
releases最近 12 个原站版本,包含发布时间、渠道、游戏版本与依赖
releases[].dependenciesproject_id / version_id / name / relation / url
metadata_completefalse 表示部分资料拉取失败,应标为暂缺,不应推断“没有依赖”

依赖属于具体发布文件,必须按所选版本展示。relation:required 必需、optional 可选、incompatible 不兼容、embedded 内置、tool 工具。列表的 dependency_count 仅对应最近版本;正文、标签和作者变化不会更换项目 ID。

07 / CATALOGUE

搜索与分页

GET /v1/catalog/search?q=优化&kind=mod&limit=20
GET /v1/catalog/projects?limit=20

// 下一页:原样传回 next_cursor,同时保持 q / kind / limit 一致
GET /v1/catalog/search?q=优化&kind=mod&limit=20&cursor=<URL编码后的next_cursor>

响应提供 projects、total_count 和 next_cursor;游标为空表示末页。limit 为 1–50,kind 为 mod / resourcepack / shader / modpack。q 检索已收录的标题、简介和中文译文,不会实时搜索全站资源。

使用索引和 keyset 分页,不执行深层 OFFSET。游标签名绑定筛选条件与每页数量,有效期 15 分钟;过期、篡改或筛选不一致时返回 409 cursor_expired,应清空分页栈重载首页。客户端保存访问过的游标实现上一页。资源库会持续新增,总数可能变化;不提供任意深页跳转或固定快照保证。

08 / BACKGROUND JOBS

轮询与 SSE 事件

GET /v1/jobs/{job_id}
Authorization: Bearer <创建该任务票据的会话令牌>

GET /v1/events?job_ids=<job_id1,job_id2>
Authorization: Bearer <同一会话令牌>

任务状态包括 queued → verifying → running / partial → ready;deferred 表示稍后重试;failed 和 source_mismatch 为终态。可读取分段完成量,不能把 partial 当成完整正文。

SSE 最多同时订阅 50 个票据,连接最长约 120 秒,断开后重连并重新读取任务状态。事件仅用于唤醒查询,最终结果以 resolve 为准。浏览器原生 EventSource 无法添加 Authorization,请使用 fetch 流或回退批量轮询,令牌不要放进 URL。

09 / CODE EXAMPLES

多语言完整示例

五种语言都演示:读取示例原文 → 计算哈希 → resolve → 缺失时创建会话和 ensure → 轮询 → 显示译文。示例只查询简介;正文 artifact 处理见第 03 节。可用环境变量 TRANSLATION_API 指向兼容平台,值应为 HTTPS 地址且包含 /v1。

正在读取示例…
生产接入时补上 UI 生命周期和退避

本地缓存键至少包含服务源、资源 ID、字段、原文哈希、语言和 profile。网络任务放在后台;401 重建会话、429 服从 Retry-After、5xx 指数退避。不要把模型密钥嵌进桌面程序。服务源切换后隔离缓存。

10 / RELIABILITY

错误、限额与性能

HTTP / code处理方式
400 invalid_request检查哈希、实体、批量上限和 JSON;不要原样高频重试
401 unauthorized会话过期,重新创建;管理接口使用独立管理员令牌
404 project_not_indexed申请 refresh 并等待任务,不要假设 source 会自动回源
409 idempotency_conflict同一键使用了不同请求体,修复幂等键管理
409 cursor_expired清空旧游标栈,重载首页
413 request_too_large请求 JSON 最大 64 KiB,拆分批次
429 rate_limited按 Retry-After 等待,不要并发重试风暴
source_mismatch任务核验的哈希与原站不一致;刷新原文重算哈希
budget_exhausted / deferred模型预算耗尽,后台延后,先保留原文

当前部署的默认限额

  • resolve:每 IP 每分钟最多 1200 次;客户端应以可见区批量查询。
  • 匿名会话:每 IP 每小时 10 个,令牌约 1 小时有效。
  • ensure:每分钟 60 次;每 IP 和会话每小时最多 200 个字段。
  • refresh:每 IP 每小时 10 次;反馈每小时 10 次。
  • 模型另有全局日/月 token 和每日调用预算,队列和原站也有并发限制。

限额可能由部署方调整;以 capabilities 和错误响应为准。端到端耗时主要取决于原站、正文长度、队列和模型,不能把缓存查询延迟等同于首次翻译耗时。缓存命中不调用模型;分段缓存复用、WAL、批量 SQL、限量 LRU 和不可变 artifact 分别减少模型成本、锁竞争和网络开销。

REFERENCE

接口索引

方法与路径(均位于 /v1)认证用途
GET /capabilities无能力与上限
POST /translations:resolve无精确哈希查询
POST /sessions/anonymous无创建匿名会话
POST /translations:ensure会话 + 幂等键异步核验、生成
GET /jobs/{job_id} · GET /events票据所属会话进度与状态
GET /artifacts/{artifact_sha256}无不可变正文
GET /projects/{provider}/{id}/source · manifest · history无原文、资料、版本记录
POST /projects/{provider}/{id}/refresh会话核验原站更新
GET /catalog/projects · /catalog/search无本地译文库分页与搜索
POST /feedback会话提交译文问题
GET /admin/overview · POST /admin/overview管理员令牌预算、队列、反馈状态

精确请求与响应定义见 OpenAPI 3.1 文件;本页示例中的省略号和注释用于说明,不可直接作为有效 JSON 请求。项目正文和图片版权归原作者所有,界面保留原项目入口与 AI 译文标识。