Set device language as locale? - ios

In one of my localized apps, Spanish is the default language. However, the user could have set English as default language, and its region to to "Spain".
The problem is that within my app I use this code:
int day = (60*60*24);
NSDate *nextNextDay = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*2)];
NSString *someString = [[dateFormatter stringFromDate:nextNextDay] capitalizedString];
NSLog(#"The day: %#", someString);
The result is the name of the day in the default locale, which is (in this scenario) spanish. So, instead of that I would get "Monday" as result, I will get "Lunes" instead. This, of course, is very ugly when the rest of the app is in English.
How can I solve this without hard-coding any locales?

Why not hardcode locales?
You could do this:
NSString *userLocale = [[NSLocale currentLocale]localeIdentifier];
NSString *userLanguage = [userLocale substringToIndex:2];
if([userLanguage isEqualToString:#"en"]){
//English
}
if([userLanguage isEqualToString:#"es"]){
//Spanish
}
Hope this helped

Related

Word delimiter for given locale

How do I know if a language NSLocale uses spaces for delimiting words in a sentence (like English or other roman languages) or not (like Japanese)?
I expected to find this information under NSLocale Component Keys … no. Any idea? Do I really need to set my own dictionary for this. I'd appreciate any advice or related resource.
You can use NSLocal Components keys' NSLocaleExemplarCharacterSet to get the set of character in that language and then see if space is part of that language character set
NSLocale *jpLocale = [[NSLocal alloc] initWithLocalDentifier: #"ja_JP"];
NSCharacterSet *jpCharSet = (NSCharacterSet *)[jpLocale objectForKey: NSLocaleExemplarCharacterSet];
[jpCharSet characterIsMember: ' '] ? NSLog("Yeah it uses space"); : NSLog("Nope");
I still haven't found a great solution. As a workaround I am checking for spaces in fullStyle strings from a random date using the NSDateFormatter
NSDate* exampleDate = [NSDate dateWithTimeIntervalSince1970:0];
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.locale = [NSLocale currentLocale];
dateFormatter.dateStyle = NSDateFormatterFullStyle;
NSString *testString = [dateFormatter stringFromDate:exampleDate];
BOOL localeLikelyUsesSpaceAsDelimitters = [testString rangeOfString:#" "].location == NSNotFound;
Better ideas?

how to convert india number to arabic number?

i'm trying to make calls from my app, but it seems i can't because the numbers are in india format (example : ٩٦٦٥٩٥٨٤٨٨٨٢) and to make it work , I have to convert this string to arabic format (example : 966595848882)
my code :
NSString *cleanedString = [[ContactInfo componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:#"0123456789-+()"] invertedSet]] componentsJoinedByString:#""];
NSString *phoneNumber = [#"telprompt://" stringByAppendingString:cleanedString];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
Use NSNumberFormatter with the appropriate locale. For example:
NSString *indianNumberString = #"٩٦٦٥٩٥٨٤٨٨٨٢";
NSNumberFormatter *nf1 = [[NSNumberFormatter alloc] init];
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"hi_IN"];
[nf1 setLocale:locale];
NSNumber *newNum = [nf1 numberFromString:indianNumberString];
NSLog(#"new: %#", newNum);
This prints "966595848882".
I'm not 100% certain on the locale identifier above-- hi_IN should be "Hindi India". If that's not correct, use [NSLocale availableLocaleIdentifiers] to get a list of all known locale identifiers, and find one that's more appropriate.
Update: in order to pad this out to nine digits (or however many you want), convert back to an NSString using standard NSString formatting:
NSString *paddedString = [NSString stringWithFormat:#"%09ld", [newNum integerValue]];
The format %09ld will zero-pad out to nine digits.
It's also possible to do this using the same number formatter, converting the number above back into a string while requiring 9 digits. This also gives at least nine digits, with zero padding if necessary:
[nf1 setMinimumIntegerDigits:9];
NSString *reverseConvert = [nf1 stringFromNumber:newNum];

Get iOS current language (including country code)

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?
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);
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;
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]);
}
Swift
NSLocale.preferredLanguages()[0] as String
Output would be like
en-GB
Source
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))
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];
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

NSLocale Language Issue

So in my app I am trying to get the devices currently set language and its acronym. So I do this:
NSString *fullLanguage = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[[NSLocale preferredLanguages] objectAtIndex:0]];
NSString *abrlanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
However some users report that the language is returning something like: en_UK or something similar, which in turn is messing up the functionality of my app.
Anyway is there a way to get the currently set language of the device regardless if the devices regional settings?
Thanks!
To get the language code, use:
NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
NSLog(#"%#", languageCode); // Prints "en"
To get the full name of the language:
NSString *languageName = [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:languageCode];
NSLog(#"%#", languageName); // Prints "English"
Note that you were using the region code (which provides for regional variations of languages), and could be gotten easier like this:
NSString *regionCode = [[NSLocale currentLocale] objectForKey:NSLocaleIdentifier];
NSLog(#"%#", regionCode); // Prints "en_US"
Region codes start with the language code, followed by the underscore, and then the regional variation. (This is standardized per Apple's documentation.)
Also, if you use currentLocale, know that it is not updated as the users preferences are changed. Use autoupdatingCurrentLocale instead if you want to keep it in sync if they change.

Get Currency Symbol and Currency Code based on ISOCountryCode

There are similar questions to this one from newbies like me in localization, but I couldn't find one that does the trick for me.
Here is my problem. We can get all the ISO country codes in an NSArray with a statement of the form [NSLocale ISOCountryCodes]. Now, for each and every country of those I would like to print the local currency as well as the currency code used in that country. What would be the appropriate way of doing this?
I did the following that does not work in the sense that I get lines of the form
US United States: (null) ((null))
when instead I would like to get lines of the form
US United States: $ (USD):
myCountryCode = [[NSLocale ISOCountryCodes] objectAtIndex:row];
appLocale = [[NSLocale alloc] initWithLocaleIdentifier: #"en_US"];
identifier = [NSLocale localeIdentifierFromComponents: [NSDictionary
dictionaryWithObject: myCountryCode
forKey: NSLocaleCountryCode]];
myDictionary = [NSLocale componentsFromLocaleIdentifier: identifier];
myCountryName = [appLocale displayNameForKey:NSLocaleCountryCode
value:[myDictionary
objectForKey:NSLocaleCountryCode]];
localCurrencySymbol = [appLocale displayNameForKey:NSLocaleCurrencySymbol
value:[myDictionary objectForKey:NSLocaleCurrencySymbol]];
currencyCode = [appLocale displayNameForKey:NSLocaleCurrencyCode
value: [myDictionary objectForKey:NSLocaleCurrencyCode]];
title = [NSString stringWithFormat:#"%# %#: %# (%#)", myCountryCode, myCountryName, localCurrencySymbol, currencyCode];
[appLocale release];
(Above identifier, myCountryCode, myCountryName, localCurrencySymbol, currencyCode, and title are all NSString pointers. Moreover myDictionary is an NSDictionary pointer and appLocale is an NSLocale pointer). Essentially the above code will be in a pickerview where I want to generate the title of each line on the fly.
Thank you very much for your time. Essentially the question is once we have the ISO country code how can we print (in the application locale) the currency symbol and the currency code for that specific country.
For anyone just wanting to get the currency code from the 3 letter iso code ( commonISOCurrencyCodes ). You can simply do this.
NSString *localeId = #"JPY"; //[[NSLocale commonISOCurrencyCodes] objectAtIndex:1];
NSLocale *locale = [NSLocale currentLocale];
NSString *currency = [locale displayNameForKey:NSLocaleCurrencySymbol
value:localeId];
NSLog(#"locale %# currency %#", localeId, currency);
Prints.
locale JPY currency ¥
Try the following test app and adapt as needed
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
// select an arbitrary locale identifier; you could use your row index but your
// indexing scheme would be different
NSString *localeIdentifier = [[NSLocale availableLocaleIdentifiers] objectAtIndex:72];
// get the selected locale and the application locale
NSLocale *selectedLocale = [[NSLocale alloc] initWithLocaleIdentifier:localeIdentifier];
NSLocale *appLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
// country code and name (in app's locale)
NSString *countryCode = [selectedLocale objectForKey:NSLocaleCountryCode];
NSString *countryName = [appLocale displayNameForKey:NSLocaleCountryCode value:countryCode];
// symbol and currency code
NSString *localCurrencySymbol = [selectedLocale objectForKey:NSLocaleCurrencySymbol];
NSString *currencyCode = [selectedLocale objectForKey:NSLocaleCurrencyCode];
NSString *title = [NSString stringWithFormat:#"%# %#: %# (%#)", countryCode, countryName, localCurrencySymbol, currencyCode];
[appLocale release];
NSLog(#"title = %#",title);
[p release];
}
This logs the following to the console:
2012-06-09 06:01:08.299 Untitled 2[11668:707] title = ES Spain: € (EUR)
I think your problem here is that you are expecting that componentsFromLocaleIdentifer will return information about the locale. Instead, it returns information about the string that is passed in as the identifier. Although you can receive NSLocalCurrencySymbol, it will only be present when the string that you are passing in has an override for the particular currency (which will never happen in your case, since you are only using the standard array). An example of this in the wild would be a user who has set up a FR system, but with a USD currency.
Generally, you shouldn't need to use -displayNameForKey:value: for the NSLocaleCurrencyCode and NSLocaleCurrencySymbol, since they both return international strings, not localized strings. Thus, once you have the preferred local, you should be able to get this information just by using -objectForKey:.
The tricky part, in my testing, is that assuming that the locale in the list is sufficient to create a valid currency code and symbol isn't true, instead you need to have a language and country code. Fortunately, +[NSLocale canonicalLanguageIdentifierFromString:] will provide you the right language, which you can then append to the country code (after a _) to create the country/language string that will appropriately result in the currency information being retrieved.
Here's my revised code:
myCountryCode = [[NSLocale ISOCountryCodes] objectAtIndex:row];
appLocale = [[NSLocale alloc] initWithLocaleIdentifier: #"en_US"];
identifier = [NSLocale localeIdentifierFromComponents: [NSDictionary
dictionaryWithObject: myCountryCode
forKey: NSLocaleCountryCode]];
myDictionary = [NSLocale componentsFromLocaleIdentifier: identifier];
myCountryName = [appLocale displayNameForKey:NSLocaleCountryCode
value:[myDictionaryobjectForKey:NSLocaleCountryCode]];
// Create the currency language combination and then make our locale
NSString *currencyLocaleLanguage= [NSLocale canonicalLanguageIdentifierFromString: myCountryCode];
NSString *countryLanguage= [NSString stringWithFormat: #"%#_%#", myCountryCode, currencyLocaleLanguage];
NSLocale *currencyLocale = [[NSLocale alloc] initWithLocaleIdentifier: countryLanguage];
localCurrencySymbol = [currencyLocale objectForKey:NSLocaleCurrencySymbol];
currencyCode = [currencyLocale objectForKey:NSLocaleCurrencyCode];
title = [NSString stringWithFormat:#"%# %#: %# (%#)", myCountryCode, myCountryName, localCurrencySymbol, currencyCode];
[currencyLocale release];
[appLocale release];

Resources