iOS Localization: XLIFF


В інтернеті легко знайти статті по локалізації 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.
До 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

Після додавання нової мови. Будуть згенеровані файли .струни для .storyboard або *.xib.

Почнемо з того, що відкриємо
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, щоб всі рядки, які відносяться до сценарію авторизації, лежали в окремому файлі Аутентифікації.strings, і коментар, щоб перекладачеві було зрозуміліше, до якого контексту відноситься текст для перекладу.
У нас ще багато рядків для перекладу в Main.storyboard. Але ми не будемо з ними нічого робити, окрім додавання коментарів. Щоб додати коментар до елемента Interface Builder'а, виберемо кнопку "Sign In" і в Identity Inspector знайдемо блок Document з розділом Notes і напишемо "Кнопка авторизації".

Тепер можна експортувати з нашого проекту файл для локалізації.
  • Проект
  • В рядку меню, Editor
  • У випадаючому меню Export For Applications...
Export For Applications
В результаті у нас з'явився файл ua.xliff. Відкриємо його в редакторі XLIFFy або скористаємося безкоштовним аналогом з Mac App Store. Якщо ви вибрали XLIFFy, то праворуч будуть перераховані імена таблиць перекладів. Це і стандартний файл перекладів Localizable.strings, і таблиці з іменами, як у файлів .storyboard або .xib, з яких вони були отримані. Також є таблиця для info.plist, в якій можна перекласти назву програми для різних країн. Є і таблиця Аутентифікації.strings, з якою ми зв'язали в коді переклад тесту помилки.

Після того, як у нас все перекладено, імпортуємо в Xcode.
  • Проект
  • В рядку меню, Editor
  • У випадаючому меню Import Localizations...
Import Localizations
Може з'явитися вікно з попередженнями, якщо деякі рядки залишилися без перекладу. Особливо часто це зустрічається, з-за непереведеного info.plist. Під час імпорту Xcode створює на основі таблиць перекладів файли *.strings, якщо їх немає, і вставляє в них ключ, значення і коментар. Краще їх не редагувати вручну, при неправильному форматування може перестати працювати export / import.

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

Міняємо Development Language
У дуже рідкісних випадках може знадобитися змінити Language Development, наприклад, на 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.
Мінуси:
  • Ключем виступає не абстрактна рядок, а текст Language Development. Якщо змінюється оригінальний текст, то його доводиться перекладати заново.
  • Для повторюваних рядків з .storyboard і .xib не вийде додати одного переказу для всіх. Це зроблено, тому що рядки пов'язані з різними елементами UI, і один варіант перекладу може виявитися занадто великим або невідповідним для контексту використання у другому випадку.
  • Немає обробки числівників і одиниць вимірювання. Для цього потрібно створювати спеціальний файл *.stringsdict. Handling Noun Plurals and Units of Measurement
Додаткова інформація по локалізації додатків:
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.