多语言开发
This commit is contained in:
parent
e8b2c4668f
commit
fa0db110b6
78
MoviaBox.xcodeproj/xcshareddata/xcschemes/MoviaBox.xcscheme
Normal file
78
MoviaBox.xcodeproj/xcshareddata/xcschemes/MoviaBox.xcscheme
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1620"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1DBC40582DA4EDFC0093FCB0"
|
||||||
|
BuildableName = "MoviaBox.app"
|
||||||
|
BlueprintName = "MoviaBox"
|
||||||
|
ReferencedContainer = "container:MoviaBox.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1DBC40582DA4EDFC0093FCB0"
|
||||||
|
BuildableName = "MoviaBox.app"
|
||||||
|
BlueprintName = "MoviaBox"
|
||||||
|
ReferencedContainer = "container:MoviaBox.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1DBC40582DA4EDFC0093FCB0"
|
||||||
|
BuildableName = "MoviaBox.app"
|
||||||
|
BlueprintName = "MoviaBox"
|
||||||
|
ReferencedContainer = "container:MoviaBox.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
@ -29,7 +29,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
|
|
||||||
// SPLoginManager.manager.requestVisitorLogin(completer: nil)
|
// SPLoginManager.manager.requestVisitorLogin(completer: nil)
|
||||||
SPLoginManager.manager.updateUserInfo(completer: nil)
|
SPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
///更新本地多语言
|
||||||
|
SPLocalizedManager.shared.updateLocalizedData(completer: nil)
|
||||||
///注册消息通知
|
///注册消息通知
|
||||||
registerAPNS()
|
registerAPNS()
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
|
|
||||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||||
guard let windowScene = (scene as? UIWindowScene) else { return }
|
guard let windowScene = (scene as? UIWindowScene) else { return }
|
||||||
|
///监听语言切换
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(localizedDidChange), name: SPLocalizedManager.localizedDidChange, object: nil)
|
||||||
|
|
||||||
let tabBarController = SPTabBarController()
|
let tabBarController = SPTabBarController()
|
||||||
SPAPPTool.mainTabBarController = tabBarController
|
SPAPPTool.mainTabBarController = tabBarController
|
||||||
|
|
||||||
@ -93,4 +96,13 @@ extension SceneDelegate {
|
|||||||
|
|
||||||
handleOpenAppMessage(webpageURL: nil)
|
handleOpenAppMessage(webpageURL: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///语言切换
|
||||||
|
@objc private func localizedDidChange() {
|
||||||
|
let tabBarController = SPTabBarController()
|
||||||
|
SPAPPTool.mainTabBarController = tabBarController
|
||||||
|
|
||||||
|
window?.rootViewController = tabBarController
|
||||||
|
window?.makeKeyAndVisible()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,5 +400,9 @@ extension UIColor {
|
|||||||
static func colorA8B8C3(alpha: CGFloat = 1) -> UIColor {
|
static func colorA8B8C3(alpha: CGFloat = 1) -> UIColor {
|
||||||
return color(hex: 0xA8B8C3, alpha: alpha)
|
return color(hex: 0xA8B8C3, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func color321F1F(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0x321F1F, alpha: alpha)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
MoviaBox/Base/Networking/API/SPSettingAPI.swift
Normal file
38
MoviaBox/Base/Networking/API/SPSettingAPI.swift
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// SPSettingAPI.swift
|
||||||
|
// MoviaBox
|
||||||
|
//
|
||||||
|
// Created by 佳尔 on 2025/5/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPSettingAPI: NSObject {
|
||||||
|
|
||||||
|
///获取语言列表
|
||||||
|
static func requestLanguageList(completer: ((_ list: [SPLanguageModel]?) -> Void)?) {
|
||||||
|
|
||||||
|
var param = SPNetworkParameters(path: "/languges")
|
||||||
|
param.method = .get
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPListModel<SPLanguageModel>>) in
|
||||||
|
completer?(response.data?.list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///获取语言数据
|
||||||
|
static func requestLocalizedData(key: String, completer: ((_ model: SPLocalizedModel?) -> Void)?) {
|
||||||
|
var param = SPNetworkParameters(path: "/translates")
|
||||||
|
param.method = .get
|
||||||
|
param.parameters = [
|
||||||
|
"lang_key" : key
|
||||||
|
]
|
||||||
|
|
||||||
|
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPLocalizedModel>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
125
MoviaBox/Class/Mine/Controller/SPLanguageViewController.swift
Normal file
125
MoviaBox/Class/Mine/Controller/SPLanguageViewController.swift
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//
|
||||||
|
// SPLanguageViewController.swift
|
||||||
|
// MoviaBox
|
||||||
|
//
|
||||||
|
// Created by 佳尔 on 2025/5/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPLanguageViewController: SPViewController {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var dataArr: [SPLanguageModel] = []
|
||||||
|
|
||||||
|
private lazy var currentLocalizedKey = SPLocalizedManager.shared.currentLocalizedKey
|
||||||
|
|
||||||
|
private lazy var tableView: SPTableView = {
|
||||||
|
let tableView = SPTableView(frame: .zero, style: .insetGrouped)
|
||||||
|
tableView.delegate = self
|
||||||
|
tableView.dataSource = self
|
||||||
|
tableView.sectionFooterHeight = 0
|
||||||
|
tableView.tableHeaderView = UIView()
|
||||||
|
tableView.rowHeight = 60
|
||||||
|
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin + 10, right: 0)
|
||||||
|
SPLanguageCell.registerCell(tableView: tableView)
|
||||||
|
return tableView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
self.edgesForExtendedLayout = .top
|
||||||
|
self.title = "Language".localized
|
||||||
|
|
||||||
|
requestDataList()
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
|
||||||
|
// SPSettingAPI.requestLocalizedData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
|
setNavigationNormalStyle(backgroundColor: .clear, isTranslucent: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPLanguageViewController {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
view.addSubview(tableView)
|
||||||
|
|
||||||
|
tableView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(kSPNavBarHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- UITableViewDelegate & UITableViewDataSource --------------
|
||||||
|
extension SPLanguageViewController: UITableViewDelegate, UITableViewDataSource {
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
|
let model = dataArr[indexPath.section]
|
||||||
|
let cell = SPLanguageCell.dequeueReusableCell(tableView: tableView, indexPath: indexPath)
|
||||||
|
cell.model = model
|
||||||
|
cell.sp_isSelected = model.lang_key == currentLocalizedKey
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return self.dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||||
|
return 12
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
|
let model = dataArr[indexPath.section]
|
||||||
|
if model.lang_key == currentLocalizedKey { return }
|
||||||
|
|
||||||
|
if let key = model.lang_key {
|
||||||
|
SPHUD.show()
|
||||||
|
SPLocalizedManager.shared.updateLocalizedData(key: key) { (finish) in
|
||||||
|
if finish {
|
||||||
|
SPLocalizedManager.shared.currentLocalizedKey = key
|
||||||
|
NotificationCenter.default.post(name: SPLocalizedManager.localizedDidChange, object: nil)
|
||||||
|
}
|
||||||
|
SPHUD.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPLanguageViewController {
|
||||||
|
|
||||||
|
private func requestDataList() {
|
||||||
|
SPSettingAPI.requestLanguageList { [weak self] list in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
if let list = list {
|
||||||
|
self.dataArr = list
|
||||||
|
self.tableView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,7 @@ class SPMineViewController: SPViewController {
|
|||||||
|
|
||||||
private lazy var dataArr: [SPMineItem] = {
|
private lazy var dataArr: [SPMineItem] = {
|
||||||
let arr = [
|
let arr = [
|
||||||
// SPMineItem(type: .language, iconImage: UIImage(named: "language_icon_01"), title: "Language".localized),
|
SPMineItem(type: .language, iconImage: UIImage(named: "language_icon_01"), title: "Language".localized),
|
||||||
SPMineItem(type: .feedBack, iconImage: UIImage(named: "feed_back_icon_01"), title: "FeedBack".localized),
|
SPMineItem(type: .feedBack, iconImage: UIImage(named: "feed_back_icon_01"), title: "FeedBack".localized),
|
||||||
SPMineItem(type: .privacyPolicy, iconImage: UIImage(named: "privacy_policy_icon_01"), title: "Privacy Policy".localized),
|
SPMineItem(type: .privacyPolicy, iconImage: UIImage(named: "privacy_policy_icon_01"), title: "Privacy Policy".localized),
|
||||||
SPMineItem(type: .userAgreement, iconImage: UIImage(named: "user_agreement_icon_01"), title: "User Agreement".localized),
|
SPMineItem(type: .userAgreement, iconImage: UIImage(named: "user_agreement_icon_01"), title: "User Agreement".localized),
|
||||||
@ -138,6 +138,10 @@ extension SPMineViewController: UITableViewDelegate, UITableViewDataSource {
|
|||||||
let vc = SPSettingsViewController()
|
let vc = SPSettingsViewController()
|
||||||
self.navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case .language:
|
||||||
|
let vc = SPLanguageViewController()
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
22
MoviaBox/Class/Mine/Model/SPLanguageModel.swift
Normal file
22
MoviaBox/Class/Mine/Model/SPLanguageModel.swift
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// SPLanguageModel.swift
|
||||||
|
// MoviaBox
|
||||||
|
//
|
||||||
|
// Created by 佳尔 on 2025/5/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class SPLanguageModel: SPModel, SmartCodable {
|
||||||
|
|
||||||
|
var cn_name: String?
|
||||||
|
var show_name: String?
|
||||||
|
var id: String?
|
||||||
|
var is_up_to_list: String?
|
||||||
|
var lang_key: String?
|
||||||
|
// var description: String?
|
||||||
|
///1:当前语言
|
||||||
|
var is_default: Int?
|
||||||
|
|
||||||
|
}
|
91
MoviaBox/Class/Mine/View/SPLanguageCell.swift
Normal file
91
MoviaBox/Class/Mine/View/SPLanguageCell.swift
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// SPLanguageCell.swift
|
||||||
|
// MoviaBox
|
||||||
|
//
|
||||||
|
// Created by 佳尔 on 2025/5/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SPLanguageCell: SPTableViewCell {
|
||||||
|
|
||||||
|
var model: SPLanguageModel? {
|
||||||
|
didSet {
|
||||||
|
titleLabel.text = model?.show_name
|
||||||
|
|
||||||
|
if model?.is_default == 1 {
|
||||||
|
self.contentView.layer.borderColor = UIColor.colorFF3232().cgColor
|
||||||
|
self.selectedButton.isSelected = true
|
||||||
|
} else {
|
||||||
|
self.contentView.layer.borderColor = UIColor.clear.cgColor
|
||||||
|
self.selectedButton.isSelected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sp_isSelected = false {
|
||||||
|
didSet {
|
||||||
|
if sp_isSelected {
|
||||||
|
self.contentView.layer.borderColor = UIColor.colorFF3232().cgColor
|
||||||
|
self.selectedButton.isSelected = true
|
||||||
|
} else {
|
||||||
|
self.contentView.layer.borderColor = UIColor.clear.cgColor
|
||||||
|
self.selectedButton.isSelected = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontMedium(ofSize: 14)
|
||||||
|
label.textColor = .colorFFFFFF()
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var selectedButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom)
|
||||||
|
button.isUserInteractionEnabled = false
|
||||||
|
button.setImage(UIImage(named: "check_icon_01"), for: .normal)
|
||||||
|
button.setImage(UIImage(named: "check_icon_01_selected"), for: .selected)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
|
self.contentView.backgroundColor = .color321F1F()
|
||||||
|
self.contentView.layer.borderWidth = 1
|
||||||
|
self.contentView.layer.cornerRadius = 10
|
||||||
|
self.contentView.layer.masksToBounds = true
|
||||||
|
|
||||||
|
|
||||||
|
_setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SPLanguageCell {
|
||||||
|
|
||||||
|
private func _setupUI() {
|
||||||
|
contentView.addSubview(titleLabel)
|
||||||
|
contentView.addSubview(selectedButton)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedButton.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,38 +9,55 @@ import UIKit
|
|||||||
|
|
||||||
class SPLocalizedManager: NSObject {
|
class SPLocalizedManager: NSObject {
|
||||||
static let shared = SPLocalizedManager()
|
static let shared = SPLocalizedManager()
|
||||||
|
private let LocalizedUserDefaultsKey = "SPLocalizedManager.LocalizedUserDefaultsKey"
|
||||||
|
private let LocalizedDataUserDefaultsKey = "SPLocalizedManager.LocalizedDataUserDefaultsKey"
|
||||||
|
|
||||||
private let userDefaultsKey = "AppLocalized"
|
|
||||||
|
///语言列表
|
||||||
|
var languageList: [SPLanguageModel]?
|
||||||
|
|
||||||
|
///多语言数据
|
||||||
|
private lazy var localizedData: [String : String]? = UserDefaults.standard.object(forKey: LocalizedDataUserDefaultsKey) as? [String : String]
|
||||||
|
{
|
||||||
|
didSet {
|
||||||
|
UserDefaults.standard.set(localizedData, forKey: LocalizedDataUserDefaultsKey)
|
||||||
|
UserDefaults.standard.synchronize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取当前语言代码(如果用户未手动设置,则返回系统语言)
|
// 获取当前语言代码(如果用户未手动设置,则返回系统语言)
|
||||||
var currentLocalizedKey: String {
|
var currentLocalizedKey: String {
|
||||||
get {
|
get {
|
||||||
// return UserDefaults.standard.string(forKey: userDefaultsKey) ?? Locale.preferredLanguages.first ?? "en"
|
// return UserDefaults.standard.string(forKey: userDefaultsKey) ?? Locale.preferredLanguages.first ?? "en"
|
||||||
return "en"
|
return UserDefaults.standard.string(forKey: LocalizedUserDefaultsKey) ?? "en"
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
UserDefaults.standard.set(newValue, forKey: userDefaultsKey)
|
UserDefaults.standard.set(newValue, forKey: LocalizedUserDefaultsKey)
|
||||||
UserDefaults.standard.synchronize()
|
UserDefaults.standard.synchronize()
|
||||||
NotificationCenter.default.post(name: SPLocalizedManager.localizedDidChange, object: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否跟随系统
|
// 判断是否跟随系统
|
||||||
var isFollowingSystem: Bool {
|
var isFollowingSystem: Bool {
|
||||||
return UserDefaults.standard.string(forKey: userDefaultsKey) == nil
|
return UserDefaults.standard.string(forKey: LocalizedUserDefaultsKey) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 还原为系统默认语言
|
// 还原为系统默认语言
|
||||||
func resetToSystemLanguage() {
|
func resetToSystemLanguage() {
|
||||||
UserDefaults.standard.removeObject(forKey: userDefaultsKey)
|
UserDefaults.standard.removeObject(forKey: LocalizedUserDefaultsKey)
|
||||||
UserDefaults.standard.synchronize()
|
UserDefaults.standard.synchronize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取本地化字符串
|
// 获取本地化字符串
|
||||||
func localizedString(forKey key: String, tableName: String? = nil) -> String {
|
func localizedString(forKey key: String, tableName: String? = nil) -> String {
|
||||||
if let selectedLanguage = UserDefaults.standard.string(forKey: userDefaultsKey),
|
if let localizedData = localizedData,
|
||||||
|
let text = localizedData[key] {
|
||||||
|
return text
|
||||||
|
|
||||||
|
} else if let selectedLanguage = UserDefaults.standard.string(forKey: LocalizedUserDefaultsKey),
|
||||||
let bundlePath = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj"),
|
let bundlePath = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj"),
|
||||||
let bundle = Bundle(path: bundlePath) {
|
let bundle = Bundle(path: bundlePath) {
|
||||||
|
|
||||||
return bundle.localizedString(forKey: key, value: nil, table: tableName)
|
return bundle.localizedString(forKey: key, value: nil, table: tableName)
|
||||||
} else {
|
} else {
|
||||||
return NSLocalizedString(key, tableName: tableName, bundle: .main, value: "", comment: "")
|
return NSLocalizedString(key, tableName: tableName, bundle: .main, value: "", comment: "")
|
||||||
@ -48,6 +65,31 @@ class SPLocalizedManager: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SPLocalizedManager {
|
||||||
|
///获取本地化数据
|
||||||
|
func updateLocalizedData(key: String = SPLocalizedManager.shared.currentLocalizedKey, completer: ((_ finish: Bool) -> Void)?) {
|
||||||
|
SPSettingAPI.requestLocalizedData(key: key) { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else {
|
||||||
|
completer?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let languageList = model.languages, languageList.count > 0 {
|
||||||
|
self.languageList = languageList
|
||||||
|
}
|
||||||
|
|
||||||
|
if let localizedData = model.translates {
|
||||||
|
self.localizedData = localizedData
|
||||||
|
completer?(true)
|
||||||
|
} else {
|
||||||
|
completer?(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extension SPLocalizedManager {
|
extension SPLocalizedManager {
|
||||||
|
|
||||||
static let localizedDidChange = Notification.Name(rawValue: "SPLocalizedManager.localizedDidChange")
|
static let localizedDidChange = Notification.Name(rawValue: "SPLocalizedManager.localizedDidChange")
|
||||||
|
18
MoviaBox/Libs/SPLocalizedManager/SPLocalizedModel.swift
Normal file
18
MoviaBox/Libs/SPLocalizedManager/SPLocalizedModel.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// SPLocalizedModel.swift
|
||||||
|
// MoviaBox
|
||||||
|
//
|
||||||
|
// Created by 佳尔 on 2025/5/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class SPLocalizedModel: SPModel, SmartCodable {
|
||||||
|
|
||||||
|
///翻译数据
|
||||||
|
var translates: [String : String]?
|
||||||
|
|
||||||
|
var languages: [SPLanguageModel]?
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user