Writing in the front
This article synchronizes personal blog Jane Book MOOCs using Xcode 9.3 Swift4.1
preface
I’m sure you’ve all heard of language localization before, but what I’m going to share today is a quick way to do language localization, switching between in-app languages
The core content is mainly three parts
- Storyboard xib/localization
- Pure code localization
- Language switching
The preparatory work
Add languages to projects
Storyboard xib/localization
Storyboard/XIB localization Xcode is basically a one-click thing. It’s very easy to just check it and check it and check it and this is just an update issue and you can use ibtools to make storyboard/xib generate new code so CD to stroyboard/xib and run ibTool XXX.storyboard –generate-strings-file new.strings Opens new.strings to manually copy new content to the original string.
Pure code localization
Create string file
Check languages and tick all of them, including Base (in preparation for scripting code generation later)
Refer to this article to optimize the process for scripting to add multilingual localization in iOS
Move script execution above compilation
Add a script
# Localizable. Strings file path
localizableFile="${SRCROOT}/${PROJECT_NAME}/Support/en.lproj/Localizable.strings"
# Generated swift file path (modify according to personal habit)
localizedFile="${SRCROOT}/${PROJECT_NAME}/Source/Utils/LocalizedUtils.swift"
Convert the text in localizable. Strings to a swift constant and store it in a temporary file
sed "s/^\"/ static var localized_/g" "${localizableFile}" | sed "s/\" = \"/: String { return \"/g" | sed "s/; $/.localized }/g" > "${localizedFile}.tmp"
Output to the target file as a calculated property first
echo -e "import Foundation\n\nextension String {\n var localized: String { return NSLocalizedString(self, comment: self) }" > "${localizedFile}"
Output constant increments from the temporary file to the target file
cat "${localizedFile}.tmp" >> "${localizedFile}"
Add a "}" to the target file to complete the output
echo -e "\n}" >> "${localizedFile}"
Delete temporary files
rm "${localizedFile}.tmp"
Copy the code
Note that the directories must correspond properly; otherwise, an error will be reported
Build and automatically generate relevant code to use directly. For details, please refer to the above article on optimizing the multilingual localization process in iOS
Language switching
The basic principle of language switching is to use Userdefault to store the currently selected language and change its contents when setting
There are two main issues involved
- How does a storyboard/ XIb switch languages
- How to Refresh the interface
For the above are considered normal localization content, basically introduce localization tutorials will have. This is relatively new for automated scripts.
But the script for string generated content with Spaces or have a problem, because it is using the sed command, I also not very familiar, only want to other way, this time Base. Lproj will come in handy We will space are replaced with an underscore, or hump, naming, in Base on the en and useful to write the content of the concrete, The purpose of Base in this case is to facilitate automatic code generation. (If you don’t want to mess up the Base, create a new one.)
About storyboard/ XIB switching languages
To customize a Bundle by replacing the Bundle, override the localizedString method, get the current selected language from Userdefault each time, and use method substitution to replace bundle. main with the custom Bundle
enum Language : String {
case english = "en"
case chinese = "zh-Hans"
}
/** * Replace mainBundle with the current language bundle */ when onLanguage is called
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 = {
// Replace bundlemain with a custom BundleEx
object_setClass(Bundle.main, BundleEx.self)}func onLanguage(a){
Bundle.onLanguageDispatchOnce()
}
class func getLanguageBundel() - >Bundle? {
let languageBundlePath = Bundle.main.path(forResource: UserDefaults.standard[AppStatic.kCurrentLanguage] as? String, ofType: "lproj")
// print("path = \(languageBundlePath)")
guardlanguageBundlePath ! =nil else {
return nil
}
let languageBundle = Bundle.init(path: languageBundlePath!)
guardlanguageBundle ! =nil else {
return nil
}
returnlanguageBundle! }}Copy the code
There is a custom subscript for Userdefault
public subscript(key: String) - >Any? {
get {
return object(forKey: key)
}
set {
set(newValue, forKey: key)
}
}
Copy the code
Execute bundle.main.onlanguage () once when reading the string
I wrote it directly into the script and modified the script as follows (note the path of several files).
# Localizable. Strings file path
localizableFile="${SRCROOT}/Base.lproj/Localizable.strings"
# Generated swift file path (modify according to personal habit)
localizedFile="${SRCROOT}/Public/LocalizedUtils.swift"
Convert the text in localizable. Strings to a swift constant and store it in a temporary file
sed "s/^\"/ static var localized_/g" "${localizableFile}" | sed "s/\" = \"/: String { return \"/g" | sed "s/; $/.localized }/g" > "${localizedFile}.tmp"
Output to the target file as a calculated property first
echo -e "import Foundation\n\nextension String {\n var localized: String { Bundle.main.onLanguage() \n return NSLocalizedString(self, comment: self) }" > "${localizedFile}"
Output constant increments from the temporary file to the target file
cat "${localizedFile}.tmp" >> "${localizedFile}"
Add a "}" to the target file to complete the output
echo -e "\n}" >> "${localizedFile}"
Delete temporary files
rm "${localizedFile}.tmp"
Copy the code
About refreshing the interface
The easiest way to refresh any interface is to reset the rootViewController and turn keyWindow black, pretend to be loading for a few seconds, and then change back. If you need to go back to the previous page, add the corresponding way to jump to VC
func chooseLanguage(a) {
DispatchQueue.global().async {
let sheet = UIAlertController.init(title: String.localized_Choose_Language, message: nil, preferredStyle: .actionSheet)
sheet.addAction(UIAlertAction.init(title: String.localized_English, style: .default, handler: { (action) in
UserDefaults.standard[AppStatic.kCurrentLanguage] = Language.english.rawValue
UIApplication.shared.keyWindow? .rootViewController =RedbotTabBar(a)UIApplication.shared.keyWindow? .alpha =0
AlertHelper.showHudWithMessage(message: "Setting Language...")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1, execute: {
UIView.animate(withDuration: 1, animations: {UIApplication.shared.keyWindow? .alpha =1})
AlertHelper.hideHudMessage()
})
}))
sheet.addAction(UIAlertAction.init(title: String.localized_Chinese, style: .default, handler: { (action) in
UserDefaults.standard[AppStatic.kCurrentLanguage] = Language.chinese.rawValue
UIApplication.shared.keyWindow? .rootViewController =RedbotTabBar(a)UIApplication.shared.keyWindow? .alpha =0
AlertHelper.showHudWithMessage(message: "Setting Language...")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1, execute: {
UIView.animate(withDuration: 1, animations: {UIApplication.shared.keyWindow? .alpha =1})
AlertHelper.hideHudMessage()
})
}))
sheet.addAction(UIAlertAction.init(title: String.localized_Cancel, style: .cancel, handler: nil))
self.present(sheet, animated: true, completion: nil)}}Copy the code
So far App language switch and localization are all finished, isn’t it very simple ~~
Afterword.
For ordinary small projects, localizing content is far less complicated and requires little replacement. Once you add a language, it’s easy to add a new one.
Refer to the article: http://www.cocoachina.com/ios/20170809/20190.html