Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions BartyCrouch.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
50A47DB71F6D334300A1C0AA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 50A47DB91F6D334300A1C0AA /* Localizable.strings */; };
50A47DBD1F6D339000A1C0AA /* CustomName.strings in Resources */ = {isa = PBXBuildFile; fileRef = 50A47DBF1F6D339000A1C0AA /* CustomName.strings */; };
00CAD6B81F7A6EF80090DD38 /* CommandLineKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00CAD6181F7A6EA60090DD38 /* CommandLineKit.swift */; };
00CAD6B91F7A6EF80090DD38 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00CAD61A1F7A6EA60090DD38 /* Option.swift */; };
00CAD6BA1F7A6EF80090DD38 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00CAD61B1F7A6EA60090DD38 /* StringExtensions.swift */; };
Expand Down Expand Up @@ -104,6 +106,10 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
5050F0921F6D2CB500F80CB4 /* SwiftExampleMultipleTables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftExampleMultipleTables.swift; sourceTree = "<group>"; };
5050F0951F6D2E0200F80CB4 /* SwiftExampleMultipleTables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftExampleMultipleTables.swift; sourceTree = "<group>"; };
50A47DBA1F6D334B00A1C0AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
50A47DC01F6D339500A1C0AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/CustomName.strings; sourceTree = "<group>"; };
00CAD6181F7A6EA60090DD38 /* CommandLineKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandLineKit.swift; sourceTree = "<group>"; };
00CAD61A1F7A6EA60090DD38 /* Option.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Option.swift; sourceTree = "<group>"; };
00CAD61B1F7A6EA60090DD38 /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -218,6 +224,31 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
5050F08E1F6D297E00F80CB4 /* Multiple Tables */ = {
isa = PBXGroup;
children = (
50A47DB91F6D334300A1C0AA /* Localizable.strings */,
50A47DBF1F6D339000A1C0AA /* CustomName.strings */,
);
path = "Multiple Tables";
sourceTree = "<group>";
};
5050F0961F6D306E00F80CB4 /* Multiple Tables Code */ = {
isa = PBXGroup;
children = (
5050F0921F6D2CB500F80CB4 /* SwiftExampleMultipleTables.swift */,
);
path = "Multiple Tables Code";
sourceTree = "<group>";
};
5050F0971F6D308100F80CB4 /* Multiple Tables Code Custom Function */ = {
isa = PBXGroup;
children = (
5050F0951F6D2E0200F80CB4 /* SwiftExampleMultipleTables.swift */,
);
path = "Multiple Tables Code Custom Function";
sourceTree = "<group>";
};
00CAD6171F7A6EA60090DD38 /* CommandLine */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -437,6 +468,8 @@
children = (
E7974AF81DFAECA700E31754 /* Multiple Arguments Code */,
E4EDD5F71E3151BE0010D878 /* Multiple Arguments Code Custom Function */,
5050F0961F6D306E00F80CB4 /* Multiple Tables Code */,
5050F0971F6D308100F80CB4 /* Multiple Tables Code Custom Function */,
82463E011CD915DB00D28A2C /* Code Files */,
E4EDD6041E3156E00010D878 /* Code Files Custom Function */,
82CDE2F81C6C0BAA00055FE6 /* Strings Files */,
Expand All @@ -462,6 +495,7 @@
82053A251CD32A0200434DAD /* LongOldExample.strings */,
82053A271CD32B4900434DAD /* LongNewExample.strings */,
A14DE16D1D71B0400010F856 /* UnsortedKeys */,
5050F08E1F6D297E00F80CB4 /* Multiple Tables */,
);
path = "Strings Files";
sourceTree = "<group>";
Expand Down Expand Up @@ -751,8 +785,10 @@
buildActionMask = 2147483647;
files = (
825550FC1C7E637700DB5DCF /* Localizable.strings in Resources */,
50A47DB71F6D334300A1C0AA /* Localizable.strings in Resources */,
A1B73EB01E00744D0070D20F /* Localizable.strings in Resources */,
82053A281CD32B4900434DAD /* LongNewExample.strings in Resources */,
50A47DBD1F6D339000A1C0AA /* CustomName.strings in Resources */,
82053A261CD32A0200434DAD /* LongOldExample.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -875,6 +911,22 @@
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
50A47DB91F6D334300A1C0AA /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
50A47DBA1F6D334B00A1C0AA /* Base */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
50A47DBF1F6D339000A1C0AA /* CustomName.strings */ = {
isa = PBXVariantGroup;
children = (
50A47DC01F6D339500A1C0AA /* Base */,
);
name = CustomName.strings;
sourceTree = "<group>";
};
821DED3E1C70D11500B8353B /* Example.storyboard */ = {
isa = PBXVariantGroup;
children = (
Expand Down
21 changes: 13 additions & 8 deletions Sources/Code/CommandLineActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ public class CommandLineActor {

private func actOnCode(path: String, override: Bool, verbose: Bool, localizable: String, defaultToKeys: Bool, additive: Bool,
overrideComments: Bool, useExtractLocStrings: Bool, sortByKeys: Bool, unstripped: Bool, customFunction: String?) {
let allLocalizableStringsFilePaths = StringsFilesSearch.shared.findAllStringsFiles(within: localizable, withFileName: "Localizable")
let allLocalizableStringsFilePaths = StringsFilesSearch.shared.findAllStringsFiles(within: localizable)

guard !allLocalizableStringsFilePaths.isEmpty else {
printError("No `Localizable.strings` file found for output.\nTo fix this, please add a `Localizable.strings` file to your project and click the localize button for the file in Xcode. Alternatively remove the line beginning with `bartycrouch code` in your build script to remove this feature entirely if you don't need it.\nSee https://github.com/Flinesoft/BartyCrouch/issues/11 for further information.") // swiftlint:disable:this line_length
printError("No `*.strings` file found for output.\nTo fix this, please add a `Localizable.strings` file to your project and click the localize button for the file in Xcode. Custom names for your `*.strings` file do also work. Alternatively remove the line beginning with `bartycrouch code` in your build script to remove this feature entirely if you don't need it.\nSee https://github.com/Flinesoft/BartyCrouch/issues/11 for further information.") // swiftlint:disable:this line_length
exit(EX_USAGE)
}

Expand Down Expand Up @@ -163,13 +163,18 @@ public class CommandLineActor {
exit(EX_UNAVAILABLE)
}

let extractedLocalizableStringsFilePath = extractedStringsFileDirectory + "Localizable.strings"
guard FileManager.default.fileExists(atPath: extractedLocalizableStringsFilePath) else {
printError("No localizations extracted from Code in directory '\(inputDirectoryPath)'.")
exit(EX_OK) // NOTE: Expecting to see this only for empty project situations.
}

for outputStringsFilePath in outputStringsFilePaths {
guard let fileName = outputStringsFilePath.components(separatedBy: "/").last else {
printError("Could not extract name of string file at path '\(outputStringsFilePath)'")
exit(EX_CONFIG)
}

let extractedLocalizableStringsFilePath = extractedStringsFileDirectory + fileName
guard FileManager.default.fileExists(atPath: extractedLocalizableStringsFilePath) else {
printError("No localizations extracted from Code for string file '\(fileName)' in directory '\(inputDirectoryPath)'.")
exit(EX_OK) // NOTE: Expecting to see this only for empty project situations.
}

guard let stringsFileUpdater = StringsFileUpdater(path: outputStringsFilePath) else {
printError("Could not read strings file at path '\(outputStringsFilePath)'")
exit(EX_CONFIG)
Expand Down
34 changes: 28 additions & 6 deletions Sources/Code/StringsFilesSearch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,29 @@ public class StringsFilesSearch {
return self.findAllFilePaths(inDirectoryPath: baseDirectoryPath, matching: stringsFileRegex)
}

public func findAllStringsFiles(within baseDirectoryPath: String) -> [String] {
// swiftlint:disable:next force_try
let stringsFileRegex = try! NSRegularExpression(pattern: ".*\\.lproj.*\\.strings\\z", options: .caseInsensitive)
let stringFiles = self.findAllFilePaths(inDirectoryPath: baseDirectoryPath, matching: stringsFileRegex)

let ibFileNames = self.findAllIBFiles(within: baseDirectoryPath).map { extractFileName(from: $0) }

return stringFiles.filter { stringFilePath in
// swiftlint:disable:next if_as_guard
for ibFileName in ibFileNames {
if stringFilePath.range(of: ibFileName) != nil {
return false
}
}

return true
}
}

public func findAllLocalesForStringsFile(sourceFilePath: String) -> [String] {
var pathComponents = sourceFilePath.components(separatedBy: "/")
let storyboardName: String = {
var fileNameComponents = pathComponents.last!.components(separatedBy: ".")
fileNameComponents.removeLast()
return fileNameComponents.joined(separator: ".")
}()
let storyboardName = extractFileName(from: sourceFilePath)

var pathComponents = sourceFilePath.components(separatedBy: "/")
pathComponents.removeLast() // Remove last path component from folder/base.lproj/some.storyboard
pathComponents.removeLast() // Remove last path component from folder/base.lproj

Expand Down Expand Up @@ -67,4 +82,11 @@ public class StringsFilesSearch {
return []
}
}

private func extractFileName(from filePath: String) -> String {
let pathComponents = filePath.components(separatedBy: "/")
var fileNameComponents = pathComponents.last!.components(separatedBy: ".")
fileNameComponents.removeLast()
return fileNameComponents.joined(separator: ".")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// SwiftExampleMultipleTables.swift
// BartyCrouch
//
// Created by Max Bothe on 16.09.17.
// Copyright © 2017 Flinesoft. All rights reserved.
//

import Foundation

class SwiftExampleMultipleTables {
func exampleFunction() {
BCLocalizedString("test.defaultTableName", comment: "test comment in default table name")
BCLocalizedString("test.customTableName", tableName: "CustomName", comment: "test comment in custom table name")
}
}
16 changes: 16 additions & 0 deletions Tests/Assets/Multiple Tables Code/SwiftExampleMultipleTables.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// SwiftExampleMultipleTables.swift
// BartyCrouch
//
// Created by Max Bothe on 16.09.17.
// Copyright © 2017 Flinesoft. All rights reserved.
//

import Foundation

class SwiftExampleMultipleTables {
func exampleFunction() {
NSLocalizedString("test.defaultTableName", comment: "test comment in default table name")
NSLocalizedString("test.customTableName", tableName: "CustomName", comment: "test comment in custom table name")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Empty file.
Empty file.
Empty file.
Empty file.
84 changes: 70 additions & 14 deletions Tests/Code/CommandLineActorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,54 @@ class CommandLineActorTests: XCTestCase {
// MARK: - Stored Properties
static let stringsFilesDirPath = "\(BASE_DIR)/Tests/Assets/Strings Files"

let codeFilesDirPath = "\(BASE_DIR)/Tests/Assets/Code Files/UnsortedKeys"
let unsortedKeysStringsFilePath = "\(stringsFilesDirPath)/UnsortedKeys/Base.lproj/Localizable.strings"
let unsortedKeysDirPath = "\(stringsFilesDirPath)/UnsortedKeys"
static let unsortedKeysCodeFilesDirPath = "\(BASE_DIR)/Tests/Assets/Code Files/UnsortedKeys"
static let unsortedKeysStringsFilePath = "\(stringsFilesDirPath)/UnsortedKeys/Base.lproj/Localizable.strings"
static let unsortedKeysDirPath = "\(stringsFilesDirPath)/UnsortedKeys"

static let multipleTablesCodeFilesDirPath = "\(BASE_DIR)/Tests/Assets/Multiple Tables Code/"
static let multipleTablesDirPath = "\(stringsFilesDirPath)/Multiple Tables"

static let filePathsToBackup = [
unsortedKeysStringsFilePath,
multipleTablesStringsFilePath(forTableName: "Localizable"),
multipleTablesStringsFilePath(forTableName: "CustomName")
]

// MARK: - Test Callbacks
override func setUp() {
super.setUp()

if FileManager.default.fileExists(atPath: unsortedKeysStringsFilePath + ".backup") {
try! FileManager.default.removeItem(atPath: unsortedKeysStringsFilePath + ".backup")
}
for filePath in CommandLineActorTests.filePathsToBackup {
if FileManager.default.fileExists(atPath: filePath + ".backup") {
try! FileManager.default.removeItem(atPath: filePath + ".backup")
}

try! FileManager.default.copyItem(atPath: unsortedKeysStringsFilePath, toPath: unsortedKeysStringsFilePath + ".backup")
try! FileManager.default.copyItem(atPath: filePath, toPath: filePath + ".backup")
}
}

override func tearDown() {
super.tearDown()

try! FileManager.default.removeItem(atPath: unsortedKeysStringsFilePath)
try! FileManager.default.copyItem(atPath: unsortedKeysStringsFilePath + ".backup", toPath: unsortedKeysStringsFilePath)
try! FileManager.default.removeItem(atPath: unsortedKeysStringsFilePath + ".backup")
for filePath in CommandLineActorTests.filePathsToBackup {
try! FileManager.default.removeItem(atPath: filePath)
try! FileManager.default.copyItem(atPath: filePath + ".backup", toPath: filePath)
try! FileManager.default.removeItem(atPath: filePath + ".backup")
}
}

// MARK: - Test Methods
func testActOnCode() {
let args = ["bartycrouch", "code", "-p", codeFilesDirPath, "-l", unsortedKeysDirPath, "-a"]
let args = [
"bartycrouch", "code",
"-p", CommandLineActorTests.unsortedKeysCodeFilesDirPath,
"-l", CommandLineActorTests.unsortedKeysDirPath,
"-a"
]
CommandLineParser(arguments: args).parse { commonOptions, subCommandOptions in
CommandLineActor().act(commonOptions: commonOptions, subCommandOptions: subCommandOptions)

guard let updater = StringsFileUpdater(path: self.unsortedKeysStringsFilePath) else {
guard let updater = StringsFileUpdater(path: CommandLineActorTests.unsortedKeysStringsFilePath) else {
XCTFail()
return
}
Expand All @@ -57,11 +75,16 @@ class CommandLineActorTests: XCTestCase {
}

func testActOnCodeWithSortedOption() {
let args = ["bartycrouch", "code", "-p", codeFilesDirPath, "-l", unsortedKeysDirPath, "-a", "-s"]
let args = [
"bartycrouch", "code",
"-p", CommandLineActorTests.unsortedKeysCodeFilesDirPath,
"-l", CommandLineActorTests.unsortedKeysDirPath,
"-a", "-s"
]
CommandLineParser(arguments: args).parse { commonOptions, subCommandOptions in
CommandLineActor().act(commonOptions: commonOptions, subCommandOptions: subCommandOptions)

guard let updater = StringsFileUpdater(path: self.unsortedKeysStringsFilePath) else {
guard let updater = StringsFileUpdater(path: CommandLineActorTests.unsortedKeysStringsFilePath) else {
XCTFail()
return
}
Expand All @@ -72,6 +95,39 @@ class CommandLineActorTests: XCTestCase {
XCTAssertEqual(resultingKeys, expectedKeys)
}
}

func testActOnCodeMultipleTables() {
let args = [
"bartycrouch", "code",
"-p", CommandLineActorTests.multipleTablesCodeFilesDirPath,
"-l", CommandLineActorTests.multipleTablesDirPath,
"-e"
]
CommandLineParser(arguments: args).parse { commonOptions, subCommandOptions in
CommandLineActor().act(commonOptions: commonOptions, subCommandOptions: subCommandOptions)

let expectedKeysPerTable = [
"Localizable": ["test.defaultTableName"],
"CustomName": ["test.customTableName"]
]

for (tableName, expectedKeys) in expectedKeysPerTable {
let filePath = CommandLineActorTests.multipleTablesStringsFilePath(forTableName: tableName)
guard let updater = StringsFileUpdater(path: filePath) else {
XCTFail()
return
}

let resultingKeys = updater.findTranslations(inString: updater.oldContentString).map { $0.key }

XCTAssertEqual(resultingKeys, expectedKeys)
}
}
}

static func multipleTablesStringsFilePath(forTableName tableName: String) -> String {
return "\(multipleTablesDirPath)/Base.lproj/\(tableName).strings"
}
}

// swiftlint:enable force_try
Loading