Your browser is not supported anymore. Please update to a more recent one.


Download Chrome

Download Firefox

Download
Internet Explorer

Download Safari

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

28 сентября 2017 | Алексей Тимин


Герои сериала «Шерлок»


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


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



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


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

Перечисленные инструменты призваны помочь в процессе локализации сайта и мобильных приложений Badoo на 47 языков. Это огромный фронт работ.


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


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


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

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


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


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



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


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


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


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


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


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


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



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



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


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



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


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



$ grep -l ‘iPhone 7’ pages/* 

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


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



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


Не будем касаться вопросов разархивирования и чтения 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 в браузере, то увидите переведённый скриншот:



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


Заключение


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


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


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