diff --git a/README.md b/README.md
index b7415c7..a62a8d2 100644
--- a/README.md
+++ b/README.md
@@ -190,6 +190,7 @@ Here's an overview of all options available for the sub command `interfaces`:
- `path` (required), `override` and `verbose` (see [Options for all Sub Commands](#options-for-all-sub-commands) above)
- `default-to-base`
- `unstripped`
+- `ignore-empty-strings`
#### Default to Base (aka `-b`, `--default-to-base`) *optional*
@@ -211,6 +212,16 @@ Example:
$ bartycrouch interfaces -p "/path/to/project" -u
```
+#### Ignore empty strings (aka `-i`, `--ignore-empty-strings`) *optional*
+
+With this options set, strings that are empty, or only contain whitespace, will not appear in the localization files.
+
+Example:
+
+```shell
+$ bartycrouch interfaces -p "/path/to/project" -i
+```
+
---
### Options for `code`
diff --git a/Sources/Code/CommandLineActor.swift b/Sources/Code/CommandLineActor.swift
index 9973ae9..843a23f 100644
--- a/Sources/Code/CommandLineActor.swift
+++ b/Sources/Code/CommandLineActor.swift
@@ -34,8 +34,8 @@ public class CommandLineActor {
customLocalizableName: customLocalizableName.value
)
- case let .interfacesOptions(defaultToBaseOption, unstripped):
- self.actOnInterfaces(path: path, override: override, verbose: verbose, defaultToBase: defaultToBaseOption.value, unstripped: unstripped.value)
+ case let .interfacesOptions(defaultToBaseOption, unstripped, ignoreEmptyStrings):
+ self.actOnInterfaces(path: path, override: override, verbose: verbose, defaultToBase: defaultToBaseOption.value, unstripped: unstripped.value, ignoreEmptyStrings: ignoreEmptyStrings.value)
case let .translateOptions(idOption, secretOption, localeOption):
guard let id = idOption.value else {
@@ -90,7 +90,7 @@ public class CommandLineActor {
)
}
- private func actOnInterfaces(path: String, override: Bool, verbose: Bool, defaultToBase: Bool, unstripped: Bool) {
+ private func actOnInterfaces(path: String, override: Bool, verbose: Bool, defaultToBase: Bool, unstripped: Bool, ignoreEmptyStrings: Bool) {
let inputFilePaths = StringsFilesSearch.shared.findAllIBFiles(within: path, withLocale: "Base")
guard !inputFilePaths.isEmpty else { print("No input files found.", level: .warning); exit(EX_OK) }
@@ -109,7 +109,7 @@ public class CommandLineActor {
}
self.incrementalInterfacesUpdate(
- inputFilePath, outputStringsFilePaths, override: override, verbose: verbose, defaultToBase: defaultToBase, unstripped: unstripped
+ inputFilePath, outputStringsFilePaths, override: override, verbose: verbose, defaultToBase: defaultToBase, unstripped: unstripped, ignoreEmptyStrings: ignoreEmptyStrings
)
}
}
@@ -320,7 +320,7 @@ public class CommandLineActor {
}
private func incrementalInterfacesUpdate(
- _ inputFilePath: String, _ outputStringsFilePaths: [String], override: Bool, verbose: Bool, defaultToBase: Bool, unstripped: Bool
+ _ inputFilePath: String, _ outputStringsFilePaths: [String], override: Bool, verbose: Bool, defaultToBase: Bool, unstripped: Bool, ignoreEmptyStrings: Bool
) {
let extractedStringsFilePath = inputFilePath + ".tmpstrings"
@@ -339,7 +339,8 @@ public class CommandLineActor {
withStringsFileAtPath: extractedStringsFilePath,
addNewValuesAsEmpty: !defaultToBase,
override: override,
- keepWhitespaceSurroundings: unstripped
+ keepWhitespaceSurroundings: unstripped,
+ ignoreEmptyStrings: ignoreEmptyStrings
)
if verbose {
diff --git a/Sources/Code/CommandLineParser.swift b/Sources/Code/CommandLineParser.swift
index 982401f..4a96b1e 100644
--- a/Sources/Code/CommandLineParser.swift
+++ b/Sources/Code/CommandLineParser.swift
@@ -34,7 +34,7 @@ public class CommandLineParser {
customFunction: StringOption,
customLocalizableName: StringOption
)
- case interfacesOptions(defaultToBase: BoolOption, unstripped: BoolOption)
+ case interfacesOptions(defaultToBase: BoolOption, unstripped: BoolOption, ignoreEmptyStrings: BoolOption)
case translateOptions(id: StringOption, secret: StringOption, locale: StringOption)
case normalizeOptions(
locale: StringOption,
@@ -143,6 +143,13 @@ public class CommandLineParser {
required: false,
helpMessage: "Fails if Strings files contain duplicate keys. Designed to be used as part of a CI service."
)
+
+ private let ignoreEmptyStrings = BoolOption(
+ shortFlag: "i",
+ longFlag: "ignore-empty-strings",
+ required: false,
+ helpMessage: "Ignores empty strings and strings consisting of whitespace only."
+ )
// MARK: - Initializers
public init(arguments: [String] = CommandLine.arguments) {
@@ -260,9 +267,9 @@ public class CommandLineParser {
)
let commonOptions: CommonOptions = (path: path, override: override, verbose: verbose)
- let subCommandOptions = SubCommandOptions.interfacesOptions(defaultToBase: defaultToBase, unstripped: unstripped)
+ let subCommandOptions = SubCommandOptions.interfacesOptions(defaultToBase: defaultToBase, unstripped: unstripped, ignoreEmptyStrings: ignoreEmptyStrings)
- commandLine.addOptions(path, override, verbose, defaultToBase, unstripped)
+ commandLine.addOptions(path, override, verbose, defaultToBase, unstripped, ignoreEmptyStrings)
return (commandLine, commonOptions, subCommandOptions)
}
diff --git a/Sources/Code/StringsFileUpdater.swift b/Sources/Code/StringsFileUpdater.swift
index 92cc02b..4c471ee 100644
--- a/Sources/Code/StringsFileUpdater.swift
+++ b/Sources/Code/StringsFileUpdater.swift
@@ -35,7 +35,8 @@ public class StringsFileUpdater {
withStringsFileAtPath otherStringFilePath: String,
addNewValuesAsEmpty: Bool, ignoreBaseKeysAndComment ignores: [String] = defaultIgnoreKeys,
override: Bool = false, updateCommentWithBase: Bool = true, keepExistingKeys: Bool = false,
- overrideComments: Bool = false, sortByKeys: Bool = false, keepWhitespaceSurroundings: Bool = false
+ overrideComments: Bool = false, sortByKeys: Bool = false, keepWhitespaceSurroundings: Bool = false,
+ ignoreEmptyStrings: Bool = false
) {
do {
let newContentString = try String(contentsOfFile: otherStringFilePath)
@@ -59,6 +60,7 @@ public class StringsFileUpdater {
for newTranslation in newTranslations {
// skip keys marked for ignore
guard !newTranslation.value.containsAny(of: ignores) else { continue }
+ if ignoreEmptyStrings && newTranslation.value.isBlank { continue }
// Skip keys that have been marked for ignore in comment
if let newComment = newTranslation.comment, newComment.containsAny(of: ignores) { continue }
diff --git a/Tests/Assets/Strings Files/NewExample.strings b/Tests/Assets/Strings Files/NewExample.strings
index c2cedee..3ad1b8e 100644
Binary files a/Tests/Assets/Strings Files/NewExample.strings and b/Tests/Assets/Strings Files/NewExample.strings differ
diff --git a/Tests/Assets/Strings Files/OldExample.strings b/Tests/Assets/Strings Files/OldExample.strings
index a0223e0..a3341dc 100644
Binary files a/Tests/Assets/Strings Files/OldExample.strings and b/Tests/Assets/Strings Files/OldExample.strings differ
diff --git a/Tests/Code/StringsFileUpdaterTests.swift b/Tests/Code/StringsFileUpdaterTests.swift
index 032badc..2a1f27f 100644
--- a/Tests/Code/StringsFileUpdaterTests.swift
+++ b/Tests/Code/StringsFileUpdaterTests.swift
@@ -67,6 +67,7 @@ class StringsFileUpdaterTests: XCTestCase {
("cHL-Zc-L39.normalTitle", "Example Button 3", " Class = \"UIButton\"; normalTitle = \"Example Button 3\"; ObjectID = \"cHL-Zc-L39\"; "),
("test.key", "This is a test key", " Completely custom comment structure in one line "),
("test.key.ignored", "This is a test key to be ignored #bc-ignore!", " Completely custom comment structure in one line to be ignored "),
+ ("test.key.ignoreEmptyStrings", " ", " This key should be ignored when ignoreEmptyKeys is set "),
("abc-12-345.normalTitle", "😀", " Class = \"UIButton\"; normalTitle = \"😀\"; ObjectID = \"abc-12-345\"; "),
("em1-3S-vgp.text", "Refrakční vzdálenost v metrech",
" Class = \"UILabel\"; text = \"Refraktionsentfernung in Meter\"; ObjectID = \"em1-3S-vgp\"; ")
@@ -120,6 +121,8 @@ class StringsFileUpdaterTests: XCTestCase {
"\"test.key\" = \"This is a test key\";", "",
"/* Completely custom comment structure in one line to be ignored */",
"\"test.key.ignored\" = \"This is a test key to be ignored #bc-ignore!\";", "",
+ "/* This key should be ignored when ignoreEmptyKeys is set */",
+ "\"test.key.ignoreEmptyStrings\" = \" \";", "",
"/* Class = \"UIButton\"; normalTitle = \"😀\"; ObjectID = \"abc-12-345\"; */",
"\"abc-12-345.normalTitle\" = \"😀\";", "",
"/* Class = \"UILabel\"; text = \"Refraktionsentfernung in Meter\"; ObjectID = \"em1-3S-vgp\"; */",
@@ -133,7 +136,7 @@ class StringsFileUpdaterTests: XCTestCase {
XCTAssertEqual(oldLinesInFile[index], expectedLine)
}
- stringsFileUpdater.incrementallyUpdateKeys(withStringsFileAtPath: newStringsFilePath, addNewValuesAsEmpty: true, updateCommentWithBase: false)
+ stringsFileUpdater.incrementallyUpdateKeys(withStringsFileAtPath: newStringsFilePath, addNewValuesAsEmpty: true, updateCommentWithBase: false, ignoreEmptyStrings: true)
let expectedLinesAfterIncrementalUpdate = [
"", "/* Class = \"UIButton\"; normalTitle = \"Example Button 1\"; ObjectID = \"35F-cl-mdI\"; */",
@@ -180,6 +183,8 @@ class StringsFileUpdaterTests: XCTestCase {
"\"test.key\" = \"This is a test key\";", "",
"/* Completely custom comment structure in one line to be ignored */",
"\"test.key.ignored\" = \"This is a test key to be ignored #bc-ignore!\";", "",
+ "/* This key should be ignored when ignoreEmptyKeys is set */",
+ "\"test.key.ignoreEmptyStrings\" = \" \";", "",
"/* Class = \"UIButton\"; normalTitle = \"😀\"; ObjectID = \"abc-12-345\"; */",
"\"abc-12-345.normalTitle\" = \"😀\";", "",
"/* Class = \"UILabel\"; text = \"Refraktionsentfernung in Meter\"; ObjectID = \"em1-3S-vgp\"; */",
@@ -197,7 +202,8 @@ class StringsFileUpdaterTests: XCTestCase {
withStringsFileAtPath: newStringsFilePath,
addNewValuesAsEmpty: true,
updateCommentWithBase: false,
- keepWhitespaceSurroundings: true
+ keepWhitespaceSurroundings: true,
+ ignoreEmptyStrings: true
)
let expectedLinesAfterIncrementalUpdate = [
@@ -245,6 +251,8 @@ class StringsFileUpdaterTests: XCTestCase {
"\"test.key\" = \"This is a test key\";", "",
"/* Completely custom comment structure in one line to be ignored */",
"\"test.key.ignored\" = \"This is a test key to be ignored #bc-ignore!\";", "",
+ "/* This key should be ignored when ignoreEmptyKeys is set */",
+ "\"test.key.ignoreEmptyStrings\" = \" \";", "",
"/* Class = \"UIButton\"; normalTitle = \"😀\"; ObjectID = \"abc-12-345\"; */",
"\"abc-12-345.normalTitle\" = \"😀\";", "",
"/* Class = \"UILabel\"; text = \"Refraktionsentfernung in Meter\"; ObjectID = \"em1-3S-vgp\"; */",
@@ -258,7 +266,7 @@ class StringsFileUpdaterTests: XCTestCase {
XCTAssertEqual(oldLinesInFile[index], expectedLine)
}
- stringsFileUpdater.incrementallyUpdateKeys(withStringsFileAtPath: newStringsFilePath, addNewValuesAsEmpty: false)
+ stringsFileUpdater.incrementallyUpdateKeys(withStringsFileAtPath: newStringsFilePath, addNewValuesAsEmpty: false, ignoreEmptyStrings: true)
let expectedLinesAfterIncrementalUpdate = [
"", "/* Class = \"UIButton\"; normalTitle = \"New Example Button 1\"; ObjectID = \"35F-cl-mdI\"; */",