NSDateFormatter и текущий язык в iOS11

Похоже, что поведение по умолчанию для NSDateFormatter было изменено в iOS11. Этот код использовался для создания и форматирования даты в соответствии с выбранным языком iPhone/iPad до iOS11:

 _dateFormatterInstance = [[NSDateFormatter alloc] init];
 _dateFormatterInstance.timeZone = [NSTimeZone systemTimeZone];

Похоже, в iOS11 мы должны явно указать для него свойство locale:

 _dateFormatterInstance = [[NSDateFormatter alloc] init];
 _dateFormatterInstance.timeZone = [NSTimeZone systemTimeZone];
 _dateFormatterInstance.locale = [NSLocale localeWithLocaleIdentifier:[[NSLocale preferredLanguages] firstObject]];

Может кто-нибудь подтвердить мои выводы?

Ответ 1

Это не проблема с NSDateFormatter, это изменение в том, как iOS 11 поддерживает локализацию.

В iOS 11, [NSLocale currentLocale] возвращает только языки, поддерживаемые локализациями приложений. Если ваше приложение поддерживает только английский язык (в качестве базовой локализации), то независимо от того, какой язык пользователь выбирает на устройстве, currentLocale всегда будет возвращать английский.

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

Классы, такие как NSDateFormatter по умолчанию, используют NSLocale currentLocale. Поэтому независимо от того, какой язык поддерживается вашим приложением через локализацию, такие классы, как NSDateFormatter, будут отображать текст на языке, установленном на устройстве, даже если он отличается от языка, используемого вашим приложением.

iOS 11 исправляет эту несогласованность. Хотя можно утверждать, что это изменение ломает множество приложений, которые поддерживают только один (или только несколько) язык, это фактически делает приложение более последовательным.

Чтобы все это было ясно, рассмотрим пример. Вы создаете простое тестовое приложение с базовой локализацией на английском языке. Если вы запустите приложение с iOS 10 и язык устройства установлен на английский, вы, очевидно, увидите текст на английском языке, и вы увидите даты, отформатированные для английского. Если теперь вы измените язык устройства на французский и перезагрузите приложение, пользователь теперь увидит текст на английском языке в приложении (так как это единственная его локализация), но даты теперь отображаются с французскими именами месяца месяца и недели.

Теперь запустите одно и то же приложение под iOS 11. Как и в случае с iOS 10, если язык устройства - английский, вы видите все на английском языке. Если вы измените язык устройства на французский и запустите приложение, iOS 11 увидит, что ваше приложение поддерживает только английский язык, а currentLocale возвращает английский, а не французский. Итак, теперь пользователь видит текст на английском языке (из-за локализации приложения), и даты теперь также остаются на английском языке.

Ответ 2

На самом деле это скорее ошибка, чем преднамеренное изменение поведения в iOS 11. Если у вас только один набор языков, это поведение отсутствует, поскольку Locale.current всегда возвращает правильный язык и область даже если ваше приложение не локализовано на этом языке.

Однако, если у вас есть несколько языков, таких как французский и английский, то iOS 11 всегда предпочитает английский или самый близкий поддерживаемый язык в вашем приложении при использовании Locale.current.

Locale.preferredLanguages, похоже, возвращает правильную информацию о регионе, поэтому вы можете использовать это вместо этого.

Ниже приведен пример вывода из Locale.current и Locale.preferredLanguages, показывающий несоответствия.

Это было создано из приложения, поддерживающего только английский. На устройстве французский был установлен как основной язык, так и регион, а английский (Австралия) был установлен в качестве второго языка в первом примере.

(Неправильно) Locale.current с несколькими языками - обратите внимание на то, насколько английский является языком, когда он должен быть французским, и поэтому fr_FR

  - identifier : "en_FR"
  - kind : "current"

(Правильно) Locale.preferredLanguages с несколькими языками

  - 0 : "fr-FR"
  - 1 : "en-AU"

(Правильно) Locale.current с французским языком как единственным языком

  - 0 : "fr-FR"

(Правильно) Locale.preferredLanguages с французским языком как единственным языком

  - identifier : "fr_FR"
  - kind : "current"

Ответ 3

Да, поведение по умолчанию изменено в iOS11 точно так же, как описано в @rmaddy.

В моем случае у меня есть проект с базовым языком разработки, установленным на Английский, но на iOS11, когда я изменил язык устройства на любой другой язык (например, шведский), даты будут по-прежнему отображается как, например, Monday 6 November. Это произошло потому, что мое приложение не поддерживало никакой локализации.

Решение было простым: для того, чтобы приложение отображало даты на шведском языке, мне просто пришлось добавить пустой файл Strings.strings, а затем в настройках проектов я добавил шведскую локализацию. Несмотря на то, что файл строк пуст, приложение стало локализованным на шведском языке, поэтому, изменив язык в настройках на шведский, мы могли видеть ту же дату, что и måndag 6 november, тем самым достигая желаемого варианта использования iOS10.

Примечание:, если вы сделаете что-то подобное, и это не сработает для вас, при добавлении языка в "Настройки проекта" обязательно перейдите в "Другое" и выберите язык оттуда (вместо этого просто выберите один из выпадающего списка первого уровня).