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