InquirerLegislator denies pushing ‘shoot-to-kill’ resolution vs Bato Dela RosaPunchKano gov congratulates Sultan on 20th coronation anniversaryThe Jerusalem PostLiberman pledges to recommend Eisenkot for PM, back Lapid as Knesset speakerDaily MaverickReporter’s Notebook: The sewer still fouling the Cradle is emblematic of local government failureBollywood HungamaScam 2010 first look out: Hansal Mehta-helmed series to premiere in January 2027 on Sony LIVZDF heuteEntdecken Sie das ZDF-NachrichtenstudioComplete SportsLinebet Bangladesh Promo Code 2026: CSMAX26, Bonuses and How to ClaimSCMP ChinaChina’s fifth plenum: cadre promotion rules overhauled, focusing on problem-solvingGIGAZINEHacker Newsで言及された1万5000冊超の書籍をランキングにした「Hacker Books」トップ10、テクノロジー愛好家が好きな本とは?Deadline‘Carrie’s Mike Flanagan Reflects On Supernatural YA Drama & Says ‘Warhammer 40,000’ Series Has “Very Cool And Unexpected On-Ramp”Egypt IndependentBitter spat between Poland’s pro-Europe PM and pro-Trump president eruptsCapital FMKarauri: Changing party colours won’t save Sakaja from Nairobi record
The Daily Newsstand · Free, Always
Monday, November 2, 2026

Прощай, платный перевод: собираем локализацию на open source и LLM

Translate

Мы в отделе технической документации переводим много текста: технические справочники, интерфейсные строки, исходный код и комментарии к нему. Счет идет на сотни документов в самых разных форматах, которые нужно постоянно переводить. Платный облачный CAT-сервис, которым мы пользовались, обходился все дороже и все меньше был под нашим контролем. Мы решили эту проблему сами: подняли on-premise инфраструктуру локализации с LLM, почти без участия разработки. В статье пошагово разбираю, как мы к этому пришли — от выбора между Zing и Weblate до финального пайплайна с Serge, Dify и своей моделью.

Привет, Хабр! Меня зовут Руслан Ташметов. Я учусь в магистратуре МГУ на факультете искусственного интеллекта и работаю в YADRO с начала стажировки «Импульс» 2025 года.

Три требования к новому CAT-инструменту

Начну с предыстории. Долгое время мы переводили документацию в Smartcat. Это удобный CAT-инструмент (Computer-Assisted Translation) с браузерным интерфейсом, памятью переводов, глоссариями и автоматической проверкой качества.

Но у удобства была цена, причем буквально: тариф считается по сетке за каждое загруженное в него слово (неважно, новое оно или уже переведенное), а проектов у нас сотни. Когда Smartcat на волне развития LLM превратился в «единую ИИ-платформу для контента на любом языке» и подорожал, мы и перестали откладывать переход на локальные LLM.

Интерфейс Smarcat

Интерфейс Smarcat

Помимо снижения стоимости, к новому CAT-инструменту у нас было три требования:

  • Размещение всей информации на серверах YADRO. При использовании сторонних сервисов перевода корпоративные тексты передаются на внешние серверы, то есть третьим лицам. Для нас было важно исключить такую передачу.

  • Возможность подключать и модифицировать параметры работы с LLM для перевода.

  • Наличие клиент-серверной архитектуры или веб-интерфейса для работы.

Zing vs Weblate: кто дожил до продакшена

В поисках CAT-инструмента мы изучили отечественные и зарубежные решения. Нам хотелось избежать сложностей с оформлением договоров на получение услуг и дополнительных затрат, поэтому нас заинтересовали решения из области open source-инструментов. После отсеивания инструментов по трем требованиям осталось два кандидата: Zing и Weblate.

Особенности Zing

Zing выглядел логичным выбором. Это бесплатный сервер перевода от Evernote с открытым исходным кодом и веб-интерфейсом. Zing разработали для бесшовной интеграции с Serge и поддержки всех его функций. Serge — это open source-инструмент от Evernote, который вытаскивает тексты на перевод из Git-репозитория и возвращает готовые переводы обратно.

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

Официальное объявление о поиске мейнтейнера для Zing. Спойлер: не нашли

Официальное объявление о поиске мейнтейнера для Zing. Спойлер: не нашли

Weblate: та же функциональность, но с поддержкой

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

Подходил Weblate и по техническим требованиям: самостоятельный веб-инструмент для локализации с API и интеграцией с системами контроля версий. В отличие от Zing, он не привязан к Serge, поэтому эти компоненты можно использовать и развивать независимо друг от друга.

В итоге инфраструктура локализации сложилась из двух основных компонентов — Serge и Weblate. Они решают разные задачи и вместе образуют единый конвейер локализации.

Первые наброски архитектуры

Первые наброски архитектуры

Все форматы к одному знаменателю

Прежде чем перейти к инструментам, немного о форматах. У бизнеса есть запрос на перевод различных форматов файлов: DITA-документы, UNI-конфиги, PDF и исходный код. Чтобы не разбираться с каждым форматом по отдельности, текст на перевод извлекается из исходного файла и сохраняется в формате PO — это стандарт в индустрии локализации.

PO (Portable Object) — текстовый формат GNU gettext. Это просто пары строк:

msgid "Server configuration"
msgstr "Конфигурация сервера"

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

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

Serge автоматизирует весь цикл работы с переводами. В упрощенном виде процесс выглядит так: исходные файлы в Git → извлечение строк → PO-файлы → перевод → интеграция переводов в исходные файлы → Git.

Сначала Serge получает исходные файлы из репозитория и с помощью подходящего парсера извлекает из них строки, предназначенные для перевода. Эти строки попадают в PO-файлы, с которыми уже работают переводчики.

После перевода процесс идет в обратную сторону: Serge берет готовые переводы из PO-файлов, с помощью того же механизма интегрирует их в исходные файлы и возвращает результат в систему контроля версий.

Такое разделение позволяет каждой стороне работать в привычной для нее среде. Разработчики продолжают работать с исходными файлами и Git, а переводчикам не приходится разбираться в форматах.

Но Serge — лишь часть локализационного цикла. Общий цикл выглядит так:

Обзор интерфейса и возможностей Weblate

Сегменты для перевода в Weblate организованы по проектам и компонентам. Каждый проект называется ровно как репозиторий и содержит в себе компоненты — файлы на перевод.

Weblate автоматически отслеживает статус каждой строки и категоризирует их: переведенные, незаконченные, непереведенные, с пометкой «К работе» и с пометкой о непройденной автоматической проверке на правильность перевода. Автопроверки помогают отлавливать и массово править частые ошибки в переводе. Например, в переведенной строке не хватает знака препинания, есть перенос строки или вообще находится тот же самый текст, что и в исходной строке.

В окне редактирования компонента мы посегментно обрабатываем его содержимое, переключаясь между вкладками:

  • Nearby strings — соседние сегменты в компоненте для понимания контекста.

  • Other occurrences — то, как этот сегмент переводится в других компонентах.

  • Comments — можно предложить или обсудить с коллегами текущий перевод.

  • Automatic suggestion — автоматическое предложение для перевода с тремя возможными источниками: память переводов, схожесть перевода с другими компонентами и ИИ-перевод.

  • Other languages — то, как исходный сегмент переводится на другие языки.

  • History — полная история изменений строки с датами и аккаунтами, вносившими изменения.

Для быстрого просмотра всего массива сегментов и перевода есть режим Zen.

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

«Толмач» — это не только Serge и Weblate, но и интеграция с Dify и LLM. В основном наши заказчики видят только веб-интерфейс, поэтому можно ошибочно подумать, что мы просто переименовали Weblate в Толмач, но это не так.

ИИ и ЫЫ

Самое интересное начинается на этапе перевода. Теперь вместо внешних сервисов типа DeepL или Google Translate мы используем собственный инференс-кластер.

Инференс-кластер — это выделенная локальная IT-инфраструктура компании для запуска обученных моделей искусственного интеллекта. Он дает полный контроль: данные никуда не уходят, стоимость фиксирована инфраструктурой, а модель и промпт можно заменить в любой момент.

Роль прослойки между Weblate и моделью играет Dify — open source-платформа для разработки и эксплуатации приложений на базе больших языковых моделей (LLM). По сути, это слой между моделью — Qwen, Deepseek, другой GPT-подобной —  и бизнес-логикой. Dify позволяет собирать ИИ-продукты без глубокого погружения в инфраструктуру.

Проект объединяет в себе:

  • конструктор LLM-приложений (чат-боты, ассистенты, агенты),

  • orchestration-слой (workflow / пайплайны),

  •  инструменты работы с базами знаний (RAG),

  • API-шлюз для интеграции в существующие системы.

Интерфейс у Dify визуальный, логика задается через блоки. Пайплайн для перевода совсем прост: текст → модель → постобработка → ответ. Для перевода мы используем reasoning-LLM Qwen3.6-35B-A3B.

Промпты и буква Ё

Промпт для модели Qwen

You are a professional translator at an IT company that manufactures high-tech equipment. All the terms are related to programming and engineering.

Translate the text from English into Russian, strictly following the instructions:

— DO NOT ADD YOUR OWN COMMENTS TO THE RESPONSE WITH THE TRANSLATED TEXT.

— Be sure to translate all lines of the original text.

— The formatting of the translated text must be exactly the same as in the original text.

— Do not invent markup and do not add extra tags to the translation.

— The number of lines in the translated text must be exactly the same as in the original text.

— The number of opening and closing tags in the translated text must be exactly the same as in the original text.

— If a word or words in the original text are enclosed in tags, then preserve exactly the same tags around the translation of that word or words.

— If the original text contains fragments that look like code, then leave these fragments unchanged in the translated text.

— If the original text contains fragments that look like code or those fragments are in codeblock or codeph tags, then leave these fragments unchanged in the translated text.

— If the original text contains words that are concatenated together or connected together with an underscore, then leave these words unchanged in the translated text.

Разберем следующий кейс: в документации исторически принято использовать букву «ё». Если мы дадим модели строку «Hedgehog in the Fog», она переведет ее как «ёжик в тумане». При этом как бы мы ни пытались внушить ей через длинный промпт, что нам не нужна буква «ё» и «ёжик» на самом деле — «ежик», она всегда будет упорно выдавать «ё».

Вся эта мышиная (ежиная) возня в промптах, относящаяся к форматированию отдельных символов, сильно забивает «мозги» модели и прилично снижает качество перевода.

Поэтому все, что можно сделать кодом, нужно и правильно делать кодом:

def main(arg1: str):
 	text = arg1.replace("ё", "е").replace("Ё", "Е")

 	return {
     	"result": text
 	}

Когда мы открываем вкладку Automatic suggestion в окне редактирования компонента, Weblate отправляет исходную строку на перевод в Dify. На обработку строки снизу понадобилось примерно 0,63 секунды.

Weblate изначально поддерживает подключение сервисов машинного перевода, которые администратор может включить в разделе автоматических подсказок. Для интеграции с Dify мы добавили его через конфигурационные файлы Docker. При запросе подсказки Weblate передает исходную строку и доступный контекст в настроенный Dify. Там запрос обрабатывается языковой моделью, а полученный перевод возвращается и отображается пользователю в привычном интерфейсе.

Загрузку переводов в Weblate мы также автоматизировали, потому что стандартные команды для отправки и получения сегментов для Weblate не работали. После формирования PO-файлов в Serge скрипт находит их в каталоге проекта и загружает через REST API в соответствующие компоненты Weblate. Скрипт проверяет наличие компонента, при необходимости создает его, а затем добавляет или обновляет файл русского перевода. Для обращения к API используется токенная авторизация. Weblate предоставляет отдельные API-методы для создания компонентов, добавления языков и загрузки файлов переводов.

ЫЫ

Без проблем, конечно, не обошлось. Основные сложности, типичные для LLM:

  • может галлюцинировать и менять смысл,

  • не всегда соблюдает терминологию,

  • иногда ломает форматирование строк.

ИИ обеспечивает качественный перевод, но не всегда консистентный из-за посегментной работы с текстом. Чтобы модель не добавляла чего-то в духе «конечно, дружище, вот твой перевод: <blah-blah>», мы задействовали структурный выход — определили единственное поле: russian_translation: string, «Перевод исходного текста на русский язык». Ответ модели возвращается в формате JSON, после чего система извлекает значение этого поля. В JSON ИИ посторонний текст дописывать стесняется. И тогда системный промпт становится предельно лаконичным:

Переведи отрывок текста с английского на русский язык, сохранив его структуру.

Желаемый формат выхода в соответствующем поле блока в Dify:

{
   "type": "object",
   "properties": {
 "russian_translation": {
   "type": "string",
   "description": "Перевод исходного отрывка текста на русский язык."
 }
   },
   "required": [
 "russian_translation"
   ],
   "additionalProperties": false
 }

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

В шесть раз дешевле Smartcat

Раз уж мы считаем деньги — вот во сколько нам обходится перевод на собственном инференс-кластере. Ниже разбивка по длине сегмента: чем он длиннее, тем дешевле каждое отдельное слово.

Расчет основан на стоимости видеокарты в 5 млн рублей, сроке ее службы в 5 лет и постоянной равномерной загрузке на уровне 30-40%. В него не входят затраты на сервер, электроэнергию, зарплаты обслуживающих инженеров и другие операционные расходы, поэтому реальная себестоимость будет выше.

Количество слов в промпте

Количество токенов

Общая стоимость в рублях

Стоимость слова в рублях

1

500

0,4

0,4

50

700

0,56

0,0112

125

1000

0,8

0,0064

250

1500

1,2

0,0048

Даже в самом дорогом сценарии обработки одно слово обходится примерно в 0,40 рублей. Для сравнения: текущие тарифы Smartcat составляют около 2,5 рублей за слово, то есть примерно в шесть раз больше.

Стоимость слова зависит от длины сегмента: чем больше в нем слов, тем дешевле каждое из них. Самый дорогой случай — сегмент из одного слова, и даже тогда цена не превышает 40 копеек.

В следующей части статьи я дам полный гайд по развертыванию и разберу все кейсы, которые мы локализовали. Долой проприетарщину!

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.