MAATRIX / Блог / Два языка в интерфейсе — и Weblate становится лишней инфраструктурой

Два языка в интерфейсе — и Weblate становится лишней инфраструктурой

MAATRIX

Кто-то в команде прочитал, что крупные опенсорс-проекты держат перевод интерфейса в Weblate, завёл тикет «поднимем и себе» — и через неделю на сервере уже крутятся Django, PostgreSQL, Redis и Celery-воркеры ради того, чтобы поддерживать ru.json и en.json на сто с небольшим строк. Формально всё работает: у переводчика есть веб-интерфейс, у строк — память переводов, у процесса — какое-то подобие ревью. По факту команда получила четвёртый сервис для бэкапов и обновлений там, где хватило бы файла в репозитории и таблицы на одной вкладке. Разберём, где Weblate — правильный выбор, а где — инфраструктура ради инфраструктуры.

Что даёт Weblate, когда он на своём месте

Weblate — не редактор одного файла, а платформа для координации перевода между людьми, которые физически не пересекаются. Её ценность раскрывается там, где есть три вещи одновременно: много целевых языков, поток переводчиков, которые приходят и уходят, и исходные строки, которые меняются достаточно часто, чтобы вручную отслеживать рассинхрон было больно.

Из того, что реально работает и экономит время в таком сценарии:

  • Веб-интерфейс для переводчика без доступа к git. Волонтёр открывает страницу, видит исходную строку, контекст (можно прикрепить скриншот экрана, где она используется), вводит перевод — и ему не нужно разбираться ни с git, ни с форматом .po.
  • Память переводов (TM). Если в интерфейсе повторяется фраза «Сохранить изменения» в разных модулях, Weblate подскажет уже переведённый вариант и не даст разъехаться терминологии между разделами — причём чем больше языков и чем больше строк, тем заметнее экономия. Это тот же принцип, что и TM в профессиональных CAT-инструментах переводчиков-фрилансеров (о ней отдельно — в статье про память переводов на своём сервере), только накопленная база работает на команду, а не на одного человека.
  • Автоматические проверки качества. Несовпадение плейсхолдеров (%s, {name}), незакрытые теги, различие в пунктуации между оригиналом и переводом, слишком длинная строка для интерфейса с фиксированной шириной — всё это ловится до того, как попадёт в прод.
  • Ревью и модерация. Анонимные или недоверенные предложения переводов попадают в очередь «suggestion», а не сразу в файл — их подтверждает доверенный переводчик или мейнтейнер.
  • Интеграция с VCS. Weblate сам подтягивает исходные строки из git-репозитория и коммитит переводы обратно (или открывает merge request) — разработчику не нужно вручную сводить правки из внешнего источника с кодом.
  • Поддержка форматов. Gettext .po/.pot, JSON (в том числе i18next), YAML, Android strings.xml, iOS .strings, Java .properties, и ещё десяток менее распространённых — один инструмент закрывает разные стеки.

Это именно тот набор, ради которого крупные опенсорс-проекты с несколькими десятками языков и постоянным потоком контрибьюторов держат Weblate у себя или пользуются облачным weblate.org — и там это окупается с запасом.

Инфраструктура Weblate на сервере: что реально придётся поддерживать

Официальный способ развернуть Weblate у себя — docker-compose из репозитория проекта WeblateOrg/docker. Даже в минимальной конфигурации это не один контейнер, а стек из нескольких сервисов:

services:
  weblate:
    image: weblate/weblate
    depends_on: [database, cache]
    ports: ["8080:8080"]
    volumes: [weblate-data:/app/data]
    environment:
      - WEBLATE_ADMIN_PASSWORD=...
      - WEBLATE_SITE_DOMAIN=...
      - POSTGRES_PASSWORD=...

  database:
    image: postgres:16-alpine
    volumes: [postgres-data:/var/lib/postgresql/data]
    environment: [POSTGRES_PASSWORD=...]

  cache:
    image: redis:7-alpine
    volumes: [redis-data:/data]

volumes:
  weblate-data:
  postgres-data:
  redis-data:

Внутри самого weblate-контейнера уже работает не только Django-приложение, но и Celery — несколько очередей воркеров (импорт из VCS, уведомления, периодические задачи вроде обновления памяти переводов) плюс celery beat как планировщик. Снаружи это один контейнер, но по факту — отдельная система процессов со своими логами и своими причинами упасть под нагрузкой.

Что из этого вытекает на практике:

  • Бэкап — это три разных объекта, а не один. Дамп PostgreSQL, содержимое git-репозиториев, которые Weblate клонирует себе в data/vcs, и медиа (скриншоты, аватары). Забыть второе — частая причина, по которой после восстановления «переводы есть в базе, а связь с исходным репозиторием потеряна».
  • Redis — не опция, а обязательная зависимость: и кеш, и брокер задач для Celery; без него Weblate не запустится вообще, а не просто станет медленнее.
  • Обновления выходят регулярно, и мажорные версии иногда требуют прогона миграций базы и сверки конфигурации с новыми обязательными параметрами — это не разовая установка «поставил и забыл», а сервис, требующий периодического внимания, как GitLab или любая другая многосервисная платформа.
  • RAM и CPU для небольшой инсталляции с одним-двумя проектами обычно укладываются в 2 vCPU и 2-4 ГБ — но это ориентир: PostgreSQL, Redis и несколько Celery-воркеров всё равно ощутимо тяжелее, чем статический .po-файл, который не потребляет ресурсов сервера, пока его не открыли в редакторе.

Если вы уже держите на сервере CI/CD и git-инфраструктуру — общий обзор того, во что это обходится по ресурсам, разобран в статье про экономику self-hosted: Weblate попадает туда же по логике «TCO — это не только цена аренды сервера, а ещё и время на обслуживание».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Два языка в интерфейсе — другая задача

Теперь наложите этот стек на реальную ситуацию: продукт, у которого в интерфейсе всего два языка — например, русский и английский. Строк перевода — от пары десятков до нескольких сотен: кнопки, заголовки разделов, сообщения об ошибках, письма. Переводчиков — один-два человека, часто это сами разработчики или один нанятый переводчик/агентство, а не постоянный поток внешних контрибьюторов.

В этой конфигурации почти всё, за что ценят Weblate, работает вхолостую:

  • Память переводов почти бесполезна при одной языковой паре. TM экономит время, когда одна и та же фраза переводится на десять языков и нужно не переизобретать формулировку в каждом. При переводе «на один язык туда и обратно» повторное использование сводится к тому, что человек и так помнит, как он перевёл эту фразу вчера.
  • Ревью-очередь не нужна, если переводчик один и он же принимает решение. Workflow «suggestion → review → approve» имеет смысл, когда предложения приходят от анонимных или недоверенных участников. Если единственный переводчик — штатный сотрудник или подрядчик с прямым доступом, лишнее звено согласования просто замедляет процесс.
  • Дашборд прогресса по языкам показывает один прогресс-бар вместо содержательной картины — для двух языков это не аналитика, а декорация.
  • Приглашение внешних волонтёров через веб-интерфейс не нужно, если у проекта нет модели «переводите нас, кто хочет» — а у закрытого коммерческого продукта с парой языков её обычно и нет.

Ключевой признак, по которому стоит проверять себя: если открыть Weblate и посмотреть на список языков, а там строго ru и en без намерения расширяться — вы платите инфраструктурную цену инструмента, спроектированного для десятков языков, ради задачи на два файла.

.po/.json в репозитории: как это работает без отдельного сервиса

Практический альтернативный вариант — держать исходные строки как обычные текстовые файлы прямо в репозитории кода, рядом с остальным. Формат зависит от стека:

  • Gettext (.po/.pot) — стандарт для Python, PHP, C и многих старых экосистем. Исходный шаблон messages.pot, переводы — ru/LC_MESSAGES/messages.po.
  • JSON-словари — стандарт для фронтенда на i18next, react-intl, vue-i18n и подобных: locales/ru.json, locales/en.json, плоские или вложенные пары ключ → строка.

Редактируется это либо прямо в текстовом редакторе (для JSON — разница в PR читается как обычный код-дифф), либо в бесплатном десктопном редакторе вроде Poedit для .po-файлов — он даёт удобный список строк, подсветку непереведённого и base-проверки плейсхолдеров, но не требует ни сервера, ни базы данных, ни отдельного логина.

Рабочий цикл выглядит так:

  1. Разработчик добавляет новый ключ в исходный файл (en.json) при разработке фичи.
  2. Переводчик получает диф (или просто открывает файл в своей ветке), переводит новые строки.
  3. Открывается обычный pull request — ревью происходит так же, как ревью любого кода: построчный дифф, комментарии, аппрув.
  4. Мержится вместе с остальными изменениями фичи, без отдельного шага синхронизации с внешним сервисом.

Автоматическую проверку «ничего не забыли перевести» несложно закрыть скриптом в CI без всякого Weblate — например, для JSON-словарей:

#!/usr/bin/env python3
import json, sys

with open("locales/en.json") as f:
    en = json.load(f)
with open("locales/ru.json") as f:
    ru = json.load(f)

missing = set(en.keys()) - set(ru.keys())
extra = set(ru.keys()) - set(en.keys())

if missing:
    print("Нет перевода для ключей:", missing)
if extra:
    print("Лишние ключи в ru.json, которых нет в en.json:", extra)

sys.exit(1 if (missing or extra) else 0)

Для gettext того же результата достигают штатной утилитой msgfmt --check и сверкой .po со свежим .pot через msgmerge --update в режиме проверки без записи. Это несколько строк в CI-пайплайне, которые уже выполняются на каждый PR — против отдельного сервиса, который нужно поднимать, обновлять и бэкапить.

Таблица или Google Docs закрывают координацию с переводчиком

Второй кусок ценности Weblate — не сам перевод, а координация: как передать строки человеку без доступа к репозиторию, получить его правки, оставить комментарий про контекст и не потерять историю изменений. Для двух языков и небольшого объёма строк это закрывает обычная таблица.

Практическая схема:

  • Разработчик выгружает пары «ключ — исходная строка» в Google Sheets: колонки key, en (исходник, только для чтения), ru (для заполнения), комментарий (где эта строка встречается в интерфейсе — при желании со скриншотом, вставленным прямо в ячейку или соседнюю колонку).
  • Переводчик заполняет колонку ru, оставляет вопросы прямо в комментариях к ячейке — это тот же функционал, что "review" в Weblate, только без отдельного сервера.
  • История версий Google Docs/Sheets уже даёт то, ради чего в Weblate городят версионирование через git — можно посмотреть, кто и когда поменял конкретную строку.
  • Небольшой скрипт (Python + csv/gspread, или ручной экспорт в CSV раз в спринт) собирает таблицу обратно в ru.json или ru.po и кладёт файл в PR.

Для проекта с парой языков и штатным объёмом правок раз в одну-две недели этот цикл занимает у разработчика меньше времени, чем настройка и последующая поддержка Weblate — при этом переводчику не нужно объяснять, что такое git, suggestion и merge request, он просто открывает знакомую таблицу.

Если вам в принципе интересно, где self-hosted инструмент оправдан, а где для небольшого объёма достаточно простого файла или таблицы — та же логика разобрана на другом примере, учёте IT-техники, в статье Snipe-IT нужен не всем: на каком количестве техники таблица сдаётся: водораздел там определяется не «модно/немодно», а объёмом и числом участников процесса, и с локализацией интерфейса работает ровно та же арифметика.

Когда Weblate всё же оправдан, даже при паре языков

Правило «два языка — не ставьте Weblate» не абсолютное. Есть три ситуации, где имеет смысл развернуть его заранее, даже если сегодня локалей всего две:

Дорожная карта прямо говорит о скором расширении на много языков. Если через квартал-два планово добавляются ещё пять-десять локалей и это не гипотеза, а пункт роадмапа, дешевле поднять Weblate сейчас и завести в него первые два языка, чем мигрировать с файлов на платформу под давлением, когда уже накопится десяток .po-файлов и несколько переводчиков в процессе.

Переводчики — внешние люди, которым нельзя давать доступ к репозиторию. У опенсорс-проекта с открытым приёмом переводов от кого угодно нет способа без веб-интерфейса безопасно принимать вклад анонимных участников — им нужен UI без доступа к коду и без git-логина, а Weblate именно эту проблему и решает.

У проекта уже была история сломанных плейсхолдеров или неверной длины строки в проде. Если однажды %s потерялся при переводе и это дошло до пользователей, автоматические проверки качества Weblate снимают конкретный риск, который на паре языков и десятке строк маловероятен, но на растущем проекте с частыми правками — уже не редкость.

Во всех трёх случаях решение принимается не потому что «Weblate — правильный стандарт индустрии», а потому что конкретный риск или конкретный процесс требует конкретной функции платформы. Если ни один пункт не описывает вашу ситуацию — файл в репозитории и таблица для переводчика справятся не хуже и не потребуют от вас поддерживать четвёртый сервис на сервере.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Сколько ресурсов реально нужно небольшой инсталляции Weblate?

Ориентировочно 2 vCPU и 2-4 ГБ RAM для одного-двух активных проектов — это именно ориентир, у вас может выйти иначе в зависимости от числа Celery-воркеров. Дело не столько в железе (оно как раз недорогое), сколько в постоянном внимании: обновлениях, бэкапах трёх разных типов данных, разборе зависших фоновых задач.

Можно ли поставить Weblate только как веб-редактор, без памяти переводов и лишних модулей?

Нет, TM и остальные механизмы завязаны на общую базу данных и логику приложения — выключить их по отдельности нельзя. Получаете Weblate целиком или не получаете вообще.

Если сейчас два языка, а через год понадобится пять — миграция с .po-файлов на Weblate сложная?

Нет, это одна из сильных сторон инструмента: он умеет импортировать существующие .po/.json-файлы из git как стартовую точку без переписывания. Решение «файлы в репозитории сейчас» не закрывает дорогу к Weblate позже.

Есть ли облачная альтернатива, чтобы не поднимать Weblate у себя вообще?

Да, у проекта есть собственный облачный weblate.org с условиями для опенсорса, а также коммерческие SaaS вроде Crowdin, Lokalise, POEditor — тарифы у них меняются, уточняйте на официальных сайтах. Принцип для пары языков тот же: сравните цену платформы (временем или деньгами) с ценой файла в репозитории.

А если переводчик — не разработчик и вообще боится git?

Тогда и не нужно давать ему git — таблица с колонками «ключ / исходник / перевод / комментарий», которую разработчик потом сводит обратно в файл, решает именно эту проблему без веб-платформы. Теряется только автоматическая синхронизация, которую при паре сотен строк несложно делать вручную раз в одну-две недели.

Что делать, если Weblate уже стоит, а локалей так и осталось две?

Не повод срочно всё сносить, если система работает стабильно и не требует внимания сверх плановых обновлений — миграция обратно на файлы тоже стоит времени. Но если через полгода-год локалей всё ещё две и переводчик один, экономика возврата к простому файлу в репозитории, вероятно, окупит перенос.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →