在做跨國項目的時候經常需要使用本地化的技術,但是在開發過程中往往需要提交給測試者一個測試人員能夠看得懂的版本,通過runtime機制可以實現強制應用使用指定語言,具體代碼如下:
var kBundleKey = "kBundleKey"
class ExBundle: Bundle {
override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
let b = objc_getAssociatedObject(self, &kBundleKey) as? Bundle
if b == nil { return super.localizedString(forKey: key, value: value, table: tableName) }
return b!.localizedString(forKey: key, value: value, table: tableName)
}
}
首先創建一個ExBundle類繼承自Bundle,重寫方法localizedString,這個方法無論是加在localizable.strings文件還是使用xib或者storyboard文件的多語言時都會調用該方法,例如你調用NSLocalizedString最終應用會調用Bundle的localizedString去查找指定tableName下的key並返回值。再來看下面的代碼:
// AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
object_setClass(Bundle.main, ExBundle.classForCoder())
let path = Bundle.main.path(forResource: "zh-Hans", ofType: "lproj")
let bundle = Bundle.init(path: path!)
objc_setAssociatedObject(Bundle.main, &kBundleKey, bundle, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return true
}
通過runtime機制,將Bundle.main對象的類型設置爲ExBundle,並且通過objc_setAssociatedObject方法爲Bundle.main對象設置一個爲bundle屬性,該bundle對象就是指向指定多語言的文件夾。
最後如果程序內有任何使用多語言的地方,都會根據kBundleKey取出bundle對象,通過bundle對象的localizedString來返回文言。