Два языка в интерфейсе — и Weblate становится лишней инфраструктурой
Кто-то в команде прочитал, что крупные опенсорс-проекты держат перевод интерфейса в Weblate, завёл тикет «поднимем и себе» — и через неделю на сервере уже крутятся Django, PostgreSQL, Redis и Celery-воркеры ради того, чтобы поддерживать ru.json и en.json на сто с небольшим строк. Формально всё работает: у переводчика есть веб-интерфейс, у строк — память переводов, у процесса — какое-то подобие ревью. По факту команда получила четвёртый сервис для бэкапов и обновлений там, где хватило бы файла в репозитории и таблицы на одной вкладке. Разберём, где Weblate — правильный выбор, а где — инфраструктура ради инфраструктуры.
Содержание
- Что даёт Weblate, когда он на своём месте
- Инфраструктура Weblate на сервере: что реально придётся поддерживать
- Два языка в интерфейсе — другая задача
- .po/.json в репозитории: как это работает без отдельного сервиса
- Таблица или Google Docs закрывают координацию с переводчиком
- Когда Weblate всё же оправдан, даже при паре языков
Что даёт Weblate, когда он на своём месте
Weblate — не редактор одного файла, а платформа для координации перевода между людьми, которые физически не пересекаются. Её ценность раскрывается там, где есть три вещи одновременно: много целевых языков, поток переводчиков, которые приходят и уходят, и исходные строки, которые меняются достаточно часто, чтобы вручную отслеживать рассинхрон было больно.
Из того, что реально работает и экономит время в таком сценарии:
- Веб-интерфейс для переводчика без доступа к git. Волонтёр открывает страницу, видит исходную строку, контекст (можно прикрепить скриншот экрана, где она используется), вводит перевод — и ему не нужно разбираться ни с git, ни с форматом
.po. - Память переводов (TM). Если в интерфейсе повторяется фраза «Сохранить изменения» в разных модулях, Weblate подскажет уже переведённый вариант и не даст разъехаться терминологии между разделами — причём чем больше языков и чем больше строк, тем заметнее экономия. Это тот же принцип, что и TM в профессиональных CAT-инструментах переводчиков-фрилансеров (о ней отдельно — в статье про память переводов на своём сервере), только накопленная база работает на команду, а не на одного человека.
- Автоматические проверки качества. Несовпадение плейсхолдеров (
%s,{name}), незакрытые теги, различие в пунктуации между оригиналом и переводом, слишком длинная строка для интерфейса с фиксированной шириной — всё это ловится до того, как попадёт в прод. - Ревью и модерация. Анонимные или недоверенные предложения переводов попадают в очередь «suggestion», а не сразу в файл — их подтверждает доверенный переводчик или мейнтейнер.
- Интеграция с VCS. Weblate сам подтягивает исходные строки из git-репозитория и коммитит переводы обратно (или открывает merge request) — разработчику не нужно вручную сводить правки из внешнего источника с кодом.
- Поддержка форматов. Gettext
.po/.pot, JSON (в том числе i18next), YAML, Androidstrings.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-проверки плейсхолдеров, но не требует ни сервера, ни базы данных, ни отдельного логина.
Рабочий цикл выглядит так:
- Разработчик добавляет новый ключ в исходный файл (
en.json) при разработке фичи. - Переводчик получает диф (или просто открывает файл в своей ветке), переводит новые строки.
- Открывается обычный pull request — ревью происходит так же, как ревью любого кода: построчный дифф, комментарии, аппрув.
- Мержится вместе с остальными изменениями фичи, без отдельного шага синхронизации с внешним сервисом.
Автоматическую проверку «ничего не забыли перевести» несложно закрыть скриптом в 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 ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →