Skip to content

Instantly share code, notes, and snippets.

@yoxisem544
Created May 15, 2023 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoxisem544/a42244b418c94eaf1d9e38eadf526a06 to your computer and use it in GitHub Desktop.
Save yoxisem544/a42244b418c94eaf1d9e38eadf526a06 to your computer and use it in GitHub Desktop.
//
// 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