diff --git a/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift b/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift index 633ec7a..485ef63 100644 --- a/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift +++ b/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift @@ -1,6 +1,6 @@ // // StringsFileGenerator.swift -// +// // // Created by Thibaut Schmitt on 04/01/2022. // @@ -9,28 +9,49 @@ import Foundation import ToolCore class StringsFileGenerator { - + // MARK: - Strings Files - + static func writeStringsFiles(sections: [Section], langs: [String], defaultLang: String, tags: [String], outputPath: String, - inputFilenameWithoutExt: String) { - var stringsFilesContent = [String: String]() - for lang in langs { - stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang, - defaultLang: defaultLang, - tags: tags, - sections: sections) - } - - // Write strings file content - langs.forEach { lang in - guard let fileContent = stringsFilesContent[lang] else { return } - - let stringsFilePath = "\(outputPath)/\(lang).lproj/\(inputFilenameWithoutExt).strings" + inputFilenameWithoutExt: String, + isXcString: Bool = false) { + + if !isXcString { + var stringsFilesContent = [String: String]() + for lang in langs { + stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang, + defaultLang: defaultLang, + tags: tags, + sections: sections) + } + + // Write strings file content + langs.forEach { lang in + guard let fileContent = stringsFilesContent[lang] else { return } + + let stringsFilePath = "\(outputPath)/\(lang).lproj/\(inputFilenameWithoutExt).strings" + let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath) + do { + try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8) + } catch let error { + let error = StringiumError.writeFile(error.localizedDescription, stringsFilePath) + print(error.description) + Stringium.exit(withError: error) + } + } + } else { + let fileContent: String = Self.generateXcStringsFileContent( + langs: langs, + defaultLang: defaultLang, + tags: tags, + sections: sections + ) + + let stringsFilePath = "\(outputPath)/Localizable.xcstrings" let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath) do { try fileContent.write(to: stringsFilePathURL, atomically: false, encoding: .utf8) @@ -41,7 +62,7 @@ class StringsFileGenerator { } } } - + static func generateStringsFileContent(lang: String, defaultLang: String, tags inputTags: [String], @@ -53,13 +74,13 @@ class StringsFileGenerator { * Language: \(lang) */\n """ - + sections.forEach { section in // Check that at least one string will be generated guard section.hasOneOrMoreMatchingTags(tags: inputTags) else { return // Go to next section } - + stringsFileContent += "\n/********** \(section.name) **********/\n\n" section.definitions.forEach { definition in var skipDefinition = false // Set to true if not matching tag @@ -69,16 +90,16 @@ class StringsFileGenerator { skipDefinition = true return nil } - + // If tags contains `noTranslationTag` => get default lang if definition.tags.contains(Stringium.noTranslationTag) { return definition.translations[defaultLang] } - + // Else: get specific lang return definition.translations[lang] }() - + if let translation = translationOpt { stringsFileContent += "\"\(definition.name)\" = \"\(translation)\";\n\n" } else if skipDefinition == false { @@ -88,12 +109,101 @@ class StringsFileGenerator { } } } - + return stringsFileContent } - + + // MARK: - XcStrings Generation + + static func generateXcStringsFileContent(langs: [String], + defaultLang: String, + tags inputTags: [String], + sections: [Section]) -> String { + let rootObject = generateRootObject(langs: langs, defaultLang: defaultLang, tags: inputTags, sections: sections) + let file = generateXcStringsFileContentFromRootObject(rootObject: rootObject) + + return file + } + + static func generateXcStringsFileContentFromRootObject(rootObject: Root) -> String { + do { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted] + + let json = try encoder.encode(rootObject) + + if let jsonString = String(data: json, encoding: .utf8) { + return jsonString + } + + } catch { + debugPrint("Failed to encode: \(error)") + } + + return "" + } + + static func generateRootObject(langs: [String], + defaultLang: String, + tags inputTags: [String], + sections: [Section]) -> Root { + + var xcStringDefinitionTab: [XCStringDefinition] = [] + + sections.forEach { section in + // Check that at least one string will be generated + guard section.hasOneOrMoreMatchingTags(tags: inputTags) else { + return // Go to next section + } + + section.definitions.forEach { definition in + var skipDefinition = false + + var localizationTab: [XCStringLocalization] = [] + + if definition.hasOneOrMoreMatchingTags(inputTags: inputTags) == false { + skipDefinition = true + } + + if !skipDefinition { + + for (lang, value) in definition.translations { + let localization = XCStringLocalization( + lang: lang, + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit(state: "translated", value: value) + ) + ) + + localizationTab.append(localization) + } + + let xcStringDefinition = XCStringDefinition( + title: definition.name, + content: XCStringDefinitionContent( + extractionState: "manual", + localizations: XCStringLocalizationContainer( + localizations: localizationTab + ) + ) + ) + + xcStringDefinitionTab.append(xcStringDefinition) + } + } + } + + let xcStringContainer = XCStringDefinitionContainer(strings: xcStringDefinitionTab) + + return Root( + sourceLanguage: defaultLang, + strings: xcStringContainer, + version: "1.0" + ) + } + // MARK: - Extension file - + static func writeExtensionFiles(sections: [Section], defaultLang lang: String, tags: [String], @@ -110,7 +220,7 @@ class StringsFileGenerator { inputFilename: inputFilename, extensionName: extensionName, extensionSuffix: extensionSuffix) - + // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) do { @@ -121,9 +231,9 @@ class StringsFileGenerator { Stringium.exit(withError: error) } } - + // MARK: - Extension content - + static func getExtensionContent(sections: [Section], defaultLang lang: String, tags: [String], @@ -139,31 +249,31 @@ class StringsFileGenerator { ] .joined(separator: "\n") } - + // MARK: - Extension part - + private static func getHeader(stringsFilename: String, extensionClassname: String) -> String { """ // Generated by ResgenSwift.Strings.\(Stringium.toolName) \(ResgenSwiftVersion) - + import UIKit - + fileprivate let kStringsFileName = "\(stringsFilename)" - + extension \(extensionClassname) { """ } - + private static func getEnumKey(sections: [Section], tags: [String], extensionClassname: String, extensionSuffix: String) -> String { var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n" - + // Enum sections.forEach { section in // Check that at least one string will be generated guard section.hasOneOrMoreMatchingTags(tags: tags) else { return // Go to next section } - + section.definitions.forEach { definition in guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { return // Go to next definition @@ -172,7 +282,7 @@ class StringsFileGenerator { enumDefinition += " case \(definition.name) = \"\(definition.name)\"\n" } } - + // KeyPath accessors enumDefinition += "\n" enumDefinition += " var keyPath: KeyPath<\(extensionClassname), String> {\n" @@ -182,7 +292,7 @@ class StringsFileGenerator { guard section.hasOneOrMoreMatchingTags(tags: tags) else { return // Go to next section } - + section.definitions.forEach { definition in guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { return // Go to next definition @@ -194,23 +304,23 @@ class StringsFileGenerator { enumDefinition += " }\n" // Switch enumDefinition += " }\n" // var keyPath enumDefinition += " }" // Enum - + return enumDefinition } - + private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String { sections.compactMap { section in // Check that at least one string will be generated guard section.hasOneOrMoreMatchingTags(tags: tags) else { return nil // Go to next section } - + var res = "\n // MARK: - \(section.name)\n" res += section.definitions.compactMap { definition in guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { return nil // Go to next definition } - + if staticVar { return "\n\(definition.getNSLocalizedStringStaticProperty(forLang: lang))" } @@ -221,11 +331,11 @@ class StringsFileGenerator { } .joined(separator: "\n") } - + private static func getFooter() -> String { """ } - + """ } } diff --git a/Sources/ResgenSwift/Strings/Model/XcString.swift b/Sources/ResgenSwift/Strings/Model/XcString.swift new file mode 100644 index 0000000..acee405 --- /dev/null +++ b/Sources/ResgenSwift/Strings/Model/XcString.swift @@ -0,0 +1,93 @@ +// +// XcString.swift +// +// +// Created by Quentin Bandera on 12/04/2024. +// + +import SwiftUI + +struct DynamicKey: CodingKey { + var intValue: Int? + init?(intValue: Int) { + self.intValue = intValue + self.stringValue = "\(intValue)" + } + + var stringValue: String + init?(stringValue: String) { + self.stringValue = stringValue + } +} + +struct Root: Codable, Equatable { + let sourceLanguage: String + let strings: XCStringDefinitionContainer + let version: String +} + +struct XCStringDefinitionContainer: Codable, Equatable { + let strings: [XCStringDefinition] + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: DynamicKey.self) + + for str in strings { + if let codingKey = DynamicKey(stringValue: str.title) { + try container.encode(str.content, forKey: codingKey) + } + } + } +} + +struct XCStringDefinition: Codable, Equatable { + let title: String // json key -> custom encoding methods + let content: XCStringDefinitionContent +} + +struct XCStringDefinitionContent: Codable, Equatable { + let extractionState: String + var localizations: XCStringLocalizationContainer + +} + +struct XCStringLocalizationContainer: Codable, Equatable { + let localizations: [XCStringLocalization] + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: DynamicKey.self) + + for loca in localizations { + if let codingKey = DynamicKey(stringValue: loca.lang) { + try container.encode(loca.content, forKey: codingKey) + } + } + } +} + +struct XCStringLocalization: Codable, Equatable { + let lang: String // json key -> custom encoding method + let content: XCStringLocalizationLangContent +} + +struct XCStringLocalizationLangContent: Codable, Equatable { + let stringUnit: DefaultStringUnit +} + +//enum VarationOrStringUnit: Encodable { +// case variations([Varation]) +// case stringUnit: (DefaultStringUnit) +// +// func encode(to encoder: any Encoder) throws { +// if let varations { +// +// } else if let { +// +// } +// } +//} + +struct DefaultStringUnit: Codable, Equatable { + let state: String + let value: String +} diff --git a/Sources/ResgenSwift/Strings/Stringium/Stringium.swift b/Sources/ResgenSwift/Strings/Stringium/Stringium.swift index 1e3897e..ad3db0a 100644 --- a/Sources/ResgenSwift/Strings/Stringium/Stringium.swift +++ b/Sources/ResgenSwift/Strings/Stringium/Stringium.swift @@ -48,8 +48,9 @@ struct Stringium: ParsableCommand { defaultLang: options.defaultLang, tags: options.tags, outputPath: options.stringsFileOutputPath, - inputFilenameWithoutExt: options.inputFilenameWithoutExt) - + inputFilenameWithoutExt: options.inputFilenameWithoutExt, + isXcString: options.isXcstring) + // Generate extension StringsFileGenerator.writeExtensionFiles(sections: sections, defaultLang: options.defaultLang, diff --git a/Sources/ResgenSwift/Strings/Stringium/StringiumOptions.swift b/Sources/ResgenSwift/Strings/Stringium/StringiumOptions.swift index 1fd1d53..63c2370 100644 --- a/Sources/ResgenSwift/Strings/Stringium/StringiumOptions.swift +++ b/Sources/ResgenSwift/Strings/Stringium/StringiumOptions.swift @@ -11,7 +11,10 @@ import ArgumentParser struct StringiumOptions: ParsableArguments { @Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation") var forceGeneration = false - + + @Flag(name: [.customShort("x"), .customLong("xcstrings")], help: "Generate xcstrings catalog") + var isXcstring = false + @Argument(help: "Input files where strings ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() }) var inputFile: String diff --git a/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift index 2456d44..eb55ee4 100644 --- a/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift +++ b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift @@ -1,6 +1,6 @@ // // StringsFileGeneratorTests.swift -// +// // // Created by Thibaut Schmitt on 06/09/2022. // @@ -12,7 +12,7 @@ import ToolCore @testable import ResgenSwift final class StringsFileGeneratorTests: XCTestCase { - + private func getDefinition(name: String, translations: [String: String], tags: [String], comment: String? = nil) -> Definition { let definition = Definition(name: name) definition.tags = tags @@ -36,7 +36,7 @@ final class StringsFileGeneratorTests: XCTestCase { "en": "Section One - Definition Two"], tags: ["ios","iosonly"]) ] - + let sectionTwo = Section(name: "section_two") sectionTwo.definitions = [ getDefinition(name: "s2_def_one", @@ -47,7 +47,7 @@ final class StringsFileGeneratorTests: XCTestCase { translations: ["fr": "Section Deux - Definition Deux"], tags: ["notranslation"]) ] - + // When let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(lang: "fr", defaultLang: "fr", @@ -57,7 +57,7 @@ final class StringsFileGeneratorTests: XCTestCase { defaultLang: "fr", tags: ["ios", "iosonly", "notranslation"], sections: [sectionOne, sectionTwo]) - + // Expect let expectFr = """ /** @@ -65,40 +65,40 @@ final class StringsFileGeneratorTests: XCTestCase { * Generated by ResgenSwift \(ResgenSwiftVersion) * Language: fr */ - + /********** section_one **********/ - + "s1_def_one" = "Section Un - Definition Un"; - + "s1_def_two" = "Section Un - Definition Deux"; - + /********** section_two **********/ - + "s2_def_one" = "Section Deux - Definition Un"; "s2_def_two" = "Section Deux - Definition Deux"; """ - + let expectEn = """ /** * Apple Strings File * Generated by ResgenSwift \(ResgenSwiftVersion) * Language: en */ - + /********** section_one **********/ - + "s1_def_one" = "Section One - Definition One"; - + "s1_def_two" = "Section One - Definition Two"; - + /********** section_two **********/ - + "s2_def_one" = "Section Two - Definition One"; "s2_def_two" = "Section Deux - Definition Deux"; """ - + XCTAssertEqual(stringsFileContentFr.adaptForXCTest(), expectFr.adaptForXCTest()) XCTAssertEqual(stringsFileContentEn.adaptForXCTest(), expectEn.adaptForXCTest()) } @@ -187,6 +187,268 @@ final class StringsFileGeneratorTests: XCTestCase { XCTAssertEqual(stringsFileContentEn.adaptForXCTest(), expectEn.adaptForXCTest()) } + // MARK: - XcString File Content + + func testGenerateXcStringsRootObject() { + // Given + let sectionOne = Section(name: "section_one") + sectionOne.definitions = [ + getDefinition(name: "s1_def_one", + translations: ["fr": "Section Un - Definition Un", + "en": "Section One - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s1_def_two", + translations: ["fr": "Section Un - Definition Deux", + "en": "Section One - Definition Two"], + tags: ["ios","iosonly"]) + ] + + let sectionTwo = Section(name: "section_two") + sectionTwo.definitions = [ + getDefinition(name: "s2_def_one", + translations: ["fr": "Section Deux - Definition Un", + "en": "Section Two - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s2_def_two", + translations: ["fr": "Section Deux - Definition Deux"], + tags: ["notranslation"]) + ] + + // When + let rootObject = StringsFileGenerator.generateRootObject( + langs: ["fr", "en"], + defaultLang: "en", + tags: ["ios", "iosonly", "notranslation"], + sections: [sectionOne, sectionTwo] + ) + + // [[section_one]] + // [s1_def_one] + // fr = Section Un - Definition Un + // en = Section One - Definition One + // tags = ios,iosonly + // comments = + // [s1_def_two] + // fr = Section Un - Definition Deux + // en = Section One - Definition Two + // tags = ios,iosonly + // comments = + // + // [[section_two] + // [s2_def_one] + // fr = Section Deux - Definition Un + // en = Section Two - Definition One + // tags = ios,iosonly + // comments = + // [s2_def_two] + // fr = Section Deux - Definition deux + // en = Section Two - Definition Two + // tags = ios,iosonly + // comments = + + // Expect + let expect = + Root( + sourceLanguage: "en", + strings: XCStringDefinitionContainer( + strings: [ + XCStringDefinition( + title: "s1_def_one", + content: XCStringDefinitionContent( + extractionState: "manual", + localizations: XCStringLocalizationContainer( + localizations: [ + XCStringLocalization( + lang: "en", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section One - Definition One" + ) + ) + ), + XCStringLocalization( + lang: "fr", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Un - Definition Un" + ) + ) + ) + ] + ) + ) + ), + XCStringDefinition( + title: "s1_def_two", + content: XCStringDefinitionContent( + extractionState: "manual", + localizations: XCStringLocalizationContainer( + localizations: [ + XCStringLocalization( + lang: "en", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section One - Definition Two" + ) + ) + ), + XCStringLocalization( + lang: "fr", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Un - Definition Deux" + ) + ) + ) + ] + ) + ) + ), + XCStringDefinition( + title: "s2_def_one", + content: XCStringDefinitionContent( + extractionState: "manual", + localizations: XCStringLocalizationContainer( + localizations: [ + XCStringLocalization( + lang: "en", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Two - Definition One" + ) + ) + ), + XCStringLocalization( + lang: "fr", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Two - Definition Un" + ) + ) + ) + ] + ) + ) + ), + XCStringDefinition( + title: "s2_def_two", + content: XCStringDefinitionContent( + extractionState: "manual", + localizations: XCStringLocalizationContainer( + localizations: [ + XCStringLocalization( + lang: "en", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Two - Definition Two" + ) + ) + ), + XCStringLocalization( + lang: "fr", + content: XCStringLocalizationLangContent( + stringUnit: DefaultStringUnit( + state: "translated", + value: "Section Deux - Definition Deux" + ) + ) + ) + ] + ) + ) + ) + ] + ), + version: "1.0" + ) + + // """ + // { + // "sourceLanguage" : "en", + // "strings" : { + // "s1_def_one" : { + // "extractionState" : "manual", + // "localizations" : { + // "en" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section One - Definition One" + // } + // }, + // "fr" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Un - Definition Un" + // } + // } + // } + // }, + // "s1_def_two" : { + // "extractionState" : "manual", + // "localizations" : { + // "en" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section One - Definition Two" + // } + // }, + // "fr" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Un - Definition Deux" + // } + // } + // } + // }, + // "s2_def_one" : { + // "extractionState" : "manual", + // "localizations" : { + // "en" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Two - Definition One" + // } + // }, + // "fr" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Deux - Definition Une" + // } + // } + // } + // }, + // "s2_def_two" : { + // "extractionState" : "manual", + // "localizations" : { + // "en" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Two - Definition Two" + // } + // }, + // "fr" : { + // "stringUnit" : { + // "state" : "translated", + // "value" : "Section Deux - Definition Deux" + // } + // } + // } + // } + // }, + // "version" : "1.0" + // } + // """ + + XCTAssertEqual(rootObject, expect) + } + // MARK: - Extension Content func testGeneratedExtensionContent() { // Given @@ -201,7 +463,7 @@ final class StringsFileGeneratorTests: XCTestCase { "en": "Section One - Definition Two"], tags: ["ios","iosonly"]) ] - + let sectionTwo = Section(name: "section_two") sectionTwo.definitions = [ getDefinition(name: "s2_def_one", @@ -212,7 +474,7 @@ final class StringsFileGeneratorTests: XCTestCase { translations: ["fr": "Section Deux - Definition Deux"], tags: ["notranslation"]) ] - + // When let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo], defaultLang: "fr", @@ -221,23 +483,23 @@ final class StringsFileGeneratorTests: XCTestCase { inputFilename: "myInputFilename", extensionName: "GenStrings", extensionSuffix: "strings") - + // Expect let expect = """ // Generated by ResgenSwift.Strings.Stringium \(ResgenSwiftVersion) - + import UIKit - + fileprivate let kStringsFileName = "myInputFilename" - + extension GenStrings { - + enum KeyStrings: String { case s1_def_one = "s1_def_one" case s1_def_two = "s1_def_two" case s2_def_one = "s2_def_one" case s2_def_two = "s2_def_two" - + var keyPath: KeyPath { switch self { case .s1_def_one: return \\GenStrings.s1_def_one @@ -247,9 +509,9 @@ final class StringsFileGeneratorTests: XCTestCase { } } } - + // MARK: - section_one - + /// Translation in fr : /// Section Un - Definition Un /// @@ -258,7 +520,7 @@ final class StringsFileGeneratorTests: XCTestCase { var s1_def_one: String { NSLocalizedString("s1_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Un", comment: "") } - + /// Translation in fr : /// Section Un - Definition Deux /// @@ -267,9 +529,9 @@ final class StringsFileGeneratorTests: XCTestCase { var s1_def_two: String { NSLocalizedString("s1_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Deux", comment: "") } - + // MARK: - section_two - + /// Translation in fr : /// Section Deux - Definition Un /// @@ -278,7 +540,7 @@ final class StringsFileGeneratorTests: XCTestCase { var s2_def_one: String { NSLocalizedString("s2_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Un", comment: "") } - + /// Translation in fr : /// Section Deux - Definition Deux /// @@ -289,7 +551,7 @@ final class StringsFileGeneratorTests: XCTestCase { } } """ - + if extensionContent != expect { print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) } @@ -422,7 +684,7 @@ final class StringsFileGeneratorTests: XCTestCase { "en": "Section One - Definition Two"], tags: ["ios","iosonly"]) ] - + let sectionTwo = Section(name: "section_two") sectionTwo.definitions = [ getDefinition(name: "s2_def_one", @@ -433,7 +695,7 @@ final class StringsFileGeneratorTests: XCTestCase { translations: ["fr": "Section Deux - Definition Deux"], tags: ["notranslation"]) ] - + // When let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo], defaultLang: "fr", @@ -442,23 +704,23 @@ final class StringsFileGeneratorTests: XCTestCase { inputFilename: "myInputFilename", extensionName: "GenStrings", extensionSuffix: "strings") - + // Expect let expect = """ // Generated by ResgenSwift.Strings.Stringium \(ResgenSwiftVersion) - + import UIKit - + fileprivate let kStringsFileName = "myInputFilename" - + extension GenStrings { - + enum KeyStrings: String { case s1_def_one = "s1_def_one" case s1_def_two = "s1_def_two" case s2_def_one = "s2_def_one" case s2_def_two = "s2_def_two" - + var keyPath: KeyPath { switch self { case .s1_def_one: return \\GenStrings.s1_def_one @@ -468,9 +730,9 @@ final class StringsFileGeneratorTests: XCTestCase { } } } - + // MARK: - section_one - + /// Translation in fr : /// Section Un - Definition Un /// @@ -479,7 +741,7 @@ final class StringsFileGeneratorTests: XCTestCase { static var s1_def_one: String { NSLocalizedString("s1_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Un", comment: "") } - + /// Translation in fr : /// Section Un - Definition Deux /// @@ -488,9 +750,9 @@ final class StringsFileGeneratorTests: XCTestCase { static var s1_def_two: String { NSLocalizedString("s1_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Deux", comment: "") } - + // MARK: - section_two - + /// Translation in fr : /// Section Deux - Definition Un /// @@ -499,7 +761,7 @@ final class StringsFileGeneratorTests: XCTestCase { static var s2_def_one: String { NSLocalizedString("s2_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Un", comment: "") } - + /// Translation in fr : /// Section Deux - Definition Deux /// @@ -510,7 +772,7 @@ final class StringsFileGeneratorTests: XCTestCase { } } """ - + if extensionContent != expect { print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) }