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

Введение

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

Рассмотрим локализацию текстовых элементов на примере iOS. Для этого используем список Localizable.strings в котором описаны все фразы в формате «ключ»=«локализованное значение». У каждого языка локализации — разное значение ключей.

Важно:
  • следить за написанием строковых ключей в коде, иначе вместо локализованной фразы получим «техническую» фразу (название константы);
  • убедиться, что у каждого ключа есть локализованные значения;
  • следить, чтобы локализация на всех платформах приложения была идентичной. Если выходит новая версия приложения, нужно проверить уже имеющиеся фразы.


С чего начать

image
Локализация была реализована при разработке МБ 2.0 — второй версии мобильного банка Тинькофф. Первоначально, выносили локализованные строки в Localizable.strings, заполняли недостающие строки перед тестированием, изменяли и добавляли новые строки во время тестирования. Далее делали новую сборку и все проверяли. И так для каждой платформы.

Естественно, возникали ошибки. Поэтому включили локализацию в ТЗ и начали брать все значения из документации, что позволило синхронизировать локализацию между платформами и избавиться от разных локализованных названий.

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

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

Как это сделать
  1. Добавить Localizable.strings файл;
  2. Добавить 2 файла для строковых констант:
    LocalizableKeys.h
    LocalizableKeys.m;
  3. Для ТЗ выбрать стиль для локализованных фраз.


Пример описания функционала в ТЗ:
Если нажата кнопка "Искать" (main_continue) на экране 1.1 то …»

Текст ТЗ пишем в wiki и храним в html, в исходном коде это выглядит так:
Если нажата кнопка "Искать" (<span style="color:red">main_continue</span>) на экране 1.1 то


Реализация

Для поиска таких фраз используем скрипт, который находит эти фразы и создает список «ключ»=«значение» вида: «main_continue» = «Далее». Это и есть главный список локализованных фраз, которые мы будем использовать в приложении.

Далее, по этому списку создаем ещё 2 списка:
  1. Для заголовочного файла: extern NSString *const LocKey_main_continue;
  2. Реализация: NSString *const LocKey_main_continue = @«main_continue»;


И сохраняем их в 3 файла:
  1. Localizable.strings – файл, в котором лежит локализация ключ-значение для каждого языка локализации
    "main_continue" = "Далее";
    "common_error" = "Ошибка";
    
  2. LocalizableKeys.h
    import <Foundation/Foundation.h>
    extern NSString *const LocKey_main_continue;
    extern NSString *const LocKey_common_error;
    
  3. 3.LocalizableKeys.m
    #import "LocalizableKeys.h"
    NSString *const LocKey_main_continue = @"main_continue";
    NSString *const LocKey_common_error = @"common_error";
    


Заменяем эти файлы в нашем проекте и собираем его. Теперь использовать новые ключи локализации можно так:
NSLocalizedString(LocKey_common_error, @"");

Если при очередном обновлении локализации проект не собирается, значит были удалены или переименованы нужные константы. Поэтому мы или меняем их в коде, или возвращаемся в ТЗ.

Таким образом, при каждом изменении ТЗ генерируются новые файлы Localizable.strings LocalizableKeys.h LocalizableKeys.m и собирается проект. В итоге, получаем полное соответствие технических требований и их реализации.

Преимущества нашего подхода:
  • целостность всех ключей проверяет компилятор. Если из локализации убрали такую константу, то компилятор скажет нам об этом при сборке;
  • название и значение ключей регламентирует ТЗ;
  • при написании кода можно пользоваться контекстной подсказкой, что заметно увеличивает скорость написания кода;
  • к чтению ТЗ подключается ещё один человек, который следит за локализацией.


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

Пример использования подхода локализации для автотестов

При написании автотестов для идентификации объектов на экране, нужны уникальные ключи для всех элементов интерфейса — поле ввода текста, кнопка, и тд.

Так же как в локализации назначим объектам accessibilityLabel константы из ТЗ и добавим стиль для оформления фраз для автотестов.

Пример описания функционала в ТЗ:
«Если нажата кнопка «Продолжить» (main_continue btn_continue) на экране 1.1 то …»

Текст ТЗ пишем в wiki и храним в html, в исходном коде это будет выглядеть так:
«Если нажата кнопка "Продолжить" (<span style="color:red;">main_continue</span> <span style="color:blue;">btn_continue</span>) на экране 1.1 то» 


В итоге получаем:
  • AccessibilityKeys.h
    #import <Foundation/Foundation.h>
    extern NSString *const AccKey_btn_continue
    
  • AccessibilityKeys.m
    #import "AccessibilityKeys.h"
    NSString *const AccKey_btn_continue = @"bnt_continue"
    


В коде это выглядит так:
UIButton *buttonRegistration;	
[buttonRegistration setAccessibilityLabel: AccKey_btn_continue];	
[buttonRegistration setTitle: NSLocalizedString(LocKey_main_continue, @"") forState:UIControlStateNormal]


Теперь для написания автотестов нужно приложение и ТЗ. Для мультиплатформенных приложений можно использовать одни и те же скрипты автотестов для всех платформ.

Комментарии (2)


  1. Pest64
    25.11.2015 20:49

    При переходе на Swift что предпримете?
    Или оставите этот функционал на совести Objective C?


    1. Korobov
      26.11.2015 15:42

      Ответ Вячеслава:
      Для swift всё ещё проще получается, нужно настроить скрипт чтобы он генерировал вместо LocalizableKeys.h и LocalizableKeys.m один файл LocalizableKeys.swift со структурой:

      //
      import Foundation
      
      
      struct Localizable
      {
           static let buttonDone = "button.done"
           static let buttonNext = "button.next"
           static let titleMain = "title.main"
      }
      //
      


      Далее в коде этим можно пользоваться так:
      //
      self.title = NSLocalizedString(Localizable.buttonDone, comment: "")
      //