Xcode localization - objective-c

I have a question on how to set the default language in an Xcode project.
My Mac OS X App supports German and English.
Everytime English is not selected in Systemsettings, default language is German.
I want to switch default language to English, so that non-german users get an English UI.
Changing "Localization native development region" in Plist file to English didn't solve the problem.
I tried to do it within the code but this is not what Apple recommends in their HIGs.
Sampleproject is hosted on Github.
https://github.com/christian123456/xcodelocalization
Xcode Version is 5.1.1
I recently added the screenshots to the repository. As you can see in the "german incorrect.png" screenshot, French and Portuguese languages are chosen but Mac OS picked German as language. I want the language to be English.

Testing and analyzing
I've added -NSShowNonLocalizedStrings YES into scheme-editor > Run .app > Arguments > Arugments Passed On Launch. This turns any string it cannot find a localized variant for into uppercase.
The result is, I see all uppercase.
To switch language for developing use -AppleLanguages (it).
As result, the en localization appears.
To switch the language of an app, you can also use the following app:
https://itunes.apple.com/de/app/app-language-chooser/id451732904?l=en&mt=12
For more information read here.
Solution
After a little searching and testing, I found this solution:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", #"de", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
This would set the language english as default.

Another option is to create your own localization class. Call your class, and it can force localization into any language you want:
- (NSString*) MyLocalizedString:(NSString*) label;
{
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSString* preferredLanguage = [defs objectForKey:#"LocalizedLanguage"];
NSString *path = [[NSBundle mainBundle] pathForResource:preferredLanguage ofType:#"lproj"];
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString *result = [NSString stringWithFormat:#"%#",[languageBundle localizedStringForKey:label value:#"" table:nil]];
return(result);
}
- (NSLocale *) forceEnglishLocalization;
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"en" forKey:#"LocalizedLanguage"];
NSLocale * currentLocale;
currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en"];
return(currentLocale);
}
Need help localizing your Xcode apps?
https://itunes.apple.com/mg/app/generate-localizable-strings/id890673579?mt=12

Related

How to Change Xcode development region to print localized string using NSLog

Documentation of operatingSystemVersionString method of NSProcessInfo says "The operating system version string is human readable, localized, and is appropriate for displaying to the user. This string is not appropriate for parsing."
NSString *versionString = [[NSProcessInfo processInfo] operatingSystemVersionString];
NSLog(#"%#",versionString);
I want to check what it will return in case of other languages like China, French. I changed region and language but NSLog always prints in english language.What settings I should change in Xcode and System Preferences to check the behavior of operatingSystemVersionString based on region and language? Or NSLog prints in English only?
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSProcessInfo_Class/index.html#//apple_ref/occ/instp/NSProcessInfo/operatingSystemVersionString
You can try adding these lines in the main.m file
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
Just change the 2 letter prefix (#"en") to any language you need.

Language is not stored correctly

I'm doing an app that lets user to choose language and change it during runtime. I have an issue trying to store desired language. It runs correctly during the same execution the user changes language, but then in next execution, it always gets spanish language (system language). Here is the code I use to store language:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (sender.tag==1){
[defaults setObject:[NSArray arrayWithObjects:#"ca",#"es", nil] forKey:#"AppleLanguages"];
}else{
[defaults setObject:[NSArray arrayWithObjects:#"es",#"ca", nil] forKey:#"AppleLanguages"];
}
[defaults synchronize];
Many thanks
The system will override the value of AppleLanguages every time your app gets started.
A solution would be to store your desired languages in a separate NSUserDefaults entry and load them (write them into AppleLanguages) at every app startup.
Hope this helps

Get ios multi-value user preferences

I try to retrieve the value selected in Settings Application using "Settings Bundle". The field is "PSMultiValueSpecifier". In "Root.plist" I implemented:
Type: PSMultiValueSpecifier
Title: Abcdefg
Key: abcdefg
DefaultValue: aaa
Values (array):
Item 0: aaa
Item 1: bbb
Titles (array):
Item 0: A
Item 1: B
And, In the implement file I have wrote:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *string = [defaults objectForKey:#"abcdefg"];
But "string" is empty. When I do the same with a user default of kind: "PSTextFieldSpecifier" I can retrieve the value.
I follow the instructions explained in the book "Apress - Beginning iOS 5 Development: Exploring the iOS SDK" but I can not retrieve the value selected.
Instructions are the same of the "Apple Development Help".
I do not understand what is the problem. It seems easy.
I have found the bug.
If you implement "Multi Value" user preferences in "Settings.bundle" (with its "Default Value"), but never enter in settings iPhone simulator and never change the multi-value preference, the sentence:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *string = [defaults objectForKey:#"key"];
Returns a "nil" value. Incredible, I lost a week trying to find the problem!!!!
But I have a doubt:
If I implement a "Multi Value" user preferences and I publish the App in iTunes Store, but user not use this "Multi Value" user preferences, "NSUserDefaults" will return nill value?
Do I have to consider the possibility of receiving an empty value?
Really, I think it is ridiculous.
It seems that DefaultValue is used only in the official Settings app. Apparently, you have to register the defaults by 1) testing one of your settings to see if it's NULL, then 2) iterating through the settings, grabbing and setting the defaults:
sample Obj-C code for this by just.do.it
The documentation on PSMultiValueSpecifier does seem deficient here. Confusion on this shows up all over SO and the web. For example:
defaultvalue-for-psmultivaluespecifier on SO
app-preferences-how-to-get-psmultivaluespecifier-property on SO
No, I think you need to register your default value, for example in:
-(BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions
{
NSDictionary* defaults = #{#"key": #"default value"};
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
}
This is because the app knows nothing about the settings bundle it contains. The page 430 of book Beginning iOS6 Development: Exploring the iOS SDK has a clear explanation of this.
if the returned object is nil then set the default value.
NSString * key = #"the key";
NSUserDefaults * uD = [NSUserDefaults standardUserDefaults];
NSString * stringValue = [uD objectForKey:key];
if (!stringValue) {
stringValue = #"the default value";
[uD registerDefaults:#{key: stringValue}];
}

Check for first launch of my application

How would I check if it is the first launch of of my application using NSUserDefaults and running some code for the first time my app opens?
This should point you in the right direction:
static NSString* const hasRunAppOnceKey = #"hasRunAppOnceKey";
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:hasRunAppOnceKey] == NO)
{
// Some code you want to run on first use...
[defaults setBool:YES forKey:hasRunAppOnceKey];
}
The NSUserDefaults answer is the first thing that popped in my head, but upon reflection I will make another suggestion. A bit more work, but it's worth considering. The motive is: sometimes when troubleshooting an app, Apple recommends deleting that app's plist file. It's a fairly ubiquitous troubleshooting technique. I would recommend storing your boolean in your plist file instead of NSUserDefaults.
Disclaimer: I only do iOS development, so I'm not sure how NSUserDefaults and plists interact on the Mac, and I don't know what all is involved in getting your plist to live in ~/Library/Application\ Support/Preferences/com.mycompany.MyAppName.plist
Anyway, I imagine what this requires is having some code which can actually author a "fresh" plist (probably a copy from a template file in your bundle), and you app does this if it launches and does not see a plist. The default plist should not include the flag which lets your users skip the 'first time' code, but if they have opened the app before, and then delete the plist, they should get default behavior back.
This is an important behavior to support where possible, to aide our users if our app ever gives them trouble.
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"hasBeenLaunched"]) {
// Run code on the first launch only ...
[defaults setBool:YES forKey:#"hasBeenLaunched"];
}
You can use NSUserDefaults to save bools, integers, objects into the program and have them available whenever you open it. You can use 'boolForKey' to set a flag called "hasBeenLaunched". By default, this value will be NO when not set. Once you change it to YES, the code in the if condition will never be executed again.
In your main controller class, implement something like this:
static NSString * const MDFirstRunKey = #"MDFirstRun";
#implementation MDAppController
+ (void)initialize {
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
[defaults setObject:[NSNumber numberWithBool:YES] forKey:MDFirstRunKey];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
// the following if on Mac and is necessary:
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:defaults];
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
BOOL firstRun = [[[NSUserDefaults standardUserDefaults]
objectForKey:MDFirstRunKey] boolValue];
if (firstRun) {
// do something
[[NSUserDefaults standardUserDefaults] setObject:
[NSNumber numberWithBool:NO] forKey:MDFirstRunKey];
} else {
// do something else
}
}
#end
The +initialize class method is called before an instance of the class it's found in is created; in other words, it is called very early on, and is a good place to set up your default values.
See Preferences and Settings Programming Guide: Registering Your App's Default Preferences for more info.

Interface language in MFMessageComposeViewController

I'm trying to send sms from my iphone using MFMessageComposeViewController. It shows a modal dialog with filled fields. everything work, but I want to show dialog in Russian Language.
I want to see all values (such as "New message", "send", etc) in Russian.
I'v checked default language:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults objectForKey:#"AppleLanguages"];
NSString *currentLanguage = [languages objectAtIndex:0];
NSLog(#"Current Locale: %#", [[NSLocale currentLocale] localeIdentifier]);
NSLog(#"Current language: %#", currentLanguage);
And it returns, that language is ru-RU.
How can I set a lang for this dialog?
You need to localize your app for Russian in order for it to show the localized controls you ask for.
All you should need to do is add a ru.lproj folder to your project (you could include here a Localizable.strings file if needed by your app) to let know Xcode that you are actively supporting that language.
For every language you add as language-code.lproj, every native control (MFMessageComposeViewController, MFMailComposeViewController) should consider using that language if set as local on the device.