Skip to content

Commit

Permalink
Merge branch 'deploy/1.4.0' into productive
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeehut committed Mar 14, 2016
2 parents 0fdd025 + 211ee8f commit 2c0dbbe
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 73 deletions.
102 changes: 63 additions & 39 deletions BartyCrouch CLI/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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."
)

Expand Down Expand Up @@ -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.findAll(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.findAll(inputFilePath).filter { $0 != inputFilePath }
case .Except:
return StringsFilesSearch.sharedInstance.findAll(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)
}

}

}
Expand Down
66 changes: 36 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<p align="center">
<img src="https://raw.githubusercontent.com/Flinesoft/BartyCrouch/develop/Logo.png"
<img src="https://raw.githubusercontent.com/Flinesoft/BartyCrouch/stable/Logo.png"
width=600 height=167>
</p>

<p align="center">
<a href="https://github.com/Flinesoft/BartyCrouch/releases">
<img src="https://img.shields.io/badge/version-1.3.0-blue.svg"
alt="Version: 1.3.0">
<img src="https://img.shields.io/badge/Version-1.4.0-blue.svg"
alt="Version: 1.4.0">
</a>
<a href="#">
<img src="https://img.shields.io/badge/Swift-2.1-DD563C.svg"
alt="Swift: 2.1">
</a>
<a href="https://github.com/Flinesoft/BartyCrouch/blob/develop/LICENSE.md">
<img src="https://img.shields.io/badge/license-MIT-lightgrey.svg"
<a href="https://github.com/Flinesoft/BartyCrouch/blob/stable/LICENSE.md">
<img src="https://img.shields.io/badge/License-MIT-lightgrey.svg"
alt="License: MIT">
</a>
</p>
Expand Down Expand Up @@ -60,11 +60,11 @@ 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
# 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
Expand All @@ -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`).
Expand Down Expand Up @@ -126,34 +132,34 @@ 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
```
<img src="Build-Script-Example.png">

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.
*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** too then simply add the following to the if part:

```
# 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**.
Expand Down
13 changes: 12 additions & 1 deletion Sources/Code/StringsFilesSearch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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(".")
Expand Down
2 changes: 1 addition & 1 deletion Sources/Supporting Files/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.4.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
17 changes: 15 additions & 2 deletions Tests/Code/StringsFilesSearchTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 2c0dbbe

Please sign in to comment.