swift - app国际化, 优雅切换

在开发的过程中, 可能你们的app 会有这样的需求, 需要坚持多种语言. 怎么做到不重启app 就更换了语言, 下面我们来讨论下.
首先我们知道, 如果你的app 中需要支持多种语言, 往往我们会选择一个Localizable.strings, 它会一种语言生成一个文件夹, 相当于一个包吧. 所以我们只要做到切换时, 选择对应的语言包就可以了.废话不多说, 我们开始吧.

  • 开始国际化
    点击项目->PROJECT->Info->Localizations -> + , 添加你想要的语言, 这个谈论中/英

    • 选择想用本地化的storyboard/xib...


      swift - app国际化, 优雅切换_第1张图片
  • 创建Localizable.strings


    swift - app国际化, 优雅切换_第2张图片
    建议命名为: Localizable
  • 选择你新创建的 Localizable.strings , Localize...
    swift - app国际化, 优雅切换_第3张图片
    xx.png

    添加你语言, 最后效果


    swift - app国际化, 优雅切换_第4张图片
  • Localizable.strings 文件中写入
    "key" = "value"; 这样的格式.

  • storyboard 中生成的


    swift - app国际化, 优雅切换_第5张图片
  • 要想生成这种形式, 可以先切换成 , 再切换回来


    swift - app国际化, 优雅切换_第6张图片
  • 我们这里主要讨论下怎么切换, 这些简单配置, 就不详细了, 请看最后的Demo.

  • 用自己创建的Bundle,想xcode 用自己指定的bundle , 达到切换语言的目的.

import Foundation

class AppSettings: NSObject {

    fileprivate static let kSharedSettingsKey = "DefaultUserSettings"

    static let shared: AppSettings = {
        let appSettings: AppSettings
        if let savedData = UserDefaults.standard.object(forKey: AppSettings.kSharedSettingsKey) as? Data,
            let defaultSettings = NSKeyedUnarchiver.unarchiveObject(with: savedData) as? AppSettings {
            appSettings = defaultSettings
        } else {
            appSettings = AppSettings()
        }

        return appSettings
    }()

    static func saveSharedInstance() {
        let data = NSKeyedArchiver.archivedData(withRootObject: AppSettings.shared)
        UserDefaults.standard.set(data, forKey: AppSettings.kSharedSettingsKey)
    }

    enum Language: String {
        /// 请注意, 这个命名不是随意的, 是根据你本地的语言包,可以show in finder 看到. en.lproj / zh-Hans.lproj
        case Chinese = "zh-Hans"
        case English = "en"
        var code: String {
            return rawValue
        }
    }
    /// 判断手机语言是不是中文
    static func localeIsChinese() -> Bool {
        if let lang = Locale.preferredLanguages.first {
            return lang.hasPrefix("zh") ? true : false ;
        } else {
            return false
        }

    }

    var language: Language
    override init() {
        // 第一次初始语言, 看手机是什么语言
        language = AppSettings.localeIsChinese() ? .Chinese : .English
        super.init()
    }

}
private var bundleByLanguageCode: [String: Foundation.Bundle] = [:]
extension AppSettings.Language {
    var bundle: Foundation.Bundle? {
        /// 存起来, 避免一直创建
        if let bundle = bundleByLanguageCode[code] {
            return bundle
        } else {
            let mainBundle = Foundation.Bundle.main
            if let path = mainBundle.path(forResource: code, ofType: "lproj"),
                let bundle = Foundation.Bundle(path: path) {
                bundleByLanguageCode[code] = bundle
                return bundle
            } else {
                return nil
            }
        }
    }
}
/// 首先, 我们会在启动时设置成我们自己的Bundle,这样就可以做到,当使用时会调用这个方法. 
class Bundle: Foundation.Bundle {
    override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
        if let bundle = AppSettings.shared.language.bundle {
            return bundle.localizedString(forKey: key, value: value, table: tableName)
        } else {
            return super.localizedString(forKey: key, value: value, table: tableName)
        }
    }
}

AppDelegate中


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        object_setClass(Foundation.Bundle.main, Bundle.self)
        return true
    }

使用

/// comment 是传参, 假如你的value 中需要外界来决定内容,可以用%@,然后comment传参.
NSLocalizedString("key", comment: "")

//切换语言时,只要设置就可以:
AppSettings.shared.language = .English //  .Chinese 

重置story

  • 对于story 中的国际化, 我们需要重设一下RootViewController
    func resetRootViewController() {
        if let appdelegate = UIApplication.shared.delegate {
            let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
            if let mainController = storyBoard.instantiateViewController(withIdentifier: "rootViewController") as? UINavigationController {
                appdelegate.window??.rootViewController = mainController
            }
        }
    }
  • 一位大神写的OC版
  • 如果想监听AppSettings.shared.language的变化,请我的swift:一个监听类属性/数据变化的Observable, 简单实现, 可以监听到语言的更改.
  • Demo

你可能感兴趣的:(swift - app国际化, 优雅切换)