Локализация приложений в Mac OS
Процесс создания приложения, ориентированного на международные рынки, состоит из двух этапов: интернационализации и локализации. Первое подразумевает под собой внесение изменений в процесс создания программы дабы облегчить дальнейший этап локализации. Последняя включает в себя приведение формата отображаемых данных и интерфейса программы к виду, принятому в отдельных государствах: как то формат отображения дат, чисел, а также месторасположение элементов визуального облика приложения, и, конечно, перевод текстовых и иных сообщений на язык целевого пользователя.
Локализация, применительно к разрабатываемым для Mac OS приложениям, должна включать в себя одну или несколько следующих частей:
- локализация и модификация nib-файлов
- перевод статического текста в коде программы
- локализация иконок и графические элементы
- звуковые файлы, содержащие сообщения на иностранном языке, должны иметь переведенные аналоги
- если ваше приложение имеет онлайновую документацию, то нужно не забывать о доступности ее текстов для пользователей всех стран, где будут использовать вашу программу
- динамический текст (включая дату, время и числа) должен быть приведен к формату согласно текущей локали
- код, обеспечивающий поддержку обработки текста, должен вычислять корректные места переносов в словах
Интернационализация приложений
Правильно проведенный процесс интернационализации значительно снижает объем работы по дальнейшей локализации приложения и добавление дополнительных поддерживаемых языков в программу.
Все ресурсы, требующие локализации, можно условно разделить на две части: текстовые и двоичные (изображение, звуки, nib-файлы). Процесс выборки локализованной версии текстового ресурса представляет собой получение значения перевода строки по указанному значению. Этот процесс похож на использование туристического разговорника. Выборка двоичных ресурсов происходит путем получения локализованной версии файла.
Структура папок локализованного приложения отличается наличием одной или нескольких папок .lproj, хранящих переведенные на указанный язык ресурсы.
Calculator.app/ сборка (bundle) Contents/ MacOS/ Calculator исполняемый файл Info.plist Resources/ папка с ресурсами Calculator.icns tapeButton.tif не локализованные ресурсы English.lproj/ папка с ресурсами, локализованными для англоязычной аудитории Localizable.strings динамически отображаемые строки Calculator.nib интерфейс приложения CalculatorHelp/ файлы документации и помощи ru.lproj/ папка с ресурсами, локализованными для русскоязычной аудитории Localizable.strings Calculator.nib CalculatorHelp/ ...
Процесс создания папок lproj и версий ресурсов для каждой из них лежит на плечах XCode, а вот ответственность за перевод и локализацию — на ваших.
Интернационализацию или подготовку приложения к дальнейшей локализации можно условно разделить на два этапа:
- Модификация кода приложения и использование консольной утилиты genstrings для формирования файла, содержащего все строки, используемые в коде приложения, которые требуют перевода
- Создание затребованного количества папок lproj под локализацию и модификация ресурсов в них для указанных языков
Начнем с первого этапа и воспользуемся созданным нами в прошлых постах приложением txtEdit в качестве основы для наших экспериментов.
Чтобы показать все возможные варианты локализации нам потребуется внести в код проекта некоторые изменения. Во-первых, удалите из класса mainViewController метод awakeFromNib, в котором мы формировали подпись “Back” к кнопке возврата. Прелесть создания приложений в XCode (как, собственно, и в любом языке) заключается в том, что к одному и тому же результату можно прийти несколькими путями. Дело в том, что свойство backBarButtonItem доступно для изменения не только программным путем, но и в Interface Builder.
Откройте файл MainWindow.xib и, раскрыв все дерево подчинения элементов, выберите в нем Navigation Item, принадлежащий mainViewController.
В инспекторе свойств перейдите на закладку атрибуты и установите значение поля Back Button как “Back”.
Благодаря нашим стараниям, в интерфейсе приложения появится новый элемент BarButtonItem, отождествленный с нашей кнопкой возврата.
Для каждой версии перевода мы впишем новое значение подписи к кнопке. Сохраните и закройте файл MainWindow.xib.
Для создания файла переводов для строк, используемых в коде приложения, нам, прежде всего, необходимо подготовить сам код к локализации, ведь в более общей ситуации нам нет нужны переводить все используемые в приложении строки и фразы. Чтобы показать, что для данного текста будет браться его локализованный вариант согласно текущей языковой настройки пользователя, необходимо конвертировать строку в вызов метода NSLocalizedString. Для примера, сделаем перевод кнопки “Done”, которую мы использовали в классе txtEditViewController.
Вы помните, что мы создавали кнопку вручную, используя метод initWithBarButtonSystemItem:target:action:, где в качестве параметров не указывается подпись к кнопке. Поэтому нам потребуется заменить строку инициализации на следующую:
UIBarButtonItem *buttonDone = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Done", @"")
style:UIBarButtonItemStyleDone
target:self
action:@selector(doneAction:)];
Во-первых, мы использовали конструктор кнопки с указанием подписи к ней, а во-вторых, добавили вызов NSLocalizedString, тем самым указав на выборку переведенной версии строки “Done”. В реальности NSLocalizedString является не методом, а макросом, скрывающим следующий вызов:
[[NSBundle mainBundle] localizedStringForKey:@"Done" value:@"" table:nil];
Для обращения к ресурсам приложения используются метода класса NSBundle. localizedStringForKey:value:table возвращает перевод указанной строки. В случае, если значения перевода не существует, используется значение value. Параметр table указывает на название файла перевода. По умолчанию, это Localizable.strings.
Нам осталось только сформировать данный файл. Для этого запустите терминал и перейдите в папку Classes нашего приложения. Находясь в этой папке, запустите команду:
genstrings ./*.m
Результатом выполнения команды станет сформированный в том же каталоге файл перевода для всех используемых в приложении классов. Добавьте файл Localizable.strings в проект, обязательно указав при его импортировании кодировку UTF-16.
Файл перевода представляет собой обычный текстовый файл, содержащий пары ключ-значение. Ключ может быть строкой символов только из нижней части ASCII-таблицы, то есть преимущественно состоящим из латинских букв, цифр и специальных символов. В качестве ключа могут использоваться также и сложные выражения, строки с информацией о форматировании, не нарушающие данного условия.
"File %@ not found." = "Le fichier %@ n’existe pas.";
Локализация приложений
Процесс локализации приложений в Mac OS легок и прост. Исполняемый файл программы отделен от локализованных ресурсов (текстов, изображений, звуков), сгруппированных по отдельным папкам. Как вы видели выше, локализованные ресурсы хранятся в отдельной .lproj директории для каждого поддерживаемого языка. Папки .lproj названы согласно спецификациям ISO. Содержимое всех таких папок должно быть одинаковым.
В региональных настройках Mac OS вы указываете свой основной язык и список дополнительных языков. В случае, если приложение не поддерживает ваш основной язык, то будет использоваться язык из указанного списка. Если ни для одного из указанных языков не было найдено файлов перевода, то приложение будет использовать язык, указанный по умолчанию при разработке программы. Это значение указывается в переменной “Localization native development region” (эквивалент в xml-варианте — CFBundleDevelopmentRegion) в файле Info.plist.
Различают идентификатор языка и идентификатор локали. Оба состоят из двух частей: идентификатора языка и идентификатора региона. Разница в том, что первый из них в качестве разделителя использует дефис, второй — знак подчеркивания. Идентификатор языка вида en-US описывает язык или диалект языка, в то время как en_US описывает регион, где разговаривают на данном языке. Несмотря на кажущуюся общность определений, имеется различие. Идентификатор языка описывает только разговорный и язык письма, а идентификатор локали — описывает регион, его специфику, культурную составляющую, в частности формат представления данных.
В своих программах вы можете использовать обобщения для представления единых данных для ряда регионов. Например, создание пакета ресурсов en.lproj, единого для США, Великобритании и Австралии вместо отдельных en_US.lproj, en_GB.lproj, и en_AU.lproj, позволит вам уменьшить размер вашей сборки. В качестве имени для папки с локализованными версиями ресурсов можно использовать полное название языка, например, Russian, German, Japanese, но поддержка такого наименования может быть убрана из будущих версий Mac OS и лучше придерживаться принятых в ISO обозначений.
Как я говорил выше, XCode берет на себя работу по созданию lproj директорий, и пришло время показать как он это делает. В нашем приложении мы будем локализовать два файла: MainWindow.xib и Localizable.strings. Найдите их в списке файлов в проекте XCode и последовательно для каждого выполните следующие действия.
Нажмите правой кнопкой мыши на файл и выберите пункт Get Info.
Находясь в закладке General, нажмите кнопку Make File Localizable.
Переключитесь обратно на закладку General, убедитесь, что локализация для языка проекта по умолчанию сформирована и добавьте еще один язык, нажав кнопку Add Localization, используя в качестве названия - ru
Если теперь вы заглянете через Finder в папку нашего проекта, то увидите две новых директории: English.lproj и ru.lproj, содержащие по копии файлов MainWindow.xib и Localizable.strings. Аналогичная группировка ресурсов по папкам видна и в XCode.
Процесс локализации строк прост до безумия. Откройте файл Localizable.strings из папки ru.lproj и впишите новое значение для подписи к кнопке возврата.
"Done" = "Готово";
Просто, верно? С такой же легкостью мы сейчас создадим перевод для файла интерфейса. Процесс локализации nib-файлов проходит в Interface Builder. Локализатор переводит подписи к элементам интерфейса, заменяет звуковые и файлы изображений, также изменяет размеры тех или иных элементов на форме, если переведенный текст не помещается полностью в пределах их размеров.
Откройте MainWindow.xib в Interface Builder и впишите новое значение для Back Button.
При локализации nib-файлов необходимо придерживаться условия — связи между объектами не должны быть нарушены в ходе процесса локализации.
Вот и все. Запустите txtEdit. По умолчанию в симуляторе в качестве основного установлен английский язык и наше приложение использует англоязычные ресурсы для отображения данных. Стоит нам переключиться в Настройках на русский (Settings->General->International->Language), как надписи на кнопках сменятся на кирилицу.
Если изменение языка в Настройках не приводит к изменениям в интерфейсе, удалите папку build из директории вашего проекта и пересоберите приложение.
На этом процесс локализации нашего приложения завершен, но для более сложных программ вам придется совершить немало дополнительных телодвижений. Я совершенно не затронул в своем посте тему приведения отображаемых данных в приложениях к формату выбранного региона, как то форматирование даты, чисел, денежных сумм и прочего — разобраться в этом помогут дополнительные источники информации, приведенные в конце статьи.
Дополнительные источники информации:
Комментарии
Ждем еще статей!
А почему не используются принятые обозначения культур? Типа EN-US, EN-UK, RU-RU и т.д.?
В качестве имен папок переводов можно использовать названия вида en_us, en_ca, en_uk, и вообще любой идентификатор локали. Т.е. можно легко создать локализацию для en_us и en_ca, и оба перевода будут доступны по отдельности, соответственно в США и Канаде.
Спасибо за статью. Мне вот интересно, есть например проект с локализацией на 15 языков. И тут вдруг в nib файл (которых 15 копий в 15-ти директориях) надо добавить новую кнопочку, или надпись… Есть какая нибудь автоматизация этого процесса? А еще хуже, если надо поменять что-то, что не локализуется — размер поменять, или местами поменять элементы.
Интересный вопрос. Для каждого локализованного файла можно сделать Remove All Localization, затем внести изменения, а после — заново создать 15 переводов, но это ход через одно место. Похоже, что помочь в подобной ситуации может AppleGlot, но мне не приходилось им пользоваться, так что не ручаюсь (описание работы с программой на русском).
AppleGlot определенно поможет.
Вообще нормальный процесс таков: изначально делается одна локаль (обычно, English.lproj), все остальные (в данном случае, 14) — готовятся для уже готовой программы с помощью AppleGlot (или другого инструмента локализации, например, iLocalize — отличная штука, но, в отличие от AppleGlot, стоит денег). В этом случае, помимо всего прочего, еще и перевод всяких стандартных элементов, вроде Edit = Правка, Services = Службы и т.п., подставляется автоматически по словарю. (коррекция размеров/расположения элементов интерфейса всегда происходит в InterfaceBuilder). Все переводы (и перемещения/изменения кнопочек и т.п.) запоминаются в «рабочем словаре». Поэтому, когда добавили кнопочку или надпись, останется снова запустить AppleGlot, перевести только то, что добавилось, и, возможно, подправить размещение этого элемента.
Большое спасибо за отличное объяснение. Вы, если не ошибаюсь, как раз и есть владелец сайта macedu.org.ru? :)
Преклоняюсь перед учителями. Без шуток, большое спасибо за вашу работу. Скажите, на уроках информатики в вашей школе удается рассказывать о Маках? На “живых” примерах?
Не ошибаетесь. Пока что работаем на «живых примерах». Но стареньких (iMac G3 ~ 2000 г. и iBook G3 2002 г.). Получается, скорее, антиреклама :-(
Это лучше, чем ничего. Вам же не видео кодировать детей учить, а для знакомства с Mac OS и Маками G3 очень даже не плохи.
Самостоятельно что-нибудь писали под Мак? Есть чем интересным поделиться, кроме того, что у вас есть на сайте? Спрашиваю не без корыстных побуждений, в попытке склонить вас напечатать пару статей на pyobjc.ru:)
Мне ж не только Finder показывать ;) А когда дети видят скорость работы G3 по сравнению с их домашними компьютерами, впечатление переносится на всю платформу.
Можно считать, что не писал ничего. Единственная программулина: http://macedu.narod.ru/soft/files/son-10.sit написана лет пять назад, да и в ней использованы только самые-самые простейшие вещи. Так что по теме сайта pyobjc.ru я могу только читать, но не писать ;)
Все равно спасибо, а статьи у вас интересные есть. Так что думаю, будет не лишним посетителям моего сайта ознакомиться с материалами на вашем. На всякий случай привожу еще раз ссылку macedu.org.ru
Скажите, а как решить проблему падежей (терминатор/терминатор_а_/терминатор_ов_)
Самодельно написанным методом. Больше ничего в голову не приходит. Т.е., например, подставлять в строчку вида NSLocalizedString(“Всего: %@”) будем не объект, а результат вызова метода, в который, кроме передачи количества единиц, будет передаваться еще и 3 словоформы (терминатор, терминатора, терминаторов), а он уже в ответ формировать строку с корректным склонением.
А в GNU gettext поддержка падежей есть по-умолчанию, а кроме того, для PO/POT-файлов есть отличный редактор, начиная от POEdit и заканчивая KBabel. Поэтому правильная локализация делается через gettext. Скажем НЕТ “1 овцы”!
Так-то! (c)
Вы меня опередили. Только что сам хотел отписать.
Да в сад gettext даешь sattelite assemblies используя SWF под моно! выглядит хоть криво (в 2.6 версии обещают native SWF driver для Carbon), но локализация, IMO, проще.
Еще понт под .NET — есть прога в составе СДК позволяющая не только локализацию ресурсов делать, но и менять свойства элементов управления под определенную локаль, типа расширить окошко, чтоб текст влезал и т.д. причем изменения заносятся в виде дифа, что позволяет попутно дорабатывать форму прогерами — добавлять на нее чтото, удалять.
Так-то =)! ©
Спасибо. С помощью этих советов полностью локализовал программу на 23 языка, даже на те языки, которых в iPhone нет! Думаю это мировой рекорд. iTunes Store пустил к себе, ссылка http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=303513809&mt=8 Стараничка программы EUtreaty http://slavamax.com/
Одна ремарка. Я не локализовывал файлы .xib их у меня 3. Я локализовывал лишь Localizable.strings правда пришлось помучиться с матрицей переводов 23x22 языка. Типа с гаэльского на мальтийский.
Форма комментирования для «Локализация приложений в Mac OS»