Created
May 15, 2023 13:49
-
-
Save yoxisem544/a42244b418c94eaf1d9e38eadf526a06 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Localization.swift | |
// | |
// | |
// Created by David on 2021/3/30. | |
// | |
import Foundation | |
import Lokalise | |
import Domain | |
extension String { | |
func lokalised(_ language: Localization.CurrentSupportLanguage? = nil) -> String { | |
let bundle = Localization.shared.updatedLokaliseBundle ?? Localization.shared.lokaliseBundle ?? Bundle.main | |
if | |
let language = language ?? Localization.shared.appLanguage, | |
let languagePath = bundle.path(forResource: language.projectName, ofType: "lproj"), | |
let languageBundle = Bundle(path: languagePath) | |
{ | |
return languageBundle.localizedString(forKey: self, value: nil, table: "Localizable") | |
} else { | |
return NSLocalizedString(self, comment: self) | |
} | |
} | |
func lokalised(with parameters: Any..., language: Localization.CurrentSupportLanguage? = nil) -> String { | |
var string = lokalised(language) | |
parameters | |
.map { "\($0)" } | |
.forEach { | |
if let range = string.range(of: "%@") { | |
string.replaceSubrange(range, with: $0) | |
} | |
} | |
return string | |
} | |
} | |
/// A wrapper of Lokalise. | |
final class Localization { | |
static let shared = Localization() | |
private init() {} | |
enum CurrentSupportLanguage: String, CaseIterable { | |
case english = "en-US" | |
case tranditionalChinese = "zh-TW" | |
var projectName: String { | |
switch self { | |
case .english: return "en" | |
case .tranditionalChinese: return "zh-Hant" | |
} | |
} | |
var appDisplayText: String { | |
switch self { | |
case .english: return "English" | |
case .tranditionalChinese: return "繁體中文" | |
} | |
} | |
var locale: Locale { | |
switch self { | |
case .english: return Locale(identifier: "en-US") | |
case .tranditionalChinese: return Locale(identifier: "zh-Hant") | |
} | |
} | |
} | |
var appLanguage: CurrentSupportLanguage? { | |
CurrentSupportLanguage(rawValue: SteakerAppEntityProvider.default.makeAppSettings().userSetAppLanguage ?? "") | |
} | |
var preferredServerLanguage: CurrentSupportLanguage { | |
if let appLanguage = appLanguage { | |
return appLanguage | |
} else { | |
if let firstLanguage = Bundle.main.preferredLocalizations.first, firstLanguage.hasPrefix("zh") { | |
// Map all chinese to transitional chinese | |
return .tranditionalChinese | |
} else { | |
// if language is not supported or english | |
return .english | |
} | |
} | |
} | |
func setupLokalise() { | |
Lokalise.shared.setProjectID(XcodeConfig.lokaliseProjectID, token: XcodeConfig.lokaliseToken) | |
Lokalise.shared.swizzleMainBundle() | |
fetchLokaliseBundleFromLibraryCache() | |
switch XcodeConfig.lokaliseMode { | |
case .debug: | |
Lokalise.shared.localizationType = .prerelease | |
case .prerelease: | |
Lokalise.shared.localizationType = .prerelease | |
case .release: | |
Lokalise.shared.localizationType = .release | |
} | |
printDebugInfo() | |
} | |
fileprivate var lokaliseBundle: Bundle? | |
fileprivate var updatedLokaliseBundle: Bundle? | |
/// Trigger Lokalise to fetch new bundle updates from server. | |
func checkUpdates() { | |
Lokalise.shared.checkForUpdates(completion: { [weak self] updated, error in | |
if error == nil { | |
if updated { | |
/* there is a new bundle downloaded from Lokalise. */ | |
self?.fetchUpdatedLokaliseBundleFromDiskAndStoreToDocument() | |
} | |
else { | |
/* there is no new updates, remains the same. */ | |
self?.removeLokaliseBundleInDocumentDirectoryIfExist() | |
} | |
} else { | |
// check updates error, bundle not updated. | |
} | |
}) | |
} | |
private func fetchLokaliseBundleFromLibraryCache() { | |
let paths = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask) | |
for path in paths { | |
// get downloaded lokalise bundle from disk. | |
let lokaliseBundlePath = path.appendingPathComponent("Lokalise").appendingPathComponent("(\(AppEnvProvider.currentDevice.appBundleVersion))Lokalise.bundle") | |
lokaliseBundle = Bundle(url: lokaliseBundlePath) | |
} | |
} | |
private func fetchUpdatedLokaliseBundleFromDiskAndStoreToDocument() { | |
let paths = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask) | |
for path in paths { | |
// get downloaded lokalise bundle from disk. | |
let lokaliseBundlePath = path.appendingPathComponent("Lokalise").appendingPathComponent("(\(AppEnvProvider.currentDevice.appBundleVersion))Lokalise.bundle") | |
if let updatedFile = lokaliseBundleInDocumentDirectoryURL { | |
removeLokaliseBundleInDocumentDirectoryIfExist() | |
// copy bundle from Library to Document | |
try? FileManager.default.copyItem(atPath: lokaliseBundlePath.path, toPath: updatedFile.path) | |
updatedLokaliseBundle = Bundle(url: updatedFile) | |
break | |
} | |
} | |
} | |
private var lokaliseBundleInDocumentDirectoryURL: URL? { | |
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("Lokalise").appendingPathExtension("bundle") | |
} | |
private func removeLokaliseBundleInDocumentDirectoryIfExist() { | |
// remove file if exist. | |
guard let updatedFile = lokaliseBundleInDocumentDirectoryURL else { return } | |
if FileManager.default.fileExists(atPath: updatedFile.path) { | |
try? FileManager.default.removeItem(at: updatedFile) | |
} | |
} | |
/// Print debug info of Lokalise | |
func printDebugInfo() { | |
let info = """ | |
\n\n==== | |
Locale | |
Locale.preferredLanguages | |
\(Locale.preferredLanguages) | |
Locale.current.identifier | |
\(Locale.current.identifier) | |
Bundle | |
Bundle.main.localizations | |
\(Bundle.main.localizations) | |
Bundle.main.preferredLocalizations | |
\(Bundle.main.preferredLocalizations) | |
Bundle.main.developmentLocalization | |
\(Bundle.main.developmentLocalization ?? "undefined") | |
Lokalise | |
Lokalise.shared.availableLocales .identifier | |
\(Lokalise.shared.availableLocales().map({$0.identifier})) | |
Lokalise.shared.localizationLocale.identifier | |
\(Lokalise.shared.localizationLocale.identifier) | |
Lokalise.shared.lokaliseBundleVersion | |
\(Lokalise.shared.lokaliseBundleVersion) | |
LokaliseFrameworkVersion | |
\(LokaliseFrameworkVersion) | |
""" | |
print(info) | |
} | |
} | |
extension Localization { | |
static func generalErrorTitle(of error: SteakerNetworkError) -> String { | |
switch error { | |
case let .networkError(httpStatusCode: statusCode, code: _, localeMessage: _): | |
if 400...499 ~= statusCode { | |
return "error_400".lokalised() | |
} else { | |
return "error_500".lokalised() | |
} | |
case .decodeError: | |
return "error_500".lokalised() | |
case .noConnectionError: | |
return "error_500".lokalised() | |
case .timeOutError: | |
return "error_500".lokalised() | |
case .unknownError: | |
return "error_500".lokalised() | |
} | |
} | |
static func generalErrorMessage(of error: SteakerNetworkError) -> String { | |
switch error { | |
case let .networkError(httpStatusCode: _, code: _, localeMessage: localeMessage): | |
return localeMessage ?? "network_error_general_text".lokalised() | |
case .decodeError(error: let error): | |
return "k_system_decode_error, reason: \(error)" | |
case .noConnectionError: | |
return "k_system_no_internet_error" | |
case .timeOutError: | |
return "k_system_time_out_error" | |
case .unknownError: | |
return "network_error_general_text".lokalised() | |
} | |
} | |
static var systemErrorTitle: String { | |
"error_500".lokalised() | |
} | |
static var networkErrorTitle: String { | |
"error_400".lokalised() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment