
Вам не нужно переводить всё заново: как работает дельта-перевод в CI
By Robert M
Вам не нужно переводить всё заново: как работает дельта-перевод в CI
Как только у вас настроен автоматический перевод в вашем CI-пайплайне, возникает естественный вопрос: переводится ли весь файл локализации каждый раз, когда кто-то делает push?
Без режима дельты — да. Каждый push, затрагивающий исходный файл локализации, отправляет весь файл в API, каждую ключевую строку, независимо от того, изменялась она или нет. Для небольшого проекта на раннем этапе это нормально. Для зрелого проекта с сотнями ключей перевода на 10 или 20 языках вы тратите токены на строки, которые не изменились с последнего запуска, и получаете обратно идентичный результат.
Дельта-перевод решает эту проблему. Вместо отправки полного файла, Action сравнивает текущий исходный файл с сохранённой базовой версией, определяет только добавленные или изменённые ключи и отправляет только их в API. Результат для неизменённых ключей берётся из уже существующих переведённых файлов. Использование токенов снижается и соответствует фактически выполненной работе.
Как работает базовая версия
Когда режим дельты запускается впервые или когда вы принудительно обновляете полностью, Action переводит весь исходный файл и сохраняет его плоское JSON-представление как базовый файл в вашем репозитории. При последующих запусках Action загружает этот базовый файл, сравнивает его с текущим исходным файлом и формирует нагрузку, содержащую только изменённые ключи.
Для JSON-файлов локализации базовый файл хранится как .polylingo-baseline.json в каталоге сообщений. Для YAML-файлов локализации — .polylingo-yaml-baseline.json в каталоге локалей. Для PHP-файлов Laravel lang — .polylingo-laravel-php-baseline.json в каталоге lang.
Базовая версия коммитится вместе с переведёнными файлами, чтобы она путешествовала вместе с репозиторием. Любой разработчик, клонирующий репозиторий, получает ту же базовую версию, с которой работает пайплайн.
Что считается изменением
Дифф работает с плоским представлением ключей вашего исходного файла. Вложенные структуры преобразуются в ключи с точечной нотацией перед сравнением:
{
"nav.home": "Главная",
"nav.about": "О нас",
"hero.title": "Добро пожаловать на нашу платформу",
"hero.cta": "Начать"
}
Ключ включается в дельта-нагрузку, если:
- Он есть в текущем исходном файле, но отсутствует в базовой версии (новый ключ)
- Он есть в обоих, но значение изменилось (изменённый ключ) Ключи, которые есть в базовой версии, но отсутствуют в текущем исходном файле (удалённые ключи), автоматически удаляются из переведённых файлов. Ключи, идентичные в обоих файлах, полностью пропускаются, и их существующие переводы остаются на месте.
Как это выглядит на практике
Предположим, у вас есть проект Next.js с 200 ключами перевода в messages/en.json, уже переведёнными на 12 языков. Разработчик обновляет текст в секции hero и добавляет два новых ключа для объявления функции. Это 4 изменённых ключа из 200.
Без режима дельты пайплайн отправляет все 200 ключей, умноженные на 12 языков, при каждом push. С режимом дельты отправляется 4 ключа. Использование токенов для этого запуска составляет примерно 2% от стоимости полного перевода. Пайплайн также работает быстрее, потому что меньше данных для отправки и ожидания.
За месяц регулярной разработки экономия значительно накапливается. Большинство push-ей затрагивают лишь несколько строк. Полный повторный перевод происходит только при добавлении нового языка или явном сбросе базовой версии.
Три GitHub Actions PolyLingo
Режим дельты доступен во всех трёх Actions перевода PolyLingo. Каждый из них создан для определённого типа контента и структуры проекта.
translateAction — JSON и Markdown
Оригинальный Action. Обрабатывает плоские JSON-файлы локализации в стиле next-intl и i18next, с опциональным проходом документации Markdown через API асинхронных задач для больших файлов.
- uses: UsePolyLingo/translate-action@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
source_file: messages/en.json
locales: fr,de,es,ja,zh
delta: true
commit: true
commit_message: "chore(i18n): синхронизация переводов"
Базовая версия дельты: messages/.polylingo-baseline.json
github.com/UsePolyLingo/translateAction — Посмотреть на Marketplace
translate-action-yaml — YAML-файлы локализации
Для проектов, использующих вложенные YAML-файлы локализации: Rails i18n, Vue i18n и любые другие фреймворки, использующие формат YAML. Action автоматически обрабатывает конвенцию Rails с корневым ключом локали — en.yml имеет корневой ключ en:, и каждый выходной файл получает правильный целевой ключ локали (fr:, de: и т.д.).
Поскольку API PolyLingo работает с JSON нативно, Action преобразует вложенный YAML в JSON с точечной нотацией перед отправкой, переводит, затем восстанавливает вложенную структуру и записывает валидный YAML. Один нюанс версии 1: ключи, содержащие точки естественным образом, не поддерживаются, так как конфликтуют с преобразованием в точечную нотацию.
- uses: UsePolyLingo/translate-action-yaml@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
locales_dir: config/locales
source_file: config/locales/en.yml
locales: fr,de,es,ja
delta: true
commit: true
Базовая версия дельты: config/locales/.polylingo-yaml-baseline.json
github.com/UsePolyLingo/translate-action-yaml — Посмотреть на Marketplace
translate-action-laravel — файлы lang Laravel
Для проектов Laravel, использующих либо JSON-файлы перевода (lang/en.json, поддерживающие вложенные и плоские структуры в стиле Laravel 9+), либо PHP-массивы lang (lang/en/*.php). Action автоматически определяет формат вашего проекта через php_format: auto — сначала проверяет lang/en.json, и если не найден, переключается на PHP-массивы.
Для PHP-файлов вызывается CLI PHP для чтения исходных файлов и сериализации переведённого вывода обратно в валидный PHP-массив в JavaScript без дополнительных зависимостей. GitHub-раннеры ubuntu-latest по умолчанию включают PHP 8.x, поэтому дополнительная настройка не требуется. Требуется PHP 7.4 или выше.
Одна особенность версии 1: ключи с точками не поддерживаются в PHP-режиме из-за стратегии преобразования в точечную нотацию.
- uses: UsePolyLingo/translate-action-laravel@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
lang_dir: lang
source_locale: en
locales: fr,de,es,pt,nl
php_format: auto
delta: true
open_pr: true
Базовая версия дельты: lang/.polylingo-laravel-json-baseline.json или lang/.polylingo-laravel-php-baseline.json в зависимости от формата.
github.com/UsePolyLingo/translate-action-laravel — Посмотреть на Marketplace
Режим PR против режима коммита
Все три Actions поддерживают два режима вывода.
Режим коммита (commit: true) записывает переведённые файлы и коммитит их напрямую в текущую ветку. Простая настройка, подходит для команд, которые рассматривают перевод как автоматизированный процесс без необходимости проверки.
Режим PR (open_pr: true) создаёт новую ветку (polylingo/yaml-<sha>, polylingo/laravel-<sha> и т.д.), записывает туда переведённые файлы и открывает pull request в вашу базовую ветку. Лучше для команд, которые хотят этап проверки человеком перед слиянием переведённого контента, или для проектов, где качество перевода напрямую влияет на пользовательский опыт.
Если оба режима включены, побеждает режим PR.
Режим PR требует разрешения pull-requests: write в правах вашего workflow:
permissions:
contents: write
pull-requests: write
Принудительное полное обновление
Режим дельты сравнивает с сохранённой базовой версией. Если вы хотите перевести всё заново, независимо от базовой версии, установите delta: false. Это также обновит базовую версию, чтобы она соответствовала текущему исходному файлу, так что последующие запуски дельты начнутся с нового состояния.
Полное обновление полезно, когда вы добавляете новый целевой язык, хотите получить улучшения качества перевода в новой версии модели или когда базовая версия отклонилась от реальности по любой причине.
- uses: UsePolyLingo/translate-action-yaml@v1
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
locales_dir: config/locales
locales: fr,de,es,ja,zh,ko,ar
delta: false # полное обновление, обновляет базовую версию
commit: true
Выходные данные для последующих шагов
Все три Actions предоставляют одинаковые выходные данные, чтобы вы могли использовать их в последующих шагах workflow:
- uses: UsePolyLingo/translate-action@v1
id: translate
with:
api_key: ${{ secrets.POLYLINGO_API_KEY }}
source_file: messages/en.json
locales: fr,de,es
delta: true
commit: true
- name: Логировать статистику перевода
run: |
echo "Переведённые локали: ${{ steps.translate.outputs.locales_translated }}"
echo "Изменённые файлы: ${{ steps.translate.outputs.files_changed }}"
echo "Использованные токены: ${{ steps.translate.outputs.tokens_used }}"
Каждый запуск также записывает сводную таблицу в summary шага GitHub Actions, чтобы вы могли видеть использование токенов и результаты перевода без необходимости просматривать логи.
Начало работы
Все три Actions доступны на GitHub Marketplace. Вам понадобится ключ API PolyLingo, доступный бесплатно на usepolylingo.com. Бесплатный тариф включает 50 000 токенов в месяц. С включённым режимом дельты большинство проектов будет оставаться в пределах этого лимита при обычных push-ах разработки.
Добавьте ваш API-ключ как секрет репозитория (POLYLINGO_API_KEY) и вставьте соответствующий Action в ваш workflow. Первый запуск выполняет полный перевод и устанавливает базовую версию. Каждый последующий запуск переводит только изменённое.