From 38a0f3b5f1811c0d4acfbbe020e4e4c8a33484ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Sun, 6 Mar 2016 13:44:35 +0100 Subject: [PATCH 1/9] [README] Bump version in badge + Capitalize badges --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 424e5c0..d336472 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@

- Version: 1.3.0 + Version: 1.3.1 Swift: 2.1 - License: MIT

From b61ab2f20b31ed5cd9b8c9f144c4cd871434b487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Sun, 6 Mar 2016 13:47:27 +0100 Subject: [PATCH 2/9] [README] Update refs to renamed branch --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d336472..c19942f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

-

@@ -12,7 +12,7 @@ Swift: 2.1 - + License: MIT From f47be0f858d6b10e53af817cef79267ab881b692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Sun, 6 Mar 2016 13:56:45 +0100 Subject: [PATCH 3/9] [README] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c19942f..83f1b00 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ With BartyCrouch you can run commands like these: ``` shell # Incrementally update English and German strings of Main.storyboard -bartycrouch -i "path/Base.lproj/Main.storyboard" -o en de zh-Hans pt-BR" +bartycrouch -i "path/Base.lproj/Main.storyboard" -o en de zh-Hans pt-BR # Incrementally update all languages of Main.storyboard bartycrouch -i "path/Base.lproj/Main.storyboard" -a From f43fbc62c0680c318193610db7850ca378fcbdfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Sun, 6 Mar 2016 13:59:21 +0100 Subject: [PATCH 4/9] [README] Update first complete examples comment to match command --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 83f1b00..044bb9a 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ Before using BartyCrouch please **make sure you have committed your code**. With BartyCrouch you can run commands like these: ``` shell -# Incrementally update English and German strings of Main.storyboard -bartycrouch -i "path/Base.lproj/Main.storyboard" -o en de zh-Hans pt-BR +# Incrementally update English, Simplified Chinese and Brazilian Portuguese strings of Main.storyboard +bartycrouch -i "path/Base.lproj/Main.storyboard" -o en zh-Hans pt-BR # Incrementally update all languages of Main.storyboard bartycrouch -i "path/Base.lproj/Main.storyboard" -a From 92d19fce913276409828d7357695b5d52c7fc2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Mon, 14 Mar 2016 22:38:21 +0100 Subject: [PATCH 5/9] Add method to find all interface builder files --- BartyCrouch CLI/main.swift | 6 +++--- Sources/Code/StringsFilesSearch.swift | 13 ++++++++++++- Tests/Code/StringsFilesSearchTests.swift | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/BartyCrouch CLI/main.swift b/BartyCrouch CLI/main.swift index f5c3147..df483a8 100644 --- a/BartyCrouch CLI/main.swift +++ b/BartyCrouch CLI/main.swift @@ -209,7 +209,7 @@ func run() { let locales = stringsFiles.filter { localeRegex.matchesInString($0, options: .ReportCompletion, range: NSMakeRange(0, $0.characters.count)).count > 0 } if locales.count == stringsFiles.count { let lprojLocales = locales.map { "\($0).lproj" } - return StringsFilesSearch.sharedInstance.findAll(inputFilePath).filter { $0.containsAny(ofStrings: lprojLocales) } + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0.containsAny(ofStrings: lprojLocales) } } } catch { print("Error! Couldn't init locale regex. Please report this issue on https://github.com/Flinesoft/BartyCrouch/issues.") @@ -217,9 +217,9 @@ func run() { } return output.value! case .Automatic: - return StringsFilesSearch.sharedInstance.findAll(inputFilePath).filter { $0 != inputFilePath } + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath } case .Except: - return StringsFilesSearch.sharedInstance.findAll(inputFilePath).filter { $0 != inputFilePath && !except.value!.contains($0) } + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath && !except.value!.contains($0) } case .None: print("Error! Missing output key '\(output.shortFlag!)' or '\(auto.shortFlag!)'.") exit(EX_USAGE) diff --git a/Sources/Code/StringsFilesSearch.swift b/Sources/Code/StringsFilesSearch.swift index fe791fb..cc8bf42 100644 --- a/Sources/Code/StringsFilesSearch.swift +++ b/Sources/Code/StringsFilesSearch.swift @@ -18,7 +18,18 @@ public class StringsFilesSearch { // MARK: - Instance Methods - public func findAll(baseFilePath: String) -> [String] { + public func findAllIBFiles(baseDirectoryPath: String) -> [String] { + do { + let ibFileRegex = try NSRegularExpression(pattern: ".*\\Base.lproj.*\\.(storyboard|xib)\\z", options: .CaseInsensitive) + let allFilePaths = try NSFileManager.defaultManager().subpathsOfDirectoryAtPath(baseDirectoryPath) + let ibFilePaths = allFilePaths.filter { ibFileRegex.matchesInString($0, options: .ReportCompletion, range: NSMakeRange(0, $0.characters.count)).count > 0 } + return ibFilePaths.map { baseDirectoryPath + "/" + $0 } + } catch { + return [] + } + } + + public func findAllStringsFiles(baseFilePath: String) -> [String] { var pathComponents = baseFilePath.componentsSeparatedByString("/") let storyboardName: String = { var fileNameComponents = pathComponents.last!.componentsSeparatedByString(".") diff --git a/Tests/Code/StringsFilesSearchTests.swift b/Tests/Code/StringsFilesSearchTests.swift index 2f190af..43c46d6 100644 --- a/Tests/Code/StringsFilesSearchTests.swift +++ b/Tests/Code/StringsFilesSearchTests.swift @@ -11,13 +11,26 @@ import XCTest @testable import BartyCrouch class StringsFilesSearchTests: XCTestCase { + + func testFindAllIBFiles() { + + let basePath = "\(PROJECT_DIR)/Tests" + + let expectedIBFilePaths = ["iOS", "OSX", "tvOS"].map { examplePath(platform: $0, locale: "Base", type: "storyboard") } + + let results = StringsFilesSearch.sharedInstance.findAllIBFiles(basePath) + + XCTAssertEqual(results.count, expectedIBFilePaths.count) + XCTAssertEqual(results, expectedIBFilePaths) + + } - func testiOSFindAllWithBaseStoryboardPath() { + func testiOSFindAllStringsFiles() { let baseStoryboardPath = examplePath(platform: "iOS", locale: "base", type: ".storyboard") let expectedStringsPaths = ["de", "en", "ja", "zh-Hans"].map { examplePath(platform: "iOS", locale: $0, type: ".strings") } - let results = StringsFilesSearch.sharedInstance.findAll(baseStoryboardPath) + let results = StringsFilesSearch.sharedInstance.findAllStringsFiles(baseStoryboardPath) XCTAssertEqual(results.count, expectedStringsPaths.count) XCTAssertEqual(results, expectedStringsPaths) From ef1aded74c19a13ef784605f128a79c0246b408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Mon, 14 Mar 2016 23:02:03 +0100 Subject: [PATCH 6/9] Add automatic input file search support to CLI --- BartyCrouch CLI/main.swift | 102 +++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 39 deletions(-) diff --git a/BartyCrouch CLI/main.swift b/BartyCrouch CLI/main.swift index df483a8..a7ff567 100644 --- a/BartyCrouch CLI/main.swift +++ b/BartyCrouch CLI/main.swift @@ -16,7 +16,7 @@ let cli = CommandLine() let input = StringOption( shortFlag: "i", longFlag: "input", - required: true, + required: false, helpMessage: "Path to your source file to be used for translation." ) @@ -197,52 +197,76 @@ func run() { return .IncrementalUpdate }() - let inputFilePath = input.value! - - let outputStringsFilePaths: [String] = { - switch outputType { - case .StringsFiles: - if let stringsFiles = output.value { - // check if output style is locales-only, e.g. `-o en de zh-Hans pt-BR` - convert to full paths if so - do { - let localeRegex = try NSRegularExpression(pattern: "\\A\\w{2}(-\\w{2,4})?\\z", options: .CaseInsensitive) - let locales = stringsFiles.filter { localeRegex.matchesInString($0, options: .ReportCompletion, range: NSMakeRange(0, $0.characters.count)).count > 0 } - if locales.count == stringsFiles.count { - let lprojLocales = locales.map { "\($0).lproj" } - return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0.containsAny(ofStrings: lprojLocales) } - } - } catch { - print("Error! Couldn't init locale regex. Please report this issue on https://github.com/Flinesoft/BartyCrouch/issues.") - } + let inputFilePaths: [String] = { + if let inputFilePath = input.value { + return [inputFilePath] + } else if outputType == .Automatic { + if Process.arguments.count > 1 { + let baseDirectoryPath = Process.arguments[1] + return StringsFilesSearch.sharedInstance.findAllIBFiles(baseDirectoryPath) + } else { + print("Error! No directory path specified to search for input files.") + exit(EX_USAGE) } - return output.value! - case .Automatic: - return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath } - case .Except: - return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath && !except.value!.contains($0) } - case .None: - print("Error! Missing output key '\(output.shortFlag!)' or '\(auto.shortFlag!)'.") + } else { + print("Error! Missing input path(s).") exit(EX_USAGE) } }() - guard NSFileManager.defaultManager().fileExistsAtPath(inputFilePath) else { - print("Error! No file exists at input path '\(inputFilePath)'") - exit(EX_NOINPUT) + guard inputFilePaths.count > 0 else { + print("Error! No input files found.") + exit(EX_USAGE) } - for outputStringsFilePath in outputStringsFilePaths { - guard NSFileManager.defaultManager().fileExistsAtPath(outputStringsFilePath) else { - print("Error! No file exists at output path '\(outputStringsFilePath)'.") - exit(EX_CONFIG) + for inputFilePath in inputFilePaths { + + let outputStringsFilePaths: [String] = { + switch outputType { + case .StringsFiles: + if let stringsFiles = output.value { + // check if output style is locales-only, e.g. `-o en de zh-Hans pt-BR` - convert to full paths if so + do { + let localeRegex = try NSRegularExpression(pattern: "\\A\\w{2}(-\\w{2,4})?\\z", options: .CaseInsensitive) + let locales = stringsFiles.filter { localeRegex.matchesInString($0, options: .ReportCompletion, range: NSMakeRange(0, $0.characters.count)).count > 0 } + if locales.count == stringsFiles.count { + let lprojLocales = locales.map { "\($0).lproj" } + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0.containsAny(ofStrings: lprojLocales) } + } + } catch { + print("Error! Couldn't init locale regex. Please report this issue on https://github.com/Flinesoft/BartyCrouch/issues.") + } + } + return output.value! + case .Automatic: + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath } + case .Except: + return StringsFilesSearch.sharedInstance.findAllStringsFiles(inputFilePath).filter { $0 != inputFilePath && !except.value!.contains($0) } + case .None: + print("Error! Missing output key '\(output.shortFlag!)' or '\(auto.shortFlag!)'.") + exit(EX_USAGE) + } + }() + + guard NSFileManager.defaultManager().fileExistsAtPath(inputFilePath) else { + print("Error! No file exists at input path '\(inputFilePath)'") + exit(EX_NOINPUT) } - } - - switch actionType { - case .IncrementalUpdate: - incrementalUpdate(inputFilePath, outputStringsFilePaths) - case .Translate: - translate(credentials: translate.value!, inputFilePath, outputStringsFilePaths) + + for outputStringsFilePath in outputStringsFilePaths { + guard NSFileManager.defaultManager().fileExistsAtPath(outputStringsFilePath) else { + print("Error! No file exists at output path '\(outputStringsFilePath)'.") + exit(EX_CONFIG) + } + } + + switch actionType { + case .IncrementalUpdate: + incrementalUpdate(inputFilePath, outputStringsFilePaths) + case .Translate: + translate(credentials: translate.value!, inputFilePath, outputStringsFilePaths) + } + } } From 4079187d981b59c4c4fc23d3bf18b57a37e3d084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Mon, 14 Mar 2016 23:15:14 +0100 Subject: [PATCH 7/9] [README] Update to use input auto search function --- README.md | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 044bb9a..017c253 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ With BartyCrouch you can run commands like these: # Incrementally update English, Simplified Chinese and Brazilian Portuguese strings of Main.storyboard bartycrouch -i "path/Base.lproj/Main.storyboard" -o en zh-Hans pt-BR -# Incrementally update all languages of Main.storyboard -bartycrouch -i "path/Base.lproj/Main.storyboard" -a +# Incrementally update all languages of all Storyboard/XIB files +bartycrouch "/absolute/path/to/project" -a # Machine-translate all empty values of all supported languages with English as source bartycrouch -t "{ id: ID }|{ secret: SECRET }" -i "path/en.lproj/Localizable.strings" -a @@ -79,11 +79,17 @@ Also you can make your life a lot easier by using the **build script method** de The `bartycrouch` main command accepts one of the following combinations of arguments: -1. Input and Output/Auto/Except -2. Translate with Input and Output/Auto/Except +1. Automatic input and output search (all localized Storyboards/XIBs) +2. Input and Output/Auto/Except +3. Translate with Input and Output/Auto/Except You can also additionally specify Force and/or Verbose on each command. +### Full Automatic (aka `/absolute/path -a`) + +If you want BartyCrouch to **search for all localized Storyboards/XIBs** (those in Base.lproj folders) and also want BartyCrouch to find the respective output files, +then simply declare the BartyCrouch command with an absolute path followed by `-a` like `/absolute/path/to/project -a`. + #### Input (aka `-i`) You can specify the input Storyboard, XIB or Strings file using `-i "path/to/my.storyboard"` (`-i` is short `--input`). @@ -126,34 +132,36 @@ You may want to **update your `.strings` files on each build automatically** wha ``` shell if which bartycrouch > /dev/null; then - # Set path to base internationalized Storyboard/XIB files - BASE_PATH="$PROJECT_DIR/Sources/Base.lproj" - # Incrementally update all Storyboards/XIBs strings files - bartycrouch -i "$BASE_PATH/Main.storyboard" -a - bartycrouch -i "$BASE_PATH/LaunchScreen.storyboard" -a - bartycrouch -i "$BASE_PATH/CustomView.xib" -a - - # Set Microsoft Translator API credentials - EN_PATH="$PROJECT_DIR/Sources/en.lproj" - CREDS="{ id: YOUR_ID }|{ secret: YOUR_SECRET }" - - # Machine-translate empty language values for all languages - bartycrouch -t $CREDS -i "$EN_PATH/Localizable.strings" -a - bartycrouch -t $CREDS -i "$EN_PATH/Main.strings" -a - bartycrouch -t $CREDS -i "$EN_PATH/LaunchScreen.strings" -a - bartycrouch -t $CREDS -i "$EN_PATH/CustomView.strings" -a + bartycrouch $PROJECT_DIR -a else echo "warning: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch" fi ``` - -Update the `BASE_PATH` to point to your Base.lproj directory, remove all unneeded lines, add a `bartycrouch -i ... -a` (or any other BartyCrouch command) for each of your base internationalized Storyboards/XIBs (if any) and you're good to go. You should also uncomment or remove the lines below `# Set Microsoft ...` until `bartycrouch -t ...` if you don't want to use the machine translation feature. Xcode will now run BartyCrouch each time you build your project and update your `.strings` files accordingly. +Xcode will now run BartyCrouch each time you build your project and update your `.strings` files accordingly. *Note: Please make sure you commit your code using source control regularly when using the build script method.* +If you want to use the **machine translation functionality when building** then simply add the following to the if part of the above: + +``` +# OPTIONAL + +# Set source language for machine translation +EN_PATH="$PROJECT_DIR/Sources/en.lproj" + +# Set Microsoft Translator API credentials +CREDS="{ id: YOUR_ID }|{ secret: YOUR_SECRET }" + +# Machine-translate empty language values for all languages +bartycrouch -t $CREDS -i "$EN_PATH/Localizable.strings" -a +bartycrouch -t $CREDS -i "$EN_PATH/Main.strings" -a +bartycrouch -t $CREDS -i "$EN_PATH/LaunchScreen.strings" -a +bartycrouch -t $CREDS -i "$EN_PATH/CustomView.strings" -a +``` + ### Exclude specific views from localization Sometimes you may want to **ignore some specific views** containing localizable texts e.g. because **their values are set programmatically**. From 8c64f89fe4c4212a28cbc3c1c316d5e70336b5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Mon, 14 Mar 2016 23:21:20 +0100 Subject: [PATCH 8/9] [README] Minor streamlining --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 017c253..a16d501 100644 --- a/README.md +++ b/README.md @@ -140,11 +140,9 @@ fi ``` -Xcode will now run BartyCrouch each time you build your project and update your `.strings` files accordingly. - *Note: Please make sure you commit your code using source control regularly when using the build script method.* -If you want to use the **machine translation functionality when building** then simply add the following to the if part of the above: +If you want to use the **machine translation functionality** too then simply add the following to the if part: ``` # OPTIONAL From 211ee8f113c9f348d5f3100ad1cb6d6ff65c24e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cihat=20Gu=CC=88ndu=CC=88z?= Date: Mon, 14 Mar 2016 23:24:05 +0100 Subject: [PATCH 9/9] Bump build num --- README.md | 4 ++-- Sources/Supporting Files/Info.plist | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a16d501..ec8de00 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@

- Version: 1.3.1 + Version: 1.4.0 CFBundlePackageType FMWK CFBundleShortVersionString - 1.0 + 1.4.0 CFBundleSignature ???? CFBundleVersion