Перейти к содержанию

Редактор переводов

Эндпоинты, лежащие в основе редактора переводов Admin Next. Они позволяют просматривать все строки перевода, поставляемые ядром Grav, плагинами и темами, видеть полноту каждого языка и переопределять любую строку для этого сайта. Переопределения хранятся отдельно для каждого языка в user/languages/<lang>.yaml.

Эти маршруты находятся под /i18n, а не под /translations, и требуют аутентификации. Публичный эндпоинт Получение переводов (GET /translations/{lang}) — это другое: он представляет собой собственный словарь админки, отдаётся без аутентификации и заполняется из английского, поэтому не может отличить отсутствующую строку от строки, переведённой теми же словами. Редактор читает источники напрямую, чтобы отсутствующая строка выглядела как отсутствующая.

Разрешения: api.translations.read для чтения, api.translations.write для сохранения переопределений, машинного перевода и импорта. Демо-учётные записи получают 403 при любой записи.

Состояния ячеек

У каждого ключа в редакторе есть ячейка для каждого языка с полем value, значением shipped (что даёт источник, или null) и полем state:

Состояние Значение
shipped Значение приходит из файла языка плагина, темы или ядра
overridden У этого сайта есть собственное значение в user/languages/<lang>.yaml
missing Ни один источник не поставляет ключ на этом языке и переопределения нет, поэтому посетители видят запасное значение

Поле known строки равно false, когда ключ вообще не поставляется ни одним источником и назван только переопределением сайта, например из-за опечатки или строки из удалённого плагина. Такие строки выводятся, чтобы их можно было найти и исправить.

Коды языков

Коды языков должны иметь вид en, fr, pt-BR или zh-Hant. На маршрутах /i18n/overrides/{lang} несоответствующий код даёт 422. Параметры запроса, такие как lang и source_lang, вместо этого откатываются к языку редактора по умолчанию: к языку сайта по умолчанию, если его поставляет какой-либо источник, иначе к en, иначе к первому языку, который поставляет какой-либо источник.

Переход с translation-strings

Сайты, использовавшие плагин translation-strings, могут перенести его переопределения с помощью Состояния импорта и Импорта строк перевода. Пока этот плагин включён, его значения по-прежнему важнее user/languages, поэтому сначала выполните импорт, проверьте результат, а затем выключите плагин.

Список языков

GET /i18n/languages

Все коды языков, которые поставляет какой-либо источник, каждый с флагом наличия файла переопределений для него на этом сайте, плюс язык редактора по умолчанию. Требуется api.translations.read.

Ответ

{"data": {"default": "en", "languages": [{"code": "de", "has_overrides": false}, {"code": "en", "has_overrides": true}, {"code": "fr", "has_overrides": false}]}}

Коды ответов

Код Описание
200 Языки возвращены.
401 Не авторизован.
403 Нет разрешения api.translations.read.

Список источников

GET /i18n/sources

Каждый источник (ядро Grav, плагины, темы и собственные переопределения этого сайта), поставляющий хотя бы одну строку на запрошенном языке, с пространствами имён ключей, которые он добавляет. Это питает панель просмотра редактора. Требуется api.translations.read.

Параметры

Имя Тип Обязательный Описание
lang string Нет Язык, на котором считать ключи. Неверный или отсутствующий код откатывается к языку редактора по умолчанию.

Ответ

{"data": {"lang": "en", "providers": [{"id": "theme:quark", "kind": "theme", "slug": "quark", "label": "Quark", "enabled": true, "key_count": 42, "namespaces": [{"name": "THEME_QUARK", "key_count": 42}]}]}}

Коды ответов

Код Описание
200 Источники возвращены.
401 Не авторизован.
403 Нет разрешения api.translations.read.

id источника — system:core, plugin:<slug>, theme:<slug> или user:overrides, а kind — system, plugin, theme или user. enabled сообщает, включён ли плагин или является ли тема активной; для ядра и переопределений сайта он всегда true. Передайте id в параметре provider для Списка ключей, чтобы увидеть строки этого источника.


Полнота перевода

GET /i18n/coverage

Для каждого языка — сколько ключей исходного языка он имеет (поставляемых или переопределённых) и сколько отсутствует. Требуется api.translations.read.

Параметры

Имя Тип Обязательный Описание
source_lang string Нет Опорный язык. Неверный или отсутствующий код откатывается к языку редактора по умолчанию.

Ответ

{"data": {"source_lang": "en", "coverage": [{"code": "fr", "total": 1868, "translated": 1702, "missing": 166, "overridden": 3}]}}

Коды ответов

Код Описание
200 Полнота возвращена.
401 Не авторизован.
403 Нет разрешения api.translations.read.

total — число ключей на исходном языке, а translated и missing считаются только по этому набору ключей, поэтому устаревший ключ, который несёт лишь старый перевод, не учитывается. overridden — число переопределений сайта на этом языке для любых ключей.


Список ключей

GET /i18n/keys

Матрица редактора: одна строка на ключ, отсортированная по ключу, со значением на исходном языке и ячейкой для каждого запрошенного языка. Ключи, существующие только как переопределения сайта, включаются, чтобы их можно было исправить. Требуется api.translations.read.

Параметры

Имя Тип Обязательный Описание
source_lang string Нет Опорный язык. Неверный или отсутствующий код откатывается к языку редактора по умолчанию.
langs string Нет Коды языков через запятую для включения в виде ячеек, например en,fr,de. Коды, которые не поставляет ни один источник, игнорируются; по умолчанию только исходный язык.
q string Нет Поисковый текст, сопоставляемый без учёта регистра с ключом и значением на исходном языке.
provider string Нет Только ключи, поставляемые этим id источника, например theme:quark (см. Список источников).
namespace string Нет Только ключи, равные этому префиксу с точками или находящиеся под ним, например PLUGIN_ADMIN.
status string Нет all (по умолчанию), shipped, overridden, missing или unknown. Строка подходит, когда ячейка любого запрошенного языка имеет это состояние; unknown совпадает с ключами, которые не поставляет ни один источник.
page integer Нет Номер страницы (по умолчанию 1).
per_page integer Нет Строк на странице (по умолчанию 20, максимум 500).

Ответ

{"data": [{"key": "THEME_QUARK.SEARCH", "namespace": "THEME_QUARK", "source_value": "Search", "providers": ["theme:quark"], "owner": "theme:quark", "known": true, "values": {"en": {"value": "Search", "state": "shipped", "shipped": "Search"}, "fr": {"value": "Rechercher", "state": "overridden", "shipped": "Recherche"}}}], "meta": {"pagination": {"page": 1, "per_page": 20, "total": 1, "total_pages": 1}}, "links": {"self": "/api/v1/i18n/keys?page=1&per_page=20"}}

Коды ответов

Код Описание
200 Строки возвращены.
401 Не авторизован.
403 Нет разрешения api.translations.read.

q сопоставляется со значением так же, как с ключом, потому что люди знают слова на экране, а не ключи за ними. source_value — переопределение сайта на исходном языке, если оно есть, иначе поставляемое значение. providers перечисляет все источники, поставляющие ключ, а owner — тот, чьё значение побеждает во время выполнения. Состояния ячеек см. во введении к разделу.

Ссылки links для постраничной разбивки сохраняют все отправленные параметры запроса (поиск, фильтры, языки), поэтому переход по одной из них остаётся в том же отфильтрованном представлении.


Получение ключа

GET /i18n/keys/{key}

Один ключ по всем языкам, которые поставляет какой-либо источник. Неизвестный ключ всё равно возвращает 200 с known: false и ячейками missing. Требуется api.translations.read.

Параметры

Имя Тип Обязательный Описание
key string Да Ключ перевода с точками (параметр пути), например THEME_QUARK.SEARCH. Маршрутизируются только буквы, цифры, _, . и -; всё остальное даёт 404.
source_lang string Нет Опорный язык для source_value. Неверный или отсутствующий код откатывается к языку редактора по умолчанию.

Ответ

{"data": {"key": "THEME_QUARK.SEARCH", "namespace": "THEME_QUARK", "source_value": "Search", "providers": ["theme:quark"], "owner": "theme:quark", "known": true, "values": {"de": {"value": "Suche", "state": "shipped", "shipped": "Suche"}, "en": {"value": "Search", "state": "shipped", "shipped": "Search"}, "fr": {"value": "Rechercher", "state": "overridden", "shipped": "Recherche"}}}}

Коды ответов

Код Описание
200 Ключ возвращён.
401 Не авторизован.
403 Нет разрешения api.translations.read.
404 Ключ содержит символы за пределами маршрутизируемого набора.

Получение переопределений

GET /i18n/overrides/{lang}

Файл переопределений сайта для одного языка (user/languages/<lang>.yaml) в виде YAML — для расширенного редактора. Без namespace это необработанный текст файла или пустая строка, когда файла нет. С namespace возвращаются только переопределения под этим префиксом, заново выгруженные как вложенный YAML, поэтому «редактировать как YAML» охватывает только то, что на экране. Требуется api.translations.read.

Параметры

Имя Тип Обязательный Описание
lang string Да Код языка (параметр пути), например fr.
namespace string Нет Префикс ключей с точками, которым ограничивается вывод, например THEME_QUARK.

Ответ

{"data": {"lang": "fr", "scoped": true, "namespace": "THEME_QUARK", "count": 1, "yaml": "THEME_QUARK:\n  SEARCH: Rechercher\n"}}

Коды ответов

Код Описание
200 Переопределения возвращены.
401 Не авторизован.
403 Нет разрешения api.translations.read.
422 Неверный код языка.

scoped равно true, когда был передан namespace, а count — число включённых переопределений. Сохраните отредактированный текст обратно через Замену переопределений, передав тот же namespace.


Обновление переопределений

PATCH /i18n/overrides/{lang}

Встроенные правки переопределений одного языка. set записывает значения, а unset удаляет переопределения, чтобы снова отображалось поставляемое значение. Отправляет X-Invalidates: i18n:update, translations:update. Требуется api.translations.write; демо-учётные записи получают 403.

Параметры

Имя Тип Обязательный Описание
lang string Да Код языка (параметр пути), например fr.
source_lang string Нет Параметр запроса: опорный язык для source_value в возвращаемых строках. Неверный или отсутствующий код откатывается к языку редактора по умолчанию.
set object Нет Объект «ключ с точками → новое значение». Должен быть объектом: JSON-массив даёт 422. Числовые ключи внутри объекта игнорируются.
unset array Нет Ключи, чьё переопределение следует удалить. Элементы, не являющиеся строками, игнорируются.

Запрос

{"set": {"THEME_QUARK.SEARCH": "Rechercher"}, "unset": ["PLUGIN_ADMIN.TITLE"]}

Ответ

{"data": {"written": {"THEME_QUARK.SEARCH": "Rechercher"}, "removed": ["PLUGIN_ADMIN.TITLE"], "reverted": [], "unknown": [], "rows": [{"key": "THEME_QUARK.SEARCH", "namespace": "THEME_QUARK", "source_value": "Search", "providers": ["theme:quark"], "owner": "theme:quark", "known": true, "values": {"fr": {"value": "Rechercher", "state": "overridden", "shipped": "Recherche"}}}, {"key": "PLUGIN_ADMIN.TITLE", "namespace": "PLUGIN_ADMIN", "source_value": "Title", "providers": ["plugin:admin"], "owner": "plugin:admin", "known": true, "values": {"fr": {"value": "Titre", "state": "shipped", "shipped": "Titre"}}}]}}

Коды ответов

Код Описание
200 Переопределения сохранены.
401 Не авторизован.
403 Нет разрешения api.translations.write или это демо-учётная запись.
422 Неверный код языка, set не является объектом, unset не является массивом, либо оба пусты.

Значение set, равное тому, что поставляет источник, сохраняется как удаление, а не как переопределение, поэтому файл содержит только реальные отличия и продолжает следовать будущим формулировкам источника. Такие ключи перечислены в reverted. Ключи, которые не поставляет ни один источник, всё равно записываются и перечисляются в unknown.

written содержит ключи, сохранённые как переопределения, с их значениями, а removed — ключи, чьё существующее переопределение было удалено. rows содержит свежую строку матрицы для каждого затронутого запросом ключа, только с ячейкой этого языка, чтобы редактор мог обновить её на месте.


Замена переопределений

PUT /i18n/overrides/{lang}

Сохранение в расширенном режиме. Разбирает yaml (отображение, вложенное или с ключами с точками) и заменяет им переопределения языка. Отправляет X-Invalidates: i18n:update, translations:update. Требуется api.translations.write; демо-учётные записи получают 403.

Параметры

Имя Тип Обязательный Описание
lang string Да Код языка (параметр пути), например fr.
yaml string Да YAML-отображение ключей в строки. YAML-список даёт 422. Пустая строка удаляет все переопределения в области действия.
namespace string Нет Префикс ключей с точками, которым ограничивается замена. Опустите его или передайте пустую строку, чтобы заменить весь файл.

Запрос

{"yaml": "THEME_QUARK:\n  SEARCH: Rechercher\n", "namespace": "THEME_QUARK"}

Ответ

{"data": {"count": 1, "dropped": [], "unknown": [], "removed": 0}}

Коды ответов

Код Описание
200 Переопределения сохранены.
401 Не авторизован.
403 Нет разрешения api.translations.write или это демо-учётная запись.
422 Неверный код языка, отсутствует yaml, YAML не разбирается или не является отображением, либо сохранение с областью действия называет ключи вне пространства имён.

С namespace заменяются только переопределения под этим префиксом, а всё остальное в файле сохраняется. Именно это делает безопасным сохранение отфильтрованного представления: сохранение строк одной темы без области действия удалило бы все остальные переопределения. Ключ вне пространства имён проваливает всё сохранение с 422, называющим ключи вне области действия (до пяти), а не с ошибкой разбора.

Значения, равные поставляемому, не сохраняются и перечисляются в dropped. Ключи, которые не поставляет ни один источник, сохраняются и перечисляются в unknown, а не отклоняются, поэтому опечатка будет замечена, а не проигнорирована. count — число переопределений, сохранённых из этого YAML, а removed — на сколько меньше переопределений в области действия стало.


Состояние перевода

GET /i18n/translate

Доступен ли машинный перевод через плагин AI Translate и, если нет, почему. Редактор скрывает свои действия перевода, когда он недоступен. Требуется api.translations.read.

Ответ

{"data": {"available": false, "installed": true, "enabled": true, "reason": "not_configured", "max_keys": 200}}

Коды ответов

Код Описание
200 Состояние возвращено.
401 Не авторизован.
403 Нет разрешения api.translations.read.

reason равен null, когда available равно true, иначе not_installed, not_enabled или not_configured (у плагина нет настроенного провайдера), чтобы клиент мог подсказать владельцу сайта, что делать. max_keys — максимальное число ключей, принимаемое одним запросом Перевода ключей.


Перевод ключей

POST /i18n/translate

Отправляет исходные значения до 200 ключей в плагин AI Translate и возвращает предложенные переводы. Ничего не записывается: просмотрите предложения и сохраните нужные через Обновление переопределений. Требуется api.translations.write, так как это расходует кредиты провайдера; демо-учётные записи получают 403.

Параметры

Имя Тип Обязательный Описание
target_lang string Да Язык, на который переводить, например fr.
keys array Да Ключи для перевода, от 1 до 200. Элементы, не являющиеся строками, игнорируются.
source_lang string Нет Язык, с которого переводить. По умолчанию язык редактора по умолчанию и должен отличаться от target_lang.

Запрос

{"source_lang": "en", "target_lang": "fr", "keys": ["THEME_QUARK.SEARCH", "PLUGIN_ADMIN.TITLE"]}

Ответ

{"data": {"source_lang": "en", "target_lang": "fr", "proposals": [{"key": "THEME_QUARK.SEARCH", "source": "Search", "value": "Rechercher", "ok": true, "reason": null}, {"key": "PLUGIN_ADMIN.TITLE", "source": "Title", "value": "Titre", "ok": true, "reason": null}]}}

Коды ответов

Код Описание
200 Предложения возвращены.
401 Не авторизован.
403 Нет разрешения api.translations.write или это демо-учётная запись.
422 Машинный перевод недоступен, отсутствует target_lang или keys, ключей нет или их больше 200, исходный и целевой языки совпадают, либо вызов провайдера не удался.

Заполнители маскируются перед отправкой текста и проверяются, когда он возвращается. Предложения приходят в том порядке, в котором были отправлены ключи. Предложение с ok: false имеет null в value и одно из следующих значений reason:

Причина Значение
no_source У ключа нет значения на исходном языке
icu_needs_human Сообщение ICU, которое должен перевести человек
nothing_to_translate В значении нет переводимого текста, только заполнители или разметка
provider_returned_nothing Провайдер вернул пустой результат
placeholders_mangled Провайдер изменил заполнитель, поэтому предложение отклонено

Первые три определяются до вызова провайдера, поэтому ничего не стоят.


Состояние импорта

GET /i18n/import/translation-strings

Что настроено в старом плагине translation-strings и что даст его импорт для каждого языка. Только чтение. Требуется api.translations.read.

Ответ

{"data": {"present": true, "plugin_enabled": true, "config_path": "/var/www/grav/user/config/plugins/translation-strings.yaml", "pending": 4, "total": 6, "languages": [{"code": "fr", "total": 6, "new": 3, "already": 1, "conflict": 1, "shipped": 1, "unknown": 0, "keys": [{"key": "THEME_QUARK.SEARCH", "status": "new", "unknown": false, "current": null, "value": "Rechercher"}]}]}}

Коды ответов

Код Описание
200 Предпросмотр импорта возвращён.
401 Не авторизован.
403 Нет разрешения api.translations.read.
422 В конфигурации плагина есть код языка, который редактор не может сохранить.

present равно true, когда в плагине настроено хотя бы одно переопределение, а plugin_enabled важен, потому что пока плагин включён, его значения по-прежнему важнее user/languages. pending считает ключи, которые запишет импорт (new плюс conflict). config_path — абсолютный путь к файлу конфигурации плагина; демо-учётные записи получают вместо него (hidden in demo mode).

Для каждого языка ключи new ещё не имеют переопределения, ключи already переопределены тем же значением, ключи conflict переопределены другим значением, которое импорт заменяет значением плагина, а ключи shipped равны поставляемому значению, поэтому импорт ничего не сохраняет. Счётчики точны, но keys перечисляет не более 50 ключей на язык. В каждом перечисленном ключе current — существующее переопределение сайта (или null), а value — значение плагина.


Импорт строк перевода

POST /i18n/import/translation-strings

Объединяет все переопределения, настроенные в плагине translation-strings, с user/languages/<lang>.yaml. Переопределения других ключей сохраняются; там, где оба называют один и тот же ключ, побеждает значение плагина, потому что именно его сайт показывает сейчас. Отправляет X-Invalidates: translations:update. Требуется api.translations.write; демо-учётные записи получают 403.

Ответ

{"data": {"imported": 4, "reverted": 1, "unknown": [], "languages": [{"code": "fr", "written": 4, "reverted": 1, "unknown": 0, "path": "/var/www/grav/user/languages/fr.yaml"}], "plugin_enabled": true}}

Коды ответов

Код Описание
200 Импорт завершён.
401 Не авторизован.
403 Нет разрешения api.translations.write или это демо-учётная запись.
422 В плагине не настроено ни одного переопределения, либо в его конфигурации есть код языка, который редактор не может сохранить.

Каждый код языка в конфигурации плагина проверяется до любой записи, поэтому плохой код проваливает весь импорт с 422, называющим его, и ни один язык не остаётся наполовину импортированным.

Плагин не выключается за вас. Его выключение — изменение конфигурации с собственным разрешением, поэтому сделайте это потом через Обновление конфигурации; plugin_enabled сообщает его текущее состояние. imported считает переопределения, записанные по всем языкам, reverted — значения, пропущенные из-за совпадения с поставляемым, а unknown перечисляет импортированные ключи, которые не поставляет ни один источник.