本地化APP(变更APP语言)

缘由:

若客户端使用者不只单一国家,就会需要有变更app语言的功能,
之前查了一些资讯都是需要退出後才能变更语言包,
然後我有找到网路神人Roman Sorochak写的范例,不用退出app就能变更语言包,觉得超棒的

实作:

前置作业:

将所有元件先与viewcontroller连结好,且将所有元件的String都设定好
续前篇的布局,加上一个变更语言的按钮,因为想区别一下与Storyboard上是不同语言所以会以英文、日文、韩文作为变更语言的示范

示范:

@IBOutlet weak var infoTextView: UITextView!
 override func viewDidLoad() {
      super.viewDidLoad()
      infoTextView.text = "Please enter your basic information"
  }

本地化Localizable档案

创建Localizable.strings的新档案
https://ithelp.ithome.com.tw/upload/images/20210917/20130757w2FVp9Fdnj.png
https://ithelp.ithome.com.tw/upload/images/20210917/20130757PoyaIyGkft.png

点击Localizable按钮
https://ithelp.ithome.com.tw/upload/images/20210917/20130757j3Fr34gTow.png

接着到Project Navigator中的Project下的info
可以在红框处添加新的语言包,如下图
https://ithelp.ithome.com.tw/upload/images/20210917/20130757D54qhQpcCn.png
https://ithelp.ithome.com.tw/upload/images/20210917/201307578gBBBH3IDx.png
https://ithelp.ithome.com.tw/upload/images/20210917/20130757ts0rWTz6f4.png
各种语言都可以以此方式创建语言包

Extension String 与 Bundle

import UIKit

extension String {
    //在String後添加.localized即可以转用设定之本地化字串
    var localized: String {
        return Bundle.localizedBundle.localizedString(forKey: self, value: nil, table: nil)
    }
    
    //在图片档名後添加.localizedImage即可以使用该语言包内相应档名的图片
    var localizedImage: UIImage? {
        return localizedImage()
            ?? localizedImage(type: ".png")
            ?? localizedImage(type: ".jpg")
            ?? localizedImage(type: ".jpeg")
            ?? UIImage(named: self)
    }
    
    private func localizedImage(type: String = "") -> UIImage? {
        guard let imagePath = Bundle.localizedBundle.path(forResource: self, ofType: type) else {
            return nil
        }
        return UIImage(contentsOfFile: imagePath)
    }
}

extension Bundle {
    static var localizedBundle: Bundle {
        let languageCode = Language.language.rawValue
        guard let path = Bundle.main.path(forResource: languageCode, ofType: "lproj") else {
            return Bundle.main
        }
        return Bundle(path: path)!
    }
}

列举要更换的语言包

private let appleLanguagesKey = "AppleLanguages"

enum Language: String {
    
    case english = "en"
    case Japanese = "ja"
    case Korean = "ko"       
    
    static var language: Language {
        get {
            if let languageCode = UserDefaults.standard.string(forKey: appleLanguagesKey),
                let language = Language(rawValue: languageCode) {
                return language
            } else {
		//获取偏好语言第一顺位的字段
                let preferredLanguage = NSLocale.preferredLanguages[0] as String
                let index = preferredLanguage.index(
                    preferredLanguage.startIndex,
                    offsetBy: 2
                )
		//本地化语言包中若有与偏好语言第一顺位相符的语言包,则显示该语言包,若无相符,一律显示英文
                guard let localization = Language(
                    rawValue: preferredLanguage.substring(to: index)
                    ) else {
                        return Language.english
                }
                
                return localization
            }
        }
        set {
            guard language != newValue else {
                return
            }
	    //变更app内中的语言
            UserDefaults.standard.set([newValue.rawValue], forKey: appleLanguagesKey)
	    //要执行synchronize()才会真的写入资料中
            UserDefaults.standard.synchronize()
            UIApplication.shared.windows[0].rootViewController = UIStoryboard(
                name: "Main",
                bundle: nil
                ).instantiateInitialViewController()
        }
    }
}

Viewcontroller中的本地化范例:

将前置作业中设定好的字串後面加上.localized

示范:
infoTextView.text = "Please enter your basic information".localized

然後将变更语言的按钮”Touch up inside”连结至viewcontroller中,使用弹窗功能将各语言选项放进弹窗中,
点击该语言按钮後,即可以更换语言包

示范:

@IBAction func changeLanguage(_ sender: Any) {
        let alert = UIAlertController(
            title: "alert_change_language_title".localized,
            message: nil,
            preferredStyle: .actionSheet
        )
        
        func addActionLanguage(language: Language) {
            alert.addAction(
                UIAlertAction(
                    title: language.rawValue.localized,
                    style: UIAlertAction.Style.default,
                    handler: { _ in
                        Language.language = language
                })
            )
        }
        addActionLanguage(language: Language.english)
        addActionLanguage(language: Language.Japanese)
        addActionLanguage(language: Language.Korean)
        
        alert.addAction(
            UIAlertAction(
                title: "alert_cancel".localized,
                style: UIAlertAction.Style.cancel,
                handler: nil
            )
        )
        present(alert, animated: true, completion: nil)
    }

Localizable.strings的本地化字串设定

将要本地化的字串列好(XXXXX.localized中的XXXXX),然後更新切换成该语言包时要显示的字串

示范:
英文
"Please enter your basic information" = "Please enter your basic information";
日文
"Please enter your basic information" = "基本情报を入力してください";
韩文
"Please enter your basic information" = "기본정보를 입력해주세요";

以上变更语言的功能完成!


<<:  [Day 2] 阿嬷都看得懂的前端与後端怎麽分

>>:  30天学会C语言: Day 1-C语言起手式

Day14.进入 ARM 世界: ARM Instruction Sets

继续探讨我们昨天没完成的 ARM Instruction Sets。 Reverse Orderin...

Day 18. Hashicorp Vault: Audit log (1)

Hashicorp Vault: Audit log 启用audit log的设定不在设定档内,而是...

Day 5 双向绑定及回圈

今天来介绍v-model&data跟v-for的用法 data→用来储存里面的资料,当dat...

Day12 天气API小实作2

继续昨天的进度,首先,因为我们用了pickerview所以要扩充UI功能,写在第十一行後。 写完之後...

Day29 - 以 NodeJS 留言板走过 GitOps 工作流程

前言 今天我们以开发者的角度,实际走过 GitOps 的工作流程,这次 Lab 准备了 NodeJS...