Все приложения нужно переводить. Какие-то на 6 языков, какие-то на 20. А какие-то на 13, но это совсем другой набор языков, в предыдущие 20 он не входит.
У всех разный стек, как следствие разные форматы строк: js, json, ts, yaml или yml. А кое-кто до сих пор хранит свои тексты в базе.
Вы работаете по Agile: ежедневная доставка ценностей, двухнедельные спринты. В DoR включено наличие всех необходимых переводов. Ну и, конечно, переводы нужны были вчера, чтобы успеть протестировать.
![image](http://risovach.ru/upload/2019/03/mem/chto-my-hotim_203596766_orig_.jpg)
Есть отдел технических писателей. Кто такой технический писатель? Это человек, который пишет внешнюю документацию, иногда — внутреннюю. Пишет все виды текстов, которые могут увидеть пользователи или партнеры: интерфейсные тексты, тексты писем, ответы API, ошибки. Сопровождает процесс разработки, чтобы быть погруженным в технику и бизнес-логику. И обеспечивает своевременную поставку переводов в приложение.
Еще есть должность копирайтера-переводчика и менеджера по локализации. Это человек, который создает все тексты на английском языке, а также следит за консистентностью переводов, назначает переводчиков, и решает все связанные проблемы.
Внимание, вопрос: как много техписов, копирайтеров и менеджеров по локализации необходимо, чтобы не стопорить разработку и не причинять боль всему техотделу?
В нашем случае мы обошлись 4 техписами и 1 копирайтером-менеджером по локализации. Поставка переводов в среднем укладывается в один рабочий день и никогда не превышает трех рабочих дней. Надеюсь, вам стало интересно.
Как мы к этому пришли
6 лет назад мы работали в Google sheets и БД. То есть, если в процессе разработки появлялись строки на перевод, мы их копировали в табличку, а потом по почте отправляли на перевод. Когда перевод был готов, его вручную заливали в БД. Единственный плюс такого решения — тебе не надо заново выкладывать приложение, чтобы увидеть новые строки. Зато если в переводах ошибка, откатиться назад не получится. Никакой памяти переводов, никаких глоссариев. Консистентность переводов достигается методом пристального взора.
Первая попытка
Первая версия автоматизировать этот процесс выглядела так: когда у разработчика появлялись строки, он добавлял их в новую ветку в специальном репозитории для переводов. Потом в этой же ветке запускался pipeline, который по API отправлял весь diff строк на перевод. Правда, обратно переводы должны были попадать уже в БД, а загружать по API строки с внешнего ресурса во внутреннюю БД не получилось.
Что дала такая интеграция? Был убран шаг, где техническому писателю нужно собирать все в одну таблицу, вручную отправлять, а затем делить полученные переводы по приложениям и по количеству языков. В данном случае строки сразу отправлялись на перевод в рамках проекта, одноименного с приложением, для которого они предназначались. На выходе технический писатель получал набор архивов, по каждому из приложений, для которых велась работа. Это существенно сократило долю ручного труда. К тому же на стороне провайдера была реализована память переводов. Но это решение сохраняло и ряд недостатков: хранение строк в БД не позволяло осуществлять полноценный менеджмент строк на нашей стороне и по-прежнему подразумевало большую долю ручной работы.
Боль и непрерывные локализации
Следующая интеграция принесла много страданий разработчикам. Мне кажется, у тех, кто ее застал, до сих пор при слове “локализация” дергается глаз. Это была первая интеграция с Serge и Smartcat.
![image](https://www.meme-arsenal.com/memes/904a6a1c916f7f2a34b21309855dce9d.jpg)
Тут важно рассказать, что такое Serge и Smartcat.
Serge — это утилита, которая поддерживает git. Она умеет доставать из ветки нужные строки, отправлять их на перевод, а затем возвращать в ту же самую ветку перевод только для этих строк. Еще нужен плагин, который будет вызывать API CAT-системы, в которой мы переводим. Плагин должен получать новые строки у Serge и возвращать Serge готовые переводы.
Smartcat — это CAT-система, с поддержкой глоссария, памяти переводов, плейсхолдеров. Также, Smartcat агрегирует и упрощает процесс взаиморасчетов с фрилансерами, поддерживает подключение вендоров переводов.
На этом шаге мы перенесли строки из БД в репозитории проектов. Теперь строки надо было отправлять прямо из репозитория приложения и возвращать их туда же.
Предполагалось, что это будет работать так: разработчик знает, от какой ветки он создал свою feature-ветку, и diff в ресурсных файлах между этими двумя ветками как раз и есть то, что надо перевести. Когда разработчик имеет набор строк для перевода, он в своей ветке запускает job с конфигом Serge. Serge вычисляет diff, извлекает новые строки, вызывает плагин и отправляет строки на перевод. Когда переводы готовы, разработчик вызывает следующий job: он разворачивает инстанс Serge, созданный на предыдущем шаге, получает готовые переводы и коммитит их в исходную ветку.
Решение оказалось нестабильным: Serge не предназначен для развертывания с нуля при каждом запуске pipeline, разработчики не желали думать о diff-ах между ветками, а плагин Smartcat остро нуждался в обновлении и доработке. Процесс доставки новых строк мог длиться часами. И, увы, не всегда заканчивался успехом.
Теоретически, были автоматизированы все стадии процесса, на деле же сопровождение, вычислении diff-а до запуска pipeline и troubleshooting занимали больше времени, чем выполнение той же задачи полностью вручную.
Свет в конце туннеля
К августу 2018 года мы запустили текущую версию интеграции. У нас есть сервер локализаций. На сервере для каждого репозитория существует свой инстанс Serge. Serge просматривает все ветки в репозитории, отправляет новые строки на перевод и коммитит готовые переводы в исходные ветки. В текущей интеграции все работает быстро и стабильно. После создания ветки для переводов, строки оказываются в Smartcat в течение 5-6 минут. После подтверждения переводов, коммит происходит аналогично, в течение тех же 5-6 минут. Срок поставки переводов ограничен лишь человеческим фактором: загруженностью переводчиков, разницей в часовых поясах и так далее.
В следующих статьях я расскажу, как с нуля настроить интеграцию Serge-Smartcat-Gitlab, и как мы решали разнообразные нестандартные задачи.
Комментарии (14)
Free_ze
27.03.2019 13:00У всех разный стек, как следствие разные форматы строк: js, json, ts, yaml или yml.
Соответствие такое себе, разве форматы нужны не затем, чтобы быть универсальными? Не в исходники строки запихивать, разумеется (кто ж до этого додумается?), а именно форматы файлов с данными xml/json/y(a)ml.NatalyaPavlikova Автор
27.03.2019 13:14Непрерывные локализации интегрировались в уже существующие проекты, и не потребовали менять формат строк. Оно просто работает из коробки с тем, что есть.
Free_ze
27.03.2019 13:27Разумеется. Я бурчу о том, что это гениальное решение, но все же для проблем, которых можно было избежать, проектируя приложения грамотно изначально.
afan
27.03.2019 21:27Это не всегда возможно: когда приложения/платформы разные, то лучше всего использовать стандартные решения и форматы для каждой платформы (.strings для iOS/macOS, XML для Android, JSON для расширений Chrome и т.д.). А возможность работы с ресурсами разных форматах в системе локализации все равно должна быть, и это уже второстепенная деталь имплементации. Хвост (локализация) точно не должен вилять собакой (инженерами). :)
Free_ze
28.03.2019 11:42то лучше всего использовать стандартные решения и форматы для каждой платформы
В данном случае именно, что не лучше: требует усложнение процесса вместо унификации. Формат хранения не такая принципиально важная штука, чтобы плодить тучу вариаций просто потому, что это дефолт.afan
28.03.2019 19:09Если вы считаете, что поддержка нескольких общепринятых форматов ресурсов локализации усложняет процесс, то что-то не так с вашим процессом локализации. Это как раз самая незамысловатая часть процесса. А вот перекраивать устоявшиеся практики разработки под платформы (а в некоторых случаях и заставлять инженеров что-то переделывать) — это только наживать проблемы между разработчиками и отделом локализации.
Я полностью соглашусь с мнением, что интернационализацию и выбор форматов файлов ресурсов лучше продумывать заранее (особенно если платформа разработки позволяет гибкость в этом плане), но и перегибать палку, принуждая всех использовать один и тот же формат, не надо. Да и как я упомянул выше, это просто далеко не всегда возможно.Free_ze
28.03.2019 20:45Если вы считаете, что поддержка нескольких общепринятых форматов ресурсов локализации усложняет процесс, то что-то не так с вашим процессом локализации.
Что вы там говорили про хвост, виляющий собакой?)
А вот перекраивать устоявшиеся практики разработки под платформы
Зачем из разницы текстовых форматов делать культ карго? Это не более, чем дефолт. Не настройки самого приложения, а лишь внешние ресурсы.
я упомянул выше, это просто далеко не всегда возможно.
Вы упомянали стандартные инструменты, но не невозможность.afan
28.03.2019 22:14Иногда это именно невозможность. При нативной разработке под Android их XML-формат это единственно возможный вариант работы с ресурсами. Нет, можно, конечно, обойти все практики и придумать на этом месте что-то свое, но при этом придется отказываться от кучи удобств связанных с использованием стандартного формата. Т.е. выбор другого формата приносит гораздо больше проблем, чем решает. Ровно та же картина и с другими платформами. Единого формата ресурсов просто нет и быть не может (и не нужно к нему стремиться). Я как раз за то, чтобы не делать культ карго из унификации и позволить инженерам использовать штатные механизмы работы с их проектами.
Free_ze
29.03.2019 11:00далеко не всегда возможно
единственно возможный вариант
Нет, можно, конечно
Ровно та же картина и с другими платформами
просто нет и быть не может
Кмк, слишком много категоричности и при этом нет аргументов, которые можно было бы обсудить.
Всего доброго!
DitriXNew
28.03.2019 09:04Вот читаю и плачу. Нам бы ваши проблемы в мире 1С :)
В 1С вообще нет такого понятия как ресурсный файл, там тупо весь текст в самом коде, как форм так и коде.
Хотя, мы решили эту проблему.
Но в отличии от вас мы пошли по пути, когда программист пишет все всегда на 1 языке.
Далее идет ветка дев, запускаются все тесты (дымовые, сценарные, синтаксические контроли т.д.), после этого, если все ок — запускается пайплайн перевода, который делает клон ветки дева, загружает/обновляет тексты для перевода, переводит, возвращает все вов ременную ветку и потом на этой ветке стартует опять весь цикл сборки с тестами, и вот если он прошел хорошо, то тогда только все собирается и уходит в мастер, а рядом ложится скомпилированный файл.
Но да, перевод это еще те чудеса, особенно с учетом того, что у нас например идут разные варианты сборок по языкам. Кстати — сами используем смарткет, совет тем кто начинает с ним и читает их апи — не верьте ему :)
Все таки ерп системы — большие, там нормальное явление сотни тысяч строк и миллионы слов на перевод (конечно есть повторы, но этого не легче, на самом деле, а совсем наоборот).
Жду вторую статью с переводом.
wtigga
С интересом жду следующей статьи про конкретную настройку Serge.