一尘不染

快速更改语言

swift

现在我知道苹果不推荐这样做。

通常,您不应在应用程序内更改iOS系统语言(通过使用AppleLanguages首选项键)。这违反了在设置应用程序中切换语言的基本iOS用户模型,并且还使用了未记录的首选项键,这意味着将来某个时候,键名可能会更改,这会破坏您的应用程序。

但是,这是一个可以随时更改语言的应用程序,请相信我。我也知道有人问过这个问题:在运行iOS时以编程方式实时更改语言。但是,这种方法已经过时了,我想知道是否有更新,更好或更容易的方法来做到这一点。当前在我的应用中,我有一个语言选择屏幕。单击此视图中的按钮会调用该按钮所关联的语言的以下功能:

 func changeLang(language: String) {

    if language != (currentLang as! String?)! {
        func handleCancel(alertView: UIAlertAction!)
        {

        }
        var alert = UIAlertController(title: NSLocalizedString("language", comment: "Language"), message: NSLocalizedString("languageWarning", comment: "Warn User of Language Change Different Than Defaults"), preferredStyle: UIAlertControllerStyle.Alert)

        alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler:handleCancel))
        alert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler:{ (UIAlertAction) in

            NSUserDefaults.standardUserDefaults().setObject([language], forKey: "AppleLanguages")
            NSUserDefaults.standardUserDefaults().synchronize()
            println(self.currentLang)

            let alert = UIAlertView()
            alert.title = NSLocalizedString("language", comment: "Sign In Failed")
            alert.message = NSLocalizedString("languageChangeNotification", comment: "Notify of language change")
            alert.addButtonWithTitle(NSLocalizedString("ok", comment: "Okay"))
            alert.show()

            self.performSegueWithIdentifier("welcome", sender: AnyObject?())


        }))
        self.presentViewController(alert, animated: true, completion: {
        })
    } else {
        self.performSegueWithIdentifier("welcome", sender: AnyObject?())
    }

}

例:

@IBAction func english(sender: UIButton) {
        changeLang("en")

    }

如果用户选择的语言不同于他们自己的语言,则会收到确认警报,然后要求重新启动该设备。这就是我要更改的内容。直到应用程序重新启动,NSUSerDefaults的这一部分才会同步。证据:

let currentLang: AnyObject? = NSLocale.preferredLanguages()[0]
println(currentLang)
// Prints english
changeLang("zh-Hans")
println(currentLang)
// Prints english still until restart

苹果当前拥有的国际化体系很棒,我计划使用它。但是,如何通过强制在NSUSerDefaults上进行更新来即时更改语言?

编辑: 我建议立即使用此来执行此操作。祝你好运!


阅读 200

收藏
2020-07-07

共1个答案

一尘不染

基本上,您必须教您捆绑软件如何通过加载不同的捆绑软件文件来切换语言。

我将我的Objective-C代码翻译为Swift-保持了NSBundle类别不变。

在此处输入图片说明

结果是提供了languageDidChange()一种覆盖方法的视图控制器类。


NSBundle + Language.h

#import <Foundation/Foundation.h>

@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;

@end

NSBundle + Language.m

#import "NSBundle+Language.h"
#import <objc/runtime.h>

static const char associatedLanguageBundle=0;

@interface PrivateBundle : NSBundle
@end

@implementation PrivateBundle
-(NSString*)localizedStringForKey:(NSString *)key
                            value:(NSString *)value
                            table:(NSString *)tableName
{
    NSBundle* bundle=objc_getAssociatedObject(self, &associatedLanguageBundle);
    return bundle ? [bundle localizedStringForKey:key
                                            value:value
                                            table:tableName] : [super localizedStringForKey:key
                                                                                      value:value
                                                                                      table:tableName];
}
@end

@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object_setClass([NSBundle mainBundle],[PrivateBundle class]);
    });

    objc_setAssociatedObject([NSBundle mainBundle], &associatedLanguageBundle, language ?
                             [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

AppDelegate.swift

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "languageWillChange:", name: "LANGUAGE_WILL_CHANGE", object: nil)

        let targetLang = NSUserDefaults.standardUserDefaults().objectForKey("selectedLanguage") as? String

        NSBundle.setLanguage((targetLang != nil) ? targetLang : "en")
        return true
    }

    func languageWillChange(notification:NSNotification){
        let targetLang = notification.object as! String
        NSUserDefaults.standardUserDefaults().setObject(targetLang, forKey: "selectedLanguage")
        NSBundle.setLanguage(targetLang)
        NSNotificationCenter.defaultCenter().postNotificationName("LANGUAGE_DID_CHANGE", object: targetLang)
    }    
}

BaseViewController.swift

import UIKit



class BaseViewController: UIViewController {

    @IBOutlet weak var englishButton: UIButton!
    @IBOutlet weak var spanishButton: UIButton!

    deinit{
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "languageDidChangeNotification:", name: "LANGUAGE_DID_CHANGE", object: nil)
        languageDidChange()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func switchLanguage(sender: UIButton) {

        var localeString:String?
        switch sender {
        case englishButton: localeString = "en"
        case spanishButton: localeString = "es"
        default: localeString = nil
        }


        if localeString != nil {
            NSNotificationCenter.defaultCenter().postNotificationName("LANGUAGE_WILL_CHANGE", object: localeString)
        }
    }


    func languageDidChangeNotification(notification:NSNotification){
        languageDidChange()
    }

    func languageDidChange(){

    }


}

ViewController.swift

import UIKit

class ViewController: BaseViewController {

    @IBOutlet weak var helloLabel: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func languageDidChange() {
        super.languageDidChange()
        self.helloLabel.text = NSLocalizedString("Hello", comment: "")

    }
}

除了使用BaseViewController的子类,您的视图控制器还可以发布“ LANGUAGE_WILL_CHANGE”并侦听“
LANGUAGE_DID_CHANGE”

我将整个项目推到了这里:InstantLanguageSwitchSwift

2020-07-07