前言
APP内部语言国际化非常常见,但唯独有一个阿拉伯语言的时候,APP是需要通过镜像来显示的,由于之前没写过阿拉伯语言不知其特性,下面我用代码来实现。
⚠️ 除了我们添加的几种语言,infoPlist 也要哦

image.png
定义一个枚举
enum LanguageType: String {
    
    /// 繁体
    case chinese = "zh-Hant"
    /// 英语
    case english = "en"
    /// 阿拉伯语
    case arabic = "ar"
    /// 俄语
    case russian = "ru"
    /// 法语
    case french = "fr"
    /// 葡萄牙语
    case portuguese = "pt"
    /// 西班牙语
    case spanish = "es"
    
    var httpLangValue: String! {
        var str = ""
        switch self {
        case .chinese:
            str = "zh-TW"
        case .English:
            str = "en-US"
        case .arabic:
            str = "ar-AE"
        case .russian:
            str = "ru-RU"
        case .French:
            str = "fr-FR"
        case .portuguese:
            str = "pt-PT"
        case .spanish:
            str = "es-ES"
        }
        return str
    }
    
}
创建一个单例,来执行整个app的国际化语言管理。
设置/切换语言-启动自动识别上次语言
import Foundation
import UIKit
import MJRefresh
import TZImagePickerController
import WebKit
private var Label_LocalizationKey: Void?
private var Button_LocalizationKey: Void?
private var TextField_LocalizationKey: Void?
private var SPTextView_LocalizationKey: Void?
private var UIBarButtonItem_LocalizationKey: Void?
private var UITabBarItem_LocalizationKey: Void?
private var UINavigationItem_LocalizationKey: Void?
class LanguageManager {
    
    static let share = LanguageManager()
    
    /// 当前语言包
    public var bundle: Bundle?
    
    /// 当前语言类型
    public var currentLanguage: LanguageType! {
        return LanguageType(rawValue: language) ?? .English
    }
    
    /// 是否是需要镜像
    public var isNeedMirror: Bool {
        return currentLanguage == .arabic
    }
    
    private let languageKey: String = "LocalLanguageKey"
    
    private(set) var language: String! {
        didSet {
            UserDefaults.standard.setValue(language, forKey: languageKey)
        }
    }
    
    private init() {
        
    }
    
    /// 初始化语言包
    public func reloadLanguage() {
        
        language = UserDefaults.standard.string(forKey: languageKey)
        
        if stringIsEmpty(str: language) {
            let languages = Locale.preferredLanguages
            guard let first = languages.first else { return }
            // 除了有国际化的语言, 其他默认英语
            if first.hasPrefix("zh") {
                language = LanguageType.chinese.rawValue
            } else if first.hasPrefix("ar") {
                language = LanguageType.arabic.rawValue
            } else if first.hasPrefix("ru") {
                language = LanguageType.russian.rawValue
            } else if first.hasPrefix("fr") {
                language = LanguageType.french.rawValue
            } else if first.hasPrefix("pt") {
                language = LanguageType.portuguese.rawValue
            } else if first.hasPrefix("es") {
                language = LanguageType.spanish.rawValue
            } else {
                language = LanguageType.english.rawValue
            }
        }
        
        setLanguage(currentLanguage)
    }
    
    /// 切换语言
    public func switchLanguage(_ languageType: LanguageType) {
        
        language = languageType.rawValue
        
       // 设置一些第三方框架的内置语言
        setLanguage(languageType)
        
       //重置整个应用,内部设置了直接跳转到您所在设置语言界面
        TabbarManager.share.resetWithLanguage()
        
        // 通知页面刷新UI
        NotificationCenter.default.post(name: LanguageChangeNC, object: nil)
    }
    
    /// 设置语言
    private func setLanguage(_ languageType: LanguageType) {
        
        // 设置第三方语言
        MJRefreshConfig.default.languageCode = languageType.rawValue
        TZImagePickerConfig.sharedInstance().preferredLanguage = languageType.rawValue
        
        // 更新http请求
        HttpRequestUtil.share.updateHeaders(name: "Accept-Language", value: languageType.httpLangValue)
        SocketUtil.share.updateHeaders(name: "Accept-Language", value: languageType.httpLangValue)
        
        // 加载语言包
        if let path = Bundle.main.path(forResource: language, ofType: "lproj") {
            bundle = Bundle(path: path)
        } else {
            bundle = Bundle.main
        }
        
        viewMirror(isMirror: isNeedMirror)
    }
    
    /// 全局控件视图镜像
    private func viewMirror(isMirror: Bool) {
        if isMirror {
            UIView.appearance().semanticContentAttribute = .forceRightToLeft
            UISearchBar.appearance().semanticContentAttribute = .forceRightToLeft
            UITextField.appearance().textAlignment = .right
            UITextView.appearance().textAlignment = .right
            WKWebView.appearance().semanticContentAttribute = .forceRightToLeft
        } else {
            UIView.appearance().semanticContentAttribute = .forceLeftToRight
            UISearchBar.appearance().semanticContentAttribute = .forceLeftToRight
            UITextField.appearance().textAlignment = .left
            UITextView.appearance().textAlignment = .left
            WKWebView.appearance().semanticContentAttribute = .forceLeftToRight
        }
    }
    
}
// MARK: - Extension - String
extension String {
    
    public var localized: String {
        if let bundle = LanguageManager.share.bundle {
            return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
        } else {
            return self
        }
    }
    
}
// MARK: - Extension - UILabel
extension UILabel {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.text = newValue.localized
            objc_setAssociatedObject(self, &Label_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &Label_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - UIButton
extension UIButton {
    
    @IBInspectable
    var localizationKey: String {
        set {
            setTitle(newValue.localized, for: .normal)
            objc_setAssociatedObject(self, &Button_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &Button_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - UITextField
extension UITextField {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.placeholder = newValue.localized
            objc_setAssociatedObject(self, &TextField_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &TextField_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - SPTextView
extension SPTextView {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.placeholder = newValue.localized
            objc_setAssociatedObject(self, &SPTextView_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &SPTextView_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - UIBarButtonItem
extension UIBarButtonItem {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.title = newValue.localized
            objc_setAssociatedObject(self, &UIBarButtonItem_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &UIBarButtonItem_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - UITabBarItem
extension UITabBarItem {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.title = newValue.localized
            objc_setAssociatedObject(self, &UITabBarItem_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &UITabBarItem_LocalizationKey) as? String ?? ""
        }
    }
    
}
// MARK: - Extension - UINavigationItem
extension UINavigationItem {
    
    @IBInspectable
    var localizationKey: String {
        set {
            self.title = newValue.localized
            objc_setAssociatedObject(self, &UINavigationItem_LocalizationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &UINavigationItem_LocalizationKey) as? String ?? ""
        }
    }
    
}
tabbar 管理工具实现重制方法
  /// 重新设置语言
    public func resetWithLanguage() {
        
        mainTC.setChildVCs()
        
        if let nav = mainTC.viewControllers?[4] as? BaseNavigationController {
            //找到所在的设置界面并且跳转,这个操作是无感的,但是会闪动一下,和微信类似
            let settingsVC = UserSetVC.fromStoryboard(name: UserSN)
            settingsVC.hidesBottomBarWhenPushed = true
            nav.pushViewController(settingsVC, animated: false) 
        }
    }
  /// 设置子控制器
    public func setChildVCs() {
        
        let homeVC = CommonUtil.createVC(name: HomeSN, identifier: HomeVC.className)
        let homeNav = getChildController(childVC: homeVC, selectedImageName: "tabbar_home_selected", normalImageName: "tabbar_home_normal")
        
        let followVC = CommonUtil.createVC(name: FollowSN, identifier: FollowVC.className)
        let followNav = getChildController(childVC: followVC, selectedImageName: "tabbar_follow_selected", normalImageName: "tabbar_follow_normal")
        
        let addVC = TabbarAddVC()
        let addNav = getChildController(childVC: addVC, selectedImageName: "tabbar_add", normalImageName: "tabbar_add")
        
        let chatVC = CommonUtil.createVC(name: ChatSN, identifier: NotificationListVC.className)
        let chatNav = getChildController(childVC: chatVC, selectedImageName: "tabbar_notify_selected", normalImageName: "tabbar_notify_normal")
        
        let userVC = CommonUtil.createVC(name: UserSN, identifier: UserVC.className)
        let userNav = getChildController(childVC: userVC, selectedImageName: "tabbar_my_selected", normalImageName: "tabbar_my_normal")
        
        setViewControllers([homeNav, followNav, addNav, chatNav, userNav], animated: false)
    }
 
    /// 设置子页面
    private func getChildController(childVC: UIViewController, selectedImageName: String, normalImageName: String) -> BaseNavigationController {
        
        childVC.tabBarItem.title = ""
        
        let selectedImage = UIImage(named: selectedImageName)?.withRenderingMode(.alwaysOriginal)
        childVC.tabBarItem.selectedImage = selectedImage
        
        let normalImage = UIImage(named: normalImageName)?.withRenderingMode(.alwaysOriginal)
        childVC.tabBarItem.image = normalImage
        
        let nav = BaseNavigationController(rootViewController: childVC)
        return nav
    }
部分箭头镜像 可以事实根据这个是否选择了阿拉伯语言来决定
extension UIImage {
    
    func cn_imageFlippedForRightToLeftLayoutDirection() -> UIImage {
        
        if LanguageManager.share.isNeedMirror, let cgImage = self.cgImage {
            return UIImage(cgImage: cgImage, scale: self.scale, orientation: .upMirrored)
        }
        
        return self
    } 
} 
使用就是动态的
 let img = UIImage(named: "icon")?.cn_imageFlippedForRightToLeftLayoutDirection()
调用.localized 即可,我这边的key用中文标识比较好识别记忆。
title = "发布动态".localized
pleaceHold.text = "分享你此刻的想法".localized