diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b8405e..e66fa36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,9 @@ Due to the removal of legacy code, there are a few breaking changes in this new * Throw an error if a format string has mismatching types for the same placeholde position. [David Jennes](https://github.com/djbe) [#44](https://github.com/SwiftGen/SwiftGenKit/issues/44) +* Added support for multiple string tables. + [David Jennes](https://github.com/djbe) + [#41](https://github.com/SwiftGen/templates/issues/41) ### Internal Changes diff --git a/Sources/Parsers/StringsFileParser.swift b/Sources/Parsers/StringsFileParser.swift index c7ceaf7..97d99ae 100644 --- a/Sources/Parsers/StringsFileParser.swift +++ b/Sources/Parsers/StringsFileParser.swift @@ -8,12 +8,15 @@ import Foundation import PathKit public enum StringsFileParserError: Error, CustomStringConvertible { + case duplicateTable(name: String) case failureOnLoading(path: String) case invalidFormat case invalidPlaceholder(previous: StringsFileParser.PlaceholderType, new: StringsFileParser.PlaceholderType) public var description: String { switch self { + case .duplicateTable(let name): + return "Table \"\(name)\" already loaded, cannot add it again" case .failureOnLoading(let path): return "Failed to load a file at \"\(path)\"" case .invalidFormat: @@ -25,29 +28,28 @@ public enum StringsFileParserError: Error, CustomStringConvertible { } public final class StringsFileParser { - var entries = [Entry]() + var tables = [String: [Entry]]() public init() {} - public func addEntry(_ entry: Entry) { - entries.append(entry) - } - // Localizable.strings files are generally UTF16, not UTF8! public func parseFile(at path: Path) throws { + let name = path.lastComponentWithoutExtension + + guard tables[name] == nil else { + throw StringsFileParserError.duplicateTable(name: name) + } guard let data = try? path.read() else { throw StringsFileParserError.failureOnLoading(path: path.string) } - let plist = try PropertyListSerialization - .propertyList(from: data, format: nil) - + let plist = try PropertyListSerialization.propertyList(from: data, format: nil) guard let dict = plist as? [String: String] else { throw StringsFileParserError.invalidFormat } - for (key, translation) in dict { - addEntry(try Entry(key: key, translation: translation)) + tables[name] = try dict.map { key, translation in + try Entry(key: key, translation: translation) } } diff --git a/Sources/Stencil/StringsContext.swift b/Sources/Stencil/StringsContext.swift index 7103d27..8c53810 100644 --- a/Sources/Stencil/StringsContext.swift +++ b/Sources/Stencil/StringsContext.swift @@ -30,7 +30,6 @@ private extension String { */ extension StringsFileParser { public func stencilContext() -> [String: Any] { - let entryToStringMapper = { (entry: Entry, keyPath: [String]) -> [String: Any] in let levelName = entry.keyStructure.last ?? "" @@ -47,14 +46,15 @@ extension StringsFileParser { return result } - let structuredStrings = structure( - entries: entries, - usingMapper: entryToStringMapper - ) - let tables: [[String: Any]] = [[ - "name": "Localizable", - "levels": structuredStrings - ]] + let tables = self.tables.map { name, entries in + return [ + "name": name, + "levels": structure( + entries: entries, + usingMapper: entryToStringMapper + ) + ] + } return [ "tables": tables diff --git a/Tests/Resources b/Tests/Resources index 98e0692..ca34235 160000 --- a/Tests/Resources +++ b/Tests/Resources @@ -1 +1 @@ -Subproject commit 98e0692d445ec0d5047c9732d4e0421ff0f2ece0 +Subproject commit ca342357ada17ecb0fd9e8d00323cb97b469d918 diff --git a/Tests/SwiftGenKitTests/StringsTests.swift b/Tests/SwiftGenKitTests/StringsTests.swift index e5136fd..30734a2 100644 --- a/Tests/SwiftGenKitTests/StringsTests.swift +++ b/Tests/SwiftGenKitTests/StringsTests.swift @@ -52,4 +52,27 @@ class StringsTests: XCTestCase { let result = parser.stencilContext() XCTDiffContexts(result, expected: "structuredonly.plist", sub: .strings) } + + func testMultipleFiles() throws { + let parser = StringsFileParser() + try parser.parseFile(at: Fixtures.path(for: "Localizable.strings", sub: .strings)) + try parser.parseFile(at: Fixtures.path(for: "LocMultiline.strings", sub: .strings)) + + let result = parser.stencilContext() + XCTDiffContexts(result, expected: "multiple.plist", sub: .strings) + } + + func testMultipleFilesDuplicate() throws { + let parser = StringsFileParser() + try parser.parseFile(at: Fixtures.path(for: "Localizable.strings", sub: .strings)) + + do { + try parser.parseFile(at: Fixtures.path(for: "Localizable.strings", sub: .strings)) + XCTFail("Code did parse file successfully while it was expected to fail for duplicate file") + } catch StringsFileParserError.duplicateTable { + // That's the expected exception we want to happen + } catch let error { + XCTFail("Unexpected error occured while parsing: \(error)") + } + } }