I am using a single, localized Storyboard for my application. The app has to have an option to change language on the fly. So far I figured out how to change the language which is used during the app launch:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
And managed to reload my entire application by removing all subviews of the key window, reloading the initial view controller from the storyboard and making it the new root view controller. (It has some problems, like managing open resources, but it can be done.)
The only thing I couldn't figure out is how do I force iOS to reload the storyboard in the new language? It seems storyboards are cached somehow, and -UIStoryboad:stroyboardWithName:fromNib
does not reload it entirely, so it appears in the last language.
I've already considered two other options:
having different storyboard files for each language (it is unamanageable, I don't want to do this)
using event listeners in all of my view controllers which respond to a language change and set the new strings on the UI (which is also has to be called every time any interface element gets instantiated from the storyboard). This solution requires more time, than we'd like to spend with this, and also highly increases the possibility of bugs.
Is there some more clever way? I don't want to keep the current state of my application, so restarting it like it was killed and realunched seems a reasonable resolution.
So I found that the problem is with Base translation of my Storyboard, which means I had only one Storyboard file and one .strings file per language for it. It can't be done using Base translations, Apple does not support it.
So my workaround was the following:
Convert Base translations to one Storyboard each language (you can do it in Xcode when you click the Storyboard and set the type to Storyboard from Strings). You can delete the Base at the end.
Translate the strings in your Storyboards
In the button handler of your language change button do the following:
(I am using tab controller as root controller, you should change this to your root controller type.)
[[NSDefaults standardDefaults] setObject:[NSArray arrayWithObject:@"hu"] forKey:@"AppleLanguages"];
[[NSDefaults standardDefaults] synchronize];
GKAppDelegate *appDelegate = (GKAppDelegate *)[[UIApplication sharedApplication] delegate];
UITabBarController* tabBar = (UITabBarController *)appDelegate.window.rootViewController;
// reload the storyboard in the selected language
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:appDelegate.lang ofType:@"lproj"];
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:bundle];
// reload the view controllers
UINavigationController *placesTab = (UINavigationController *)[storyBoard instantiateViewControllerWithIdentifier:@"placesTab"];
UINavigationController *informationTab = (UINavigationController *)[storyBoard instantiateViewControllerWithIdentifier:@"informationTab"];
// set them
NSArray *newViewControllers = @[placesTab, informationTab];
tabBar.viewControllers = newViewControllers;
In your appname.pch
file:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
And you should change all of this:
NSLocalizedString(@"key", @"comment")
to this:
NSLocalizedStringFromTableInBundle(@"key", nil, currentLanguageBundle, @"");
Please notice, that I removed the second parameter, the comment. It seems comments with non-ASCII letters can cause trouble, so it's better to avoid them at this point.
The adventages of this method:
you can use system tools to gather strings to .strings files
the UI will not flicker when you change language
you don't have to write a lot of code or use a lot of outlets
language changig code needs to be ran only once, when the user pushes the button
I hope this helps, and maybe you can improve my solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With