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/translate uses multipart/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 targetLang submitted to /api/translate must be the code in 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’s targetLang
  • name — the display name under the UI language specified by lang

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

  1. 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} (display name, use code as 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.
  2. Let the user pick a target language: the code of the selected option is the targetLang to submit.
  3. Submit for translation: POST /api/translate with file as the subtitle file, targetLang as the code from the previous step, plus optional outputFormat / apiKey, etc.
  4. Handle the result: on success, render data.content or offer a download via data.filename; on failure, read error and 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/languages
  • POST 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 targetLang to be a language code (e.g. en, zh), with the selectable list obtained via GET /api/languages.
  • To keep your server robust against all clients, it is recommended that the language validation in /api/translate accept both codes and display names — recognizing en as 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.