前言
项目开发中不同语言环境需要进行多语言适配,例如:中文、英语、法语、俄语、葡萄牙语等
- 纯代码界面开发时,直接添加本地化语言文件,并针对键值对获取即可
下面我们来介绍如何国际化:
全局添加需要适配的多语言
PROHECT -> Info -> Localizetions 下:选择 + 号添加:
Chinese,Simplified:中文简体
Chinese,Traditional:中文繁体
English - Development Localization:英语
French(fr):法语
Russian:俄语
Arabic:阿拉伯语
…
添加完成之后的效果:
细心的朋友会发现如今 English
后面是 1 File Localized
,这是因为 英语
是系统默认加入的,并且同一时刻为 Main.storyboard
和 LaunchScreen.storyboard
设置了多语言
纯代码本地化
- 创建本地化文件
默认文件名为 Localizable
,不要去修改
- 点击 Next,Save As:Localizable
Localizable.strings
就是你需要的本地化文化
点击右侧的 Localizable
,关联本地化语言
- 在本地化文件中设置
Key-Value
注意:不要忘记行末的 ;
号
分别在对应的本地化语言文件中,设置不同的 Key-Value
- 调用本地化
1 2 3
| // 调用字符串对应的本地化符号 let title = NSLocalizedString("title", comment: "title") MyLog(message: title)
|
这种设置完之后仅仅能让应用随系统的语言进行切换,而用户不能手进行切换
图片本地化
- 选中需要本地化的图片,同上面一样点击
Localize...
,创建本地化 图片资源文件
- 关联你需要本地化的语言
- 图片
Show In Finder
,可以看到在 中文和英文资源下都有这个图片,把需要替换的图片换掉即可
- 图片使用和平常一样
1
| let img = UIImage(named: "loading.png")
|
App 名称的 本地化
- 要实现应用名称根据语言环境显示不一样的名称,只需要创建
InfoPlist.strings
文件,创建 InfoPlist.strings
并关联语言
- 获取info.plist中的key
点击 Infoplist
右键选择 Open As -> Source Code
,查看我们所要获取权限的原始key。
新版Xcode获取不出来数据不用急,去代码中将info打印出来,拿到key效果一样。
1 2
| let infoPlist = Bundle.main.infoDictionary MyLog(message: infoPlist)
|
- 本地化文件中,对key-value进行配置
1 2 3 4 5
| // Chinese,Simplified "CFBundleDisplayName" = "中图云书房"
// English "CFBundleDisplayName" = "SRSF"
|
- 运行App,然后切换手机语言为英文,会发现软件名称变成了英文
Xcode中切换语言
为了调试国际化,我们除了可以进入 模拟器或真机
切换系统语言,也可以在 Xcode
中配置相关项,使 Debug
环境下运行时预览不同语言和地区 App的界面效果
- 选择 Product -> Scheme -> Edit Scheme -> Run -> Options -> App Language
- 切换语言后,运行工程
应用内切换语言
纯代码本地化只能跟随系统进行切换,并不能手动进行切换,下面先介绍一下相关宏
1 2 3 4 5 6 7 8 9 10 11 12
| // 尾随系统切换, 多语言文件名称必须是Localizable NSLocalizedString("title", nil);
// 以下三个都能够手动设置多语言 // 第一个參数:是多语言中的key // 第二个參数:是多语言文件的名字 // 第三个參数:是对key的自定义的说明,一般传nil NSLocalizedStringFromTable(@"title", @"Localizable", nil); // 指定多语言文件名称和bundle NSLocalizedStringFromTableInBundle(@"title", @"Localizable", bundle, nil); // 在上面的基础上添加一个默认值的參数 NSLocalizedStringWithDefaultValue(@"title", @"Localizable", bundle, @"label", nil);
|
- Resources -> Show In Finder后,发现每一种语言都有对应的文件目录,后缀是
.lproj
总结:
1、因此 ar.lproj、en.lproj、fr.lproj、ru.lproj、zh-Hans.lproj、zh-Hant.lproj
为我们可以从本地获取到的 语言资源文件
2、在 App
内切换语言的时候,实际上就是获取 语言资源文件
的 Localizable.strings
文件
- 将所有的
语言文件
设置成 字符串类型的枚举
并且有初始值 rawValue
, 获取 Localizable.strings
- 获取
某语言
文件的 value值
,相应的想要切换语言的话,直接切换 pathForResource
面的 参数
就可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| // 本地化语言类型 enum LocalizedType: String { // 字符串需要对应本地的国际化文件名 .lproj case English = "en" // 英语 case ChineseHans = "zh-Hans" // 简体中文 case ChineseHant = "zh-Hant" // 繁体中文 case Russian = "ru" // 俄语 case Frcench = "fr" // 法语 }
// 获取语言文件路径(可以为:en/zh-Hans/zh-Hant/fr/ru 任意一个) let languageBundlePath = Bundle.main.path(forResource: LocalizedType.English, ofType: "lproj") // 获取语言文件路径下对应 key 的 value let value = Bundle(path: languageBundlePath ?? "")?.localizedString(forKey: "title", value: nil, table: "ZJLocalizable") MyLog(message: value)
|
- 根据上面的思路,我们可以用
NSUserDefaults
缓存当前的 语言
,以便 第一次启动程序
或 程序退出去后
,下次进入继续使用上次关闭程序的语言。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| // 本地化语言类型 enum LocalizedType: String { // 字符串需要对应本地的国际化文件名 .lproj case English = "en" // 英语 case ChineseHans = "zh-Hans" // 简体中文 case ChineseHant = "zh-Hant" // 繁体中文 case Russian = "ru" // 俄语 case Frcench = "fr" // 法语 }
// 初始化启动时语言 func initLaunchLanguage() { // 获取上一次设置的语言 var languageType = kUserDefault.getInfo(key: "appLanguage") // 如果是第一次启动 if languageType == nil { // 获取系统第一个首选语言 let systemLanguage = Locale.preferredLanguages.first! MyLog(message: systemLanguage) // 赋值给上一次设置的语言类型 if systemLanguage.hasPrefix(LocalizedType.English.rawValue) { // 英文 languageType = LocalizedType.English.rawValue }else if systemLanguage.hasPrefix(LocalizedType.ChineseHans.rawValue) { // 简体中文 languageType = LocalizedType.ChineseHans.rawValue }else if systemLanguage.hasPrefix(LocalizedType.ChineseHant.rawValue) { // 繁体中文 languageType = LocalizedType.ChineseHant.rawValue }else if systemLanguage.hasPrefix(LocalizedType.Frcench.rawValue) { // 法文 languageType = LocalizedType.Frcench.rawValue }else if systemLanguage.hasPrefix(LocalizedType.Russian.rawValue) { // 俄文 languageType = LocalizedType.Russian.rawValue }else { // 其他语言 languageType = systemLanguage } } // 缓存语言 kUserDefault.saveInfo(value: languageType!, key: "appLanguage") // 设置bundle setCurrentBundle() }
|
注:
每次设置完语言,我们跟要更新一下 bundle
,以便随时获取 key-value
- 接下来,我们要根据缓存的语言来获取本地语言资源文件,赋值给一个全局的
bundle
,以便随时可以通过 bundle
来拿到具体语言文件下的 key-value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| // 设置bundle func setCurrentBundle() { // 拿到当前语言 let currentLanguageType = kUserDefault.getInfo(key: "appLanguage") as! String // 获取本地语言资源路径 let languageBundlePath = Bundle.main.path(forResource: currentLanguageType, ofType: "lproj") // MyLog(message: languageBundlePath) guard languageBundlePath != nil else { return } // 获取 bundle let languageBundle = Bundle(path: languageBundlePath!) guard languageBundle != nil else { return } // 赋值给全局的 bundle currentBundle = languageBundle // MyLog(message: currentBundle) }
|
- 根据
key
获取 value
1 2 3 4 5 6
| // 获取要显示的文本 func getLanguageValueWithKey(key: String) -> String { let bundle = LocalizableManager.sharedManager.currentBundle let value = bundle?.localizedString(forKey: key, value: nil, table: nil) return value ?? "" }
|
- 至此,我们的
App内+系统
切换国际化语言,大功告成!!!