Перевод страницы
Опубликовать перевод, который входит в группу оригинала в том же вызове, проверить группу и подтянуть наборы данных и меню нового языка.
Перевод — отдельная страница на своём языке, связанная с оригиналом в группе переводов Polylang. Из группы печатаются hreflang и переключатель языка: страница вне группы выглядит нормально, но для обоих невидима. Ответы ниже — настоящие: их получила русская версия раздела рецептов при публикации.
1. Опубликовать перевод
Возьмите документ оригинала и поменяйте четыре вещи: lang — на язык перевода, translation_of — на оригинал (id, слаг или путь), текст, а id уберите совсем. url оставьте без языкового префикса: /ru/ Polylang добавит сам, а родитель на этом языке уже должен существовать.
---
name: "Рецепты"
excerpt: "Короткие пошаговые разборы того, что чаще всего делают через API v2."
slug: "recepty"
template: "docs"
status: "publish"
url: "/docs-ru/recepty/"
lang: "ru"
frame: "obolochka-dokumentaciya"
translation_of: 6349
---
На этом сайте у русского корня документации свой слаг, docs-ru, поэтому его дети лежат под /docs-ru/; на сайте, где переведённый раздел сохраняет слаг оригинала, url совпадает с оригинальным. Публикуется это через POST /pages/markdown, как любая другая страница.
{
"success": true,
"updated": false,
"id": 6356,
"status": "publish",
"lang": "ru",
"parent": 6231,
"url": "/docs-ru/recepty/",
"link": "https://test.onpress.pro/ru/docs-ru/recepty/",
"visible": true,
"translations": { "ru": 6356, "en": 6349 },
"translation_group": { "origin": { "id": 6349, "lang": "en" }, "term_id": 150, "created": true, "changed": true, "unlinked": [] },
"frame": { "id": "af33214f168f8efd", "slug": "obolochka-dokumentaciya", "meta_key": "_onpress_frame" },
"…": "…"
}
Страница пишется и связывается в одной транзакции: translation_of, который не сходится, — это 422 translation_link_failed с reason (lang_required, origin_not_found, origin_has_no_language, same_language, polylang_missing), и страница не создаётся. В translations должны быть оба языка. Повторная публикация того же перевода вернёт translation_group.changed: false. Третий язык входит в ту же группу — всегда указывайте в translation_of один и тот же оригинал.
2. Не отправлять id оригинала
Единственная ошибка, которая раньше затирала оригиналы: взять выгруженную шапку с id и поменять только lang. Такой запрос отклоняется до любой записи.
{
"success": false,
"error": "lang_mismatch",
"message": "page #6349 belongs to language en, ru requested; to publish a translation use \"translation_of\": 6349 instead of \"id\"",
"id": 6349,
"page_lang": "en",
"requested_lang": "ru"
}
id в шапке перевода уместен только после того, как перевод создан, и только свой. Выгрузка GET /wp-json/onpress/v1/pages/{id}/markdown?as=translation_source сразу даёт документ с translation_of вместо id.
3. Проверить группу
GET /pages/{ref}/translations показывает группу с любой её страницы. {ref} — id, слаг или путь с ~ вместо /.
curl -s -H "Authorization: Bearer $OP_TOKEN" -H "X-OnPress-Blog-Id: 233" "$BASE/pages/6349/translations"
{
"success": true,
"blog_id": 233,
"page": { "id": 6349, "lang": "en", "title": "Recipes" },
"translations": { "en": 6349, "ru": 6356 },
"pages": {
"en": { "id": 6349, "title": "Recipes", "status": "publish", "url": "/docs/recepty/", "link": "https://test.onpress.pro/docs/recepty/" },
"ru": { "id": 6356, "title": "Рецепты", "status": "publish", "url": "/ru/docs-ru/recepty/", "link": "https://test.onpress.pro/ru/docs-ru/recepty/" }
},
"missing_languages": []
}
missing_languages — языки сайта, для которых в группе ещё нет страницы.
4. Связать уже существующие страницы
Если обе страницы уже опубликованы, группа задаётся напрямую через PUT /pages/{ref}/translations. Карта — это вся группа: страница, которая в ней была, а в карте отсутствует, из группы выходит.
curl -s -X PUT -H "Authorization: Bearer $OP_TOKEN" -H "X-OnPress-Blog-Id: 240" -H 'Content-Type: application/json' \
"$BASE/pages/6703/translations" -d '{"translations": {"en": 6703, "ru": "/ru/about/"}}'
{
"success": true,
"blog_id": 240,
"page": { "id": 6703 },
"translations": { "en": 6703, "ru": 6711 },
"changed": true,
"group": { "term_id": 912, "created": true },
"unlinked": [],
"deleted_groups": [],
"content_saved": [6703, 6711]
}
Повтор той же карты ничего не делает и отвечает changed: false. Страница, чей язык не совпадает с ключом, или страница, которая уже состоит в другой группе, отклоняются с 409 (translations_rejected, page_in_other_group) до любой записи. Чтобы добавить один язык и сохранить остальные, есть POST /pages/{ref}/translations/{lang} с {"page": …}.
5. Перевести данные
Наборы данных тоже бывают по языкам. PUT /data/<name> с lang сохраняет вариант рядом с общим списком; повторитель на странице этого языка читает его, остальные языки читают общий.
curl -s -X PUT -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/data/footer_legal" -d '{
"blog_id": 235,
"lang": "ru",
"items": [
{ "text": "Политика конфиденциальности", "url": "/privacy/" },
{ "text": "Условия использования", "url": "/terms/" }
]
}'
Чтение с lang возвращает этот вариант, а option показывает, где он лежит:
curl -s -H "Authorization: Bearer $OP_TOKEN" "$BASE/data/footer_legal?blog_id=235&lang=ru"
{
"success": true,
"blog_id": 235,
"name": "footer_legal",
"origin": "site",
"contextual": false,
"option": "onpress_dataset_footer_legal__ru",
"lang": "ru",
"total": 2,
"items": [
{ "text": "Политика конфиденциальности", "url": "/privacy/" },
{ "text": "Условия использования", "url": "/terms/" }
],
"…": "…"
}
GET /data показывает по записи на каждый вариант, у каждой свой lang. Язык без своего варианта читает общий список и сообщает об этом в lang_fallback.
6. Дать языку его меню
Меню ставится в область темы для конкретного языка через PUT /menus/{ref}/location. С lang пишется карта Polylang; для языка по умолчанию заодно пишется и собственная карта темы. Все фреймы с op/menu перепекаются в том же вызове.
curl -s -X PUT -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/menus/header-ru/location" -d '{"blog_id": 233, "location": "header", "lang": "ru"}'
{
"success": true,
"blog_id": 233,
"theme": "onpress-v2",
"menu": { "id": 107, "name": "header ru", "slug": "header-ru" },
"assigned": { "location": "header", "theme": "onpress-v2", "lang": "ru", "polylang": true, "verified": true },
"rebaked": { "status": "ok", "…": "…" }
}
GET /menus?blog_id=233 показывает итог по каждому меню, например "assigned": [{"location": "header", "lang": "ru"}]; GET /data/menu.header?lang=ru возвращает пункты, которые напечатает русская страница.
7. Починить страницу без языка
Страница, созданная без языка на многоязычном сайте, не открывается: WordPress редиректит её саму на себя, хотя API ответил 200. POST /pages/language ставит термин языка; сначала попробуйте с dry_run.
curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/pages/language" -d '{"blog_id": 233, "missing": true, "dry_run": true}'
{
"success": false,
"error": "nothing_to_update",
"message": "nothing to change: pass \"pages\" with the links, or \"missing\": true to fix every page without a language"
}
Это здоровый ответ: у всех страниц сайта язык уже есть, чинить нечего. Когда есть что, ответ перечисляет каждую страницу с "lang": {"from": null, "to": "en"}; чтобы поставить не язык по умолчанию, передайте pages с конкретными id или путями и lang.
Проверка
GET /pages/{ref}/translations с любой из страниц показывает оба языка и пустой missing_languages. У оригинала и перевода есть ссылки hreflang друг на друга, и переключатель языка на каждой ведёт на другую. Переведённая страница печатает меню и данные своего языка.
См. также
- Переводы — все ручки переводов и их ошибки.
- Страницы и markdown —
lang,translation_of,link_softи правила поиска страницы. - Данные — языковые варианты наборов.
- Меню — пункты меню и области темы.