Все проекты

Open source-проект · 2026

Переводчик XLF-файлов для Angular

Консольная утилита на Node.js: переводит XLF-файлы Angular через Google Translate, сохраняя теги, отступы и готовые переводы.

Роль
Автор и мейнтейнер
Период
2026
Стек
Node.js, Angular i18n, XLIFF, Google Translate, npm

Задача

В Angular-приложении на несколько языков каждая новая строка интерфейса должна попасть во все файлы перевода: messages.en.xlf, messages.tr.xlf, messages.kk.xlf и дальше по списку. Вручную это долгое копирование между файлом и переводчиком, а платформа локализации ради черновых переводов — лишняя подписка и интеграция.

Подвох в формате. Внутри строк Angular оставляет теги <x id="…"/> — на их месте интерполяции и переносы строк. Если отдать строку переводчику как есть, теги потеряются или исказятся, и перевод придётся чинить руками.

Решение

Один файл на Node.js без зависимостей — только встроенные fs и https. Утилита запускается в папке с переводами и обходит все XLF-файлы в ней:

Bash
npx translate-xlf --from=ru --exclude=en
  • Язык — из имени файла: messages.tr.xlf переводится на турецкий, messages.kk.xlf — на казахский. Файл без кода языка пропускается.
  • Теги не трогаются: перед отправкой <x …/> заменяются плейсхолдерами, после перевода возвращаются на место.
  • Файл правится построчно, а не пересобирается из XML-дерева. Отступы и многострочные <source> и <target> остаются как были, поэтому в диффе видны только новые переводы.
  • Готовое не перезаписывается: строки со state="translated" и final пропускаются. Переведённые получают state="translated", а с флагом --keep-state сохраняют свой статус.
  • Ошибки не теряются: запросы идут пачками, неудачный повторяется. Если строку перевести так и не удалось, она помечается [ОШИБКА ПЕРЕВОДА] и переводится заново при следующем запуске.

Ключ API и биллинг Google Cloud не нужны: утилита обращается к тому же бесплатному эндпоинту Google Translate, что и браузерные расширения.

Когда Google начал блокировать

В октябре 2026 года все запросы вдруг стали падать с ответом 429 и страницей «your computer or network may be sending automated queries». При этом тот же запрос через curl или встроенный в Node fetch проходил.

Дело оказалось не в IP и не в частоте запросов, а в TLS-рукопожатии: модуль https по умолчанию не отправляет расширение ALPN, и по этому отпечатку Google отличал скрипт от браузера. В версии 1.0.3 запросы идут через https.Agent с ALPNProtocols: ['http/1.1'] — рукопожатие совпадает с тем, что делает fetch, и блокировка ушла. Способ быстро отличить блокировку клиента от блокировки сети описан в README.

Результат

Утилита опубликована в npm и на GitHub. Новый язык в приложении — это новый файл messages.XX.xlf и один запуск. Машинный перевод остаётся черновиком, который стоит вычитать перед релизом, но рутина копирования строк уходит.