macOS 开发之本地化工具 bartycrouch 4 使用教程

前些日子写了三篇关于 macOS app 本地化的文章,在文章中用到了一个名为 bartycrouch 的工具,当时十里安装的 bartycrouch 版本是 v3.13.3,昨天升级了 bartycrouch 现在是 v4.0.0 ,发现使用方法变化还挺大,所以赶快在前面三篇文章中标注了一下版本使用问题,本文简单介绍一下 bartycrouch 4 的使用。

开发平台

  • macOS 10.14.3
  • swift 4.2.1
  • xcode 10.1

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 60+ 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.

BartyCrouch

bartycrouch 可以依据 interfaces 文件( xib 文件) 和代码(swift 、m、h 文件)来增量更新 strings 文件。在这里 增量 是指 bartycrouch 会默认保留已经翻译的值及改变了的注释。另外您也可使用 bartycrouch 借助微软的服务从一种语言机器翻译成超过 60+ 种语言。在命令行调用几个简单的命令您就可以轻而易举的使用 bartycrouch,另外您也可以在 xcode 的工程配置中添加运行脚本自动化使用 bartycrouch 完成您期望的任务。

依赖

  • Xcode 10.1+
  • Swift 4.2+
  • Xcode Command Line Tools (详见:点我)

安装方法

使用 [Homebrew](https://brew.sh/) 安装

通过下面的命令可以很容易安装 bartycrouch:

brew install bartycrouch

另外可以通过下面的命令更新 bartycrouch,保证一直使用最新保本:

brew upgrade bartycrouch
通过 [Mint](https://github.com/yonaskolb/Mint) 安装

通过以下命令就可以安装 bartycrouch(目前通过这种方式会出现缺少动态库的问题,估计很快就会修复了,所以建议使用 homebrew 安装的方式):

mint install Flinesoft/BartyCrouch

bartycrouch 使用

这里提醒一下,如果您直接用一个现有的工程尝试这个工具的话,以防万一请先用 git 提交 一下您的代码,尽量保证安全,另外这里强烈建议如果研究明白怎么用了后使用为 xcode 创建编译脚本 的方式使用 bartycrouch。

在命令行下,先执行一下 bartycrouch -h

$ bartycrouch -h

Usage: bartycrouch <command> [options]

Incrementally update & translate your Strings files from code or interface files.

Commands:
  init            Creates the default configuration file & creates a build script if Xcode project found
  update          Update your .strings file contents with the configured tasks (default: interfaces, code, normalize)
  lint            Lints your .strings file contents
  help            Prints help information
  version         Prints the current version of this app
  • help: 打印帮助信息,也就是上面,bartycrouch -h 等同于 bartycrouch help
  • version: 打印当前 bartycrouch 的版本号

下面以 bartycrouch 正常的使用流程分别讲一下 init updatelint 三个命令。

init 命令

这个命令用于生成针对 Xcode 工程的 bartycrouch 配置文件。进入到 xcode 的根目录,执行以下命令:

bartycrouch init

工程根目录下会出现名为 .bartycrouch.toml 的文件。

`.bartycrouch.toml` 默认内容
[update]
tasks = ["interfaces", "code", "transform", "normalize"]

[update.interfaces]
path = "."
defaultToBase = false
ignoreEmptyStrings = false
unstripped = false

[update.code]
codePath = "."
localizablePath = "."
defaultToKeys = false
additive = true
unstripped = false

[update.transform]
codePath = "."
localizablePath = "."
transformer = "foundation"
supportedLanguageEnumPath = "."
typeName = "BartyCrouch"
translateMethodName = "translate"

[update.normalize]
path = "."
sourceLocale = "en"
harmonizeWithSource = true
sortByKeys = true

[lint]
path = "."
duplicateKeys = true
emptyValues = true

在这个配置文件中包含了另外两个命令( update 和 lint )的相关配置,这是 bartycrouch 的默认配置,应该可以在绝大多数工程中使用,但是这里需要注意以下几点:

  • [update] 的值就代表了,执行 bartycrouch update 时要完成的任务,不想执行某个任务可以直接删除,比如不执行 code 任务,可以写成:
[update]
tasks = ["interfaces", "transform", "normalize"]
  • 每个任务子项中都包含了对应的配置信息,可依据工程需要进行调整,具体含义可以参考后面任务的介绍

  • 尽可能为包含关键字的 path 键提供具体的路径名称 (例如:codePath 设置为包含 swift 代码文件的目录)

  • 如果您的工程是纯 swift 实现并且使用了 update 命令的的 tranform 任务,可以删除 code 任务

  • 如果您正在使用支持 structured-swift4 模板的 SwiftGen ,您需要将 [update.transform]transformerfoundation 改为 swiftgenStructured

  • 如果您要使用 transform 任务,需要在工程中创建一个新文件,命名为 BartyCrouch.swift,内容如下:

`BartyCrouch.swift` 代码
//
//  This file is required in order for the `transform` task of the translation helper tool BartyCrouch to work.
//  See here for more details: https://github.com/Flinesoft/BartyCrouch
//

import Foundation

enum BartyCrouch {
    enum SupportedLanguage: String {
        // TODO: remove unsupported languages from the following cases list & add any missing languages
        case arabic = "ar"
        case chineseSimplified = "zh-Hans"
        case chineseTraditional = "zh-Hant"
        case english = "en"
        case french = "fr"
        case german = "de"
        case hindi = "hi"
        case italian = "it"
        case japanese = "ja"
        case korean = "ko"
        case malay = "ms"
        case portuguese = "pt-BR"
        case russian = "ru"
        case spanish = "es"
        case turkish = "tr"
    }

    static func translate(key: String, translations: [SupportedLanguage: String], comment: String? = nil) -> String {
        let typeName = String(describing: BartyCrouch.self)
        let methodName = #function

        print(
            "Warning: [BartyCrouch]",
            "Untransformed \(typeName).\(methodName) method call found with key '\(key)' and base translations '\(translations)'.",
            "Please ensure that BartyCrouch is installed and configured correctly."
        )

        // fall back in case something goes wrong with BartyCrouch transformation
        return "BC: TRANSFORMATION FAILED!"
    }
}
  • 如果您的第一语言不是英语, 您需要将 normalize 任务的 sourceLocale 改为您的第一语言,值参考上面代码中的枚举 SupportedLanguage 的元素

  • 如果您想使用 bartycrouch 的翻译功能,需要将如下的配置添加到 .bartycrouch.toml 中,并且将 translate 添加到任务列表中,其中您需要将 secret 的值替换成您的 Microsoft Translator Text API Subscription Key:

[update.translate]
path = "."
secret = "<#Subscription Key#>"
sourceLocale = "en"

update 命令

update 命令可以执行以下几个任务:

  • interfaces: 从 Storyboards & XIBs 更新 .strings 文件
  • code: 根据代码中的 NSLocalizedString 调用更新 Localizable.strings
  • transform: 仅支持 swift 文件,可以替换特定方法的调用替换为可以提供多种语言翻译的单行方式
  • translate: 从指定语言翻译成多种语言并替换结果到 strings 文件中
  • normalize: 格式化 .strings 文件内容:排序或者清楚多余内容

上面已经提到过的,可以通过 .bartycrouch.tomltask 配置要执行的任务:

[update]
tasks = ["interfaces", "code", "transform", "normalize"]

任务配置项介绍

`interfaces` 配置项含义
  • path: 查找 Storyboards & XIB 文件的路径
  • defaultToBase: 添加 Base translation 作为新键的值
  • ignoreEmptyStrings: 不添加 views 中是空值的项
  • unstripped: 保留 Strings 文件开始和结尾的空白字符串
`code` 配置项含义
  • codePath: 查找 Swift 代码文件的路径
  • localizablePath: 包含 Localizable.strings 文件的目录的父目录
  • defaultsToKeys: 为新键添加与新键名称一致的值
  • additive: 不清除未在代码中发现的键
  • customFunction: 替代 NSLocalizedString 的函数名称
  • customLocalizableName: 替代 Localizable.strings 的文件的名称
  • unstripped: 保留 Strings 文件开始和结尾的空白字符串
`transform` 配置项含义
  • codePath: 查找 Swift 代码文件的路径
  • localizablePath: 包含 Localizable.strings 文件的目录的父目录
  • transformer: 指定转换的模式: 若调用 NSLocalizedString 接口,值就设成 foundation; 若调用 L10n 形式的接口,值就设成 swiftgenStructured
  • supportedLanguageEnumPath: 包含 SupportedLanguage 枚举定义的 swift 文件的路径
  • typeName: 包含 SupportedLanguage 枚举和翻译方法的类型名称
  • translateMethodName: 翻译方法的名称
  • customLocalizableName: 替代 Localizable.strings 的文件的名称
`translate` 配置项含义
`normalize` 配置项含义
  • path: 查找 .strings 文件的路径
  • sourceLocale: 指定依照哪种语言对其他语言的 string 文件进行格式化
  • harmonizeWithSource: 同步键值对的源语言
  • sortByKeys: 按照字母顺序对键进行排序

transform 任务

如果配置文件中配置了 transform 任务(详见 init 命令)并且已经在 xcode 中创建编译脚本, 在开发中您可以使用下面简化的流程编写本地化代码:

  • 您可以使用 BartyCrouch.translate 替代 NSLocalizedString 指定键、翻译方法和注释,例如:
self.title = BartyCrouch.translate(key: "onboarding.first-page.header-title",  translations: [.english: "Welcome!"])
  • 编译应用的时候, BartyCrouch 会自动向所有的 Localizable.strings 文件中添加您指定的键,并且为指定语言的键添加指定语言翻译结果

  • 同时 BartyCrouch 会自动依据配置中指定的 transformer 替换上面 BartyCrouch.translate 的调用为对应的方法

    • transformer 设置为 foundation, 上面 BartyCrouch.translate 的调用会替换为如下的结果:

      self.title = NSLocalizedString("onboarding.first-page.header-title", comment: "")
      
    • transformer 设置为 swiftgenStructured, 上面 BartyCrouch.translate 的调用会替换为如下的结果:

      self.title = L10n.Onboarding.FirstPage.headerTitle
      
使用 transform 的优点:
  • 不用为了添加翻译的键值而不断的切换不同语言的 Strings 文件
  • 一旦使用了 SwiftGen, 不需要手动替换 NSLocalizedStringL10n 的调用了
  • 与机器翻译配合使得只需在代码中使用一行代码就可以实现所有语言的翻译和值的替换
使用 transform 的缺点:
  • 只支持 swift 代码而不支持 Objective-C
  • 在下次编译之前,xcode 会有一些错误提示,但是一编译就会没有了错误提示
  • 由于 SwiftSyntax 当前运行不是特别快所以看上去不如 code 任务快速. (但是这个会随着时间改善!)

lint 命令

lint 命令可以检查 .strings 文件,主要有下面两个检查项:

  • duplicateKeys: 查找同一个文件中重复的键值对
  • emptyValues: 查找空值的键值对

创建编译脚本

为了让 xcode 可以使用 bartycrouch 来更新和检查您的 .strings 文件,您可以添加一个编译脚本实现。

按照下图所示步骤添加脚本:

脚本内容(点我查看)
if which bartycrouch > /dev/null; then
    bartycrouch update -x
    bartycrouch lint -x
else
    echo "warning: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch"
fi

下一步确保这个运行脚本在 Compiling SourcesSwiftGen(如果使用了的话) 之前运行,比如在 Target Dependencies 后面,像下图这样:

现在每次运行工程,都会自动的更新和检查 .strings 文件,而不用手动处理了。另外如果工程的成员如果没有安装 bartycrouch 的脚本会产生警告:

warning: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch

另外补充的是,lint 和 update 有以下三个参数可用:

  • -v, --verbose: 打印更多的执行信息
  • -x, --xcode-output: 以 xcode 兼容的形式呈现错误和提醒,在 xcode 中的运行脚本中添加以后,一旦检查出错误或警告会在 xcode 的 issue 导航栏中呈现
  • -w, --fail-on-warnings: 遇到警告的时候返回对应代码