diff --git a/Swifternalization.xcodeproj/project.pbxproj b/Swifternalization.xcodeproj/project.pbxproj index 883abe6..a31b8e3 100644 --- a/Swifternalization.xcodeproj/project.pbxproj +++ b/Swifternalization.xcodeproj/project.pbxproj @@ -92,6 +92,18 @@ 6DBB6C941B40769F002F39A3 /* SharedPolishExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBB6C8E1B40768A002F39A3 /* SharedPolishExpression.swift */; }; 6DBB6C961B4076E8002F39A3 /* SharedBaseExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBB6C951B4076E8002F39A3 /* SharedBaseExpressionTests.swift */; }; 6DBB6C981B4077FA002F39A3 /* SharedPolishExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBB6C971B4077FA002F39A3 /* SharedPolishExpressionTests.swift */; }; + 6DD3B93A1B5ED35200C79EAC /* base.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3B9371B5ED35200C79EAC /* base.json */; }; + 6DD3B93B1B5ED35200C79EAC /* expressions.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3B9381B5ED35200C79EAC /* expressions.json */; }; + 6DD3B93C1B5ED35200C79EAC /* pl.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD3B9391B5ED35200C79EAC /* pl.json */; }; + 6DD3B9411B5ED38B00C79EAC /* JSONFileLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD3B9401B5ED38B00C79EAC /* JSONFileLoaderTests.swift */; }; + 6DD3B9421B5ED3F000C79EAC /* JSONFileLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC691B5EBDA600A1220F /* JSONFileLoader.swift */; }; + 6DD3B9441B5ED55500C79EAC /* ExpressionsLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD3B9431B5ED55500C79EAC /* ExpressionsLoaderTests.swift */; }; + 6DD3B9451B5ED58A00C79EAC /* ExpressionsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC671B5EBDA600A1220F /* ExpressionsLoader.swift */; }; + 6DD3B9461B5ED5B500C79EAC /* ProcessableExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC6D1B5EBDA600A1220F /* ProcessableExpression.swift */; }; + 6DD3B9471B5ED61100C79EAC /* ExpressionPatternType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC681B5EBDA600A1220F /* ExpressionPatternType.swift */; }; + 6DD3B9481B5ED61500C79EAC /* Processable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC6C1B5EBDA600A1220F /* Processable.swift */; }; + 6DD3B9491B5ED61800C79EAC /* ExpressionRepresentationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB3CC661B5EBDA600A1220F /* ExpressionRepresentationType.swift */; }; + 6DD3B94B1B5ED65A00C79EAC /* NSBundle+TestExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD3B94A1B5ED65A00C79EAC /* NSBundle+TestExtension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -174,6 +186,12 @@ 6DBB6C8E1B40768A002F39A3 /* SharedPolishExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedPolishExpression.swift; sourceTree = ""; }; 6DBB6C951B4076E8002F39A3 /* SharedBaseExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedBaseExpressionTests.swift; sourceTree = ""; }; 6DBB6C971B4077FA002F39A3 /* SharedPolishExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedPolishExpressionTests.swift; sourceTree = ""; }; + 6DD3B9371B5ED35200C79EAC /* base.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = base.json; sourceTree = ""; }; + 6DD3B9381B5ED35200C79EAC /* expressions.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = expressions.json; sourceTree = ""; }; + 6DD3B9391B5ED35200C79EAC /* pl.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = pl.json; sourceTree = ""; }; + 6DD3B9401B5ED38B00C79EAC /* JSONFileLoaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONFileLoaderTests.swift; sourceTree = ""; }; + 6DD3B9431B5ED55500C79EAC /* ExpressionsLoaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionsLoaderTests.swift; sourceTree = ""; }; + 6DD3B94A1B5ED65A00C79EAC /* NSBundle+TestExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSBundle+TestExtension.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -206,6 +224,7 @@ isa = PBXGroup; children = ( 6D140F431B56D03D00359143 /* RandomNumbers.swift */, + 6DD3B94A1B5ED65A00C79EAC /* NSBundle+TestExtension.swift */, ); name = Helpers; sourceTree = ""; @@ -234,6 +253,7 @@ isa = PBXGroup; children = ( 6DB3CC8E1B5EC27600A1220F /* Enums */, + 6DD3B93E1B5ED36F00C79EAC /* Loaders */, 6DB3CC8D1B5EC1FF00A1220F /* Matchers and Parsers */, 6DB3CC8C1B5EC1E000A1220F /* Processable */, 6DB3CC8A1B5EC19400A1220F /* Protocols */, @@ -241,9 +261,6 @@ 6DB3CC6A1B5EBDA600A1220F /* LengthVariation.swift */, 6DB3CC711B5EBDA600A1220F /* TranslationLengthVariation.swift */, 6DB3CC721B5EBDA600A1220F /* TranslationSimple.swift */, - 6DB3CC671B5EBDA600A1220F /* ExpressionsLoader.swift */, - 6DB3CC691B5EBDA600A1220F /* JSONFileLoader.swift */, - 6DB3CC731B5EBDA600A1220F /* TranslationsLoader.swift */, 6D6282911B3F04C800E65FCD /* Expression.swift */, 6D6464811B40106C00C46C6D /* LocalizableFilesLoader.swift */, 6D6282991B3F17CA00E65FCD /* Regex.swift */, @@ -268,6 +285,7 @@ 6D5004571B3EF91600A54B36 /* SwifternalizationTests */ = { isa = PBXGroup; children = ( + 6DD3B93F1B5ED37A00C79EAC /* Loaders */, 6D140F451B56D04300359143 /* Helpers */, 6D6282971B3F13C300E65FCD /* ExpressionTests.swift */, 6D6282BE1B3F42CA00E65FCD /* InequalityExpressionMatcherTests.swift */, @@ -285,6 +303,7 @@ 6D5004581B3EF91600A54B36 /* Supporting Files */, 6D5004941B3EFF6D00A54B36 /* Localizable.strings */, 6DBB6C5B1B4026B8002F39A3 /* Expressions.strings */, + 6DD3B93D1B5ED35600C79EAC /* Localizable Files */, ); path = SwifternalizationTests; sourceTree = ""; @@ -395,6 +414,35 @@ path = "Shared Expressions"; sourceTree = ""; }; + 6DD3B93D1B5ED35600C79EAC /* Localizable Files */ = { + isa = PBXGroup; + children = ( + 6DD3B9371B5ED35200C79EAC /* base.json */, + 6DD3B9381B5ED35200C79EAC /* expressions.json */, + 6DD3B9391B5ED35200C79EAC /* pl.json */, + ); + name = "Localizable Files"; + sourceTree = ""; + }; + 6DD3B93E1B5ED36F00C79EAC /* Loaders */ = { + isa = PBXGroup; + children = ( + 6DB3CC671B5EBDA600A1220F /* ExpressionsLoader.swift */, + 6DB3CC691B5EBDA600A1220F /* JSONFileLoader.swift */, + 6DB3CC731B5EBDA600A1220F /* TranslationsLoader.swift */, + ); + name = Loaders; + sourceTree = ""; + }; + 6DD3B93F1B5ED37A00C79EAC /* Loaders */ = { + isa = PBXGroup; + children = ( + 6DD3B9401B5ED38B00C79EAC /* JSONFileLoaderTests.swift */, + 6DD3B9431B5ED55500C79EAC /* ExpressionsLoaderTests.swift */, + ); + name = Loaders; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -516,7 +564,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6DD3B93B1B5ED35200C79EAC /* expressions.json in Resources */, + 6DD3B93A1B5ED35200C79EAC /* base.json in Resources */, 6D5004961B3EFFC100A54B36 /* Info.plist in Resources */, + 6DD3B93C1B5ED35200C79EAC /* pl.json in Resources */, 6DBB6C591B4026B8002F39A3 /* Expressions.strings in Resources */, 6D5004921B3EFF6D00A54B36 /* Localizable.strings in Resources */, ); @@ -587,7 +638,9 @@ files = ( 6D6282C91B3F4F6700E65FCD /* RegexExpressionParser.swift in Sources */, 6DBB6C981B4077FA002F39A3 /* SharedPolishExpressionTests.swift in Sources */, + 6DD3B9441B5ED55500C79EAC /* ExpressionsLoaderTests.swift in Sources */, 6D6282C11B3F43C600E65FCD /* InequalityExtendedExpressionMatcherTests.swift in Sources */, + 6DD3B9451B5ED58A00C79EAC /* ExpressionsLoader.swift in Sources */, 6D6282981B3F13C300E65FCD /* ExpressionTests.swift in Sources */, 6DBB6C661B40369A002F39A3 /* SharedExpressionsConfigurator.swift in Sources */, 6D50045B1B3EF91600A54B36 /* SwifternalizationTests.swift in Sources */, @@ -595,9 +648,13 @@ 6D6282B81B3F3E2200E65FCD /* InequalitySign.swift in Sources */, 6DB3CC861B5EBF4800A1220F /* CountryCode.swift in Sources */, 6D6282A71B3F25BE00E65FCD /* ExpressionMatcher.swift in Sources */, + 6DD3B94B1B5ED65A00C79EAC /* NSBundle+TestExtension.swift in Sources */, 6D6464851B40146600C46C6D /* KeyValueType.swift in Sources */, + 6DD3B9481B5ED61500C79EAC /* Processable.swift in Sources */, 6D6282C81B3F4F6400E65FCD /* RegexExpressionMatcher.swift in Sources */, + 6DD3B9421B5ED3F000C79EAC /* JSONFileLoader.swift in Sources */, 6DBB6C6A1B40412D002F39A3 /* InternalPattern.swift in Sources */, + 6DD3B9411B5ED38B00C79EAC /* JSONFileLoaderTests.swift in Sources */, 6DB3CC911B5EC29E00A1220F /* ExpressionType.swift in Sources */, 6D6282941B3F052B00E65FCD /* TranslatablePairTests.swift in Sources */, 6DBB6C941B40769F002F39A3 /* SharedPolishExpression.swift in Sources */, @@ -610,14 +667,17 @@ 6D6282B31B3F3C2800E65FCD /* InequalityExtendedExpressionParser.swift in Sources */, 6D140F441B56D03D00359143 /* RandomNumbers.swift in Sources */, 6D6282AD1B3F327C00E65FCD /* InequalityExpressionMatcher.swift in Sources */, + 6DD3B9491B5ED61800C79EAC /* ExpressionRepresentationType.swift in Sources */, 6D62829D1B3F19CC00E65FCD /* RegexTests.swift in Sources */, 6D6282CB1B3F508C00E65FCD /* RegexExpressionParserTests.swift in Sources */, + 6DD3B9461B5ED5B500C79EAC /* ProcessableExpression.swift in Sources */, 6D6282C31B3F45A600E65FCD /* InequalityExtendedExpressionParserTests.swift in Sources */, 6D6282A91B3F25DC00E65FCD /* InequalityExpressionParserTests.swift in Sources */, 6D6282AA1B3F269900E65FCD /* ExpressionParser.swift in Sources */, 6D6282BB1B3F41DB00E65FCD /* InequalityExtendedExpressionMatcher.swift in Sources */, 6DBB6C511B401B7C002F39A3 /* LocalizableFilesLoader.swift in Sources */, 6DBB6C6C1B40431D002F39A3 /* LocalizableFilesLoaderTests.swift in Sources */, + 6DD3B9471B5ED61100C79EAC /* ExpressionPatternType.swift in Sources */, 6DBB6C961B4076E8002F39A3 /* SharedBaseExpressionTests.swift in Sources */, 6D62829B1B3F17FE00E65FCD /* Regex.swift in Sources */, 6D6282CD1B3F52AD00E65FCD /* RegexExpressionMatcherTests.swift in Sources */, diff --git a/Swifternalization/ExpressionsLoader.swift b/Swifternalization/ExpressionsLoader.swift index 6654368..7f83995 100644 --- a/Swifternalization/ExpressionsLoader.swift +++ b/Swifternalization/ExpressionsLoader.swift @@ -12,9 +12,9 @@ final class ExpressionsLoader: JSONFileLoader { :returns: array of loaded expressions. */ - class func loadExpressions(countryCode: CountryCode) -> [ProcessableExpression] { + class func loadExpressions(countryCode: CountryCode, bundle: NSBundle) -> [ProcessableExpression] { var expressions = [ProcessableExpression]() - if let json = self.load("expressions", fileType: "json", bundle: NSBundle.mainBundle()), + if let json = self.load("expressions", bundle: bundle), let expressionsDict = json[countryCode] as? Dictionary { for (identifier, pattern) in expressionsDict { expressions.append(ProcessableExpression(identifier: identifier, pattern: pattern)) diff --git a/Swifternalization/JSONFileLoader.swift b/Swifternalization/JSONFileLoader.swift index 05c2096..39f9e94 100644 --- a/Swifternalization/JSONFileLoader.swift +++ b/Swifternalization/JSONFileLoader.swift @@ -15,11 +15,11 @@ class JSONFileLoader { :return: JSON or nil. */ - final class func load(fileName: String, fileType: String, bundle: NSBundle = NSBundle.mainBundle()) -> JSONDictionary? { - if let fileURL = bundle.URLForResource(fileName, withExtension: fileType) { + final class func load(fileName: String, bundle: NSBundle = NSBundle.mainBundle()) -> JSONDictionary? { + if let fileURL = bundle.URLForResource(fileName, withExtension: "json") { return load(fileURL) } - println("Cannot find file \(fileName).\(fileType).") + println("Cannot find file \(fileName).json.") return nil } diff --git a/Swifternalization/TranslationsLoader.swift b/Swifternalization/TranslationsLoader.swift index de4a241..0c47403 100644 --- a/Swifternalization/TranslationsLoader.swift +++ b/Swifternalization/TranslationsLoader.swift @@ -26,7 +26,7 @@ final class TranslationsLoader: JSONFileLoader { */ class func loadTranslations(countryCode: CountryCode) -> [TranslationType] { var loadedTranslations = [TranslationType]() - let json = self.load(countryCode, fileType: "json", bundle: NSBundle.mainBundle()) + let json = self.load(countryCode, bundle: NSBundle.mainBundle()) if json == nil { return [TranslationType]() } for (translationKey, value) in json! { diff --git a/SwifternalizationTests/ExpressionsLoaderTests.swift b/SwifternalizationTests/ExpressionsLoaderTests.swift new file mode 100644 index 0000000..4673893 --- /dev/null +++ b/SwifternalizationTests/ExpressionsLoaderTests.swift @@ -0,0 +1,28 @@ +// +// ExpressionsLoaderTests.swift +// Swifternalization +// +// Created by Tomasz Szulc on 21/07/15. +// Copyright (c) 2015 Tomasz Szulc. All rights reserved. +// + +import UIKit +import XCTest + +class ExpressionsLoaderTests: XCTestCase { + + func testShouldLoadBase() { + let content = ExpressionsLoader.loadExpressions("base", bundle: NSBundle.testBundle()) + XCTAssertTrue(content.count > 0, "") + } + + func testShouldLoadPL() { + let content = ExpressionsLoader.loadExpressions("pl", bundle: NSBundle.testBundle()) + XCTAssertTrue(content.count > 0, "") + } + + func testShouldNotLoadDE() { + let content = ExpressionsLoader.loadExpressions("de", bundle: NSBundle.testBundle()) + XCTAssertFalse(content.count > 0, "") + } +} diff --git a/SwifternalizationTests/JSONFileLoaderTests.swift b/SwifternalizationTests/JSONFileLoaderTests.swift new file mode 100644 index 0000000..0d308ba --- /dev/null +++ b/SwifternalizationTests/JSONFileLoaderTests.swift @@ -0,0 +1,23 @@ +// +// JSONFileLoaderTests.swift +// Swifternalization +// +// Created by Tomasz Szulc on 21/07/15. +// Copyright (c) 2015 Tomasz Szulc. All rights reserved. +// + +import UIKit +import XCTest + +class JSONFileLoaderTests: XCTestCase { + + func testJSONShouldBeLoaded() { + let content = JSONFileLoader.load("base", bundle: NSBundle.testBundle()) + XCTAssertNotNil(content!, "") + } + + func testFileShouldNotBeLoaded() { + let content = JSONFileLoader.load("not-existing", bundle: NSBundle.testBundle()) + XCTAssertNil(content, "") + } +} diff --git a/SwifternalizationTests/NSBundle+TestExtension.swift b/SwifternalizationTests/NSBundle+TestExtension.swift new file mode 100644 index 0000000..780dc4e --- /dev/null +++ b/SwifternalizationTests/NSBundle+TestExtension.swift @@ -0,0 +1,15 @@ +// +// NSBundle+TestExtension.swift +// Swifternalization +// +// Created by Tomasz Szulc on 21/07/15. +// Copyright (c) 2015 Tomasz Szulc. All rights reserved. +// + +import Foundation + +extension NSBundle { + class func testBundle() -> NSBundle { + return NSBundle(forClass: JSONFileLoaderTests.self) + } +} \ No newline at end of file diff --git a/SwifternalizationTests/base.json b/SwifternalizationTests/base.json new file mode 100644 index 0000000..e0b4524 --- /dev/null +++ b/SwifternalizationTests/base.json @@ -0,0 +1,28 @@ +{ + "welcome": "welcome", + + "cars": { + "one": "1 car", + "ie:x=2": "2 cars", + "more": "%d cars" + }, + + "forgot-password": { + "@100": "Forgot Password? Help.", + "@200": "Forgot Password? Get password Help.", + "@300": "Forgotten Your Password? Get password Help." + }, + + "car-sentence": { + "one": { + "@100": "one car", + "@200": "just one car", + "@300": "you've got just one car" + }, + + "more": { + "@100": "%d cars", + "@300": "you've got %d cars" + } + } +} diff --git a/SwifternalizationTests/expressions.json b/SwifternalizationTests/expressions.json new file mode 100644 index 0000000..05f0b5d --- /dev/null +++ b/SwifternalizationTests/expressions.json @@ -0,0 +1,11 @@ +{ + "base": { + "one": "ie:x=1", + "two": "ie:x=2", + "more": "exp:(^[^1])|(^\\d{2,})" + }, + + "pl": { + "few": "exp:(((?!1).[2-4]{1})$)|(^[2-4]$)" + } +} diff --git a/SwifternalizationTests/pl.json b/SwifternalizationTests/pl.json new file mode 100644 index 0000000..ebea036 --- /dev/null +++ b/SwifternalizationTests/pl.json @@ -0,0 +1,28 @@ +{ + "welcome": "witaj", + + "cars": { + "one": "1 samochód", + "ie:x=2": "2 samochody", + "more": "%d samochodów" + }, + + "forgot-password": { + "@100": "Zapomniałeś hasła? Pomoc.", + "@200": "Zapomniałeś hasła? Skorzystaj z Pomocy.", + "@300": "Zapomniałeś swojego hasła? Skorzystaj z pomocy." + }, + + "car-sentence": { + "one": { + "@100": "jeden samochód", + "@200": "tylko jeden samochód", + "@300": "posiadasz tylko jeden samochód" + }, + + "more": { + "@100": "%d samochodów", + "@300": "posiadasz %d samochodów" + } + } +}