在开发的过程中, 可能你们的app 会有这样的需求, 需要坚持多种语言. 怎么做到不重启app 就更换了语言, 下面我们来讨论下.
首先我们知道, 如果你的app 中需要支持多种语言, 往往我们会选择一个Localizable.strings, 它会一种语言生成一个文件夹, 相当于一个包吧. 所以我们只要做到切换时, 选择对应的语言包就可以了.废话不多说, 我们开始吧.
-
开始国际化
点击项目->PROJECT->Info->Localizations -> + , 添加你想要的语言, 这个谈论中/英-
选择想用本地化的storyboard/xib...
-
-
创建Localizable.strings
- 选择你新创建的 Localizable.strings , Localize...
添加你语言, 最后效果
Localizable.strings 文件中写入
"key" = "value"; 这样的格式.-
storyboard 中生成的
-
要想生成这种形式, 可以先切换成 , 再切换回来
我们这里主要讨论下怎么切换, 这些简单配置, 就不详细了, 请看最后的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