iOS wrong localization - ios

I have an iOS application that is localized in multiple languages. I have Localizable.strings files for English, Dutch and Dutch (Belgium). The problem is that when Dutch is set as the device language and Belgium as the country, the Dutch strings are used and NOT the Dutch-Belgium strings.
I've added some logging to make sure that the correct language is set on the device, and it appears to be correct:
NSLocale *locale = [NSLocale currentLocale];
NSString *language = [locale displayNameForKey:NSLocaleIdentifier
value:[locale localeIdentifier]];
NSLog(#"language %#", language);
This prints out
2015-04-09 11:49:26.227 MyTestApp[222:7459] language Nederlands (België)
But if I try to get a string using NSLocalizedString I get the Dutch resource, not the Dutch Belgium one.
I've tested this on an iPhone 5s running 8.1 and on several 7.1/8.1 simulators and I can't get it to work. The interesting thing is that if I forcefully set the language to Dutch (Belgium) in XCode under Edit Scheme -> Application Language, the correct language is used.

It turns out that the problem is that Xcode creates resource folders for each language with a hyphen separating the language and region, e.g. nl-BE.proj. However, the locale code uses an underscore, e.g. nl_BE, so the region is never matched. This appears to be an XCode bug.
The solution is to change the locale so that it includes a hyphen as discussed here https://stackoverflow.com/a/14357315/416214

Related

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").

localizedStringForKey:value:table: with CFBundleDevelopmentRegion

I have the following:
And the CFBundleDevelopmentRegion is set as "en" in the Info.plist:
The default language is english and has all the strings. The swedish and french version are not complete and I want to fallback in english when a string is not localized in fr or sv.
Here's how I translate:
translatedContent = [[NSBundle mainBundle] localizedStringForKey:translationKey
value:nil
table:#"Localizable"];
When the device is in english, everything is fine.
However, when the device is in swedish or french, it works but the translation does not fallback to english if the key is not present in the sv/fr file. Instead, it fallbacks to the translation key.
I can't figure out what is wrong. Any thoughts?

localizedStringForKey:value:table ignores Base localization

My application need to be localised in 2 languages: German and English. German should be Base language. It means that app should always localize to German except the language on device is english (in this case it should be on english)
I have custom *.string files for localisation and use localizedStringForKey:value:table to localise strings.
When I have only base localisation everything works fine. But in case if I add english localisation, in some reason localizedStringForKey:value:table just ignore Base localisation and always use English (for all languages)
Here how it looks like after I've added english:
and here is how I localise strings:
[[NSBundle mainBundle] localizedStringForKey:#"key" value:#"" table:#"Shared"]
I'm testing on simulator and here is my language screen:
Does anybody know what could be a problem? Thanks in advance!
As I mentioned in the comments, you need to set the Localization native development region (CFBundleDevelopmentRegion) in the Info.plist to your language code. Xcode seems to set it to a en_GB or de_DE style region code, setting it to de (no region) will fix it. Note that by default it is en, but selecting United Kingdom or Germany will change it to use the longer codes.
I have another solution, I think it works for you:
NSString* NSCustomLocalizedString( NSString *key , NSString *comment)
{
NSString *rs = nil;
if( [[NSUserDefaults standardUserDefaults] integerForKey:KEY_LANGUAGE ] == e_language_japanese)
{
rs = NSLocalizedStringFromTable(key,#"Localizable.strings-ja",nil);
}
else
{
rs = NSLocalizedStringFromTable(key,#"Localizable.strings-en",nil);
}
return rs;
}

Finding the current localization of iOS app in code

Connected issue: Non-English default language for iOS App?
I am wondering how to check the current localization of my app in code.
For example:
I want to check if the app is running with German localization (.strings, storyboard)
This line of code:
[[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:#"de"]
doesn't provide the correct answer. Because if a user's language list in device settings looks like this for example (french, german, english) and we have only localization for english and german, application is launched in german but the above condition isn't fulfilled.
My naive solution would be to create a localized string "LanguageCode" which is set to "de" in the german string file and to "en" in the english string file
e.g.:
if ([NSLocalizedString(#"LanguageCode", #"en, de etc.") isEqualToString:#"de"]) {
// german
}
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
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):
Check the first entry of Bundle's preferredLocalizations property, which is:
an array of NSString objects containing language IDs for localizations
in the bundle. The strings are ordered according to the user's
language preferences and available localizations.
For example, if you're checking to see if your German localization are being used:
if Bundle.main.preferredLocalizations.first == "de" {
// Is using German
}

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

Resources