Get currency symbol from currency codes in Objective-C - ios

I'm having trouble getting the currency symbol (e.g. '$') out of currency codes (e.g. 'USD').
I'm currently trying this way:
NSString *code = [NSLocale ISOCurrencyCodes][indexPath.row];
NSLog(#"%#", [[NSLocale currentLocale] displayNameForKey:NSLocaleCurrencySymbol value:code]);
Receiving (null) as result... Looking for the correct way to get the currency symbol from currency codes.
Even though I haven't seen the result yet, I'm pretty sure this will give repeated entries (Euro zone countries for example will be repeated, and will end up with many different '€' symbols). Is there a better approach to this problem?
EDIT: I'm not having problems with NSNumberFormatter, what I need is a list of all currencies supported in iOS for the user to select one (I will handle the formatting of the correct currency with the NSNumberFormatter, not having trouble with that).
Thanks

I can't reproduce your issue. The following works fine:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
for (NSString *code in [NSLocale ISOCurrencyCodes]) {
NSLog(#"%# -> %#", code, [[NSLocale currentLocale] displayNameForKey:NSLocaleCurrencySymbol value:code]);
}
}
return 0;
}
I suspect that your problem is that indexPath.row isn't what you expect it to be.
You shouldn't expect many duplicates (if any). The list of currency codes doesn't list countries; it lists currencies. So there's just one EUR which maps to €. On my system, all but two resolve (EQE and LSM which are discontinued currencies).
Keep in mind that there are 299 different currencies in the list I'm looking at, so your pick list may be much longer than you're thinking.

I don't know if you've figured this out already.
I've had similar issues running on the emulator, but not a device. If you're running on the emulator, see if manually setting the language and region helps. I've noticed this is specific to when your scheme is relying on "System Language" and "System Region". If I manually set the language to "English" and region to "United States" that it can determine the currency symbols again.
Steps to do so:
Click on your scheme -> click "edit scheme" -> make sure you've selected the run option in the side bar -> "Options" -> Application Language and Application Region set to not defaults system.
Let me know if this helps.

Related

How to always get english string from NSError?

I've got an iOS application that is designed with English-only strings. When running on an iOS device that is using another language for display (i.e. Settings/General/Language/iPhoneLanguage is something non-English) I would like to also show system errors in English since my font can't display non-english characters at the moment.
Is there a way to always get the english error message from NSError? Or to lookup the english error string in the system somehow manually?
After digging around I found a potential workaround.
First, it turns out that in most cases, iOS is returning English strings from [myNSError localizedDescription] when I'm running on a system that has the region set to, say, France, with the language set to, say, French. I believe this is because I have CFBundleDevelopmentRegion set to "en" in my info.plist. This is what I wanted to happen since I am trying to build an app that runs fully in English everywhere (for the moment).
However, in some cases, like if you try to buy something in the app and the network is off (this is my most reliable repro case), I will get NSErrors that return a localized error from [myNSError localizedDescription]. In this case: "Connexion à l’iTunes Store impossible."
When I get an error like this, a workaround that kinda works is to create an NSError manually using the domain and error code from the original. If you then ask it for the localizedDescription it will give you one in English, but it seems to be more general. In this case: "The operation couldn’t be completed.". What appears to be happening is that the system is filling in more detailed errors using the local language.
string GetEnglishLocalizedDescription(NSError *originalError)
{
if(originalError == nil)
{
return "";
}
else
{
NSString *originalNSErrorString = [originalError localizedDescription];
string originalUtf8String = originalNSErrorString == nil ? "" : [originalNSErrorString UTF8String];
// If we have a character outside of the US Ascii range
// Our font won't display it properly and this is probably
// a localized description
// https://tools.ietf.org/html/rfc3629
bool isUSAscii = true;
for(uint8_t c : originalUtf8String)
{
if(c > 0x7F)
{
isUSAscii = false;
break;
}
}
if(!isUSAscii)
{
// Has non-US Ascii characters, probably localized, get the standard error instead
NSString *englishNSErrorString = [[NSError errorWithDomain:originalError.domain code:originalError.code userInfo:nil] localizedDescription];
string englishUtf8String = englishNSErrorString == nil ? "" : [englishNSErrorString UTF8String];
return englishUtf8String;
}
else
{
return originalUtf8String;
}
}
}
Then, the trick is to figure out when you want to do this because you can't really tell in an obvious way that you got an error in the local language. In my case, I can just look for characters that my font can't display and convert it. If my font can display it, I guess I'm OK displaying it since either:
a) it is in english and the whole app is so nothing surprising or
b) it is actually localized just happens to be a string that has characters that are all also English characters. In this case, presumably the user will be able to read it in their local language.
One final gotcha using the code/algorithm above: It turns out the English error messages that Apple uses don't stick to the normal ASCII character set. They will use the fancy apostrophe in Unicode as opposed to the ASCII "'". So, the code above will think that is a "localized" message. Unclear what other characters they do this with. So this isn't really a full solution. It does solve the original question of "How do I always retrieve an English error message", but it doesn't fully solve my problem since i have no idea how to build a font that will even show all English error messages. Sigh.
Still have to decide the best approach here, but it is something.

Determine country code for iOS Region "Europe"

I am working on an app which asks users for phone number and has a country picker, where the user should input country code.
But while testing null country code values, I found out that somehow my iPhone with iOS 10.2.1 has a region format set to Europe.
The Europe region does not exist in the regions list when I search for it.
When I try to get the current locale country code
NSLocale *currentLocale = [NSLocale currentLocale];
return [currentLocale objectForKey:NSLocaleCountryCode]
I get en_150 which is not useful to determine user's country, at least on my device. Returned country code is 150, which does not exist.
I found a workaround to find to country code by using CTTelephonyNetworkInfo
if(![currentLocale objectForKey:NSLocaleCountryCode]) {
CTCarrier *carrier = [[CTTelephonyNetworkInfo new] subscriberCellularProvider];
NSString *countryCode = carrier.isoCountryCode;
return [countryCode capitalizedString];
}
But how does it work with this Europe locale and why do I have it set like this?
First of all, Europe is a continent not a country. It doesn’t have a country code. It does, however, have a region code. That region code is indeed 150.
Continents have numeric area codes instead including 001 for “World” and 150 for “Europe”.
Be sure to read my article “Are there standard language codes for ‘World English’ and ‘European English’” for a much more detailed explanation. These codes are based in UN M.49, which is the basis for ISO 3166, which is the standard you’re probably thinking of when you say “country codes”.
The problem you’re facing is that you can’t use someone’s language or formatting preferences to determine their physical location. My current device’s locale is en_DK but my physical location is NO. Many devices default to en_US and users all over the world never change the default settings.
Please use CoreLocation to automatically determine the user’s location, or just ask the user to disclose their location.

Which NSLocale to use with uppercaseStringWithLocale:?

When I have an UI string with capital letters, i'm used to define them in lowercase as for all the others, and then to use uppercaseStringWithLocale:[NSLocale currentLocale].
But recently I happened to notice that the [NSLocale currentLocale] may not be the one used in your app. For example if your device is in Turkish but your app only support english, the currentLocale would be a Turkish locale while your app is localized in english.
With those settings, a direct effect of using [NSLocale currentLocale] is that my uppercaseString will be "İ LİKE İOS" instead of "I LIKE IOS".
So far, the only workaround I see is to create a category of NSLocale to add a +(NSLocale*) applicationLocale; and use it in all uppercaseStringWithLocale:.
+ (NSLocale*) applicationLocale
{
NSMutableDictionary<NSString*,NSString*>* localeComponents = [[NSLocale componentsFromLocaleIdentifier:[NSLocale currentLocale].localeIdentifier] mutableCopy];
localeComponents[NSLocaleLanguageCode] = NSBundle.mainBundle.preferredLocalizations.firstObject;
return [NSLocale localeWithLocaleIdentifier:[NSLocale localeIdentifierFromComponents:localeComponents]];
}
My question is simple: am I doing this the right way or did I miss something? I indeed wonder why Apple links to currentLocale while it won't work as expected in a lot of cases.
The most robust way to get the application locale is to edit your Localizable.strings files. In the English localization file add an entry
"lang"="en";
in the German localization file add an entry
"lang"="de";
in the French localization file add an entry
"lang"="fr";
and so on... You can get the localization code with NSLocalizedString(#"lang").

Localizing iPhone app for Region

I've got an app that has all content regardless of language displaying content in English. In the products section of the app product content is displayed based on a plist. Products available for purchased are based on location, not all products are available in every market.
In the settings of my simulator I've got my language set to English and my Region Format set to Singapore.
Above my loading of the plist which has been localized, I first do a log to check that I am in fact seeing SG (Singapore) as my region.
NSString *locale = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];
NSLog(#"LOCALE: %#", locale);
if([locale isEqualToString:#"SG"]){
NSLog(#"singapore do something?");
productCategory = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:#"Products" ofType:#"plist"]];
}
The current result is showing my log statement logging LOCALE: SG which is expected, however my Singapore specific content is not loading.
I have tried both cleaning the project, and deleting the app from the simulator.
This is how my plist files appear in my project navigator
What am I doing incorrectly that is preventing my localized plist from being displayed?
Localization (the process of loading translated resources from the relevant language folders in your application bundle) is based exclusively on the language setting. So pathForResource only cares about the language setting and ignores the region format setting.
The region format setting affects the conversion between strings and locale-dependent data types (in both directions: parsing input and formatting output). For example if you convert a NSDate to a string for display, depending on the region format setting you might get the month before the day (as in the US) or the opposite (as in the UK).
[NSLocale currentLocale] refers to the region format, so you were simply looking at the wrong thing in your debugging.
There is plenty more info on this here: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPInternational/BPInternational.html#//apple_ref/doc/uid/10000171i
Edit
See the comments below, this appears to be more complex. It looks like Region does affect localisation when the language is set to a neutral language (e.g. "en" but not "en-US").
I had once the same problem, somehow a non-localized file was found. What worked for me was to use:
[[NSBundle mainBundle] pathForResource:#"Products" ofType:#"plist" inDirectory:nil]
This will always search for all localized files and return the correct one based on the users settings

NSLocaleUsesMetricSystem always YES on iPad

I am trying to decide if the users Region/Locale settings validates the use of Metric values (in this case if kg or lb should be appended).
I am running 3.2 on my iPad and on the simulator(Xcode 3.2.4).
I have tried out a few different Region settings but I simply can not make it return NO for NSLocaleUsesMetricSystem
NSLocale *locale = [NSLocale systemLocale];
BOOL usesMetric = [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue];
NSLog(#"The system is Metric: %#\n", (usesMetric ? #"YES" : #"NO"));
This even happens for language set to English and region set to United States on both the simulator and on the actual device.
I also tried NSLocaleMeasurementSystem and it too always returns "Metric", never "U.S.".
How will I go about deciding if I should use Metric or not?
Thanks for any help given:)
...could I be so lucky that the whole world changed to metric while I was sleeping:)
Try currentLocale instead of systemLocale
Had the same problem, until I realized, that UK officially uses metric system. I have always thought that they still use imperial, so I tested with UK.
As soon as I started to test US locale, NSLocaleUsesMetricSystem started to return "NO" as expected.
Hope this helps.

Resources