Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Reduce amount of requests to download localization. #286

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Example/AppleReminders.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = C66Y3DM74C;
INFOPLIST_FILE = AppleReminders/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -759,6 +760,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = C66Y3DM74C;
INFOPLIST_FILE = AppleReminders/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
7 changes: 6 additions & 1 deletion Example/AppleReminders/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
//

import UIKit
import DebugSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
true

DebugSwift.setup()
DebugSwift.show()

return true
}

// MARK: UISceneSession Lifecycle
Expand Down
3 changes: 0 additions & 3 deletions Example/AppleReminders/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import UIKit
import CrowdinSDK
import netfox

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
Expand All @@ -22,8 +21,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
private let clientSecret = "client_secret"

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
NFX.sharedInstance().start()

let crowdinProviderConfig = CrowdinProviderConfig(hashString: distributionHash,
sourceLanguage: sourceLanguage)
let loginConfig = try! CrowdinLoginConfig(clientId: clientId,
Expand Down
2 changes: 1 addition & 1 deletion Example/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ target 'AppleReminders' do
pod 'RealmSwift'
pod 'SwiftDate'
pod 'SwiftLint'
pod 'netfox', :configurations => ['Debug']
pod 'DebugSwift', :configurations => ['Debug']

pod 'CrowdinSDK', :path => '../'
pod 'CrowdinSDK/Settings', :path => '../'
Expand Down
10 changes: 5 additions & 5 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ PODS:
- CrowdinSDK/RealtimeUpdate
- CrowdinSDK/RefreshLocalization
- CrowdinSDK/Screenshots
- netfox (1.21.0)
- DebugSwift (0.3.6)
- Realm (10.42.0):
- Realm/Headers (= 10.42.0)
- Realm/Headers (10.42.0)
Expand All @@ -59,15 +59,15 @@ PODS:
DEPENDENCIES:
- CrowdinSDK (from `../`)
- CrowdinSDK/Settings (from `../`)
- netfox
- DebugSwift
- RealmSwift
- SwiftDate
- SwiftLint

SPEC REPOS:
trunk:
- BaseAPI
- netfox
- DebugSwift
- Realm
- RealmSwift
- Starscream
Expand All @@ -81,13 +81,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
BaseAPI: 7a3abac9fa1e19147a5c87dcfbb1829a584cd1ca
CrowdinSDK: 65fd7989c86e5ff79c8734979bc61510238d8725
netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
DebugSwift: f766d934affddea9ffe36b0cf2631cd28311481f
Realm: 490aad28f1360e58fc22256d5d686d3a36525346
RealmSwift: f6a9b56d747bbdd7931de1835896c5f024b6898a
Starscream: fb2c4510bebf908c62bd383bcf05e673720e91fd
SwiftDate: bbc26e26fc8c0c33fbee8c140c5e8a68293a148a
SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3

PODFILE CHECKSUM: 074b840e8445d9c503f88d22ae46cf4abf8bae59
PODFILE CHECKSUM: 5664bd8b1580f61ed499f2165acb89a39868332c

COCOAPODS: 1.15.2
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extension CrowdinSDK {
guard let config = CrowdinSDK.config else { return }
let crowdinProviderConfig = config.crowdinProviderConfig ?? CrowdinProviderConfig()
if config.realtimeUpdatesEnabled {
RealtimeUpdateFeature.shared = RealtimeUpdateFeature(hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, organizationName: config.crowdinProviderConfig?.organizationName)
RealtimeUpdateFeature.shared = RealtimeUpdateFeature(hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, organizationName: config.crowdinProviderConfig?.organizationName, minimumUpdateInterval: crowdinProviderConfig.minimumManifestUpdateInterval)
swizzleControlMethods()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class RURemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
let fileDownloader: RUFilesDownloader
let manifestManager: ManifestManager

init(localization: String, sourceLanguage: String, hash: String, projectId: String, organizationName: String?) {
init(localization: String, sourceLanguage: String, hash: String, projectId: String, organizationName: String?, minimumManifestUpdateInterval: TimeInterval) {
self.localization = localization
self.hash = hash
manifestManager = ManifestManager.manifest(for: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
manifestManager = ManifestManager.manifest(for: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
self.fileDownloader = RUFilesDownloader(projectId: projectId, manifestManager: manifestManager, organizationName: organizationName)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protocol RealtimeUpdateFeatureProtocol {
var disconnect: (() -> Void)? { get set }
var enabled: Bool { get set }

init(hash: String, sourceLanguage: String, organizationName: String?)
init(hash: String, sourceLanguage: String, organizationName: String?, minimumUpdateInterval: TimeInterval)

func start()
func stop()
Expand All @@ -29,7 +29,7 @@ protocol RealtimeUpdateFeatureProtocol {
func refreshAllControls()
}

class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
static var shared: RealtimeUpdateFeatureProtocol?

var success: (() -> Void)?
Expand All @@ -39,9 +39,10 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
let localizations = Localization.current.provider.remoteStorage.localizations
return CrowdinSDK.currentLocalization ?? Bundle.main.preferredLanguage(with: localizations)
}
var hashString: String
let hashString: String
let sourceLanguage: String
let organizationName: String?
let minimumManifestUpdateInterval: TimeInterval

var distributionResponse: DistributionsResponse? = nil

Expand All @@ -59,11 +60,12 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
private var socketManger: CrowdinSocketManagerProtocol?
private var mappingManager: CrowdinMappingManagerProtocol

required init(hash: String, sourceLanguage: String, organizationName: String?) {
required init(hash: String, sourceLanguage: String, organizationName: String?, minimumUpdateInterval minimumManifestUpdateInterval: TimeInterval) {
self.hashString = hash
self.sourceLanguage = sourceLanguage
self.organizationName = organizationName
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.minimumManifestUpdateInterval = minimumManifestUpdateInterval
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}

func downloadDistribution(with successHandler: (() -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
Expand Down Expand Up @@ -120,7 +122,7 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
}
setupRealtimeUpdatesLocalizationProvider(with: projectId) { [weak self] in
guard let self = self else { return }
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl)
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}
}

Expand All @@ -136,7 +138,7 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {

func setupRealtimeUpdatesLocalizationProvider(with projectId: String, completion: @escaping () -> Void) {
oldProvider = Localization.current.provider
Localization.current.provider = LocalizationProvider(localization: self.localization, localStorage: RULocalLocalizationStorage(localization: self.localization), remoteStorage: RURemoteLocalizationStorage(localization: self.localization, sourceLanguage: sourceLanguage, hash: self.hashString, projectId: projectId, organizationName: self.organizationName))
Localization.current.provider = LocalizationProvider(localization: self.localization, localStorage: RULocalLocalizationStorage(localization: self.localization), remoteStorage: RURemoteLocalizationStorage(localization: self.localization, sourceLanguage: sourceLanguage, hash: self.hashString, projectId: projectId, organizationName: self.organizationName, minimumManifestUpdateInterval: self.minimumManifestUpdateInterval))

Localization.current.provider.refreshLocalization { [weak self] error in
guard let self = self else { return }
Expand All @@ -163,13 +165,13 @@ class RealtimeUpdateFeature: RealtimeUpdateFeatureProtocol {
}
}

func setupSocketManager(with projectId: String, projectWsHash: String, userId: String, wsUrl: String) {
func setupSocketManager(with projectId: String, projectWsHash: String, userId: String, wsUrl: String, minimumManifestUpdateInterval: TimeInterval) {
// Download manifest if it is not initialized.
let manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName)
let manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
guard manifestManager.downloaded else {
manifestManager.download { [weak self] in
guard let self = self else { return }
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl)
self.setupSocketManager(with: projectId, projectWsHash: projectWsHash, userId: userId, wsUrl: wsUrl, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension CrowdinSDK {
guard let config = CrowdinSDK.config else { return }
if config.screenshotsEnabled {
let crowdinProviderConfig = config.crowdinProviderConfig ?? CrowdinProviderConfig()
let screenshotUploader = CrowdinScreenshotUploader(organizationName: config.crowdinProviderConfig?.organizationName, hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage)
let screenshotUploader = CrowdinScreenshotUploader(organizationName: config.crowdinProviderConfig?.organizationName, hash: crowdinProviderConfig.hashString, sourceLanguage: crowdinProviderConfig.sourceLanguage, minimumManifestUpdateInterval: crowdinProviderConfig.minimumManifestUpdateInterval)
ScreenshotFeature.shared = ScreenshotFeature(screenshotUploader: screenshotUploader, screenshotProcessor: CrowdinScreenshotProcessor())
swizzleControlMethods()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ class CrowdinScreenshotUploader: ScreenshotUploader {
case noLocalizedStringsDetected = "There are no localized strings detected on current screen."
}

init(organizationName: String?, hash: String, sourceLanguage: String) {
init(organizationName: String?, hash: String, sourceLanguage: String, minimumManifestUpdateInterval: TimeInterval) {
self.organizationName = organizationName
self.hash = hash
self.sourceLanguage = sourceLanguage
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.mappingManager = CrowdinMappingManager(hash: hash, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
}

func loginAndGetProjectId(success: (() -> Void)? = nil, errorHandler: ((Error) -> Void)? = nil) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ import Foundation
var hashString: String
var sourceLanguage: String
var organizationName: String?
var minimumManifestUpdateInterval: TimeInterval

public init(hashString: String, sourceLanguage: String, organizationName: String? = nil) {
public init(hashString: String, sourceLanguage: String, organizationName: String? = nil, minimumManifestUpdateInterval: TimeInterval = Constants.defaultMinimumManifestUpdateInterval) {
self.hashString = hashString
self.sourceLanguage = sourceLanguage
self.organizationName = organizationName
self.minimumManifestUpdateInterval = minimumManifestUpdateInterval
}

@available(*, deprecated, renamed: "init(hashString:sourceLanguage:)")
public init(hashString: String, localizations: [String], sourceLanguage: String) {
self.hashString = hashString
self.sourceLanguage = sourceLanguage
self.minimumManifestUpdateInterval = Constants.defaultMinimumManifestUpdateInterval
}

public override init() {
Expand All @@ -33,5 +36,11 @@ import Foundation
fatalError("Please add CrowdinPluralsFileNames key to your Info.plist file")
}
self.sourceLanguage = crowdinSourceLanguage
self.minimumManifestUpdateInterval = Constants.defaultMinimumManifestUpdateInterval
}

public enum Constants {
// New default minimum interval for manifest updates
public static let defaultMinimumManifestUpdateInterval: TimeInterval = 15 * 60 // 15 minutes
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class CrowdinRemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
self.localization = localization
self.hashString = config.hashString
self.organizationName = config.organizationName
self.manifestManager = ManifestManager.manifest(for: config.hashString, sourceLanguage: config.sourceLanguage, organizationName: config.organizationName)
self.manifestManager = ManifestManager.manifest(for: config.hashString, sourceLanguage: config.sourceLanguage, organizationName: config.organizationName, minimumManifestUpdateInterval: config.minimumManifestUpdateInterval)
self.crowdinDownloader = CrowdinLocalizationDownloader(manifestManager: manifestManager)
self.localizations = self.manifestManager.iOSLanguages
self.crowdinSupportedLanguages = CrowdinSupportedLanguages(organizationName: config.organizationName)
Expand Down Expand Up @@ -58,13 +58,13 @@ class CrowdinRemoteLocalizationStorage: RemoteLocalizationStorageProtocol {
})
}

required init(localization: String, sourceLanguage: String, organizationName: String?) {
required init(localization: String, sourceLanguage: String, organizationName: String?, minimumManifestUpdateInterval: TimeInterval) {
self.localization = localization
guard let hashString = Bundle.main.crowdinDistributionHash else {
fatalError("Please add CrowdinDistributionHash key to your Info.plist file")
}
self.hashString = hashString
self.manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName)
self.manifestManager = ManifestManager.manifest(for: hashString, sourceLanguage: sourceLanguage, organizationName: organizationName, minimumManifestUpdateInterval: minimumManifestUpdateInterval)
self.crowdinDownloader = CrowdinLocalizationDownloader(manifestManager: self.manifestManager)
self.localizations = []
self.crowdinSupportedLanguages = CrowdinSupportedLanguages(organizationName: organizationName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ extension CrowdinSDK {
/// - errorHandler: Error handler.
public class func localizationDictionary(for localization: String, hashString: String, completion: @escaping ([AnyHashable: Any]) -> Void, errorHandler: @escaping (Error) -> Void) {
let localLocalizationStorage = LocalLocalizationStorage(localization: localization)
let remoteLocalizationStorage = CrowdinRemoteLocalizationStorage(localization: localization, config: CrowdinProviderConfig(hashString: hashString, sourceLanguage: .empty, organizationName: nil))
// Hardcode value for minimumManifestUpdateInterval as ReactNative support will be removed.
let remoteLocalizationStorage = CrowdinRemoteLocalizationStorage(localization: localization, config: CrowdinProviderConfig(hashString: hashString, sourceLanguage: .empty, organizationName: nil, minimumManifestUpdateInterval: 15 * 60))
remoteLocalizationStorage.prepare {
localizationProvider = LocalizationProvider(localization: localization, localStorage: localLocalizationStorage, remoteStorage: remoteLocalizationStorage)
localizationProvider?.refreshLocalization(completion: { error in
Expand Down
Loading