24

Im retrieving a country name from a server in english. For example, "Spain"

What I want to do is, assuming the country name is going to be written in english, get the country code.

What should I do? I´ve found getting the country name from the country code quite easy, but I´ve got no idea of how to do the opposite operation.

Thanks a lot.

pdrcabrod
  • 1,467
  • 1
  • 14
  • 22

9 Answers9

30

Jef's answer helped here, with slight additions.

NSArray *countryCodes = [NSLocale ISOCountryCodes];
NSMutableArray *countries = [NSMutableArray arrayWithCapacity:[countryCodes count]];

for (NSString *countryCode in countryCodes)
{
    NSString *identifier = [NSLocale localeIdentifierFromComponents: [NSDictionary dictionaryWithObject: countryCode forKey: NSLocaleCountryCode]];
    NSString *country = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_UK"] displayNameForKey: NSLocaleIdentifier value: identifier];
    [countries addObject: country];
}

NSDictionary *codeForCountryDictionary = [[NSDictionary alloc] initWithObjects:countryCodes forKeys:countries];

Now go through the 'codeForCountryDictionary' with the name of the country for which you require the code, for example,

NSLog(@"%@",[codeForCountryDictionary objectForKey:@"Spain"]);

would yield the result as 'ES', which is the 2 letter country code for spain.

Community
  • 1
  • 1
Breakpoint
  • 1,511
  • 1
  • 18
  • 41
  • 4
    Well, if you know the country names are in English, you should of course NOT use the currentLocale, but a fixed locale. The currentLocale can be in any language. Use [NSLocale initWithLocaleIdentifier:@"en_UK"] instead. – fishinear Apr 14 '13 at 13:16
  • initWithLocaleIdentifier is an instance method, not a class method, so use `[[NSLocale alloc] initWithLocaleIdentifier:@"en_UK"]` instead – pyrou May 09 '14 at 12:49
  • Just to make sure I would also lower/upper case the dictionary keys. We're not sure what the server returns (which is a different problem, but at least that can minimize the 'displayName' weakness) – surui Dec 30 '14 at 19:50
15

A Swift 4 updated version of @Daxesh Nagar solution:

private func locale(for fullCountryName : String) -> String {
    var locales : String = ""
    for localeCode in NSLocale.isoCountryCodes {
        let identifier = NSLocale(localeIdentifier: localeCode)
        let countryName = identifier.displayName(forKey: NSLocale.Key.countryCode, value: localeCode)
        if fullCountryName.lowercased() == countryName?.lowercased() {
            return localeCode as! String
        }
    }
    return locales
}

For this Input as fullCountryName

"United Kingdom"

It will return the country code as follows

"GB"

Hope it helps you guys!

Agent Smith
  • 2,873
  • 17
  • 32
Guimo
  • 335
  • 2
  • 17
  • This only seems to work if you're in an English speaking locale, right? Any suggestions on if the `fullCountryName` was "Estados Unidos"? Nice solution, thanks! – ArielSD Sep 17 '18 at 20:20
  • I'd suggest a better name for this function. This doesn't return a locale, it returns a country code. – rmaddy May 21 '19 at 15:53
  • Please note that this code only works if the country name is in the appropriate language of the country code. For example, "Spain" gives nothing but "España" returns "ES". – rmaddy May 21 '19 at 15:58
4

In the Swift you will use this code

extension NSLocale {
    class func locales1(countryName1 : String) -> String {
        var locales : String = ""
        for localeCode in NSLocale.ISOCountryCodes() {
            let countryName = NSLocale.systemLocale().displayNameForKey(NSLocaleCountryCode, value: localeCode)!
            if countryName1.lowercaseString == countryName.lowercaseString {
                return localeCode as! String
            }
        }
        return locales
    }


}

Get the data:

strP2countrycode = NSLocale.locales1("PASS_COUNTRYNAME")
Daxesh Nagar
  • 1,405
  • 14
  • 22
2

My compact version including the fix for matching only against english country names version.

extension NSLocale
{
    class func localeForCountry(countryName : String) -> String?
    {
        return NSLocale.ISOCountryCodes().first{self.countryNameFromLocaleCode($0 as! String) == countryName} as? String
    }

    private class func countryNameFromLocaleCode(localeCode : String) -> String
    {
        return NSLocale(localeIdentifier: "en_UK").displayNameForKey(NSLocaleCountryCode, value: localeCode) ?? ""
    }
}
Fawkes
  • 3,831
  • 3
  • 22
  • 37
  • I would suggest using the special locale of `en_US_POSIX` when you want to ensure standard English names and formatting. – rmaddy May 21 '19 at 15:51
2

Using swift 3 (some of the answers above are missing a piece)

extension NSLocale {
class func locales1(countryName1 : String) -> String {
    let locales : String = ""
    for localeCode in NSLocale.isoCountryCodes {
        let countryName = (Locale.current as NSLocale).displayName(forKey: .countryCode, value: localeCode)
        if countryName1.lowercased() == countryName?.lowercased() {
            return localeCode
        }
    }
    return locales
}
}
Saqib Omer
  • 5,387
  • 7
  • 50
  • 71
Robert Varga
  • 477
  • 1
  • 7
  • 15
2

Here is a simple solution that works in Swift 3 or later. Depending on your OS version, this supports roughly 256 country names and codes.

extension Locale {
    func isoCode(for countryName: String) -> String? {
        return Locale.isoRegionCodes.first(where: { (code) -> Bool in
            localizedString(forRegionCode: code)?.compare(countryName, options: [.caseInsensitive, .diacriticInsensitive]) == .orderedSame
        })
    }
}

The trick to using this correctly is knowing the language of the country names you wish to convert to the standard 2-letter ISO country code.

If you know the country names are in English, you must use this on a locale set to English. It would be best to use the special locale of en_US_POSIX in such a case.

let locale = Locale(identifier: "en_US_POSIX") 
print(locale.isoCode(for: "Spain")) // result is `ES`

If you have country names in Spanish, then be sure to use a Spanish locale:

let locale = Locale(identifier: "es") 
print(locale.isoCode(for: "España")) // result is `ES`
rmaddy
  • 314,917
  • 42
  • 532
  • 579
1

Swift 3.0 :

Getting the country code and country name as NS Dictionary-

let countryCodes: [AnyObject] = NSLocale.isoCountryCodes as [AnyObject]

        let countries: NSMutableArray = NSMutableArray(capacity: countryCodes.count)

        for countryCode in countryCodes {
            let identifier: String = NSLocale.localeIdentifier(fromComponents: NSDictionary(object: countryCode, forKey: NSLocale.Key.countryCode as NSCopying) as! [String : String])
            let country: String = NSLocale(localeIdentifier: "en_US").displayName(forKey: NSLocale.Key.identifier, value: identifier)!
            countries.add(country)
        }
        let codeForCountryDictionary: [NSObject : AnyObject] = NSDictionary(objects: countryCodes, forKeys: countries as! [NSCopying]) as [NSObject : AnyObject]

        print(codeForCountryDictionary)
Alvin George
  • 14,148
  • 92
  • 64
0

So this solution works well in swift 4 taken from comments above...

extension NSLocale {
   struct Locale {
    let countryCode: String
    let countryName: String
   }

  class func locales() -> [Locale] {

    var locales = [Locale]()

    for localeCode in NSLocale.isoCountryCodes {
        let identifier = NSLocale(localeIdentifier: localeCode)
        let countryName = identifier.displayName(forKey: NSLocale.Key.countryCode, value: localeCode)!
        let countryCode = localeCode
        let locale = Locale(countryCode: countryCode, countryName: countryName)
        locales.append(locale)
    }

    return locales.sorted{$0.countryName.localizedCaseInsensitiveCompare($1.countryName) == ComparisonResult.orderedAscending}
 }
}

enjoy!

  • This makes no attempt to answer the question. And you certainly should not be naming a struct `Locale` in Swift since `Locale` is already a struct provided by Foundation. – rmaddy May 21 '19 at 15:40
-1

Swift 5

extension Locale {
    func countryCode(by countryName: String) -> String? {
        return Locale.isoRegionCodes.first(where: { code -> Bool in
            guard let localizedCountryName = localizedString(forRegionCode: code) else {
                return false
            }
            return localizedCountryName.lowercased() == countryName.lowercased()
        })
    }
}

To use:

let locale = Locale(identifier: "en_US")
let countryCode = locale.countryCode(by: "Russia")
Martin Brisiak
  • 3,872
  • 12
  • 37
  • 51
T_Anton_T
  • 11
  • 1
  • 4