From 78e15bb0314e117b5783851485da2b59465854b4 Mon Sep 17 00:00:00 2001 From: Tomasz Szulc Date: Thu, 30 Jul 2015 20:57:47 +0200 Subject: [PATCH] Simplify TranslationsLoader and add LoadedTranslation struct with corresponding type --- Swifternalization.xcodeproj/project.pbxproj | 6 ++ Swifternalization/LoadedTranslation.swift | 76 ++++++++++++++ Swifternalization/TranslationsLoader.swift | 108 ++++++-------------- 3 files changed, 111 insertions(+), 79 deletions(-) create mode 100644 Swifternalization/LoadedTranslation.swift diff --git a/Swifternalization.xcodeproj/project.pbxproj b/Swifternalization.xcodeproj/project.pbxproj index 9f25c23..0ea86a6 100644 --- a/Swifternalization.xcodeproj/project.pbxproj +++ b/Swifternalization.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 6D140F441B56D03D00359143 /* RandomNumbers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D140F431B56D03D00359143 /* RandomNumbers.swift */; }; + 6D4C4EAF1B6AA48F00B7839A /* LoadedTranslation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C4EAE1B6AA48F00B7839A /* LoadedTranslation.swift */; }; + 6D4C4EB01B6AA54800B7839A /* LoadedTranslation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C4EAE1B6AA48F00B7839A /* LoadedTranslation.swift */; }; 6D50044E1B3EF91600A54B36 /* Swifternalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D50044D1B3EF91600A54B36 /* Swifternalization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6D5004541B3EF91600A54B36 /* Swifternalization.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D5004481B3EF91600A54B36 /* Swifternalization.framework */; }; 6D50045B1B3EF91600A54B36 /* SwifternalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D50045A1B3EF91600A54B36 /* SwifternalizationTests.swift */; }; @@ -134,6 +136,7 @@ /* Begin PBXFileReference section */ 6D140F431B56D03D00359143 /* RandomNumbers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomNumbers.swift; sourceTree = ""; }; + 6D4C4EAE1B6AA48F00B7839A /* LoadedTranslation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadedTranslation.swift; sourceTree = ""; }; 6D5004481B3EF91600A54B36 /* Swifternalization.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swifternalization.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6D50044C1B3EF91600A54B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6D50044D1B3EF91600A54B36 /* Swifternalization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Swifternalization.h; sourceTree = ""; }; @@ -473,6 +476,7 @@ 6DB3CC671B5EBDA600A1220F /* SharedExpressionLoader.swift */, 6DB3CC691B5EBDA600A1220F /* JSONFileLoader.swift */, 6DB3CC731B5EBDA600A1220F /* TranslationsLoader.swift */, + 6D4C4EAE1B6AA48F00B7839A /* LoadedTranslation.swift */, ); name = Loaders; sourceTree = ""; @@ -654,6 +658,7 @@ 6DB3CC761B5EBDA600A1220F /* ExpressionRepresentationType.swift in Sources */, 6DB3CC7C1B5EBDA600A1220F /* Processable.swift in Sources */, 6DB3CC751B5EBDA600A1220F /* CountryCode.swift in Sources */, + 6D4C4EAF1B6AA48F00B7839A /* LoadedTranslation.swift in Sources */, 6D5BA6001B6526F0000D7E49 /* SharedExpression.swift in Sources */, 6D62829F1B3F1FA000E65FCD /* InequalityExpressionParser.swift in Sources */, 6D6282A51B3F24A800E65FCD /* ExpressionParser.swift in Sources */, @@ -708,6 +713,7 @@ 6D5BA5F21B6517FE000D7E49 /* TranslationType.swift in Sources */, 6DBB6C6A1B40412D002F39A3 /* InternalPattern.swift in Sources */, 6DD3B9411B5ED38B00C79EAC /* JSONFileLoaderTests.swift in Sources */, + 6D4C4EB01B6AA54800B7839A /* LoadedTranslation.swift in Sources */, 6DB3CC911B5EC29E00A1220F /* ExpressionType.swift in Sources */, 6D6282941B3F052B00E65FCD /* TranslatablePairTests.swift in Sources */, 6DBB6C941B40769F002F39A3 /* SharedPolishExpression.swift in Sources */, diff --git a/Swifternalization/LoadedTranslation.swift b/Swifternalization/LoadedTranslation.swift new file mode 100644 index 0000000..10e911f --- /dev/null +++ b/Swifternalization/LoadedTranslation.swift @@ -0,0 +1,76 @@ +// +// LoadedTranslation.swift +// Swifternalization +// +// Created by Tomasz Szulc on 30/07/15. +// Copyright (c) 2015 Tomasz Szulc. All rights reserved. +// + +import Foundation + +/** +Specifies few types of available translation type. +*/ +enum LoadedTranslationType { + /** + Simple key-value pair. + + "welcome": "welcome" + */ + case Simple + + /** + Pair where value is a dictionary with expressions. + + "cars": { + "one": "1 car", + "ie:x=2": "2 cars", + "more": "%d cars" + } + */ + case WithExpressions + + /** + Pair where value is a dictionary with length variations. + + "forgot-password": { + "@100": "Forgot Password? Help.", + "@200": "Forgot Password? Get password Help.", + "@300": "Forgotten Your Password? Get password Help." + } + */ + case WithLengthVariations + + /** + Pair where value is dictionary that contains dictionary with expression and + length variations. + + "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" + } + } + */ + case WithExpressionsAndLengthVariations + + /// Not supported type. + case NotSupported +} + +/** +Struct that represents loaded translation. +*/ +struct LoadedTranslation { + /// A type of translation. + let type: LoadedTranslationType + + /// A content of translation just loaded from a file. + let content: Dictionary +} diff --git a/Swifternalization/TranslationsLoader.swift b/Swifternalization/TranslationsLoader.swift index 1ba08e0..2200a12 100644 --- a/Swifternalization/TranslationsLoader.swift +++ b/Swifternalization/TranslationsLoader.swift @@ -1,59 +1,29 @@ import Foundation -/** -Represents translations loader. -Class is looking for json file named as country code. -It parse such file. +/** +Class that loads translations from a file. */ final class TranslationsLoader: JSONFileLoader { - typealias DictWithStrings = Dictionary - typealias DictWithDicts = Dictionary - - enum ElementType { - case NotSupported - case TranslationWithLengthVariations - case TranslationWithLoadedExpressions - case TranslationWithLengthVariationsAndLoadedExpressions - } - /** - Method loads a file and parses it. + Loads content from file with name equal to passed country code in a bundle. :params: countryCode A country code. - - :return: translations parsed from the file. + :params: bundle A bundle when file is placed. + :return: `LoadedTranslation` objects from specified file. */ - class func loadTranslations(countryCode: CountryCode, bundle: NSBundle = NSBundle.mainBundle()) -> [TranslationType] { - var loadedTranslations = [TranslationType]() - let json = self.load(countryCode, bundle: bundle) - if json == nil { return [TranslationType]() } - - for (translationKey, value) in json! { - if let translationValue = value as? String { - loadedTranslations.append(TranslationSimple(key: translationKey, value: translationValue)) - } else { - let dictionary = value as! JSONDictionary - switch detectElementType(dictionary) { - case .TranslationWithLengthVariations: - let variations = parseLengthVariations(dictionary as! DictWithStrings) - loadedTranslations.append(TranslationLengthVariation(key: translationKey, variations: variations)) - - case .TranslationWithLoadedExpressions: - let expressions = parseExpressions(dictionary as! DictWithStrings) - loadedTranslations.append(ProcessableTranslationExpression(key: translationKey, loadedExpressions: expressions)) - - case .TranslationWithLengthVariationsAndLoadedExpressions: - var expressions = [ProcessableLengthVariationExpression]() - for (expressionIdentifier, lengthVariationsDict) in dictionary as! DictWithDicts { - let variations = parseLengthVariations(lengthVariationsDict) - expressions.append(ProcessableLengthVariationExpression(identifier: expressionIdentifier, variations: variations)) + class func loadTranslations(countryCode: CountryCode, bundle: NSBundle = NSBundle.mainBundle()) -> [LoadedTranslation] { + var loadedTranslations = [LoadedTranslation]() + if let json = self.load(countryCode, bundle: bundle) { + for (key, value) in json { + if value is String { + loadedTranslations.append(LoadedTranslation(type: .Simple, content: [key: value])) + } else { + let dictionary = value as! JSONDictionary + let type = detectElementType(dictionary) + if type != .NotSupported { + loadedTranslations.append(LoadedTranslation(type: type, content: dictionary)) } - loadedTranslations.append(ProcessableTranslationExpressionLengthVariationExpression(key: translationKey, expressions: expressions)) - - case .NotSupported: - // Do nothing - continue } } } @@ -61,43 +31,23 @@ final class TranslationsLoader: JSONFileLoader { return loadedTranslations } - private class func parseLengthVariations(dict: DictWithStrings) -> [LengthVariation] { - var variations = [LengthVariation]() - for (key, translationValue) in dict { - let numberValue = parseNumberFromLengthVariation(key) - variations.append(LengthVariation(length: numberValue, value: translationValue)) - } - return variations - } - - private class func parseExpressions(dict: DictWithStrings) -> [ProcessableExpressionSimple] { - var expressions = [ProcessableExpressionSimple]() - for (expressionKey, translationValue) in dict { - expressions.append(ProcessableExpressionSimple(identifier: expressionKey, value: translationValue)) - } - return expressions - } + /** + Analyzes passed dictionary and checks its content to match it to some translation type. - private class func detectElementType(element: JSONDictionary) -> ElementType { - - if element is DictWithStrings { - if let key = element.keys.first { - let toIndex = advance(key.startIndex, 1) - let firstCharacter = key.substringToIndex(toIndex) - if firstCharacter == "@" { - return .TranslationWithLengthVariations - } else { - return .TranslationWithLoadedExpressions - } - } + :params: element A dictionary that will be analyzed. + :returns: translation type of a dictionary. + */ + private class func detectElementType(element: JSONDictionary) -> LoadedTranslationType { + typealias DictWithStrings = Dictionary + typealias DictWithDicts = Dictionary + + if element is DictWithStrings, let key = element.keys.first { + let toIndex = advance(key.startIndex, 1) + return key.substringToIndex(toIndex) == "@" ? .WithLengthVariations : .WithExpressions } else if element is DictWithDicts { - return .TranslationWithLengthVariationsAndLoadedExpressions + return .WithExpressionsAndLengthVariations } return .NotSupported } - - private class func parseNumberFromLengthVariation(string: String) -> Int { - return (Regex.matchInString(string, pattern: "@(\\d+)", capturingGroupIdx: 1)! as NSString).integerValue - } }