App 内部语言切换

1、App 的语言配置列表可从如下方式读取:

let languageArray = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]

默认语言为数组的第一个值所存储的语言,可以通过更改该数组值得存储顺序来实现app内如的语言切换。

UserDefaults.standard.set(["zh-Hans-CN", "en-CN"], forKey: "AppleLanguages")

2、更改完语言数组以后需要重新设置app的rootViewController

//Bundle.main.onLanguage()
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController
        
 UIApplication.shared.keyWindow?.rootViewController = tabBarController
 UIApplication.shared.keyWindow?.backgroundColor = UIColor.white
 UIApplication.shared.keyWindow?.makeKeyAndVisible()

3、此时发现并能实时的切换语言,因为在app启动时资源文件已经读取,此时并未更改读取的资源文件。因此需要在切换语言是更换资源路径。继承Bundle,重写localizedString本地化函数,写一个扩展将Bundle类型替换为自定义的BundleEx类型,在语言切换时调用Bundle.main.onLanguage()然后再更换为rootViewController。

class BundleEx: Bundle {
    
    override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
        if let bundle = Bundle.getLanguageBundel() {
            return bundle.localizedString(forKey: key, value: value, table: tableName)
        }else {
            return super.localizedString(forKey: key, value: value, table: tableName)
        }
    }
}
extension Bundle {
    private static var onLanguageDispatchOnce: ()->Void = {
        //替换Bundle.main为自定义的BundleEx
        object_setClass(Bundle.main, BundleEx.self)
    }
    
    func onLanguage(){
        Bundle.onLanguageDispatchOnce()
    }
    
    class func getLanguageBundel() -> Bundle? {
        var languageString = "Base"
        let languageArray = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
        if languageArray.first == "zh-Hans-CN"{
            languageString = "zh-Hans"
        }
        let languageBundlePath = Bundle.main.path(forResource: languageString, ofType: "lproj")
        guard languageBundlePath != nil else {
            return nil
        }
        let languageBundle = Bundle.init(path: languageBundlePath!)
        guard languageBundle != nil else {
            return nil
        }
        return languageBundle!
        
    }
}

注意事项:storyboard类型和xib类型的本地化文件需要是.strings类型,如果是storyboard类型和xib类型在切换语言时不能实时更新。

你可能感兴趣的:(App 内部语言切换)