14

Is there a way to change the application language during runtime?

So, after the change NSLocalizedString immediately returns the string for the new language.

What I'm doing now is changing the language using the code below:

- (void)onChangeLanguage: (id)sender 
{
    NSArray *lang = [NSArray arrayWithObjects:((InfoWhatever *)sender).language, nil];
    [[NSUserDefaults standardUserDefaults] setObject:lang forKey:@"AppleLanguages"];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
    NSString *currentLanguage = [languages objectAtIndex:0];

    NSLog(@"Current language: %@", currentLanguage);
}

The language will change but only after restarting the app.

P.J.Radadiya
  • 1,493
  • 1
  • 12
  • 21
shinjin
  • 2,858
  • 5
  • 29
  • 44
  • FWIW, this is how it works on the desktop (Mac), too. Running applications aren't affected by language changes. – Wevah Oct 18 '09 at 12:37
  • I just answered a similar question, and posted some code [here][1] [1]: http://stackoverflow.com/questions/9416923/ios-how-to-change-app-language-programmatically-without-restarting-the-app – software evolved Jul 18 '12 at 06:56
  • In my application have a settings page with arabic and english. once i change the language it should flip the view controller and the nslocalizedstrings. It works only once i restart the app. but it should change without closing the app, is possible? – Arun Kumar P Jun 01 '16 at 07:09

7 Answers7

11
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray* languages = [userDefaults objectForKey:@"AppleLanguages"];
[languages insertObject:@"de" atIndex:0]; // ISO639-1
[[NSUserDefaults standardUserDefaults] synchronize];
Just a coder
  • 15,480
  • 16
  • 85
  • 138
YellowSnail
  • 119
  • 1
  • 2
  • This is the right way to do it, but there is a simpler implementation here: http://stackoverflow.com/questions/6150576/change-ios-apps-language-on-the-fly – ThomasW Feb 09 '12 at 09:47
  • This implementation is better. ThomasW is replacing the original contents of the array. This method is inserting the language above what is already there. – Just a coder May 20 '12 at 19:12
  • How did this work? at least for iOS 8.2 "[userDefaults objectForKey:@"AppleLanguages"];" returns immutable array – Fawkes Mar 14 '15 at 02:11
  • This cause a crash: [__NSArrayI insertObject:atIndex:]: unrecognized selector sent to instance 0x60800003c580 – David Karlsson Apr 08 '15 at 11:18
7

You Can do it . Here is the way http://aggressive-mediocrity.blogspot.com/2010/03/custom-localization-system-for-your.html

  1. In Brief Download and add 2 files to the project

    http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.h

    http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.m

2
#import "LocalizationSystem.h"

3

- (IBAction)btnEnglishClicked:(id)sender {
     LocalizationSetLanguage(@"en");
}

4 After you set the language as above

AMLocalizedString(@"Key", nil)

Thats it.

MadNik
  • 7,713
  • 2
  • 37
  • 39
  • 1
    This sounds like the proper approach to the problem, however since you're not using NSLocalizedString (or its variants) directly, you lose the ability to use genstrings to generate your string tables. You can likely use this open source implementation of genstrings to detect your functions though: https://github.com/Cocoanetics/DTLocalizableStringScanner – Sebastien Martin Mar 17 '13 at 17:37
  • But, how about image resources. If there are many images on a screen, we will have to set them explicitly. Any better approach of images? – NNikN Jan 10 '14 at 22:53
7

The trick to use specific language by selecting it from the app is to force the NSLocalizedString to use specific bundle depending on the selected language ,

here is the post i have written for this 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

object2.0
  • 891
  • 1
  • 12
  • 12
5

I doubt you can do this, even the Settings app cannot do it.

(When you change the language in the Settings app, the screen goes black, and displays "setting language..." and a progress wheel. After a long wait, you are back in Springboard. It almost looks like the phone reboots.)

oefe
  • 19,298
  • 7
  • 47
  • 66
  • Okay then, the reboot sounds acceptable. Is there any apple policy against quitting? – shinjin Oct 20 '09 at 09:13
  • 1
    I agree with your suppositions - but this is not an answer. Do you have any information about performing a runtime language change? – Brandon Jun 25 '10 at 16:33
  • @Brandon: Why the downvote? You may not like the answer, but it's how things are. Or do you know it better? Then why don't you show us your better answer? – oefe Jun 25 '10 at 21:41
  • Again, you did not provide an answer. You made a guess. This is an answer: http://stackoverflow.com/questions/1669645/how-to-force-nslocalizedstring-to-use-a-specific-language – Brandon Jun 29 '10 at 14:29
  • 1
    @Brandon: that's an answer to a different question. And the wording of my answer makes it obvious enough that it is based on assumptions and observations, not on some first-hand information (which I would have cited, if I had it). And nobody provided a different (better) answer, so I still think it's the correct answer. – oefe Jul 04 '10 at 19:51
  • 1
    Yes, that is a different question. Check out the answer, the answerer clearly had some first-hand knowledge of the subject matter - even if the question was not completely resolved. Your answer provides absolutely no useful information. In addition to being simply wrong, the assertion that 'the Settings app cannot do it' is misleading. Why does it matter that the settings app does not (as opposed to cannot) change the presentation language at runtime? The use case that the asker is pursuing does not require redisplaying localized icons or even involve other applications. The answer is inane. – Brandon Jul 05 '10 at 13:31
  • 1
    @Brandon: why don't you share *your* answer with us? – oefe Jul 06 '10 at 17:46
  • 2
    It took quite a while for me to devise a solution. I actually ended up using the 'NSLocalizedStringFromTable' macro and the 'AppleLanguages' setting to set and check language settings. I'll write up an actual answer if I have the chance. Maybe you should delete this answer? Seeing an inane yet accepted answer doesn't exactly inspire anyone to spend a whole lot of effort. – Brandon Jul 07 '10 at 13:11
  • @Brandon So did you come up with a solution? I'm looking for a solution to this same problem – Just a coder May 20 '12 at 18:40
3

I came up with a solution that allows you to use NSLocalizedString. I create a category of NSBundle call NSBundle+RunTimeLanguage. The interface is like this.

// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end

The implementation is like this.

// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"

@implementation NSBundle (RunTimeLanguage)

- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithPath:path];
    NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
    return localizedString;
}
@end

Than just add import NSBundle+RunTimeLanguage.h into the files that use NSLocalizedString.

As you can see I store my languageCode in a property of AppDelegate. This could be stored anywhere you'd like.

This only thing I don't like about it is a Warning that NSLocalizedString marco redefined. Perhaps someone could help me fix this part.

qman64
  • 151
  • 1
  • 4
1

Simply add these lines:

 #define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]   


 1. NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; 
            [defaults setObject:@[@"en"] forKey:@"AppleLanguages"];  [defaults
            synchronize];

 2. _label.text = NSLocalizedStringFromTableInBundle(@"Key", nil, currentLanguageBundle, @"");
Chewpers
  • 2,430
  • 5
  • 23
  • 30
Arsen Avetisyan
  • 171
  • 2
  • 4
-1

try this: object_setClass([NSBundle mainBundle],[MyBundle class]);

https://github.com/maximbilan/ios_language_manager/blob/master/README.md

  • I tried your solution on my project but I get an exception: "There doesn't seem to be a valid compiled storyboard at path ". I then noticed that the reason was that I had enabled Size Classes in my storyboard. The same thing happens with your project if you enable Size Classes for your storyboard. Any ideas how this issue can be tackled? – Kremk Dec 10 '15 at 01:55
  • The question was about "switch during runtime". You suggest to rebuild. – Alexander Volkov Jul 29 '16 at 09:51