How to convert two letter currency code to base locale identifier on IOS - identifier

I need to convert my two letter country code, to its default, native, identifier, e.g. TW > zh_TW not en_TW. US > en_US. RU > ru_RU, not en_RU. IT isn't justg the same two letters repeated. Note, I need to do this from the COUNTRY code, not the language code. Is there a simple way, using NSLocale, or do I have to have a big list !?
Thanks
Shaun Southern

NSString *countryCode = #"IE";
NSDictionary *components = [NSDictionary dictionaryWithObject:countryCode forKey:NSLocaleCountryCode];
id localeIdent = [NSLocale localeIdentifierFromComponents:components];
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:localeIdent];

Related

How to determine if locale currency has a decimal point

Is there anyway in objective-c to determine if a currency uses a decimal point (regardless of declared NSNumber type)?
I have multiple locales and I use NSNumberFormatter (based on locale) to set string currency string style, however before-hand I would like to know if the selected locale currency uses a decimal point.
[_cf setLocale:
[NSLocale localeWithLocaleIndentifier:[NSString stringWithFormat:#"%#",locale]]]];
[cf setNumberStyle:NSNUmberFormatterCurrencyStyle];
NSString *value = [cf stringFromNumber:price];
return value;
After creating the NSNumberFormatter with currency style, ask the formatter how many fraction digits it has.
NSInteger maxFractionDigits = cf.maximumFractionDigits;
if (maxFractionDigits == 0) {
// this currency is an integer, not a decimal
}
One example where this is true is the Japanese Yen (¥).

NSLocale Country Code and Name is Null

I am using the below code for Code and Country name but it returns null.
NSLocale *locale = [NSLocale currentLocale];
NSString *countryCode = [locale objectForKey: NSLocaleCountryCode];
NSString *country = [locale displayNameForKey: NSLocaleCountryCode value: countryCode];
NSLog(#"Language : %# Lang2 : %#",[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0],[[NSLocale preferredLanguages] objectAtIndex:0]);
NSLog(#"Locale:%# Code:%# Name%#:", locale, countryCode, country);
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
fr,
de,
nl,
ja,
es,
tr,
it,
pl,
pt,
);
Logs : Locale:<__NSCFLocale: 0x7fbef943f810> Code:(null) Name(null)
Language : nl Lang2 : nl
Tested both on device and simulator.i don't know whats going on here.It should work fine.Please let me know if you guys have any idea.i am using xcode 6.4.
Finally found the bugger.
I tested the above code in another test project and was working fine but not in my current project.
So i used the developer tool FileMerge and compared the two and found a difference in the below line.(xcshareddata->xcschemes->****.xcscheme).
I don't know how the language = "nl" got there may be due to a bad merge but rolling back and re-merge didn't work either.
Manually removing the line solved my Ghostly Problem :)

iOS Currency input field

I would like to have a currency input field in my app where the user can either include the currency symbol (as appropriate for their locale), or not, as they please.
I have a text field set up and I am storing the value in a NSDecimalNumber (which I understand is the recommended way to store currency).
The following code will get me from an NSDecimalNumber to a formatted currency string:
[NSNumberFormatter localizedStringFromNumber:currencyValue numberStyle:NSNumberFormatterCurrencyStyle]
But I can't find a way to do the reverse of that. i.e., take the string that the user has typed into my text field and convert it (if possible) into an NSDecimalNumber. Keeping in mind that the currency symbol may be there (because it came from the function above) or not (because the user didn't bother to type the currency symbol).
What am I missing?
If I can't figure this out I will just not accept any currency symbol at all (i.e., just parse it using the code below). But it seems better to allow the currency symbol.
[NSDecimalNumber decimalNumberWithString:currencyString locale:[NSLocale currentLocale]]
I have the feeling I am missing something. What's the right way to convert back and forth between a localized currency string and an NSDecimalNumber?
If you get an instance of an NSNumberFormatter (instead of using the static method call) you can use the NSNumberFormatter's "stringFromNumber" method to format the currency string and use "numberFromString" to parse that string back into a number.
https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html
If you are sure that the currency symbol, if it exists, will be at the beginning of the string, then you can just use this (string is the NSString that the user enters and number is the NSDecimalNumber that represents the value of the currency)
NSDecimalNumber *number;
if([string hasPrefix:#"0"] || [string hasPrefix:#"1"] || [string hasPrefix:#"2"] || [string hasPrefix:#"3"] || [string hasPrefix:#"4"] || [string hasPrefix:#"5"] || [string hasPrefix:#"6"] || [string hasPrefix:#"7"] || [string hasPrefix:#"8"] || [string hasPrefix:#"9"]) {
// The string does not contain a currency symbol in the beginning so we can just assign that to a NSDecimalNumber
number = [NSDecimalNumber decimalNumberWithString:string];
}
else {
// The string contains a currency symbol at the beginning and we will assign the currency symbol to the currencySymbol variable
NSString *currencySymbol;
currencySymbol = [string substringWithRange:NSMakeRange(0,1)];
number = [NSDecimalNumber decimalNumberWithString:[string stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:#""];
}
This should do the trick:
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setLenient:YES];
NSString* input = #"$3,456.78";
NSNumber *number = [currencyFormatter numberFromString:input];
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithDecimal:[number decimalValue]];

Native iOS Language Translated String and its Language Code Identification (LCID)

How does iOS Show the List of Languages in the Translated String or in the Language's Locale.
Is there an LCID associated with it?
If so, where can I find it's Mapping?
How does it work?
Is there an API or any documentation you can point me towards?
I am attaching a screenshot of what I actually mean:
All I could find is this link
Update:
I want to achieve something like this:
Where I can map the Country with its Language, which is actually in its Locale. So is there an LCID Kind of a thing where I can map it and get that Locale string using the LCID using an iOS API?
Mockup is Below
You can get a list of languages translated in the languages locale with the following code:
Objective-C:
NSArray *languages = [NSLocale preferredLanguages];
for (NSString *lang in languages)
{
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:lang];
NSString *translated = [locale displayNameForKey:NSLocaleIdentifier value:lang];
NSLog(#"%#, %#", lang, translated);
}
Swift:
let languages = NSLocale.preferredLanguages()
for lang in languages {
let locale = NSLocale(localeIdentifier: lang)
let translated = locale.displayNameForKey(NSLocaleIdentifier, value: lang)!
print("\(lang), \(translated)")
}
Output:
en, English
fr, français
de, Deutsch
ja, 日本語
nl, Nederlands
...
I hope that this answers the first part of your question and perhaps helps with the second part.
Swift 3 update:
let languages = NSLocale.preferredLanguages
for lang in languages {
let locale = NSLocale(localeIdentifier: lang)
let translated = locale.displayName(forKey: NSLocale.Key.identifier, value: lang)!
print("\(lang), \(translated)")
}
LCIDs are a Windows concept. There is no such thing on iOS. Languages are generally identified by ISO 639-1 or 639-2 language codes.
From the way you frame your question, I think it would be best to start by reading Apple's internationalization and localization documentation. NSLocale is going to be your friend.

Getting current device language in iOS?

I'd like to show the current language that the device UI is using. What code would I use?
I want this as an NSString in fully spelled out format. (Not #"en_US")
EDIT: For those driving on by, there are a ton of useful comments here, as the answer has evolved with new iOS releases.
The solutions provided will actually return the current region of the device - not the currently selected language. These are often one and the same. However, if I am in North America and I set my language to Japanese, my region will still be English (United States). In order to retrieve the currently selected language, you can do:
NSString * language = [[NSLocale preferredLanguages] firstObject];
This will return a two letter code for the currently selected language. "en" for English, "es" for Spanish, "de" for German, etc. For more examples, please see this Wikipedia entry (in particular, the 639-1 column):
List of ISO 639-1 codes
Then it's a simple matter of converting the two letter codes to the string you would like to display. So if it's "en", display "English".
EDIT
Worth to quote the header information from NSLocale.h:
+ (NSArray *)preferredLanguages NS_AVAILABLE(10_5, 2_0); // note that this list does not indicate what language the app is actually running in; the [NSBundle mainBundle] object determines that at launch and knows that information
People interested in app language take a look at #mindvision's answer
The selected answer returns the current device language, but not the actual language used in the app. If you don't provide a localization in your app for the user's preferred language, the first localization available, ordered by the user's preferred order, is used.
To discover the current language selected within your localizations use
[[NSBundle mainBundle] preferredLocalizations];
Example:
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
Swift:
let language = NSBundle.mainBundle().preferredLocalizations.first as NSString
iOS13, Swift 5+
Locale.preferredLanguages.first
Solution for iOS 9:
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
language = "en-US"
NSDictionary *languageDic = [NSLocale componentsFromLocaleIdentifier:language];
languageDic will have the needed components
NSString *countryCode = [languageDic objectForKey:#"kCFLocaleCountryCodeKey"];
countryCode = "US"
NSString *languageCode = [languageDic objectForKey:#"kCFLocaleLanguageCodeKey"];
languageCode = "en"
This will probably give you what you want:
NSLocale *locale = [NSLocale currentLocale];
NSString *language = [locale displayNameForKey:NSLocaleIdentifier
value:[locale localeIdentifier]];
It will show the name of the language, in the language itself.
For example:
Français (France)
English (United States)
The accepted, and the other answers all don't take into account that the preferred language can be another language than the device language.
The device language is the language in which operating system elements and Apple apps are presented.
The preferred language is the language the user would like to have apps localized in. Apple only provides a limited set of translations. If the preferred language is one language Apple translated their apps to, it will also be the device language. However if the user prefers a language for which Apple doesn't provide translations the device and preferred languages won't match. The device language will not be on first position in the preferred languages list.
The following function will go through the preferred languages list and check if there is a translation in the Apple frameworks. The first language to have a translation is the device language. The function will return its language code.
func deviceLanguage() -> String? {
let systemBundle: NSBundle = NSBundle(forClass: UIView.self)
let englishLocale: NSLocale = NSLocale(localeIdentifier: "en")
let preferredLanguages: [String] = NSLocale.preferredLanguages()
for language: String in preferredLanguages {
let languageComponents: [String : String] = NSLocale.componentsFromLocaleIdentifier(language)
guard let languageCode: String = languageComponents[NSLocaleLanguageCode] else {
continue
}
// ex: es_MX.lproj, zh_CN.lproj
if let countryCode: String = languageComponents[NSLocaleCountryCode] {
if systemBundle.pathForResource("\(languageCode)_\(countryCode)", ofType: "lproj") != nil {
// returns language and country code because it appears that the actual language is coded within the country code aswell
// for example: zh_CN probably mandarin, zh_HK probably cantonese
return language
}
}
// ex: English.lproj, German.lproj
if let languageName: String = englishLocale.displayNameForKey(NSLocaleIdentifier, value: languageCode) {
if systemBundle.pathForResource(languageName, ofType: "lproj") != nil {
return languageCode
}
}
// ex: pt.lproj, hu.lproj
if systemBundle.pathForResource(languageCode, ofType: "lproj") != nil {
return languageCode
}
}
return nil
}
This works if the preferred language list is:
Afrikaans (iOS is not translated into Afrikaans)
Spanish (Device Language)
The preferred language list can be edited in: Settings.app -> General -> Language & Region -> Preferred Language Order
You can than use the device language code and translate it into the language name. The following lines will print the device language in the device language. For example "Español" if the device is set to spanish.
if let deviceLanguageCode: String = deviceLanguage() {
let printOutputLanguageCode: String = deviceLanguageCode
let printOutputLocale: NSLocale = NSLocale(localeIdentifier: printOutputLanguageCode)
if let deviceLanguageName: String = printOutputLocale.displayNameForKey(NSLocaleIdentifier, value: deviceLanguageCode) {
// keep in mind that for some localizations this will print a language and a country
// see deviceLanguage() implementation above
print(deviceLanguageName)
}
}
iOS13, Swift 5+, WWDC2019
https://developer.apple.com/videos/play/wwdc2019/403/
Users can select the preferred language of an app independently from the OS language.
You can use these:
// Returns a list of the user's preferred languages.
// Maybe more than (or none of) your app supports!
Locale.preferredLanguages
// a subset of this bundle's localizations, re-ordered into the preferred order
// for this process's current execution environment; the main bundle's preferred localizations
// indicate the language (of text) the user is most likely seeing in the UI
Bundle.main.preferredLocalizations
// The current running app language
Bundle.main.preferredLocalizations.first
// list of language names this bundle appears to be localized to
Bundle.main.localizations
i use this
NSArray *arr = [NSLocale preferredLanguages];
for (NSString *lan in arr) {
NSLog(#"%#: %# %#",lan, [NSLocale canonicalLanguageIdentifierFromString:lan], [[[NSLocale alloc] initWithLocaleIdentifier:lan] displayNameForKey:NSLocaleIdentifier value:lan]);
}
ignore memory leak..
and result is
2013-03-02 20:01:57.457 xx[12334:907] zh-Hans: zh-Hans 中文(简体中文)
2013-03-02 20:01:57.460 xx[12334:907] en: en English
2013-03-02 20:01:57.462 xx[12334:907] ja: ja 日本語
2013-03-02 20:01:57.465 xx[12334:907] fr: fr français
2013-03-02 20:01:57.468 xx[12334:907] de: de Deutsch
2013-03-02 20:01:57.472 xx[12334:907] nl: nl Nederlands
2013-03-02 20:01:57.477 xx[12334:907] it: it italiano
2013-03-02 20:01:57.481 xx[12334:907] es: es español
Translating language codes such as en_US into English (United States) is a built in feature of NSLocale and NSLocale does not care where you get the language codes from. So there really is no reason to implement your own translation as the accepted answer suggests.
// Example code - try changing the language codes and see what happens
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en"];
NSString *l1 = [locale displayNameForKey:NSLocaleIdentifier value:#"en"];
NSString *l2 = [locale displayNameForKey:NSLocaleIdentifier value:#"de"];
NSString *l3 = [locale displayNameForKey:NSLocaleIdentifier value:#"sv"];
NSLog(#"%#, %#, %#", l1, l2, l3);
Prints: English, German, Swedish
Even there's a better way to get current device language. Let's try it by below code -
NSLog(#"Current Language - %#", [[NSLocale preferredLanguages] firstObject]);
Suggested by Abizern on here
You can use the displayNameForKey:value: method of NSLocale:
// get a French locale instance
NSLocale *frLocale = [[[NSLocale alloc] initWithLocaleIdentifier:#"fr_FR"] autorelease];
// use it to get translated display names of fr_FR and en_US
NSLog(#"%#", [frLocale displayNameForKey:NSLocaleIdentifier value:#"fr_FR"]);
NSLog(#"%#", [frLocale displayNameForKey:NSLocaleIdentifier value:#"en_US"]);
This will print out:
français (France)
anglais (États-Unis)
If you specify the same locale identifier for the initWithLocaleIdentifier: and also the displayNameForKey:value: method, then it will give you the native name of the language. I've discovered that if you remove the country code and use just fr and en, that it will also omit the country from the display name (on Mac OS X at least, not sure about iOS).
I tried to found out the right solution for myself. When I use Locale.preferredLanguages.first was returned the preferred language from your app settings.
If you want get to know language from user device settings, you should the use string below:
Swift 3
let currentDeviceLanguage = Locale.current.languageCode
// Will return the optional String
To unwrap and use look at the line below:
if let currentDeviceLanguage = Locale.current.languageCode {
print("currentLanguage", currentDeviceLanguage)
// For example
if currentDeviceLanguage == "he" {
UIView.appearance().semanticContentAttribute = .forceRightToLeft
} else {
UIView.appearance().semanticContentAttribute = .forceLeftToRight
}
}
Swift
To get current language of device
NSLocale.preferredLanguages()[0] as String
To get application language
NSBundle.mainBundle().preferredLocalizations[0] as NSString
Note:
It fetches the language that you have given in CFBundleDevelopmentRegion of info.plist
if CFBundleAllowMixedLocalizations is true in info.plist then first item of CFBundleLocalizations in info.plist is returned
For getting user device current language use the following it code it worked for me.
NSString * myString = [[NSLocale preferredlanguage]objectAtIndex:0];
If you're looking for preferred language code ("en", "de", "es" ...), and localized preferred language name (for current locale), here's a simple extension in Swift:
extension Locale {
static var preferredLanguageIdentifier: String {
let id = Locale.preferredLanguages.first!
let comps = Locale.components(fromIdentifier: id)
return comps.values.first!
}
static var preferredLanguageLocalizedString: String {
let id = Locale.preferredLanguages.first!
return Locale.current.localizedString(forLanguageCode: id)!
}
}
For MonoTouch C# developers use:
NSLocale.PreferredLanguages.FirstOrDefault() ?? "en"
Note: I know this was an iOS question, but as I am a MonoTouch developer, the answer on this page led me in the right direction and I thought I'd share the results.
In Swift:
let languageCode = NSLocale.currentLocale().objectForKey(NSLocaleLanguageCode) as? String
Swift 3
let locale = Locale.current
let code = (locale as NSLocale).object(forKey: NSLocale.Key.countryCode) as! String?
print(code!)
Simple Swift 3 function:
#discardableResult
func getLanguageISO() -> String {
let locale = Locale.current
guard let languageCode = locale.languageCode,
let regionCode = locale.regionCode else {
return "de_DE"
}
return languageCode + "_" + regionCode
}
-(NSString *)returnPreferredLanguage { //as written text
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
NSArray *preferredLanguages = [defaults objectForKey:#"AppleLanguages"];
NSString *preferredLanguageCode = [preferredLanguages objectAtIndex:0]; //preferred device language code
NSLocale *enLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en"]; //language name will be in English (or whatever)
NSString *languageName = [enLocale displayNameForKey:NSLocaleIdentifier value:preferredLanguageCode]; //name of language, eg. "French"
return languageName;
}
If you want to get only language here is my suggested answer:
NSString *langplusreg = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString * langonly = [[langplusreg componentsSeparatedByString:#"-"]
objectAtIndex:0];
In my case i just wanted only Locale language not locale region.
Output:
If your Locale language is Japanese and locale region is Japan then:
langplusreg = ja-JP
langonly = ja
Obviously, the solutions relying, for example, on
[[NSLocale preferredLanguages] objectAtIndex:0]
usually work fine and return the current device language.
But it could be misleading in some cases :
If the app in which you want to get this value has already changed the language, for example with this kind of code :
NSString *lg = #"en"; // or anything like #"en", #"fr", etc.
[[NSUserDefaults standardUserDefaults]
setObject:[NSArray arrayWithObjects:lg, nil]
forKey:#"AppleLanguages"]
In this case, [NSLocale preferredLanguages] actually returns the preferred language set (and used) in this particular app, not the current device language !
And... in this case the only way to properly get the actual current device language (and not that previously set in the app), is to firstly clear the key #"appleLanguages" in NSUserDefaults, like this :
[[NSUserDefaults standardUserDefaults]removeObjectForKey:#"AppleLanguages"];
Then, [NSLocale preferredLanguages] now returns the correct value.
Hope this help.
In Swift 4.2 and Xcode 10.1
let language = NSLocale.preferredLanguages[0]
debugPrint(language)//en
In Swift 5.x
let langStr = Locale.current.languageCode
debugPrint(langStr ?? "") //en el
I actually misread the original question, thought it asked for the "app UI" language (that's what I had googled for), not the "device UI", in which case the best answers would be the ones using preferredLocalizations, but those answers still give you a code, there is one more step to get a nice string to display.
So, while the "device UI" language is already answered, if you want to display a nice string for which of the UI languages you support is currently in use, obviously the simplest solution is:
NSLocalizedString(#"currentLanguage", #"")
Where in every one of your UI localizations you have specified it exactly the way you want it shown. E.g. in the en version of your .strings file you'd have:
"currentLanguage"="English";
in your fr version of the .strings file you'd have:
"currentLanguage"="Francais";
etc. No messing with codes etc, you make your own strings to nicely match your UI.
SWIFT-4
// To get device default selected language. It will print like short name of zone. For english, en or spain, es.
let language = Bundle.main.preferredLocalizations.first! as NSString
print("device language",language)
#amir response in Swift :
// Get language prefered by user
let langageRegion = NSLocale.preferredLanguages().first!
let languageDic = NSLocale.componentsFromLocaleIdentifier(langageRegion)
let language = languageDic[NSLocaleLanguageCode]
According to Apple documentation
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:#"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];
Two letters format. Apple uses the ISO standard ISO-3166.
NSString *localeCountryCode = [[NSLocale autoupdatingCurrentLocale] objectForKey:NSLocaleCountryCode];
For Swift 3:
NSLocale.preferredLanguages[0] as String
As of iOS 9, if you just want the language code without country code, you'll want this sort of helper function - since the language will contain the country code.
// gets the language code without country code in uppercase format, i.e. EN or DE
NSString* GetLanguageCode()
{
static dispatch_once_t onceToken;
static NSString* lang;
dispatch_once(&onceToken, ^
{
lang = [[[NSLocale preferredLanguages] objectAtIndex:0] uppercaseString];
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"^[A-Za-z]+" options:0 error:nil];
NSTextCheckingResult* match = [regex firstMatchInString:lang options:0 range:NSMakeRange(0, lang.length)];
if (match.range.location != NSNotFound)
{
lang = [lang substringToIndex:match.range.length];
}
});
return lang;
}
Updated answer for Swift 4
let language = Bundle.main.preferredLocalizations.first

Resources