Manual language with correct NumberFormatter and localizedStringWithFormat - ios

I added a manual language section inside my iOS App where you can change the language the app should be displayed in. If someone chooses to select a manual language I override the "AppleLanguages" standardUserDefaults like so
NSString *language = [[[NSUserDefaults alloc] initWithSuiteName:kAppGroup] objectForKey:kManualLanguageKey];
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:language, nil]
forKey:#"AppleLanguages"];
Now when the user restarts the app (after terminating it) the App automatically loads the correct LocalizedStrings.
Now here is my problem:
even though this solves my problem of changing the language of the app it does not display numbers etc. correctly. Number/DateFormatter and localizedStringWithFormat depend on the [NSLocale currentLocale]. I know I could just overrite the current lokale as well like so
[[NSUserDefaults standardUserDefaults] setObject:language
forKey:#"AppleLocale"];
but then I can't get the real language/region selected in the system settings once the user decides to disable the manual language. I could store the currentLocale inside my own userDefaults before I override it but then if the user decides (for whatever reason) to change the system language while the manual language in the app is active I won't be able to get this new selected system language.
Is there any way to get the right format of Numbers and Dates without manually changing the locale property of NumberFormatter etc.?

Ok, I found a way to reset the current locale after the user disables the manual language on http://www.thetawelle.de/?p=3800
In main.m if the bool for manual language is false, I reset the current language like this:
NSArray *keysToRemove = #[#"AppleLanguages",#"NSLanguages",#"AppleLocale"];
NSLog( #"RESETTING TO USE SYSTEM LOCALE" );
#try {
for( NSString *currentKey in keysToRemove ) {
if( [defaults objectForKey:currentKey] ) {
[defaults removeObjectForKey:currentKey];
}
}
}
#catch (NSException *exception) {
// NOTHNG TO CATCH HERE
}
#finally {
[defaults synchronize];
}
after that, the current locale and language are back to the language and region selected in the system settings.

Related

Why is implementing a while statement in viewDidLoad not working? [duplicate]

I need to load user data, but I need to do it looped. (always loading). My code is
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"preferenceName"];
And also, whenever I make an if function, for example
if (t1activity == "active")
{
//code here
}
I get an error saying Expected identifier or '('
Thanks so much! (objective-c)
In the case the value differs only between YES/NO is better to provide a BOOL.
BOOL isUserActive = [[NSUserDefaults standardUserDefaults] boolForKey:#"preferenceName];
and the set method:
[[NSUserDefaults standardUserDefaults]
setBool:YES
forKey:#"preferenceName"];
Then the decision is simpler:
if(isUserActive) {
{
//code here
}
I was curious to know, how often the NSUSerDefaults do update. Here the Apple Docs.
NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.

iOS app localization depends on user choice in app

I'm pretty stuck with localization inside the app. What is idea:
You choose language inside the app, and depends on which language you choose it save value in NSUserDefaults. Because I didn't find material for this kind of localization, my idea is to make class that will have class method that return string depending on which language is saved in NSUserDefaults. Example:
+(NSString *) helloString
{
NSString *hello = [NSString new];
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqualToString:#"en"]) {
hello = #"Hello";
}
else if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqualToString:#"es"]) {
hello = #"Holla!";
}
return hello;
}
Is this legit way, is there any better solution?
I found solution for my problem. I used LocalizationSystem class, which simulated changed language from system settings.

NSLocalizedStringFromTable change default language at runtime

I'm using this line to change the default language
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:#"it"] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
and using this line to get the value
NSLocalizedStringFromTable(#"text", #"PA", nil);
Only issue is that I need to restart the app for the changes to be applied.
When i call NSLocalizedStringFromTable it always return from the language before the change
Is it possible to let the user have the option to change the local language without exiting the app?
Here is a sample project i created that demonstrate the issue
https://dl.dropboxusercontent.com/u/13431688/LocalizationTest.zip
As far as I know, it is not possible. What you could do is to have in your Localizable.strings file key-value pairs like
"en.error.general" = "An error occured.";
"fr.error.general" = "...";
then define a macro like:
#define LocalizedString(key, language) [[NSBundle mainBundle] localizedStringForKey:[NSString stringWithFormat:#"%#.%#", language, key] value:key table:nil]
and call it by LocalizedString(#"error.general", #"en");

iOS App default Language "en" is not applied

in Xcode 4.6.3 I set the "Localization native development region" = en.
I provide my app with Spanish, English and Russian locales.
Unfortunately when I set the Language of the Iphone Simulator to for example "German"
my app uses then the Spanish locale.
I suspect because I have a "Spanish Computer".
But I would like that the customers of my app get English if their locale is not provided by the app.
How can I ensure this?
One thing I noticed. In the "copy bundle resources" tab I see my other Localizable.strings files appear red. But I know that they are being despite red deployed...
Actual language which the app will have has a dynamic nature because it depends on a dynamic list in device settings. iOS will fall down through it and choose the 1st supported language.
Let's consider some app supports "en" and "ru". Despite that fact that "en" is much more preferable language for Portuguese locale, "ru" will be chosen because it situated higher than "en" in device settings on the screenshot below.
I had the same issue with one of my apps. What I did is force en as the second language in AppleLanguages and it's working now. You have to do that before the application starts (main). It's a bit of an ugly hack but works for now (NSLocalizedString is looking at that list to determine the language)... You have to be careful though, because you may get some weird stuff from NSLocale after you do that. For example if you want to use the - displayNameForKey:value: it won't be in sync and you'll have to restart the app so you get the correct result. so what you can do is initialize NSLocale with the first element in the [NSLocale preferredLanguages] (NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale preferredLanguages][0]];) and then it's going to return the expected results.
Here's what you have to do to swap the languages:
// remove what was previously stored in NSUserDefaults (otherwise the previously selected language will be still the first one in the list and your app won't be localized in the language selected in settings)
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; // make the change immediate
// reorder the languages so English is always the default fallback
NSMutableArray *mutableLanguages = [[NSLocale preferredLanguages] mutableCopy];
NSInteger enIndex = NSNotFound;
for (NSString *lang in mutableLanguages) { if ([lang isEqualToString:#"en"]) { enIndex = [mutableLanguages indexOfObject:lang]; break; } }
#try {
if ((enIndex != 0) && (enIndex != 1)) { [mutableLanguages exchangeObjectAtIndex:1 withObjectAtIndex:enIndex]; }
} #catch (NSException *exception) {
}
// save the changes
[[NSUserDefaults standardUserDefaults] setObject:mutableLanguages forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; // to make the change immediate
return UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));

CFUUID - creating ONCE & using throughout life of app

I wrote these lines in my code:
CFUUIDRef identifier = CFUUIDCreate(NULL);
NSString *identifierString = (NSString*)CFUUIDCreateString(NULL, identifier);
NSLog(#"%#",identifierString);
[self setValue:identifierString forKey:kParamNameDeviceId];
But these lines are getting called every time when the app launches.
Now my question is, how can the following be achieved?
Create CFUUID.
Store it in some variable in such a way that, when next time my app starts, it should not create a new CFUUID. It should look for the previously created CFUUID and return it.
In short, I want a CFUUID be created ONCE and used throughout the life of the app (till it gets uninstalled).
easiest way is to store it in NSUserDefaults
NSString *identifierString = [[NSUserDefaults standardUserDefaults] objectForKey:#"myID"];
if (!identifierString) {
CFUUIDRef identifier = CFUUIDCreate(NULL);
identifierString = (NSString*)CFUUIDCreateString(NULL, identifier);
[[NSUserDefaults standardUserDefaults] setObject:identifierString forKey:#"myID"];
}
NSLog(#"%#",identifierString);
/* ... */
Create once. Add it in NSUSerDefaults and check whether you have a UUID stored already before creating one. Simple Pseudo code,
NSString *CFUUID = nil;
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"UUID"]) {
//create CFUUDID.
[[NSUserDefaults standardUserDefaults] setObject:CFUUID forKey:#"UUID"];
}
else
{
CFUUID = [[NSUserDefaults standardUserDefaults] objectForKey:#"UUID"];
}
If you are storing identifier on server to keep track of important information regarding unique user than i suggest you store identifierString in "KeyChain" which keeps that identifier even if you application has been deleted by user.
NSUserDefaults keep data until app is deleted. Keychain keeps data even if app is deleted.
I had similar case so this might help if your case is equivalent to mine.

Resources