Как переводить файлы XLIFF (Drupal, Symfony, Angular, iOS)

Разработчик Drupal на прошлой неделе опубликовал на Stack Overflow историю, которая тысячи раз в год повторяется в корпоративных командах локализации. Ее команда экспортировала 40-мегабайтный файл XLIFF со своего сайта Drupal. Она открыла его в текстовом редакторе, вставила фрагменты в Google Translate, заново собрала файл, импортировала обратно в Drupal — и половина страниц отказалась отображаться, потому что переведенные строки содержали некорректный XML, экранированные символы не в тех местах и сломанные теги <g>, где было уничтожено встроенное форматирование.
XLIFF не просто так является корпоративным стандартом локализации. Он основан на XML, не зависит от инструментов и поддерживает богатые метаданные, которые необходимы для серьезных проектов перевода: состояния перевода, альтернативные переводы, заметки между переводчиками и разработчиками, а также структурированную встроенную разметку. Но его гибкость делает его уязвимым к повреждению, а инструменты, безопасно работающие с файлами .po, часто не справляются с XLIFF.
В этом руководстве рассказывается о том, что отличает XLIFF, почему общие подходы к переводу его нарушают, и как правильно переводить файлы XLIFF для Drupal, Symfony, Angular и iOS — четырех платформ, где XLIFF чаще всего используется в 2026 году.
Что такое XLIFF (и почему его используют корпоративные команды)
XLIFF расшифровывается как XML Localization Interchange File Format. Это стандарт OASIS, разработанный специально для перемещения содержимого перевода между инструментами — системами управления контентом, базами данных памяти переводов, CAT-инструментами и платформами локализации. В отличие от файлов Gettext .po (которые хранят плоские пары ключ-значение) или файлов локали JSON (которые могут быть произвольно вложенными), XLIFF — это структурированный XML-документ со стандартизированной схемой.
XLIFF 1.2 против XLIFF 2.0
В реальном мире существуют две версии, и они не полностью совместимы.
XLIFF 1.2 — это более старая, более широко используемая версия. Она использует элементы <trans-unit> для обертывания переводимого содержимого, с дочерними элементами <source> и <target>. Встроенное форматирование использует парные теги <g>, <x> и <bpt> / <ept>. Translation Management Tool Drupal и многие старые платформы по-прежнему экспортируют 1.2.
XLIFF 2.0 — это пересмотр 2014 года, более простой и чистый. Он использует <unit> и <segment> с <source> и <target>. Встроенная разметка использует <pc> (парный код) и <ph> (заполнитель). Компонент переводчика Symfony и современные экспорты iOS по умолчанию используют 2.0.
Инструмент перевода, который обрабатывает 1.2, не обрабатывает автоматически 2.0. Словари тегов отличаются, и правила экранирования немного различаются. Всегда проверяйте, какую версию экспортирует ваша платформа, прежде чем выбирать конвейер перевода.
Анатомия единицы XLIFF
Минимальная единица trans-unit XLIFF 1.2 выглядит так:
<trans-unit id="msg_welcome" datatype="plaintext">
<source>Welcome, <g id="1">%name%</g>!</source>
<target state="needs-translation">Welcome, <g id="1">%name%</g>!</target>
<note>Displayed on the homepage after login</note>
</trans-unit>
<g id="1"> оборачивает переменную-заполнитель. Атрибут state сообщает платформе, что эта строка нуждается в переводе. <note> — это подсказка для разработчика. Переводчик, понимающий XLIFF, должен получить следующее:
<target state="translated">¡Bienvenido, <g id="1">%name%</g>!</target>
Переводчик, который рассматривает файл как обычный текст, может получить любой из этих поврежденных вариантов:
<target>¡Bienvenido, <g id="1">%nombre%</g>!</target>
<target>¡Bienvenido, <g id="1">%name%</g>!</target>
<target>¡Bienvenido, %name%!</target>
Каждый из них по-разному нарушает импорт. Первый переименовывает переменную. Второй экранирует XML. Третий полностью отбрасывает тег форматирования.
Плохие решения (почему нельзя просто переводить XML)
Большинство команд начинают с одних и тех же трех подходов и тратят несколько дней, прежде чем сдаться.
Передача XLIFF в общий ИИ
Скопируйте файл, вставьте в Claude или ChatGPT, попросите перевести. Модель обычно неплохо справляется с текстом, но непоследовательно обрабатывает теги XLIFF. Иногда она сохраняет теги <g>, иногда переводит атрибут id, иногда полностью их удаляет. Проверка завершается неудачей. Ваш импорт выдает ошибки парсинга XML.
Использование CAT-инструмента без поддержки XLIFF
Такие инструменты, как Poedit, созданы для формата .po. Они могут открывать XLIFF, но рассматривают его как общий текстовый контейнер. Встроенные теги не заблокированы. Заполнители не защищены. Вы получаете перевод, который хорошо выглядит в редакторе, но не проходит проверку схемы при импорте.
Написание пользовательского скрипта
Ваша команда пишет скрипт на Node или Python, который парсит XLIFF с помощью xml2js, извлекает исходные строки, вызывает Google Translate и записывает переводы обратно. Он работает для 90% строк. Остальные 10% — строки с вложенным форматированием, группами множественного числа или специальными символами — ломаются таким образом, что это проявляется только после того, как вы уже выпустили продукт.
Тот же режим отказа «гибкий формат встречается с наивным переводчиком» затрагивает файлы i18next JSON и Gettext .po. Наше руководство по переводу файлов i18next JSON для React и Next.js и наша статья о том, как переводить файлы .po, не ломая переменные кода, охватывают параллельные проблемы для этих форматов.
Правильный путь: синтаксически-ориентированная обработка XLIFF
Правильный конвейер перевода XLIFF следует тем же принципам, что и наш движок PO, адаптированный для XML.
Парсить, а не использовать регулярные выражения
Рассматривайте XLIFF как структурированный документ. Парсите его с помощью настоящего XML-парсера, стройте дерево и обходите элементы <trans-unit> (или <unit> для 2.0). Попытка сопоставить исходное и целевое содержимое с помощью регулярных выражений — это быстрый путь к поврежденным файлам.
Блокировать встроенные теги перед переводом
Каждый <g>, <x>, <bpt>, <ept>, <ph>, <pc> внутри <source> должен быть сохранен по позиции и атрибуту id. Замените их числовыми заполнителями перед отправкой текста в LLM, а затем повторно вставьте исходные теги с их атрибутами после получения перевода.
Соблюдать конечный автомат
Единицы XLIFF имеют атрибуты состояния: new, needs-translation, translated, reviewed, final, signed-off. Конвейер должен переводить только единицы в состоянии new или needs-translation и устанавливать выходное состояние на translated (не final — рецензент все еще должен проверить).
Сохранять структуру за пределами единиц перевода
Файлы XLIFF содержат заголовки, метаданные, атрибуты на уровне файла, примечания и альтернативные переводы (<alt-trans>). Они должны оставаться неизменными на протяжении всего цикла. Удаление или изменение их порядка нарушает совместимость с исходной платформой.
Проверять перед доставкой
Перед возвратом переведенного XLIFF проверьте его на соответствие схеме. XLIFF 1.2 имеет официальную XSD. XLIFF 2.0 имеет свою собственную. Инструмент, который не может самопроверяться, — это инструмент, который доставит вам поврежденные файлы.
Заметки по конкретным платформам
Каждая крупная платформа, использующая XLIFF, имеет свои особенности, о которых стоит знать.
Drupal
Drupal's Translation Management Tool (TMGMT) экспортирует XLIFF 1.2. Типы контента включают узлы (страницы, статьи), термины таксономии и конфигурацию. TMGMT оборачивает каждое переводимое поле в отдельный <trans-unit> с Drupal-специфическим форматом ID (fieldname:delta:format).
Подвох: Drupal хранит информацию о формате текста (отфильтрованный HTML, полный HTML, простой текст) вместе с содержимым. Перевод должен сохранять разметку HTML, когда формат это позволяет, и удалять ее до простого текста, когда формат не позволяет. Ваш конвейер нуждается в осведомленности о каждом поле.
Symfony
Компонент перевода Symfony использует XLIFF 2.0 по умолчанию (начиная с Symfony 4). Строки находятся в translations/messages.xx.xliff. Symfony поддерживает формат сообщений ICU внутри XLIFF, что означает, что одна единица может содержать структуры {count, plural, one {...} other {...}}.
Подвох: правила множественного числа ICU внутри XLIFF нуждаются в двойной защите. XML-теги остаются нетронутыми, И ключевые слова ICU (plural, one, other, =0) не должны переводиться. Многие инструменты XLIFF обрабатывают один уровень, но не оба.
Angular i18n
Angular экспортирует XLIFF 1.2 или 2.0 с помощью команды ng extract-i18n. Файлы содержат строки шаблонов компонентов, с тегами <x>, представляющими выражения Angular и интерполяции, такие как {{ count }}.
Подвох: Angular использует коллизии хешей id для идентичных исходных строк. Перевод должен точно сохранять идентификаторы единиц, иначе Angular не сможет сопоставить их при импорте. Переименование атрибутов id во время обработки приводит к мгновенному сбою.
iOS (Xcode Export)
Xcode экспортирует XLIFF 1.2 для локализации приложений через Product > Export Localizations. Строки поступают из Localizable.strings, записей Info.plist, раскадровок и XIBs. Правила множественного числа iOS находятся в файлах .stringsdict, экспортируемых как дополнительные единицы перевода.
Подвох: строки раскадровки iOS ссылаются на идентификаторы элементов пользовательского интерфейса. Они не должны быть изменены. Кроме того, Xcode требует, чтобы атрибут target-language точно соответствовал ожидаемому формату локали (например, es, а не es-ES, в некоторых контекстах), иначе он молча игнорирует импорт.
Перевод XLIFF с помощью SimplePoTranslate
SimplePoTranslate поддерживает XLIFF в планах Pro и Lifetime. Рабочий процесс такой же, как и для файлов .po.
1. Экспортируйте ваш XLIFF
С вашей исходной платформы экспортируйте один или несколько файлов .xliff. Для Drupal используйте действие экспорта TMGMT. Для Symfony найдите translations/messages.en.xliff. Для Angular запустите ng extract-i18n --format=xlf2. Для Xcode используйте экспорт локализации.
2. Загрузите в SimplePoTranslate
Перетащите файл на панель управления. Платформа автоматически определяет версию XLIFF (1.2 или 2.0), анализирует структуру и идентифицирует переводимые единицы. Выберите целевой язык и тон.
3. Синтаксически-ориентированный перевод
Встроенные теги, параметры ICU, заполнители и идентификаторы единиц блокируются перед переводом. Базовый ИИ-движок видит только чистый текст с контекстом. Переведенный текст вставляется обратно в точную исходную структуру, состояния обновляются, и файл проверяется на соответствие схеме XLIFF перед доставкой.
4. Скачайте и импортируйте
Скачайте переведенный XLIFF (плюс эквиваленты .po, .json и .php, если вам нужна кроссплатформенность). Импортируйте на вашу исходную платформу. Проверьте, отобразив несколько переведенных страниц или представлений, прежде чем внедрять.
# Angular example
ng extract-i18n --format=xlf2 --output-path=src/locale
# upload src/locale/messages.xlf to SimplePoTranslate
# download messages.es.xlf
# reference in angular.json i18n configuration
ng build --localize
5. Интегрируйте в CI
Как только вы доверяете конвейеру, автоматизируйте его. Экспортируйте XLIFF при каждом выпуске, отправляйте через API, скачивайте переведенные файлы, коммитьте в репозиторий, развертывайте. Это тот же паттерн, дружественный к CI, который многие агентства используют для перевода .po файлов WordPress — см. нашу статью о облачном переводе без сломанных сайтов для архитектурного паттерна.
Подводя итог
XLIFF — это правильный инструмент для серьезной работы по локализации: структурированный, не зависящий от инструментов и достаточно богатый для передачи метаданных проекта между системами. Но его XML-структура также хрупка. Каждый тег, атрибут и значение состояния имеют семантический вес, и переводчик, который не понимает XLIFF как формат, повредит ваш файл таким образом, что это может не проявиться до тех пор, пока импорт не завершится с ошибкой или пользователь не сообщит о сломанном пользовательском интерфейсе.
Безопасный подход — это синтаксически-ориентированный: парсить XML, блокировать структурные элементы, переводить только текстовые поверхности с контекстом, проверять на соответствие схеме перед доставкой. Это справедливо независимо от того, отправляете ли вы сайт Drupal, API Symfony, SPA на Angular или приложение iOS. Платформа отличается, но дисциплина XLIFF — нет.
Готовы переводить файлы XLIFF для Drupal, Symfony, Angular или iOS без поврежденных тегов? Попробуйте SimplePoTranslate бесплатно — кредитная карта не требуется. Загрузите
.xliff, скачайте безопасные переводы, импортируйте на свою платформу.