前言
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