# 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`  | query | одно из двух | Ваш ключ. Используйте его или заголовок `Authorization: Bearer`. |

### Поля ответа

| Поле                          | Тип         | Примечания                                                                                                                                           |
| ----------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                          | целое число | Id фильма.                                                                                                                                           |
| `translations`                | массив      | Одна строка на язык с текстом, отсортированы по коду языка. Фильм 550 возвращает 50 строк.                                                           |
| `translations[].iso_3166_1`   | строка      | Код страны, соответствующий языку, например `US` для `en` или `BR` для `pt`. Для языков вне 14 обслуживаемых повторяет код языка заглавными буквами. |
| `translations[].iso_639_1`    | строка      | Код языка, например `ru` или `pt`. Уникален в массиве.                                                                                               |
| `translations[].name`         | строка      | Название языка на самом этом языке.                                                                                                                  |
| `translations[].english_name` | строка      | Название языка по-английски.                                                                                                                         |
| `translations[].data`         | объект      | Переведенные поля. Ключи зависят от ресурса, см. таблицу ниже.                                                                                       |

### Пример ответа

Показаны две строки из 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/ru/movies/).

## Эндпоинты переводов и их ключи данных

У всех путей общая база `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/ru/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/ru/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/ru/errors/) и [лимиты запросов](https://amodb.dev/ru/rate-limits/).

## Практические заметки

- Один вызов заменяет до 14 вызовов деталей. Используйте его, когда нужно больше двух языков одного названия.
- Строки отсортированы по коду языка, а это не порядок приоритета. Выбирайте строки по `iso_639_1`, а не по позиции в массиве.
- Вызовы типа деталей кэшируются на CDN на 6 часов, поэтому клиентский кэш такой же длины ничего не стоит по свежести данных.
- Оригинальные названия в других письменностях, например японской или корейской, всегда доступны в `original_title` и `original_name` записи деталей.
- Чтобы добавить переводы к вызову деталей, передайте `append_to_response=translations` и читайте тот же массив из ответа. Это работает для фильмов, сериалов и серий. У добавленного блока нет `id`.

## Вопросы и ответы

### Когда использовать переводы вместо параметра language?

Используйте language, когда показываете пользователю один язык. Используйте переводы, когда нужно сразу несколько языков одного названия, например для экрана редактора, страниц на других языках или проверки покрытия. Эндпоинт также возвращает языки, которые language не обслуживает, например ja или de.

### Чем отличаются iso_639_1 и iso_3166_1?

iso_639_1 это код языка, например pt. iso_3166_1 это страна, которая к нему относится, например BR. Для языков вне 14 обслуживаемых он повторяет код языка заглавными буквами, например DA для da, поэтому всегда сопоставляйте по iso_639_1.

### Почему поле внутри data пустое?

Пустая строка или ноль означают, что для этого поля на этом языке текста нет. Не показывайте его. Переходите к следующему языку в цепочке, обычно к английскому, или к оригинальному названию.

### Какие языки охватывает эндпоинт?

Записи фильмов и сериалов перечисляют все языки, которые есть в каталоге, часто от 40 до 80 строк. Сюда входят 14 обслуживаемых: en, ru, uk, be, zh, pt, bg, he, cs, ro, fr, pl, it и es. Для серий перечислены только некоторые из этих 14.

## Связанные страницы

- [API деталей фильма](https://amodb.dev/ru/movies/): API деталей фильма с теми же путями и JSON, что в TMDB v3. Получите фильм по ID, добавьте актеров, рейтинги и настроения через append_to_response, на 14 языках.
- [API сериалов](https://amodb.dev/ru/tv-series/): API сериалов с теми же путями и JSON, что в TMDB v3. Сериал по id с сезонами, телесетями и следующей серией, а также возрастные рейтинги и сервисы просмотра.
- [API деталей человека](https://amodb.dev/ru/people/): API деталей человека с теми же путями и JSON, что в TMDB v3. Получайте актера или члена съемочной группы по ID: биография, фильмография, внешние ID, популярные.
- [API коллекций](https://amodb.dev/ru/collections/): API коллекций фильмов с путями TMDB v3: получите франшизу по ID со всеми частями, прочитайте belongs_to_collection у фильма и найдите коллекцию по названию.
- [Языки](https://amodb.dev/ru/languages/): amodb отдает названия, описания и имена на 14 языках. Передайте в language тег в стиле TMDB, например ru-RU или pt-BR; другие теги откатываются на английский.
- [Многоязычный API метаданных фильмов](https://amodb.dev/ru/multilingual-movie-metadata-api/): Многоязычный API метаданных фильмов на 14 языках. Теги языков TMDB, все переводы одним запросом, откат на английский и поддержка иврита справа налево.

Обновлено: 2026-10-18. Source: https://amodb.dev/ru/translations/
