# 翻译 API

> 翻译接口在一个响应中返回记录的所有语言版本：电影和剧集的标题或名称、简介、宣传语和主页，单集的名称和简介。每行带有 iso_639_1、iso_3166_1 和 english_name。可读取 language 参数未提供的语言，或构建回退链。

## 接口

`GET /3/movie/{movie_id}/translations`

```bash
curl "https://api.amodb.dev/3/movie/550/translations" \
  -H "Authorization: Bearer $AMODB_KEY"
```

响应:

```json
{
  "id": 550,
  "translations": [
    {
      "iso_3166_1": "AR",
      "iso_639_1": "ar",
      "name": "العربية",
      "english_name": "Arabic",
      "data": {
        "title": "نادي القتال",
        "overview": "يعيش موظف مكتبي يعاني من الأرق والملل حياة روتينية فارغة، إلى أن يلتقي بالرجل الغامض تايلر ديردن، الذي يختلف عنه تمامًا ويؤمن بأن التحرر من قيود المجتمع يبدأ برفض الحياة التقليدية. تنشأ بينهما صداقة غريبة تقودهما إلى تأسيس نادٍ سري يتجمع في...",
        "homepage": "",
        "tagline": "نادي القتال هو نادي يوجد في العقل الباطن لكل واحد منا !",
        "runtime": 0
      }
    },
    {
      "iso_3166_1": "AZ",
      "iso_639_1": "az",
      "name": "Azərbaycan",
      "english_name": "Azerbaijani",
      "data": {
        "title": "Döyüş Klubu",
        "overview": "Xəyalları olmayan bir gənc yuxusuzluğa qarşı mübarizə aparır, bəlkə də boz və gündəlik həyatı ilə cansıxıcılığının nəticəsidir. Təyyarə gəzintisində o, çox xüsusi bir fəlsəfəyə sahib olan xarizmatik sabun satıcısı Tyler Durden ilə tanış olu...",
        "homepage": "",
        "tagline": "",
        "runtime": 0
      }
    },
    {
      "iso_3166_1": "BY",
      "iso_639_1": "be",
      "name": "Беларуская",
      "english_name": "Belarusian",
      "data": {
        "title": "Байцоўскі клуб",
        "overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy. Their concept catches on, with underground \"fight clubs\" forming in every town, until an eccentric gets in the wa...",
        "homepage": "",
        "tagline": "",
        "runtime": 0
      }
    }
  ]
}
```

## 获取电影的翻译

`GET /3/movie/{movie_id}/translations` 为电影每种有文本的语言返回一行。每一行带有包含译文字段的 `data` 对象。该调用没有语言参数，因为它的意义就在于一次看到所有语言。

示例找到俄语那一行，打印其标题和简介开头。

```bash
curl -s "https://api.amodb.dev/3/movie/550/translations" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```js
const url = 'https://api.amodb.dev/3/movie/550/translations';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { translations } = await res.json();
const ru = translations.find((t) => t.iso_639_1 === 'ru');
console.log(ru ? `${ru.data.title}: ${ru.data.overview.slice(0, 80)}` : 'no Russian row');
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/550/translations",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
ru = next((t for t in r.json()["translations"] if t["iso_639_1"] == "ru"), None)
print(f"{ru['data']['title']}: {ru['data']['overview'][:80]}" if ru else "no Russian row")
```

```php
<?php
$ch = curl_init('https://api.amodb.dev/3/movie/550/translations');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    throw new RuntimeException("amodb returned $status");
}
foreach (json_decode($body, true)['translations'] as $t) {
    if ($t['iso_639_1'] === 'ru') {
        echo $t['data']['title'], ': ', mb_substr($t['data']['overview'], 0, 80), PHP_EOL;
        exit;
    }
}
echo 'no Russian row', PHP_EOL;
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Translations struct {
	Translations []struct {
		ISO6391 string `json:"iso_639_1"`
		Data    struct {
			Title    string `json:"title"`
			Overview string `json:"overview"`
		} `json:"data"`
	} `json:"translations"`
}

func main() {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/movie/550/translations", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	client := &http.Client{Timeout: 10 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}
	var t Translations
	if err := json.NewDecoder(res.Body).Decode(&t); err != nil {
		panic(err)
	}
	for _, row := range t.Translations {
		if row.ISO6391 == "ru" {
			text := []rune(row.Data.Overview)
			if len(text) > 80 {
				text = text[:80]
			}
			fmt.Printf("%s: %s\n", row.Data.Title, string(text))
			return
		}
	}
	fmt.Println("no Russian row")
}
```

### 参数

| 参数         | 位置 | 必填  | 说明                                        |
| ---------- | -- | --- | ----------------------------------------- |
| `movie_id` | 路径 | 是   | 数字形式的电影 ID，例如 `550`。                      |
| `api_key`  | 查询 | 二选一 | 你的密钥。使用它，或使用 `Authorization: Bearer` 请求头。 |

### 响应字段

| 字段                            | 类型      | 说明                                                                       |
| ----------------------------- | ------- | ------------------------------------------------------------------------ |
| `id`                          | integer | 电影 ID。                                                                   |
| `translations`                | array   | 每种有文本的语言一行，按语言代码排序。电影 550 返回 50 行。                                       |
| `translations[].iso_3166_1`   | string  | 与语言配套的国家代码，例如 `en` 对应 `US`，`pt` 对应 `BR`。对于 14 种提供语言以外的语言，它把语言代码改成大写重复一遍。 |
| `translations[].iso_639_1`    | string  | 语言代码，例如 `ru` 或 `pt`。在数组中唯一。                                              |
| `translations[].name`         | string  | 用该语言书写的语言名称。                                                             |
| `translations[].english_name` | string  | 英文的语言名称。                                                                 |
| `translations[].data`         | object  | 译文字段。键取决于资源，见下表。                                                         |

### 示例响应

这里显示了 50 行中的两行，简介已缩短。

```json
{
  "id": 550,
  "translations": [
    {
      "iso_3166_1": "US",
      "iso_639_1": "en",
      "name": "English",
      "english_name": "English",
      "data": {
        "title": "Fight Club",
        "overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy....",
        "homepage": "https://www.20thcenturystudios.com/movies/fight-club",
        "tagline": "Mischief. Mayhem. Soap.",
        "runtime": 0
      }
    },
    {
      "iso_3166_1": "RU",
      "iso_639_1": "ru",
      "name": "Русский",
      "english_name": "Russian",
      "data": {
        "title": "Бойцовский клуб",
        "overview": "Сотрудник страховой компании страдает хронической бессонницей и отчаянно пытается вырваться из мучительно скучной жизни. Однажд...",
        "homepage": "https://www.20thcenturystudios.com/movies/fight-club",
        "tagline": "«Интриги. Хаос. Мыло»",
        "runtime": 0
      }
    }
  ]
}
```

在 amodb 中，翻译行里的 `runtime` 始终为 0。请从[电影详情](https://amodb.dev/zh/movies/)记录读取片长。

## 翻译接口及其 data 键

所有路径使用同一个基础地址 `https://api.amodb.dev/3`。每个都返回 `id` 和上述行结构的 `translations` 数组。只有 `data` 里的键不同。

| 方法和路径                                                                              | `data` 键                                                 |
| ---------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `GET /movie/{movie_id}/translations`                                               | `title`、`overview`、`homepage`、`tagline`、`runtime`（始终为 0） |
| `GET /tv/{series_id}/translations`                                                 | `name`、`overview`、`homepage`、`tagline`                   |
| `GET /tv/{series_id}/season/{season_number}/translations`                          | 无，数组始终为空                                                 |
| `GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/translations` | `name`、`overview`                                        |

剧集记录列出的语言数量与电影差不多。单集的行只覆盖该单集有文本的提供语言，在检查过的样本中为 2 到 14 种。把缺失的键当作空值处理，并忽略你不认识的键。上级记录见[电视剧](https://amodb.dev/zh/tv-series/)。

amodb 不提供人物或系列合集的翻译。人物传记遵循人物详情调用的 `language` 参数，系列合集的简介按存储的内容返回。

## 文本缺失时回退

一部作品可能有 14 种语言，但在用户选择的那种语言里简介仍为空。沿着语言链依次尝试，取第一个非空值，并记住它来自哪种语言。

```js
function pickText(translations, wanted, field) {
  for (const code of [...wanted, 'en']) {
    const row = translations.find((t) => t.iso_639_1 === code);
    const value = row?.data?.[field];
    if (value) return { code, value };
  }
  return null;
}

// Prefer Ukrainian, then Russian, then English.
// const hit = pickText(translations, ['uk', 'ru'], 'overview');
```

对于剧集，把字段改为传 `'name'` 而不是 `'title'`。在界面中标出来自回退语言的文本，让用户知道为什么乌克兰语页面显示的是英文剧情简介。

## 翻译接口还是 language 参数

| 需求                           | 使用                   |
| ---------------------------- | -------------------- |
| 向一个用户展示一种语言                  | 详情调用上的 `language`    |
| 在编辑界面列出作品的所有语言               | 此接口                  |
| 读取 `language` 不提供的语言，例如 `ja` | 此接口，按 `iso_639_1` 选行 |
| 检查 14 种提供语言中哪些有文本            | 此接口，比较 `iso_639_1`   |
| 为页面构建多语言链接                   | 此接口，读取存在的代码          |

`language` 接受的标签见[语言](https://amodb.dev/zh/languages/)。详情调用上任何其他标签都会回退到英文。

## 错误

| HTTP | status_code | 何时出现                           |
| ---- | ----------- | ------------------------------ |
| 401  | 7           | 密钥缺失或错误。                       |
| 402  | 36          | 套餐周期已结束。                       |
| 404  | 34          | 没有该 ID 的季或单集，或 ID 不是数字。        |
| 405  | 37          | 你对翻译路径使用了写入方法。                 |
| 429  | 25          | 超过了每分钟请求数。请等待 `Retry-After` 秒。 |

不存在的电影或剧集 ID 在此路径上不算错误：它返回 200 和 `"translations": []`，而详情路径返回 404。更多见[错误](https://amodb.dev/zh/errors/)和[速率限制](https://amodb.dev/zh/rate-limits/)。

## 实用说明

- 一次调用可以替代多达 14 次详情调用。需要同一作品两种以上语言时使用它。
- 各行按语言代码排序，这不是优先级顺序。请按 `iso_639_1` 选行，不要按数组位置。
- 详情类调用在边缘缓存 6 小时，所以同样时长的客户端缓存不会损失新鲜度。
- 日语或韩语等其他文字的原始标题，始终可在详情记录的 `original_title` 和 `original_name` 中获得。
- 要把翻译加入详情调用，请传 `append_to_response=translations`，并从响应中读取同样的数组。它适用于电影、剧集和单集。追加的数据块没有 `id`。

## 常见问题

### 什么时候用 translations 而不是 language 参数？

向用户展示一种语言时用 language。需要同时获得一部作品的多种语言时用 translations，例如编辑界面、多语言页面或覆盖检查。它还会返回 language 不提供的语言，比如 ja 或 de。

### iso_639_1 和 iso_3166_1 有什么区别？

iso_639_1 是语言代码，例如 pt。iso_3166_1 是与之配套的国家，例如 BR。对于 14 种提供语言以外的语言，它会把语言代码改成大写重复一遍，例如 da 对应 DA，所以请始终按 iso_639_1 匹配。

### 为什么 data 里的某个字段是空的？

空字符串或 0 表示该语言没有这个字段的文本。不要展示它。请回退到你回退链中的下一种语言，通常是英文，或使用原始标题。

### 这个接口覆盖哪些语言？

电影和剧集记录会列出目录中的所有语言，通常有 40 到 80 行，其中包括 14 种提供语言：en、ru、uk、be、zh、pt、bg、he、cs、ro、fr、pl、it 和 es。单集只列出其中一部分。

## 相关页面

- [电影详情 API](https://amodb.dev/zh/movies/): 路径和 JSON 与 TMDB v3 相同的电影详情 API：按 ID 取电影，用 append_to_response 加入演职员和评分，支持 14 种语言。
- [电视剧 API](https://amodb.dev/zh/tv-series/): 路径和 JSON 与 TMDB v3 相同的电视剧 API。按 ID 获取剧集的季、电视网和下一集，以及内容分级和观看平台。
- [人物详情 API](https://amodb.dev/zh/people/): 路径和 JSON 与 TMDB v3 相同的人物详情 API。按 ID 获取演员或幕后人员，含传记、作品列表、外部 ID 和热门列表。
- [系列合集 API](https://amodb.dev/zh/collections/): 采用 TMDB v3 路径的系列合集 API：按 ID 获取系列及全部成员影片，读取电影的 belongs_to_collection，并按名称搜索合集。
- [语言](https://amodb.dev/zh/languages/): amodb 以 14 种语言提供片名、简介和姓名。在 language 中传入 ru-RU 或 pt-BR 这样的 TMDB 风格标签，其他标签回退到英语。
- [多语言电影元数据 API](https://amodb.dev/zh/multilingual-movie-metadata-api/): 支持 14 种语言的多语言电影元数据 API。使用 TMDB 语言标签，读取全部译文，回退到英语，并处理希伯来语的从右到左排版。

更新于: 2026-10-18. Source: https://amodb.dev/zh/translations/
