Переводим интерфейсы на полсотни языков. Sketch

в 9:00, , рубрики: javascript, node.js, nodejs, open source, sketch, Блог компании Badoo, интерфейсы, Программирование

Переводим интерфейсы на полсотни языков. Sketch - 1
Герои сериала «Шерлок»

Привет! Я Алексей Тимин, инженер из команды локализации Badoo. В этом посте я расскажу вам о том, как мы помогаем переводчикам в их нелёгком труде, и о новом Open Source-решении, позволяющем генерировать скриншоты дизайна, подготовленного в Sketch, для разных языков.

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

В команде локализации Badoo всего лишь два разработчика, но мы держимся и создаём очень интересные инструменты:

  • Translation Memory
  • Collaborative Translation Platform, доступной по адресу https://translate.badoo.com/,
  • функционал предоставления корректного перевода конкретному пользователю (в зависимости от языка, пола, склонения, числа),
  • система подготовки переводов для A/B-тестирования (да, мы проводим тестирование вариантов перевода, чтобы определить, какая формулировка лучше),
  • десяток интерфейсов для работы переводчиков,
  • сбор статистики по работе переводчиков и использованию ими инструментов.

Перечисленные инструменты призваны помочь в процессе локализации сайта Badoo, двух мобильных приложений Badoo (для Android и iOS), а также партнёрских приложений Chappy, Bumble, Huggle, Hot or Not на 47 языков. Это огромный фронт работ.

Наши переводчики работают с лексемами (так мы называем неделимую единицу перевода: слово или предложение). Для каждой лексемы подбирается формулировка оптимальной длины, чтобы обеспечить корректное отображение приложения на экранах пользователей. Иногда перевод должен быть не только корректным, но и привлекательным (например, для маркетинговых нужд).

Процесс перевода выглядит так:

  1. Дизайнеры рисуют.
  2. Программисты программируют.
  3. Переводчики переводят.
  4. Релиз.

Как видно, переводчики вынуждены ждать прототип приложения от программистов. Или, если произошли изменения в переводах, им необходимо попросить разработчиков собрать заново тестовую версию, чтобы проверить отображение. Но у нас зародилась идея максимально ограничить участие программистов в процессе перевода и ускорить подготовку релиза.

По нашей задумке, процесс должен выглядеть так:

  1. Дизайнеры рисуют.
  2. Программисты программируют, а переводчики – переводят и могут каким-то способом сразу видеть результат.
  3. Релиз.

Чтобы вам было проще представить проблему, привожу схемы процесса до и после. Красным на первой схеме выделен оптимизируемый участок:

Переводим интерфейсы на полсотни языков. Sketch - 2

Наши дизайнеры работают в графическом редакторе Sketch. Мы выяснили, что идущая вместе с ним утилита sketch-tool умеет генерировать скриншоты, а это значит, при добавлении перевода есть возможность сразу показывать скриншот переводчику! Но возник вопрос: как заменить исходные тексты в дизайне, чтобы получить локализованный скриншот?

В перерывах между вечеринками мы обсуждали возможные варианты реализации идеи. И выход был найден.

Давайте разберёмся, как устроен .sketch-файл изнутри.

Представление данных внутри .sketch-файла

В 43-й версии Sketch разработчики стали использовать новый формат .sketch-файла для «лучшей интеграции со сторонними сервисами».

Логически в подготовленном в Sketch дизайне выделяются Pages, Artboards и графические элементы. Каждой сущности – Pages, Artboards и графическим элементам – один раз (в момент создания) присваивается уникальный идентификатор (UUID), который впоследствии не меняется.

Схематично связи между сущностями можно изобразить так:

Переводим интерфейсы на полсотни языков. Sketch - 3

Смотрите картинку ниже, чтобы понять, что есть что в интерфейсе Sketch: iPhone SE и iPhone 7 – две из возможных Artboards, a Page 1 – это одна из возможных Pages.

Переводим интерфейсы на полсотни языков. Sketch - 4

Сохранённый в .sketch-файл дизайн представляет собой ZIP-архив, внутри которого находятся директории с PNG- и JSON-файлами. Выглядит просто?

Если мы разархивируем .sketch-файл, то дерево директорий получится примерно таким:

Переводим интерфейсы на полсотни языков. Sketch - 5

Информация о каждой Page и связанных объектах Artboard хранится в pages/*.json. Именем файла служит UUID объекта Page, каждому объекту Page соответствует один файл.

Мы можем запросто открыть любой pages/*.json и отредактировать, например, название одного из Artboards. Чтобы определить конкретный файл для редактирования, запускаем:

$ grep -l ‘iPhone 7’ pages/* 

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

…смерть его на конце иглы, та игла в яйце, то яйцо в утке, та утка в зайце, тот заяц в сундуке, а сундук стоит на высоком дубу...
«Царевна-лягушка»

Текст на кнопке упакован в бинарный plist, закодированный в строку Base64, являющуюся значением атрибута сериализованного JS-объекта, находящегося в одном из файлов, сжатых ZIP-ом.
Переводим интерфейсы на полсотни языков. Sketch - 6

Не будем касаться вопросов разархивирования и чтения JSON из файлов, но стоит сказать о формате Property Lists (bplist на схеме выше). Чтобы модифицировать текст «Нажми меня», можно использовать утилиту plutil. Она позволяет вставить новое и удалить старое значение некоего свойства, а ещё с её помощью можно преобразовать plist из бинарного вида в XML и обратно. XML – удобный формат, для работы с ним существует множество инструментов. Также возможен экспорт в JSON, но, во-первых, при этом происходит потеря типов данных, а во-вторых, не всегда plist может быть сконвертирован в JSON. Например, с plist-ом из .sketch-файла экспорт в JSON не сработал.

Итак, мы разобрались с внутренним представлением и наконец переходим к вариантам реализации нашей задумки.

Выбор подходящей реализации

Вариант 1. Ленивое решение

Мы пытались рассказать переводчикам про JSON, Base64 и bplist, научить их самостоятельно заменять тексты переводами и делать скриншоты. Но когда им показали консольную команду экспорта превью

$ sketchtool export artboards --items='42C53146-F9BF-4EEE-A4F8-BB489F0A3CDA,BF38A95A-F0CD-452E-BE26-E346EBD349CE' --formats=png --save-for-web example_design.sketch

поняли, что этот вариант не годится.

(Шутка, ничего переводчикам мы не рассказывали, а сразу перешли ко второму варианту).

Вариант 2. True way

Переводчики не должны думать о технических вопросах. Просто нужно, чтобы при сохранении перевода им был предоставлен скриншот.

Для этого мы решили разработать сервис, минимальным функционалом которого стало бы:

  1. Определение в .sketch-файле UUID графических элементов, содержащих текст.
  2. Генерация скриншотов с локализованным текстом.

Проект получил название Sketch Modifier и был опубликован на GitHub.

Работа со Sketch Modifier

Чтобы начать использовать Sketch Modifier, нужно установить Node.js. на macOS (где конечно уже должен быть установлен Sketch https://www.sketchapp.com/). Да, Sketch есть только под macOS. Но если ваш дизайнер работает в Sketch, то как минимум один Mac у вас есть.

Рассмотрим процесс работы со Sketch Modifier по шагам.

Шаг 1. Установка

Находите компьютер под управлением macOS. Скачиваете и устанавливаете на него Node.js, что совсем просто.

Далее скачиваете архив или клонируете репозиторий с GitHub командой

$ git clone https://github.com/AlexTimin/sketch-modifier.git

Переходите в директорию проекта

$ cd sketch-modifier

Устанавливаете зависимости с помощью npm:

$ npm install

И, наконец, запускаете сервер

$ ./bin/www

Всё, теперь по адресу http://localhost:3000 у вас должен отзываться сервер. Можете перейти по этому адресу в браузере и проверить.

Шаг 2. Загрузка .sketch-файла и определение исходных текстов

Для примера возьмем example_design.sketch и загрузим его в систему. Для этого нужно отправить запрос из директории, в которую вы сохранили example_design.sketch:

$ curl -F 'data=@example_design.sketch' http://localhost:3000/add-sketch/

.sketch-файлу будет присвоен UUID. В ответ вы получите JSON следующего вида:

{
    "8a2009c5-36ca-4328-87d6-16aa0c2e2800": {  // присвоенный example_design.sketch UUID, у вас он будет другой
        "5A0F429A-C974-460A-9482-93AED7456850": {  // Page 1 UUID
            "C1C29749-B967-494D-8D7E-A484EAB37534": {  // iPhone SE Artboard UUID
                "E335D359-9DF3-4DCC-8B79-E77E38824714": "Нажми меня" // UUID текста на кнопке
            }
            … // информация по другим Artboards
        }
        … // информация по другим Pages
    }
}

Можете сохранить эти данные себе в базу, отправить в /dev/null или сделать ещё что-нибудь интересное. Но мы сохраняем их в базу.

Шаг 3. Генерация переведённых превью

Чтобы заменить текст, нужно отправить запрос на адрес http://localhost:3000/generate-preview/ с указанием параметров screens и textReplaces. Список необходимых команд будет ниже, а пока разберёмся со структурой параметров запроса.

В параметре screens мы указываем список UUID тех Artboards, скриншоты которых хотим получить. Значение параметра имеет такую структуру:

{
    Example Design UUID: [  // example_design.sketch
        Artboard UUID,  // iPhone SE
        ... 
    ]
}

В textReplaces мы указываем UUID текстовых элементов и новый текст. Значение параметра имеет такую структуру:

{
    Text UUID: "новый текст, перевод",
    ...
}

Итак, формируем запрос для генерации скриншота. Заменим текст «Нажми меня» на «Start the party!», например. Для этого нам понадобится файл generate-preview-request-data, в котором мы укажем значения параметров запроса.

Содержимое файла generate-preview-request-data:

textReplaces={
    "E335D359-9DF3-4DCC-8B79-E77E38824714": "Start the  party!"
}&screens={
    "8a2009c5-36ca-4328-87d6-16aa0c2e2800" : [
        "C1C29749-B967-494D-8D7E-A484EAB37534"
    ]
}

Выполняем команду из директории, в которую вы сохранили файл generate-preview-request-data.

$ curl -X POST -d "@generate-preview-request-data" http://localhost:3000/generate-preview/

В ответ вы получите скриншоты в Base64. Структура ответа будет такая:

{
    "C1C29749-B967-494D-8D7E-A484EAB37534": "data:image/7HYUIY786GFFDASeY+...;base64", 
    ...
}

Наверное, вы догадались, что ключом в структуре ответа является UUID запрошенного скриншота, а в значении записано представление скриншота (напомню, мы запрашивали скриншот для iPhone SE) в Base64.

Если вы сохраните, допустим, в example.html следующий код с подставленным Base64-представлением картинки

<img src="скриншот в Base64">

а потом откроете example.html в браузере, то увидите переведённый скриншот:

Переводим интерфейсы на полсотни языков. Sketch - 7

C помощью Sketch Modifier вы можете делать скриншоты до локализации, в процессе и после локализации, что очень важно. Вы будете видеть, как ведёт себя дизайн при использовании реальных текстов, и понимать, что нужно доработать.

Заключение

Мы настраиваем работу со Sketch Modifier таким образом, что дизайн загружается один раз, а скриншоты генерируются при сохранении переводов. Переводчики будут сразу видеть, умещаются ли выбранные формулировки переводов в заданных областях. А значит, о проблемах будет известно заранее.

Исходный код реализации находится на GitHub.

Пользуйтесь, советуйте способы усовершенствования, пишите отзывы.

Автор: aatimin

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js