11

I need to get a string like en_US or es_ES in iOS.

The obvious method is to use [NSLocale currentLocale] and get the language info from there. However, that gives you the "region format" and not the actual device language, which means that if you have the device language in english but the region format as "spain", it'll erroneously report es_ES.

If you need the device language you must do this instead: [[NSLocale preferredLanguages] objectAtIndex:0]

However, that only gives you the language, so you get something like en or es, without the country code at the end.

How would I get the country code correctly, like Safari does?

hasvn
  • 1,054
  • 1
  • 11
  • 15

7 Answers7

3

Try with this code:

NSString *locale = [[NSLocale currentLocale] localeIdentifier];
NSRange startRange = [locale rangeOfString:@"_"];
NSString *result = [locale stringByReplacingCharactersInRange:NSMakeRange(0, startRange.length+1) withString:[[NSLocale preferredLanguages] objectAtIndex:0]];
DebugLog(@"current locale: %@", result);
Manuel Escrig
  • 2,825
  • 1
  • 27
  • 36
  • As I explained in the question, the currentLocale doesn't return the language, but the region format. This means I can set up the device in English and the region format as Catalan(Spain), and then I'll get ca_ES even though the whole device is in English. Safari, however, returns en_US in that device, as it should. – hasvn Sep 09 '13 at 14:47
  • 1
    @hasvn I edit the answer, I don't know if that it is exactly what you are looking for. But it does shows the "language_region" I hope it helps! – Manuel Escrig Sep 09 '13 at 15:11
  • Nope, that combines your original answer with @null's, but that'd return "en_ES" in this case, instead of the logical "en_US" Safari returns :-\ – hasvn Sep 09 '13 at 15:23
2

Ok, seeing getting the right info out of iOS is probably not possible, here's a hackish solution but which gives the output I needed. It's not complete and it won't give precise output in some cases (like for arabic), but it's the best I've been able to get.

const string lang = [[[NSLocale preferredLanguages] objectAtIndex:0] UTF8String];

// Search the language with country code in the langs map
static std::map<string, string> langMap;
static bool initialized = false;
if(!initialized) {
    #define LANG(l, c) langMap.insert(std::make_pair(#l, #c))

    LANG(en, en-us); LANG(es, es-es); LANG(fr, fr-fr); LANG(de, de-de);
    LANG(ja, ja-jp); LANG(nl, nl-nl); LANG(it, it-it); LANG(pt, pt-br);
    LANG(da, da-dk); LANG(fi, fi-fi); LANG(nb, nb-no); LANG(sv, sv-se);
    LANG(ko, ko-kr); LANG(ru, ru-ru); LANG(pl, pl-pl); LANG(tr, tr-tr);
    LANG(uk, uk-ua); LANG(hr, hr-hr); LANG(cs, cs-cz); LANG(el, el-gr);
    LANG(he, he-il); LANG(ro, ro-ro); LANG(sk, sk-sk); LANG(th, th-th);
    LANG(ca, ca-es); LANG(hu, hu-hu); LANG(vi, vi-vn);
    LANG(zh-Hans, zh-cn); LANG(pt-PT, pt-pt); LANG(id, id); LANG(ms, ms);
    LANG(zh-Hant, zh-tw); LANG(en-GB, en-gb); LANG(ar, ar);

    #undef LANG
    initialized = true;
}

map<string,string>::iterator it = langMap.find(lang);
if( it != langMap.end() ){
    return it->second;
}

// Didn't find a country code, default to the lang name
return lang;
hasvn
  • 1,054
  • 1
  • 11
  • 15
1

Check the below code:

NSArray *langs = [NSLocale preferredLanguages];
for (NSString *lang in langs) {
     NSLog(@"%@: %@ %@",lang, [NSLocale canonicalLanguageIdentifierFromString:lang],    [[[NSLocale alloc] initWithLocaleIdentifier:lang] displayNameForKey:NSLocaleIdentifier value:lang]);
}
Tarek Hallak
  • 18,422
  • 7
  • 59
  • 68
  • 1
    That prints "en: en English", not "en_US" as I need. – hasvn Sep 09 '13 at 14:43
  • Dude [NSLocale canonicalLanguageIdentifierFromString:lang] prints `ar-QA` for me. double check. Try to set the lang `en_US` manually and check also. – Tarek Hallak Sep 09 '13 at 14:51
  • There are some regions for which it indeed displays the country, but for most it doesn't. Here's the complete list I get with your code: https://gist.github.com/JonValdes/c9ff4e7b09d10222e9d1 As you can see, most locales don't show the country code. – hasvn Sep 09 '13 at 15:20
  • Sorry man but I think this is the maximum you can get from iOS. – Tarek Hallak Sep 09 '13 at 15:27
1

Swift

NSLocale.preferredLanguages()[0] as String

Output would be like

en-GB

Source

Community
  • 1
  • 1
Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
1

An alternative would be to reconstruct the locale from the components of the current locale, swapping in the language that you want.

For example, to get the current locale but modified to use the language which UIKit is currently using to display the app:

let languageCode = Bundle.main.preferredLocalizations.first ?? "en"
var components = Locale.components(fromIdentifier: Locale.current.identifier)
components[NSLocale.Key.languageCode.rawValue] = languageCode
let locale = Locale(identifier: Locale.identifier(fromComponents: components))
Manav
  • 10,094
  • 6
  • 44
  • 51
0

I am using this at the moment. I have run a few test cases and it seems ok, However I am not convinced that it is a robust solution. I am surprised not to find a clear answer to this simple problem. I would not recommend my solution but I hope it can generate discussion.

NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey: NSLocaleCountryCode];

NSString *language = [[NSLocale preferredLanguages] firstObject];
NSString *myLocale = [NSString stringWithFormat:@"%@_%@",language,countryCode];
NSLocale *userLocale = [[NSLocale alloc] initWithLocaleIdentifier:myLocale];

NSDate* now = [NSDate date];

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSString *dateFormat = [NSDateFormatter dateFormatFromTemplate:@"E MMM d yyyy HH:mm" options:0 locale:userLocale];
Ryan Heitner
  • 13,119
  • 6
  • 77
  • 119
0

Simply do this:

NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *locale = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];

NSString *formattedStr = [NSString stringWithFormat:@"%@_%@",language, locale];
NSLog(@"%@", formattedStr); // Display en_US for example
Lapinou
  • 1,467
  • 2
  • 20
  • 39