diff --git a/LocalizationManager.xcodeproj/project.pbxproj b/LocalizationManager.xcodeproj/project.pbxproj index 10dfd08..ab9e083 100644 --- a/LocalizationManager.xcodeproj/project.pbxproj +++ b/LocalizationManager.xcodeproj/project.pbxproj @@ -91,15 +91,15 @@ B464DB702319CCAE00713265 /* LocalizationManager+ApplicationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B464DB6C2319CCAE00713265 /* LocalizationManager+ApplicationState.swift */; }; B4B6C94F231ECB8B001A8E5C /* DefaultLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B6C94E231ECB8B001A8E5C /* DefaultLanguage.swift */; }; B4B6C954231ED7B8001A8E5C /* LocalizationManager_iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = B4B6C953231ED7B7001A8E5C /* LocalizationManager_iOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B4B6C966231ED7D4001A8E5C /* Localization_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localization_da-DK.json */; }; - B4B6C967231ED7D4001A8E5C /* Localization_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localization_da-DK.json */; }; - B4B6C968231ED7D4001A8E5C /* Localization_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localization_da-DK.json */; }; - B4B6C969231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localization_fr-FR.json */; }; - B4B6C96A231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localization_fr-FR.json */; }; - B4B6C96B231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localization_fr-FR.json */; }; - B4B6C96C231ED7D4001A8E5C /* Localization_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localization_en-GB.json */; }; - B4B6C96D231ED7D4001A8E5C /* Localization_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localization_en-GB.json */; }; - B4B6C96E231ED7D4001A8E5C /* Localization_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localization_en-GB.json */; }; + B4B6C966231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localizations_da-DK.json */; }; + B4B6C967231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localizations_da-DK.json */; }; + B4B6C968231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C956231ED7D4001A8E5C /* Localizations_da-DK.json */; }; + B4B6C969231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localizations_fr-FR.json */; }; + B4B6C96A231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localizations_fr-FR.json */; }; + B4B6C96B231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C957231ED7D4001A8E5C /* Localizations_fr-FR.json */; }; + B4B6C96C231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localizations_en-GB.json */; }; + B4B6C96D231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localizations_en-GB.json */; }; + B4B6C96E231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */ = {isa = PBXBuildFile; fileRef = B4B6C958231ED7D4001A8E5C /* Localizations_en-GB.json */; }; B4B6C96F231ED7D4001A8E5C /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B6C95A231ED7D4001A8E5C /* Localization.swift */; }; B4B6C970231ED7D4001A8E5C /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B6C95A231ED7D4001A8E5C /* Localization.swift */; }; B4B6C971231ED7D4001A8E5C /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4B6C95A231ED7D4001A8E5C /* Localization.swift */; }; @@ -193,9 +193,9 @@ B490AD7123356F4B00260A17 /* AutoMockable.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoMockable.generated.swift; sourceTree = ""; }; B4B6C94E231ECB8B001A8E5C /* DefaultLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultLanguage.swift; sourceTree = ""; }; B4B6C953231ED7B7001A8E5C /* LocalizationManager_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalizationManager_iOS.h; sourceTree = ""; }; - B4B6C956231ED7D4001A8E5C /* Localization_da-DK.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localization_da-DK.json"; sourceTree = ""; }; - B4B6C957231ED7D4001A8E5C /* Localization_fr-FR.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localization_fr-FR.json"; sourceTree = ""; }; - B4B6C958231ED7D4001A8E5C /* Localization_en-GB.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localization_en-GB.json"; sourceTree = ""; }; + B4B6C956231ED7D4001A8E5C /* Localizations_da-DK.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localizations_da-DK.json"; sourceTree = ""; }; + B4B6C957231ED7D4001A8E5C /* Localizations_fr-FR.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localizations_fr-FR.json"; sourceTree = ""; }; + B4B6C958231ED7D4001A8E5C /* Localizations_en-GB.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Localizations_en-GB.json"; sourceTree = ""; }; B4B6C95A231ED7D4001A8E5C /* Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; B4B6C95D231ED7D4001A8E5C /* LocalizationsRepositoryMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationsRepositoryMock.swift; sourceTree = ""; }; B4B6C95E231ED7D4001A8E5C /* FileManagerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileManagerMock.swift; sourceTree = ""; }; @@ -350,9 +350,9 @@ B4B6C955231ED7D4001A8E5C /* Resources */ = { isa = PBXGroup; children = ( - B4B6C956231ED7D4001A8E5C /* Localization_da-DK.json */, - B4B6C957231ED7D4001A8E5C /* Localization_fr-FR.json */, - B4B6C958231ED7D4001A8E5C /* Localization_en-GB.json */, + B4B6C956231ED7D4001A8E5C /* Localizations_da-DK.json */, + B4B6C957231ED7D4001A8E5C /* Localizations_fr-FR.json */, + B4B6C958231ED7D4001A8E5C /* Localizations_en-GB.json */, ); path = Resources; sourceTree = ""; @@ -752,9 +752,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - B4B6C96D231ED7D4001A8E5C /* Localization_en-GB.json in Resources */, - B4B6C96A231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */, - B4B6C967231ED7D4001A8E5C /* Localization_da-DK.json in Resources */, + B4B6C96D231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */, + B4B6C96A231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */, + B4B6C967231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -776,9 +776,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - B4B6C96E231ED7D4001A8E5C /* Localization_en-GB.json in Resources */, - B4B6C96B231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */, - B4B6C968231ED7D4001A8E5C /* Localization_da-DK.json in Resources */, + B4B6C96E231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */, + B4B6C96B231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */, + B4B6C968231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -793,9 +793,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - B4B6C96C231ED7D4001A8E5C /* Localization_en-GB.json in Resources */, - B4B6C969231ED7D4001A8E5C /* Localization_fr-FR.json in Resources */, - B4B6C966231ED7D4001A8E5C /* Localization_da-DK.json in Resources */, + B4B6C96C231ED7D4001A8E5C /* Localizations_en-GB.json in Resources */, + B4B6C969231ED7D4001A8E5C /* Localizations_fr-FR.json in Resources */, + B4B6C966231ED7D4001A8E5C /* Localizations_da-DK.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverDelegate.swift b/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverDelegate.swift index 9d38d20..c3b9df4 100644 --- a/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverDelegate.swift +++ b/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverDelegate.swift @@ -10,7 +10,7 @@ import Foundation /// A delegate protocol for application state observer which you should implement if you /// want to listen to application state changes. -internal protocol ApplicationStateObserverDelegate: class { +internal protocol ApplicationStateObserverDelegate: AnyObject { /// A function called whenever an application state changes. /// diff --git a/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverType.swift b/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverType.swift index 4c64d75..c6d2643 100644 --- a/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverType.swift +++ b/LocalizationManager/Classes/Application State Observer/ApplicationStateObserverType.swift @@ -9,7 +9,7 @@ import Foundation /// A type of class that can observe application state. -internal protocol ApplicationStateObserverType: class { +internal protocol ApplicationStateObserverType: AnyObject { var delegate: ApplicationStateObserverDelegate? { get set } func startObserving() func stopObserving() diff --git a/LocalizationManager/Classes/Manager/AcceptLanguageProvider.swift b/LocalizationManager/Classes/Manager/AcceptLanguageProvider.swift index 0d55f91..6b12758 100644 --- a/LocalizationManager/Classes/Manager/AcceptLanguageProvider.swift +++ b/LocalizationManager/Classes/Manager/AcceptLanguageProvider.swift @@ -8,7 +8,7 @@ import Foundation -public protocol AcceptLanguageProviderType: class { +public protocol AcceptLanguageProviderType: AnyObject { /// Creates the accept language provider. /// diff --git a/LocalizationManager/Classes/Manager/LocalizationManager+ApplicationState.swift b/LocalizationManager/Classes/Manager/LocalizationManager+ApplicationState.swift index 2560eb1..4d2e9c8 100644 --- a/LocalizationManager/Classes/Manager/LocalizationManager+ApplicationState.swift +++ b/LocalizationManager/Classes/Manager/LocalizationManager+ApplicationState.swift @@ -18,10 +18,12 @@ extension LocalizationManager: ApplicationStateObserverDelegate { case .automatic: // Update localizations when we go to foreground and update mode is automatic updateLocalizations() - case .manual: // Don't do anything on manual update mode break + case .never: + // Same goes for never + break } case .background: diff --git a/LocalizationManager/Classes/Manager/LocalizationManager.swift b/LocalizationManager/Classes/Manager/LocalizationManager.swift index 721b5ee..5861b9c 100644 --- a/LocalizationManager/Classes/Manager/LocalizationManager.swift +++ b/LocalizationManager/Classes/Manager/LocalizationManager.swift @@ -215,7 +215,7 @@ public class LocalizationManager w stateObserver.startObserving() // Load persisted or fallback translations - if (try? localization()) == nil { + if (try? localization(lookupPersistedLocalizations: updateMode != .never)) == nil { parseFallbackJSONLocalizations() } @@ -223,10 +223,12 @@ public class LocalizationManager w case .automatic: // Try updating the localizations updateLocalizations() - case .manual: // Don't do anything on manual update mode break + case .never: + // Same goes for never + break } } @@ -563,7 +565,7 @@ public class LocalizationManager w /// If a persisted version cannot be found, the fallback json file in the bundle will be used. /// /// - Returns: A localizations object. - public func localization(localeId: String? = nil) throws -> T { + public func localization(localeId: String? = nil, lookupPersistedLocalizations: Bool = true) throws -> T { guard let locale = localeId ?? bestFitLanguage?.locale.identifier ?? languageOverride?.locale.identifier ?? getAvailablePreferredLanguageLocale() @@ -584,7 +586,7 @@ public class LocalizationManager w } // Load persisted or fallback localizations - try createLocalizationObject(locale) + try createLocalizationObject(locale, lookupPersistedLocalizations: lookupPersistedLocalizations) // Now we must have correct localizations, so return it if let to = localizableObjectDictonary[locale] as? T { @@ -620,22 +622,27 @@ public class LocalizationManager w } /// Loads and initializes the localizations object from either persisted or fallback dictionary. - func createLocalizationObject(_ localeId: String) throws { + func createLocalizationObject(_ localeId: String, lookupPersistedLocalizations: Bool = true) throws { let localization: LocalizationResponse var shouldUnwrapLocalization = false - //try to use persisted localizations for locale - if let persisted = try persistedLocalization(localeId: localeId), - let typeString = userDefaults.string(forKey: Constants.Keys.persistedLocalizationType), - let localizationType = PersistedLocalizationType(rawValue: typeString) { - localization = persisted - shouldUnwrapLocalization = localizationType == .all // only unwrap when all localizations are stored + if lookupPersistedLocalizations { + //try to use persisted localizations for locale + if let persisted = try persistedLocalization(localeId: localeId), + let typeString = userDefaults.string(forKey: Constants.Keys.persistedLocalizationType), + let localizationType = PersistedLocalizationType(rawValue: typeString) { + localization = persisted + shouldUnwrapLocalization = localizationType == .all // only unwrap when all localizations are stored + } else { + //otherwise search for fallback + localization = try fallbackLocalization(localeId: localeId) + } } else { - //otherwise search for fallback localization = try fallbackLocalization(localeId: localeId) } + // Figure out and set localizations guard let parsed = try processAllLocalizations(localization, shouldUnwrap: shouldUnwrapLocalization) else { localizableObjectDictonary.removeValue(forKey: localeId) diff --git a/LocalizationManager/Classes/Models/UpdateMode.swift b/LocalizationManager/Classes/Models/UpdateMode.swift index 715fe98..aaa9d89 100644 --- a/LocalizationManager/Classes/Models/UpdateMode.swift +++ b/LocalizationManager/Classes/Models/UpdateMode.swift @@ -15,4 +15,5 @@ import Foundation public enum UpdateMode { case automatic case manual + case never } diff --git a/LocalizationManager/Classes/Protocols/LocalizationManagerDelegate.swift b/LocalizationManager/Classes/Protocols/LocalizationManagerDelegate.swift index 59dd7ba..4e6d986 100644 --- a/LocalizationManager/Classes/Protocols/LocalizationManagerDelegate.swift +++ b/LocalizationManager/Classes/Protocols/LocalizationManagerDelegate.swift @@ -8,6 +8,6 @@ import Foundation -public protocol LocalizationManagerDelegate: class { +public protocol LocalizationManagerDelegate: AnyObject { func localizationManager(languageUpdated: LanguageModel?) } diff --git a/LocalizationManagerTests/Resources/Localization_da-DK.json b/LocalizationManagerTests/Resources/Localizations_da-DK.json similarity index 100% rename from LocalizationManagerTests/Resources/Localization_da-DK.json rename to LocalizationManagerTests/Resources/Localizations_da-DK.json diff --git a/LocalizationManagerTests/Resources/Localization_en-GB.json b/LocalizationManagerTests/Resources/Localizations_en-GB.json similarity index 100% rename from LocalizationManagerTests/Resources/Localization_en-GB.json rename to LocalizationManagerTests/Resources/Localizations_en-GB.json diff --git a/LocalizationManagerTests/Resources/Localization_fr-FR.json b/LocalizationManagerTests/Resources/Localizations_fr-FR.json similarity index 100% rename from LocalizationManagerTests/Resources/Localization_fr-FR.json rename to LocalizationManagerTests/Resources/Localizations_fr-FR.json diff --git a/LocalizationManagerTests/Tests/LocalizationManagerTests.swift b/LocalizationManagerTests/Tests/LocalizationManagerTests.swift index 364d2e7..69daa4e 100644 --- a/LocalizationManagerTests/Tests/LocalizationManagerTests.swift +++ b/LocalizationManagerTests/Tests/LocalizationManagerTests.swift @@ -159,16 +159,20 @@ class LocalizationManagerTests: XCTestCase { func testUpdateLocalizationsFail() { let expect = expectation(description: "") let config = mockLocalizationConfigWithUpdate + let expectedNumberOfNilValues = 2 + var currentNumberOfNilValuesReceived = 0 let localizations: [DefaultLocalizationDescriptor] = [config, mockLocalizationConfigWithUpdate, mockLocalizationConfigWithoutUpdate] + expect.expectedFulfillmentCount = 3 repositoryMock.availableLocalizations = localizations repositoryMock.localizationsResponse = nil manager.updateLocalizations { (error) in - XCTAssertNotNil(error) + if error != nil { + currentNumberOfNilValuesReceived += 1 + } + XCTAssertTrue(currentNumberOfNilValuesReceived <= expectedNumberOfNilValues) expect.fulfill() } - waitForExpectations(timeout: 1.0) { (_) in - XCTFail() - } + wait(for: [expect], timeout: 1.0) } func testUpdateCurrentLanguageWithBestFit() { diff --git a/Podfile.lock b/Podfile.lock index 390516e..fd0c61d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -17,4 +17,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 54f5f694e106ddcbcd3724c53daeefebfe959bc1 -COCOAPODS: 1.8.4 +COCOAPODS: 1.11.2