SA1041 — Интернационализация
Содержание страницы
До сих пор все приложения, которые вы сделали в этой книге, были на английском языке. Без сомнения, Соединенные Штаты являются крупнейшим рынком приложений, за ними следует Азия. Но если вы сложите все небольшие страны, где английский не является основным языком, то все равно получите довольно значительный рынок, который, возможно, вам не хватает.
К счастью, iOS позволяет очень легко добавить поддержку других языков в ваши приложения-процесс, известный как интернационализация. Это часто сокращается до “i18n”, потому что это намного короче для написания; 18 означает количество букв между i и n. Вы также часто услышите слово локализация, которое означает примерно то же самое.
В этой главе, чтобы намочить ноги в локализации, вы добавите поддержку голландского языка. Вы также обновите запрос веб-службы, чтобы возвращать результаты, оптимизированные для региональных настроек пользователя.
Вы охватите следующие пункты:
- Добавьте новый язык: Как добавить поддержку нового языка отображения (для отображаемого текста) в ваше приложение.
- Локализация экранного текста: Как локализовать текстовые значения, используемые в коде.
- InfoPlist.strings: Локализуйте параметры файла Info.plist, такие как имя приложения.
- Региональные настройки: Измените веб-запрос, чтобы отправить язык и регион устройства для получения локализованных результатов поиска.
Добавить новый язык
На данный момент структура вашей папки с исходным кодом, вероятно, выглядит примерно так:

Файлы в папке с исходным кодом
Существует подпапка Base.lproj, которая содержит, по крайней мере, раскадровку Main.storyboard. Базовая папка.lproj предназначена для файлов, которые можно локализовать. Пока это может быть только раскадровка, но скоро вы добавите в эту папку еще несколько файлов.
Когда вы добавляете поддержку другого языка, создается новая папка XX.lproj с XX-двухбуквенным кодом для этого нового языка — en для английского, nl для голландского и т. Д.
Локализация файла nib
Давайте начнем с локализации простого файла NothingFoundCell.xib. Часто файлы nib содержат текст, который необходимо перевести. Вы можете просто сделать новую копию существующего файла nib для определенного языка и поместить его в правую папку .lproj. Когда iPhone использует этот язык, он автоматически загрузит переведенный наконечник.
Выберите NothingFoundCell.xib в навигаторе проектов. Переключитесь на панель инспектора файлов справа.
Поскольку файл NothingFoundCell.xib не находится ни в одной папке XX.lproj, он еще не имеет никаких локализаций.

NothingFoundCell не имеет локализаций
BOS Нажмите кнопку Локализовать… в разделе Локализация.
Xcode запрашивает подтверждение, поскольку это связано с перемещением файла в новую папку:

Xcode спрашивает, можно ли переместить файл
BOS Выберите английский (не базовый) и нажмите Локализовать, чтобы продолжить.
Посмотрите в Finder, и вы увидите, что есть новая en.lproj — for English — folder и NothingFoundCell.xib был перемещен в эту папку:

Xcode переместил NothingFoundCell.xib в папку en.lproj
Инспектор файлов для NothingFoundCell.xib теперь перечисляет английский язык как одну из локализаций.

Раздел локализации теперь содержит запись на английском языке
Добавить поддержку нового языка
Чтобы добавить поддержку нового языка в приложение, вам необходимо переключиться на экран настроек проекта.
BOS Нажмите на StoreSearch в верхней части навигатора проекта, чтобы открыть страницу настроек. На центральной боковой панели выберите StoreSearch в разделе PROJECT (не в разделе TARGETS).
Если центральная боковая панель не видна, нажмите на маленький значок в верхней части боковой панели, чтобы открыть ее.

Настройки проекта
BOS На вкладке Информация в разделе Локализации нажмите кнопку + .:
Добавление нового языка
Во всплывающем меню выберите Dutch (nl).
Теперь Xcode спрашивает, какие ресурсы вы хотите локализовать. Снимите флажок все, кроме NothingFoundCell.xib, и нажмите кнопку Готово.

Выбор файлов для локализации
Если вы снова заглянете в Finder, то заметите, что добавлена новая подпапка nl.lproj, содержащая еще одну копию NothingFoundCell.xib.
Это означает, что теперь есть два файла nib для NothingFoundCell
. Вы также можете увидеть это в навигаторе проекта:

NothingFoundCell.xib имеет две локализации
Редактирование пера для конкретного языка
Давайте отредактируем голландскую версию этого пера.
BOS Нажмите на NothingFoundCell.xib (голландский), чтобы открыть его в Interface Builder.
BOS Измените текст этикетки на Niets gevonden.

Вот как ты говоришь по-голландски
Совершенно нормально изменять размер или перемещать элементы в переведенном наконечнике. Вы могли бы сделать весь наконечник совершенно другим, если бы захотели, но это, вероятно, плохая идея. Некоторые языки, такие как немецкий, имеют очень длинные слова, и в этих случаях вам, возможно, придется настроить размеры этикеток и шрифты, чтобы все поместилось.
Если вы запустите приложение сейчас, то ничего не изменится. Сначала вы должны переключить симулятор на голландский язык. Однако прежде чем вы это сделаете, вам действительно следует удалить приложение из симулятора, очистить проект и сделать новую сборку.
Причина этого в том, что перья ранее не были локализованы. Если бы вы сейчас переключили язык симулятора, приложение могло бы по-прежнему использовать старые, нелокализованные версии nibs, а могло бы и нет. Лучше быть в безопасности, чем рвать на себе волосы, гадая, что пошло не так, верно?
Примечание: По этой причине при их создании рекомендуется уже поместить все ваши файлы nib и раскадровки в папку en.lproj — или в Base.lproj, о которой мы вскоре поговорим. Даже если вы не собираетесь интернационализировать свое приложение в ближайшее время, вы не хотите, чтобы ваши пользователи столкнулись с той же проблемой позже. Нехорошо просить пользователей удалить приложение — и потерять свои данные — чтобы иметь возможность переключать языки.
Язык коммутационного устройства
BOS Удалите приложение из симулятора. Очистите проект (Product ▸ Clean Build Folder или Shift-⌘-K) и заново создайте приложение.
BOS Откройте приложение Настройки в симуляторе и перейдите в раздел Общие ▸ Язык и регион ▸ Язык iPhone. Из списка выберите Nederlands (голландский).

Переключение языков в симуляторе
Симулятору потребуется некоторое время, чтобы переключиться между языками. Это завершает работу приложения, если оно все еще работает.
BOS Найдите какой-нибудь бессмысленный текст, и приложение теперь ответит на голландском языке.:

Я был бы удивлен, если бы это действительно нашло совпадение
Довольно круто, просто поместив некоторые файлы в папки en.lproj и nl.lproj, вы интернационализировали приложение! Некоторое время вы будете держать Симулятор на голландском языке, потому что другие наконечники тоже нуждаются в переводе.
Примечание: Если в этот момент приложение выйдет из строя, вам может помочь следующее. Выйти из Xcode. Сбросьте симулятор, а затем выйдите из него. В Finder перейдите в папку Library, Developer/Xcode и выбросьте всю папку DerivedData. Опорожни свою мусорную корзину. Затем снова откройте проект StoreSearch и попробуйте еще раз. Кроме того, не забудьте переключить симулятор обратно на Nederlands.
Интернационализация базы
Чтобы локализовать другие nibs, вы можете повторить процесс и добавить копии их xib-файлов в папку nl.lproj. Это не так уж плохо для этого приложения, но если у вас есть приложение с действительно сложными экранами, наличие нескольких копий одного и того же наконечника может стать кошмаром обслуживания.
Всякий раз, когда вам нужно что-то изменить на определенном экране, вам нужно обновить все эти наконечники для каждого языка. Существует риск того, что вы можете пропустить один или несколько файлов nib, и они будут несинхронизированы. Это просто напрашивается на ошибки — на языках, которыми вы, вероятно, не владеете!
Чтобы этого не произошло, вы можете использовать базовую интернационализацию. Если эта функция включена, вы копируете не весь наконечник целиком, а только текстовые строки. Для этого и предназначена папка Base.lproj.
Давайте переведем другие крупицы.
Выберите LoadingCell.xib в навигаторе проекта. В инспекторе файлов нажмите кнопку Локализовать.… На этот раз используйте базу в качестве языка.
Проверьте с помощью Finder, что LoadingCell.xib был перемещен в папку Base.lproj.
Раздел локализации в инспекторе файлов LoadingCell.xib теперь содержит три варианта: базовый (с галочкой), английский и голландский. Поставьте галочку перед Датчем:

Добавление голландской локализации
В Finder вы можете видеть, что nl.proj не получает копию наконечника, но добавляется новый файл: LoadingCell.strings.
BOS Щелкните треугольник раскрытия перед LoadingCell.xib, чтобы развернуть его в навигаторе проектов, и выберите файл LoadingCell.strings (голландский).
Вы должны увидеть что — то вроде следующего:

Голландская локализация-это строковый файл
Есть еще только один наконечник, тот, что от Базовой локализации. Голландский перевод состоит из файла “strings”, содержащего только текст меток, кнопок и других элементов управления.
Этот конкретный файл строк содержит:
/* Class = "UILabel"; text = "Loading..."; ObjectID = "x7v-YC-QRj"; */ "x7v-YC-QRj.text" = "Loading...";
Первая строка-это комментарий, как и в Swift. Во второй строке говорится, что свойство text объекта с идентификатором “x7v-YC-QRj” содержит загрузку текста…
Идентификатор-это внутренний идентификатор, который Xcode использует для отслеживания объектов в ваших наконечниках; ваш собственный наконечник, вероятно, имеет другой идентификатор, чем мой. Вы можете увидеть этот идентификатор в инспекторе идентификационных данных для метки.
BOS Измените текст с Loading… на Zoeken…
Совет: Вы можете использовать Помощник редактора в Interface Builder, чтобы получить предварительный просмотр локализованного наконечника. Переключитесь на LoadingCell.xib (Base) и откройте Помощник редактора. Панель вкладок в верхней части имеет значок двух связанных кругов справа. Нажмите на него, чтобы показать меню, и выберите в меню пункт Предварительный просмотр.
Примечание: Если вы не видите предварительный просмотр во вторичной панели, попробуйте сохранить файл nib. Если это не сработает, попробуйте выйти из Xcode и перезапустить его.
В правом нижнем углу написано по-английски. Нажмите эту кнопку, чтобы переключиться на голландский предварительный просмотр.

Помощник редактора показывает предварительный просмотр перевода
BOS Сделайте продукт ▸ Очистите папку сборки (на всякий случай) и снова запустите приложение.
BOS Повторите шаги, чтобы добавить голландскую локализацию для Main.storyboard. У него уже есть базовая локализация, так что вам просто нужно поставить галочку перед голландским в инспекторе файлов.
Для экрана контроллера представления поиска необходимо изменить две вещи: текст-заполнитель в строке поиска и метки на сегментированном элементе управления.
В Main.strings (голландский) измените текст заполнителя на Naam van artiest, nummer, album.
"68e-CH-NSs.placeholder" = "Naam van artiest, nummer, album";
Сегментными лейблами станут: Alles, Muziek, Softwareи E-boeken.
"Sjk-fv-Pca.segmentTitles[0]" = "Alles"; "Sjk-fv-Pca.segmentTitles[1]" = "Muziek"; "Sjk-fv-Pca.segmentTitles[2]" = "Software"; "Sjk-fv-Pca.segmentTitles[3]" = "E-boeken";
Конечно, ваши идентификаторы объектов будут разными, поэтому не полагайтесь на идентификаторы, чтобы найти правильные значения в файле.

Локализованный SearchViewController
BOS Для всплывающего окна Detail вам нужно только изменить Type: label, чтобы сказать Soort:
"DCQ-US-EVg.text" = "Soort:";
Вам не нужно их менять:
"ZYp-Zw-Fg6.text" = "Genre:"; "yz2-Gh-kzt.text" = "Kind Value"; "Ph9-wm-1LS.text" = "Artist Name"; "JVj-dj-Iz8.text" = "Name"; "7sM-UJ-kWH.text" = "Genre Value"; "xOH-GC-bHs.normalTitle" = "$9.99";
Эти метки могут оставаться неизменными, потому что вы все равно замените их значениями из SearchResult
объекта. Кроме того, “Жанр” одинаков в обоих языках.
Примечание: Если бы вы захотели, вы даже могли бы удалить текст, который не нуждается в локализации, из файла strings. Если локализованная версия для конкретного ресурса отсутствует для языка пользователя, iOS вернется к версии из базовой локализации.

Всплывающее окно на голландском языке
Благодаря функции Auto Layout размер надписей автоматически изменяется в соответствии с переведенным текстом. Общая проблема локализации заключается в том, что английские слова, как правило, короче слов на других языках, поэтому вы должны убедиться, что ваши ярлыки достаточно велики, чтобы вместить любой язык. С автоматической компоновкой это проще простого.
Контроллер ландшафтного вида не имеет текста для перевода.
BOS Нет необходимости давать SearchResultCell.xib голландскую локализацию — в самом наконечнике нет экранного текста-но дайте ему базовую локализацию. Это готовит приложение к будущему, если вам понадобится локализовать этот наконечник в какой-то момент.
Когда вы закончите, вне папок .lproj не должно быть никаких xib-файлов. Вот и все для перьев и раскадровки. Не так уж плохо, правда? Я бы сказал, что все эти изменения достойны фиксации.
Совет: Вы также можете протестировать локализации, изменив настройки активной схемы. Нажмите на StoreSearch в селекторе active scheme на панели инструментов Xcode — рядом с именем симулятора — и выберите Edit Scheme.

На вкладке Параметры вы можете изменить язык приложения и настройки региона приложения. Это немного быстрее, чем перезапуск симулятора.
Локализация экранного текста
Несмотря на то, что перья и раскадровка были переведены, не весь текст переведен. Например, в изображении one-before-the-previous текст из kind
свойства по-прежнему является “Песней”.
Хотя в этом случае вам, вероятно, это сойдет с рук — все в мире, вероятно, знают, что означает слово “Песня”, — не весь текст из type
свойства будет понят неанглоговорящими пользователями.
Локализация текста, используемого в коде
Чтобы локализовать текст, которого нет в наконечнике или раскадровке, вы должны использовать другой подход.
BOS В SearchResult.swiftубедитесь, что фреймворк Foundation импортирован.:
import Foundation
BOS Затем замените type
свойство на:
var type: String { let kind = self.kind ?? "audiobook" switch kind { case "album": return NSLocalizedString( "Album", comment: "Localized kind: Album") case "audiobook": return NSLocalizedString( "Audio Book", comment: "Localized kind: Audio Book") case "book": return NSLocalizedString( "Book", comment: "Localized kind: Book") case "ebook": return NSLocalizedString( "E-Book", comment: "Localized kind: E-Book") case "feature-movie": return NSLocalizedString( "Movie", comment: "Localized kind: Feature Movie") case "music-video": return NSLocalizedString( "Music Video", comment: "Localized kind: Music Video") case "podcast": return NSLocalizedString( "Podcast", comment: "Localized kind: Podcast") case "software": return NSLocalizedString( "App", comment: "Localized kind: Software") case "song": return NSLocalizedString( "Song", comment: "Localized kind: Song") case "tv-episode": return NSLocalizedString( "TV Episode", comment: "Localized kind: TV Episode") default: return kind } }
Совет: Вместо того чтобы вводить вышеописанное, вы можете использовать мощную функцию замены регулярных выражений Xcode, чтобы внести эти изменения всего за несколько секунд.
Перейдите в навигатор поиска — вкладку со значком лупы на левой боковой панели — и измените его режим с Поиска на замену > Регулярное выражение>.
В поле поиска введите: return “(.+)” и нажмите return для поиска.
В сменной коробке типа:
return NSLocalizedString(”$1”, комментарий: “Локализованный вид: $1”)
Это ищет любые линии, которые соответствуют шаблону возврата “что-то”. Что бы это ни было, оно будет помещено в заполнитель $1 текста замены.
Убедитесь, что выбраны только релевантные результаты поиска из SearchResult.swift — вы не хотите вносить это изменение во все результаты поиска! Нажмите кнопку Заменить, чтобы закончить.
Спасибо Скотту Гарднеру за подсказку!
Структура type
все еще та же, что и раньше, но вместо того, чтобы делать:
return "Album"
Теперь это так:
return NSLocalizedString("Album", comment: "Localized kind: Album")
Немного сложнее, но и намного гибче.
NSLocalizedString()
принимает два параметра: возвращаемый текст "Album"
и комментарий "Localized kind: Album"
.
Вот что интересно: если ваше приложение включает в себя файл с именем Localizable.strings для языка пользователя, то NSLocalizedString()
он будет искать текст (“Альбом”) и возвращать перевод, как указано в Localizable.strings.
Если перевод этого текста отсутствует или нет локализуемого файла.strings, то NSLocalizedString()
просто возвращает текст как есть.
BOS Запустите приложение еще раз. Поле “Type:” во всплывающем окне- или “Soort:” на голландском языке — все равно должно показывать те же текстовые значения, что и раньше, потому что вы еще ничего не перевели.
Во-первых, вам нужно создать пустой файл Localizable.strings.
BOS Щелкните правой кнопкой мыши папку StoreSearch в навигаторе проекта, выберите Новый файл…, выберите шаблон файла строк в разделе iOS — Ресурс и нажмите Далее. Сохраните файл как Localizable.strings.
BOS Выберите Localizable.strings, в инспекторе файлов (справа) нажмите Localize…, выберите английский из выпадающего списка и нажмите Localize.
Это создает пустой английский локализуемый файл.strings. Вам нужно использовать инструмент командной строки с именем genstrings, чтобы заполнить файл текстовыми строками из исходных файлов. Для этого требуется поездка в Терминал.
Создание локализуемых текстовых строк
BOS Откройте терминал cd
в папке, содержащей проект StoreSearch. Вы хотите перейти в папку, содержащую фактические исходные файлы. В моей системе это так:
cd ~/Desktop/StoreSearch/StoreSearch
Затем введите следующую команду:
genstrings *.swift -o en.lproj
Он просматривает все ваши исходные файлы (*.swift) и записывает текстовые строки из этих исходных файлов в файл Localizable.strings в папке en.lproj.
Если вы сейчас откроете файл Localizable.strings, то это то, что он должен содержать:
`/* Localized kind: Album */
«Album» = «Album»;
/* Localized kind: Software */
«App» = «App»;
/* Localized kind: Audio Book */
«Audio Book» = «Audio Book»;
/* Localized kind: Book */
«Book» = «Book»;
/* Localized kind: E-Book */
«E-Book» = «E-Book»;
/* Localized kind: Feature Movie */
«Movie» = «Movie»;
/* Localized kind: Music Video */
«Music Video» = «Music Video»;
/* Localized kind: Podcast */
«Podcast» = «Podcast»;
/* Localized kind: Song */
«Song» = «Song»;
/* Localized kind: TV Episode */
«TV Episode» = «TV Episode»;`
Вещи между символами /*
и*/
-это комментарии, которые вы указали в качестве второго параметра NSLocalizedString()
.
Они дают переводчику некоторый контекст о том, где строка должна использоваться в приложении.
Совет: Рекомендуется сделать эти комментарии как можно более подробными. По словам товарища raywenderlich.com автор Скотт Гарднер:
“Комментарий к переводчику должен быть настолько подробным, насколько это необходимо, чтобы указать не только слова, подлежащие транскрипции, но и перспективу, намерение, гендерную систему отсчета и т.д. Во многих языках есть разные слова, основанные на этих соображениях. Однажды я перевел приложение на упрощенный китайский язык, и мне потребовалось несколько проходов, чтобы сделать это правильно, потому что мои оригинальные комментарии были недостаточно подробными”.
BOS Измените строку “Песня” на:
"Song" = "SUPER HIT!";
Теперь запустите приложение еще раз и найдите музыку. Для любого результата поиска, который является песней, теперь он будет говорить “СУПЕР ХИТ!” вместо”Песня».

Там, где раньше говорилось «Песня», теперь написано «СУПЕРХИТ»!
Конечно, менять текст в английской локализации не имеет особого смысла. Измените изменение на Песню, и тогда мы сделаем это правильно.
BOS В инспекторе файловдобавьте голландскую локализацию для этого файла. Это создает копию Localizable.strings в папке nl.lproj.
BOS Измените переводы в голландской версии Localizable.strings на:
"Album" = "Album"; "App" = "App"; "Audio Book" = "Audioboek"; "Book" = "Boek"; "E-Book" = "E-Boek"; "Movie" = "Film"; "Music Video" = "Videoclip"; "Podcast" = "Podcast"; "Song" = "Liedje"; "TV Episode" = "TV serie";
Если вы снова запустите приложение, все типы продуктов будут написаны на голландском языке. Мило!
Всегда используйте NSLocalizedString() с самого начала
В приложении есть куча других строк, которые также нуждаются в переводе. Вы можете искать все, что начинается с
"
, но было бы намного проще, если бы вы использовалиNSLocalizedString()
с самого начала. Тогда все, что вам нужно было бы сделать, это запустить инструмент genstrings, и вы получите все строки.Теперь вам предстоит прочесать исходный код и добавить
NSLocalizedString()
ко всему тексту строки, которые будут показаны пользователю — mea culpa!Вы действительно должны привыкнуть всегда использовать
NSLocalizedString()
строки, которые вы хотите отобразить пользователю, даже если вы не заботитесь об интернационализации сразу.Добавление поддержки других языков-отличный способ для того, чтобы ваши приложения стали более популярными, а возвращаться к добавлению кода
NSLocalizedString()
-не очень весело. Лучше сделать это с самого начала!
Вот другие строки, которые я нашел, которые должны бытьNSLocalizedString
-ified:
`// DetailViewController, updateUI()
artistNameLabel.text = «Unknown»
priceText = «Free»
// LandscapeViewController, showNothingFoundLabel()
label.text = «Nothing Found»
// SearchResultCell, configure(for)
artistNameLabel.text = «Unknown»
// SearchViewController, showNetworkError()
title: «Whoops…»,
message: «There was an error reading from the iTunes Store.
Please try again.»,
title: «OK»`
BOS Добавьте NSLocalizedString()
вокруг этих строк. Не забывайте использовать описательные комментарии!
Например, при создании экземпляра UIAlertController
in showNetworkError()
вы можете написать:
let alert = UIAlertController( title: NSLocalizedString("Whoops...", comment: "Error alert: title"), message: NSLocalizedString( "There was an error reading from the iTunes Store. Please try again.", comment: "Error alert: message"), preferredStyle: .alert)
Примечание: Вам не нужно использовать
NSLocalizedString()
с вашимиprint()
«ы». Отладочный вывод действительно предназначен только для вас, разработчика, поэтому лучше всего, если он будет на английском или любом другом вашем родном языке.
Снова запустите инструмент genstrings. Приведите ему те же аргументы, что и раньше. Он поместит чистый файл со всеми новыми строками в папку en.lproj.
К сожалению, на самом деле нет хорошего способа заставить genstrings объединять новые строки в существующие переводы. Он перезапишет весь ваш файл и выбросит все внесенные вами изменения. Существует способ заставить инструмент добавлять свои выходные данные в существующий файл, но тогда вы получите много повторяющихся строк.
Совет: Всегда восстанавливайте только файл в en.lproj, а затем копируйте недостающие строки в другие локализуемые файлы.strings. Вы можете использовать такой инструмент, как FileMerge или Kaleidoscope, чтобы сравнить два файла и найти новые строки. В Mac App Store также есть несколько сторонних инструментов, которые немного удобнее в использовании, чем genstrings.
Вы также можете получить предупреждение, подобное следующему, если вы не были последовательны в использовании одного и того же комментария для одного и того же слова, когда оно появляется в нескольких местах:
Warning: Key "Unknown" used with multiple comments "Artist name label: Unknown" & "Artist name: Unknown"
Если вы проверите файл Localizable.strings, то заметите, что в файле нет двух экземпляров слова “Unknown” (или любого другого слова, которое породило ошибку). Но есть два комментария к одному и тому же слову.
Вы можете легко исправить это — если захотите — вернувшись назад и используя тот же комментарий для того же слова, а затем снова запустив инструмент genstrings.
BOS Добавьте эти новые переводы в голландские локализуемые строки.:
`»Nothing Found» = «Niets gevonden»;
«There was an error reading from the iTunes Store. Please try again.» = «Er ging iets fout bij het communiceren met de iTunes winkel. Probeer het nog eens.»;
«Unknown» = «Onbekend»;
«Whoops…» = «Foutje…»;`
Может показаться немного странным, что такая длинная строка, как “Произошла ошибка чтения из iTunes Store. Пожалуйста, попробуйте еще раз”. будет использоваться в качестве ключа поиска для переведенной строки, но на самом деле в этом нет ничего плохого.
Кстати, точка с запятой в конце каждой строки не является необязательной. Если вы забудете точку с запятой, файл Localizable.strings не может быть скомпилирован, и сборка завершится неудачно.
Некоторые люди пишут код для NSLocalizedString
этого:
let s = NSLocalizedString("ERROR_MESSAGE23", comment: "Error message on screen X")
Тогда файл Localizable.strings будет выглядеть следующим образом:
/* Error message on screen X */ "ERROR_MESSAGE23" = "Does not compute!";
Это работает, но мне труднее читать. Это требует, чтобы у вас всегда был английский Localizable.strings. Обратите также внимание, что текст "Unknown"
встречается только один раз в Localizable.strings, хотя он отображается в двух разных местах исходного кода. Каждый фрагмент текста нужно перевести только один раз.
Локализация динамически построенных строк
Если ваше приложение создает строки динамически, то вы также можете локализовать такой текст. Например, в SearchResultCell.swiftconfigure(for:)
вы делаете:
artistNameLabel.text = String( format: "%@ (%@)", result.artist, result.type)
Интернационализируйте это следующим образом::
artistNameLabel.text = String( format: NSLocalizedString( "%@ (%@)", comment: "Format for artist name"), result.artist, result.type)
После повторного запуска genstrings это отображается в Localizable.strings следующим образом::
/* Format for artist name */ "%@ (%@)" = "%1$@ (%2$@)";
Если вы хотите, вы можете изменить порядок этих параметров в переведенном файле. Например:
"%@ (%@)" = "%2$@ van %1$@";
Это превратит ярлык с именем исполнителя во что-то вроде этого:

«Вид “теперь стоит на первом месте, имя художника-на последнем
В этом случае я бы выступал за использование специального ключа, а не буквальной строки для поиска перевода. Вполне возможно, что ваше приложение будет использовать строку формата "%@ (%@)"
в каком-то другом месте, и вы можете перевести ее совершенно по-другому.
Вместо этого я бы назвал это чем-то вроде ARTIST_NAME_LABEL_FORMAT
(это происходит в голландском Localizable.strings).:
/* Format for artist name label */ "ARTIST_NAME_LABEL_FORMAT" = "%2$@ van %1$@";
Вам также необходимо добавить этот ключ в английскую версию Localizable.strings:
/* Format for artist name label */ "ARTIST_NAME_LABEL_FORMAT" = "%1$@ (%2$@)";
Не забудьте также изменить код:
artistNameLabel.text = String( format: NSLocalizedString( "ARTIST_NAME_LABEL_FORMAT", // Change this line comment: "Format for artist name"), result.artist, result.type)
Локализация на основе данных
Есть еще одна вещь, которую я хотел бы улучшить. Помните, как в SearchResult.swift type
свойство является этим огромным switch
утверждением? По-моему, это “вонючий”. Проблема в том, что любые новые продукты требуют, чтобы вы добавили еще один корпус к коммутатору.
В подобных ситуациях лучше использовать подход, основанный на данных. Здесь это означает, что вы помещаете типы продуктов и их удобочитаемые имена в структуру данных, словарь, а не в структуру кода.
BOS Добавьте следующий словарь в SearchResult.swift, внутри class
(вы можете скопировать и вставить его, так type
как он почти идентичен):
private let typeForKind = [ "album": NSLocalizedString( "Album", comment: "Localized kind: Album"), "audiobook": NSLocalizedString( "Audio Book", comment: "Localized kind: Audio Book"), "book": NSLocalizedString( "Book", comment: "Localized kind: Book"), "ebook": NSLocalizedString( "E-Book", comment: "Localized kind: E-Book"), "feature-movie": NSLocalizedString( "Movie", comment: "Localized kind: Feature Movie"), "music-video": NSLocalizedString( "Music Video", comment: "Localized kind: Music Video"), "podcast": NSLocalizedString( "Podcast", comment: "Localized kind: Podcast"), "software": NSLocalizedString( "App", comment: "Localized kind: Software"), "song": NSLocalizedString( "Song", comment: "Localized kind: Song"), "tv-episode": NSLocalizedString( "TV Episode", comment: "Localized kind: TV Episode") ]
Теперь код для type
становится действительно коротким:
var type: String { let kind = self.kind ?? "audiobook" return typeForKind[kind] ?? kind }
Это не что иное, как простой поиск по словарю.
Это ??
нулевой коалесцирующий оператор. Помните, что поиск по словарю всегда возвращает необязательный параметр на случай, если ключ, который вы ищете — kind
в данном случае — не существует в словаре. Это может произойти, если веб-служба iTunes добавит новые типы продуктов. Если словарь дает вам nil
, ??
оператор просто возвращает исходное значение kind.
InfoPlist.strings
Само приложение может иметь другое имя в зависимости от языка пользователя. Имя, отображаемое на главном экране iPhone, берется из параметра Имя пакета на вкладке Информация или, если он присутствует, из параметра Отображаемое имя пакета.
Чтобы локализовать строки на вкладке Info, вам понадобится файл с именем InfoPlist.strings.
BOS Добавьте новый файл в проект. В окне выбора шаблона прокрутите вниз до группы ресурсов и выберите файл строк. Назовите его InfoPlist.strings (капитализация имеет значение!).

Добавление нового файла Strings в проект
BOS Выберите InfoPlist.strings и нажмите кнопку Localize… в инспекторе файлов. Выберите английскую локализацию.
BOS Также добавьте голландскую локализацию для этого файла.
BOS Откройте голландскую версию и добавьте следующую строку:
CFBundleDisplayName = "StoreZoeker";
Ключ для настройки “Отображаемое имя пакета” таков CFBundleDisplayName
.
Голландские читатели, извините за глупое название. Это лучшее, что я мог придумать. Не стесняйтесь подставлять свои собственные.
BOS Запустите приложение и закройте его, чтобы увидеть его значок. Теперь на трамплине симулятора должно отображаться переведенное название приложения:

Даже название приложения локализовано!
Если вы переключите симулятор обратно на английский, название приложения снова будет StoreSearch (и, конечно, весь остальной текст тоже вернется на английский).
Примечание: Если вы тестировали голландские локализации с помощью параметров схемы, то вы не увидите, что имя приложения изменено на голландский в трамплине – параметры схемы влияют только на приложение. В этом случае вам все равно придется переключить свой симулятор (или устройство) на голландский, чтобы увидеть изменение имени.
Региональные настройки
Я не знаю, заметили ли вы это на некоторых предыдущих скриншотах, но даже несмотря на то, что вы переключили язык на голландский, цены на продукты по-прежнему отображаются в долларах США, а не в евро. Это по двум причинам:
- Языковые настройки не зависят от региональных настроек. Способ отображения валют и чисел зависит от региональных настроек, а не от языка.
- Приложение ничего не указывает о стране или языке, когда отправляет запросы в iTunes Store, поэтому веб-сервис всегда возвращает цены в долларах США.
Исправить веб-запрос, чтобы включить язык и регион
Вы исправите приложение таким образом, чтобы оно отправляло информацию о языковых и региональных настройках пользователя в iTunes Store.
BOS В Search.swiftизмените iTunesURL(searchText:category:)
метод следующим образом::
`private func iTunesURL(
searchText: String,
category: Category
) -> URL {
// Add the following 3 lines
let locale = Locale.autoupdatingCurrent
let language = locale.identifier
let countryCode = locale.regionCode ?? «en_US»
. . .
// Modify the URL string
let urlString = «https://itunes.apple.com/search?» +
«term=(encodedText)&limit=200&entity=(kind)» +
«&lang=(language)&country=(countryCode)»
let url = URL(string: urlString)
print(«URL: (url!)») // Add this
return url!
}`
Региональные настройки также называются языковым стандартом пользователя, и, конечно же, есть объект для его представления Locale
. Вы получаете ссылку на autoupdatingCurrent
локаль.
Этот объект локали называется “autoupdating”, поскольку он всегда отражает текущее состояние настроек локали пользователя. Другими словами, если пользователь изменяет свою региональную информацию во время работы приложения, приложение автоматически использует эти новые настройки при следующем выполнении каких-либо действий с Locale
объектом.
Из locale
объекта вы получаете язык и код страны. Затем вы помещаете эти два значения в URL-адрес, используя параметры &lang=
and&country=
. Потому locale.regionCode
что , может бытьnil
, мы используем ?? "US"
его как безотказный.
Это print()
позволяет вам увидеть, каким именно будет URL-адрес.
BOS Запустите приложение и выполните поиск. Xcode должен вывести что — то вроде следующего, если в качестве языка задан английский:
Он добавил “en_US” в качестве идентификатора языка и просто “US” в качестве страны. Для продуктов с описаниями (например, приложений) веб-служба iTunes вернет английскую версию описания. Цены на все товары будут иметь доллары США в качестве валюты.
Примечание: Также возможно, что вы получили сообщение об ошибке, которое возникает, когда идентификатор локали возвращает что-то бессмысленное, например
nl_US
. Это связано с сочетанием языковых и региональных настроек на вашем Mac или симуляторе. Если вы также измените регион (см. Ниже), ошибка должна исчезнуть. Веб-служба iTunes поддерживает не все комбинации языков и регионов, поэтому улучшением приложения будет проверка значенияlanguage
по списку разрешенных языков. Я оставлю это как упражнение для вас.
Тест на изменение региона
BOS В симуляторе переключитесь в приложение «Настройки», чтобы изменить региональные настройки. Перейдите в раздел Общие ▸ Язык и регион ▸ Регион. Выберите Нидерланды.
Если Симулятор все еще на голландском языке, то он находится под Algemeen ▸ Taal en Regio ▸ Regio. Поменяй его на «Недерланд«. Если язык не установлен на голландский, то установите язык на голландский прямо сейчас.
Снова запустите StoreSearch и повторите поиск.
Xcode теперь говорит:
Язык и страна теперь установлены на NL — для Нидерландов. Если вы нажмете на результат поиска, то увидите, что цена теперь указана в евро:

Цена в соответствии с настройками региона пользователя
Конечно, NumberFormatter
за это нужно благодарить. Теперь он знает, что настройки региона происходят из Нидерландов, поэтому использует запятую для десятичной точки.
А поскольку веб-сервис теперь возвращает "EUR"
код валюты, форматер чисел помещает символ евро перед суммой. Вы можете получить много функциональности бесплатно, если знаете, какие классы использовать!
Вот и все, что касается интернационализации. Это требует лишь небольшого усилия, но оно определенно окупается.
Теперь вы можете перевести Симулятор обратно на английский язык.
Пришло время совершить коммит, потому что в следующем разделе вы собираетесь внести некоторые большие изменения.
Если вы также пометили код, вы можете назвать это v0.9, так как вы быстро приближаетесь к версии 1.0, которая готова к выпуску.
Файлы проекта для этой главы можно найти в разделе 41-Интернационализация в папке исходного кода.