diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0023a53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/.swiftpm/WPSwift.xctestplan b/.swiftpm/WPSwift.xctestplan new file mode 100644 index 0000000..a950784 --- /dev/null +++ b/.swiftpm/WPSwift.xctestplan @@ -0,0 +1,32 @@ +{ + "configurations" : [ + { + "id" : "779FA71B-8A24-4208-8B95-11435B194ED1", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : { + "targets" : [ + { + "containerPath" : "container:", + "identifier" : "WPSwift", + "name" : "WPSwift" + } + ] + } + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "WPSwiftTests", + "name" : "WPSwiftTests" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WPSwift.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WPSwift.xcscheme new file mode 100644 index 0000000..ead1f8d --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/WPSwift.xcscheme @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..96c2d22 --- /dev/null +++ b/Package.swift @@ -0,0 +1,24 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "WPSwift", + defaultLocalization: "en", + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "WPSwift", + targets: ["WPSwift"]), + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target( + name: "WPSwift"), + .testTarget( + name: "WPSwiftTests", + dependencies: ["WPSwift"]), + ] +) diff --git a/Sources/WPSwift/Localizable.swift b/Sources/WPSwift/Localizable.swift new file mode 100644 index 0000000..6909839 --- /dev/null +++ b/Sources/WPSwift/Localizable.swift @@ -0,0 +1,66 @@ +// +// File.swift +// +// +// Created by Ulaş Sancak on 1.10.2023. +// + +import Foundation + +protocol AllKeys { + static var allKeys: [String] { get } +} + +protocol Localizable: RawRepresentable, CaseIterable, AllKeys where RawValue == String {} + +extension Localizable { + static var allKeys: [String] { + allCases.map { $0.rawValue } + } +} + +public enum Localization: String, Localizable { + //Default cases + case ok + case yes + case no + case cancel + case success + case failure + case unknown + case unknownError = "unknown_error" + case error + case done + case next + + //All keys as nested. This needs to be updated if another nested enum is added. + public static var allKeys: [String] { + allCases.map({ $0.rawValue }) + + Configuration.allKeys + } + + //Cases for specific parts + + enum Configuration { + enum Error: String, Localizable { + case notSetup = "configuration.error.notSetup" + case route = "configuration.error.route" + case namespace = "configuration.error.namespace" + } + + static var allKeys: [String] { + Error.allKeys + } + } +} + +extension Localizable { + var localized: String { + NSLocalizedString(rawValue, bundle: Bundle.module, comment: "") + } + + func localized(_ args: CVarArg...) -> String { + String(format: localized, args) + } +} + diff --git a/Sources/WPSwift/Resources/en.lproj/Localizable.strings b/Sources/WPSwift/Resources/en.lproj/Localizable.strings new file mode 100644 index 0000000..833dbc1 --- /dev/null +++ b/Sources/WPSwift/Resources/en.lproj/Localizable.strings @@ -0,0 +1,25 @@ +/* + Localizable.strings + + + Created by Ulaş Sancak on 1.10.2023. + +*/ + +//General +"ok" = "OK"; +"yes" = "Yes"; +"no" = "No"; +"cancel" = "Cancel"; +"success" = "Success"; +"failure" = "Failure"; +"unknown" = "Unknown"; +"unknown_error" = "Unknown error"; +"error" = "Error"; +"done" = "Done"; +"next" = "Next"; + +//Setup Configuration +"configuration.error.notSetup" = "Wordpress Configuration was not setup. Use WPSwift.configuration function to set it up."; +"configuration.error.route" = "Wordpress `route` is empty. Use WPSwift.configuration function to set it up."; +"configuration.error.namespace" = "Wordpress `namespace` is empty. Use WPSwift.configuration function to set it up."; diff --git a/Sources/WPSwift/Resources/tr.lproj/Localizable.strings b/Sources/WPSwift/Resources/tr.lproj/Localizable.strings new file mode 100644 index 0000000..58cdf94 --- /dev/null +++ b/Sources/WPSwift/Resources/tr.lproj/Localizable.strings @@ -0,0 +1,25 @@ +/* + Localizable.strings + + + Created by Ulaş Sancak on 1.10.2023. + +*/ + +//Genel +"ok" = "TAMAM"; +"yes" = "Evet"; +"no" = "Hayır"; +"cancel" = "İptal"; +"success" = "Başarılı"; +"failure" = "Hata"; +"unknown" = "Bilinmeyen"; +"unknown_error" = "Bilinmeyen hata"; +"error" = "Hata"; +"done" = "Bitti"; +"next" = "Sonraki"; + +//Setup Configuration +"configuration.error.notSetup" = "Wordpress konfigurasyonu oluşturulmamış. WPSwift.initialize fonksiyonunu kullanın."; +"configuration.error.route" = "Wordpress `route` boş görünüyor. WPSwift.initialize fonksiyonunu kullanın."; +"configuration.error.namespace" = "Wordpress `namespace` boş görünüyor. WPSwift.initialize fonksiyonunu kullanın."; diff --git a/Sources/WPSwift/WPSwift.swift b/Sources/WPSwift/WPSwift.swift new file mode 100644 index 0000000..0bf605a --- /dev/null +++ b/Sources/WPSwift/WPSwift.swift @@ -0,0 +1,47 @@ +// The Swift Programming Language +// https://docs.swift.org/swift-book +import Foundation + +enum WPConfigurationError: LocalizedError { + case wasNotSetup + case route + case namespace + + var errorDescription: String? { + switch self { + case .wasNotSetup: + Localization.Configuration.Error.notSetup.localized + case .route: + Localization.Configuration.Error.route.localized + case .namespace: + Localization.Configuration.Error.namespace.localized + } + } +} + +struct WPConfiguration { + let route: String + let namespace: String +} + +public struct WPSwift { + static internal var configuration: WPConfiguration { + get throws { + guard let _configuration else { throw WPConfigurationError.wasNotSetup } + guard !_configuration.route.isEmpty else { throw WPConfigurationError.route } + guard !_configuration.namespace.isEmpty else { throw WPConfigurationError.namespace } + return _configuration + } + } + static private var _configuration: WPConfiguration? + + static func resetConfiguration() { + _configuration = nil + } +} + +public extension WPSwift { + static func initialize(route: String, namespace: String) { + WPSwift._configuration = .init(route: route, namespace: namespace) + } +} diff --git a/Tests/WPSwiftTests/LocalizationTests.swift b/Tests/WPSwiftTests/LocalizationTests.swift new file mode 100644 index 0000000..0d8aa7d --- /dev/null +++ b/Tests/WPSwiftTests/LocalizationTests.swift @@ -0,0 +1,39 @@ +// +// WPSwiftSetupTests.swift +// +// +// Created by Ulaş Sancak on 30.09.2023. +// + +import XCTest +@testable import WPSwift + +class LocalizationTests: XCTestCase { + + func testLocalizations() throws { + let localizations = Bundle.module.localizations + for localization in localizations { + guard let path = Bundle.module.path(forResource: localization, ofType: "lproj"), + let bundle = Bundle(path: path) else { + XCTAssert(false, "Localization file is missing for '" + localization + "'.") + return + } + guard let localizationPath = bundle.path(forResource: "Localizable", ofType: "strings") else { + XCTAssert(false, "Localizable.strings file is missing for " + localization + ".") + return + } + guard let localizationKeys = NSDictionary(contentsOfFile: localizationPath)?.allKeys as? [String] else { + XCTAssert(false, localization + "localization file is curropted.") + return + } + let allKeys = Localization.allKeys + for key in allKeys { + XCTAssert(localizationKeys.contains(key), key + " key is missing from the " + localization + " file") + } + for key in localizationKeys { + XCTAssert(allKeys.contains(key), "Found key '" + key + "' in localization file(" + localization + ") is not in Localization nested enum.") + } + } + } + +} diff --git a/Tests/WPSwiftTests/WPSwiftSetupTests.swift b/Tests/WPSwiftTests/WPSwiftSetupTests.swift new file mode 100644 index 0000000..2ec40c9 --- /dev/null +++ b/Tests/WPSwiftTests/WPSwiftSetupTests.swift @@ -0,0 +1,46 @@ +// +// WPSwiftSetupTests.swift +// +// +// Created by Ulaş Sancak on 30.09.2023. +// + +import XCTest +@testable import WPSwift + +final class WPSwiftSetupTests: XCTestCase { + override func setUp() async throws { + WPSwift.resetConfiguration() + } + + func testSetupSuccess() throws { + WPSwift.initialize(route: "https://www.example.com/wp-json", namespace: "wp/v2") + _ = try WPSwift.configuration + } + + func testSetupFailure() throws { + do { + _ = try WPSwift.configuration + } catch WPConfigurationError.wasNotSetup { + XCTAssertEqual(WPConfigurationError.wasNotSetup.errorDescription, "Wordpress Configuration was not setup. Use WPSwift.configuration function to set it up.", "WPConfigurationError.wasNotSetup is incorrect.") + } + } + + func testRouteSetupFailure() throws { + WPSwift.initialize(route: "", namespace: "wp/v2") + do { + _ = try WPSwift.configuration + } catch WPConfigurationError.route { + XCTAssertEqual(WPConfigurationError.route.errorDescription, "Wordpress `route` is empty. Use WPSwift.configuration function to set it up.", "WPConfigurationError.route is incorrect.") + } + } + + func testNamespaceSetupFailure() throws { + WPSwift.initialize(route: "https://www.example.com/wp-json", namespace: "") + do { + _ = try WPSwift.configuration + } catch WPConfigurationError.namespace { + XCTAssertEqual(WPConfigurationError.namespace.errorDescription, "Wordpress `namespace` is empty. Use WPSwift.configuration function to set it up.", "WPConfigurationError.namespace is incorrect.") + } + } +}