Синтез речи для TranslatePress: что работает и как

2 мин чтения 17 мин прослушивания
Синтез речи для TranslatePress: что работает и как

TranslatePress переводит готовый HTML страницы в момент запроса и хранит все переводы в локальных таблицах базы данных. У каждой статьи один ID поста, а смена языка происходит через trp_translate(), а не через дублирование постов. Этот факт меняет подход к синтезу речи на сайтах с TranslatePress.

Это пятый и последний материал в нашей серии о мультиязычном TTS. Мы уже разобрали WPML, Polylang, Weglot и GTranslate. С технической точки зрения TranslatePress занимает среднее положение между ними, и настройка аудио это отражает.

Чем TranslatePress отличается от WPML, Polylang и Weglot

WPML и Polylang создают отдельный пост для каждого языка. У каждого перевода свой ID, своё поле post_content и свой permalink. Генерация аудио прямолинейна: каждый язык — это отдельный объект WordPress.

Weglot работает иначе. Переводы хранятся на серверах Weglot и встраиваются в страницу через прокси или поддомен. Оригинальная база данных WordPress переведённый текст не видит, поэтому серверный TTS на Weglot без JavaScript-хуков практически невозможен.

TranslatePress — нечто среднее. У каждой статьи один пост, поэтому post_content содержит только язык по умолчанию. Но все переводы хранятся локально в вашей базе WordPress, в таблицах wp_trp_. Их можно читать, делать к ним запросы и передавать в TTS-движок. Это принципиально меняет подход к аудио по сравнению с любым из четырёх других плагинов.

Где хранятся переводы

TranslatePress хранит переводы в выделенных таблицах с префиксом wp_trp_. Каждая языковая пара получает собственную словарную таблицу с ключом вида wp_trp_dictionary_<source>_<target>. Есть также wp_trp_original_strings для исходных строк и таблицы gettext для переводов тем и плагинов.

Хранение направленное. Немецкий перевод английского сайта лежит в словаре «английский — немецкий». Читать его нужно в том же направлении. Ключевая публичная функция — trp_translate(): она принимает строку контента и код языка и возвращает переведённую версию.

if ( function_exists( 'trp_translate' ) ) {
    $translated = trp_translate( $post->post_content, 'de_DE' );
    // Передавайте $translated в TTS-движок, а не $post->post_content.
}

Для TTS-интеграции эта функция — единственный источник истины. Прямое чтение post_content всегда вернёт язык по умолчанию, какой бы URL ни открывал посетитель. Подробнее о том, как TTSWP это обрабатывает на своей стороне, читайте в документации по интеграции с TranslatePress.

Схема: trp_translate() преобразует один post_content в три локализованных аудиовыхода
Один ID поста, один post_content — и множество аудиовыходов на разных языках через trp_translate().

Ловушка с кодами локали

TranslatePress использует полные коды локали, а не короткие slug-и. Немецкий — это de_DE, а не de. Французский — fr_FR. Бразильский португальский — pt_BR. Любая интеграция, рассчитанная на двухбуквенные slug-и в стиле Polylang, молча сломается на TranslatePress.

Документация для разработчиков TranslatePress прямо об этом говорит. Код языка, передаваемый в trp_translate(), — это локаль из настроек TranslatePress, и она не обязательно совпадает с языковым slug-ом в URL. Короткий slug вроде de не найдёт словарь, и функция молча вернёт исходную строку. Если вы пишете собственный код, нормализуйте коды языка перед вызовом trp_translate() и сохраняйте тот же формат локали рядом с аудиофайлами, чтобы потом их правильно сопоставлять.

Структура URL и кэширование

По умолчанию TranslatePress использует подпапку для каждого языка. Английская страница доступна по адресу site.com/blog/post, немецкая — по site.com/de/blog/post. Есть также опция добавить подпапку для языка по умолчанию, чтобы все языки были симметричны.

Для кэширования это хороший вариант. Разные URL означают разные ключи кэша для каждого языка. WP Rocket, LiteSpeed и CDN-серверы обрабатывают /de/blog/post как отдельный ресурс от /blog/post, поэтому немецкий аудиофайл отдаётся вместе с немецкой страницей, а английский — с английской. Правила исключений описаны в нашей документации по кэшированию.

Единственный риск связан с платным дополнением Automatic User Language Detection. Оно перенаправляет посетителей по языку браузера, что может конфликтовать с кэшем страниц и отдавать неправильный редирект не тому пользователю. Эту же ситуацию мы разбирали в статье про Polylang. На TranslatePress такое встречается реже, потому что обнаружение языка — платная функция. Но если вы её используете, исключите логику редиректа из кэша.

Проблема перевода элементов плеера

Это особенность только TranslatePress. Плагин умеет обнаруживать и переводить строки, вставленные через JavaScript, — что редкость. Большинство инструментов перевода игнорируют контент, отрисованный JS. TranslatePress перехватывает его в DOM после рендеринга и предлагает перевести.

Побочный эффект: подписи кнопок плеера — «Play», «Pause», «Listen to this article» — появляются в редакторе TranslatePress как переводимые строки. Если перевести их машинно без проверки, кнопки плеера могут получить неловкий или ошибочный текст. Хуже того — неправильно переведённые ARIA-метки сбивают с толку скринридеры.

TranslatePress предлагает два способа это исправить. Добавьте атрибут data-no-translation к любому элементу, который не нужно переводить. Или укажите CSS-селекторы в разделе Advanced Settings, чтобы исключить целые контейнеры. Оба способа описаны в настройках TranslatePress. Для плеера TTSWP исключите обёртку плеера по классу — тогда метки будут управляться языковыми файлами самого плагина.

Что нужно исключить

  • Контейнер аудиоплеера
  • ARIA-метки кнопок воспроизведения, паузы и управления прогрессом
  • Отображение времени и продолжительности
  • Названия голосов и языков, отображаемые TTSWP

Если после исключения вы хотите изменить стиль плеера, нужные селекторы описаны в нашей документации по кастомному CSS.

Проблема рассинхронизации после редактирования

TranslatePress привязывает каждый перевод к точной исходной строке. Если вы изменили оригинал, TranslatePress создаёт новую исходную строку и отвязывает существующий перевод. Translation Memory предложит старый перевод обратно, но пока человек его не подтвердит, целевой язык откатится к оригиналу.

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

Чеклист после редактирования контента:

  1. Подтвердите новую исходную строку в редакторе TranslatePress для каждого активного языка.
  2. Перегенерируйте аудио для поста на языке по умолчанию.
  3. Перегенерируйте аудио для каждого языка, затем прослушайте аудио на каждом локализованном URL и убедитесь, что новый файл соответствует видимому тексту.
  4. Очистите кэш страниц для каждого локализованного URL, а не только для языка по умолчанию.

Настройка TTSWP на сайте с TranslatePress

Вот текущий порядок действий. В документации по интеграции всегда описано актуальное поведение.

  1. Установите TTSWP из каталога плагинов WordPress.org. Пошаговая инструкция — в руководстве по установке.
  2. Подключите плагин к бэкенду TTSWP. Бесплатный план включает стартовые кредиты — вы сможете протестировать весь процесс до оплаты. Подробнее в разделе подключение сайта.
  3. Убедитесь, что TranslatePress активен и хотя бы один целевой язык настроен с полным кодом локали.
  4. Назначьте голос каждому языку через сопоставление языка и голоса. Привяжите немецкий голос к de_DE, французский — к fr_FR и так далее. Каталог голосов — в разделе выбор голоса.
  5. Опубликуйте или обновите пост. Аудио сначала генерируется для языка по умолчанию.
  6. Прослушайте аудио на каждом переведённом URL. Генерация происходит по запросу. Когда посетитель впервые нажимает Play на странице второго языка, TranslatePress сообщает TTSWP активный язык, TTSWP генерирует файл и кэширует его. Все последующие воспроизведения используют кэшированный файл.
  7. Исключите плеер из перевода TranslatePress с помощью data-no-translation или CSS-селектора в Advanced Settings — тогда метки плеера будут управляться языковыми файлами TTSWP.

TTSWP хранит один аудиофайл на каждый пост и язык, а плеер загружает файл, соответствующий языку текущего URL. На /de/blog/post плеер загружает немецкий файл, на URL по умолчанию — файл языка по умолчанию. При активном автоматическом переводе TTSWP читает переведённый текст напрямую из TranslatePress перед отправкой в ElevenLabs, поэтому аудио совпадает с тем, что видит посетитель.

Бесплатная и платная версии TranslatePress для TTS

Бесплатный TranslatePress поддерживает один дополнительный язык, включает перевод 2000 слов через TranslatePress AI и позволяет использовать Google Translate с вашим собственным API-ключом. Этого достаточно для двуязычного блога с соответствующим аудио на обоих языках.

Платный TranslatePress добавляет неограниченное количество языков, SEO Pack для переведённых slug-ов, мета-данных и управления hreflang, поддержку DeepL, аккаунты переводчиков, дополнение Automatic User Language Detection и разные домены для разных языков. Если сайт требует более двух языков, hreflang-тегов для поисковиков или переводов качества DeepL перед генерацией аудио — платная версия оправдана. Качество самого аудио от тарифа не зависит.

SEO и AEO при наличии аудио на каждом языке

SEO Pack позволяет настроить hreflang-теги для каждого языка с выбором конкретной локали, языка без привязки к региону или обоих вариантов. Именно это сигнализирует поисковикам и ИИ-движкам, какое аудио соответствует какому региону.

Добавьте запись схемы AudioObject для каждого языкового URL с правильным значением inLanguage, соответствующим hreflang. Google и Bing распознают языковую пару, и по нашим собственным тестам ИИ-движки — Perplexity, ChatGPT Search — чаще цитируют статьи с аудио, когда схема корректна и URL аудио отвечает. Подробнее об этом — в нашем материале про AEO и аудиоконтент.

Типичные проблемы и способы их решения

ПроблемаПричинаРешение
Аудио воспроизводится не на том языкеТекст берётся из post_content, а не из trp_translate()Передавайте текст через trp_translate( $content, $locale ) с полным кодом локали
Кнопки плеера переведены неправильноTranslatePress захватил метки плеера, вставленные через JSДобавьте data-no-translation к обёртке плеера или исключите его контейнер по CSS-селектору в Advanced Settings
Аудио пропало после редактированияИзменение исходника отвязывает переводы и, как следствие, аудио для каждого языкаПодтвердите переводы в редакторе TranslatePress, затем перегенерируйте аудио для каждого языка
Несоответствие кода локалиИнтеграция передаёт de вместо de_DEНормализуйте до полного кода локали перед вызовом trp_translate()
RTL-вёрстка сломана для арабского или ивритаCSS плеера не поддерживает RTLИспользуйте кастомный CSS для зеркального отображения элементов управления на RTL-локалях
Кэшированный редирект ведёт не на тот языкКонфликт дополнения Automatic User Language Detection с кэшем страницИсключите редирект из кэша или отключите автоопределение языка

Замечание о доступности

Аудионарратив поддерживает несколько критериев успеха WCAG при условии, что плеер управляется с клавиатуры и правильно размечен. Если вы исключили плеер из перевода TranslatePress, сохраните ARIA-метки в языковых файлах TTSWP. Наше руководство по WCAG и аудио подробно разбирает критерии, а основной туториал по настройке — хорошая отправная точка.

Часто задаваемые вопросы

Работает ли TranslatePress с синтезом речи?

Да. TranslatePress хранит переводы локально в таблицах wp_trp_, а функция trp_translate() возвращает переведённый контент на стороне сервера. TTS-интеграция может читать переведённый текст и генерировать аудио на каждом языке — при условии, что аудио привязано к ID поста плюс локаль и используются полные коды вида de_DE, а не короткие slug-и.

Нужна ли платная версия TranslatePress для аудио?

Нет. Бесплатный TranslatePress поддерживает один дополнительный язык и включает перевод через TranslatePress AI, Google Translate с собственным ключом или ручное редактирование. Этого достаточно для двуязычного сайта с аудио. Платная версия добавляет неограниченные языки, SEO Pack, DeepL и дополнения для определения языка — они нужны, если требуется более двух языков или управление hreflang.

Почему кнопки плеера переведены неправильно?

TranslatePress обнаруживает строки, вставленные через JS, поэтому метки аудиоплеера попадают в его редактор и могут быть переведены машинно. Исправьте это, добавив data-no-translation к обёртке плеера, или исключите контейнер плеера в Advanced Settings по CSS-селектору. Тогда метки будут браться из языковых файлов TTSWP.

Почему аудио перестало совпадать с переводом?

Редактирование исходной строки в TranslatePress создаёт новую строку и отвязывает существующий перевод. Translation Memory предложит его вернуть, но пока вы не подтвердите, целевой язык откатится к оригиналу. После любого редактирования перегенерируйте аудио для поста по умолчанию и каждого языка, затем очистите кэш для всех локализованных URL.

Чем TranslatePress отличается от Weglot для TTS?

Weglot хранит переводы на своих серверах и встраивает их в страницу, поэтому WordPress не видит переведённый текст на стороне сервера. TranslatePress хранит все переводы в локальной базе данных и предоставляет trp_translate() для серверного доступа. Это делает генерацию аудио на каждом языке на TranslatePress значительно проще, чем на Weglot.

Что делать дальше

Установите Синтез речи - TTSWP из каталога плагинов WordPress.org, подключите к своему аккаунту и назначьте голос для каждого языка, который вы уже используете в TranslatePress. Опубликуйте пост, прослушайте аудио на каждом переведённом URL и убедитесь, что аудио совпадает с видимым текстом. Если что-то пойдёт не так, первым делом загляните в документацию по интеграции с TranslatePress.

Синтез речи для сайтов на WPML: что реально работает

Синтез речи для сайтов на WPML: что реально работает

Как добавить синтез речи на сайт с WPML так, чтобы плагин выбирал правильный голос для каждого языка, генерировал отдельный аудиофайл для каждого перевода и корректно определял язык при AJAX-запросах.

2 мин чтения