[Локализация продуктов, Разработка мобильных приложений, Разработка под iOS] Реализация наследования в файлах локализации iOS
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Приветствую, дорогие хабражители!
Сегодня я хочу поделиться интересным опытом в решении проблемы локализации. В iOS локализация устроена достаточно удобно с точки зрения одного таргета, либо нескольких таргетов, в которых ключи в localizable.strings не сильно повторяются. Но всё становится сложнее, когда у вас появляется с десяток таргетов, в которых больше половины ключей повторяются, но при этом частично имеют разные значения, а так же есть набор уникальных для конкретного таргета ключей.
Для тех, кто с этим пока не сталкивался, объясню проблему подробнее на примере.
Допустим, у нас есть большой проект, в котором 90% общего кода и 3 таргета: MyApp1, MyApp2, MyApp3, которые имеют некоторое количество специфичных экранов, а так же каждый имеет своё название и тексты. По сути таргет представляет из себя самостоятельное приложение. Каждый из них должен быть переведен на 10 языков. При этом мы НЕ хотим добавлять ключи локализации типа app1_localizable_key1, app2_localizable_key1 и т.д. Хотим, чтобы в коде всё было красиво и локализация происходила одной строчкой
NSLocalizedString(@"localizable_key1", nil)
Без всяких if и ifdef, чтобы при добавлении нового таргета нам не пришлось искать по всему коду огромного проекта места с NSLocalizedString и прописывать там новые ключи. Так же хотим, чтобы часть ключей была привязана к специфичным экранам таргета, т.е. были ключи app2_screen1_key, app3_screen2_key.
Штатными средствами Xcode сейчас можно сделать следующее:
- Скопировать общую часть localizable.strings в каждый таргет, при этом мы получим 3 копии этих файлов.
- Добавить в соответствующие localizable.strings ключи специфичные для конкретного таргета.
Каким проблемы мы получаем:
- Добавить новый общий ключ в проект достаточно накладно. Число мест равняется числу таргетов помноженному на число языков. В нашем примере это 30 мест.
- Есть вероятность ошибки, когда добавили строку в 1-2 текущих таргета, с которыми идёт активная работа, а через год решили воскресить еще один или несколько таргетов. Придется вручную синхронизировать между собой локализации, либо писать для этого скрипт. А если была проявлена некоторая неряшливость при добавлении или мерже веток, и общие ключи смешаны со специфичными, то тут будет самый настоящий квест.
- Объём файлов локализации. Они все постоянно растут, это затрудняет работу с ними и увеличивает шансы конфликта при мерже веток.
Что хотелось бы:
- Чтобы все общие ключи хранились в отдельном файле.
- Для каждого таргета был файл, в котором хранились только специфичные для него ключи, а так же общие ключи со значениями для данного таргета.
Для нашего примера имея общий файл localizable.strings со строками
"shared_localizable_key1" = "MyApp title"
"shared_localizable_key2" = "MyApp description"
"shared_localizable_key3" = "Shared text1"
"shared_localizable_key4" = "Shared text2"
Хотелось бы иметь файл localizable_app2.strings, в котором были бы ключи
"shared_localizable_key1" = "MyApp2 another title"
"shared_localizable_key2" = "MyApp2 another description"
"app2_screen1_key" = "Profile screen title"
Т.е. организовать в файлах локализации принцип наследования.
К сожалению Xcode не заточен под это, по-этому пришлось изобретать свой «велосипед», который долго не хотел ехать из-за того, что Xcode то тут, то там вставлял палки в колеса.
Мы имеем проект с 18 таргетами и 12 языками. И это не шутка, проект действительно большой и такое количество таргетов там необходимо. Каждый раз, когда нам нужно добавить новый общий ключ для перевода, мы имеем дело с 216 файлами локализации. Это отнимает достаточно много времени. А добавление нового таргета приводит к тому, что нужно скопировать в него еще 12 localizable.strings. В общем в какой-то момент мы поняли, что так больше жить нельзя и нужно искать решение.
Не буду долго рассказывать про все методы, которые я успел опробовать в процессе, перейду сразу к рабочему решению.
Итак, для начала нам нужно было найти все общие ключи. Это можно сделать с помощью скрипта, не буду вдаваться в подробности, это достаточно тривиальная задача.
Далее, когда мы получили общий (базовый) файл локализации, а точнее 12 физических файлов, а так же набор файлов для каждого таргета, идем в Xcode, добавляем туда все файлы. При этом не прикрепляем файлы к какому-либо таргету, т.е. в правой панели в разделе Target Membership не должно быть отметок.
Эти отметки мы поставим только для файла, который будет результатом работы скрипта по сборке файлов.
Далее начинается тот самый «велосипед»:
- Создаём в корне папку Localization, там будет лежать скрипт build_localization.py.
- Создаём рядом со скриптом папку Localizable. В неё скрипт будет генерировать файлы localizable.strings.
- Копируем в папку Localizable базовую локализацию.
Она нам нужна просто для того, чтобы корректно добавить ссылку на файлы в проект, и чтобы Xcode правильно их распознал. Иначе он не будет их использовать для поиска ключей. Например, если создать папку Localizable с правильно разложенными файлами localizable.strings внутри, и добавить в проект как ссылку на папку (create folder references), то не смотря ни на что Xcode не поймет, что мы дали ему ключи локализации. По-этому берем папку Localizable, перетаскиваем как группу (create group) и снимаем галочку copy items if needed, чтобы получилось как на картинке ниже.
Удаляем папку Localizable и вносим её в исключения для гита. Потому что результат работы скрипта нам в гите не нужен, он будет меняться для каждого таргета и засорять коммиты.
Теперь нам нужно добавить скрипт в фазу сборки. Для этого в Build Phases нажимаем New Run Script Phase и прописываем наш скрипт с параметрами.
python3 ${SRCROOT}/Localization/build_localization.py -b “${SRCROOT}/BaseLocalization" -s "${SRCROOT}/Target1Localization" -d "${SRCROOT}/Localization/Localizable"
b — это папка с базовой локализацией, s — локализация текущего таргета, d — папка результата.
Перемещаем новую фазу вверх, она должна быть не ниже фазы Copy Bundle Resources. Т.е. сначала скрипт генерирует файлы, а уже потом они забираются в бандл.
Теперь важно сообщить Xcode, что в процессе выполнения скрипта меняются файлы, иначе при сборке он будет выкидывать ошибку, что не смог найти файлы. Причем ошибка будет только на чистой сборке, и не сразу будет понятно в чем проблема. В фазе сборки добавляем в output files все файлы локализации
Это нужно проделать для каждого таргета. Проще всего это сделать открыв проект с помощью текстового редактора, потому что Xcode не сумеет скопировать/вставить фазу между таргетами. Соответственно параметр скрипта -s для каждого таргета будет свой.
Теперь при каждой сборке скрипт будет брать базовый файл локализации, накатывать на него изменения из файла таргета (добавлять, перезаписывать ключи) и генерировать локализацию в папку Localizable, которую iOS будет использовать для поиска ключей.
В целом получили то, что и планировалось при реализации механизма наследования:
- Общие ключи лежат в одном файле и не мешаются в других. Время на процесс внесения новых ключей сокращено в 18! раз.
- Ключи, относящиеся к конкретному таргету, лежат в соответствующем файле.
- Размер файлов значительно снизился. Избавились от захламления повторяющимися строками.
- Процесс добавления нового языка в проект так же значительно упрощён.
- При создании нового таргета не нужно копировать локализацию с кучей ненужных строк. Создаём новый файл localizable.strings и добавляем туда только нужное для этого таргета.
- Если решили реанимировать старый таргет, то со строками вообще ни чего делать не надо, всё подтянется из базового файла.
- Скрипт не захламляет гит, результат работы остаётся локально и его можно безболезненно удалить.
Готовый скрипт можно взять тут: github.com/iBlacksus/iOSLocalizationInheritance
Не претендую на идеальность скрипта, пул-реквесты приветствуются.
===========
Источник:
habr.com
===========
Похожие новости:
- [C#, C++, Java, Python] Публикация кода CaptureManager SDK под MIT лицензией
- [Usability, Веб-дизайн, Интерфейсы, Разработка веб-сайтов, Разработка мобильных приложений] 21 метод UX-исследований: какой выбрать
- [Ненормальное программирование] Храним числа экономно
- [C, Swift] Swift и Си: туда и обратно
- [Open source, Программирование, Python, Социальные сети и сообщества] Spothiefy: как переехать из Яндекс.Музыки быстро, бесплатно
- [Анализ и проектирование систем, ООП, Программирование, Проектирование и рефакторинг] ООП: Кто взял Измаил? Вопрос принадлежности методов объекту
- [Open source, Rust, Компиляторы, Программирование, Системное программирование] Rust 1.45.0: стабилизация функциональных процедурных макросов, исправление дефектов преобразования (перевод)
- [JavaScript, PHP, Ненормальное программирование, Программирование, Разработка веб-сайтов] Inertia.js – современный монолит
- [Open source, Python, Информационная безопасность, Сетевые технологии] Реализация ARP-спуфинга на Python
- [Машинное обучение, Облачные сервисы, Промышленное программирование] Промышленный Machine Learning: 10 принципов разработки
Теги для поиска: #_lokalizatsija_produktov (Локализация продуктов), #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_razrabotka_pod_ios (Разработка под iOS), #_objectivec, #_ios, #_localization, #_swift, #_python, #_programmirovanie (программирование), #_xcode, #_lokalizatsija_produktov (
Локализация продуктов
), #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_razrabotka_pod_ios (
Разработка под iOS
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:56
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Приветствую, дорогие хабражители! Сегодня я хочу поделиться интересным опытом в решении проблемы локализации. В iOS локализация устроена достаточно удобно с точки зрения одного таргета, либо нескольких таргетов, в которых ключи в localizable.strings не сильно повторяются. Но всё становится сложнее, когда у вас появляется с десяток таргетов, в которых больше половины ключей повторяются, но при этом частично имеют разные значения, а так же есть набор уникальных для конкретного таргета ключей. Для тех, кто с этим пока не сталкивался, объясню проблему подробнее на примере. Допустим, у нас есть большой проект, в котором 90% общего кода и 3 таргета: MyApp1, MyApp2, MyApp3, которые имеют некоторое количество специфичных экранов, а так же каждый имеет своё название и тексты. По сути таргет представляет из себя самостоятельное приложение. Каждый из них должен быть переведен на 10 языков. При этом мы НЕ хотим добавлять ключи локализации типа app1_localizable_key1, app2_localizable_key1 и т.д. Хотим, чтобы в коде всё было красиво и локализация происходила одной строчкой NSLocalizedString(@"localizable_key1", nil)
Без всяких if и ifdef, чтобы при добавлении нового таргета нам не пришлось искать по всему коду огромного проекта места с NSLocalizedString и прописывать там новые ключи. Так же хотим, чтобы часть ключей была привязана к специфичным экранам таргета, т.е. были ключи app2_screen1_key, app3_screen2_key. Штатными средствами Xcode сейчас можно сделать следующее:
Каким проблемы мы получаем:
Что хотелось бы:
Для нашего примера имея общий файл localizable.strings со строками "shared_localizable_key1" = "MyApp title"
"shared_localizable_key2" = "MyApp description" "shared_localizable_key3" = "Shared text1" "shared_localizable_key4" = "Shared text2" Хотелось бы иметь файл localizable_app2.strings, в котором были бы ключи "shared_localizable_key1" = "MyApp2 another title"
"shared_localizable_key2" = "MyApp2 another description" "app2_screen1_key" = "Profile screen title" Т.е. организовать в файлах локализации принцип наследования. К сожалению Xcode не заточен под это, по-этому пришлось изобретать свой «велосипед», который долго не хотел ехать из-за того, что Xcode то тут, то там вставлял палки в колеса. Мы имеем проект с 18 таргетами и 12 языками. И это не шутка, проект действительно большой и такое количество таргетов там необходимо. Каждый раз, когда нам нужно добавить новый общий ключ для перевода, мы имеем дело с 216 файлами локализации. Это отнимает достаточно много времени. А добавление нового таргета приводит к тому, что нужно скопировать в него еще 12 localizable.strings. В общем в какой-то момент мы поняли, что так больше жить нельзя и нужно искать решение. Не буду долго рассказывать про все методы, которые я успел опробовать в процессе, перейду сразу к рабочему решению. Итак, для начала нам нужно было найти все общие ключи. Это можно сделать с помощью скрипта, не буду вдаваться в подробности, это достаточно тривиальная задача. Далее, когда мы получили общий (базовый) файл локализации, а точнее 12 физических файлов, а так же набор файлов для каждого таргета, идем в Xcode, добавляем туда все файлы. При этом не прикрепляем файлы к какому-либо таргету, т.е. в правой панели в разделе Target Membership не должно быть отметок. Эти отметки мы поставим только для файла, который будет результатом работы скрипта по сборке файлов. Далее начинается тот самый «велосипед»:
Она нам нужна просто для того, чтобы корректно добавить ссылку на файлы в проект, и чтобы Xcode правильно их распознал. Иначе он не будет их использовать для поиска ключей. Например, если создать папку Localizable с правильно разложенными файлами localizable.strings внутри, и добавить в проект как ссылку на папку (create folder references), то не смотря ни на что Xcode не поймет, что мы дали ему ключи локализации. По-этому берем папку Localizable, перетаскиваем как группу (create group) и снимаем галочку copy items if needed, чтобы получилось как на картинке ниже. Удаляем папку Localizable и вносим её в исключения для гита. Потому что результат работы скрипта нам в гите не нужен, он будет меняться для каждого таргета и засорять коммиты. Теперь нам нужно добавить скрипт в фазу сборки. Для этого в Build Phases нажимаем New Run Script Phase и прописываем наш скрипт с параметрами. python3 ${SRCROOT}/Localization/build_localization.py -b “${SRCROOT}/BaseLocalization" -s "${SRCROOT}/Target1Localization" -d "${SRCROOT}/Localization/Localizable"
b — это папка с базовой локализацией, s — локализация текущего таргета, d — папка результата. Перемещаем новую фазу вверх, она должна быть не ниже фазы Copy Bundle Resources. Т.е. сначала скрипт генерирует файлы, а уже потом они забираются в бандл. Теперь важно сообщить Xcode, что в процессе выполнения скрипта меняются файлы, иначе при сборке он будет выкидывать ошибку, что не смог найти файлы. Причем ошибка будет только на чистой сборке, и не сразу будет понятно в чем проблема. В фазе сборки добавляем в output files все файлы локализации Это нужно проделать для каждого таргета. Проще всего это сделать открыв проект с помощью текстового редактора, потому что Xcode не сумеет скопировать/вставить фазу между таргетами. Соответственно параметр скрипта -s для каждого таргета будет свой. Теперь при каждой сборке скрипт будет брать базовый файл локализации, накатывать на него изменения из файла таргета (добавлять, перезаписывать ключи) и генерировать локализацию в папку Localizable, которую iOS будет использовать для поиска ключей. В целом получили то, что и планировалось при реализации механизма наследования:
Готовый скрипт можно взять тут: github.com/iBlacksus/iOSLocalizationInheritance Не претендую на идеальность скрипта, пул-реквесты приветствуются. =========== Источник: habr.com =========== Похожие новости:
Локализация продуктов ), #_razrabotka_mobilnyh_prilozhenij ( Разработка мобильных приложений ), #_razrabotka_pod_ios ( Разработка под iOS ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:56
Часовой пояс: UTC + 5