Tanya Veryasova
452
Блоги

Готовим мобильное приложение к мировому успеху

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

Поделиться

В избранное

В избранном

Хочешь увеличить продажи? Приручи локализацию!

Речь в этой статье пойдет о том, как изначально писать приложение или игру с тем прицелом, чтобы она вышла на региональные рынки. Что же нужно знать, чтобы на этапе локализации не пришлось переписывать исходный код или, что еще обиднее, отказываться от идеи международного признания? К каким уловкам прибегнуть, чтобы создать действительно дружественный к локализации продукт? Говоря проще, как приручить локализацию? Имея достаточный опыт и опираясь на советы от таких титанов индустрии, как, например, Google, мы с коллегами из Allcorrect собрали список того, на что обязательно нужно обратить внимание разработчика при планировании стадий работы над продуктом.

Локализация, интернационализация и… нижнее белье. Что между ними общего?

Ключевым словом этой статьи будет даже не «локализация» (в англоязычных источниках известная как l10n), а «интернационализация» (i18n). Слово не очень популярное, но зато описывающее концепт как нельзя точно. Поясню: локализация — это адаптация продукта под отдельно взятый регион, или локаль; интернационализация же — это список подготовительных мер, способных обеспечить в будущем легкую и, как сейчас модно говорить, бесшовную локализацию на языки вашей целевой аудитории. Мне очень нравится сравнение интернационализации с нижним бельем: когда оно на месте, его никто не видит, но стоит нам о нем забыть, — и мы начинаем притягивать осуждающие взгляды (окей, не всегда осуждающие, но точно нежелательные).

В некоторых компаниях интернационализацией занимаются менеджеры по локализации совместно с разработчиками, в некоторых существуют целые отделы по интернационализации, а где-то вопросам интернационализации не уделяют должного внимания до тех пор, пока не приступят к локализации.

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

И тогда на разработку и менеджеров сыпется ворох проблем: как локализовать на арабский, если при написании кода не были предусмотрены обратнонаправленные (Bidi) шрифты? Как быть, если предустановленный формат даты не подходит для таргет-локали? Как, в конце концов, объяснить переводчику, где текст, подлежащий переводу, а где — ключ? Выясняется, что при кажущейся незначительности этапа интернационализации, она способна серьезно облегчить жизнь всем, кто работает над продуктом, и совершенно незаменима в тех командах, где запланировано расширение продукта, то есть его постоянные обновления. Итак, что же делать, чтобы избежать подобных трудностей?

Руководство к действию. По пунктам.

1. Отдели текст, который увидит конечный пользователь, от кода. Это нужно сделать на этапе разработки независимо от характера создаваемого продукта, так как в дальнейшем этот процесс может повлечь потери разного рода. Например, невозможность локализации некоторых строк в дальнейшем.

Если локализуемые ресурсы отделены от кода и хранятся отдельно, то ими можно управлять. В последнее время появились очень достойные (и бесплатные!) системы, направленные как раз на это.

2. Позаботься о поддержке разных символьных систем (например, двухбайтовых и обратно направленных). Возможно, однажды будет принято решение о том, чтобы приложение заговорило на арабском или иврите.

Кстати, вот здесь есть отличное видео об особенностях работы с обратнонаправленными текстами.

3. Позаботься о поддержке разных методов ввода и раскладок клавиатуры.

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

4. Не увлекайся конкатенацией, или склеиванием строк. Если предложения собираются из «кусков» кода, то при изменении правил языка такие предложения выглядят как плохой перевод. Ну или как цитаты мастера Йоды.

Поясню: многим разработчикам, не искушенным в вопросах локализации, кажется, что, если заменить определенные существительные переменными, то это унифицирует многие фразы и приведет к экономии времени и ресурсов. Однако на практике это может привести к тому, что большая часть фраз, содержащих такие переменные, будет переведена максимально обезличенно. Приведу пример: (1) invites you to (2), где (1) — это имя игрока, скажем, Вася, а (2) — локация. Например, Лысая пустошь. Наличие переменной предполагает одинаковое использование имени/названия во всех случаях употребления, и мы можем использовать только именительный падеж, поэтому перевод такой фразы может превратиться во что-то подобное: «Лысая пустошь — вот куда приглашает вас игрок Вася!» Изначально идея склеивать строки выглядит очень привлекательно из-за кажущегося снижения расходов на его обработку. Однако, как любая стандартизация, она сильно ограничивает свободу. Это может вылиться в тяжелые, трудно читаемые или откровенно плохие тексты, что для игр, например, является критичным. Реальное сокращение затрат на локализацию возможно только при грамотном планировании циклов, когда предусмотрены риски и проведен целый ряд мероприятий по интернационализации.

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

5. Локализуй графику. Текст, вшитый в графические объекты, тоже должен быть локализован. Любой уважающий себя локализатор без возражений примет файлы .psd и многих других популярных графических форматов в работу. Правда, потребуется перерисовка, что дороже. Поэтому лучше заблаговременно вытащить текст из картинок и затем вставить локализованные строки обратно в графику.

Этот список может быть дополнен и другими пунктами в зависимости от характера выпускаемого продукта, универсального чек-листа здесь быть не может.

Для многих приложений, например, не лишним будет воспользоваться библиотеками дат, валют, адресов, телефонных номеров и прочих культурных особенностей. Кстати, таких библиотек масса, и они в свободном доступе. Достаточно поискать i18n libraries в поисковике, и вуаля — ты великолепен! В идеале приложение должно подтягивать такие данные прямо из браузера или операционной системы, на которую оно установлено.

Карта стран, в которых используется формат даты MMDDYYYY

6. Теперь протестируй это. Предположим, мы вынесли локализуемые ресурсы за пределы кода, убедились, что поддерживаются все вышеописанные требования и даже библиотеки встроили. Если всё так, то нам не составит большого труда воспользоваться машинным переводом и вшить получившийся текст на русском, греческом, японском и всех остальных таргет-языках в продукт. Этот прием позволит увидеть, на сколько увеличился или уменьшился объем текста, все ли символы поддерживаются, как отображаются списки и нет ли где в «готовом» продукте кода. Это называется псевдолокализацией. Хорошей практикой является включение псевдолокализации в список стандартного набора процедур тестирования. Для подавляющего большинства локализованных продуктов эта ступень выявляет многие недочеты и позволяет устранить их с наименьшими потерями. Другими словами, псевдолокализация поможет вам удостовериться, что локализованный билд сохраняет изначальную функциональность и соответствует заявленным параметрам. Это куда лучше, чем за пару дней до релиза получить тексты от локализатора, встроить их и обнаружить, что ничего не умещается! Вот, кстати, ресурс, где с помощью простого запроса можно посмотреть, сколько места займет тот или иной язык. Обладая этой информацией, можно просто добавить {n} процентов символов, например, немецкого языка (или любого другого) в начало строки, чтобы увидеть, обрезается или нет оставшийся английский текст. Этот метод хорош для тех, кто не знает немецкого, конечно.

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

8. Отдай это все локализатору. Даже если твой сосед отлично говорит на японском. Даже если у тебя была пятерка по английскому в универе. Даже если тексты на первый взгляд простые, и кажется, что любой человек со знанием языка справится с переводом. Соблазн очень велик, но ведь мы говорим о хорошей локализации, правда? Здесь также нужно отметить, что тексты, полученные от локализатора, все равно нужно будет протестировать после имплементации, но это уже другой тип тестирования — лингвистический. Если приложение отдается в локализацию под ключ, то эта услуга, как правило, включена.

От теории к практике

Все это довольно понятно в теории, тем более, что сейчас хватает ресурсов, подробно объясняющих, на что именно обращать внимание на этапе интернационализации. Но что же на практике? В индустрии локализации проводятся периодические мероприятия по обмену опытом между менеджерами, переводчиками и редакторами, но как же инженеры и разработчики, ведь их часть работы над локализацией принципиально иная? Здесь налицо очевидный пробел: статей, кейсов и лучших практик на эту тему катастрофически мало, да и они преимущественно на английском. Поэтому программные решения по интернационализации ложатся на плечи самих разработчиков. Приведу пример: как отделить текст, который нужно локализовать, от кода? Если приложение пишется для iOS, то ответ на этот вопрос можно найти здесь, здесь и здесь. Если это Android-приложение, то будет полезно заглянуть сюда. Но если в разработке десктопное приложение или приложение на базе web? Что если строки, которые нужно локализовать, вшиты в HTML-шаблоны? Тут, вероятно, придется повозиться. Каждая текстовая константа должна проходить через фреймворк, отделяющий такие строки, независимо от используемого языка программирования. Только так можно обеспечить последующую локализацию на любые таргет-языки.

Этот процесс нельзя назвать легким. Для того, чтобы получился добротный материал, возможно, придется пересмотреть механизмы парсинга, присущие современным TMS системам. Что здесь имеется в виду? Повторюсь, подавляющее большинство продуктов на сегодняшний день используют английский язык в качестве оригинального. Но английский - это аналитический язык, где одно слово может иметь целую кучу смыслов, в отличие, например, от синтетических языков, где грамматические значения выражаются при помощи служебных слов, или даже полисинтетических языков, где в пределах цельнооформленного комплекса (внешне напоминающего слово) объединено несколько именных и глагольных лексических значений. Проще говоря, you в английском может переводиться как du или Sie в немецком. Это значит, что для одной строчки ключа придется оставить две или даже три строчки под локализованный текст. И даже встроить контекст с примерами для переводчиков!

Такая работа в идеале подразумевает постоянное взаимодействие разработки и локализаторов: встречи, консультации, переписка. Это процесс не быстрый, он может занять месяцы, но это то, чего требует localization friendly продукт.

Но ведь лучше сделать это однажды, чем потом переписывать исходный код для каждого нового рынка. В итоге это действительно сэкономит время и ресурсы!

От интернационализации к локализации

Да, интернационализация — дело довольно скучное, но очень нужное. А для компаний, выпускающих мультиязычные продукты, она просто необходима. Выход приложения на глобальный рынок — это очень серьезный шаг, который требует сил, времени и ресурсов. И чем профессиональнее подготовка, тем легче и дешевле будет в дальнейшем проводить любые финишные работы по локализации. Когда приложение хорошо говорит на языке пользователя, возрастают продажи, ведь конечный пользователь понимает, что о нем позаботились, его любят. И он обязательно отвечает взаимностью.

Материал подготовила Марина Лехина — менеджер проектов Allсorrect

{ "author_name": "Tanya Veryasova", "author_type": "self", "tags": [], "comments": 1, "likes": 7, "favorites": 12, "is_advertisement": false, "section_name": "blog", "id": "36078", "is_wide": "" }
{ "is_needs_advanced_access": false }

Комментарии Комм.

Популярные

По порядку

0

Прямой эфир

Подписаться на push-уведомления
[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ]