From 8cd1669d8fdce10fb3b10192fa1a166801ba70bf Mon Sep 17 00:00:00 2001 From: Andres Silva Date: Wed, 26 Sep 2018 19:35:14 -0500 Subject: [PATCH] v2.0.5 --- .travis.yml | 3 + CHANGELOG.md | 5 + Example/Example/AppDelegate.swift | 27 ++-- Example/Example/ViewController.swift | 26 ++-- Localize.podspec | 4 +- Localize.xcodeproj/project.pbxproj | 22 ++++ .../UserInterfaceState.xcuserstate | Bin 51062 -> 56320 bytes Package.swift | 4 +- README.md | 2 +- Source/Localize.swift | 74 ++++++----- Source/LocalizeCommonProtocol.swift | 105 ++++++++-------- Source/LocalizeExtensions.swift | 46 +++---- Source/LocalizeJson.swift | 70 +++++------ Source/LocalizeProtocol.swift | 46 +++---- Source/LocalizeStatic.swift | 48 ++++--- Source/LocalizeString.swift | 21 ++-- Source/LocalizeStrings.swift | 9 +- Source/LocalizeUI.swift | 21 ++-- Tests/BaseTest.swift | 32 ++--- Tests/BaseTestInSpanish.swift | 26 ++-- Tests/JSONBadSources.swift | 18 +-- Tests/JsonChanginFileName.swift | 10 +- Tests/OtherLangTest.swift | 8 +- Tests/ReadingOtherFiles.swift | 10 +- Tests/StringBadSources.swift | 6 +- Tests/StringBaseTest.swift | 20 +-- Tests/StringBaseTestInSpanish.swift | 24 ++-- Tests/StringFallbackTest.swift | 4 +- Tests/StringSingleTest.swift | 4 +- Tests/StringsChanginDefaultFileName.swift | 8 +- Tests/UIViewComponents.swift | 116 ++++++++--------- Tests/UIViewComponentsES.swift | 117 +++++++++--------- Tests/UIViewComponentsWithString.swift | 114 ++++++++--------- 33 files changed, 562 insertions(+), 488 deletions(-) diff --git a/.travis.yml b/.travis.yml index 116f2e0..0399dcc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,9 @@ script: - xcodebuild -version - xcodebuild -showsdks + # Build Framework + - xcodebuild -workspace "$WORKSPACE" -scheme "Localize" -sdk "$SDK" -destination "$DESTINATION" + # Build Framework in Debug and Run Tests if specified - if [ $RUN_TESTS == "YES" ]; then xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; diff --git a/CHANGELOG.md b/CHANGELOG.md index 8356e49..8adcd54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. `Localize` adheres to [Semantic Versioning](http://semver.org/). +## [2.0.5](https://github.com/andresilvagomez/Localize/releases/tag/2.0.5) +- Swift 4.2 Support. + - By [Gustavo Graña](https://github.com/ggrana) in Pull Request [#36](https://github.com/andresilvagomez/Localize/pull/36). +Released on 2018-09-26. + ## [2.0.4](https://github.com/andresilvagomez/Localize/releases/tag/2.0.4) - Swift 4.2 Support. - By [Daniel Clelland](https://github.com/dclelland) in Pull Request [#34](https://github.com/andresilvagomez/Localize/pull/34). diff --git a/Example/Example/AppDelegate.swift b/Example/Example/AppDelegate.swift index aafe3e7..b4aafa0 100644 --- a/Example/Example/AppDelegate.swift +++ b/Example/Example/AppDelegate.swift @@ -13,8 +13,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) + -> Bool { + let localize = Localize.shared // Set your localize provider. localize.update(provider: .json) @@ -30,38 +33,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate { print(localize.currentLanguage) // List of aviable languajes print(localize.availableLanguages) - + // Or you can use static methods for all - + Localize.update(fileName: "lang") Localize.update(defaultLanguage: "fr") Localize.update(language: "en-DE") - + return true } func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } + } } - diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift index 5c6c41a..bc9a5aa 100644 --- a/Example/Example/ViewController.swift +++ b/Example/Example/ViewController.swift @@ -21,21 +21,31 @@ class ViewController: UIViewController { } @IBAction func updateLanguage(_ sender: Any) { - let actionSheet = UIAlertController(title: nil, message: "app.update.language".localize(), preferredStyle: UIAlertControllerStyle.actionSheet) + let actionSheet = UIAlertController( + title: nil, + message: "app.update.language".localize(), + preferredStyle: UIAlertControllerStyle.actionSheet + ) + for language in Localize.availableLanguages { let displayName = Localize.displayNameForLanguage(language) - let languageAction = UIAlertAction(title: displayName, style: .default, handler: { - (alert: UIAlertAction!) -> Void in - Localize.update(language: language) + let languageAction = UIAlertAction( + title: displayName, + style: .default, + handler: { (_: UIAlertAction!) -> Void in + + Localize.update(language: language) }) actionSheet.addAction(languageAction) } - let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { - (alert: UIAlertAction) -> Void in - }) + let cancelAction = UIAlertAction( + title: "Cancel", + style: UIAlertActionStyle.cancel, + handler: nil + ) + actionSheet.addAction(cancelAction) self.present(actionSheet, animated: true, completion: nil) } } - diff --git a/Localize.podspec b/Localize.podspec index ad6e932..b942f95 100644 --- a/Localize.podspec +++ b/Localize.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = "Localize" - s.version = "2.0.4" + s.version = "2.0.5" s.license = 'MIT' s.summary = "Localize is a framework writed in swift to localize your projects easier improves i18n, including storyboards and strings." s.homepage = "https://github.com/andresilvagomez/Localize" s.author = { "Andres Silva" => "andresilvagomez@gmail.com" } - s.source = { :git => "https://github.com/andresilvagomez/Localize.git", :tag => "2.0.4" } + s.source = { :git => "https://github.com/andresilvagomez/Localize.git", :tag => "2.0.5" } s.ios.deployment_target = '9.0' s.source_files = "Source/*.swift" diff --git a/Localize.xcodeproj/project.pbxproj b/Localize.xcodeproj/project.pbxproj index 4ec5595..83fde7a 100755 --- a/Localize.xcodeproj/project.pbxproj +++ b/Localize.xcodeproj/project.pbxproj @@ -238,6 +238,7 @@ 69F1B5701D955990000A2B87 /* Frameworks */, 69F1B5711D955990000A2B87 /* Headers */, 69F1B5721D955990000A2B87 /* Resources */, + 9F80E5EE215C502D0048E0A6 /* SwiftLint */, ); buildRules = ( ); @@ -340,6 +341,27 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 9F80E5EE215C502D0048E0A6 /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 69F1B56F1D955990000A2B87 /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/Localize.xcworkspace/xcuserdata/andresilvagomez.xcuserdatad/UserInterfaceState.xcuserstate b/Localize.xcworkspace/xcuserdata/andresilvagomez.xcuserdatad/UserInterfaceState.xcuserstate index 23dd7b44c90d6747560077f4d9316b7b2a6c0371..0fa640c30c2c2c8b5703f821ed7b86a8a62c31e1 100644 GIT binary patch delta 27119 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

L`sax^ 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 U@z3p{RjYs6uI``y|5m;Ke~Pxk_5c6? delta 23622 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%0AdW)IQw4hkZ}`X!{cTM*Ai9JM0hGAGAMY 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�eO zKd1h3{ZIA3)ZeXtFfwXn>d5qwnIp4Dt{Ay>oht5MaX#*S(p zC5;+4>ino%qkbIq)2KTQp$+j3i4DmOsSUFlmNYDDXlq!}aIfKI!>fir8s3cVH+sP6 z^3elFSB|+m=7pw_XoQVSBi|@Cnlzd>S~c1<+BZ5jMmCl=)-*0^T;8~;acAR~jVBsU zH=b*}*m$M!hsK{8?=;?PeAxJStT5JpZ1mW{V@Hf_9y?*|?6Hf-E*aZ8wteiXv75(k z8@qk%&ar#Oem?fn*f&jjO+igPn^K$dnkt&AnnpC$HH~T-(=@J0GqLHzrjMGYH_dEX z*woszv1v!s?xxS14m2HV`ljh*)0w7oO&6OkH{EJ_)by&EZB{lLHJdhDG+Q^jG`lx< zZ&o$?Hv2b6G{-e(H5W7&H}`K=HxF#CZmwyrZywb=rg?1h{N{bl-!wmM{!_zhj5RhI zdySLERpX)Y*92)oHQ^dfq$Wy}r0J*WuNkHpsTr*qtI=p$G#_cEYi4O=%{>&y$P;-XALNI^Q4GpJd8iPTpfXgBhN0o87S*E$ zGzN`BGtok{5^X|T(PwBU+Jg?Guh22{4LXTVqbukK^cek){y=Y9$QD}D(yhgy#kj?^ z#iGTk#ks|&C9EZ(C8MQJOTU)9mco|umO(8av%#s!WG85cIL$GD#3631nZD;_s+T;;f-n&l-gn96tfJm+)n&v}jv5;aOAd(Qbj zEhzXg(@H1Qnw)v=)`4Z;?ft&=ypKwxe3K z3++eE=oC7SE~3j3bQN7kccDEz3?1Q7=mNc90K`KAB*JJI11T^bCO|r5z+}jR_hA++ zfP7d21yBeKB>1obis5tk3IeEtTBwIc*b6^EGaQFs;5YaKPQiI-!|ic5+#C1B{c#+A z1`ol*@CclM6LBO7r{Z+{9?rva@TYhoUW}JwgbC(YVjr)-75FE7hIA%9Nq;hsB#=Zh znv5YSB$cF-3^Ivik$_Z@MzWXeCkMzOa+Dk+C&*vq0=Y!4kZYuk+#+|#UHUYQr%7}I z&8D;H0=kgq(?YtOx)EAVE9pkMiB{1D`aRu8o9ID$n4V$nSXb7KJ?k|QPP0~amdElzJf08bFYpBZ5}(MY@NAyL zb9p}JyqK@#tN3bO#@F)icmt0d<0trOeu-b@cSR==CkBcXktK4)bTLEB60^lzAw`KO z6>CJ9*d(@yYEdJ0h&pjV91<twxblE>v`ucH_1 z4fn=*Io=|#+N<;Sc!#~;y;EMRch)=a{q5cKZhLpUdn!X^t6Vi*%}}4HxoW;zsFo^6 z3017tDWgKQL2XnuYKN**4XRPy@O$|2euAI;e}DOD{y6_l|84&rf2u#t&+}*cAN%wD zMgC|0GC$%6{&5|nyXYP|Ru9s{^awptkJ8CHRj283`VBovXX+{XLp@v1(+hOIj_BnY zX`-1f(j~fFSL$lLUDxV*y-zpkgZhYW)-AeKUknxnivx%RML|hW8mtMv4AuqT1RH~@ zU~8}~*csFX^}+7ooat&3O^%sq=9wj?z+mH' do - pod 'Localize' , '~> 2.0.4' + pod 'Localize' , '~> 2.0.5' end ``` diff --git a/Source/Localize.swift b/Source/Localize.swift index 2fea944..82e9db8 100644 --- a/Source/Localize.swift +++ b/Source/Localize.swift @@ -5,14 +5,13 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation /// Name for language change notification -public let LocalizeChangeNotification = "LocalizeChangeNotification" +public let localizeChangeNotification = "LocalizeChangeNotification" /// Internal current language key -public let LocalizeStorageKey = "LocalizeDefaultLanguage" - +public let localizeStorageKey = "LocalizeDefaultLanguage" /// Different types to localize your app, using json files or strings default by Apple. public enum LocalizeType { @@ -25,31 +24,31 @@ public enum LocalizeType { /// Is a pricipal class, contents all logic to localize your keys /// read json and determinate all configurations. public class Localize: NSObject { - + // MARK: Properties - + /// Shated instance public static let shared: Localize = Localize() - + /// Provider to localize your app. private var provider: LocalizeProtocol = LocalizeStrings() - + /// Show all aviable languajes whit criteria name /// /// - returns: list with storaged languages code public var availableLanguages: [String] { return provider.availableLanguages } - + /// Return storaged language or default language in device /// /// - returns: current used language public var currentLanguage: String { return provider.currentLanguage } - + // MARK: Public methods - + /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values @@ -58,27 +57,35 @@ public class Localize: NSObject { public func localize(key: String, tableName: String? = nil) -> String { return provider.localize(key: key, tableName: tableName) } - + /// Localize a string using your JSON File /// That replace all % character in your string with replace value. /// /// - parameter value: The replacement value /// /// - returns: localized key or same text - public func localize(key: String, replace: String, tableName: String? = nil) -> String { + public func localize( + key: String, + replace: String, + tableName: String? = nil) -> String { + return provider.localize(key: key, replace: replace, tableName: tableName) } - + /// Localize a string using your JSON File /// That replace each % character in your string with each replace value. /// /// - parameter value: The replacement values /// /// - returns: localized key or same text - public func localize(key: String, values: [Any], tableName: String? = nil) -> String { + public func localize( + key: String, + values: [Any], + tableName: String? = nil) -> String { + return provider.localize(key: key, values: values, tableName: tableName) } - + /// Localize string with dictionary values /// Get properties in your key with rule :property /// If property not exist in this string, not is used. @@ -86,23 +93,26 @@ public class Localize: NSObject { /// - parameter value: The replacement dictionary /// /// - returns: localized key or same text - public func localize(key: String, dictionary: [String:String], tableName: String? = nil) -> String { + public func localize( + key: String, + dictionary: [String: String], + tableName: String? = nil) -> String { + return provider.localize(key: key, dictionary: dictionary, tableName: tableName) } - // MARK: Config methods - + /// Update default language, this stores a language key which can be retrieved the next time - public func update(language: String) -> Void { + public func update(language: String) { provider.update(language: language) } - + /// Update base file name, searched in path. - public func update(fileName:String) { + public func update(fileName: String) { provider.update(fileName: fileName) } - + /// Update the bundle used to load files from. public func update(bundle: Bundle) { provider.update(bundle: bundle) @@ -112,28 +122,28 @@ public class Localize: NSObject { public func update(defaultLanguage: String) { provider.update(defaultLanguage: defaultLanguage) } - + /// This remove the language key storaged. - public func resetLanguage() -> Void { + public func resetLanguage() { provider.resetLanguage() } - + /// Display name for current user language. /// /// - return: String form language code in current user language public func displayNameForLanguage(_ language: String) -> String { return provider.displayNameForLanguage(language) } - + // MARK: Config providers - + /// Update provider to localize your app. public func update(provider: LocalizeType) { - if provider == .strings { - self.provider = LocalizeStrings() - } - if provider == .json { + switch provider { + case .json: self.provider = LocalizeJson() + case .strings: + self.provider = LocalizeStrings() } } } diff --git a/Source/LocalizeCommonProtocol.swift b/Source/LocalizeCommonProtocol.swift index 5d11552..da66486 100644 --- a/Source/LocalizeCommonProtocol.swift +++ b/Source/LocalizeCommonProtocol.swift @@ -5,17 +5,17 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation class LocalizeCommonProtocol: LocalizeProtocol { - + /// Show all aviable languajes whit criteria name /// /// - returns: list with storaged languages code var availableLanguages: [String] { return ["en"] } - + /// Name for storaged Json Files /// The rule for name is fileName-LanguageKey.json public var fileName = "lang" @@ -23,22 +23,20 @@ class LocalizeCommonProtocol: LocalizeProtocol { /// Bundle used to load files from. /// Defaults to the main bundle. private var usedBundle = Bundle.main - + /// Default language, if this can't find a key in your current language /// Try read key in default language public var defaultLanguage: String = "en" - + /// Storaged language or default language in device public var currentLanguage: String { - get { - let defaults = UserDefaults.standard - if let lang = defaults.string(forKey: LocalizeStorageKey) { - return lang - } - return Locale.preferredLanguages.first ?? defaultLanguage + let defaults = UserDefaults.standard + if let lang = defaults.string(forKey: localizeStorageKey) { + return lang } + return Locale.preferredLanguages.first ?? defaultLanguage } - + /// Path for your env /// if testing mode is enable we change the bundle /// in other case use a main bundle. @@ -47,57 +45,61 @@ class LocalizeCommonProtocol: LocalizeProtocol { internal var bundle: Bundle { return usedBundle } - + // MARK: Internal methods. - - + // MARK: Public methods - - + /// Update default language, this stores a language key which can be retrieved the next time - public func update(language: String) -> Void { + public func update(language: String) { let defaults = UserDefaults.standard - defaults.setValue(language, forKey: LocalizeStorageKey) + defaults.setValue(language, forKey: localizeStorageKey) defaults.synchronize() - NotificationCenter.default.post(name: Notification.Name(rawValue: LocalizeChangeNotification), object: nil) + NotificationCenter.default.post( + name: Notification.Name(rawValue: localizeChangeNotification), + object: nil + ) } - + /// Update default language public func update(defaultLanguage: String) { self.defaultLanguage = defaultLanguage } - + /// This remove the language key storaged. - public func resetLanguage() -> Void { + public func resetLanguage() { let defaults = UserDefaults.standard - defaults.removeObject(forKey: LocalizeStorageKey) + defaults.removeObject(forKey: localizeStorageKey) defaults.synchronize() } - + /// Display name for current user language. /// /// - return: String form language code in current user language public func displayNameForLanguage(_ language: String) -> String { - let locale : NSLocale = NSLocale(localeIdentifier: currentLanguage) - if let name = locale.displayName(forKey: NSLocale.Key.identifier, value: language) { - return name.capitalized + let locale: NSLocale = NSLocale(localeIdentifier: currentLanguage) + + guard let name = locale.displayName( + forKey: NSLocale.Key.identifier, + value: language) else { + return "" } - return "" + + return name.capitalized } - + /// Update base file name, searched in path. public func update(fileName: String) { self.fileName = fileName } - + /// Update the bundle used to load files from. public func update(bundle: Bundle) { self.usedBundle = bundle } // MARK: Localize methods. - - + /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values @@ -106,7 +108,7 @@ class LocalizeCommonProtocol: LocalizeProtocol { public func localize(key: String, tableName: String? = nil) -> String { return "" } - + /// Localize a string using your JSON File /// That replace all % character in your string with replace value. /// @@ -118,32 +120,33 @@ class LocalizeCommonProtocol: LocalizeProtocol { return string.replacingOccurrences(of: "%", with: replace) } - + /// Localize a string using your JSON File /// That replace each % character in your string with each replace value. /// /// - parameter value: The replacement values /// /// - returns: localized key or same text - public func localize(key: String, values replace: [Any], tableName: String? = nil) -> String { + public func localize( + key: String, + values replace: [Any], + tableName: String? = nil) -> String { + var string = localize(key: key, tableName: tableName) - if string == key { - return key - } + if string == key { return key } var array = string.components(separatedBy: "%") string = "" - _ = replace.count + 1 - for (index, element) in replace.enumerated() { - if index < array.count { - let new = array.remove(at: 0) - string = index == 0 ? "\(new)\(element)" : "\(string)\(new)\(element) " - } + + for (index, element) in replace.enumerated() where index < array.count { + let new = array.remove(at: 0) + string = index == 0 ? "\(new)\(element)" : "\(string)\(new)\(element) " } + string += array.joined(separator: "") string = string.replacingOccurrences(of: " ", with: " ") return string } - + /// Localize string with dictionary values /// Get properties in your key with rule :property /// If property not exist in this string, not is used. @@ -151,12 +154,16 @@ class LocalizeCommonProtocol: LocalizeProtocol { /// - parameter value: The replacement dictionary /// /// - returns: localized key or same text - public func localize(key: String, dictionary replace: [String: String], tableName: String? = nil) -> String { - var string = localize(key: key, tableName:tableName) + public func localize( + key: String, + dictionary replace: [String: String], + tableName: String? = nil) -> String { + + var string = localize(key: key, tableName: tableName) for (key, value) in replace { string = string.replacingOccurrences(of: ":\(key)", with: value) } return string } - + } diff --git a/Source/LocalizeExtensions.swift b/Source/LocalizeExtensions.swift index 56cbc6d..f00f2fb 100644 --- a/Source/LocalizeExtensions.swift +++ b/Source/LocalizeExtensions.swift @@ -16,7 +16,7 @@ extension NSCoding { fileprivate func localizedValue(key: UnsafeMutablePointer) -> String? { return objc_getAssociatedObject(self, key) as? String } - + /// Set associated property by IBInspectable var. fileprivate func setLocalizedValue(_ value: String?, key: UnsafeMutablePointer) { guard let value = value else { return } @@ -32,7 +32,7 @@ extension NotificationCenter { NotificationCenter.default.addObserver( observer, selector: selector, - name: NSNotification.Name(LocalizeChangeNotification), + name: NSNotification.Name(localizeChangeNotification), object: nil ) } @@ -45,7 +45,7 @@ extension UIBarButtonItem { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UIBarButtonItem @@ -54,7 +54,7 @@ extension UIBarButtonItem { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { title = LocalizeUI.localize(key: &localizeKey, value: &title) @@ -68,7 +68,7 @@ extension UIButton { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UIButton in each state @@ -77,7 +77,7 @@ extension UIButton { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { var title = titleLabel?.text @@ -102,7 +102,7 @@ extension UILabel { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UILabel @@ -111,7 +111,7 @@ extension UILabel { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { LocalizeUI.localize(key: &localizeKey, value: &text) @@ -125,13 +125,13 @@ extension UINavigationItem { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Localizable tag storeged property @IBInspectable public var localizePrompt: String? { get { return localizedValue(key: &localizeKey2) } set { setLocalizedValue(newValue, key: &localizeKey2) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title and prompt for UINavigationItem @@ -140,7 +140,7 @@ extension UINavigationItem { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { LocalizeUI.localize(key: &localizeTitle, value: &title) @@ -155,13 +155,13 @@ extension UISearchBar { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Localizable tag storeged property @IBInspectable public var localizePrompt: String? { get { return localizedValue(key: &localizeKey2) } set { setLocalizedValue(newValue, key: &localizeKey2) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title and prompt for UISearchBar @@ -170,7 +170,7 @@ extension UISearchBar { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { LocalizeUI.localize(key: &localizePlaceholder, value: &placeholder) @@ -185,7 +185,7 @@ extension UISegmentedControl { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UISegmentedControl in each state @@ -194,7 +194,7 @@ extension UISegmentedControl { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { for index in 0...(numberOfSegments - 1) { @@ -213,7 +213,7 @@ extension UITabBarItem { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UITabBarItem @@ -222,7 +222,7 @@ extension UITabBarItem { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { LocalizeUI.localize(key: &localizeKey, value: &title) @@ -236,13 +236,13 @@ extension UITextField { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Localizable tag storeged property @IBInspectable public var localizePlaceholder: String? { get { return localizedValue(key: &localizeKey2) } set { setLocalizedValue(newValue, key: &localizeKey2) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title and placeholder for UITextField @@ -251,7 +251,7 @@ extension UITextField { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { LocalizeUI.localize(key: &localizeText, value: &text) @@ -266,7 +266,7 @@ extension UITextView { get { return localizedValue(key: &localizeKey1) } set { setLocalizedValue(newValue, key: &localizeKey1) } } - + /// Override awakeFromNib when is going visible, try search a key in JSON File /// If key match replace text, if can't match return the key (original text) /// Set title for UITextView @@ -275,7 +275,7 @@ extension UITextView { localize() NotificationCenter.localize(observer: self, selector: #selector(localize)) } - + /// Here we change text with key replacement @objc public func localize() { var localize = text diff --git a/Source/LocalizeJson.swift b/Source/LocalizeJson.swift index aa04125..da7aad1 100644 --- a/Source/LocalizeJson.swift +++ b/Source/LocalizeJson.swift @@ -5,9 +5,9 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation -fileprivate typealias JSON = NSDictionary +private typealias JSON = NSDictionary fileprivate extension JSON { /// This method has path where file is @@ -17,16 +17,18 @@ fileprivate extension JSON { guard let path = bundle.path(forResource: name, ofType: "json") else { return nil } - let data = try? Data(contentsOf: URL(fileURLWithPath: path)) do { - return try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary - } - catch { + let data = try Data(contentsOf: URL(fileURLWithPath: path)) + return try JSONSerialization.jsonObject( + with: data, + options: JSONSerialization.ReadingOptions.mutableContainers + ) as? NSDictionary + } catch { print("Localize can't parse your file", error) } return nil } - + /// Try search key in your dictionary using single level /// If it doesn't find the key it will use the multilevel /// If the key not exis in your JSON return nil value @@ -34,14 +36,14 @@ fileprivate extension JSON { if let string = self[key] { return string as? String } - + if let string = valueForKeyInLevels(key: key) { return string } - + return nil } - + /// Try search key in your dictionary using multiples levels /// It is necessary that the result be a string /// Otherwise it returns nil value @@ -55,7 +57,7 @@ fileprivate extension JSON { return nil } } - + return jsonCopy as? String } } @@ -67,13 +69,13 @@ class LocalizeJson: LocalizeCommonProtocol { super.init() fileName = "lang" } - + /// Show all aviable languages with criteria name /// /// - returns: list with storaged languages code override var availableLanguages: [String] { - var languages : [String] = [] - + var languages: [String] = [] + for localeId in NSLocale.availableLocaleIdentifiers { let name = "\(fileName)-\(localeId)" let path = bundle.path(forResource: name, ofType: "json") @@ -81,12 +83,12 @@ class LocalizeJson: LocalizeCommonProtocol { languages.append(localeId) } } - + return languages } - + // MARK: Read JSON methods - + /// This metod contains a logic to read return JSON data /// If JSON not is defined, this try use a default /// As long as the default language is the same as the current one. @@ -94,21 +96,21 @@ class LocalizeJson: LocalizeCommonProtocol { let tableName = tableName ?? fileName var lang = currentLanguage var json = JSON.read(bundle: bundle, named: "\(tableName)-\(lang)") - + if json != nil { return json } - + lang = lang.components(separatedBy: "-")[0] json = JSON.read(bundle: bundle, named: "\(tableName)-\(lang)") - + if json == nil && lang != defaultLanguage { json = readDefaultJSON() } - + return json } - + /// Read a JSON with default language value. /// /// - returns: json or nil value. @@ -116,9 +118,9 @@ class LocalizeJson: LocalizeCommonProtocol { let tableName = tableName ?? fileName return JSON.read(bundle: bundle, named: "\(tableName)-\(defaultLanguage)") } - + // MARK: Public methods - + /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values @@ -128,21 +130,19 @@ class LocalizeJson: LocalizeCommonProtocol { guard let json = readJSON(tableName: tableName) else { return key } - - let string = json.valueFor(key: key) - if string != nil { - return string! + + if let string = json.valueFor(key: key) { + return string } - + guard let defaultJSON = readDefaultJSON(tableName: tableName) else { return key } - - let defaultString = defaultJSON.valueFor(key: key) - if defaultString != nil { - return defaultString! + + guard let defaultString = defaultJSON.valueFor(key: key) else { + return key } - - return key + + return defaultString } } diff --git a/Source/LocalizeProtocol.swift b/Source/LocalizeProtocol.swift index 61c63e1..ab8184f 100644 --- a/Source/LocalizeProtocol.swift +++ b/Source/LocalizeProtocol.swift @@ -5,35 +5,33 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation protocol LocalizeProtocol { - + /// Default language, if this can't find a key in your current language /// Try read key in default language var defaultLanguage: String {get set} - + /// Storaged language or default language in device /// /// - returns: storaged language var currentLanguage: String {get} - + /// Show all aviable languajes whit criteria name /// /// - returns: list with storaged languages code var availableLanguages: [String] {get} - - + // MARK: Localize Methos - - + /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values /// /// - returns: localized key or same text func localize(key: String, tableName: String?) -> String - + /// Localize a string using your JSON File /// That replace all % character in your string with replace value. /// @@ -41,7 +39,7 @@ protocol LocalizeProtocol { /// /// - returns: localized key or same text func localize(key: String, replace: String, tableName: String?) -> String - + /// Localize a string using your JSON File /// That replace each % character in your string with each replace value. /// @@ -49,7 +47,7 @@ protocol LocalizeProtocol { /// /// - returns: localized key or same text func localize(key: String, values replace: [Any], tableName: String?) -> String - + /// Localize string with dictionary values /// Get properties in your key with rule :property /// If property not exist in this string, not is used. @@ -57,29 +55,31 @@ protocol LocalizeProtocol { /// - parameter value: The replacement dictionary /// /// - returns: localized key or same text - func localize(key: String, dictionary replace: [String: String], tableName: String?) -> String - - + func localize( + key: String, + dictionary replace: [String: String], + tableName: String?) -> String + // MARK: Config methods - + /// Update default language, this stores a language key which can be retrieved the next time - func update(language: String) -> Void - + func update(language: String) + /// Update base file name, searched in path. func update(fileName: String) - + /// Update the bundle used to load files from. func update(bundle: Bundle) - + /// Update default language func update(defaultLanguage: String) - + /// This remove the language key storaged. - func resetLanguage() -> Void - + func resetLanguage() + /// Display name for current user language. /// /// - return: String form language code in current user language func displayNameForLanguage(_ language: String) -> String - + } diff --git a/Source/LocalizeStatic.swift b/Source/LocalizeStatic.swift index 4484c5c..368e7eb 100644 --- a/Source/LocalizeStatic.swift +++ b/Source/LocalizeStatic.swift @@ -5,24 +5,24 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation extension Localize { - + /// Show all aviable languajes whit criteria name /// /// - returns: list with storaged languages code public static var availableLanguages: [String] { return Localize.shared.availableLanguages } - + /// Return storaged language or default language in device /// /// - returns: current used language public static var currentLanguage: String { return Localize.shared.currentLanguage } - + /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values @@ -31,27 +31,35 @@ extension Localize { public static func localize(key: String, tableName: String? = nil) -> String { return Localize.shared.localize(key: key, tableName: tableName) } - + /// Localize a string using your JSON File /// That replace all % character in your string with replace value. /// /// - parameter value: The replacement value /// /// - returns: localized key or same text - public static func localize(key: String, replace: String, tableName: String? = nil) -> String { + public static func localize( + key: String, + replace: String, + tableName: String? = nil) -> String { + return Localize.shared.localize(key: key, replace: replace, tableName: tableName) } - + /// Localize a string using your JSON File /// That replace each % character in your string with each replace value. /// /// - parameter value: The replacement values /// /// - returns: localized key or same text - public static func localize(key: String, values replace: [Any], tableName: String? = nil) -> String { + public static func localize( + key: String, + values replace: [Any], + tableName: String? = nil) -> String { + return Localize.shared.localize(key: key, values: replace, tableName: tableName) } - + /// Localize string with dictionary values /// Get properties in your key with rule :property /// If property not exist in this string, not is used. @@ -59,20 +67,24 @@ extension Localize { /// - parameter value: The replacement dictionary /// /// - returns: localized key or same text - public static func localize(key: String, dictionary replace: [String:String], tableName: String? = nil) -> String { + public static func localize( + key: String, + dictionary replace: [String: String], + tableName: String? = nil) -> String { + return Localize.shared.localize(key: key, dictionary: replace, tableName: tableName) } - + /// Update default language, this stores a language key which can be retrieved the next time public static func update(language: String) { return Localize.shared.update(language: language) } - + /// Update base file name, searched in path. public static func update(fileName: String) { return Localize.shared.update(fileName: fileName) } - + /// Update the bundle used to load files from. public static func update(bundle: Bundle) { return Localize.shared.update(bundle: bundle) @@ -82,24 +94,24 @@ extension Localize { public static func update(defaultLanguage: String) { return Localize.shared.update(defaultLanguage: defaultLanguage) } - + /// This remove the language key storaged. public static func resetLanguage() { return Localize.shared.resetLanguage() } - + /// Display name for current user language. /// /// - return: String form language code in current user language public static func displayNameForLanguage(_ language: String) -> String { return Localize.shared.displayNameForLanguage(language) } - + // MARK: Config providers - + /// Update provider to localize your app. public static func update(provider: LocalizeType) { Localize.shared.update(provider: provider) } - + } diff --git a/Source/LocalizeString.swift b/Source/LocalizeString.swift index 3015309..5b52b60 100644 --- a/Source/LocalizeString.swift +++ b/Source/LocalizeString.swift @@ -5,12 +5,12 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation /// String extension used to localize your keys matched /// in your JSON File. public extension String { - + /// Localize a string using your JSON File /// If the key is not found return the same key /// that prevent replace untagged values @@ -19,7 +19,7 @@ public extension String { public var localized: String { return Localize.localize(key: self) } - + /// Localize a string using your JSON File /// If the key is not found return the same key /// that prevent replace untagged values @@ -28,7 +28,7 @@ public extension String { public func localize() -> String { return Localize.localize(key: self) } - + /// Localize a string using your JSON File /// If the key is not found return the same key /// that prevent replace untagged values @@ -37,7 +37,7 @@ public extension String { public func localize(tableName: String) -> String { return Localize.localize(key: self, tableName: tableName) } - + /// Localize a string using your JSON File /// that replace all % character in your string with replace value. /// @@ -47,7 +47,7 @@ public extension String { public func localize(value: String, tableName: String? = nil) -> String { return Localize.localize(key: self, replace: value, tableName: tableName) } - + /// Localize a string using your JSON File /// that replace each % character in your string with each replace value. /// @@ -57,7 +57,7 @@ public extension String { public func localize(values: String..., tableName: String? = nil) -> String { return Localize.localize(key: self, values: values, tableName: tableName) } - + /// Localize string with dictionary values /// get properties in your key with rule :property /// if property not exist in this string, not is used. @@ -65,8 +65,11 @@ public extension String { /// - parameter [String:String]: The replacement dictionary /// /// - returns: localized key or same text - public func localize(dictionary values: [String: String], tableName: String? = nil) -> String { + public func localize( + dictionary values: [String: String], + tableName: String? = nil) -> String { + return Localize.localize(key: self, dictionary: values, tableName: tableName) } - + } diff --git a/Source/LocalizeStrings.swift b/Source/LocalizeStrings.swift index 8e670ff..f4f7833 100755 --- a/Source/LocalizeStrings.swift +++ b/Source/LocalizeStrings.swift @@ -5,7 +5,7 @@ // Copyright © 2017 @andresilvagomez. // -import UIKit +import Foundation class LocalizeStrings: LocalizeCommonProtocol { @@ -28,7 +28,6 @@ class LocalizeStrings: LocalizeCommonProtocol { // MARK: Public methods - /// Localize a string using your JSON File /// If the key is not found return the same key /// That prevent replace untagged values @@ -64,15 +63,15 @@ class LocalizeStrings: LocalizeCommonProtocol { return localized } - + if bundle.path(forResource: tableName, ofType: "strings") != nil { let localized = bundle.localizedString(forKey: key, value: nil, table: tableName) - + if localized != key { return localized } } - + // If we can't find a translation anywhere, return the original key. return key } diff --git a/Source/LocalizeUI.swift b/Source/LocalizeUI.swift index 92fd978..a8eaa05 100644 --- a/Source/LocalizeUI.swift +++ b/Source/LocalizeUI.swift @@ -5,7 +5,7 @@ // Copyright © 2018 @andresilvagomez. // -import UIKit +import Foundation class LocalizeUI: NSObject { /// Localize UI component using key and value or result @@ -14,7 +14,11 @@ class LocalizeUI: NSObject { /// /// - returns: localized string and also edit it inside. @discardableResult - static func localize(key: inout String?, value: inout String?, updateKey: Bool = true) -> String { + static func localize( + key: inout String?, + value: inout String?, + updateKey: Bool = true) -> String { + if let localized = key?.localize() { value = localized return localized @@ -24,9 +28,10 @@ class LocalizeUI: NSObject { value = localized return localized } + return value ?? "" } - + /// Get key for segment controls based on string like to /// navigation.segment: one, two or one, two /// it returns the right access key to localize segment at index @@ -35,19 +40,19 @@ class LocalizeUI: NSObject { static func keyFor(index: Int, localizeKey: String?) -> String? { var localizeKey = localizeKey?.replacingOccurrences(of: " ", with: "") let root = localizeKey?.components(separatedBy: ":") - var rootKey: String? = nil - + var rootKey: String? + if root?.count == 2 { rootKey = root?.first localizeKey = root?.last } - + let keys = localizeKey?.components(separatedBy: ",") let key = keys?.count ?? 0 > index ? keys?[index] : nil - + if key == nil || key?.isEmpty ?? true { return nil } if rootKey == nil { return key } - + return "\(rootKey ?? "").\(key ?? "")" } } diff --git a/Tests/BaseTest.swift b/Tests/BaseTest.swift index 319d5c8..8b0b7df 100644 --- a/Tests/BaseTest.swift +++ b/Tests/BaseTest.swift @@ -9,77 +9,77 @@ import XCTest import Localize class BaseTest: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "en") } - + func testRemoveKeyAndGetDefaultForLang() { - UserDefaults.standard.removeObject(forKey: LocalizeStorageKey) + UserDefaults.standard.removeObject(forKey: localizeStorageKey) XCTAssertTrue(Localize.currentLanguage == Locale.preferredLanguages.first) } - + func testSameKeyWithTableName() { let localized = "heymamiwhereareyou".localize(values: "", "", tableName: "heymamiwhereareyou") XCTAssertTrue(localized == "heymamiwhereareyou") } - + func testLocalizeInAnyDictionary() { let localized = "heymomhowareyoy".localized XCTAssertTrue(localized == "heymomhowareyoy") } - + func testLocalizeProperty() { let localized = "hello.world".localized XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKeyWithValue() { let localized = "name".localize(value: "Andres") XCTAssertTrue(localized == "Hello Andres") } - + func testLocalizeKeyWithValues() { let localized = "values".localize(values: "Andres", "Software Developer") XCTAssertTrue(localized == "Hello everyone my name is Andres and I'm Software Developer , see you soon") } - + func testLocalizeKeyWithDictionary() { let localized = "username".localize(dictionary: ["username": "andresilvagomez"]) XCTAssertTrue(localized == "My username is andresilvagomez") } - + func testLocalizeKeyWithManyLevels() { let localized = "level.one.two.three".localize() XCTAssertTrue(localized == "This is a multilevel key") } - + func testLocalizeKeyWithSingleLevel() { let localized = "the.same.lavel".localize() XCTAssertTrue(localized == "This is a localized in the same level") } - + func testSearchInOtherFile() { let localized = "hello.baby".localize(tableName: "other") XCTAssertTrue(localized == "This is a welcome, new baby is here!") } - + func testListOfAvailableLanguages() { let languages = Localize.availableLanguages XCTAssertTrue(languages.count == 3) } - + func testCurrentLanguage() { let language = Localize.currentLanguage XCTAssertTrue(language == "en") } - + } diff --git a/Tests/BaseTestInSpanish.swift b/Tests/BaseTestInSpanish.swift index b038193..eab2710 100644 --- a/Tests/BaseTestInSpanish.swift +++ b/Tests/BaseTestInSpanish.swift @@ -9,63 +9,63 @@ import XCTest import Localize class BaseTestInSpanish: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "es") } - + func testRemoveKeyAndGetDefaultForLang() { - UserDefaults.standard.removeObject(forKey: LocalizeStorageKey) + UserDefaults.standard.removeObject(forKey: localizeStorageKey) XCTAssertTrue(Localize.currentLanguage == Locale.preferredLanguages.first) } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hola mundo!") } - + func testLocalizeKeyWithValue() { let localized = "name".localize(value: "Andres") XCTAssertTrue(localized == "Hola Andres") } - + func testLocalizeKeyWithValues() { let localized = "values".localize(values: "Andres", "Software Developer") XCTAssertTrue(localized == "Hola a todos mi nombre es Andres y soy Software Developer , nos vemos pronto") } - + func testLocalizeKeyWithDictionary() { let localized = "username".localize(dictionary: ["username": "andresilvagomez"]) XCTAssertTrue(localized == "Mi nombre de usuario es andresilvagomez") } - + func testLocalizeKeyWithManyLevels() { let localized = "level.one.two.three".localize() XCTAssertTrue(localized == "Esta es una llave multinivel") } - + func testLocalizeKeyWithSingleLevel() { let localized = "the.same.lavel".localize() XCTAssertTrue(localized == "Esto es una internazionalizacion en el mismo nivel") } - + func testDefaultValuesFromOtherLanguage() { let localized = "enlish".localize() XCTAssertTrue(localized == "This key only exist in english file.") } - + func testListOfAvailableLanguages() { let languages = Localize.availableLanguages // ["en", "es", "fr"] XCTAssertTrue(languages.count == 3) } - + func testCurrentLanguage() { let language = Localize.currentLanguage XCTAssertTrue(language == "es") } - + } diff --git a/Tests/JSONBadSources.swift b/Tests/JSONBadSources.swift index a402b3f..5acbaa0 100644 --- a/Tests/JSONBadSources.swift +++ b/Tests/JSONBadSources.swift @@ -16,47 +16,47 @@ class JSONBadSources: XCTestCase { Localize.update(language: "en") Localize.update(defaultLanguage: "rs") } - + func testLocalizeInAnyDictionary() { let localized = "heymomhowareyoy".localized XCTAssertTrue(localized == "heymomhowareyoy") } - + func testLocalizeProperty() { let localized = "hello.world".localized XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hello world!") } - + func testWithTableName() { let localized = "test.in.table".localize(tableName: "langTable") XCTAssertTrue(localized == "Test in table name") } - + func testWithBadTableName() { let localized = "test.in.table".localize(tableName: "langTablesss") XCTAssertTrue(localized == "test.in.table") } - + func testBadValueForKeyInLevels() { let localized = "test.in.table".localized XCTAssertTrue(localized == "test.in.table") } - + func testBadJSONFormat() { let localized = "test.in.table".localize(tableName: "badJSON") XCTAssertTrue(localized == "test.in.table") } - + func testNameForLanguage() { let localized = Localize.displayNameForLanguage("es") XCTAssertTrue(localized == "Spanish") } - + func testRestDefaultLang() { Localize.resetLanguage() XCTAssertTrue(true) diff --git a/Tests/JsonChanginFileName.swift b/Tests/JsonChanginFileName.swift index 4dcedf6..cd0f5c4 100644 --- a/Tests/JsonChanginFileName.swift +++ b/Tests/JsonChanginFileName.swift @@ -9,7 +9,7 @@ import XCTest import Localize class JsonChanginFileName: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) @@ -17,22 +17,22 @@ class JsonChanginFileName: XCTestCase { Localize.update(fileName: "lang") Localize.update(bundle: Bundle(for: type(of: self))) } - + func testKeyInOtherLanguage() { let localized = "hello.baby".localize(tableName: "other") XCTAssertTrue(localized == "Esto es un saludo, el nuevo bebé está aquí!") } - + func testSearchInOtherFile() { let localized = "hello".localize(tableName: "other") XCTAssertTrue(localized == "Hola mundo!") } - + func testNameForLanguage() { let localized = Localize.displayNameForLanguage("es") XCTAssertTrue(localized == "Español") } - + func testNameBadForLanguage() { let localized = Localize.displayNameForLanguage("esus") XCTAssertTrue(localized == "") diff --git a/Tests/OtherLangTest.swift b/Tests/OtherLangTest.swift index ef6f21b..6ac9853 100644 --- a/Tests/OtherLangTest.swift +++ b/Tests/OtherLangTest.swift @@ -9,22 +9,22 @@ import XCTest import Localize class OtherLangTest: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "it") } - + func testLocalizeKey() { let localized = "hello".localize() XCTAssertTrue(localized == "hello") } - + func testLocalizeKeyUsingDefaultLang() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hello world!") } - + } diff --git a/Tests/ReadingOtherFiles.swift b/Tests/ReadingOtherFiles.swift index dcc07a2..a2a64f1 100644 --- a/Tests/ReadingOtherFiles.swift +++ b/Tests/ReadingOtherFiles.swift @@ -9,12 +9,12 @@ import XCTest import Localize class ReadingOtherFiles: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) } - + func testOtherEnglish() { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "en") @@ -22,7 +22,7 @@ class ReadingOtherFiles: XCTestCase { let result = "hello".localize() XCTAssert(result == "Hello world!") } - + func testSomeItalian() { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "it") @@ -30,7 +30,7 @@ class ReadingOtherFiles: XCTestCase { let result = "hello".localize() XCTAssert(result == "Ciao mondo!") } - + func testFileGerman() { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "de") @@ -38,5 +38,5 @@ class ReadingOtherFiles: XCTestCase { let result = "hello".localize() XCTAssert(result == "Hallo Welt!") } - + } diff --git a/Tests/StringBadSources.swift b/Tests/StringBadSources.swift index 85967b2..bb89569 100644 --- a/Tests/StringBadSources.swift +++ b/Tests/StringBadSources.swift @@ -16,17 +16,17 @@ class StringBadSources: XCTestCase { Localize.update(language: "en") Localize.update(defaultLanguage: "rs") } - + func testLocalizeInAnyDictionary() { let localized = "heymomhowareyoy".localized XCTAssertTrue(localized == "heymomhowareyoy") } - + func testLocalizeProperty() { let localized = "hello.world".localized XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hello world!") diff --git a/Tests/StringBaseTest.swift b/Tests/StringBaseTest.swift index 9fbced4..173e330 100755 --- a/Tests/StringBaseTest.swift +++ b/Tests/StringBaseTest.swift @@ -15,47 +15,47 @@ class StringBaseTest: XCTestCase { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "en") } - + func testLocalizeInAnyDictionary() { let localized = "heymomhowareyoy".localized XCTAssertTrue(localized == "heymomhowareyoy") } - + func testLocalizeProperty() { let localized = "hello.world".localized XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hello world!") } - + func testLocalizeKeyWithValue() { let localized = "name".localize(value: "Andres") XCTAssertTrue(localized == "Hello Andres") } - + func testLocalizeKeyWithValues() { let localized = "values".localize(values: "Andres", "Software Developer") XCTAssertTrue(localized == "Hello everyone my name is Andres and I'm Software Developer , see you soon") } - + func testLocalizeKeyWithDictionary() { let localized = "username".localize(dictionary: ["username": "andresilvagomez"]) XCTAssertTrue(localized == "My username is andresilvagomez") } - + func testLocalizeWithTableName() { let localized = "other.key".localize(tableName: "Other") XCTAssertTrue(localized == "This key exist in other file") } - + func testListOfAvailableLanguages() { let languages = Localize.availableLanguages - XCTAssertTrue(languages == ["en","es","es-CO","fr"]) + XCTAssertTrue(languages == ["en", "es", "es-CO", "fr"]) } - + func testCurrentLanguage() { let language = Localize.currentLanguage XCTAssertTrue(language == "en") diff --git a/Tests/StringBaseTestInSpanish.swift b/Tests/StringBaseTestInSpanish.swift index 47403a9..dbd5a3f 100755 --- a/Tests/StringBaseTestInSpanish.swift +++ b/Tests/StringBaseTestInSpanish.swift @@ -9,57 +9,57 @@ import XCTest import Localize class StringBaseTestInSpanish: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .strings) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "es") } - + func testLocalizeKey() { let localized = "hello.world".localize() XCTAssertTrue(localized == "Hola mundo!") } - + func testLocalizeKeyWithValue() { let localized = "name".localize(value: "Andres") XCTAssertTrue(localized == "Hola Andres") } - + func testLocalizeKeyWithValues() { let localized = "values".localize(values: "Andres", "Software Developer") XCTAssertTrue(localized == "Hola a todos mi nombre es Andres y soy Software Developer , nos vemos pronto") } - + func testLocalizeKeyWithDictionary() { let localized = "username".localize(dictionary: ["username": "andresilvagomez"]) XCTAssertTrue(localized == "Mi nombre de usuario es andresilvagomez") } - + func testLocalizeKeyWithManyLevels() { let localized = "level.one.two.three".localize() XCTAssertTrue(localized == "Esta es una llave multinivel") } - + func testLocalizeKeyAviableInDefaultLanguage() { let localized = "enlish".localize() XCTAssertTrue(localized == "This key only exist in english file.") } - + func testLocalizeWithTableName() { let localized = "other.key".localize(tableName: "Other") XCTAssertTrue(localized == "Esta llave existe en otro archivo") } - + func testListOfAvailableLanguages() { let languages = Localize.availableLanguages - XCTAssertTrue(languages == ["en", "es","es-CO","fr"]) + XCTAssertTrue(languages == ["en", "es", "es-CO", "fr"]) } - + func testCurrentLanguage() { let language = Localize.currentLanguage XCTAssertTrue(language == "es") } - + } diff --git a/Tests/StringFallbackTest.swift b/Tests/StringFallbackTest.swift index ed17cbc..bece34c 100644 --- a/Tests/StringFallbackTest.swift +++ b/Tests/StringFallbackTest.swift @@ -17,12 +17,12 @@ class StringFallbackTest: XCTestCase { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "es-CO") } - + func testKeyMainLanguage() { let localized = "only.spanish".localize() XCTAssertTrue(localized == "Solo Español") } - + func testKeyOtherLanguage() { Localize.update(language: "es") let localized = "only.spanish".localize() diff --git a/Tests/StringSingleTest.swift b/Tests/StringSingleTest.swift index 24f8ffb..6866fae 100644 --- a/Tests/StringSingleTest.swift +++ b/Tests/StringSingleTest.swift @@ -16,12 +16,12 @@ class StringSingleTest: XCTestCase { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(fileName: "OnlyOneLang") } - + func testLocalizeInSingleStringFile() { let localized = "hello.world.for.all".localized XCTAssertTrue(localized == "Hello world for all") } - + func testLocalizeInSingleStringFileNil() { let localized = "hello.world.for.allll".localized XCTAssertTrue(localized == "hello.world.for.allll") diff --git a/Tests/StringsChanginDefaultFileName.swift b/Tests/StringsChanginDefaultFileName.swift index f086872..b4e10fd 100644 --- a/Tests/StringsChanginDefaultFileName.swift +++ b/Tests/StringsChanginDefaultFileName.swift @@ -9,7 +9,7 @@ import XCTest import Localize class StringsChanginDefaultFileName: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .strings) @@ -17,15 +17,15 @@ class StringsChanginDefaultFileName: XCTestCase { Localize.update(fileName: "Other") Localize.update(bundle: Bundle(for: type(of: self))) } - + func testKeyInOtherLanguage() { let localized = "hello.baby".localize() XCTAssertTrue(localized == "This is a welcome, new baby is here!") } - + func testSearchInOtherFile() { let localized = "hello.world".localize(tableName: "Strings") XCTAssertTrue(localized == "Hello world!") } - + } diff --git a/Tests/UIViewComponents.swift b/Tests/UIViewComponents.swift index 490dee4..e0ff03b 100644 --- a/Tests/UIViewComponents.swift +++ b/Tests/UIViewComponents.swift @@ -10,223 +10,223 @@ import UIKit import Localize class UIViewComponents: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "en") } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + // MARK: - UIBarButtonItem func testButtonItemWithLocalizeKey() { let button = UIBarButtonItem(title: "", style: .plain, target: self, action: nil) button.localizeKey = "the.same.lavel" button.awakeFromNib() - + XCTAssertTrue(button.title == "This is a localized in the same level") } - + func testButtonItemWithTextKey() { let button = UIBarButtonItem(title: "the.same.lavel", style: .plain, target: self, action: nil) button.awakeFromNib() - + XCTAssertTrue(button.title == "This is a localized in the same level") } - + func testButtonItemWithoutKeys() { let button = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil) button.awakeFromNib() - + XCTAssertTrue(button.title == nil) } - + // MARK: - UIButton func testButtonWithLocalizeKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.localizeKey = "the.same.lavel" button.awakeFromNib() - + XCTAssertTrue(button.titleLabel?.text == "This is a localized in the same level") } - + func testButtonWithTextKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.titleLabel?.text = "the.same.lavel" button.awakeFromNib() - + XCTAssertTrue(button.titleLabel?.text == "This is a localized in the same level") } - + func testButtonWithoutKeys() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.awakeFromNib() - + XCTAssertTrue(button.titleLabel?.text == "") } - + // MARK: - UILabel func testLabelWithLocalizeKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.localizeKey = "the.same.lavel" label.awakeFromNib() - + XCTAssertTrue(label.text == "This is a localized in the same level") } - + func testLabelWithTextKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.text = "the.same.lavel" label.awakeFromNib() - + XCTAssertTrue(label.text == "This is a localized in the same level") } - + func testLabelWithoutKeys() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.awakeFromNib() - + XCTAssertTrue(label.text == nil) } - + // MARK: - UINavigationItem func testNavigationItemWithLocalizeKey() { let item = UINavigationItem(title: "") item.localizeTitle = "the.same.lavel" item.localizePrompt = "the.same.lavel" item.awakeFromNib() - + XCTAssertTrue(item.title == "This is a localized in the same level") XCTAssertTrue(item.prompt == "This is a localized in the same level") } - + func testNavigationItemWithTextKey() { let item = UINavigationItem(title: "the.same.lavel") item.prompt = "the.same.lavel" item.awakeFromNib() - + XCTAssertTrue(item.title == "This is a localized in the same level") XCTAssertTrue(item.prompt == "This is a localized in the same level") } - + func testNavigationItemWithoutKeys() { let item = UINavigationItem(title: "") item.awakeFromNib() - + XCTAssertTrue(item.title == "") XCTAssertTrue(item.prompt == nil) } - + // MARK: - UISearchBar func testSearchBarWithLocalizeKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.localizePlaceholder = "the.same.lavel" bar.localizePrompt = "the.same.lavel" bar.awakeFromNib() - + XCTAssertTrue(bar.placeholder == "This is a localized in the same level") XCTAssertTrue(bar.prompt == "This is a localized in the same level") } - + func testSearchBarWithTextKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.placeholder = "the.same.lavel" bar.prompt = "the.same.lavel" bar.awakeFromNib() - + XCTAssertTrue(bar.placeholder == "This is a localized in the same level") XCTAssertTrue(bar.prompt == "This is a localized in the same level") } - + func testSearchBarWithoutKeys() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.awakeFromNib() - + XCTAssertTrue(bar.placeholder == nil) XCTAssertTrue(bar.prompt == nil) } - + // MARK: - UITabBarItem func testTabBarItemWithLocalizeKey() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.localizeKey = "the.same.lavel" bar.awakeFromNib() - + XCTAssertTrue(bar.title == "This is a localized in the same level") } - + func testTabBarItemWithTextKey() { let bar = UITabBarItem(title: "the.same.lavel", image: nil, tag: 0) bar.awakeFromNib() - + XCTAssertTrue(bar.title == "This is a localized in the same level") } - + func testTabBarItemWithoutKeys() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.awakeFromNib() - + XCTAssertTrue(bar.title == "") } - + // MARK: - UITextField func testTextFieldWithLocalizeKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.localizeText = "the.same.lavel" textField.localizePlaceholder = "the.same.lavel" textField.awakeFromNib() - + XCTAssertTrue(textField.text == "This is a localized in the same level") XCTAssertTrue(textField.placeholder == "This is a localized in the same level") } - + func testTextFieldWithTextKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.text = "the.same.lavel" textField.placeholder = "the.same.lavel" textField.awakeFromNib() - + XCTAssertTrue(textField.text == "This is a localized in the same level") XCTAssertTrue(textField.placeholder == "This is a localized in the same level") } - + func testTextFieldWithoutKeys() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.awakeFromNib() - + XCTAssertTrue(textField.text == "") XCTAssertTrue(textField.placeholder == nil) } - + // MARK: - UITextView func testTextViewWithLocalizeKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.localizeKey = "the.same.lavel" textView.awakeFromNib() - + XCTAssertTrue(textView.text == "This is a localized in the same level") } - + func testTextViewWithTextKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.text = "the.same.lavel" textView.awakeFromNib() - + XCTAssertTrue(textView.text == "This is a localized in the same level") } - + func testTextViewWithoutKeys() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.awakeFromNib() - + XCTAssertTrue(textView.text == "") } - + // MARK: - UISegmentedControl func testSegmentedControlWithLocalizeKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) @@ -234,38 +234,38 @@ class UIViewComponents: XCTestCase { segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "one, two" segment.awakeFromNib() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithLocalizeKeyBased() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "segment.base: one, two" segment.awakeFromNib() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithTextKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "segment.base.one", at: 0, animated: false) segment.insertSegment(withTitle: "segment.base.two", at: 1, animated: false) segment.awakeFromNib() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithoutKeys() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.awakeFromNib() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "") XCTAssertTrue(segment.titleForSegment(at: 1) == "") } diff --git a/Tests/UIViewComponentsES.swift b/Tests/UIViewComponentsES.swift index 22681ee..5852c12 100644 --- a/Tests/UIViewComponentsES.swift +++ b/Tests/UIViewComponentsES.swift @@ -10,223 +10,223 @@ import UIKit import Localize class UIViewComponentsES: XCTestCase { - + override func setUp() { super.setUp() Localize.update(provider: .json) Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "es") } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + // MARK: - UIBarButtonItem func testButtonItemWithLocalizeKey() { let button = UIBarButtonItem(title: "", style: .plain, target: self, action: nil) button.localizeKey = "the.same.lavel" button.localize() - + XCTAssertTrue(button.title == "Esto es una internazionalizacion en el mismo nivel") } - + func testButtonItemWithTextKey() { let button = UIBarButtonItem(title: "the.same.lavel", style: .plain, target: self, action: nil) button.localize() - + XCTAssertTrue(button.title == "Esto es una internazionalizacion en el mismo nivel") } - + func testButtonItemWithoutKeys() { let button = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil) button.localize() - + XCTAssertTrue(button.title == nil) } - + // MARK: - UIButton func testButtonWithLocalizeKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.localizeKey = "the.same.lavel" button.localize() - + XCTAssertTrue(button.titleLabel?.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testButtonWithTextKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.titleLabel?.text = "the.same.lavel" button.localize() - + XCTAssertTrue(button.titleLabel?.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testButtonWithoutKeys() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.localize() - + XCTAssertTrue(button.titleLabel?.text == "") } - + // MARK: - UILabel func testLabelWithLocalizeKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.localizeKey = "the.same.lavel" label.localize() - + XCTAssertTrue(label.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testLabelWithTextKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.text = "the.same.lavel" label.localize() - + XCTAssertTrue(label.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testLabelWithoutKeys() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.localize() - + XCTAssertTrue(label.text == nil) } - + // MARK: - UINavigationItem func testNavigationItemWithLocalizeKey() { let item = UINavigationItem(title: "") item.localizeTitle = "the.same.lavel" item.localizePrompt = "the.same.lavel" item.localize() - + XCTAssertTrue(item.title == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(item.prompt == "Esto es una internazionalizacion en el mismo nivel") } - + func testNavigationItemWithTextKey() { let item = UINavigationItem(title: "the.same.lavel") item.prompt = "the.same.lavel" item.localize() - + XCTAssertTrue(item.title == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(item.prompt == "Esto es una internazionalizacion en el mismo nivel") } - + func testNavigationItemWithoutKeys() { let item = UINavigationItem(title: "") item.localize() - + XCTAssertTrue(item.title == "") XCTAssertTrue(item.prompt == nil) } - + // MARK: - UISearchBar func testSearchBarWithLocalizeKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.localizePlaceholder = "the.same.lavel" bar.localizePrompt = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.placeholder == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(bar.prompt == "Esto es una internazionalizacion en el mismo nivel") } - + func testSearchBarWithTextKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.placeholder = "the.same.lavel" bar.prompt = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.placeholder == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(bar.prompt == "Esto es una internazionalizacion en el mismo nivel") } - + func testSearchBarWithoutKeys() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.localize() - + XCTAssertTrue(bar.placeholder == nil) XCTAssertTrue(bar.prompt == nil) } - + // MARK: - UITabBarItem func testTabBarItemWithLocalizeKey() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.localizeKey = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.title == "Esto es una internazionalizacion en el mismo nivel") } - + func testTabBarItemWithTextKey() { let bar = UITabBarItem(title: "the.same.lavel", image: nil, tag: 0) bar.localize() - + XCTAssertTrue(bar.title == "Esto es una internazionalizacion en el mismo nivel") } - + func testTabBarItemWithoutKeys() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.localize() - + XCTAssertTrue(bar.title == "") } - + // MARK: - UITextField func testTextFieldWithLocalizeKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.localizeText = "the.same.lavel" textField.localizePlaceholder = "the.same.lavel" textField.localize() - + XCTAssertTrue(textField.text == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(textField.placeholder == "Esto es una internazionalizacion en el mismo nivel") } - + func testTextFieldWithTextKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.text = "the.same.lavel" textField.placeholder = "the.same.lavel" textField.localize() - + XCTAssertTrue(textField.text == "Esto es una internazionalizacion en el mismo nivel") XCTAssertTrue(textField.placeholder == "Esto es una internazionalizacion en el mismo nivel") } - + func testTextFieldWithoutKeys() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.localize() - + XCTAssertTrue(textField.text == "") XCTAssertTrue(textField.placeholder == nil) } - + // MARK: - UITextView func testTextViewWithLocalizeKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.localizeKey = "the.same.lavel" textView.localize() - + XCTAssertTrue(textView.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testTextViewWithTextKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.text = "the.same.lavel" textView.localize() - + XCTAssertTrue(textView.text == "Esto es una internazionalizacion en el mismo nivel") } - + func testTextViewWithoutKeys() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.localize() - + XCTAssertTrue(textView.text == "") } - + // MARK: - UISegmentedControl func testSegmentedControlWithLocalizeKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) @@ -234,40 +234,39 @@ class UIViewComponentsES: XCTestCase { segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "one, two" segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "Primero") XCTAssertTrue(segment.titleForSegment(at: 1) == "Segundo") } - + func testSegmentedControlWithLocalizeKeyBased() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "segment.base: one, two" segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "Primero") XCTAssertTrue(segment.titleForSegment(at: 1) == "Segundo") } - + func testSegmentedControlWithTextKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "segment.base.one", at: 0, animated: false) segment.insertSegment(withTitle: "segment.base.two", at: 1, animated: false) segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "Primero") XCTAssertTrue(segment.titleForSegment(at: 1) == "Segundo") } - + func testSegmentedControlWithoutKeys() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "") XCTAssertTrue(segment.titleForSegment(at: 1) == "") } } - diff --git a/Tests/UIViewComponentsWithString.swift b/Tests/UIViewComponentsWithString.swift index d7b14e2..494e9fc 100644 --- a/Tests/UIViewComponentsWithString.swift +++ b/Tests/UIViewComponentsWithString.swift @@ -15,216 +15,216 @@ class UIViewComponentsWithString: XCTestCase { Localize.update(bundle: Bundle(for: type(of: self))) Localize.update(language: "en") } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + // MARK: - UIBarButtonItem func testButtonItemWithLocalizeKey() { let button = UIBarButtonItem(title: "", style: .plain, target: self, action: nil) button.localizeKey = "the.same.lavel" button.localize() - + XCTAssertTrue(button.title == "This is a localized in the same level") } - + func testButtonItemWithTextKey() { let button = UIBarButtonItem(title: "the.same.lavel", style: .plain, target: self, action: nil) button.localize() - + XCTAssertTrue(button.title == "This is a localized in the same level") } - + func testButtonItemWithoutKeys() { let button = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil) button.localize() - + XCTAssertTrue(button.title == nil) } - + // MARK: - UIButton func testButtonWithLocalizeKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.localizeKey = "the.same.lavel" button.localize() - + XCTAssertTrue(button.titleLabel?.text == "This is a localized in the same level") } - + func testButtonWithTextKey() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.titleLabel?.text = "the.same.lavel" button.localize() - + XCTAssertTrue(button.titleLabel?.text == "This is a localized in the same level") } - + func testButtonWithoutKeys() { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) button.localize() - + XCTAssertTrue(button.titleLabel?.text == "") } - + // MARK: - UILabel func testLabelWithLocalizeKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.localizeKey = "the.same.lavel" label.localize() - + XCTAssertTrue(label.text == "This is a localized in the same level") } - + func testLabelWithTextKey() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.text = "the.same.lavel" label.localize() - + XCTAssertTrue(label.text == "This is a localized in the same level") } - + func testLabelWithoutKeys() { let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) label.localize() - + XCTAssertTrue(label.text == nil) } - + // MARK: - UINavigationItem func testNavigationItemWithLocalizeKey() { let item = UINavigationItem(title: "") item.localizeTitle = "the.same.lavel" item.localizePrompt = "the.same.lavel" item.localize() - + XCTAssertTrue(item.title == "This is a localized in the same level") XCTAssertTrue(item.prompt == "This is a localized in the same level") } - + func testNavigationItemWithTextKey() { let item = UINavigationItem(title: "the.same.lavel") item.prompt = "the.same.lavel" item.localize() - + XCTAssertTrue(item.title == "This is a localized in the same level") XCTAssertTrue(item.prompt == "This is a localized in the same level") } - + func testNavigationItemWithoutKeys() { let item = UINavigationItem(title: "") item.localize() - + XCTAssertTrue(item.title == "") XCTAssertTrue(item.prompt == nil) } - + // MARK: - UISearchBar func testSearchBarWithLocalizeKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.localizePlaceholder = "the.same.lavel" bar.localizePrompt = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.placeholder == "This is a localized in the same level") XCTAssertTrue(bar.prompt == "This is a localized in the same level") } - + func testSearchBarWithTextKey() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.placeholder = "the.same.lavel" bar.prompt = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.placeholder == "This is a localized in the same level") XCTAssertTrue(bar.prompt == "This is a localized in the same level") } - + func testSearchBarWithoutKeys() { let bar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) bar.localize() - + XCTAssertTrue(bar.placeholder == nil) XCTAssertTrue(bar.prompt == nil) } - + // MARK: - UITabBarItem func testTabBarItemWithLocalizeKey() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.localizeKey = "the.same.lavel" bar.localize() - + XCTAssertTrue(bar.title == "This is a localized in the same level") } - + func testTabBarItemWithTextKey() { let bar = UITabBarItem(title: "the.same.lavel", image: nil, tag: 0) bar.localize() - + XCTAssertTrue(bar.title == "This is a localized in the same level") } - + func testTabBarItemWithoutKeys() { let bar = UITabBarItem(title: "", image: nil, tag: 0) bar.localize() - + XCTAssertTrue(bar.title == "") } - + // MARK: - UITextField func testTextFieldWithLocalizeKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.localizeText = "the.same.lavel" textField.localizePlaceholder = "the.same.lavel" textField.localize() - + XCTAssertTrue(textField.text == "This is a localized in the same level") XCTAssertTrue(textField.placeholder == "This is a localized in the same level") } - + func testTextFieldWithTextKey() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.text = "the.same.lavel" textField.placeholder = "the.same.lavel" textField.localize() - + XCTAssertTrue(textField.text == "This is a localized in the same level") XCTAssertTrue(textField.placeholder == "This is a localized in the same level") } - + func testTextFieldWithoutKeys() { let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textField.localize() - + XCTAssertTrue(textField.text == "") XCTAssertTrue(textField.placeholder == nil) } - + // MARK: - UITextView func testTextViewWithLocalizeKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.localizeKey = "the.same.lavel" textView.localize() - + XCTAssertTrue(textView.text == "This is a localized in the same level") } - + func testTextViewWithTextKey() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.text = "the.same.lavel" textView.localize() - + XCTAssertTrue(textView.text == "This is a localized in the same level") } - + func testTextViewWithoutKeys() { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) textView.localize() - + XCTAssertTrue(textView.text == "") } - + // MARK: - UISegmentedControl func testSegmentedControlWithLocalizeKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) @@ -232,38 +232,38 @@ class UIViewComponentsWithString: XCTestCase { segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "one, two" segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithLocalizeKeyBased() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localizeKey = "segment.base: one, two" segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithTextKey() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "segment.base.one", at: 0, animated: false) segment.insertSegment(withTitle: "segment.base.two", at: 1, animated: false) segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "First") XCTAssertTrue(segment.titleForSegment(at: 1) == "Second") } - + func testSegmentedControlWithoutKeys() { let segment = UISegmentedControl(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) segment.insertSegment(withTitle: "", at: 0, animated: false) segment.insertSegment(withTitle: "", at: 1, animated: false) segment.localize() - + XCTAssertTrue(segment.titleForSegment(at: 0) == "") XCTAssertTrue(segment.titleForSegment(at: 1) == "") }