'Locale.current reporting wrong language on device

I'm trying to format currency values in an iOS app, and I'm using the current Locale settings on the device to use the appropriate currency formatting.

In the simulator, everything seems to run fine: when using currencyFormatter.locale = Locale.current, it takes the right locale settings and prints numbers with the right currency format.

On my iPhone however, which is configured in French with French regional settings, I would expect another format to be used (e.g.: 1 234,56 €). But it does not work, and seems to use an English formatting style (e.g.: €1 234,56).

In fact, if I print the current Locale from my app on the device, it does not return fr_FR as I would expect:

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

The region is good but the language is not, though iOS on that device is clearly in French.

Has anyone an idea about this?

Thanks!



Solution 1:[1]

Based on @Romain's answer the forced unwrapping of first! could be avoided by using the Locale.current.identifier as fallback.

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

Solution 2:[2]

@Romain The problem here is that you have not localized your app for French but only for English.

Go to the upper left blue file with the name of your app, select Project > Info and in the Localization area you will see "English - Development Language". Press + and choose French (fr).

That's it. Now you can use Locale.current and if the first language of a device (or simulator) is French, your app will show French currency format.

Solution 3:[3]

@florieger's answer in the form of extension:

import Foundation

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

Then use it like this:

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

Solution 4:[4]

If everything else fails

I spent an hour debugging this. I am in Germany and my iPhone language settings are English and my Region is Germany.

I am debugging an app that takes the locale from the iPhone and pass it in an API call as a header to a server. I was wondering why I always get all the data strings in German. Looking into the app it was all done correctly:

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

The variable above deviceLanguageCode always returns de.
But it should be "en"!
I tried everything. I used Locale.autoupdatingCurrent.languageCode or Locale.preferredLanguages.first etc, nothing would work. I checked my project settings, my Localizable.strings files. All good. If I made a new Xcode project and print those variables I would get the correct locale, and region: en_DE.

This is so infuriating!
Only when I exhausted all possibilities, I read this post by Paul Hudson, (who else?) and at the end, he gives a tip for testing the localisations:

Tip: You can switch between languages by going to the Product menu, holding down the Alt key, then choosing “Run...” Look under the Options tab and you’ll see Application Language is set to System Language by default, but you can change to others there for testing purposes.

And... 'quelle horreur!' Somebody had been there before me and had set the App Language and Region to Germany!!! No wonder I had a hard time!

End of story: Make sure these are set to system or nothing will work ;)

enter image description here

Solution 5:[5]

Following @MartinR's hint, I'm now using currencyFormatter.locale = Locale(identifier: Locale.preferredLanguages.first!), which corresponds exactly to the device's current language & region settings.

I'm not entirely sure this code is bullet-proof though (because of first!, most notably) so if you have other suggestions, please feel free.

Solution 6:[6]

use this code for get current System language code from iOS device

let pre = Locale.preferredLanguages[0]

Still if you face this issue if you got wrong language code. kindly remove this object from UserDefaults "AppleLanguages" and use this same code Locale.preferredLanguages[0]

for your reference

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
}

Solution 7:[7]

Summary

Apple expects that when a developer decides to support localizations, the project would have localizable resources like strings or storyboards to provide consistent UI (e.g. not just to print currency in local format) and in this case using Locale.current is the appropriate choice and it would work just fine for supported localizations (as mentioned by this answer).

However, in cases like @Romain's:

"I would have hoped I would be able to print currency numbers in the user's regional settings without having to provide a localization for every language"

the workaround to achieve that is by using Locale.preferredLanguages.first with fallback in case of null (as mentioned by this answer)

Solution 8:[8]

When the widget should have the same language as the app and the iPhone language is different you can use this:

func getPreferredLocale() -> Locale {
    guard let preferredIdentifier = Bundle.main.preferredLocalizations.first else {
        return Locale.current
    }
    return Locale(identifier: preferredIdentifier)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marc_s
Solution 2 Nikos Polychronakis
Solution 3 marc_s
Solution 4
Solution 5 Romain
Solution 6 Alagu Raja.B
Solution 7 Dima G
Solution 8 Michael