Locale.current сообщает о неправильном языке на устройстве

Я пытаюсь отформатировать валютные значения в приложении для iOS и использую текущие настройки локали на устройстве, чтобы использовать соответствующее форматирование валюты.

В симуляторе все вроде нормально работает: при использовании currencyFormatter.locale = Locale.current, он принимает правильные настройки локали и печатает числа в правильном формате валюты.

Однако на моем iPhone, который настроен на французском языке с французскими региональными настройками, я ожидаю, что будет использоваться другой формат (например: 1 234,56 €). Но это не работает, и, кажется, использует английский стиль форматирования (например: 1 234,56 €).

Фактически, если я печатаю текущую локаль из моего приложения на устройстве, она не возвращается fr_FR как и следовало ожидать:

NSLog(Locale.current.identifier)
>>> en_FR

Регион хороший, но язык нет, хотя iOS на этом устройстве явно на французском.

У кого-нибудь есть идеи по этому поводу?

Спасибо!

9 ответов

Решение

Основываясь на ответе @ Ромена, принудительное развертывание first! можно избежать с помощью Locale.current.identifier как запасной вариант.

func getPrefferedLocale() -> Locale {
    guard let prefferredIdentifier = Locale.preferredLanguages.first else {
        return Locale.current
    }
    return Locale(identifier: prefferredIdentifier)
}

@Romain Проблема в том, что вы не локализовали свое приложение для французского, а только для английского.

Перейдите к верхнему левому синему файлу с названием вашего приложения, выберите "Проект"> "Информация", и в области "Локализация" вы увидите "Английский - Язык разработки". Нажмите + и выберите французский (пт).

Вот и все. Теперь вы можете использовать Locale.current, и если первый язык устройства (или симулятора) - французский, ваше приложение будет отображать формат французской валюты.

@florieger ответ в виде расширения:

import Foundation

extension Locale {
    static func prefferedLocale() -> Locale {
        guard let prefferredIdentifier = Locale.preferredLanguages.first else {
            return Locale.current
        }
        return Locale(identifier: prefferredIdentifier)
    }
}

Тогда используйте это так:

dateFormatter.locale = Locale.prefferedLocale()
datePicker.locale = Locale.prefferedLocale()

Если все остальное не удается

Я потратил час на отладку. Я нахожусь в Германии, и мои языковые настройки iPhone - английский, а мой регион - Германия.

Я отлаживаю приложение, которое берет языковой стандарт с iPhone и передает его в вызове API в качестве заголовка на сервер. Мне было интересно, почему я всегда получаю все строки данных на немецком языке. Заглянув в приложение, все было сделано правильно:

          if let deviceLanguageCode = Locale.current.languageCode,
    deviceRegionCode = Locale.current.regionCode {
        // do stuff here
    }

Переменная выше deviceLanguageCode всегда возвращается de.
Но это должно быть «ан»!
Все перепробовала. я использовал Locale.autoupdatingCurrent.languageCode или же Locale.preferredLanguages.firstи т.д., ничего не получится. Я проверил настройки своего проекта, мой Localizable.stringsфайлы. Все хорошо. Если бы я создал новый проект Xcode и распечатал эти переменные, я бы получил правильный языковой стандарт и регион: en_DE.

Это так бесит!
Только когда я исчерпал все возможности, я прочитал этот пост Пола Хадсона (кого еще?), И в конце он дает совет по тестированию локализаций:

Совет: вы можете переключаться между языками, перейдя в меню «Продукт», удерживая клавишу Alt, затем выбрав «Выполнить ...». Посмотрите на вкладку «Параметры», и вы увидите, что язык приложения по умолчанию установлен на системный язык, но можно изменить на другие для целей тестирования.

И ... quelle horreur! Кто-то был там до меня и установил язык и регион приложения на Германию !!! Неудивительно, что мне пришлось нелегко!

Конец истории: убедитесь, что они настроены на систему, иначе ничего не будет работать;)

Следуя подсказке @MartinR, я сейчас использую currencyFormatter.locale = Locale(identifier: Locale.preferredLanguages.first!), что в точности соответствует текущим настройкам языка и региона устройства.

Я не совсем уверен, что этот код пуленепробиваемый, хотя (из-за first!, особенно), поэтому, если у вас есть другие предложения, пожалуйста, не стесняйтесь.

если вы хотите, чтобы текущий язык зависел от региона пользователя и локали, используйте это:

      Locale.current.languageCode

НО ЕСЛИ вы хотите НАСТРОЙКИ ТЕКУЩЕГО языка, используйте этот код:

      Locale.preferredLanguages.first

Резюме

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

Однако в таких случаях, как @Romain:

«Я надеялся, что смогу печатать номера валют в региональных настройках пользователя без необходимости локализации для каждого языка».

обходной путь для достижения этого заключается в использовании с резервом на случай (как упоминалось в этом ответе )

используйте этот код для получения текущего кода языка системы с устройства iOS

      let pre = Locale.preferredLanguages[0]

Тем не менее, если вы столкнетесь с этой проблемой, если у вас неправильный код языка. Пожалуйста, удалите этот объект из UserDefaults "AppleLanguages" и используйте тот же код Locale.preferredLanguages[0]

для справки

      func getSystemLanguageCode() -> String {
    UserDefaults.standard.removeObject(forKey: "AppleLanguages")
    let pref_Language = NSLocale.preferredLanguages[0] as String //"fr-IN"
    let language = pref_Language.components(separatedBy: "-") //["fr","IN"]
    let lang_Code = language.first?.lowercased() ?? "" //"fr"
    UserDefaults.standard.set([lang_Code], forKey: "AppleLanguages")
    
    return lang_Code
}

Когда виджет должен иметь тот же язык, что и приложение, а язык iPhone отличается, вы можете использовать это:

      func getPreferredLocale() -> Locale {
    guard let preferredIdentifier = Bundle.main.preferredLocalizations.first else {
        return Locale.current
    }
    return Locale(identifier: preferredIdentifier)
}
Другие вопросы по тегам