多语言开发

This commit is contained in:
zjx 2025-06-12 18:24:39 +08:00
parent 2a71917084
commit 78f810498d
65 changed files with 749 additions and 341 deletions

View File

@ -148,6 +148,12 @@
BF5E75DB2DE5B8B700DE9DFE /* VPMarqueeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75DA2DE5B8B700DE9DFE /* VPMarqueeView.swift */; };
BFCCE10D2DF951F600EDE165 /* SceneDelegate+APNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE10C2DF951ED00EDE165 /* SceneDelegate+APNS.swift */; };
BFCCE1122DF9638B00EDE165 /* VPVipAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE1112DF9638B00EDE165 /* VPVipAlertView.swift */; };
BFCCE1142DFAAC0900EDE165 /* VPLanguageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE1132DFAAC0900EDE165 /* VPLanguageViewController.swift */; };
BFCCE1162DFAB66F00EDE165 /* VPLanguageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE1152DFAB66F00EDE165 /* VPLanguageCell.swift */; };
BFCCE1182DFAB77500EDE165 /* VPSettingAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE1172DFAB76E00EDE165 /* VPSettingAPI.swift */; };
BFCCE11A2DFAB7CA00EDE165 /* VPLanguageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE1192DFAB7CA00EDE165 /* VPLanguageModel.swift */; };
BFCCE11C2DFAB83900EDE165 /* VPLocalizedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE11B2DFAB83900EDE165 /* VPLocalizedModel.swift */; };
BFCCE11F2DFAD18000EDE165 /* VPGuideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCCE11E2DFAD18000EDE165 /* VPGuideViewController.swift */; };
BFF5AFA42DE6F15E0044227A /* VPMeVipCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFA32DE6F15E0044227A /* VPMeVipCell.swift */; };
BFF5AFA62DE700420044227A /* VPMeVipPrivilegeItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFA52DE700420044227A /* VPMeVipPrivilegeItemView.swift */; };
BFF5AFA82DE704DC0044227A /* VPMeCoinCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFA72DE704DC0044227A /* VPMeCoinCell.swift */; };
@ -376,6 +382,12 @@
BF5E75DA2DE5B8B700DE9DFE /* VPMarqueeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMarqueeView.swift; sourceTree = "<group>"; };
BFCCE10C2DF951ED00EDE165 /* SceneDelegate+APNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SceneDelegate+APNS.swift"; sourceTree = "<group>"; };
BFCCE1112DF9638B00EDE165 /* VPVipAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVipAlertView.swift; sourceTree = "<group>"; };
BFCCE1132DFAAC0900EDE165 /* VPLanguageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLanguageViewController.swift; sourceTree = "<group>"; };
BFCCE1152DFAB66F00EDE165 /* VPLanguageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLanguageCell.swift; sourceTree = "<group>"; };
BFCCE1172DFAB76E00EDE165 /* VPSettingAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSettingAPI.swift; sourceTree = "<group>"; };
BFCCE1192DFAB7CA00EDE165 /* VPLanguageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLanguageModel.swift; sourceTree = "<group>"; };
BFCCE11B2DFAB83900EDE165 /* VPLocalizedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPLocalizedModel.swift; sourceTree = "<group>"; };
BFCCE11E2DFAD18000EDE165 /* VPGuideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGuideViewController.swift; sourceTree = "<group>"; };
BFF5AFA32DE6F15E0044227A /* VPMeVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeVipCell.swift; sourceTree = "<group>"; };
BFF5AFA52DE700420044227A /* VPMeVipPrivilegeItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeVipPrivilegeItemView.swift; sourceTree = "<group>"; };
BFF5AFA72DE704DC0044227A /* VPMeCoinCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeCoinCell.swift; sourceTree = "<group>"; };
@ -552,6 +564,7 @@
BF0FA7422DDF024400C9E5F2 /* Explore */,
BF0FA6FD2DDC65F300C9E5F2 /* Player */,
BFF5B21D2DEEE28B0044227A /* Login */,
BFCCE11D2DFAD14C00EDE165 /* Guide */,
);
path = Class;
sourceTree = "<group>";
@ -696,6 +709,7 @@
isa = PBXGroup;
children = (
1B056E692DDAD0BF007EE38D /* VPLocalizedManager.swift */,
BFCCE11B2DFAB83900EDE165 /* VPLocalizedModel.swift */,
);
path = LocalizedManager;
sourceTree = "<group>";
@ -780,6 +794,7 @@
BF0FA6F72DDC64CF00C9E5F2 /* API */ = {
isa = PBXGroup;
children = (
BFCCE1172DFAB76E00EDE165 /* VPSettingAPI.swift */,
BFF5AFB92DE8372A0044227A /* VPWalletAPI.swift */,
BF0FA6F82DDC64E700C9E5F2 /* VPHomeAPI.swift */,
BF0FA73C2DDED2D000C9E5F2 /* VPVideoAPI.swift */,
@ -1020,6 +1035,7 @@
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */,
BFF5B22B2DEFE8A80044227A /* VPDeleteAccountViewController.swift */,
BFF5B23C2DF034420044227A /* VPFeedbackViewController.swift */,
BFCCE1132DFAAC0900EDE165 /* VPLanguageViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
@ -1042,6 +1058,7 @@
BFF5B2312DEFF1220044227A /* VPDeleteAccountDetailView.swift */,
BFF5B2332DEFF2030044227A /* VPDeleteAccountTipView.swift */,
BFCCE1112DF9638B00EDE165 /* VPVipAlertView.swift */,
BFCCE1152DFAB66F00EDE165 /* VPLanguageCell.swift */,
);
path = View;
sourceTree = "<group>";
@ -1050,6 +1067,7 @@
isa = PBXGroup;
children = (
BF0FA7B02DE447EB00C9E5F2 /* VPMeItem.swift */,
BFCCE1192DFAB7CA00EDE165 /* VPLanguageModel.swift */,
);
path = Model;
sourceTree = "<group>";
@ -1107,6 +1125,14 @@
path = MarqueeView;
sourceTree = "<group>";
};
BFCCE11D2DFAD14C00EDE165 /* Guide */ = {
isa = PBXGroup;
children = (
BFCCE11E2DFAD18000EDE165 /* VPGuideViewController.swift */,
);
path = Guide;
sourceTree = "<group>";
};
BFF5AFBB2DE837710044227A /* Wallet */ = {
isa = PBXGroup;
children = (
@ -1382,12 +1408,14 @@
1B056E772DDB3641007EE38D /* VPTabBarItemNormalVew.swift in Sources */,
BFF5B2662DF16CF60044227A /* VPWaitRestoreModel.swift in Sources */,
1B056E4B2DDAC6BA007EE38D /* VPDefine.swift in Sources */,
BFCCE11A2DFAB7CA00EDE165 /* VPLanguageModel.swift in Sources */,
BFF5B2302DEFEF0C0044227A /* VPDeleteAccountNormalView.swift in Sources */,
1B056E702DDB019B007EE38D /* VPTabBarItemContainer.swift in Sources */,
BF0FA7752DE071B500C9E5F2 /* VPSearchViewController.swift in Sources */,
BF0FA78D2DE16A8B00C9E5F2 /* VPSearchViewModel.swift in Sources */,
1B056E592DDACD44007EE38D /* VPTabBarItemContentView.swift in Sources */,
1B056E2B2DDAC0FD007EE38D /* AppDelegate.swift in Sources */,
BFCCE1162DFAB66F00EDE165 /* VPLanguageCell.swift in Sources */,
1B056E6C2DDADAA1007EE38D /* VPTabBar.swift in Sources */,
BF0FA72E2DDD7DD400C9E5F2 /* VPHomeRankingCell.swift in Sources */,
BF0FA7792DE075FF00C9E5F2 /* VPSearchHomeView.swift in Sources */,
@ -1401,6 +1429,7 @@
BFF5B2202DEEE2C50044227A /* VPLoginContentView.swift in Sources */,
1B056E5D2DDACD8E007EE38D /* UIFont+VPAdd.swift in Sources */,
BF0FA7282DDC91F800C9E5F2 /* VPCollectionViewCell.swift in Sources */,
BFCCE11C2DFAB83900EDE165 /* VPLocalizedModel.swift in Sources */,
BF0FA7672DE0469300C9E5F2 /* VPEpisodeView.swift in Sources */,
BF0FA6F92DDC64E700C9E5F2 /* VPHomeAPI.swift in Sources */,
BF0FA6F42DDC604500C9E5F2 /* VPHUD.swift in Sources */,
@ -1506,6 +1535,7 @@
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */,
BF0FA7192DDC7F4900C9E5F2 /* VPHomeBannerCell.swift in Sources */,
BF0FA7712DE062EB00C9E5F2 /* VPVideoRateModel.swift in Sources */,
BFCCE1142DFAAC0900EDE165 /* VPLanguageViewController.swift in Sources */,
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */,
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */,
BF0FA7BE2DE4592A00C9E5F2 /* UserDefaults+VPAdd.swift in Sources */,
@ -1520,6 +1550,7 @@
BF0FA7892DE161F200C9E5F2 /* VPSearchResultView.swift in Sources */,
1B056E792DDB365A007EE38D /* VPTabBarItemSelectedView.swift in Sources */,
1B056E722DDB022F007EE38D /* VPTabBarItem.swift in Sources */,
BFCCE11F2DFAD18000EDE165 /* VPGuideViewController.swift in Sources */,
BFF5B23D2DF034420044227A /* VPFeedbackViewController.swift in Sources */,
BFF5B2392DF014520044227A /* VPBaseAlertView.swift in Sources */,
BFF5AFCC2DE98C7F0044227A /* VPOrderRecordsViewController.swift in Sources */,
@ -1532,6 +1563,7 @@
BF0FA73F2DDEF26E00C9E5F2 /* VPHomeSearchButton.swift in Sources */,
BFF5B2562DF139200044227A /* VPGiveCoinRecordsViewController.swift in Sources */,
1B056E512DDACBE5007EE38D /* VPViewController.swift in Sources */,
BFCCE1182DFAB77500EDE165 /* VPSettingAPI.swift in Sources */,
BF0FA7122DDC6D2C00C9E5F2 /* VPHomeModuleItem.swift in Sources */,
BFF5B2482DF051D90044227A /* AppDelegate+Thirdparty.swift in Sources */,
BFF5AFAC2DE70CE20044227A /* VPMeToolCell.swift in Sources */,

View File

@ -39,7 +39,7 @@ extension SceneDelegate {
private static var webpageURL: URL?
func vp_handleOpenAppMessage(webpageURL: URL?) {
guard VPNetworkReachabilityManager.manager.isReachable == true, SceneDelegate.haveBeenShownAPNS else {
guard VPNetworkReachabilityManager.manager.isReachable == true, SceneDelegate.haveBeenShownAPNS, self.isOpenApp else {
if let webpageURL = webpageURL {
SceneDelegate.webpageURL = webpageURL
}

View File

@ -43,7 +43,7 @@ extension SceneDelegate {
}
private func showApnsAlert() {
let alert = VPAlertView(title: "kAPNSAlertTitle".localized, subtitle: "kAPNSAlertText".localized, icon: UIImage(named: "alert_icon_03"), normalButtonText: nil, highlightButtonText: "Allow".localized)
let alert = VPAlertView(title: "open_notice_at_watch_video".localized, subtitle: "veloria_open_notice_alert_text".localized, icon: UIImage(named: "alert_icon_03"), normalButtonText: nil, highlightButtonText: "veloria_allow".localized)
alert.show()
alert.clickHighlightButton = { [weak self] in

View File

@ -12,15 +12,18 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var timer: Timer?
private var onLineTimer: Timer?
private(set) var isOpenApp = false
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
VPAppTool.windowScene = windowScene
timer = Timer.scheduledTimer(timeInterval: 60 * 10, target: YYWeakProxy(target: self), selector: #selector(handleOnLine), userInfo: nil, repeats: true)
onLineTimer = Timer.scheduledTimer(timeInterval: 60 * 10, target: YYWeakProxy(target: self), selector: #selector(handleOnLine), userInfo: nil, repeats: true)
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(localizedDidChangeNotification), name: VPLocalizedManager.localizedDidChangeNotification, object: nil)
self.requestAPNS()
@ -30,11 +33,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
window = UIWindow(windowScene: windowScene)
startApp()
}
private func setTabBarController() {
isOpenApp = true
window?.rootViewController = VPTabBarController()
window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
@ -42,18 +49,17 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
func sceneDidBecomeActive(_ scene: UIScene) {
// vpLog(message: "++++++++++++++sceneDidBecomeActive")
vpLog(message: "++++++++++++++sceneDidBecomeActive")
enterForeground()
}
func sceneWillResignActive(_ scene: UIScene) {
// vpLog(message: "++++++++++++++sceneWillResignActive")
vpLog(message: "++++++++++++++sceneWillResignActive")
enterBackground()
}
func sceneWillEnterForeground(_ scene: UIScene) {
// vpLog(message: "++++++++++++++sceneWillEnterForeground")
// enterForeground()
vpLog(message: "++++++++++++++sceneWillEnterForeground")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.vp_handleOpenAppMessage(webpageURL: nil)
@ -61,17 +67,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
func sceneDidEnterBackground(_ scene: UIScene) {
// vpLog(message: "++++++++++++++sceneDidEnterBackground")
// enterBackground()
vpLog(message: "++++++++++++++sceneDidEnterBackground")
}
// private var isEnterForeground = false
private func enterForeground() {
// if !isEnterForeground {
// vpLog(message: "++++++++++++++enterForeground")
// }
// isEnterForeground = true
handleOnLine()
VPStatAPI.requestEnterApp()
@ -89,18 +88,75 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
extension SceneDelegate {
private func startApp() {
let localizedManager = VPLocalizedManager.shared
if localizedManager.localizedDataLocalizedKey != localizedManager.currentLocalizedKey,
let lanuchVC = VPAppTool.lanuchViewController {
window?.rootViewController = lanuchVC
window?.makeKeyAndVisible()
self.requestLocalizedData()
} else {
VPLocalizedManager.shared.updateLocalizedData(completer: nil)
setRootVC()
}
}
private func setRootVC() {
let hasOpenApp = UserDefaults.standard.object(forKey: kVPHasBeenOpenedAPPDefaultsKey) as? Bool
if hasOpenApp != true {
///
let guideVc = VPGuideViewController()
guideVc.clickOpenButton = { [weak self] in
guard let self = self else { return }
self.setTabBarController()
self.vp_retryHandleOpenAppMessage()
}
window?.rootViewController = guideVc
window?.makeKeyAndVisible()
} else {
setTabBarController()
}
}
}
extension SceneDelegate {
@objc private func handleOnLine() {
VPStatAPI.requestStatOnLine()
}
@objc private func reachabilityDidChangeNotification() {
vp_retryHandleOpenAppMessage()
if VPNetworkReachabilityManager.manager.isReachable == true {
handleOnLine()
let data = VPLocalizedManager.shared.localizedData ?? [:]
if data.isEmpty {
requestLocalizedData()
}
}
}
@objc private func localizedDidChangeNotification() {
MJRefreshConfig.default.languageCode = VPLocalizedManager.shared.mjLocalizedKey
setTabBarController()
}
private func requestLocalizedData() {
VPLocalizedManager.shared.updateLocalizedData { [weak self] finish in
guard let self = self else { return }
self.setRootVC()
}
}
}

View File

@ -84,10 +84,10 @@ extension VPTabBarController {
let nav1 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
let nav2 = createNavigationController(viewController: VPExploreViewController(), title: "Explore".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
let nav3 = createNavigationController(viewController: VPMyListViewController(), title: "My List".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
let nav4 = createNavigationController(viewController: VPMeViewController(), title: "Me".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
let nav1 = createNavigationController(viewController: VPHomePageViewController(), title: "veloria_home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
let nav2 = createNavigationController(viewController: VPExploreViewController(), title: "veloria_explore".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
let nav3 = createNavigationController(viewController: VPMyListViewController(), title: "veloria_my_list".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
let nav4 = createNavigationController(viewController: VPMeViewController(), title: "veloria_me".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
viewControllers = [nav1, nav2, nav3, nav4]

View File

@ -23,11 +23,11 @@ public let kVPAPPName: String = (Bundle.main.infoDictionary!["CFBundleDisplayNam
//MARK: ------- ----------
#if DEBUG
public func vpLog(message:Any? , file: String = #file, function: String = #function, line: Int = #line) {
public func vpLog(message: Any? , file: String = #file, function: String = #function, line: Int = #line) {
print("\n\(Date(timeIntervalSinceNow: 8 * 60 * 60)) \(file.components(separatedBy: "/").last ?? "") \(function) \(line): \(message ?? "")")
}
#else
public func vpLog(message:Any?) { }
public func vpLog(message: Any?) { }
#endif
public func vp_swizzled_instanceMethod(_ prefix: String, oldClass: Swift.AnyClass!, oldSelector: String, newClass: Swift.AnyClass) {

View File

@ -24,3 +24,6 @@ let kVPApnsAlertDefaultsKey = "kVPApnsAlertDefaultsKey"
///vip
let kVPVipAlertDateDefaultsKey = "kVPVipAlertDateDefaultsKey"
///APP
let kVPHasBeenOpenedAPPDefaultsKey = "kVPHasBeenOpenedAPPDefaultsKey"

View File

@ -0,0 +1,34 @@
//
// VPSettingAPI.swift
// Veloria
//
// Created by on 2025/6/12.
//
class VPSettingAPI {
///
static func requestLanguageList(completer: ((_ list: [VPLanguageModel]?) -> Void)?) {
var param = VPNetworkParameters(path: "/languges")
param.method = .get
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPLanguageModel>>) in
completer?(response.data?.list)
}
}
///
static func requestLocalizedData(key: String, completer: ((_ model: VPLocalizedModel?) -> Void)?) {
var param = VPNetworkParameters(path: "/translates")
param.method = .get
param.parameters = [
"lang_key" : key
]
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPLocalizedModel>) in
completer?(response.data)
}
}
}

View File

@ -95,7 +95,7 @@ class VPWalletAPI {
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPIAPOrderModel>) in
if let message = response.data?.message, message.count > 0 {
if response.data?.code == 30007 {
VPToast.show(text: "kVipToast01".localized)
VPToast.show(text: "veloria_vip_error_1".localized)
} else {
VPToast.show(text: message)
}

View File

@ -81,7 +81,7 @@ class VPNetwork: NSObject {
completion?(res)
} else {
if code == 402, parameters.isToast {
VPToast.show(text: "kNetworkToast02".localized)
VPToast.show(text: "veloria_network_error_1".localized)
}
///token
self.requestToken { token in
@ -144,7 +144,7 @@ class VPNetwork: NSObject {
var res = VPNetworkResponse<T>()
res.code = -1
if parameters.isToast {
VPToast.show(text: "kNetworkToast01".localized)
VPToast.show(text: "veloria_network".localized)
}
completion?(res)
break

View File

@ -23,6 +23,7 @@ class VPNetworkReachabilityManager {
monitor.pathUpdateHandler = { [weak self] path in
guard let self = self else { return }
if path.status == .satisfied {
if self.isReachable == false {
self.isReachable = true
@ -32,7 +33,7 @@ class VPNetworkReachabilityManager {
} else {
self.isReachable = true
}
vpLog(message: "+++++++++++++++网络变化==有网")
} else {
if self.isReachable == true {
self.isReachable = false
@ -42,6 +43,7 @@ class VPNetworkReachabilityManager {
} else {
self.isReachable = false
}
vpLog(message: "+++++++++++++++网络变化==无网")
}
}

View File

@ -19,13 +19,13 @@ class VPCampaignWebViewController: VPWebViewController {
super.viewDidLoad()
autoTitle = false
if urlStr == kVPFeedBackListWebUrl {
self.title = "Feedback History".localized
self.title = "veloria_my_feedback_history".localized
} else if urlStr == kVPFeedBackHomeWebUrl {
self.title = "Feedback".localized
self.title = "veloria_my_feedback".localized
} else if urlStr == kVPFeedBackDetailWebUrl {
self.title = "Feedback Details".localized
self.title = "veloria_my_feedback_details".localized
} else if urlStr == kVPRewardsWebUrl {
self.title = "Rewards".localized
self.title = "veloria_rewards".localized
}
self.webView.scrollView.vp_addRefreshHeader { [weak self] in

View File

@ -11,14 +11,15 @@ class VPExplorePlayerControlView: VPVideoPlayerControlView {
override var videoInfo: VPVideoInfoModel? {
didSet {
epLabel.text = String(format: "EP.%@".localized, videoInfo?.episode ?? "0")
epLabel.text = "veloria_EP.".localizedReplace(text: videoInfo?.episode ?? "0")
}
}
override var shortModel: VPShortModel? {
didSet {
allView.setTitle(String(format: "All %@ Episodes".localized, "\(shortModel?.episode_total ?? 0)"), for: .normal)
allView.setTitle("veloria_all_episodes".localizedReplace(text: "\(shortModel?.episode_total ?? 0)"), for: .normal)
videoNameLabel.text = shortModel?.name
}
}

View File

@ -0,0 +1,63 @@
//
// VPGuideViewController.swift
// Veloria
//
// Created by on 2025/6/12.
//
import UIKit
class VPGuideViewController: VPViewController {
var clickOpenButton: (() -> Void)?
private(set) lazy var lanuchVC: UIViewController? = {
let vc = VPAppTool.lanuchViewController
return vc
}()
private lazy var openButton: VPGradientButton = {
let button = VPGradientButton(type: .custom)
button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor]
button.locations = [0, 1]
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.bt_setGradientBorder()
button.layer.cornerRadius = 24
button.setTitle("veloria_get_started".localized, for: .normal)
button.addTarget(self, action: #selector(handleOpenButton), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
vp_setupUI()
}
@objc private func handleOpenButton() {
UserDefaults.standard.set(true, forKey: kVPHasBeenOpenedAPPDefaultsKey)
self.clickOpenButton?()
}
}
extension VPGuideViewController {
private func vp_setupUI() {
if let vc = lanuchVC {
addChild(vc)
view.addSubview(vc.view)
}
view.addSubview(openButton)
openButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.height.equalTo(48)
make.width.equalTo(180)
make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 100))
}
}
}

View File

@ -84,7 +84,7 @@ class VPHomePageViewController: VPViewController {
let label = UILabel()
label.font = .fontMedium(ofSize: 17)
label.textColor = .colorFFFFFF()
label.text = "kHomeMenuTitle".localized
label.text = "veloria_select_categories".localized
return label
}()
@ -105,7 +105,7 @@ class VPHomePageViewController: VPViewController {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = "kHomeTitleText".localized
label.text = "veloria_addictive_short_await".localized
return label
}()

View File

@ -34,7 +34,7 @@ class VPHomeRankingContentCell: VPHomeItemContentCell {
let label = UILabel()
label.font = .fontMedium(ofSize: 15)
label.textColor = .colorFFFFFF()
label.text = "Drama Champions".localized
label.text = "veloria_drama_champions".localized
return label
}()
@ -44,7 +44,7 @@ class VPHomeRankingContentCell: VPHomeItemContentCell {
config.imagePlacement = .trailing
config.contentInsets = .init(top: 5, leading: 0, bottom: 5, trailing: 0)
config.image = UIImage(named: "arrow_right_icon_03")
config.attributedTitle = AttributedString.createAttributedString(string: "More".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12))
config.attributedTitle = AttributedString.createAttributedString(string: "veloria_more".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12))
let button = UIButton(configuration: config)
button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside)
return button

View File

@ -38,7 +38,7 @@ class VPHomeRecommandContentCell: VPHomeItemContentCell {
config.imagePlacement = .trailing
config.contentInsets = .init(top: 5, leading: 0, bottom: 5, trailing: 0)
config.image = UIImage(named: "arrow_right_icon_03")
config.attributedTitle = AttributedString.createAttributedString(string: "More".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12))
config.attributedTitle = AttributedString.createAttributedString(string: "veloria_more".localized, color: .colorFFFFFF(alpha: 0.5), font: .fontRegular(ofSize: 12))
let button = UIButton(configuration: config)
button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside)
return button

View File

@ -34,7 +34,7 @@ class VPHomeSearchButton: UIControl {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF(alpha: 0.3)
label.text = "kSearchPlaceholderText1".localized
label.text = "veloria_search_dramas".localized
return label
}()
@ -87,7 +87,7 @@ extension VPHomeSearchButton: VPMarqueeViewDataSource {
func marqueeView(_ marqueeView: VPMarqueeView, cellForItemAt index: Int) -> NSAttributedString {
var text: String
if marqueeArr.count == 0 {
text = "kSearchPlaceholderText1".localized
text = "veloria_search_dramas".localized
} else {
text = marqueeArr[index].name ?? ""
}

View File

@ -22,7 +22,7 @@ class VPSearchHistoryView: UIView {
let label = UILabel()
label.font = .fontRegular(ofSize: 13)
label.textColor = .colorFFFFFF()
label.text = "Recent Searches".localized
label.text = "veloria_recent_searches".localized
return label
}()

View File

@ -29,7 +29,7 @@ class VPSearchInputView: UIView {
let textField = VPTextField()
textField.font = .fontRegular(ofSize: 14)
textField.returnKeyType = .search
textField.vp_placeholder = "kSearchPlaceholderText2".localized
textField.vp_placeholder = "veloria_recersal_of_fate".localized
textField.vp_placeholderFont = textField.font
textField.textDidChange = { [weak self] text in
self?.textDidChange?(text)

View File

@ -18,7 +18,7 @@ class VPSearchRecommendedView: UIView {
let label = UILabel()
label.font = .fontMedium(ofSize: 15)
label.textColor = .colorFFFFFF()
label.text = "Recommended For You".localized
label.text = "veloria_recommended".localized
return label
}()
@ -40,7 +40,7 @@ class VPSearchRecommendedView: UIView {
view.borderColors = [UIColor.colorFBF2C7(alpha: 0.6).cgColor, UIColor.colorA8A38E(alpha: 0.4).cgColor, UIColor.color555555(alpha: 0.3).cgColor, UIColor.colorFBF2C7(alpha: 0.05).cgColor]
view.titleColors = [UIColor.colorFBF2C7().cgColor, UIColor.colorA87A46().cgColor]
view.iconImage = UIImage(named: "top_icon_01")
view.title = "Trending Top 10".localized
view.title = "veloria_trending_top".localized
return view
}()
@ -49,7 +49,7 @@ class VPSearchRecommendedView: UIView {
view.borderColors = [UIColor.colorFFBFBE(alpha: 0.6).cgColor, UIColor.colorFFBFBE(alpha: 0.4).cgColor, UIColor.color555555(alpha: 0.3).cgColor, UIColor.colorFFBFBE(alpha: 0.05).cgColor]
view.titleColors = [UIColor.colorFFBFBE().cgColor, UIColor.colorD87675().cgColor]
view.iconImage = UIImage(named: "hot_icon_02")
view.title = "Latest Trends".localized
view.title = "veloria_latest_trends".localized
return view
}()

View File

@ -24,7 +24,7 @@ class VPSearchResultView: UIView {
let label = UILabel()
label.font = .fontMedium(ofSize: 13)
label.textColor = .colorFFFFFF()
label.text = "Search Results".localized
label.text = "veloria_search_results".localized
return label
}()
@ -42,7 +42,7 @@ class VPSearchResultView: UIView {
collectionView.dataSource = self
collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 0)
collectionView.register(VPSearchResultCell.self, forCellWithReuseIdentifier: "cell")
collectionView.vp_addNormalEmpty(image: UIImage(named: "empty_image_02"), title: "kEmptyTitle02".localized, des: "kEmptyDes02".localized)
collectionView.vp_addNormalEmpty(image: UIImage(named: "empty_image_02"), title: "veloria_not_found".localized, des: "veloria_not_found_string".localized)
collectionView.keyboardDismissMode = .onDrag
return collectionView
}()

View File

@ -29,7 +29,7 @@ class VPHomeViewModel: VPModel {
var rawCategoryList: [VPCategoryModel] = [] {
didSet {
let allCategory = VPCategoryModel()
allCategory.name = "All".localized
allCategory.name = "veloria_all".localized
allCategory.id = "0"
categoryList.removeAll()
@ -65,7 +65,7 @@ class VPHomeViewModel: VPModel {
categoryTitleList.removeAll()
let allCategory = VPCategoryModel()
allCategory.name = "All".localized
allCategory.name = "veloria_all".localized
allCategory.id = "0"
categoryList.append(allCategory)
categoryList += ($0.categoryList ?? [])

View File

@ -25,14 +25,15 @@ class VPLoginContentView: HWPanModalContentView {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = String(format: "Welcome to %@".localized, "kAppName".localized)
label.text = "veloria_welcome_to".localized
return label
}()
private lazy var agreementLabel: YYLabel = {
let userAgreementText = "User Agreement".localized
let privacyPolicyText = "Privacy Policy".localized
let text = String(format: "kLoginAgreementText".localized, userAgreementText, privacyPolicyText)
let userAgreementText = "veloria_my_agreement".localized
let privacyPolicyText = "veloria_my_privacy".localized
let text = "veloria_login_hint_ios".localizedReplace(text1: userAgreementText, text2: privacyPolicyText)
let range1 = text.ocString().range(of: userAgreementText)
let range2 = text.ocString().range(of: privacyPolicyText)
@ -70,7 +71,7 @@ class VPLoginContentView: HWPanModalContentView {
private lazy var appleButton: VPLoginButton = {
let button = VPLoginButton()
button.icon = UIImage(named: "apple_icon_01")
button.title = "Login with Apple".localized
button.title = "veloria_login_apple".localized
button.addTarget(self, action: #selector(handleAppleButton), for: .touchUpInside)
return button
}()
@ -78,7 +79,7 @@ class VPLoginContentView: HWPanModalContentView {
private lazy var facebookButton: VPLoginButton = {
let button = VPLoginButton()
button.icon = UIImage(named: "facebook_icon_01")
button.title = "Login with Facebook".localized
button.title = "veloria_login_facebook".localized
button.addTarget(self, action: #selector(handleFacebookButton), for: .touchUpInside)
return button
}()

View File

@ -11,12 +11,12 @@ class VPAboutUsViewController: VPViewController {
private lazy var dataArr: [VPMeItem] = {
let arr = [
VPMeItem(title: "User Agreement".localized, type: .userAgreement),
VPMeItem(title: "Privacy Policy".localized, type: .privacyPolicy),
VPMeItem(title: "Child Personal Information Protection Rules".localized, type: .informationProtection),
VPMeItem(title: "Youth Internet Civility Convention".localized, type: .civizatioConvention),
VPMeItem(title: "Third-party information sharing list".localized, type: .informationSharing),
VPMeItem(title: "Explicit List of Personal Information Collection".localized, type: .persoInforDisclosure),
VPMeItem(title: "veloria_my_agreement".localized, type: .userAgreement),
VPMeItem(title: "veloria_my_privacy".localized, type: .privacyPolicy),
VPMeItem(title: "veloria_child_protection_text".localized, type: .informationProtection),
VPMeItem(title: "veloria_civizatio_convention_text".localized, type: .civizatioConvention),
VPMeItem(title: "veloria_information_sharing_text".localized, type: .informationSharing),
VPMeItem(title: "veloria_persoInfor_disclosure_text".localized, type: .persoInforDisclosure),
]
return arr
}()
@ -38,7 +38,7 @@ class VPAboutUsViewController: VPViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "About Us".localized
self.title = "veloria_me_about".localized
vp_setupUI()
}

View File

@ -90,7 +90,7 @@ class VPDeleteAccountViewController: VPViewController {
button.configurationUpdateHandler = { button in
guard let button = button as? VPGradientButton else { return }
let title = "Delete Account".localized
let title = "veloria_delete_account".localized
if button.isEnabled {
button.configuration?.attributedTitle = .createAttributedString(string: title, color: .colorFFFFFF(), font: .fontRegular(ofSize: 14))
@ -110,7 +110,7 @@ class VPDeleteAccountViewController: VPViewController {
super.viewDidLoad()
self.bgImageView.isHidden = true
self.view.backgroundColor = .color080B16()
self.title = "Account Deletion".localized
self.title = "veloria_delete_account".localized
vp_setupUI()
}
@ -132,7 +132,7 @@ extension VPDeleteAccountViewController {
}
@objc private func handleDeleteButton() {
let alert = VPAlertView(title: "kDeleteAccountAlertTitle".localized, subtitle: "kDeleteAccountAlertText".localized, icon: UIImage(named: "alert_icon_01"), normalButtonText: "Delete Forever".localized, highlightButtonText: "Cancel".localized)
let alert = VPAlertView(title: "veloria_confirm_deletion".localized, subtitle: "veloria_action_cannot_undone".localized, icon: UIImage(named: "alert_icon_01"), normalButtonText: "veloria_delete_forever".localized, highlightButtonText: "veloria_cancel".localized)
alert.show()
alert.clickNormalButton = {

View File

@ -0,0 +1,102 @@
//
// VPLanguageViewController.swift
// Veloria
//
// Created by on 2025/6/12.
//
import UIKit
class VPLanguageViewController: VPViewController {
private lazy var dataArr: [VPLanguageModel] = []
private lazy var currentLocalizedKey = VPLocalizedManager.shared.currentLocalizedKey
private lazy var tableView: VPTableView = {
let tableView = VPTableView(frame: .zero, style: .plain)
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 60
tableView.separatorStyle = .none
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 0)
tableView.register(VPLanguageCell.self, forCellReuseIdentifier: "cell")
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "veloria_language".localized
requestDataList()
vp_setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
setNavigationNormalStyle()
}
}
extension VPLanguageViewController {
private func vp_setupUI() {
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
}
}
}
//MARK: -------------- UITableViewDelegate UITableViewDataSource --------------
extension VPLanguageViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = dataArr[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! VPLanguageCell
cell.model = model
cell.vp_isSelected = model.lang_key == currentLocalizedKey
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let model = dataArr[indexPath.row]
if model.lang_key == currentLocalizedKey { return }
if let key = model.lang_key {
VPHUD.show()
VPLocalizedManager.shared.updateLocalizedData(key: key) { (finish) in
if finish {
VPLocalizedManager.shared.currentLocalizedKey = key
NotificationCenter.default.post(name: VPLocalizedManager.localizedDidChangeNotification, object: nil)
}
VPHUD.dismiss()
}
}
}
}
extension VPLanguageViewController {
private func requestDataList() {
VPSettingAPI.requestLanguageList { [weak self] list in
guard let self = self else { return }
if let list = list {
self.dataArr = list
self.tableView.reloadData()
}
}
}
}

View File

@ -192,6 +192,10 @@ extension VPMeViewController: UITableViewDelegate, UITableViewDataSource {
let vc = VPWalletViewController()
self.navigationController?.pushViewController(vc, animated: true)
case .language:
let vc = VPLanguageViewController()
self.navigationController?.pushViewController(vc, animated: true)
default:
break
}
@ -228,15 +232,15 @@ extension VPMeViewController {
]
var cellArr: [VPMeItem] = []
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_07"), title: "Order Record".localized, type: .orderRecord, cellKey: .normal))
// cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "Language".localized, type: .language, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_07"), title: "veloria_order_record".localized, type: .orderRecord, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_05"), title: "veloria_language".localized, type: .language, cellKey: .normal))
if VPLoginManager.manager.userInfo?.is_tourist == false {
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_06"), title: "Delete Account".localized, type: .deleteAccount, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_06"), title: "veloria_delete_account".localized, type: .deleteAccount, cellKey: .normal))
}
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "Privacy Policy".localized, type: .privacyPolicy, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "User Agreement".localized, type: .userAgreement, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "Feedback".localized, type: .feedback, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_03"), title: "About Us".localized, type: .aboutUs, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "veloria_my_privacy".localized, type: .privacyPolicy, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "veloria_my_agreement".localized, type: .userAgreement, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "veloria_my_feedback".localized, type: .feedback, cellKey: .normal))
cellArr.append(VPMeItem(icon: UIImage(named: "me_item_icon_03"), title: "veloria_me_about".localized, type: .aboutUs, cellKey: .normal))
dataArr.append(cellArr)

View File

@ -0,0 +1,20 @@
//
// VPLanguageModel.swift
// Veloria
//
// Created by on 2025/6/12.
//
import UIKit
import SmartCodable
class VPLanguageModel: VPModel, 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?
var is_default: Int?
}

View File

@ -0,0 +1,62 @@
//
// VPLanguageCell.swift
// Veloria
//
// Created by on 2025/6/12.
//
import UIKit
class VPLanguageCell: VPTableViewCell {
var model: VPLanguageModel? {
didSet {
titleLabel.text = model?.show_name
}
}
var vp_isSelected: Bool = false {
didSet {
selectedVew.isSelected = vp_isSelected
}
}
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var selectedVew: UIButton = {
let view = UIButton(type: .custom)
view.isUserInteractionEnabled = false
view.setImage(UIImage(named: "choice_icon_01"), for: .normal)
view.setImage(UIImage(named: "choice_icon_01_selected"), for: .selected)
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(titleLabel)
contentView.addSubview(selectedVew)
titleLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(15)
}
selectedVew.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().offset(-15)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -24,13 +24,13 @@ class VPMeCoinCell: VPTableViewCell {
private lazy var coinView1: VPMeCoinItemView = {
let view = VPMeCoinItemView()
view.title = "Conins".localized
view.title = "coins".localized
return view
}()
private lazy var coinView2: VPMeCoinItemView = {
let view = VPMeCoinItemView()
view.title = "Donate".localized
view.title = "veloria_bonus".localized
return view
}()

View File

@ -21,9 +21,9 @@ class VPMeFooterView: UIView {
button.layer.masksToBounds = true
button.layer.borderColor = UIColor.color585858().cgColor
button.layer.borderWidth = 1
button.setTitle("Log In".localized, for: .normal)
button.setTitle("Sign Out".localized, for: .selected)
button.setTitle("Sign Out".localized, for: [.selected, .highlighted])
button.setTitle("veloria_login".localized, for: .normal)
button.setTitle("veloria_sign_out".localized, for: .selected)
button.setTitle("veloria_sign_out".localized, for: [.selected, .highlighted])
button.setTitleColor(.colorB3B3B3(), for: .normal)
button.titleLabel?.font = .fontRegular(ofSize: 14)
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
@ -53,7 +53,7 @@ class VPMeFooterView: UIView {
if userInfo?.is_tourist == true {
VPLoginManager.manager.openLogin()
} else {
let alert = VPAlertView(title: "kLogoutAlertTitle".localized, subtitle: "kLogoutAlertText".localized, icon: UIImage(named: "alert_icon_02"), normalButtonText: "Log Out".localized, highlightButtonText: "Cancel".localized).show()
let alert = VPAlertView(title: "veloria_ready_to_leave".localized, subtitle: "veloria_ready_to_leave_text".localized, icon: UIImage(named: "alert_icon_02"), normalButtonText: "veloria_log_out".localized, highlightButtonText: "veloria_cancel".localized).show()
alert.clickNormalButton = {
VPLoginManager.manager.logout(completer: nil)
}

View File

@ -19,25 +19,25 @@ class VPMeToolCell: VPTableViewCell {
}()
private lazy var walletButton: UIButton = {
let button = self.createButton(icon: UIImage(named: "wallet_icon_01"), title: "Wallet".localized)
let button = self.createButton(icon: UIImage(named: "wallet_icon_01"), title: "veloria_wallet".localized)
button.addTarget(self, action: #selector(handleWalletButton), for: .touchUpInside)
return button
}()
private lazy var storeButton: UIButton = {
let button = self.createButton(icon: UIImage(named: "store_icon_01"), title: "Store".localized)
let button = self.createButton(icon: UIImage(named: "store_icon_01"), title: "veloria_store".localized)
button.addTarget(self, action: #selector(handleStoreButton), for: .touchUpInside)
return button
}()
private lazy var rewardsButton: UIButton = {
let button = self.createButton(icon: UIImage(named: "rewards_icon_01"), title: "Rewards".localized)
let button = self.createButton(icon: UIImage(named: "rewards_icon_01"), title: "veloria_rewards".localized)
button.addTarget(self, action: #selector(handleRewardsButton), for: .touchUpInside)
return button
}()
private lazy var favoritesButton: UIButton = {
let button = self.createButton(icon: UIImage(named: "favorites_icon_01"), title: "Favorites".localized)
let button = self.createButton(icon: UIImage(named: "favorites_icon_01"), title: "veloria_favorites".localized)
button.addTarget(self, action: #selector(handleFavoritesButton), for: .touchUpInside)
return button
}()

View File

@ -17,7 +17,7 @@ class VPMeUserInfoCell: VPTableViewCell {
if let name = userInfo?.family_name, name.count > 0 {
nicknameLabel.text = name
} else {
nicknameLabel.text = "Visitor".localized
nicknameLabel.text = "veloria_visitor".localized
}
idLabel.text = "ID \(userInfo?.customer_id ?? "")"
@ -51,7 +51,7 @@ class VPMeUserInfoCell: VPTableViewCell {
}()
private lazy var loginButton: VPGradientButton = {
let title = AttributedString.createAttributedString(string: "Check in".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 12))
let title = AttributedString.createAttributedString(string: "veloria_check_in".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 12))
var config = UIButton.Configuration.plain()
config.imagePlacement = .leading

View File

@ -14,11 +14,11 @@ class VPMeVipCell: VPTableViewCell {
didSet {
if userInfo?.is_vip == true {
let date = Date(timeIntervalSince1970: userInfo?.vip_end_time ?? 0)
subtitleLabel.text = String(format: "kVipTipText2".localized, date.formatString(dateFormat: "yyyy-MM-dd"))
titleLabel.text = "VIP Active".localized
subtitleLabel.text = "veloria_vip_expires_date".localizedReplace(text: date.formatString(dateFormat: "yyyy-MM-dd"))
titleLabel.text = "veloria_vip_active".localized
} else {
subtitleLabel.text = "kVipTipText1".localized
titleLabel.text = "Join VIP".localized
subtitleLabel.text = "veloria_unlock_exclusive".localized
titleLabel.text = "veloria_vip_join".localized
}
}
}
@ -63,21 +63,21 @@ class VPMeVipCell: VPTableViewCell {
private lazy var itemView1: VPMeVipPrivilegeItemView = {
let view = VPMeVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_01")
view.title = "kVipPrivilegeText1".localized
view.title = "veloria_ad_free_streaming_ios".localized
return view
}()
private lazy var itemView2: VPMeVipPrivilegeItemView = {
let view = VPMeVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_02")
view.title = "kVipPrivilegeText2".localized
view.title = "veloria_exclusive_episodes_ios".localized
return view
}()
private lazy var itemView3: VPMeVipPrivilegeItemView = {
let view = VPMeVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_03")
view.title = "kVipPrivilegeText3".localized
view.title = "veloria_daily_free_coins_ios".localized
return view
}()

View File

@ -46,7 +46,8 @@ class VPVipAlertView: VPBaseAlertView {
if let coin = model?.send_coins, coin > 0 {
extraBgView.isHidden = false
let text = String(format: "Extra %@".localized, "\(coin)")
let text = "veloria_extra".localized + " \(coin)"
// let text = String(format: "Extra %@".localized, "\(coin)")
extraLabel.text = "+" + text
} else {
extraBgView.isHidden = true
@ -74,7 +75,7 @@ class VPVipAlertView: VPBaseAlertView {
private lazy var unlockButton: UIButton = {
let button = UIButton(type: .custom)
button.setBackgroundImage(UIImage(named: "vip_unlock_button"), for: .normal)
button.setTitle("kUnlockButtonText".localized, for: .normal)
button.setTitle("veloria_vip_splash_onclick".localized, for: .normal)
button.setTitleColor(.color005D48(), for: .normal)
button.titleLabel?.font = .fontMedium(ofSize: 14)
button.addTarget(self, action: #selector(hadnleUnlockButton), for: .touchUpInside)
@ -85,7 +86,7 @@ class VPVipAlertView: VPBaseAlertView {
let label = UILabel()
label.font = .fontBold(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = "kVipAlertTitle".localized
label.text = "veloria_vip_splash_title".localized
return label
}()
@ -93,7 +94,7 @@ class VPVipAlertView: VPBaseAlertView {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorC5C5C5()
label.text = "kVipAlertText".localized
label.text = "veloria_vip_splash_content".localized
label.numberOfLines = 0
label.textAlignment = .center
return label
@ -182,13 +183,16 @@ extension VPVipAlertView {
@objc private func hadnleUnlockButton() {
guard let model = model else { return }
self.dismiss()
let vc = VPVipPageViewController()
VPAppTool.topViewController?.navigationController?.pushViewController(vc, animated: true)
VPIAPManager.manager.start(model: model) { [weak self] finish in
if finish {
self?.dismiss()
VPLoginManager.manager.updateUserInfo(completer: nil)
}
}
// VPIAPManager.manager.start(model: model) { [weak self] finish in
// if finish {
// self?.dismiss()
// VPLoginManager.manager.updateUserInfo(completer: nil)
// }
// }
}
}

View File

@ -72,7 +72,7 @@ class VPCollectListViewController: VPViewController {
private lazy var allSelectedButton: UIButton = {
var config = UIButton.Configuration.plain()
config.attributedTitle = AttributedString.createAttributedString(string: "Select All".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 15))
config.attributedTitle = AttributedString.createAttributedString(string: "veloria_all_select".localized, color: .colorFFFFFF(), font: .fontRegular(ofSize: 15))
config.imagePadding = 6
config.imagePlacement = .leading
config.baseBackgroundColor = .clear
@ -169,7 +169,7 @@ class VPCollectListViewController: VPViewController {
if count > 0 {
requestCancelCollect()
} else {
VPToast.show(text: "kToastText1".localized)
VPToast.show(text: "veloria_delete_short_tip".localized)
}
}
}

View File

@ -51,7 +51,7 @@ class VPMyListViewController: VPViewController {
private lazy var pageParam: WMZPageParam = {
let param = WMZPageParam()
param.wTitleArr = ["My List".localized, "History".localized]
param.wTitleArr = ["veloria_my_list".localized, "veloria_history".localized]
param.wViewController = { [weak self] index in
return self?.viewControllers[index]
}

View File

@ -18,13 +18,14 @@ class VPWatchHistoryCell: VPTableViewCell {
let epString = NSMutableAttributedString()
let currentEP = NSMutableAttributedString(string: String(format: "EP.%@".localized, model?.current_episode ?? ""))
let currentEP = NSMutableAttributedString(string: "veloria_EP.".localizedReplace(text: model?.current_episode ?? ""))
currentEP.color = .color05CEA0()
epString.append(currentEP)
let totalEp = NSMutableAttributedString()
totalEp.appendString(" / ")
totalEp.appendString(String(format: "EP.%@".localized, "\(model?.episode_total ?? 0)"))
totalEp.appendString("veloria_all_episodes".localizedReplace(text: "\(model?.episode_total ?? 0)"))
totalEp.color = .colorFFFFFF(alpha: 0.6)
epString.append(totalEp)

View File

@ -191,10 +191,10 @@ extension VPDetailPlayerViewController {
switch model.status {
case .jump:
VPToast.show(text: "kLockPreviousEpisodeText".localized)
VPToast.show(text: "veloria_jump_unlock_error".localized)
case .noPlay:
VPToast.show(text: "kLockFailText".localized)
VPToast.show(text: "veloria_jump_unlock_error_1".localized)
case .notEnough:
self.onRecharge()

View File

@ -26,7 +26,8 @@ class VPDetailPlayerControlView: VPVideoPlayerControlView {
override var videoInfo: VPVideoInfoModel? {
didSet {
epView.setTitle(String(format: "EP.%@".localized, "\(videoInfo?.episode ?? "0")"), for: .normal)
epView.setTitle("veloria_EP.".localizedReplace(text: videoInfo?.episode ?? "0"), for: .normal)
lockView.isHidden = !(videoInfo?.is_lock ?? false)
lockView.videoInfo = videoInfo
}
@ -34,7 +35,7 @@ class VPDetailPlayerControlView: VPVideoPlayerControlView {
override var shortModel: VPShortModel? {
didSet {
allEpView.setTitle(String(format: "All %@ Episodes".localized, "\(shortModel?.episode_total ?? 0)"), for: .normal)
allEpView.setTitle("veloria_all_episodes".localizedReplace(text: "\(shortModel?.episode_total ?? 0)"), for: .normal)
}
}

View File

@ -61,7 +61,7 @@ class VPDetailRecommandView: HWPanModalContentView {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFFFFF()
label.text = "kDetailRecommandTitle".localized
label.text = "veloria_detail_recommand_title".localized
return label
}()
@ -117,7 +117,7 @@ class VPDetailRecommandView: HWPanModalContentView {
button.startPoint = .init(x: 0, y: 0.3)
button.endPoint = .init(x: 1, y: 0.8)
button.bt_setGradientBorder()
button.setTitle("Watch Now".localized, for: .normal)
button.setTitle("veloria_watch_now".localized, for: .normal)
button.setTitleColor(.colorFFFFFF(), for: .normal)
button.titleLabel?.font = .fontMedium(ofSize: 14)
button.layer.cornerRadius = 24

View File

@ -48,7 +48,7 @@ class VPPlayerCoinBuyView: UIView {
label.numberOfLines = 0
label.textColor = .colorFFFFFF(alpha: 0.5)
label.font = .fontRegular(ofSize: 12)
label.text = "kStoreTips".localized
label.text = "veloria_store_tips_ios".localized
return label
}()

View File

@ -144,8 +144,8 @@ class VPPlayerRechargeView: HWPanModalContentView {
extension VPPlayerRechargeView {
@objc private func updateCoin() {
let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
let text = String(format: "Coins: %@".localized, coinCountStr)
let coinCountStr = " \(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
let text = "veloria_your_coins".localized + coinCountStr
let coinRange = text.ocString().range(of: coinCountStr)
let string = NSMutableAttributedString(string: text)

View File

@ -54,24 +54,24 @@ class VPPlayerVipBuyView: UIView {
private lazy var tipLabel: UILabel = {
let hText1 = "1 week".localized
let text1 = "· " + String(format: "kVipPrivilegeText4".localized, hText1)
// let hText1 = "1 week".localized
let text1 = "· " + "veloria_store_no_ads".localized
let hText2 = "8 days".localized
let text2 = "· " + String(format: "kVipPrivilegeText5".localized, hText2)
// let hText2 = "8 days".localized
let text2 = "· " + "veloria_store_donate_coins".localized
let text3 = "· " + String(format: "kVipPrivilegeText6".localized)
let text3 = "· " + "veloria_store_auto_renew".localized
let text = text1 + "\n" + text2 + "\n" + text3
let hRange1 = text.ocString().range(of: hText1)
let hRange2 = text.ocString().range(of: hText2)
// let hRange1 = text.ocString().range(of: hText1)
// let hRange2 = text.ocString().range(of: hText2)
let string = NSMutableAttributedString(string: text)
string.lineSpacing = 5
string.color = .colorFFFFFF(alpha: 0.8)
string.setColor(.color05CEA0(), range: hRange1)
string.setColor(.color05CEA0(), range: hRange2)
// string.setColor(.color05CEA0(), range: hRange1)
// string.setColor(.color05CEA0(), range: hRange2)

View File

@ -41,9 +41,9 @@ class VPVideoLockView: UIView {
guard let self = self else { return }
let title: String
if hasLastEpisodeUnlocked {
title = "kVideoLockTipText".localized
title = "veloria_video_lock_tip_text".localized
} else {
title = String(format: "Unlocking costs %@ coins".localized, "\(videoInfo?.coins ?? 0)")
title = "veloria_unlocking_costs".localizedReplace(text: "\(videoInfo?.coins ?? 0)")
}
let string = AttributedString.createAttributedString(string: title, color: .colorFFFFFF(), font: .fontRegular(ofSize: 14))
button.configuration?.attributedTitle = string
@ -80,7 +80,7 @@ class VPVideoLockView: UIView {
@objc private func handleUnlockButton() {
if hasLastEpisodeUnlocked {
VPToast.show(text: "kUnlockVideoErrorToast01".localized)
VPToast.show(text: "veloria_jump_unlock_error".localized)
} else {
self.clickUnlockButton?()
}
@ -88,8 +88,7 @@ class VPVideoLockView: UIView {
@objc private func userInfoUpdateNotification() {
let userInfo = VPLoginManager.manager.userInfo
coinCountLabel.text = String(format: "Balance: %@ Coins | %@ Bonus".localized, "\(userInfo?.coin_left_total ?? 0)", "\(userInfo?.send_coin_left_total ?? 0)")
coinCountLabel.text = "veloria_coins_count_text".localizedReplace(text1: "\(userInfo?.coin_left_total ?? 0)", text2: "\(userInfo?.send_coin_left_total ?? 0)")
}
}

View File

@ -208,7 +208,7 @@ extension VPVideoPlayerControlView {
if isCollect {
self.collectShort(isCollect: isCollect)
} else {
let alert = VPAlertView(title: "kUnFavoritesAlertTitle".localized, subtitle: "kUnFavoritesAlertText".localized, icon: UIImage(named: "alert_icon_03"), normalButtonText: nil, highlightButtonText: "Confirm".localized)
let alert = VPAlertView(title: "veloria_un_favorites".localized, subtitle: "veloria_un_favorites_text".localized, icon: UIImage(named: "alert_icon_03"), normalButtonText: nil, highlightButtonText: "veloria_confirm".localized)
alert.show()
alert.clickHighlightButton = { [weak self] in

View File

@ -34,7 +34,7 @@ class VPCoinsViewController: VPViewController {
let label = UILabel()
label.font = .fontMedium(ofSize: 15)
label.textColor = .colorFFFFFF()
label.text = "Get More Coins".localized
label.text = "veloria_get_more_coins".localized
return label
}()
@ -70,7 +70,7 @@ class VPCoinsViewController: VPViewController {
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF(alpha: 0.5)
label.numberOfLines = 0
label.text = "kStoreTips".localized
label.text = "veloria_store_tips_ios".localized
return label
}()
@ -92,8 +92,8 @@ class VPCoinsViewController: VPViewController {
private func updateCoin() {
let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
let text = String(format: "Coins: %@".localized, coinCountStr)
let coinCountStr = " \(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
let text = "veloria_your_coins".localized + coinCountStr
let coinRange = text.ocString().range(of: coinCountStr)
let string = NSMutableAttributedString(string: text)

View File

@ -18,8 +18,8 @@ class VPOrderRecordsViewController: WMZPageController {
private lazy var pageParam: WMZPageParam = {
let param = WMZPageParam()
param.wTitleArr = [
"Coin Record".localized,
"VIP Record".localized
"veloria_coin_record".localized,
"veloria_vip_record".localized
]
param.wViewController = { [weak self] index in
return self?.viewControllers[index]

View File

@ -47,7 +47,7 @@ class VPVipPageViewController: VPViewController {
private lazy var pageParam: WMZPageParam = {
let param = WMZPageParam()
param.wTitleArr = ["VIP".localized, "Coins".localized]
param.wTitleArr = ["vip".localized, "coins".localized]
param.wViewController = { [weak self] index in
return self?.viewControllers[index]
}
@ -95,7 +95,7 @@ class VPVipPageViewController: VPViewController {
override func viewDidLoad() {
super.viewDidLoad()
let rightBar = UIBarButtonItem(title: "Restore".localized, style: .plain, target: self, action: #selector(handleRestore))
let rightBar = UIBarButtonItem(title: "veloria_restore".localized, style: .plain, target: self, action: #selector(handleRestore))
self.navigationItem.rightBarButtonItem = rightBar
vp_setupUI()

View File

@ -33,7 +33,7 @@ class VPVipViewController: VPViewController {
let label = UILabel()
label.font = .fontMedium(ofSize: 15)
label.textColor = .colorFFFFFF()
label.text = "Membership Benefits".localized
label.text = "veloria_membership_benefits".localized
return label
}()
@ -49,12 +49,12 @@ class VPVipViewController: VPViewController {
let view = VPVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_04")
let hText = "1 week".localized
let string = NSMutableAttributedString(string: String(format: "kVipPrivilegeText4".localized, hText))
let hRange = string.string.ocString().range(of: hText)
// let hText = "1 week".localized
let string = NSMutableAttributedString(string: "veloria_store_no_ads".localized)
// let hRange = string.string.ocString().range(of: hText)
string.color = .colorFFFFFF()
string.setColor(.color05CEA0(), range: hRange)
// string.setColor(.color05CEA0(), range: hRange)
view.string = string
@ -65,12 +65,12 @@ class VPVipViewController: VPViewController {
let view = VPVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_05")
let hText = "8 days".localized
let string = NSMutableAttributedString(string: String(format: "kVipPrivilegeText5".localized, hText))
let hRange = string.string.ocString().range(of: hText)
// let hText = "8 days".localized
let string = NSMutableAttributedString(string: "veloria_store_donate_coins".localized)
// let hRange = string.string.ocString().range(of: hText)
string.color = .colorFFFFFF()
string.setColor(.color05CEA0(), range: hRange)
// string.setColor(.color05CEA0(), range: hRange)
view.string = string
return view
@ -80,7 +80,7 @@ class VPVipViewController: VPViewController {
let view = VPVipPrivilegeItemView()
view.icon = UIImage(named: "privilege_icon_06")
let string = NSMutableAttributedString(string: "kVipPrivilegeText6".localized)
let string = NSMutableAttributedString(string: "veloria_store_auto_renew".localized)
string.color = .colorFFFFFF()
@ -111,7 +111,7 @@ class VPVipViewController: VPViewController {
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF(alpha: 0.5)
label.numberOfLines = 0
label.text = "kStoreTips".localized
label.text = "veloria_store_tips_ios".localized
return label
}()

View File

@ -22,19 +22,19 @@ class VPWalletViewController: WMZPageController {
let param = WMZPageParam()
param.wTitleArr = [
[
WMZPageBTNKey.keyName : "Order\nRecords".localized,
WMZPageBTNKey.keyName : "veloria_order_records_1".localized,
WMZPageBTNKey.keyImage : UIImage(named: "order_icon_01")!,
WMZPageBTNKey.keySelectImage : UIImage(named: "order_icon_01_selected")!,
WMZPageBTNKey.keyImageOffset : 6
],
[
WMZPageBTNKey.keyName : "Consumption\nRecords".localized,
WMZPageBTNKey.keyName : "veloria_consumption_records_1".localized,
WMZPageBTNKey.keyImage : UIImage(named: "coin_icon_05")!,
WMZPageBTNKey.keySelectImage : UIImage(named: "coin_icon_05_selected")!,
WMZPageBTNKey.keyImageOffset : 6
],
[
WMZPageBTNKey.keyName : "Reward\nCoins".localized,
WMZPageBTNKey.keyName : "veloria_reward_coins_1".localized,
WMZPageBTNKey.keyImage : UIImage(named: "coin_icon_06")!,
WMZPageBTNKey.keySelectImage : UIImage(named: "coin_icon_06_selected")!,
WMZPageBTNKey.keyImageOffset : 6
@ -105,7 +105,7 @@ class VPWalletViewController: WMZPageController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "My Wallet".localized
self.title = "veloria_my_wallet".localized
self.param = self.pageParam
view.backgroundColor = .clear
downSc?.backgroundColor = .clear

View File

@ -19,16 +19,16 @@ class VPPayTemplateItem: VPModel, SmartCodable {
func getText() -> String {
switch self {
case .week:
return "week".localized
return "week_short_type".localized
case .month:
return "month".localized
return "month_short_type".localized
case .quarter:
return "quarter".localized
return "quarter_short_type".localized
case .year:
return "year".localized
return "year_short_type".localized
}
}
}

View File

@ -25,7 +25,7 @@ class VPCoinsBuyCell: VPCollectionViewCell {
sendBgView.isHidden = false
sendCountLabel.isHidden = false
sendCountLabel.text = String(format: "kBonusCoinCount".localized, "\(sendCoins)")
sendCountLabel.text = "veloria_bonus_count_text".localizedReplace(text: "\(sendCoins)")
let percent = CGFloat(sendCoins) / CGFloat(coins) * 100
sendLabel.text = String(format: "+%.0f%%".localized, percent)

View File

@ -12,7 +12,7 @@ class VPConsumptionRecordsCell: VPWalletBaseCell {
var model: VPConsumptionRecordsModel? {
didSet {
timeLabel.text = model?.created_at
let episode = String(format: "EP.%@".localized, "\(model?.episode ?? "0")") + "\(model?.name ?? "")"
let episode = "veloria_EP.".localizedReplace(text: "\(model?.episode ?? "0")") + "\(model?.name ?? "")"
subtitleLabel.text = episode
coinCountLabel.text = "-\(model?.coins ?? 0)"
}
@ -24,7 +24,7 @@ class VPConsumptionRecordsCell: VPWalletBaseCell {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFFFFF(alpha: 0.9)
label.text = "Purchase Single Episode".localized
label.text = "veloria_purchase_single_episode".localized
return label
}()

View File

@ -20,7 +20,7 @@ class VPGiveCoinRecordsCell: VPWalletBaseCell {
let days = nowDate.differenceDay(date: expireDate)
if days > 0 {
expiresLabel.text = String(format: "Expires in %@ days".localized, "\(days)")
expiresLabel.text = "veloria_expires_days".localizedReplace(text: "\(days)")
} else {
expiresLabel.text = "Expired".localized
}

View File

@ -22,7 +22,7 @@ class VPVIPRecordCell: VPWalletBaseCell {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF(alpha: 0.9)
label.text = "Purchase VIP".localized
label.text = "veloria_purchase_vip".localized
return label
}()

View File

@ -24,7 +24,7 @@ class VPVipBuyCell: VPCollectionViewCell {
if let coin = item?.send_coins, coin > 0 {
sendCoinBgView.isHidden = false
sendCoinView.isHidden = false
let text = String(format: "Extra %@".localized, "\(coin)")
let text = "veloria_extra".localized + " \(coin)"
sendCoinView.setTitle("+" + text, for: .normal)
} else {
sendCoinBgView.isHidden = true

View File

@ -40,7 +40,7 @@ class VPWalletHeaderView: UIView {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF(alpha: 0.8)
label.text = "Total Coins".localized
label.text = "veloria_total_coins".localized
return label
}()
@ -58,13 +58,13 @@ class VPWalletHeaderView: UIView {
private lazy var rechargeCoinView: VPWalletHeaderItemView = {
let view = VPWalletHeaderItemView()
view.title = "Recharge".localized
view.title = "veloria_recharge".localized
return view
}()
private lazy var sendCoinView: VPWalletHeaderItemView = {
let view = VPWalletHeaderItemView()
view.title = "Donate".localized
view.title = "veloria_bonus".localized
return view
}()

View File

@ -19,6 +19,13 @@ class VPAppTool: NSObject {
return keyWindow?.rootViewController
}
///
static var lanuchViewController: UIViewController? {
let storyboard = UIStoryboard(name: "LaunchScreen", bundle: nil)
let vc = storyboard.instantiateInitialViewController()
return vc
}
static var topViewController: UIViewController? {
var resultVC: UIViewController? = self.rootViewController
if let rootNav = resultVC as? UINavigationController {

View File

@ -9,7 +9,7 @@ import UIKit
import EmptyDataSet_Swift
extension UIScrollView {
func vp_addNormalEmpty(image: UIImage? = UIImage(named: "empty_image_01"), title: String? = "kEmptyTitle01".localized, des: String? = "kEmptyDes01".localized) {
func vp_addNormalEmpty(image: UIImage? = UIImage(named: "empty_image_01"), title: String? = "veloria_no_data".localized, des: String? = "veloria_no_data_add".localized) {
let emptyView = VPEmptyView()
emptyView.image = image

View File

@ -14,8 +14,6 @@ class VPLocalizedManager: NSObject {
private let LocalizedDataUserDefaultsKey = "VPLocalizedManager.LocalizedDataUserDefaultsKey"
private let LocalizedDataLocalizedKeyUserDefaultsKey = "VPLocalizedManager.LocalizedDataLocalizedKeyUserDefaultsKey"
///
// var languageList: [SPLanguageModel]?
///
private(set) lazy var localizedData: [String : String]? = UserDefaults.standard.object(forKey: LocalizedDataUserDefaultsKey) as? [String : String]
@ -37,17 +35,17 @@ class VPLocalizedManager: NSObject {
//
var currentLocalizedKey: String {
get {
// var key = (UserDefaults.standard.string(forKey: LocalizedUserDefaultsKey) ?? Locale.preferredLanguages.first) ?? "en"
// if key.contains("zh-Hans") {
// key = "zh"
// } else if key.contains("zh-Hant") {
// key = "zh_hk"
// } else {
// let arr = key.components(separatedBy: "-")
// key = arr.first ?? "en"
// }
// return key
return "en"
var key = UserDefaults.standard.string(forKey: LocalizedUserDefaultsKey) ?? Locale.preferredLanguages.first
if key?.contains("zh-Hans") == true {
key = "zh"
} else if key?.contains("zh-Hant") == true {
key = "zh_hk"
} else {
let arr = key?.components(separatedBy: "-")
key = arr?.first
}
return key ?? "en"
}
set {
UserDefaults.standard.set(newValue, forKey: LocalizedUserDefaultsKey)
@ -97,36 +95,50 @@ class VPLocalizedManager: NSObject {
extension VPLocalizedManager {
///
func updateLocalizedData(key: String = VPLocalizedManager.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.localizedDataLocalizedKey = key
// self.localizedData = localizedData
// completer?(true)
// } else {
// completer?(false)
// }
// }
VPSettingAPI.requestLocalizedData(key: key) { [weak self] model in
guard let self = self else { return }
guard let model = model else {
completer?(false)
return
}
if let localizedData = model.translates {
self.localizedData = localizedData
self.localizedDataLocalizedKey = key
completer?(true)
} else {
completer?(false)
}
}
}
}
extension VPLocalizedManager {
static let localizedDidChange = Notification.Name(rawValue: "VPLocalizedManager.localizedDidChange")
static let localizedDidChangeNotification = Notification.Name(rawValue: "VPLocalizedManager.localizedDidChangeNotification")
}
extension String {
var localized: String {
return VPLocalizedManager.shared.localizedString(forKey: self)
var text = VPLocalizedManager.shared.localizedString(forKey: self)
text = text.replacingOccurrences(of: "<br>", with: "\n")
return text
}
func localizedReplace(text: String) -> String {
return self.localized.replacingOccurrences(of: "##", with: text)
}
func localizedReplace(text1: String, text2: String, text3: String? = nil) -> String {
var string = self.localized.replacingOccurrences(of: "#1#", with: text1)
string = string.replacingOccurrences(of: "#2#", with: text2)
if let text = text3 {
string = string.replacingOccurrences(of: "#3#", with: text)
}
return string
}
}

View File

@ -0,0 +1,17 @@
//
// VPLocalizedModel.swift
// Veloria
//
// Created by on 2025/6/12.
//
import UIKit
import SmartCodable
class VPLocalizedModel: VPModel, SmartCodable {
///
var translates: [String : String]?
var languages: [VPLanguageModel]?
}

View File

@ -38,7 +38,7 @@ class VPIAPManager {
func start(model: VPPayTemplateItem, shortPlayId: String? = nil, videoId: String? = nil, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) {
if let _ = self.waitRestoreModel {
VPToast.show(text: "kIapErrorToast01".localized)
VPToast.show(text: "veloria_pay_error_1".localized)
handler?(false)
return
}
@ -80,7 +80,7 @@ class VPIAPManager {
let receipt = waitRestoreModel.receipt
else {
if isLoding {
VPToast.show(text: "kIapErrorToast03".localized)
VPToast.show(text: "veloria_pay_error_3".localized)
}
return
}
@ -107,7 +107,7 @@ class VPIAPManager {
}
if isLoding {
VPToast.show(text: "Success".localized)
VPToast.show(text: "veloria_succeed".localized)
}
completer?(true)
if buyType == .subVip {
@ -159,7 +159,7 @@ extension VPIAPManager: JXIAPManagerDelegate {
VPLoginManager.manager.userInfo?.is_vip = true
}
VPToast.show(text: "Success".localized)
VPToast.show(text: "veloria_succeed".localized)
self.completionHandler?(true)
if buyType == .subVip {
NotificationCenter.default.post(name: VPIAPManager.buyVipFinishNotification, object: nil)
@ -179,9 +179,9 @@ extension VPIAPManager: JXIAPManagerDelegate {
VPHUD.dismiss()
if code == .noProduct {
VPToast.show(text: "kIapErrorToast02".localized)
VPToast.show(text: "veloria_pay_error_2".localized)
} else if code == .cancelled {
VPToast.show(text: "kIapErrorToast04".localized)
VPToast.show(text: "veloria_pay_error_4".localized)
}
self.completionHandler?(false)
}

View File

@ -8,152 +8,139 @@
"kAppName" = "Veloria";
"Home" = "Home";
"Me" = "Me";
"All" = "All";
"Drama Champions" = "Drama Champions";
"Explore" = "Explore";
"EP.%@" = "EP.%@";
"All %@ Episodes" = "All %@ Episodes";
"Recommended For You" = "Recommended For You";
"Trending Top 10" = "Trending Top 10";
"Latest Trends" = "Latest Trends";
"Search Results" = "Search Results";
"Recent Searches" = "Recent Searches";
"My List" = "My List";
"History" = "History";
"Select All" = "Select All";
"Privacy Policy" = "Privacy Policy";
"User Agreement" = "User Agreement";
"Child Personal Information Protection Rules" = "Child Personal Information Protection Rules";
"Youth Internet Civility Convention" = "Youth Internet Civility Convention";
"Third-party information sharing list" = "Third-party information sharing list";
"Explicit List of Personal Information Collection" = "Explicit List of Personal Information Collection";
"About Us" = "About Us";
"Visitor" = "Visitor";
"Feedback History" = "Feedback History";
"Feedback" = "Feedback";
"Feedback Details" = "Feedback Details";
"Rewards" = "Rewards";
"Join VIP" = "Join VIP";
"VIP Active" = "VIP Active";
"Conins" = "Conins";
"Donate" = "Donate";
"Wallet" = "Wallet";
"Store" = "Store";
"Favorites" = "Favorites";
"Language" = "Language";
"VIP" = "VIP";
"Coins" = "Coins";
"Membership Benefits" = "Membership Benefits";
"1 week" = "1 week";
"8 days" = "8 days";
"week" = "week";
"month" = "month";
"quarter" = "quarter";
"year" = "year";
"Error" = "Error";
"Extra %@" = "Extra %@";
"Get More Coins" = "Get More Coins";
"Coins: %@" = "Coins: %@";
"My Wallet" = "My Wallet";
"Order\nRecords" = "Order\nRecords";
"Consumption\nRecords" = "Consumption\nRecords";
"Reward\nCoins" = "Reward\nCoins";
"Coin Record" = "Coin Record";
"VIP Record" = "VIP Record";
"Total Coins" = "Total Coins";
"Recharge" = "Recharge";
"Unlocking costs %@ coins" = "Unlocking costs %@ coins";
"Balance: %@ Coins | %@ Bonus" = "Balance: %@ Coins | %@ Bonus";
"Check in" = "Check in";
"Welcome to %@" = "Welcome to %@";
"Login with Apple" = "Login with Apple";
"Login with Facebook" = "Login with Facebook";
"Log In" = "Log In";
"Sign Out" = "Sign Out";
"Delete Account" = "Delete Account";
"Account Deletion" = "Account Deletion";
"Delete Account" = "Delete Account";
"Delete Forever" = "Delete Forever";
"Cancel" = "Cancel";
"Log Out" = "Log Out";
"Recharge Coins" = "Recharge Coins";
"Purchase VIP" = "Purchase VIP";
"Purchase Single Episode" = "Purchase Single Episode";
"Check in" = "Check in";
"Expires in %@ days" = "Expires in 30 days";
"veloria_home" = "Home";
"veloria_me" = "Me";
"veloria_all" = "All";
"veloria_drama_champions" = "Drama Champions";
"veloria_explore" = "Explore";
"veloria_EP." = "EP.##";
"veloria_all_episodes" = "All ## Episodes";
"veloria_recommended" = "Recommended For You";
"veloria_trending_top" = "Trending Top 10";
"veloria_latest_trends" = "Latest Trends";
"veloria_search_results" = "Search Results";
"veloria_recent_searches" = "Recent Searches";
"veloria_my_list" = "My List";
"veloria_history" = "History";
"veloria_all_select" = "Select All";
"veloria_my_privacy" = "Privacy Policy";
"veloria_my_agreement" = "User Agreement";
"veloria_child_protection_text" = "Child Personal Information Protection Rules";
"veloria_civizatio_convention_text" = "Youth Internet Civility Convention";
"veloria_information_sharing_text" = "Third-party information sharing list";
"veloria_persoInfor_disclosure_text" = "Explicit List of Personal Information Collection";
"veloria_me_about" = "About Us";
"veloria_visitor" = "Visitor";
"veloria_my_feedback_history" = "Feedback History";
"veloria_my_feedback" = "Feedback";
"veloria_my_feedback_details" = "Feedback Details";
"veloria_rewards" = "Rewards";
"veloria_vip_join" = "Join VIP";
"veloria_vip_active" = "VIP Active";
"coins" = "Coins";
"veloria_bonus" = "Donate";
"veloria_wallet" = "Wallet";
"veloria_store" = "Store";
"veloria_favorites" = "Favorites";
"veloria_language" = "Language";
"vip" = "VIP";
"veloria_membership_benefits" = "Membership Benefits";
"week_short_type" = "Weekly";
"month_short_type" = "Monthly";
"quarter_short_type" = "Quarterly";
"year_short_type" = "Yearly";
"veloria_error" = "Error";
"veloria_extra" = "Extra";
"veloria_get_more_coins" = "Get More Coins";
"veloria_your_coins" = "Your Coins:";
"veloria_my_wallet" = "My Wallet";
"veloria_order_records_1" = "Order<br>Records";
"veloria_consumption_records_1" = "Consumption<br>Records";
"veloria_reward_coins_1" = "Reward<br>Coins";
"veloria_coin_record" = "Coin Record";
"veloria_vip_record" = "VIP Record";
"veloria_total_coins" = "Total Coins";
"veloria_recharge" = "Recharge";
"veloria_unlocking_costs" = "Unlocking costs ## coins";
"veloria_coins_count_text" = "Balance: #1# Coins | #2# Bonus";
"veloria_check_in" = "Check in";
"veloria_welcome_to" = "Welcome to Veloria";
"veloria_login_apple" = "Login with Apple";
"veloria_login_facebook" = "Login with Facebook";
"veloria_login" = "Log In";
"veloria_sign_out" = "Sign Out";
"veloria_delete_account" = "Delete Account";
"veloria_delete_forever" = "Delete Forever";
"veloria_cancel" = "Cancel";
"veloria_log_out" = "Log Out";
"veloria_purchase_vip" = "Purchase VIP";
"veloria_purchase_single_episode" = "Purchase Single Episode";
"veloria_expires_days" = "Expires in ## days";
"Expired" = "Expired";
"Success" = "Success";
"Restore" = "Restore";
"Watch Now" = "Watch Now";
"More" = "More";
"Confirm" = "Confirm";
"Order Record" = "Order Record";
"Allow" = "Allow";
"veloria_succeed" = "Success";
"veloria_restore" = "Restore";
"veloria_watch_now" = "Watch Now";
"veloria_more" = "More";
"veloria_confirm" = "Confirm";
"veloria_order_record" = "Order Record";
"veloria_allow" = "Allow";
"veloria_get_started" = "Get Started";
"kBonusCoinCount" = "+%@ Bonus";
"kEmptyTitle01" = "Nothing Here Yet";
"kEmptyDes01" = "Start exploring and add something!";
"kEmptyTitle02" = "Not Found";
"kEmptyDes02" = "Sorry, we couldn't find anything.";
"kDetailRecommandTitle" = "Picked Just for You";
"kHomeTitleText" = "10,000+ Addictive Shorts Await!";
"kSearchPlaceholderText1" = "Search dramas";
"kSearchPlaceholderText2" = "#Recersal of fate";
"kHomeMenuTitle" = "Select Categories";
"kVipTipText1" = "unlock exclusive dramas";
"kVipTipText2" = "vip expires: %@";
"kVipPrivilegeText1" = "Ad-Free\nStreaming";
"kVipPrivilegeText2" = "Exclusive\nEpisodes";
"kVipPrivilegeText3" = "Daily free\ncoins";
"kVipPrivilegeText4" = "Unlimited access to all series for %@ (No Ads)";
"kVipPrivilegeText5" = "The donate coins will expire in %@";
"kVipPrivilegeText6" = "Auto renew, cancel anytime";
"kLoginAgreementText" = "By logging in you agree to: %@ & %@";
"kVideoLockTipText" = "Please unlock the previous episode";
"veloria_bonus_count_text" = "+## Bonus";
"veloria_no_data" = "Nothing Here Yet";
"veloria_no_data_add" = "Start exploring and add something!";
"veloria_not_found" = "Not Found";
"veloria_not_found_string" = "Sorry, we couldn't find anything.";
"veloria_detail_recommand_title" = "Picked Just for You";
"veloria_addictive_short_await" = "10,000+ Addictive Shorts Await!";
"veloria_search_dramas" = "Search dramas";
"veloria_recersal_of_fate" = "#Recersal of fate";
"veloria_select_categories" = "Select Categories";
"veloria_unlock_exclusive" = "unlock exclusive dramas";
"veloria_vip_expires_date" = "VIP expires: ##";
"veloria_ad_free_streaming_ios" = "Ad-Free<br>Streaming";
"veloria_exclusive_episodes_ios" = "Exclusive<br>Episodes";
"veloria_daily_free_coins_ios" = "Daily free<br>coins";
"veloria_store_no_ads" = "Unlimited access to all series for 1 week (No Ads)";
"veloria_store_donate_coins" = "The donate coins will expire in 8 days";
"veloria_store_auto_renew" = "Auto renew, cancel anytime";
"veloria_login_hint_ios" = "By logging in you agree to: #1# & #2#";
"veloria_video_lock_tip_text" = "Please unlock the previous episode";
//无网提示
"kNetworkToast01" = "The service is abnormal. Check the network.";
"kNetworkToast02" = "Your account is already logged in on another device~";
"veloria_network" = "The service is abnormal. Check the network.";
"veloria_network_error_1" = "Your account is already logged in on another device~";
//解锁上一集提示
"kLockPreviousEpisodeText" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
"veloria_jump_unlock_error" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
//解锁失败
"kLockFailText" = "Purchase failed, please try again later!";
"veloria_jump_unlock_error_1" = "Purchase failed, please try again later!";
//已是会员
"kVipToast01" = "You are already a member!";
"veloria_vip_error_1" = "You are already a member!";
//还有未完成购买
"kIapErrorToast01" = "You have unfinished in-app purchases, please restore them first.";
"kIapErrorToast02" = "Invalid in-app purchase";
"veloria_pay_error_1" = "You have unfinished in-app purchases, please restore them first.";
"veloria_pay_error_2" = "Invalid in-app purchase";
///没有可恢复购买
"kIapErrorToast03" = "There are no in-app purchases to restore.";
"kIapErrorToast04" = "Payment has been cancelled.";
///请购买上一集
"kUnlockVideoErrorToast01" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
"veloria_pay_error_3" = "No in-app purchases can be restored";
"veloria_pay_error_4" = "Payment has been cancelled";
"kStoreTips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
2. Gold coins will never expire, the reward coins will expire 24 hours a day.
3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.
4. The purchase has not been credited, click <Restore> to refresh.
5. For other questions, contact us via Me>Feedback.";
"veloria_store_tips_ios" = "1. Coins are virtual items and cannot be refunded. Use it for this product.<br>2. Gold coins will never expire, the reward coins will expire 24 hours a day.<br>3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.<br>4. The purchase has not been credited, click <Restore> to refresh.<br>5. For other questions, contact us via Me>Feedback.";
//请选择需要删除的短剧
"kToastText1" = "Please select the short plays that need to be deleted";
"veloria_delete_short_tip" = "Please select the short plays that need to be deleted";
"kUnlockButtonText" = "Unlock VIP Benefits";
"veloria_vip_splash_onclick" = "Unlock VIP Benefits";
"kDeleteAccountAlertTitle" = "Confirm Account Deletion";
"kDeleteAccountAlertText" = "This action cannot be undone.";
"kUnFavoritesAlertTitle" = "UnFavorites";
"kUnFavoritesAlertText" = "You may not find this collection after you uncollect it";
"kAPNSAlertTitle" = "Turn on Notifications?";
"kAPNSAlertText" = "Get alerts for new episodes and exclusive offers.";
"kVipAlertTitle" = "Unlock VIP Privileges!";
"kVipAlertText" = "Enjoy ad-free streaming, early access, and exclusive content!";
"kLogoutAlertTitle" = "Ready to Leave?";
"kLogoutAlertText" = "when you sign out, your watch history will not be synced to your account.";
"veloria_confirm_deletion" = "Confirm Account Deletion";
"veloria_action_cannot_undone" = "This action cannot be undone.";
"veloria_un_favorites" = "UnFavorites";
"veloria_un_favorites_text" = "You may not find this collection after you uncollect it";
"open_notice_at_watch_video" = "Turn on Notifications?";
"veloria_open_notice_alert_text" = "Get alerts for new episodes and exclusive offers.";
"veloria_vip_splash_title" = "Unlock VIP Privileges!";
"veloria_vip_splash_content" = "Enjoy ad-free streaming, early access, and exclusive content!";
"veloria_ready_to_leave" = "Ready to Leave?";
"veloria_ready_to_leave_text" = "when you sign out, your watch history will not be synced to your account.";
"DeleteAccount_tips_1" = "Your account will be permanently deleted";
"DeleteAccount_tips_2" = "You will not be able to log in with this user ID";