Как перевести файлы .po Drupal с помощью ИИ

Большинство людей ассоциируют файлы .po с WordPress, но формат gettext появился за десятилетия до WordPress и обеспечивает перевод интерфейса во всем мире открытого исходного кода. Drupal — один из крупнейших его пользователей. Если вы управляете многоязычным сайтом Drupal, каждая метка меню, описание поля, сообщение об ошибке и строка модуля проходят через файлы .po точно так же, как и в WordPress, только с другим диалектом заполнителей и другим рабочим процессом импорта. И точно так же, как и в WordPress, как только ваш сайт выходит за рамки нескольких строк, ручной перевод этих файлов становится узким местом.
Это руководство о том, как переводить файлы po Drupal с помощью ИИ, не нарушая того, что делает Drupal Drupal'ом. Мы рассмотрим систему перевода Drupal, откуда на самом деле берутся строки, синтаксис заполнителей, который отличается от WordPress и абсолютно должен быть сохранен, а также полный цикл экспорта, перевода и повторного импорта, включая команды drush, которые делают его повторяемым.
Как работает система перевода Drupal
Drupal обрабатывает перевод интерфейса через основной модуль locale (иногда называемый "Перевод интерфейса" в современном Drupal). После включения он управляет таблицей базы данных исходных строк и их переводов для каждого языка, и может импортировать и экспортировать эти переводы в виде стандартных файлов gettext .po.
Административный интерфейс находится по адресу /admin/config/regional/translate. Оттуда вы можете искать непереведенные строки, редактировать их на месте и, что крайне важно, импортировать файл .po для массовой загрузки переводов или экспортировать текущее состояние в файл .po для автономного редактирования. Этот цикл экспорта/редактирования/импорта — это рабочий процесс, который мы оптимизируем.
В отличие от WordPress, где каждый плагин и тема поставляют свои собственные файлы .po и .mo в каталоге languages/, Drupal централизует строки интерфейса в своей базе данных и рассматривает .po как формат обмена. Вы экспортируете, работаете над файлом и импортируете его обратно. Шаг компиляции .mo, который требуется WordPress, обрабатывается внутренне.
Откуда берутся строки
Строки Drupal поступают из трех источников, и полный перевод должен охватывать все из них:
- Ядро поставляет тысячи переводимых строк для административного интерфейса, форм и системных сообщений.
- Модули Contrib (Views, Webform, Commerce и остальные) регистрируют свои собственные строки через функцию
t(). - Темы предоставляют строки шаблонов, метки регионов и описания настроек тем.
При экспорте из /admin/config/regional/translate вы можете ограничить экспорт переведенными, непереведенными или всеми строками. Для нового прохода перевода экспорт только непереведенных строк дает вам сфокусированный файл .po с точно той работой, которая остается.
Практическое следствие этой трехсторонней структуры: ваша работа по переводу никогда не бывает по-настоящему "завершена". Каждый раз, когда вы добавляете contrib модуль, включаете новую функцию или обновляете ядро Drupal, в таблицах локалей появляется новая порция непереведенных записей msgid. Вот почему команды Drupal рассматривают перевод как повторяющийся процесс, а не как одноразовую задачу запуска. Один и тот же цикл экспорта, перевода и повторного импорта выполняется при каждом развертывании, затрагивающем модули, и чем быстрее этот цикл, тем меньше задолженности по переводу накапливается между выпусками.
Также стоит отметить, что Drupal может автоматически загружать переводы, предоставленные сообществом, с localize.drupal.org для ядра и популярных contrib модулей. Они охватывают общие строки, но редко охватывают ваши пользовательские модули, вашу тему или специфическую для проекта фразу, которую фактически использует ваш сайт. Разрыв между переводом сообщества и полностью локализованным сайтом — это именно та работа, которую быстро устраняет ИИ.
Заполнители Drupal — это не заполнители WordPress
Вот самое важное, что нужно понять, прежде чем отправлять любой файл .po Drupal переводчику ИИ: Drupal не использует заполнители в стиле printf %s и %1$s, которые преобладают в WordPress. Функция t() Drupal использует три различных префикса заполнителей, каждый с разным поведением экранирования:
@variable— значение экранируется HTML, безопасное значение по умолчанию для текста, предоставляемого пользователем.%variable— значение экранируется и заключается в теги выделения<em>.:placeholder— используется для атрибутов URL, проходит через санитаризацию URL.
Типичная исходная строка Drupal выглядит так в экспортированном файле .po:
#: core/modules/node/node.module
msgid "@count comments"
msgid_plural "@count comments"
msgstr[0] ""
msgstr[1] ""
#: core/modules/user/user.module
msgid "Welcome @name, you last logged in on %date."
msgstr ""
Если переводчик изменит @count на @cuenta, заменит @name переведенным словом "name" или вставит пробел, превратив @count в @ count, заполнитель перестанет соответствовать тому, что передает вызов t(). Тогда Drupal выведет буквальный токен @count на страницу вместо фактического числа. Перевод выглядит завершенным, но сайт явно не работает.
Это тот же класс ошибок, который встречается в строках WordPress %s, и мы подробно рассматриваем общий принцип в статье как переводить PO-файлы, не нарушая кодовые переменные. Особенность Drupal заключается лишь в том, что существует три стиля заполнителей вместо одного, и инструмент перевода должен распознавать их все.
Почему универсальные переводчики здесь не справляются
Вставьте эту строку node.module в обычный ящик машинного перевода, и вы часто получите искаженный @count, связанный с <em> %date локализованным в другой токен, или формы множественного числа, свернутые в одну. Ни один из этих инструментов не был создан с учетом семантики gettext. Они переводят текст; они не понимают, что @count — это контракт с кодом приложения.
Конвейер перевода, осведомленный о gettext, с Блокировкой синтаксиса обрабатывает @variable, %variable и :placeholder как неизменяемые токены. Они блокируются перед переводом и восстанавливаются после, так что окружающее предложение переводится, а заполнители остаются нетронутыми. Та же блокировка охватывает WordPress %s и %1$s, i18next {{name}} и встроенный HTML, поэтому один инструмент может обслуживать проекты Drupal, Symfony или Laravel так же легко, как и WordPress. Формы множественного числа Drupal через msgid_plural сохраняются как формы множественного числа, а не сглаживаются, что важно, потому что языки Drupal могут иметь от одного до шести вариантов множественного числа.
Стоит отметить и более тонкий сбой. Строки Drupal часто содержат встроенную разметку и ссылки внутри переводимого текста, например Read the <a href=":url">documentation</a>, где :url является заполнителем, а теги <a> должны сохраниться. Переводчик, который не понимает структуру, может перевести атрибут href, удалить закрывающий тег или локализовать имя заполнителя. Контекстно-ориентированный ИИ, который читает всю строку как единое целое, в сочетании с блокировкой токенов, сохраняет как разметку, так и контракт :url нетронутыми, переводя только удобочитаемый текст "documentation" между ними.
Цикл экспорта, перевода, повторного импорта
Повторяемый рабочий процесс состоит из трех этапов, и drush делает экспорт и импорт скриптуемыми, так что вам не придется каждый раз нажимать кнопки в административном интерфейсе.
Шаг 1: Экспорт файла PO
Вы можете экспортировать из пользовательского интерфейса по адресу /admin/config/regional/translate, выбрав язык и область экспорта, или сделать это из командной строки. Модуль locale предоставляет экспорт через службы перевода Drupal, и большинство команд скриптуют его. Типичный вызов drush для запуска импорта перевода (обратное действие, которое мы используем на третьем шаге) выглядит так:
# Re-import a translated PO file for Spanish, overwriting customized strings
drush locale:import es /var/www/translations/es-untranslated.po \
--type=customized --override=all
# Rebuild caches so the new strings render immediately
drush cache:rebuild
Что касается экспорта, то административная форма экспорта создает файл .po; многие команды оборачивают службу экспорта локалей в небольшую пользовательскую команду Drush для полной автоматизации. В любом случае вы получите стандартный файл gettext .po, содержащий ваши непереведенные записи msgid.
Шаг 2: Перевод файла
Это этап, на котором ИИ заменяет часы ручного редактирования. Загрузите экспортированный файл .po в облачный переводчик, выберите целевой язык и дайте ему обработать. Поскольку файлы .po Drupal для большого сайта регулярно превышают 10 МБ после объединения ядра, contrib и тем, Умное пакетирование здесь важно: файл разбивается на части, переводится и собирается заново без того, чтобы вы делили его вручную или сталкивались с ограничениями по размеру. В результате получается полный файл .po с заполненным каждым msgstr и каждым заполнителем @count, %date и :url точно там, где он начался.
Шаг 3: Повторный импорт в Drupal
Импортируйте переведенный файл обратно через /admin/config/regional/translate или с помощью команды drush locale:import, показанной выше, затем перестройте кэш. Drupal объединяет переводы в свои таблицы локалей, и строки немедленно появляются на всем сайте. Запускайте цикл снова всякий раз, когда вы добавляете модуль или обновляете ядро, так как каждый из них приносит новые непереведенные строки.
Одна важная деталь импорта: флаг --override управляет тем, заменяют ли входящие переводы существующие. Используйте --override=all, когда вы хотите, чтобы файл, переведенный ИИ, был авторитетным, или более консервативную настройку, если вы вручную настроили определенные строки в пользовательском интерфейсе Drupal, которые не хотите перезаписывать. Для большинства автоматизированных конвейеров, рассматривая файл .po как источник истины и переопределяя все, система остается предсказуемой: файл в системе контроля версий — это то, что отображает сайт, точка.
Для многоязычных сайтов с несколькими целевыми языками цикл выполняется один раз для каждого языка. Экспортируйте непереведенный набор, переведите его на немецкий, импортируйте; экспортируйте снова, переведите на испанский, импортируйте; и так далее. Поскольку каждый язык представляет собой независимый файл .po, вы можете запускать их параллельно, и облачный переводчик, обрабатывающий их одновременно, превращает то, что раньше было неделей работы подрядчика, в один день.
PO Drupal — один из нескольких форматов
Стоит отметить, что gettext .po — не единственный способ обработки перевода в Drupal. Сущности конфигурации и контента также могут быть обменяны как XLIFF, который является стандартом, на который опирается модуль Translation Management Tool (TMGMT) для рабочих процессов профессиональных поставщиков переводов. Если ваша локализация Drupal выполняется через XLIFF, а не через интерфейсные файлы .po, принципы сохранения заполнителей идентичны, но структура файла отличается, и мы рассматриваем этот путь в переводе файлов XLIFF для Drupal, Symfony и Angular.
Однако для уровня перевода интерфейса .po остается рабочей лошадкой. Цикл экспорта, перевода ИИ и повторного импорта превращает многодневную ручную работу в несколько минут обработки, и до тех пор, пока используемый вами инструмент действительно понимает заполнители gettext, ваши контракты @variable остаются нетронутыми, а ваш сайт Drupal остается работоспособным на каждом языке, который вы выпускаете.
Готовы переводить файлы
.poDrupal, не нарушая ни одного@variable? Попробуйте SimplePoTranslate бесплатно — кредитная карта не требуется. Бесплатный уровень поддерживает стандартные файлы gettext.poи.potс полной Блокировкой синтаксиса, так что ваши заполнители Drupal проходят точно так, как ожидает код.