How to select an storyboard programmatically? - ios

I have an iOS 5 app that supports 3 different languages. Localizing an storyboard creates a copy in each language and each one must be translated.
The language selection depends on system settings, so if my iPhone has 'English' as a system language the choosen storyboard in my application will be the English one. If I change to Catalan, my app will show Catalan words.
This approach has several drawbacks in my opinion:
An app cannot be translated to languages not supported by Apple. This could be important for moniroty languages ( Catalan has not been supported until iOS 5 ).
If a user wants to have my app in Catalan but the rest of the system in English ?
So my question is how can I select the storyboard language at app startup time ? Is it possible at all ? Also it will work for strings localized using NSLocalizedString ?
Regards,
JoanBa

It seems like you can split the storyboard into localized versions just like localized.strings as to how to do it?
This question has been answered before although I haven't tried from experience.

After reading the Jacob answer and testing a little bit, this is the code that has worked for me:
int main(int argc, char *argv[])
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// Reset system defaults to get the complete language list.
[defaults removeObjectForKey:#"AppleLanguages"];
// Default language choosen by user.
NSString *defLanguage = [defaults objectForKey:#"Language"];
NSArray *sysLangugages = [defaults arrayForKey:#"AppleLanguages"];
// System default language: first element of array.
NSString *sysLanguage = [sysLangugages objectAtIndex:0];
NSArray *array = [NSArray arrayWithObjects:defLanguage, sysLanguage, nil];
[defaults setObject:array forKey:#"AppleLanguages"];
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
Just restarting the app after changing the default language, all localized resources are changed: strings and storyboards.
Also tried this code in AppDelegate.m, in method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
but it doesn't work. Only in main.m works fine. I don't know why.
Note that with this code you can have an application with a language not supported by iOS.
Regards,
JoanBa

Related

iOS: Localizable.strings doesn't work

This has been bothering for days now.
I've set up Arabic localisation in my project and I've set my device Language to Arabic.
When I run my app from Xcode with the run scheme option set to use Arabic Localization, localisation works fine.
When I run the app without Xcode, the app uses English.
I've read the answers to similar questions but none of them have worked for me thus far.
I am using NSLocalizableString(#"login",#""); to load the strings from the Localizable.strings file. This works fine as long as I set the Run scheme localization option to Arabic.
I've tried uninstalling the app, cleaning the project and then re-installing. Now the app uses the Localizabe.strings key names instead of their arabic values.
The Localizable.strings file is named correctly, and is listed under "Copy Bundle Resources".
The Localizable.strings is perfectly formatter. I've verified this using plutil.
What else could I be missing?
Example:
-(void) viewDidLoad
{
[super viewDidLoad];
// ...
[self setupLocalization];
}
-(void) setupLocalization
{
self.mailAddress.placeholder = NSLocalizedString(#"email_address", #"");
self.password.placeholder = NSLocalizedString(#"password", #"");
}
I found out what the issue is:
AppDelegate's application:didFinishLoadingWithOptions: contained this snippet of code
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#[#"en"] forKey:#"AppleLanguages"];
[defaults synchronize];
which forces NSLocalizedString() to return English values.
The project was outsourced and I had no idea that the snippet was there.
Are you calling NSLocalizedString(_:,comment:) to convert your strings to localized strings?
If you are not doing that, that is the reason it is not working.

Disable Target Localization in Xcode

In our project we have multiple build targets which each use an English, French and Base (English) localization files. Some of these are string files while others are localized storyboard files that have been constructed to include both of these languages.
What is the best way to, on a single build target, restrict the localization so that it only uses English and not French while at the same time keeping it so all the other build targets still have both English and French localizations working? I try to not include the French localizations for that specific build but that removes the entire localization file since this seems to be done at project level.
I found a few posts here but nothing that worked for disabling a single localization language from a specific build target while leaving the others alone.
We are working in Xcode 6 currently.
I'm not sure it's exactly what you're looking for, but if you want to force your app to be displayed in a specific language, you can do that without removing the other localizations from your project. You can change your main.m implementation to:
int main(int argc, char *argv[])
{
#autoreleasepool
{
if (/*Some condition for this build*/)
{
NSString *newLanguage = [[NSUserDefaults standardUserDefaults] objectForKey:kNewLanguageCode];
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:newLanguage, nil] forKey:#"AppleLanguages"];
}
else // If you want other conditions, or just do nothing if you want to support the device's current localization settings
{
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:#"en", nil] forKey:#"AppleLanguages"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
I know it's not exactly what you asked about, but I thought that it may solve your problem from a slightly different direction, so I hope this helps. Good Luck!

iOS Localization (setting it in the app)

in my application I must have two languages, but the problem is that they should be switched by pressing a button in the application (on the first screen, or screen settings). As I understand, all the methods of localization (Localizing the Storyboard, Localizing Dynamic Strings) based on the language settings of the iPhone. The only option that comes to my mind - do it by the record in NSUserDefault about language preference, and in ViewDidLoad methods of all ViewControllers check the record about language and in accordance with it set strings, picture and so on. Can it be done on a more clever way?
Try this:
If de is the new language selected by the user. Also assure that you are reinitiating the current view.
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"de", nil]
forKey:#"AppleLanguages"];
See the below link and source code
http://learning-ios.blogspot.com/2011/04/advance-localization-in-ios-apps.html
and here is the code of one sample app https://github.com/object2dot0/Advance-Localization-in-ios-apps
All the best.
this tutorial & sample app helpful you more
localization-tutorial-for-ios
ios-programming-tutorial-localization-apps
Ya The way you are following for Localization is not up to Mark.
Please Follow this beautiful tutorial http://www.raywenderlich.com/2876/localization-tutorial-for-ios
You have to manually mange the currently selected language into user default and load the bundle folder according to selected language key like, i have done this and worked like charm
if ([currentLanguage isEqualToString:#"fr"]) { // If French.
languageBundle = nil;
NSString* path = [[NSBundle mainBundle] pathForResource:#"fr" ofType:#"lproj"];
languageBundle = [NSBundle bundleWithPath:path];
}

Why does my iOS app only detect the current language properly on first run?

I am localizing my iOS app, and in the Simulator it runs correctly in my chosen language every time.
When testing on my iPhone 5, it only detects the language properly the first time the app runs. Every other time I recompile and run my app on the device, it detects "en" as the language, even though I am testing with EspaƱol ("es") selected.
I detect the language using:
[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]
I've also used:
[[NSLocale preferredLanguages] objectAtIndex:0]
Same result.
If I kill the app after the first run, and restart it on the device, it continues to detect the language properly.
But if I kill the app and then recompile/restart via Xcode after the initial run, it will load with "en" (English) detected instead.
After that, killing and re-starting the app continuously detects as English unless I delete the app completely, and recompile/reinstall/run the app via Xcode. The cycle then repeats... subsequent rebuild/restart without first deleting the app from the device results in misdetection.
All other apps on my device display with Spanish language the entire time. The entire UI shows in Spanish.
UPDATE: I've now tested on my iPad (3rd gen) also running iOS 6, and am experiencing the same behavior.
UPDATE 2:
In didFinishLaunchingWithOptions, I have this code to detect language: (language is an NSString*):
language = [[NSLocale preferredLanguages] objectAtIndex:0];
Followed by this debugging statement, to compare the value I'm getting, as well as a slightly different way of detecting it, just for debugging:
NSLog(#"Detected language: %# / %#", language, [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]);
The output shows as "Detected language: es / es" when the app works properly in Spanish mode, and then shows as "Detected language: en / en" when it doesn't. Still no idea why it decides to load as English sometimes...
UPDATE 4: I appreciate everybody's answers, and I've tried the various suggestions. Unfortunately I was unable to award the +100 bounty as none of the suggestions seemed to fix the issue. If someone does ultimate find a solution that works for me, I will award another +50 bounty to them at that time.
UPDATE 5: I have updated from Xcode 4.5 to 4.5.2, and experiencing this same issue.
UPDATE 6: I have now created a new test project from scratch, and it works perfectly fine! Obviously something must be wrong in the way my project is laid out, or perhaps in one of the data files. I guess my next journey will be to re-create the project from scratch, copying file data over one by one...
UPDATE 7 (MONTHS LATER): Sadly, I am again facing this issue after temporarily resolving it (seemingly) by painstakingly recreating my project. On first load, the language is correctly rendered, but on subsequent loads, it reverts back to English.
SOLVED See my final solution below. Thanks for the help everyone. I may dole out some of the bounty since it will go to waste anyway.
I have FINALLY solved this problem after many months! Thanks to all for the help (I also had some good back and forth with an Apple developer via the dev channels).
TL;DR: I was accidentally syncing language preferences (among many other unexpected things) between devices, using my app's iCloud key value store (via MKiCloudSync)! Read on...
I am using a third-party class called MKiCloudSync, which helps with syncing [NSUserDefaults standardUserDefaults] to my app's iCloud key value store. My intention when I began using it was to let it handle some user favorites syncing in the background.
However, not understanding how standardUserDefaults works, what I didn't realize is that there are a lot of other things being written into standardUserDefaults other than just my own custom app settings!
So what was happening was this:
Start the app up for the first time. Fresh standardUserDefaults in place, and the internal "AppleLanguages" key that stores the ordered list of language preferences is correct based on the current device choices.
App displays properly in the designated language.
In the background, MKiCloudSync syncs ALL standardUserDefaults to iCloud. Conversely, if you had run this app elsewhere, say with an English set device, that device would have also synced it's language settings up to iCloud. So now this current running app is actually having it's language preferences overwritten.
BOOM ... next time the app is run, no matter what you have selected on the device, it's whatever was pulled down from iCloud that will be used as the default language!
What I plan to do to solve the issue with my next app update:
Use a forked version of MKiCloudSync that allows for syncing only whitelisted key names.
Add code that will do a one-time cleanup, first cleaning out the iCloud keystore for my app, then (based on this SO answer), calling this code to reset the user defaults:
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
In my testing so far, this sort of solves the issue... unfortunately, the user would have to restart the app for the language fix to kick in. However, my guess is most users are not experiencing this issue, as they are unlikely to be using multiple devices with different default languages.
In settings->general->international, there is an option to set the location language etc. if you set that to the language you are trying to test it will work if your code is correct.
I tested your steps on my iPhone 5 without issues. This leads me to think there's something else at play here: most probably there's something interferring with the way in which you're reading the locale value.
The steps I'd recommend you take to help you debug this issue are:
Post the complete code of the method in which you're obtaining the preferred language value. Make sure the method is executed each time the app is run.
Make sure the code you post includes the location of the NSLog directive you're using to test for the language setting.
Are you storing the preferred language somewhere else after the first run?
Try with following code:
LocalizationSystem.h===
#import <Foundation/Foundation.h>
#define AMLocalizedString(key, comment) \
[[LocalizationSystem sharedLocalSystem] localizedStringForKey:(key) value:(comment)]
#define LocalizationSetLanguage(language) \
[[LocalizationSystem sharedLocalSystem] setLanguage:(language)]
#define LocalizationGetLanguage \
[[LocalizationSystem sharedLocalSystem] getLanguage]
#define LocalizationReset \
[[LocalizationSystem sharedLocalSystem] resetLocalization]
#interface LocalizationSystem : NSObject {
NSString *language;
}
+ (LocalizationSystem *)sharedLocalSystem;
//gets the string localized
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment;
//sets the language
- (void) setLanguage:(NSString*) language;
//gets the current language
- (NSString*) getLanguage;
//resets this system.
- (void) resetLocalization;
#end
LocalizationSystem.m===
#import "LocalizationSystem.h"
#implementation LocalizationSystem
//Singleton instance
static LocalizationSystem *_sharedLocalSystem = nil;
//Current application bundle to get the languages.
static NSBundle *bundle = nil;
+ (LocalizationSystem *)sharedLocalSystem{
#synchronized([LocalizationSystem class])
{
if (!_sharedLocalSystem){
[[self alloc] init];
}
return _sharedLocalSystem;
}
// to avoid compiler warning
return nil;
}
+(id)alloc{
#synchronized([LocalizationSystem class])
{
NSAssert(_sharedLocalSystem == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedLocalSystem = [super alloc];
return _sharedLocalSystem;
}
// to avoid compiler warning
return nil;
}
- (id)init{
if ((self = [super init]))
{
//empty.
bundle = [NSBundle mainBundle];
}
return self;
}
// Gets the current localized string as in NSLocalizedString.
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment{
return [bundle localizedStringForKey:key value:comment table:nil];
}
// If this function is not called it will use the default OS language.
// If the language does not exists y returns the default OS language.
- (void) setLanguage:(NSString*) l{
NSLog(#"preferredLang: %#", l);
NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:#"lproj" ];
if (path == nil)
//in case the language does not exists
[self resetLocalization];
else
bundle = [[NSBundle bundleWithPath:path] retain];
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:l, nil] forKey:#"AppleLanguages"];
}
// Just gets the current setted up language.
// returns "es","fr",...
//
// example call:
// NSString * currentL = LocalizationGetLanguage;
- (NSString*) getLanguage{
NSArray* languages = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"];
NSString *preferredLang = [languages objectAtIndex:0];
return preferredLang;
}
// Resets the localization system, so it uses the OS default language.
//
// example call:
// LocalizationReset;
- (void) resetLocalization{
bundle = [NSBundle mainBundle];
}
#end
This code works perfectly as you mentioned.
It worked for me and that game is live now app store, if you want to check(HueShapes).
Do you by chance use NSUserDefaults to save something language related?
Look into your Simulator App directory -> Library -> Preferences -> <YourAppBundleName>.plist
See: How to force NSLocalizedString to use a specific language for description of the NSUserDefaults method of setting a language.
Perhaps you just save your language and thus detection just returns the saved value.

iOS : How deal with specific resources for US residents ( en_US )?

I'm working on an iOS app that must have a different name and some different
images for US residents (different brand name).
I defined an en-US.lproj rep but it's never used. When I simulate an US resident I have : [[NSLocale currentLocale] locale localeIdentifier] => 'en_US', but the en.lproj is used.
I tried to change (in Xcode) the 'Localization native development region' but it doesn't change anything.
I don't have any problem with the french localization.
I could do it with code but not for the app name or the Default.png.
How to make the en-US.lproj work ?
Thanks.
I solved a part of my problem with this answer :
iPhone App Localization - English problems?
But as "iPhone localisations (or is that localizations?) do not take any notice of the Region the user sets", I can do nothing for the BundleDisplayName or the Default.png.
UPDATE: You should also know that if you change the language/region settings you may have to restart the phone to get the app work with the correct region settings!!!
i fixed it by setting the base language to english and in the main.m i called:
int main(int argc, char * argv[]) {
#autoreleasepool {
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:[[NSLocale currentLocale] localeIdentifier], nil] forKey:#"AppleLanguages"];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Resources