Subtitle Translation API Protocol
1. Overview
This document targets third-party integration and describes two HTTP endpoints for subtitle translation. Developers can implement their own translation backend against it:
GET /api/languages— fetch the list of supported target languages (with localized display names)POST /api/translate— upload a subtitle file and translate it
The two endpoints are used together: first call /api/languages to render a language dropdown, then submit the selected code as targetLang to /api/translate.
Translation is typically powered by an upstream LLM (e.g. Alibaba Cloud DashScope
qwen-mt-flash, DeepSeek, etc.). This server handles protocol adaptation, batch scheduling and output formatting.
2. Common Conventions
2.1 Base URL
- Direct connection:
http(s)://<host>:<port> - Behind a reverse proxy: may carry a path prefix, e.g.
https://<host>/subtitle-api
The examples below assume http://localhost:3000; replace it with your actual deployment. The port is controlled by PORT / HTTPS_PORT in the server-side .env.
2.2 Encoding & Format
- Requests and responses are UTF-8.
/api/translateusesmultipart/form-data(file upload included).- All JSON responses share a unified structure: success is
{ "success": true, "data": ... }, failure is{ "success": false, "error": "..." }.
3. Supported Target Languages
There are 13 target languages, each with a stable code (ISO 639-1) that serves as the contract value submitted to /api/translate. The display name changes with the UI language, but the code is constant.
| code | Chinese name | Native name |
|---|---|---|
zh |
中文 | 中文 |
en |
英语 | English |
ja |
日语 | 日本語 |
ko |
韩语 | 한국어 |
fr |
法语 | Français |
de |
德语 | Deutsch |
es |
西班牙语 | Español |
ru |
俄语 | Русский |
pt |
葡萄牙语 | Português |
it |
意大利语 | Italiano |
ar |
阿拉伯语 | العربية |
th |
泰语 | ไทย |
vi |
越南语 | Tiếng Việt |
The
targetLangsubmitted to/api/translatemust be thecodein the table above (e.g.en), not a display name (e.g. “English” or “英语”). Submitting a legacy Chinese name will be rejected.
4. GET /api/languages
Fetch the list of supported target languages, optionally localized by UI language.
4.1 Request
| Param | Location | Required | Description |
|---|---|---|---|
lang |
query | no | UI language code; controls the display language of name. Accepts the 13 codes above. Falls back to zh when omitted or unknown. Case-insensitive. |
4.2 Response
data is an array whose items look like { "code": string, "name": string }:
code— the stable language code, the contract value for/api/translate’stargetLangname— the display name under the UI language specified bylang
Example: GET /api/languages?lang=zh (default)
{
"success": true,
"data": [
{ "code": "zh", "name": "中文" },
{ "code": "en", "name": "英语" },
{ "code": "ja", "name": "日语" },
{ "code": "ko", "name": "韩语" },
{ "code": "fr", "name": "法语" },
{ "code": "de", "name": "德语" },
{ "code": "es", "name": "西班牙语" },
{ "code": "ru", "name": "俄语" },
{ "code": "pt", "name": "葡萄牙语" },
{ "code": "it", "name": "意大利语" },
{ "code": "ar", "name": "阿拉伯语" },
{ "code": "th", "name": "泰语" },
{ "code": "vi", "name": "越南语" }
]
}
Example: GET /api/languages?lang=en
{
"success": true,
"data": [
{ "code": "zh", "name": "Chinese" },
{ "code": "en", "name": "English" },
{ "code": "ja", "name": "Japanese" },
{ "code": "ko", "name": "Korean" }
]
}
Example: GET /api/languages?lang=ko
{
"success": true,
"data": [
{ "code": "zh", "name": "중국어" },
{ "code": "en", "name": "영어" },
{ "code": "ko", "name": "한국어" }
]
}
4.3 Behavior
| Scenario | Result |
|---|---|
Missing / empty lang |
Equivalent to lang=zh |
Known code (ko, ja, ru …) |
Returns localized names for that UI language |
Uppercase (KO, En) |
Normalized to lowercase, then looked up |
Unknown code (xx) |
That item’s name falls back to Chinese (names.zh) |
5. POST /api/translate
Upload a .srt / .vtt subtitle file and return the translated subtitle content.
5.1 Request
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file |
File | yes | Subtitle file (.srt or .vtt, max 10MB) |
targetLang |
string | yes | Target language code, e.g. en, zh, ja (taken from the code of /api/languages); case-insensitive |
apiKey |
string | no | Translation API key; if omitted, the server-side DEFAULT_API_KEY is used; if neither is present a 500 is returned |
model |
string | no | Translation model; if omitted, the server-side DEFAULT_MODEL is used (default qwen-mt-flash) |
batchSize |
number | no | Subtitles per batch, range 1–50, default 20; clamped into range when out of bounds |
outputFormat |
string | no | Output format: vtt (default) or srt; anything other than srt is treated as vtt |
5.2 Success Response
{
"success": true,
"data": {
"content": "WEBVTT\n\n1\n00:00:01.000 --> 00:00:03.000\nHello World\n\n",
"format": "vtt",
"totalSubtitles": 120,
"filename": "movie.translated.vtt"
}
}
| Field | Description |
|---|---|
content |
The full translated subtitle text |
format |
Output format: vtt or srt |
totalSubtitles |
Number of subtitle entries |
filename |
Suggested download filename (<original>.translated.<ext>) |
5.3 Error Response
{
"success": false,
"error": "Error description"
}
5.4 Status Codes
| HTTP status | Trigger |
|---|---|
200 |
Translation succeeded |
400 |
No file uploaded; empty targetLang; targetLang is not a valid code (including legacy Chinese names) |
422 |
Subtitle parsing failed, or parsed content is empty |
500 |
Server has no DEFAULT_API_KEY configured and the request carries no apiKey |
502 |
Upstream translation API call failed |
For an invalid targetLang, the error message lists all valid codes so the client can surface a helpful prompt, e.g.:
{
"success": false,
"error": "不支持的目标语言代码 \"英语\",有效代码:zh、en、ja、ko、fr、de、es、ru、pt、it、ar、th、vi"
}
6. Typical Integration Flow
- Fetch the language list: request
GET /api/languages?lang=<ui-lang>per the client UI language, then render a dropdown from the returned{code, name}(displayname, usecodeas the value). The UI language should be explicitly chosen and persisted by the user — not hard-coded to Chinese or read from the browser language. - Let the user pick a target language: the
codeof the selected option is thetargetLangto submit. - Submit for translation:
POST /api/translatewithfileas the subtitle file,targetLangas the code from the previous step, plus optionaloutputFormat/apiKey, etc. - Handle the result: on success, render
data.contentor offer a download viadata.filename; on failure, readerrorand branch by status code.
Translation calls the upstream model in batches against the source text. Long subtitles are processed in multiple batches within a single synchronous, blocking request — the longer the file, the slower the response. The client should set a sufficiently long timeout and provide progress feedback.
7. curl Examples
# 1. Fetch the language list (localized to English UI)
curl -s 'http://localhost:3000/api/languages?lang=en'
# 2. Translate to English (VTT output)
curl -X POST http://localhost:3000/api/translate \
-F "file=@/path/to/subtitle.srt" \
-F "targetLang=en" \
-F "apiKey=sk-your-api-key"
# 3. Translate to Chinese (SRT output, using the server default key & model)
curl -X POST http://localhost:3000/api/translate \
-F "file=@/path/to/subtitle.vtt" \
-F "targetLang=zh" \
-F "outputFormat=srt"
# 4. Uppercase code is equivalent (same as targetLang=en)
curl -X POST http://localhost:3000/api/translate \
-F "file=@/path/to/subtitle.srt" \
-F "targetLang=EN"
8. Connecting to ZWPlayer
ZWPlayer points its translation service via the translateApi initialization option. It expects the base URL of the service (the common prefix shared by both endpoints); the player automatically appends /languages and /translate to it:
const player = new ZWPlayer({
url: 'http://example.com/vod/movie.mp4',
playerElm: '#player-holder',
translateApi: 'https://your-translate-server.com/subtitle-api/api'
});
With the configuration above, the player actually requests:
GET https://your-translate-server.com/subtitle-api/api/languagesPOST https://your-translate-server.com/subtitle-api/api/translate
Once configured, a “Subtitle Translate” entry automatically appears in the player’s subtitle menu (CC menu). The user can select a target language and load the translated subtitle as a subtitle track. See Subtitle Setup for full usage of the subtitle menu.
8.1 Protocol Compatibility Note
This document describes the target protocol specification (using ISO language codes). When implementing a server, note that the actual targetLang value sent by a ZWPlayer client depends on the client version:
- The target protocol requires
targetLangto be a language code (e.g.en,zh), with the selectable list obtained viaGET /api/languages. - To keep your server robust against all clients, it is recommended that the language validation in
/api/translateaccept both codes and display names — recognizingenas well as legacy inputs like英语/English, and returning a clear error message otherwise (see §5.4).
A server that satisfies the request/response structure in this document can be called by ZWPlayer.