Change Language in the app programmatically in iOS

How to change the language in Xcode 5

I have 3 buttons on the ChangeLanguageViewController

This are:

  • English
  • Chinese Simplified
  • Bahasa Malaysia

Here is code:

#import <UIKit/UIKit.h>
@interface ChangeLanguageViewController :UIViewController
-(IBAction)changeEnglish:(id)sender;
-(IBAction)changeChinesesimplified:(id)sender;
-(IBAction)changeBahasaMalaysia:(id)sender;

-(IBAction)changeEnglish:(id)sender{

[[NSUSerDefaults standardUSerDefaults] setObject:[NSArray arrayWithObjects:@"en", @"zh-Hans", @"ms", nil] forKey:@"AppleLanguage"];
}
-(IBAction)changeChinesesimplified:(id)sender{
[[NSUSerDefaults standardUSerDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", @"ms", @"en", nil] forKey:@"AppleLanguage"];
}
-(IBAction)changeBahasaMalaysia:(id)sender{
[[NSUSerDefaults standardUSerDefaults] setObject:[NSArray arrayWithObjects:@"ms",@"en",@"zh-Hans", nil] forKey:@"AppleLanguage"];
}

I want to see the language change when the user presses a button and it will not kill the application but it changes the language of the app inside


Solution 1:

Usually when you support official languages that Apple supports in iOS, there is no reason to provide language switching within the app, just properly set up translations in your project and interface language will automatically switch with the system. But since you want it from the app, there are few ways to go about this:

1) You could force a specific language for just your app with the following code:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];

I would suggest putting this code inside main.m file in "int main" function just before the "return UIApplicationMain". But this method requires you to kill the app or tell user to restart the app for it to take effect.

You can kill the app without having user to force quit the app using exit(0), but make sure user has chance to abort the action with UIAlertView or similar, or Apple might reject your app.

2) Alternative is implementing your own localization logic, where you just take translations from your own language file. One way is this example which takes translations from official lproj files. This way you can change the language on the fly without a restart, but you have to manually load all label texts from the code. When you change the translation, you have to repopulate the text on screen.

Solution 2:

You can't do this without restarting the app. So you need to save the selected language in NSUserDefaults and restart the app after putting below lines in your main.h.

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects: your_lang, nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];

Solution 3:

EDIT: SWIFT 3.

Use this helper class for your requirement.

    class LanguageManager: NSObject {


    var availableLocales = [CustomLocale]()
    static let sharedInstance = LanguageManager()
    var lprojBasePath = String()

    override fileprivate init() {

        super.init()
        let english = CustomLocale(languageCode: GlobalConstants.englishCode, countryCode: "gb", name: "United Kingdom")
        let finnish  = CustomLocale(languageCode: GlobalConstants.finnishLangCode, countryCode: "fi", name: "Finland")
        self.availableLocales = [english,finnish]
        self.lprojBasePath =  getSelectedLocale()
    }


    fileprivate func getSelectedLocale()->String{

        let lang = Locale.preferredLanguages//returns array of preferred languages
        let languageComponents: [String : String] = Locale.components(fromIdentifier: lang[0])
        if let languageCode: String = languageComponents["kCFLocaleLanguageCodeKey"]{

            for customlocale in availableLocales {

                if(customlocale.languageCode == languageCode){

                    return customlocale.languageCode!
                }
            }
        }
        return "en"
    }

    func getCurrentBundle()->Bundle{

        if let bundle = Bundle.main.path(forResource: lprojBasePath, ofType: "lproj"){

            return Bundle(path: bundle)!

        }else{

            fatalError("lproj files not found on project directory. /n Hint:Localize your strings file")
        }
    }

    func setLocale(_ langCode:String){

        UserDefaults.standard.set([langCode], forKey: "AppleLanguages")//replaces Locale.preferredLanguages
        UserDefaults.standard.synchronize()
        self.lprojBasePath =  getSelectedLocale()
    }
}


 class CustomLocale: NSObject {
    var name:String?
    var languageCode:String?
    var countryCode:String?

    init(languageCode: String,countryCode:String,name: String) {

        self.name = name
        self.languageCode = languageCode
        self.countryCode = countryCode

    }

}

I have made a demo project in github.