iOS Localization: XLIFF

в 10:20, , рубрики: iOS, redmadrobot, xliff, Блог компании REDMADROBOT, мобильная разработка, разработка мобильных приложений, разработка под iOS

iOS Localization: XLIFF - 1

В интернете легко найти статьи по локализации iOS, где описываются все основные этапы. Проблема в том, что чаще нам на глаза попадается вариант ручного заполнения файла *.strings. Это довольно муторный подход и даже небольшая автоматизация в этом нам бы пригодилась. Ещё в iOS 8 Apple добавила возможность частичной автоматизации перевода приложения посредством экспорта и импорта локализованных строк через XLIFF-документ.

XLIFF (XML Localization Interchange File Format) — это обыкновенный XML, соотвествующий стандарту для обмена локализованными данными.

Я посчитал, что этот способ незаслуженно обходят стороной или упоминают его вскользь. А ведь он позволяет достать все строки для перевода из исходников (m, swift) и ресурсов (.storyboard, .xib) и объединить их в один файл *.xliff. А после может вставить перевод из него в проект. Остается лишь не забывать использовать NSLocalizedString.

NSLocalizedString

Разметка XLIFF-документа легко ложится на NSLocalizedString, который по умолчанию используется для работы с локализованными строками. Если мы пишем на Swift, то это функция:

public func NSLocalizedString(key: String, tableName: String? = default, bundle: NSBundle = default, value: String = default, comment: String) -> String

Если же мы еще пишем на Objective-C, то нужно использовать си макросы:

#define NSLocalizedString(key, comment)
#define NSLocalizedStringFromTable(key, tbl, comment)
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment)
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment)

Они имеют одинаковые аргументы и идентичную функциональность.

  • key Ключ, по которому лежит переведенная строка.
  • tableName Таблица, в которой находится ключ. Соответствует имени файла с расширением tableName.strings. Не обязательный параметр. По умолчанию используется Localizable.strings.
  • bundle Бандл, в котором находится таблица с ключами и переводами. Не обязательный параметр. По умолчанию используется NSBundle.mainBundle().
  • comment Комментарий для переводчика. Обязательно пишите его! Он поможет вам в будущем сориентироваться в коде.
  • value Значение, возвращаемое, если локализованная строка для ключа не была найдена в таблице.

Аргументы NSLocalizedString соответствуют содержимому XLIFF-файла:

  • Таблицы с ключами, на основе которых Xcode создаст файлы типа *.strings. Имена для них берутся на этапе создания xliff-файла из параметра tableName.
  • Оригинальный текст из параметра key.
  • Текст для перевода, который нужно заполнить.
  • Комментарий для переводчика из параметра comment.

Дo iOS 8

В старые времена нам приходилось на несколько часов становиться секретаршами, чтобы пробежаться и сделать несколько монотонных вещей:

  • Вставить NSLocalizedString, если не сделали это сразу.
  • Придумать тег NSLocalizedString("TITLE", comment: "Заголовок первого экрана") и написать комментарий, если успеваем.
  • Скопировать этот тег в файл Localizable.strings.
  • Вставить перевод для тега. "TITLE" = "My App".
  • Скопировать новую строчку в отдельный документ (например, Google Docs), чтобы переводчику было удобнее перевести.

К этому алгоритму добавлялись условия, когда тег уже существует и нужно использовать его или придумать новый, когда переводы разбиты на разные файлы или бандлы. В этой последовательности рутинного копипаста было легко допустить ошибку или "уснуть". К тому же у нас есть .storyboard или .xib файлы, и в них приходится делать IBOutlet, чтобы перевести весь текст в них из кода.

После iOS 8

С использованием XLIFF наш воркфлоу немного изменился.

  • В коде, когда добавляем текст для UI, сразу пишем его в NSLocalizedString ("My App", comment: "Заголовок первого экрана"). Если язык разработки приложения Английский и вы его не меняли.
  • Когда настало время, чтобы перевести приложение, экспортируем XLIFF-документ. В итоге у нас получаются файлы, соответсвующие поддерживаемым языкам. Например: ru.xliff, de.xliff.
  • После того как переводы заполнены, импортируем их.

В результате Xcode сам создаст все необходимые файлы типа *.strings на основе xliff-файла.

А как же .storyboard и .xib ?

Строки из них Xcode также экспортирует в таблицы с именами как у их исходных файлов.

XLIFFy

Но остается одна проблема. Чем открыть файлы xliff? Когда Apple представила такую возможность, редакторов для этих файлов почти не было, а те что были, имели неудобный интерфейс. Сейчас Mac App Store полон ими на любой вкус. Но в то время я не нашел для себя подходящую программу и решил написать сам. XLIFFy

Пример

У нас есть демо-приложение с окном авторизации, в которое мы должны будем добавить русскую локализацию. По умолчанию Xcode создает проект с английским языком разработки. Это подразумевает, что весь ваш текст в UI будет на нем.

Добавим русский язык в проект.

  • Проект
  • Настроки проекта
  • Вкладка Info
  • + внизу списка Localization

iOS Localization: XLIFF - 2

После добавления нового языка. Будут сгенерированы файлы .strings для .storyboard или *.xib.

iOS Localization: XLIFF - 3

Начнем с того, что откроем ViewController.swift и взглянем на метод signInAction(:_).

class ViewController: UIViewController {
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var signInButton: UIButton!

    @IBAction func signInAction(sender: AnyObject) {
        if usernameTextField.text == "user" && passwordTextField.text == "pass" {
            // success
        } else {
            // fail

            let alert = UIAlertController(
                title: "Error",
                message: "Username or Password is not correct",
                preferredStyle: .Alert
            )
            let okAction = UIAlertAction(
                title: "OK",
                style: .Cancel,
                handler: nil
            )
            alert.addAction(okAction)

            presentViewController(alert, animated: true, completion: nil)
        }
    }
}

У нас есть UIAlertController, который должен показать пользователю описание ошибки, если он ввел неправильный логин или пароль.

Переведем заголовок.

let alert = UIAlertController(
    title: NSLocalizedString("Error", comment: ""),
    message: "Username or Password is not correct",
    preferredStyle: .Alert
)

Часто в проекте повторяется одна строка, например “Error”, и было бы хорошо, чтобы и перевод для нее был один. В таком случае нам везде, где используется эта строка нужно вызывать метод с ней в качестве аргумента.

NSLocalizedString("Error", comment: "")

В результате перевод этой строки будет лежать в единственном экземпляре в файле Localizable.strings. Этот файл используется по умолчанию если не указывается имя другого.

Добавим сообщение об ошибке.

let message = NSLocalizedString(
    "Username or Password is not correct",
    tableName: "Auth",
    comment: "Сообщение о неверном логине или пароле"
)
let alert = UIAlertController(
    title: NSLocalizedString("Error", comment: ""),
    message: message,
    preferredStyle: .Alert
)

Сейчас мы уже добавили tableName, чтобы все строки, относящиеся к сценарию авторизации, лежали в отдельном файле Auth.strings, и комментарий, чтобы переводчику было понятнее, к какому контексту относится текст для перевода.

У нас еще много строк для перевода в Main.storyboard. Но мы не будем ничего с ними делать, кроме добавления комментариев. Чтобы добавить комментарий к элементу Interface Builder'а, выберем кнопку "Sign In" и в Identity Inspector найдем блок Document с разделом Notes и напишем "Кнопка авторизации".

iOS Localization: XLIFF - 4

Теперь можно экспортировать из нашего проекта файл для локализации.

  • Проект
  • В строке меню, Editor
  • В выпадающем меню Export For Localization...

Export For Localization

В результате у нас появился файл ru.xliff. Откроем его в редакторе XLIFFy или воспользуемся бесплатным аналогом из Mac App Store. Если вы выбрали XLIFFy, то справа будут перечислены имена таблиц переводов. Это и стандартный файл переводов Localizable.strings, и таблицы с именами, как у файлов .storyboard или .xib, из которых они были получены. Также есть таблица для info.plist, в которой можно перевести название приложения для разных стран. Есть и таблица Auth.strings, с которой мы связали в коде перевод теста ошибки.

iOS Localization: XLIFF - 6

После того, как у нас все переведено, импортируем в Xcode.

  • Проект
  • В строке меню, Editor
  • В выпадающем меню Import Localizations...

Import Localizations

Может появиться окно с предупреждениями, если некоторые строки остались без перевода. Особенно часто это встречается, из-за непереведенного info.plist. Во время импорта Xcode создает на основе таблиц переводов файлы *.strings, если их нет, и вставляет в них ключ, значение и комментарий. Лучше их не редактировать вручную, при неправильном форматировании может перестать работать export / import.

iOS Localization: XLIFF - 8

После иморта переводов самое время проверить, как отображается наше приложение на разных языках. Перезапускать его на симуляторе или на девайсе, конечно, нужно, но довольно долго. Куда быстрее это можно сделать в Interface Builder.
Откройте Main.storyboard, включите Assistant Editor и выберите в его выпадающем списке Preview. В этом режиме вы можете просмотреть, как будет выглядеть ваше приложение на разных девайсах и в разных локализациях.

iOS Localization: XLIFF - 9

Меняем Development Language

В очень редких случаях может понадобиться поменять Development Language, например, на Russian, потому что весь ваш дизайн сперва создается с русским текстом.
Вам нужно будет закрыть Xcode, открыть файл проекта в текстовом редакторе <project_name>.xcodeproj/project.pbxproj, найти пару строчек

developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
    en,
    Base,
);

и заменить их на

developmentRegion = Russian;
hasScannedForEncodings = 0;
knownRegions = (
    ru,
    Base,
);

Подробнее вы можете прочитать тут

Итого

Использование файлов xliff имеет как свои плюсы, так и минусы:

Плюсы:

  • Больше не нужно заниматься монотонным копипастом.
  • Удобный перевод .storyboard и .xib.
  • Весь менеджмент файлов *.strings берет на себя Xcode.
  • Вся работа по локализации сводится к использованию NSLocalizedString.

Минусы:

  • Ключом выступает не абстрактная строка, а текст на Development Language. Если меняется оригинальный текст, то его приходится заново переводить.
  • Для повторяющихся строк из .storyboard и .xib не получится добавить одного перевода для всех. Это сделано, потому что строки связаны с разными элементами UI, и один вариант перевода может оказаться слишком большим или неподходящим для контекста использования во втором случае.
  • Нет обработки числительных и единиц измерения. Для этого нужно создавать специальный файл *.stringsdict. Handling Noun Plurals and Units of Measurement

Дополнительная информация по локализации приложений:

Автор: REDMADROBOT

Источник


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


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