Home > Net >  How do I find the Locale Identifier using the ISO country code (2 letters)
How do I find the Locale Identifier using the ISO country code (2 letters)

Time:10-10

In my App I would like to display the correct currency code depending on the country the user is looking in:

var isoCountryCode = "GB"
    
let currency = Locale(identifier: isoCountryCode).currency?.identifier ?? "GBP"

So instead of hard coding "GB" I would like to replace this with a variable that uses the ISOCountryCode to determine the Locale Identifier. i.e. for the United Kingdom this would be GB as the two character ISO country code and the result would either be "en_GB".

Alternatively, if there is an easier way to use the Country Code to determine the local currency, I would be equally happy.

CodePudding user response:

I have found the answer here:

swift get currencycode from country code

The code was a bit outdated, so the updated code is:

let components: [String: String] = [NSLocale.Key.countryCode.rawValue: isoCountryCode]
    
let identifier = NSLocale.localeIdentifier(fromComponents: components)
    
let locale = NSLocale(localeIdentifier: identifier)
    
let currencyCode = locale.object(forKey: NSLocale.Key.currencyCode)

CodePudding user response:

You're assuming that every language group within in region uses the same currency. This happens to be true, but it's not promised (humans are very inconsistent). But it is true, so we can use that fact.

First, let's prove it's currently true so you could detect if it ever weren't true. To do that, create all the locales (this is a technique you'll need later, so it's worth trying out).

let locales = Locale.availableIdentifiers.map(Locale.init(identifier:))

Now, make a mapping of every region to every currency used in that region:

let currencies = Dictionary(grouping: locales,
                            by: { $0.region?.identifier ?? ""})
    .mapValues { $0.compactMap { $0.currency?.identifier }}

The output of this is in the pattern:

["BZ": ["BZD", "BZD"], "MR": ["MRU", "MRU", "MRU", "MRU"], ...

Then the question is: are there any regions that use more than one currency?

let allMatch = currencies.values
    .filter { list in !list.allSatisfy { $0 == list.first }}
    .isEmpty  // true

Good. This assumption seems to work. We can pick any random language within a region that has a currency, and that currency should be the currency for the region.


Given that it's safe to pick a random language, let's do that:

let isoCountryCode = "GB"

let locale = Locale.availableIdentifiers.lazy
    .map(Locale.init(identifier:))
    .first(where: { $0.region?.identifier == isoCountryCode && $0.currency != nil })

locale?.currency?.identifier  // "GBP"

BTW, this happens to pick Cornish (kw) as the language on my machine, not English, but that's fine. The assumption was that any regional language will have the same currency.

  • Related