Compare commits

...

13 Commits

Author SHA1 Message Date
129eb135f1 DEVTOOLS-185 Remplacer le json en dur des images resgen
Some checks are pending
gitea-openium/resgen.swift/pipeline/pr-master Build started...
2024-04-19 17:02:00 +02:00
4ad15fcded Merge pull request 'xcstrings' (#10) from xcstrings into master
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #10
Reviewed-by: Thibaut Schmitt <t.schmitt@openium.fr>
2024-04-19 16:59:03 +02:00
fb2ddb2227 DEVTOOLS-181 Gérer le tag noTranslation pour les xcstrings 2024-04-17 09:44:09 +02:00
27f86f5c4d Correction de l'option pour le fichier xcstrings 2024-04-15 16:51:18 +02:00
209ba49e3f Gestion des commentaires 2024-04-12 17:15:15 +02:00
ba07005b13 Fix equatable properties for arrays 2024-04-12 16:45:09 +02:00
6c3f3a8982 Correction du test testGenerateXcStringsRootObject 2024-04-12 16:25:10 +02:00
0d651b810f Première implémentation des xcstrings 2024-04-12 16:09:54 +02:00
1d7fc76340 Changed the condition for moe visibility 2024-04-11 15:49:07 +02:00
5d4e461933 Affichage du commentaire même si nil ou empty 2024-04-11 14:20:54 +02:00
55264d61ad Modification de l'affichage des commentaires
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-04-11 11:18:57 +02:00
d21ad9d1ea Update JenkinsFile Xcode version
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-04-11 10:19:10 +02:00
0bd6c3c2d4 Correction des commentaires des strings
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-04-11 10:16:28 +02:00
18 changed files with 2090 additions and 193 deletions

2
Jenkinsfile vendored
View File

@ -1,6 +1,6 @@
library "openiumpipeline" library "openiumpipeline"
env.DEVELOPER_DIR="/Applications/Xcode-15.0.1.app/Contents/Developer" env.DEVELOPER_DIR="/Applications/Xcode-15.3.0.app/Contents/Developer"
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-" //env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
env.IS_PACKAGE_SWIFT=1 env.IS_PACKAGE_SWIFT=1
env.TARGETS_MACOS=1 env.TARGETS_MACOS=1

View File

@ -14,8 +14,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git", "location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : { "state" : {
"revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e", "revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
"version" : "1.8.0" "version" : "1.8.2"
} }
}, },
{ {

View File

@ -9,7 +9,7 @@ import Foundation
enum GenerateError: Error { enum GenerateError: Error {
case fileNotExists(String) case fileNotExists(String)
case invalidConfigurationFile(String) case invalidConfigurationFile(String, String)
case commandError([String], String) case commandError([String], String)
case writeFile(String, String) case writeFile(String, String)
@ -18,8 +18,8 @@ enum GenerateError: Error {
case .fileNotExists(let filename): case .fileNotExists(let filename):
return "error: [\(Generate.toolName)] File \(filename) does not exists" return "error: [\(Generate.toolName)] File \(filename) does not exists"
case .invalidConfigurationFile(let filename): case .invalidConfigurationFile(let filename, let underneathErrorDescription):
return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file" return "error: [\(Generate.toolName)] File \(filename) is not a valid configuration file. Underneath error: \(underneathErrorDescription)"
case .commandError(let command, let terminationStatus): case .commandError(let command, let terminationStatus):
let readableCommand = command let readableCommand = command

View File

@ -269,14 +269,22 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
let extensionName: String? let extensionName: String?
let extensionSuffix: String? let extensionSuffix: String?
private let staticMembers: Bool? private let staticMembers: Bool?
private let xcStrings: Bool?
var staticMembersOptions: Bool { var staticMembersOptions: Bool {
if let staticMembers = staticMembers { if let staticMembers = staticMembers {
return staticMembers return staticMembers
} }
return false return false
} }
var xcStringsOptions: Bool {
if let xcStrings = xcStrings {
return xcStrings
}
return false
}
internal init(inputFile: String, internal init(inputFile: String,
outputPath: String, outputPath: String,
langs: String, langs: String,
@ -284,7 +292,8 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
extensionOutputPath: String, extensionOutputPath: String,
extensionName: String?, extensionName: String?,
extensionSuffix: String?, extensionSuffix: String?,
staticMembers: Bool?) { staticMembers: Bool?,
xcStrings: Bool?) {
self.inputFile = inputFile self.inputFile = inputFile
self.outputPath = outputPath self.outputPath = outputPath
self.langs = langs self.langs = langs
@ -293,6 +302,7 @@ struct StringsConfiguration: Codable, CustomDebugStringConvertible {
self.extensionName = extensionName self.extensionName = extensionName
self.extensionSuffix = extensionSuffix self.extensionSuffix = extensionSuffix
self.staticMembers = staticMembers self.staticMembers = staticMembers
self.xcStrings = xcStrings
} }
var debugDescription: String { var debugDescription: String {

View File

@ -16,12 +16,15 @@ class ConfigurationFileParser {
Generate.exit(withError: error) Generate.exit(withError: error)
} }
guard let configuration = try? YAMLDecoder().decode(ConfigurationFile.self, from: data) else { do {
let error = GenerateError.invalidConfigurationFile(configurationFile) return try YAMLDecoder().decode(ConfigurationFile.self, from: data)
} catch {
let error = GenerateError.invalidConfigurationFile(
configurationFile,
error.localizedDescription.description
)
print(error.description) print(error.description)
Generate.exit(withError: error) Generate.exit(withError: error)
} }
return configuration
} }
} }

View File

@ -14,7 +14,7 @@ extension StringsConfiguration: Runnable {
if force { if force {
args += ["-f"] args += ["-f"]
} }
args += [ args += [
inputFile.prependIfRelativePath(projectDirectory), inputFile.prependIfRelativePath(projectDirectory),
"--output-path", "--output-path",
@ -26,7 +26,9 @@ extension StringsConfiguration: Runnable {
"--extension-output-path", "--extension-output-path",
extensionOutputPath.prependIfRelativePath(projectDirectory), extensionOutputPath.prependIfRelativePath(projectDirectory),
"--static-members", "--static-members",
"\(staticMembersOptions)" "\(staticMembersOptions)",
"--xc-strings",
"\(xcStringsOptions)"
] ]
if let extensionName = extensionName { if let extensionName = extensionName {

View File

@ -119,7 +119,7 @@ class XcassetsGenerator {
} }
// Write Content.json // Write Content.json
let imagesetContentJson = parsedImage.contentJson guard let imagesetContentJson = parsedImage.contentJson else { return }
let contentJsonFilePath = "\(imagesetPath)/Contents.json" let contentJsonFilePath = "\(imagesetPath)/Contents.json"
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath) let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)

View File

@ -0,0 +1,32 @@
//
// ImageContent.swift
//
//
// Created by Quentin Bandera on 19/04/2024.
//
import Foundation
struct AssetContent: Codable, Equatable {
let images: [AssetImageDescription]
let info: AssetInfo
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
guard lhs.images.count == rhs.images.count else { return false }
let lhsImages = lhs.images.sorted(by: { $0.scale < $1.scale })
let rhsImages = rhs.images.sorted(by: { $0.scale < $1.scale })
return lhsImages == rhsImages
}
}
struct AssetImageDescription: Codable, Equatable {
let idiom: String
let scale: String
let filename: String
}
struct AssetInfo: Codable, Equatable {
let version: Int
let author: String
}

View File

@ -42,34 +42,45 @@ struct ParsedImage {
// MARK: - Assets // MARK: - Assets
var contentJson: String { var contentJson: String? {
""" let encoder = JSONEncoder()
{ encoder.outputFormatting = .prettyPrinted
"images" : [
{ guard let data = try? encoder.encode(imageContent) else {
"idiom" : "universal", let error = ImagesError.writeFile("Contents.json", "Error encoding json file")
"scale" : "1x", print(error.description)
"filename" : "\(name).\(XcassetsGenerator.outputImageExtension)" Images.exit(withError: error)
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
}
} }
"""
return String(data: data, encoding: .utf8)
} }
var imageContent: AssetContent {
return AssetContent(
images: [
AssetImageDescription(
idiom: "universal",
scale: "1x",
filename: "\(name).\(XcassetsGenerator.outputImageExtension)"
),
AssetImageDescription(
idiom: "universal",
scale: "2x",
filename: "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
),
AssetImageDescription(
idiom: "universal",
scale: "3x",
filename: "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
)
],
info: AssetInfo(
version: 1,
author: "ResgenSwift-Imagium"
)
)
}
// MARK: - Extension property // MARK: - Extension property
func getImageProperty(isStatic: Bool, isSwiftUI: Bool) -> String { func getImageProperty(isStatic: Bool, isSwiftUI: Bool) -> String {

View File

@ -1,6 +1,6 @@
// //
// StringsFileGenerator.swift // StringsFileGenerator.swift
// //
// //
// Created by Thibaut Schmitt on 04/01/2022. // Created by Thibaut Schmitt on 04/01/2022.
// //
@ -9,15 +9,16 @@ import Foundation
import ToolCore import ToolCore
class StringsFileGenerator { class StringsFileGenerator {
// MARK: - Strings Files // MARK: - Strings Files
static func writeStringsFiles(sections: [Section], static func writeStringsFiles(sections: [Section],
langs: [String], langs: [String],
defaultLang: String, defaultLang: String,
tags: [String], tags: [String],
outputPath: String, outputPath: String,
inputFilenameWithoutExt: String) { inputFilenameWithoutExt: String) {
var stringsFilesContent = [String: String]() var stringsFilesContent = [String: String]()
for lang in langs { for lang in langs {
stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang, stringsFilesContent[lang] = Self.generateStringsFileContent(lang: lang,
@ -25,11 +26,11 @@ class StringsFileGenerator {
tags: tags, tags: tags,
sections: sections) sections: sections)
} }
// Write strings file content // Write strings file content
langs.forEach { lang in langs.forEach { lang in
guard let fileContent = stringsFilesContent[lang] else { return } guard let fileContent = stringsFilesContent[lang] else { return }
let stringsFilePath = "\(outputPath)/\(lang).lproj/\(inputFilenameWithoutExt).strings" let stringsFilePath = "\(outputPath)/\(lang).lproj/\(inputFilenameWithoutExt).strings"
let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath) let stringsFilePathURL = URL(fileURLWithPath: stringsFilePath)
do { do {
@ -41,7 +42,32 @@ class StringsFileGenerator {
} }
} }
} }
static func writeXcStringsFiles(sections: [Section],
langs: [String],
defaultLang: String,
tags: [String],
outputPath: String,
inputFilenameWithoutExt: String) {
let fileContent: String = Self.generateXcStringsFileContent(
langs: langs,
defaultLang: defaultLang,
tags: tags,
sections: sections
)
let stringsFilePath = "\(outputPath)/\(inputFilenameWithoutExt).xcstrings"
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)
}
}
static func generateStringsFileContent(lang: String, static func generateStringsFileContent(lang: String,
defaultLang: String, defaultLang: String,
tags inputTags: [String], tags inputTags: [String],
@ -53,13 +79,13 @@ class StringsFileGenerator {
* Language: \(lang) * Language: \(lang)
*/\n */\n
""" """
sections.forEach { section in sections.forEach { section in
// Check that at least one string will be generated // Check that at least one string will be generated
guard section.hasOneOrMoreMatchingTags(tags: inputTags) else { guard section.hasOneOrMoreMatchingTags(tags: inputTags) else {
return // Go to next section return // Go to next section
} }
stringsFileContent += "\n/********** \(section.name) **********/\n\n" stringsFileContent += "\n/********** \(section.name) **********/\n\n"
section.definitions.forEach { definition in section.definitions.forEach { definition in
var skipDefinition = false // Set to true if not matching tag var skipDefinition = false // Set to true if not matching tag
@ -69,16 +95,16 @@ class StringsFileGenerator {
skipDefinition = true skipDefinition = true
return nil return nil
} }
// If tags contains `noTranslationTag` => get default lang // If tags contains `noTranslationTag` => get default lang
if definition.tags.contains(Stringium.noTranslationTag) { if definition.tags.contains(Stringium.noTranslationTag) {
return definition.translations[defaultLang] return definition.translations[defaultLang]
} }
// Else: get specific lang // Else: get specific lang
return definition.translations[lang] return definition.translations[lang]
}() }()
if let translation = translationOpt { if let translation = translationOpt {
stringsFileContent += "\"\(definition.name)\" = \"\(translation)\";\n\n" stringsFileContent += "\"\(definition.name)\" = \"\(translation)\";\n\n"
} else if skipDefinition == false { } else if skipDefinition == false {
@ -88,12 +114,123 @@ class StringsFileGenerator {
} }
} }
} }
return stringsFileContent 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 isNoTranslation = false
var localizationTab: [XCStringLocalization] = []
if definition.hasOneOrMoreMatchingTags(inputTags: inputTags) == false {
skipDefinition = true
}
if definition.tags.contains(Stringium.noTranslationTag) {
isNoTranslation = true
}
if !skipDefinition {
if isNoTranslation {
// Search for langs in yaml
for lang in langs {
if let value = definition.translations[defaultLang], !value.isEmpty {
let localization = XCStringLocalization(
lang: lang,
content: XCStringLocalizationLangContent(
stringUnit: DefaultStringUnit(state: "translated", value: value)
)
)
localizationTab.append(localization)
}
}
} else {
// Search for langs in twine
for (lang, value) in definition.translations where !value.isEmpty {
let localization = XCStringLocalization(
lang: lang,
content: XCStringLocalizationLangContent(
stringUnit: DefaultStringUnit(state: "translated", value: value)
)
)
localizationTab.append(localization)
}
}
let xcStringDefinition = XCStringDefinition(
title: definition.name,
content: XCStringDefinitionContent(
comment: definition.comment,
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 // MARK: - Extension file
static func writeExtensionFiles(sections: [Section], static func writeExtensionFiles(sections: [Section],
defaultLang lang: String, defaultLang lang: String,
tags: [String], tags: [String],
@ -110,7 +247,7 @@ class StringsFileGenerator {
inputFilename: inputFilename, inputFilename: inputFilename,
extensionName: extensionName, extensionName: extensionName,
extensionSuffix: extensionSuffix) extensionSuffix: extensionSuffix)
// Write content // Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
do { do {
@ -121,9 +258,9 @@ class StringsFileGenerator {
Stringium.exit(withError: error) Stringium.exit(withError: error)
} }
} }
// MARK: - Extension content // MARK: - Extension content
static func getExtensionContent(sections: [Section], static func getExtensionContent(sections: [Section],
defaultLang lang: String, defaultLang lang: String,
tags: [String], tags: [String],
@ -139,31 +276,31 @@ class StringsFileGenerator {
] ]
.joined(separator: "\n") .joined(separator: "\n")
} }
// MARK: - Extension part // MARK: - Extension part
private static func getHeader(stringsFilename: String, extensionClassname: String) -> String { private static func getHeader(stringsFilename: String, extensionClassname: String) -> String {
""" """
// Generated by ResgenSwift.Strings.\(Stringium.toolName) \(ResgenSwiftVersion) // Generated by ResgenSwift.Strings.\(Stringium.toolName) \(ResgenSwiftVersion)
import UIKit import UIKit
fileprivate let kStringsFileName = "\(stringsFilename)" fileprivate let kStringsFileName = "\(stringsFilename)"
extension \(extensionClassname) { extension \(extensionClassname) {
""" """
} }
private static func getEnumKey(sections: [Section], tags: [String], extensionClassname: String, extensionSuffix: String) -> String { private static func getEnumKey(sections: [Section], tags: [String], extensionClassname: String, extensionSuffix: String) -> String {
var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n" var enumDefinition = "\n enum Key\(extensionSuffix.uppercasedFirst()): String {\n"
// Enum // Enum
sections.forEach { section in sections.forEach { section in
// Check that at least one string will be generated // Check that at least one string will be generated
guard section.hasOneOrMoreMatchingTags(tags: tags) else { guard section.hasOneOrMoreMatchingTags(tags: tags) else {
return // Go to next section return // Go to next section
} }
section.definitions.forEach { definition in section.definitions.forEach { definition in
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
return // Go to next definition return // Go to next definition
@ -172,7 +309,7 @@ class StringsFileGenerator {
enumDefinition += " case \(definition.name) = \"\(definition.name)\"\n" enumDefinition += " case \(definition.name) = \"\(definition.name)\"\n"
} }
} }
// KeyPath accessors // KeyPath accessors
enumDefinition += "\n" enumDefinition += "\n"
enumDefinition += " var keyPath: KeyPath<\(extensionClassname), String> {\n" enumDefinition += " var keyPath: KeyPath<\(extensionClassname), String> {\n"
@ -182,7 +319,7 @@ class StringsFileGenerator {
guard section.hasOneOrMoreMatchingTags(tags: tags) else { guard section.hasOneOrMoreMatchingTags(tags: tags) else {
return // Go to next section return // Go to next section
} }
section.definitions.forEach { definition in section.definitions.forEach { definition in
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
return // Go to next definition return // Go to next definition
@ -194,23 +331,23 @@ class StringsFileGenerator {
enumDefinition += " }\n" // Switch enumDefinition += " }\n" // Switch
enumDefinition += " }\n" // var keyPath enumDefinition += " }\n" // var keyPath
enumDefinition += " }" // Enum enumDefinition += " }" // Enum
return enumDefinition return enumDefinition
} }
private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String { private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String {
sections.compactMap { section in sections.compactMap { section in
// Check that at least one string will be generated // Check that at least one string will be generated
guard section.hasOneOrMoreMatchingTags(tags: tags) else { guard section.hasOneOrMoreMatchingTags(tags: tags) else {
return nil // Go to next section return nil // Go to next section
} }
var res = "\n // MARK: - \(section.name)\n" var res = "\n // MARK: - \(section.name)\n"
res += section.definitions.compactMap { definition in res += section.definitions.compactMap { definition in
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
return nil // Go to next definition return nil // Go to next definition
} }
if staticVar { if staticVar {
return "\n\(definition.getNSLocalizedStringStaticProperty(forLang: lang))" return "\n\(definition.getNSLocalizedStringStaticProperty(forLang: lang))"
} }
@ -221,11 +358,11 @@ class StringsFileGenerator {
} }
.joined(separator: "\n") .joined(separator: "\n")
} }
private static func getFooter() -> String { private static func getFooter() -> String {
""" """
} }
""" """
} }
} }

View File

@ -84,22 +84,29 @@ class Definition {
return (inputParameters: inputParameters, translationArguments: translationArguments) return (inputParameters: inputParameters, translationArguments: translationArguments)
} }
private func getBaseProperty(lang: String, translation: String, isStatic: Bool) -> String { private func getBaseProperty(lang: String, translation: String, isStatic: Bool, comment: String?) -> String {
""" """
/// Translation in \(lang) : /// Translation in \(lang) :
/// \(translation) /// \(translation)
///
/// Comment :
/// \(comment?.isEmpty == false ? comment! : "No comment")
\(isStatic ? "static ": "")var \(name): String { \(isStatic ? "static ": "")var \(name): String {
NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "") NSLocalizedString("\(name)", tableName: kStringsFileName, bundle: Bundle.main, value: "\(translation)", comment: "\(comment ?? "")")
} }
""" """
} }
private func getBaseMethod(lang: String, translation: String, isStatic: Bool, inputParameters: [String], translationArguments: [String]) -> String { private func getBaseMethod(lang: String, translation: String, isStatic: Bool, inputParameters: [String], translationArguments: [String], comment: String?) -> String {
""" """
/// Translation in \(lang) : /// Translation in \(lang) :
/// \(translation) /// \(translation)
///
/// Comment :
/// \(comment?.isEmpty == false ? comment! : "No comment")
\(isStatic ? "static ": "")func \(name)(\(inputParameters.joined(separator: ", "))) -> String { \(isStatic ? "static ": "")func \(name)(\(inputParameters.joined(separator: ", "))) -> String {
String(format: \(isStatic ? "Self" : "self").\(name), \(translationArguments.joined(separator: ", "))) String(format: \(isStatic ? "Self" : "self").\(name), \(translationArguments.joined(separator: ", ")))
} }
@ -114,8 +121,13 @@ class Definition {
} }
// Generate property // Generate property
let property = getBaseProperty(lang: lang, translation: translation, isStatic: false) let property = getBaseProperty(
lang: lang,
translation: translation,
isStatic: false,
comment: self.comment
)
// Generate method // Generate method
var method = "" var method = ""
if let parameters = self.getStringParameters(input: translation) { if let parameters = self.getStringParameters(input: translation) {
@ -123,7 +135,8 @@ class Definition {
translation: translation, translation: translation,
isStatic: false, isStatic: false,
inputParameters: parameters.inputParameters, inputParameters: parameters.inputParameters,
translationArguments: parameters.translationArguments) translationArguments: parameters.translationArguments,
comment: self.comment)
} }
return property + method return property + method
@ -137,7 +150,12 @@ class Definition {
} }
// Generate property // Generate property
let property = getBaseProperty(lang: lang, translation: translation, isStatic: true) let property = getBaseProperty(
lang: lang,
translation: translation,
isStatic: true,
comment: self.comment
)
// Generate method // Generate method
var method = "" var method = ""
@ -146,7 +164,8 @@ class Definition {
translation: translation, translation: translation,
isStatic: true, isStatic: true,
inputParameters: parameters.inputParameters, inputParameters: parameters.inputParameters,
translationArguments: parameters.translationArguments) translationArguments: parameters.translationArguments,
comment: self.comment)
} }
return property + method return property + method
@ -160,10 +179,14 @@ class Definition {
print(error.description) print(error.description)
Stringium.exit(withError: error) Stringium.exit(withError: error)
} }
return """ return """
/// Translation in \(lang) : /// Translation in \(lang) :
/// \(translation) /// \(translation)
///
/// Comment :
/// \(comment?.isEmpty == false ? comment! : "No comment")
var \(name): String { var \(name): String {
"\(translation)" "\(translation)"
} }
@ -180,6 +203,9 @@ class Definition {
return """ return """
/// Translation in \(lang) : /// Translation in \(lang) :
/// \(translation) /// \(translation)
///
/// Comment :
/// \(comment?.isEmpty == false ? comment! : "No comment")
static var \(name): String { static var \(name): String {
"\(translation)" "\(translation)"
} }

View File

@ -0,0 +1,109 @@
//
// 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)
}
}
}
static func == (lhs: XCStringDefinitionContainer, rhs: XCStringDefinitionContainer) -> Bool {
return lhs.strings.sorted(by: {
$0.title < $1.title
}) == rhs.strings.sorted(by: { $0.title < $1.title })
}
}
struct XCStringDefinition: Codable, Equatable {
let title: String // json key -> custom encoding methods
let content: XCStringDefinitionContent
}
struct XCStringDefinitionContent: Codable, Equatable {
let comment: String?
let extractionState: String
var localizations: XCStringLocalizationContainer
init(comment: String? = nil, extractionState: String, localizations: XCStringLocalizationContainer) {
self.comment = comment
self.extractionState = extractionState
self.localizations = localizations
}
}
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)
}
}
}
static func == (lhs: XCStringLocalizationContainer, rhs: XCStringLocalizationContainer) -> Bool {
return lhs.localizations.count == rhs.localizations.count && lhs.localizations.sorted(by: { $0.lang < $1.lang }) == rhs.localizations.sorted(by: { $0.lang < $1.lang })
}
}
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
}

View File

@ -43,13 +43,26 @@ struct Stringium: ParsableCommand {
let sections = TwineFileParser.parse(options.inputFile) let sections = TwineFileParser.parse(options.inputFile)
// Generate strings files // Generate strings files
StringsFileGenerator.writeStringsFiles(sections: sections, print(options.xcStrings)
langs: options.langs, if !options.xcStrings {
defaultLang: options.defaultLang, print("[\(Self.toolName)] Will generate strings")
tags: options.tags,
outputPath: options.stringsFileOutputPath, StringsFileGenerator.writeStringsFiles(sections: sections,
inputFilenameWithoutExt: options.inputFilenameWithoutExt) langs: options.langs,
defaultLang: options.defaultLang,
tags: options.tags,
outputPath: options.stringsFileOutputPath,
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
} else {
print("[\(Self.toolName)] Will generate xcStrings")
StringsFileGenerator.writeXcStringsFiles(sections: sections,
langs: options.langs,
defaultLang: options.defaultLang,
tags: options.tags,
outputPath: options.stringsFileOutputPath,
inputFilenameWithoutExt: options.inputFilenameWithoutExt)
}
// Generate extension // Generate extension
StringsFileGenerator.writeExtensionFiles(sections: sections, StringsFileGenerator.writeExtensionFiles(sections: sections,
defaultLang: options.defaultLang, defaultLang: options.defaultLang,
@ -59,7 +72,7 @@ struct Stringium: ParsableCommand {
extensionName: options.extensionName, extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath, extensionFilePath: options.extensionFilePath,
extensionSuffix: options.extensionSuffix) extensionSuffix: options.extensionSuffix)
print("[\(Self.toolName)] Strings generated") print("[\(Self.toolName)] Strings generated")
} }

View File

@ -11,8 +11,8 @@ import ArgumentParser
struct StringiumOptions: ParsableArguments { struct StringiumOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation") @Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false var forceGeneration = false
@Argument(help: "Input files where strings ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() }) @Argument(help: "Input files where strings are defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var inputFile: String var inputFile: String
@Option(name: .customLong("output-path"), help: "Path where to strings file.", transform: { $0.replaceTiltWithHomeDirectoryPath() }) @Option(name: .customLong("output-path"), help: "Path where to strings file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
@ -32,7 +32,10 @@ struct StringiumOptions: ParsableArguments {
@Option(help: "Tell if it will generate static properties or not") @Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false var staticMembers: Bool = false
@Option(help: "Tell if it will generate xcStrings file or not")
var xcStrings: Bool = false
@Option(help: "Extension name. If not specified, it will generate an String extension.") @Option(help: "Extension name. If not specified, it will generate an String extension.")
var extensionName: String = Stringium.defaultExtensionName var extensionName: String = Stringium.defaultExtensionName

View File

@ -91,7 +91,7 @@ final class ParsedColorTests: XCTestCase {
// When // When
let contentJson = color.contentsJSON() let contentJson = color.contentsJSON()
guard let data = contentJson.data(using: .utf8), guard let data = contentJson.data(using: .utf8),
let parsedJson = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { let parsedJson = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
XCTFail("Cannot convert `contentJSON` string to Data") XCTFail("Cannot convert `contentJSON` string to Data")
return return
} }

View File

@ -127,35 +127,33 @@ final class ParsedImageTests: XCTestCase {
height: 10) height: 10)
// When // When
let property = parsedImage.contentJson let property = parsedImage.imageContent
// Expect // Expect
let expect = """ let expect = AssetContent(
{ images: [
"images" : [ AssetImageDescription(
{ idiom: "universal",
"idiom" : "universal", scale: "1x",
"scale" : "1x", filename: "\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)"
"filename" : "\(imageName).\(XcassetsGenerator.outputImageExtension)" ),
}, AssetImageDescription(
{ idiom: "universal",
"idiom" : "universal", scale: "2x",
"scale" : "2x", filename: "\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)"
"filename" : "\(imageName)@2x.\(XcassetsGenerator.outputImageExtension)" ),
}, AssetImageDescription(
{ idiom: "universal",
"idiom" : "universal", scale: "3x",
"scale" : "3x", filename: "\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)"
"filename" : "\(imageName)@3x.\(XcassetsGenerator.outputImageExtension)" )
} ],
], info: AssetInfo(
"info" : { version: 1,
"version" : 1, author: "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium" )
} )
}
""" XCTAssertEqual(property, expect)
XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest())
} }
} }

View File

@ -100,24 +100,33 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// C'est la traduction francaise /// C'est la traduction francaise
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "This is a comment")
} }
""" """
let expectEn = """ let expectEn = """
/// Translation in en : /// Translation in en :
/// This is the english translation /// This is the english translation
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "This is a comment")
} }
""" """
let expectEnUs = """ let expectEnUs = """
/// Translation in en-us : /// Translation in en-us :
/// This is the english us translation /// This is the english us translation
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "This is a comment")
} }
""" """
@ -125,7 +134,118 @@ final class DefinitionTests: XCTestCase {
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
} }
func testGeneratedNSLocalizedStringPropertyWithEmptyComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.comment = ""
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr")
let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en")
let propertyEnUs = definition.getNSLocalizedStringProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
func testGeneratedNSLocalizedStringPropertyWithNoComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr")
let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en")
let propertyEnUs = definition.getNSLocalizedStringProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
// MARK: - getNSLocalizedStringStaticProperty
func testGeneratedNSLocalizedStringStaticProperty() { func testGeneratedNSLocalizedStringStaticProperty() {
// Given // Given
let definition = Definition(name: "definition_name") let definition = Definition(name: "definition_name")
@ -146,24 +266,33 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// C'est la traduction francaise /// C'est la traduction francaise
///
/// Comment :
/// This is a comment
static var definition_name: String { static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "This is a comment")
} }
""" """
let expectEn = """ let expectEn = """
/// Translation in en : /// Translation in en :
/// This is the english translation /// This is the english translation
///
/// Comment :
/// This is a comment
static var definition_name: String { static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "This is a comment")
} }
""" """
let expectEnUs = """ let expectEnUs = """
/// Translation in en-us : /// Translation in en-us :
/// This is the english us translation /// This is the english us translation
///
/// Comment :
/// This is a comment
static var definition_name: String { static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "This is a comment")
} }
""" """
@ -171,7 +300,116 @@ final class DefinitionTests: XCTestCase {
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
} }
func testGeneratedNSLocalizedStringStaticPropertyWithEmptyComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.comment = ""
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getNSLocalizedStringStaticProperty(forLang: "fr")
let propertyEn = definition.getNSLocalizedStringStaticProperty(forLang: "en")
let propertyEnUs = definition.getNSLocalizedStringStaticProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
func testGeneratedNSLocalizedStringStaticPropertyWithNoComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getNSLocalizedStringStaticProperty(forLang: "fr")
let propertyEn = definition.getNSLocalizedStringStaticProperty(forLang: "en")
let propertyEnUs = definition.getNSLocalizedStringStaticProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "")
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "")
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
static var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "")
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
func testGeneratedNSLocalizedStringPropertyWithOneArgument() { func testGeneratedNSLocalizedStringPropertyWithOneArgument() {
// Given // Given
let definition = Definition(name: "definition_name") let definition = Definition(name: "definition_name")
@ -188,17 +426,23 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// Welcome "%@" ! /// Welcome "%@" !
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "This is a comment")
} }
/// Translation in fr : /// Translation in fr :
/// Welcome "%@" ! /// Welcome "%@" !
///
/// Comment :
/// This is a comment
func definition_name(arg0: String) -> String { func definition_name(arg0: String) -> String {
String(format: self.definition_name, arg0) String(format: self.definition_name, arg0)
} }
""" """
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
} }
@ -218,12 +462,18 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// Welcome "%@" ! Your age is %d :) Your weight is %f ;-) /// Welcome "%@" ! Your age is %d :) Your weight is %f ;-)
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)", comment: "This is a comment")
} }
/// Translation in fr : /// Translation in fr :
/// Welcome "%@" ! Your age is %d :) Your weight is %f ;-) /// Welcome "%@" ! Your age is %d :) Your weight is %f ;-)
///
/// Comment :
/// This is a comment
func definition_name(arg0: String, arg1: Int, arg2: Double) -> String { func definition_name(arg0: String, arg1: Int, arg2: Double) -> String {
String(format: self.definition_name, arg0, arg1, arg2) String(format: self.definition_name, arg0, arg1, arg2)
} }
@ -249,12 +499,18 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// Vous %%: %1$@ %2$@ Age: %3$d /// Vous %%: %1$@ %2$@ Age: %3$d
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Vous %%: %1$@ %2$@ Age: %3$d", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Vous %%: %1$@ %2$@ Age: %3$d", comment: "This is a comment")
} }
/// Translation in fr : /// Translation in fr :
/// Vous %%: %1$@ %2$@ Age: %3$d /// Vous %%: %1$@ %2$@ Age: %3$d
///
/// Comment :
/// This is a comment
func definition_name(arg0: String, arg1: String, arg2: Int) -> String { func definition_name(arg0: String, arg1: String, arg2: Int) -> String {
String(format: self.definition_name, arg0, arg1, arg2) String(format: self.definition_name, arg0, arg1, arg2)
} }
@ -263,12 +519,18 @@ final class DefinitionTests: XCTestCase {
let expectEn = """ let expectEn = """
/// Translation in en : /// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d /// You %%: %2$@ %1$@ Age: %3$d
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "") NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "This is a comment")
} }
/// Translation in en : /// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d /// You %%: %2$@ %1$@ Age: %3$d
///
/// Comment :
/// This is a comment
func definition_name(arg0: String, arg1: String, arg2: Int) -> String { func definition_name(arg0: String, arg1: String, arg2: Int) -> String {
String(format: self.definition_name, arg0, arg1, arg2) String(format: self.definition_name, arg0, arg1, arg2)
} }
@ -300,6 +562,9 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// C'est la traduction francaise /// C'est la traduction francaise
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
"C'est la traduction francaise" "C'est la traduction francaise"
} }
@ -308,6 +573,9 @@ final class DefinitionTests: XCTestCase {
let expectEn = """ let expectEn = """
/// Translation in en : /// Translation in en :
/// This is the english translation /// This is the english translation
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
"This is the english translation" "This is the english translation"
} }
@ -316,6 +584,9 @@ final class DefinitionTests: XCTestCase {
let expectEnUs = """ let expectEnUs = """
/// Translation in en-us : /// Translation in en-us :
/// This is the english us translation /// This is the english us translation
///
/// Comment :
/// This is a comment
var definition_name: String { var definition_name: String {
"This is the english us translation" "This is the english us translation"
} }
@ -325,7 +596,118 @@ final class DefinitionTests: XCTestCase {
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
} }
func testGeneratedRawPropertyWithEmptyComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.comment = ""
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getProperty(forLang: "fr")
let propertyEn = definition.getProperty(forLang: "en")
let propertyEnUs = definition.getProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
var definition_name: String {
"C'est la traduction francaise"
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
var definition_name: String {
"This is the english translation"
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
var definition_name: String {
"This is the english us translation"
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
func testGeneratedRawPropertyWithNoComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getProperty(forLang: "fr")
let propertyEn = definition.getProperty(forLang: "en")
let propertyEnUs = definition.getProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
var definition_name: String {
"C'est la traduction francaise"
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
var definition_name: String {
"This is the english translation"
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
var definition_name: String {
"This is the english us translation"
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
// MARK: - Raw static properties
func testGeneratedRawStaticProperty() { func testGeneratedRawStaticProperty() {
// Given // Given
let definition = Definition(name: "definition_name") let definition = Definition(name: "definition_name")
@ -346,6 +728,9 @@ final class DefinitionTests: XCTestCase {
let expectFr = """ let expectFr = """
/// Translation in fr : /// Translation in fr :
/// C'est la traduction francaise /// C'est la traduction francaise
///
/// Comment :
/// This is a comment
static var definition_name: String { static var definition_name: String {
"C'est la traduction francaise" "C'est la traduction francaise"
} }
@ -354,7 +739,10 @@ final class DefinitionTests: XCTestCase {
let expectEn = """ let expectEn = """
/// Translation in en : /// Translation in en :
/// This is the english translation /// This is the english translation
static var definition_name: String { ///
/// Comment :
/// This is a comment
static var definition_name: String {
"This is the english translation" "This is the english translation"
} }
""" """
@ -362,6 +750,9 @@ final class DefinitionTests: XCTestCase {
let expectEnUs = """ let expectEnUs = """
/// Translation in en-us : /// Translation in en-us :
/// This is the english us translation /// This is the english us translation
///
/// Comment :
/// This is a comment
static var definition_name: String { static var definition_name: String {
"This is the english us translation" "This is the english us translation"
} }
@ -371,4 +762,113 @@ final class DefinitionTests: XCTestCase {
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
} }
func testGeneratedRawStaticPropertyWithEmptyComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.comment = ""
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getStaticProperty(forLang: "fr")
let propertyEn = definition.getStaticProperty(forLang: "en")
let propertyEnUs = definition.getStaticProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
static var definition_name: String {
"C'est la traduction francaise"
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
static var definition_name: String {
"This is the english translation"
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
static var definition_name: String {
"This is the english us translation"
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
func testGeneratedRawStaticPropertyWithNoComment() {
// Given
let definition = Definition(name: "definition_name")
definition.tags = ["ios","iosonly","notranslation"]
definition.translations = [
"fr": "C'est la traduction francaise",
"en": "This is the english translation",
"en-us": "This is the english us translation"
]
// When
let propertyFr = definition.getStaticProperty(forLang: "fr")
let propertyEn = definition.getStaticProperty(forLang: "en")
let propertyEnUs = definition.getStaticProperty(forLang: "en-us")
// Expect
let expectFr = """
/// Translation in fr :
/// C'est la traduction francaise
///
/// Comment :
/// No comment
static var definition_name: String {
"C'est la traduction francaise"
}
"""
let expectEn = """
/// Translation in en :
/// This is the english translation
///
/// Comment :
/// No comment
static var definition_name: String {
"This is the english translation"
}
"""
let expectEnUs = """
/// Translation in en-us :
/// This is the english us translation
///
/// Comment :
/// No comment
static var definition_name: String {
"This is the english us translation"
}
"""
XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest())
XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest())
XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest())
}
} }

File diff suppressed because it is too large Load Diff