Локализация ломается не у переводчиков. Она ломается во время деплоя
В ноябре 2022 года мы выкатили безобидный хотфикс для SaaS-сервиса с клиентами в 14 странах. Никаких новых текстов не писали. Буквально поправили валидацию полей в форме оплаты и обновили пару зависимостей в Next.js. Утром в саппорт прилетело письмо от разъяренного пользователя из Мюнхена: на немецкой версии сайта кнопка подписки гордо сообщала «Sign up now», а плашка с ошибкой карты вылезла на чистейшем русском языке: «Не удалось обработать платеж». Четыре дня этот гибрид висел на проде, пока трафик бодро сливался в трубу.
Переводчики были не при чем. Их файлы локализации лежали в репозитории нетронутыми, со всеми галочками в Lokalise. Ошибку создал разработчик, который захардкодил временный текст в кастомный хук и забыл обернуть его в i18n-функцию. А fallback-логика фреймворка молча подставила английский язык для кнопки, потому что после обновления пакета один из ключей в JSON просто потерял вложенность.
Перевод сдан — проблемы только начинаются
Компании тратят тысячи долларов на агентства переводов, вычитывают каждый дефис у пруфридеров, а потом разработчик накатывает обновление Strapi или WordPress. Бам — половина полей слетает на дефолтный язык темы. Контент-менеджер публикует кейс на испанском, копируя структуру с английского черновика, и оставляет три англоязычных блока в середине лонгрида. В отчетах все чисто, а на живой странице зияют дыры.
Классический контроль качества локализации застрял в парадигме документов. Команды сверяют Google-таблицы, выгружают PO-файлы и считают, что работа сделана, как только статус таски меняется на «Done». Но сайт — это не статичный документ. Это живая система компонентов, API-ответов и сторонних скриптов.
Языковые утечки на страницах почти никогда не происходят из-за лени копирайтеров. Они случаются по трем прозаичным инженерным причинам:
Во-первых, тихие фоллбэки. Почти все i18n-библиотеки настроены так, чтобы сайт не падал с белым экраном, если перевод отсутствует. Нет ключа? Покажи английский. В итоге интерфейс не падает, мониторинг молчит, а пользователь видит кашу из трех языков на одном экране.
Во-вторых, сторонние виджеты и скрипты. Чат поддержки, баннер cookie, форма подписки из HubSpot или окно Stripe Elements часто определяют язык не по URL страницы, а по заголовку браузера сборщика или собственным внутренним настройкам. В результате у вас весь сайт французский, а виджет согласия на обработку данных внезапно говорит с пользователем по-голландски.
В-третьих, CMS-сюрпризы. Достаточно разработчику переименовать слаг кастомного типа записей, как база данных тихо возвращает пустую строку для вторичных локалей. Шаблон видит пустоту и рендерит дефолтную заглушку.
Почему ручной прогон — это иллюзия безопасности
Когда у вас сайт на трех языках и двадцать страниц, можно посадить джуна или тестировщика, чтобы он раз в месяц кликал по меню. Когда у вас пять языков, блог на двести статей, документация и динамический личный кабинет, ручное тестирование превращается в фикцию. Ни один живой человек не будет после каждого релизного спринта открывать 1200 страниц и глазами искать, не вылезло ли английское слово в футере португальской версии.
Проверять исходники в репозитории тоже бессмысленно. В коде ключ может существовать, но из-за ошибки гидратации в React или бага в кеше CDN клиент в браузере получит не тот чанк. Единственная правда — это финальный DOM, который отрисовался на экране пользователя.
Именно поэтому нормальный QA для мультиязычного сайта должен работать на уровне реального рендера. Нужно брать готовые HTML-страницы, вычищать технический мусор вроде названий брендов, имен собственных и кода, а затем прогонять текстовые ноды через алгоритмы языковой идентификации. Если на странице с локалью /it/ плотность испанских или английских предложений превышает порог погрешности — это баг, требующий алерта в Slack до того, как его найдет клиент.
Как выстроить защиту от сползания языков
Если вы отвечаете за мультиязычный продукт, перестаньте верить галочкам в таск-трекере. Настройте базовую санитарию процессов.
Заставьте линтеры ругаться на сырые строки в JSX или шаблонах. Любой текст без обертки в функцию интернационализации должен блокировать пулл-реквест. Это примитивно, но срезает примерно 40% глупых утечек при спешных фиксах.
Перестаньте молча проглатывать отсутствующие ключи на стейджинге. В дев-окружении fallback должен не тихо подставлять базовый язык, а взрываться красным баннером или бросать исключение. Если разработчик потерял ключ локализации, он должен споткнуться об это сразу в браузере, а не на продакшене.
И главное: перенесите мониторинг на прод. Непрерывная проверка перевода сайта автоматически защищает от ситуаций, когда маркетолог ночью обновил лендинг через админку, сломав разметку для четырех стран одновременно.
В GuardLabs мы набили слишком много шишек на клиентских сайтах, пытаясь отлавливать эти баги вручную или через самописные кривые баш-скрипты. В итоге мы собрали для себя сервис, который делает ровно одну задачу без раздутого энтерпрайз-пафоса: наш детектор языковых утечек на многоязычном сайте (QA перевода) регулярно сканирует живые страницы, находит инородный текст и сразу показывает, где именно слетела локализация. Если у вас интернациональный трафик и регулярные релизы — настройте мониторинг один раз, сбережете кучу нервов и конверсий.