Не так давно я опубликовал подробную инструкцию по использованию LocoLaser — утилиты для локализации Android и iOS приложений в Google Sheets. Мне бы хотелось продолжить тему локализации и обратить больше внимания на iOS приложения. В отличии от Android, в iOS разработке есть ряд мелких но неприятных моментов, которые, в сумме, могут привести к совсем не мелким проблемам.
Сегодня я хочу уделить особое внимание Interface Builder-у. Все мы знаем, он не идеален. Но это единственное, что у нас есть и с этим приходится мириться. В этой статье я расскажу о главной проблеме, с которой вы можете столкнуться при локализации приложений в Interface Builder, а также расскажу как с ней можно справиться.
Суть проблемы
Когда вы переводите Storyboard или XIB файл, помимо основного файла с разметкой, создаются дополнительные файлы с ресурсными строками. Эти ресурсные файлы принято выгружать в специальные таблицы и отдавать переводчикам. Беда заключается в том, что ключи для строк, в этом файле, строятся на основе Object ID, которые генерируются автоматически и нет ни какой возможности на них повлиять. Если вас угораздило скопировать или вырезать а затем вставить какой либо View, Interface Builder сгенерирует новые идентификаторы и перевод будет потерян.
Каждый решает эту проблему как может. Помню, 2 года назад, на мобильной конференции я спрашивал одного ведущего iOS разработчика одной из ведущих фирм о том как они решают проблему локализации интерфейса. В то время я только начинал изучать iOS, но у меня уже был достаточно богатый опыт в области Android и мне было с чем сравнивать. Честно говоря, я был ошарашен ответом. Во ViewController через IBOutlet они получали ссылки на Label и прочие View и переводили их программно. В коде это выглядит приблизительно так:
class MainViewController: UIViewController { @IBOutlet var labelToTranslate: UILabel! override func viewDidLoad() { super.viewDidLoad() self.labelToTranslate.text = NSLocalizedString("scr_main_txt_example", comment: "Some Example text") ... } ... }
В этом случае все строки находятся в одном файле Localizable.strings. Подобный метод в настоящий момент является наиболее распространенным и используется почти повсеместно. Признайтесь, получается не слишком элегантно. Мало того что вы засоряете ViewController лишним кодом, которому тут не место, так еще и не решаете проблему с копированием или перемещением View. Пора бы найти что-то получше.
Решение
И тут у меня есть кое-что, что я могу вам предложить. Дело в том, что в Interface Builder, в свойствах View, можно прописать так называемые «User Defined Runtime Attributes». Их то мы и будем использовать. Но для начала необходимо создать Extension для UILabel.
extension UILabel { public var lzText : String? { set { if newValue != nil { self.text = NSLocalizedString(newValue, comment: “”) } else { self.text = nil } } get { return self.text } } }
Теперь у всех UILabel появилось свойство lzText при изменении которого в свойство text записывается локализованная строка. Используем это свойство в Interface Builder.
- Выбираем UILabel и переходим на вкладку «Identity Inspector»;
- Жмем кнопку добавления атрибута в «User Defined Runtime Attributes»;
- Указываем ключ атрибута «lzText», тип: «String», значение: «scr_main_txt_example»
И это все. Больше не нужно засорять код ничем лишним. Вы можете не бояться что перевод или ссылка на View потеряется при копировании или перемещении в другой контейнер. Атрибуты копируются вместе с View.
Для еще большего удобства я подготовил файл, в котором собрано достаточно большое количество расширений для часто используемых View, где у каждого текстового свойства есть двойник с приставкой «lz»(сокращение слова «localized»). Вы можете найти этот файл в примере по использованию LocoLaser: LocalizationExtensions.swift. Весь проект опубликован под лицензией Apache 2.0, можете смело копировать этот файл к себе и начинать использовать.
Помимо расширений для View, в LocalizationExtensions.swift добавлено расширение к классу String. Оно добавляет вычисляемое свойство localized, которое возвращает локализованную строку. Если перевод найти не получается, отправляется оповещение через NotificationCenter. Вы можете подписаться на эти оповещения и обрабатывать их как вам заблагорассудится. В Debug билде можно писать в лог или показывать уведомления, в Release билде отправлять репорт в систему аналитики.
В итоге, после применения вышеописанного метода, вся работа со строками остается в Interface Builder. Плюс ко всему вы получите дополнительный механизм по отлову «битых» строк.
На этом закончу. Спасибо за внимание. Пользуйтесь на здоровье!
ссылка на оригинал статьи https://habrahabr.ru/post/325810/
Добавить комментарий