Localization/I18n: Incrementally update your Strings files from .swift, .h, .m(m), .storyboard or .xib files.
Swift Other

README.md

Build Status codebeat badge Version: 3.13.1 Swift: 4 License: MIT

InstallationUsageBuild ScriptMigration GuidesIssuesContributingLicense

BartyCrouch

BartyCrouch incrementally updates your Strings files from your Code and from Interface Builder files. "Incrementally" means that BartyCrouch will by default keep both your already translated values and even your altered comments. Additionally you can also use BartyCrouch for machine translating from one language to 40+ other languages. Using BartyCrouch is as easy as running a few simple commands from the command line what can even be automated using a build script within your project.

Requirements

  • Xcode 9 and Swift 4
  • Xcode Command Line Tools (see here for installation instructions)

Installation

Using Homebrew:

Install Homebrew first if you don't have it already (more about Homebrew here):

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Bartycrouch now is part of Homebrew Core! No tap needed any more.

If you had installed a previous version (<= 3.8.0) via the tap, you should run the following once:

$ brew untap flinesoft/bartycrouch

To install Bartycrouch the first time, simply run the command:

$ brew install bartycrouch

To update to the newest version of BartyCrouch when you have an old version already installed run:

$ brew update
$ brew upgrade bartycrouch

Using CocoaPods:

Simply add the following line to your Podfile:

pod 'BartyCrouch'

Usage

Before using BartyCrouch please make sure you have committed your code.

Complete Examples (TL;DR)

With BartyCrouch you can run commands like these:

# Incrementally updates all Strings files of Storyboards/XIBs in project
$ bartycrouch interfaces -p "/absolute/path/to/project"

# Updates `Localizable.strings` files with new keys searching your code for `NSLocalizedString`
$ bartycrouch code -p "/path/to/code/directory" -l "/directory/containing/all/Localizables" -a

# Machine-translate all empty localization values using English as source language
$ bartycrouch translate -p "/path/to/project" -l en -i "<API_ID>" -s "<API_SECRET>"

# Normalize your Strings files to keep them nice and clean
$ bartycrouch normalize -p "/path/to/project" -l en -d -w -h -s

# Lint your Strings files to check if they are nice and clean
$ bartycrouch lint -p "/path/to/project" -d -e

Also you can make your life a lot easier by using the build script method described below.


Sub Commands Overview

The bartycrouch main command accepts one of the following sub commands:

  • interfaces: Incrementally updates Strings files of localized Storyboards and XIBs.
  • code: Incrementally updates Localizable.strings files from .h, .m and .swift files.
  • translate: Machine-translates values from a source Strings file to all other languages.
  • normalize: Normalizes Strings files with configurable options to keep them nice and clean.
  • lint: Lint your Strings files to check if they are nice and clean.

Note that each sub command accepts a different set of options. Some of them are required and some optional. You can combine all options with each other to create your own expected behavior. If you're not sure which options are available or required you can always look them up in terminal by running a sub command without options like so:

$ bartycrouch code

Missing required options: ["-p, --path", "-l, --localizables"]

Usage: /usr/local/bin/bartycrouch [options]
  -p, --path:
      Set the base path to recursively search within for code files (.h, .m, .mm, .swift).
  -l, --localizables:
      The path to the folder of your output `Localizable.strings` file to be updated.
  ...

Important Notice: Please make sure you always localize all localizable files in all the languages you support in your project. Otherwise BartyCrouch might not work as expected. If you don't need to localize a Storyboard (like the LaunchScreen) then you should simply unlocalize the screen entirely so it doesn't appear even in Base.lproj.


Options for all Sub Commands

Some options are common to all sub commands and must (if required) or can always be specified.

Path (aka -p, --path) required

For each command BartyCrouch needs to know where it should search for files to do its work. This is done by providing an absolute path to a directory using -p.

Example:

# Finds all Storyboard / XIB files within the specified path as input
$ bartycrouch interfaces -p "/Users/Name/DemoProject/Sources"

Override (aka -o, --override) optional

BartyCrouch keeps non-empty values by default so nothing gets lost (except for keys which are no longer used). If you want to override all your existing translation values you can force BartyCrouch to do this by specifying the -o command.

Example:

# Clears all values of Storyboards / XIBs Strings files
$ bartycrouch interfaces -p "/path/to/project" -o

Verbose (aka -v, --verbose) optional

If you want to know exactly which files BartyCrouch found and updated you can specify the -v command to see a more verbose output.

Example:

$ bartycrouch interfaces -p "/path/to/project" -v

Incrementally updated keys of file '/path/to/project/de.lproj/Main.strings'.
Incrementally updated keys of file '/path/to/project/en.lproj/Main.strings'.
Incrementally updated keys of file '/path/to/project/fr.lproj/Main.strings'.
BartyCrouch: Successfully updated strings file(s) of Storyboard or XIB file.

Options for interfaces

Here's an overview of all options available for the sub command interfaces:

Default to Base (aka -b, --default-to-base) optional

To use the Base localization values when adding new keys (instead of empty values) simply add the option -b.

Example:

$ bartycrouch interfaces -p "/path/to/project" -b

Unstripped (aka -u, --unstripped) optional

If you use any service or other tool that alters your Strings files and if BartyCrouch seems to change the beginning and ends of those files due to different whitespacing/newline conventions, then you can simply use the -u command to keep the beginning and end as they are. By default BartyCrouch adds exactly one line to both the beginning and end of a file. Note that this option keeps up to 10 newline/whitespace characters from the original file at both beginning and end.

Example:

$ bartycrouch interfaces -p "/path/to/project" -u

Options for code

Here's an overview of all options available for the sub command code:

  • path (required), override and verbose (see Options for all Sub Commands above)
  • localizable (required)
  • default-to-keys
  • additive
  • override-comments
  • extract-loc-strings
  • sort-by-keys
  • unstripped
  • custom-function
  • custom-localizable-name

Localizable (aka -l, --localizable) required

Specifies the path to the directory which contains all Localizable.strings files within <locale>.lproj folders. BartyCrouch will search for all files named Localizable.strings recursively within the specified path and incrementally update them. Make sure to specify a path with only your projects Localizable.strings files.

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/Users/Name/DemoProject/Sources/Supporting Files"

Default to Keys (aka -k, --default-to-keys) optional

To use the keys as localization values when adding new keys (instead of empty values) simply add the option -k.

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/localizables" -k

Additive (aka -a, --additive) optional

To prevent BartyCrouch from deleting (seemingly) unused keys you can configure it to only add new keys keeping all existing ones by providing the option -a. This can be useful for example when you want to generate your Localizable.strings using BartyCrouch but use static strings (e.g. with Laurine) once they are added to your Localizables.

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/localizables" -a

Override Comments (aka -c, --override-comments) optional

If you want to override all your existing translations comments you can enforce this by specifying the -c command.

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/localizables" -c

ExtractLocStrings (aka -e, --extract-loc-strings) optional

If you are using the NSLocalizedString macro with more than two arguments (NSLocalizedString(key:tableName:bundle:value:comment:)) then you should specify the -e command to use the successor of the genstrings command line tool which BartyCrouch uses to extract localizable strings from code files by default. The newer extractLocStrings command will be used then instead.

Note that we are planning to make this the default behavior after testing it in practice with a major BartyCrouch upgrade (version 4.0+) in the near future – if you encounter any problems please open an issue!

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/localizables" -e

Sort by Keys (aka -s, --sort-by-keys) optional

If you want the order of translations in your resulting Localizable.strings file to be alphabetically sorted by their keys (instead of simply adding new keys to the end and keeping them in that order forever) just use the option -s. To ensure that you can still easily find your untranslated keys this option will check the value of your translations and place those without a translation at the end of the file. Once you translated those entries they will be correctly sorted amongst the translated keys on the next run of BartyCrouch.

Example:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/localizables" -s

Unstripped (aka -u, --unstripped) optional

If you use any service or other tool that alters your Strings files and if BartyCrouch seems to change the beginning and ends of those files due to different whitespacing/newline conventions, then you can simply use the -u command to keep the beginning and end as they are. By default BartyCrouch adds exactly one line to both the beginning and end of a file. Note that this option keeps up to 10 newline/whitespace characters from the original file at both beginning and end.

Example:

$ bartycrouch interfaces -p "/path/to/project" -u

Custom Function (aka -f, --custom-function) optional

If you use a custom function in your code to localize your Strings (instead of NSLocalizedString) you can specify it using this option. BartyCrouch passes this along to the genstrings/extractLocStrings tools. So you need to make sure your custom function follows the requirements of genstrings/extractLocStrings.

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/Localizables" -f "YourCustomFunction"

Custom Localizable Name (aka -n, --custom-localizable-name) optional

If you want to use a different name for your Localizable.strings file for whatever reason, you can specify a custom name using this option like this:

$ bartycrouch code -p "/path/to/code/files" -l "/path/to/Localizables" -n "MyCustomLocalizable"

Options for translate

Here's an overview of all options available for the sub command translate:

ID and Secret (aka -i and -s, --id and --secret) required

BartyCrouch acts as a client for the Microsoft Translator API. In order to use that API you need to register here (the free tier allows for 2 million translations/month). Then you can add a client here which will provide you the id and secret credentials required for machine-translation.

Example:

$ bartycrouch translate -p "/path/to/project" -l en -i "<YOUR_API_ID>" -s "<YOUR_API_SECRET>"

Locale (aka -l, --locale) required

This specifies the source language to use as the input for machine-translation. BartyCrouch can only translate keys which have a value in their source language.

Example:

# Uses Simpliied Chinese as the source language for translating to all other languages
$ bartycrouch translate -p "/path/to/project" -l "zh-Hans" -i "<API_ID>" -s "<API_SECRET>"

Options for normalize

Here's an overview of all options available for the sub command normalize:

  • path (required), override and verbose (see Options for all Sub Commands above)
  • locale (required)
  • prevent-duplicate-keys
  • warn-empty-values
  • harmonize-with-source
  • sort-by-keys

Locale (aka -l, --locale) required

Specify the source locale from which to normalize other languages Strings files (.strings).

Example:

$ bartycrouch normalize -p "/path/to/code/files" -l en

Prevent Duplicate Keys (aka -d, --prevent-duplicate-keys) optional

Warns if Strings files contain duplicate keys or removes duplicates automatically if values are equal.

Example:

$ bartycrouch normalize -p "/path/to/code/files" -l en -d

Warn Empty Values (aka -w, --warn-empty-values) optional

Warns if Strings files contain keys with empty values. Designed to be used as part of Xcode build scripts.

Example:

$ bartycrouch normalize -p "/path/to/code/files" -l en -w

Harmonize with Source (aka -h, --harmonize-with-source) optional

Makes sure all languages have exactly the same keys as the source language specified with -l. This command will remove all keys from target languages files which don't appear in the source language file. And vice versa it also adds keys to target language files that are missing compared to the source language file.

Example:

$ bartycrouch normalize -p "/path/to/code/files" -l en -h

Sort by Keys (aka -s, --sort-by-keys) optional

If you want the order of translations in your Strings files to be alphabetically sorted by their keys just use the option -s. To ensure that you can still easily find your untranslated keys this option will check the value of your translations and place those without a translation at the end of the file. Once you translated those entries they will be correctly sorted amongst the translated keys on the next run of BartyCrouch.

Example:

$ bartycrouch normalize -p "/path/to/code/files" -l en -s

Options for lint

Here's an overview of all options available for the sub command lint:

Duplicate Keys (aka -d, --duplicate-keys) optional

Fails if any Strings file contains duplicate keys. Designed to be used as part of a CI service.

Example:

$ bartycrouch lint -p "/path/to/code/files" -d

Empty Values (aka -e, --empty-values) optional

Fails if any Strings file contains a key with an empty value. Designed to be used as part of a CI service.

Example:

$ bartycrouch lint -p "/path/to/code/files" -e

Build Script

You may want to update your Strings files on each build automatically what you can easily do by adding a run script to your target in Xcode. In order to do this select your target, choose the Build Phases tab and click the + button on the top left corner of that pane. Select New Run Script Phase and copy the following into the text box below the Shell: /bin/sh of your new run script phase:

if which bartycrouch > /dev/null; then
    # Incrementally update all Storyboards/XIBs strings files
    bartycrouch interfaces -p "$PROJECT_DIR"

    # Add new keys to Localizable.strings files from NSLocalizedString in code
    bartycrouch code -p "$PROJECT_DIR" -l "$PROJECT_DIR" -a -s
else
    echo "warning: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch"
fi

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 in addition then simply use the following build script instead:

if which bartycrouch > /dev/null; then
    # Incrementally update all Storyboards/XIBs strings files
    bartycrouch interfaces -p "$PROJECT_DIR"

    # Add new keys to Localizable.strings files from NSLocalizedString in code
    bartycrouch code -p "$PROJECT_DIR" -l "$PROJECT_DIR" -a -s

    # Translate all empty values using the Microsoft Translator API
    bartycrouch translate -p "$PROJECT_DIR" -l en -i "<API_ID>" -s "<API_SECRET>"
else
    echo "warning: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch"
fi

It is recommended that you update the -p "$PROJECT_DIR" appearances in this script to point to the directory of your own code only, for example by using -p "$PROJECT_DIR/Sources" instead. Also you should alter -l "$PROJECT_DIR" to a path more specific (e.g. -l "$PROJECT_DIR/Sources/Supporting Files"). This is to make sure BartyCrouch doesn't change any Localizable.strings files within frameworks included using the likes of Carthage or CocoaPods.

Alternatively, if you've installed BartyCrouch via CocoaPods the script should look like this:

"${PODS_ROOT}/BartyCrouch/bartycrouch" interfaces -p "$PROJECT_DIR"

Exclude specific Views / NSLocalizedStrings from Localization

Sometimes you may want to ignore some specific views containing localizable texts e.g. because their values are gonna be set programmatically. For these cases you can simply include #bartycrouch-ignore! or the shorthand #bc-ignore! into your value within your base localized Storyboard/XIB file. Alternatively you can add #bc-ignore! into the field "Comment For Localizer" box in the utilities pane.

This will tell BartyCrouch to ignore this specific view when updating your .strings files.

Here's an example of how a base localized view in a XIB file with partly ignored strings might look like:

Here's an example with the alternative comment variant:

You can also use #bc-ignore! in your NSLocalizedString macros comment part to ignore them so they are not added to your Localizable.strings. This is helpful when you are using a .stringsdict file to handle pluralization (see docs).

For example you can do something like this:

func updateTimeLabel(minutes: Int) {
  String.localizedStringWithFormat(NSLocalizedString("%d minute(s) ago", comment: "pluralized and localized minutes #bc-ignore!"), minutes)
}

The %d minute(s) ago key will be taken from Localizable.stringsdict file, not from Localizable.strings.

Migration Guides

This project follows Semantic Versioning.

Please follow the appropriate guide below when upgrading to a new major version of BartyCrouch (e.g. 1.5 -> 2.0).

Upgrade from 2.x to 3.x

  • Change structure bartycrouch -s "$BASE_PATH" to bartycrouch interfaces -p "$BASE_PATH"
  • Change structure bartycrouch -t "{ id: <API_ID> }|{ secret: <API_SECRET> }" -s "$BASE_PATH" -l en to bartycrouch translate -p "$BASE_PATH" -l en -i "<API_ID>" -s "<API_SECRET>"
  • Use automatic file search with -p (was -s before) instead of options -i, -o, -e (those were deleted)
  • Rename usages of option "force" (-f) to be "override" (-o)

It is recommended to update your build script to the currently suggested one if you were using it.

Upgrade from 1.x to 2.x

  • Change command structure bartycrouch "$BASE_PATH" -a to bartycrouch -s "$BASE_PATH"
  • Remove -c option if you were using it, BartyCrouch 2.x creates missing keys by default
  • Use the new -t -s -l options instead of adding all Strings files manually, e.g.:

Simplify this build script code

bartycrouch -t $CREDS -i "$EN_PATH/Localizable.strings" -a -c
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

by replacing it with this:

bartycrouch -t "$CREDS" -s "$PROJECT_DIR" -l en

Upgrade from 0.x to 1.x

  • --input-storyboard and -in were renamed to --input and -i
  • --output-strings-files and -out were renamed to --output and -o
  • Multiple paths passed to -output are now separated by whitespace instead of comma
    • e.g. -out "path/one,path/two" should now be -o "path/one" "path/two"
  • --output-all-languages and -all were renamed to --auto and -a

Contributing

Contributions are welcome. Please just open an Issue on GitHub to discuss a point or request a feature there or send a Pull Request with your suggestion.

When sending a pull request please also make sure to:

  • write tests for your changes in order to make sure they don't break in the future
  • follow the same syntax and semantic in your commit messages (see rationale here)

Note that there is a framework target within the project to make testing easier.

License

This library is released under the MIT License. See LICENSE for details.