使用 Transifex Native 本地化您的 iOS 应用程序:操作指南

Transifex Native 是一项强大的技术,它允许您通过完全重新定义本地化堆栈,使本地化成为开发生命周期的无缝部分。

从开发人员的角度来看,它以开源 SDK 的形式出现,您可以在几分钟内直接集成到您的代码中。这为您提供了一个高度自动化的本地化流程,该流程围绕易用性和消除不必要的、繁琐的操作而展开,否则这些操作会耗费大量时间和资源。

目录

介绍

Transifex 原生架构

Transifex Native 的技术依赖于3 个不同的部分SDK内容交付服务 (CDS)Transifex 平台本身

每个 SDK,例如iOS SDK,都是应用程序之上的一个薄层。它们的主要目的是提供一种方法来管理应用程序中的本地化挂钩、将内容从应用程序推送到 CDS 并从 CDS 检索翻译的内容以便在应用程序中显示它。

CDS 是一种可以为多个客户端(例如移动设备)快速提供内容的服务。它充当 SDK 和 Transifex 之间的中介。您可以选择使用 Transifex 托管的服务器,也可以使用开源服务器轻松地将其托管在您的基础设施上。

SDK理念

iOS Native SDK 是使用合理的默认值和可扩展性良好的架构构建的。并非所有应用程序都有相同的需求。因此,SDK 允许您提供许多核心组件的自定义实现,例如缓存机制或丢失翻译的处理,或者使用涵盖最常见情况的默认值。即使对于自定义实现,SDK 也提供了丰富的 API 和大量现成的类,以便您可以构建复杂的行为。

它们都是开源的,因此您可以详细了解要添加到应用程序的依赖项,还可以利用社区或将您自己的更新提交到 SDK。

无文件数据交换

Transifex Native 的最大优势之一是它不依赖本地化文件。在 Transifex 方面,Native 使用 FILELESS 资源,而不是 Android XML 文件或 iOS .strings 文件。

CDS 使用 Transifex API 向 Transifex 发送和接收内容作为 FILELESS 有效负载。SDK 使用 CDS API 将内容作为 JSON 有效负载发送到 CDS 以及从 CDS 接收内容。

CDS 和 SDK 都处理内容格式,因此您根本不需要关心内容的结构以及内容将如何到达 Transifex。这使得整个工作流程维护成本低且轻松。

Transifex 设置

在开始集成 SDK 之前,您需要在 Transifex 上创建一个项目。

创建 Transifex 项目

Transifex Native 适用于特殊类型的 Transifex 项目。前往 www.transifex.com/<myorganization>/add/ 创建一个新项目并确保选择“Transifex Native”作为项目类型。

然后单击“立即生成本机凭据”并将您在弹出窗口中看到的令牌和秘密复制到安全的地方。现在您可以继续在您的 iOS 项目中集成 Transifex Native。

提示:如果由于任何原因丢失了密码,您可以从与上述相同的页面生成一对新的令牌/密码。

本地化的基本 iOS 设置Transifex Native

我们将在这篇文章中的所有代码示例中使用 Swift。Transifex Native 还支持开箱即用的 Objective-C;查看自述文件了解详细信息。

注意:SDK 的最低要求是 Swift 5.3、Xcode 12.3 和 MacOS 10.13。

设置 XCode 项目

添加Swift包依赖

在 XCode 上打开您的项目并选择 File > Swift Packages > Add Package Dependency。在输入框中输入 https://github.com/transifex/transifex-swift/ 并选择建议的最新版本

添加语言

转到项目导航器,选择您的项目,然后单击信息。然后,在本地化下,单击添加按钮 (+),然后选择一种语言。对项目中所需的所有语言重复此操作。

初始化 SDK

Transifex Native 需要尽快在应用流程中初始化。更新

application(_:didFinishLaunchingWithOptions:)

函数,添加如下所示的几行。 

现在是时候使用为您的 Transifex 项目生成的令牌了。确保替换的值

sourceLocale

,

locales

token

使用与您的项目相对应的正确值。

导入 Transifex

import Transifex

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let sourceLocale = "en"
        let locales = ["en", "el", "fr_FR", "es_MX"]
        let token = "1/84d1b54ff99b491a2d4c5831412dee8de6983758"

        let localeState = TXLocaleState(sourceLocale: sourceLocale, appLocales: locales)
        TXNative.initialize(locales: localeState, token: token)
        TXNative.fetchTranslations()

        return true
    }
}

获取翻译

请注意,我们正在调用

TXNative.fetchTranslations()

初始化之后。这将开始在后台运行,并将下载您在初始化期间定义的语言环境的所有可用翻译。 

我们建议尽快获取翻译,以便在 UI 首次呈现时在您的应用中可用。如果出于任何原因,您不希望这种情况立即发生,您可以随时致电

TXNative.fetchTranslations()

之后。此外,您可以在每次将应用程序置于前台或建立 Internet 连接时执行此操作

最后,您可以使用完成处理程序调用 fetch 方法,以便在下载翻译时收到通知。例如,您可以显示加载屏幕,直到您的所有资产(包括翻译)都准备好。

添加 TXNativeExtensions

您还需要在项目中复制TXNativeExtensions.swift文件,并将其包含在调用以下任何 Swift 方法的所有目标中:

  • String.localizedStringWithFormat(format:...)
  • NSString.localizedStringWithFormat(format:...)

如果您的应用程序目标都没有调用上述任何方法,那么您不需要将此文件添加到您的项目中。

处理本地化 Transifex Native 的本地化挂钩

适用于 iOS 的 Transifex Native 的设计方式对开发人员来说需要最少的努力。除了您在上面看到的初始化代码之外,无需再做任何事情来在代码或 UI 中指定正确的本地化挂钩。

SDK 与 iOS 本地化框架本身提供的现有挂钩一起工作。例如,它使用以下语句开箱即用:

let localizedString = NSLocalizedString("Welcome!", comment: "Sign up page")
let localizedMinutes = NSLocalizedString("unit-time.%d-minute(s)", comment: "dminutes")
NSString.localizedStringWithFormat(localizedMinutes as NSString, 3)
String.localizedStringWithFormat(localizedMinutes, 3)

初始运行

如果你现在运行你的应用程序,你会发现没有什么不同。但是,所有可翻译的内容都将由 Transifex Native 提供。由于 SDK 尚不知道任何翻译,因此源字符串将用于所有语言。

将源内容推送到 Transifex

将源短语推送到 Transifex 的最常见方法是使用我们构建的 CLI 工具。

通过在 Mac 上运行以下命令来安装 CLI 工具:

git clone git@github.com:transifex/transifex-swift-cli.git
cd transifex-swift-cli
swift build -c release
cp .build/release/txios-cli /usr/local/bin/txios-cli.

现在您可以从任何路径调用 CLI 命令。转到 XCode 项目的根目录并运行:

txios-cli push --token <transifex_token> --secret <transifex_secret> --project MyApp.xcodeproj --verbose

确保将令牌和机密替换为您之前存储的实际值。

该命令的作用是导出提供的 Xcode 项目的基本本地化,解析生成的 XLIFF 文件,将翻译单元转换为 CDS 期望的格式并将它们推送到 CDS,然后再将它们推送到 Transifex。

提示:如果设置了 TRANSIFEX_TOKEN 和 TRANSIFEX_SECRET 环境变量,那么推送命令可以简化为:

txios-cli push --project MyApp.xcodeproj

push 命令支持额外的参数:

  • –dry-run,提取所有字符串而不实际发送任何内容到 CDS/Transifex
  • –append-tags,让您为 Transifex 上推送的字符串定义一个或多个自定义标签

注意:以这种方式推送到 CDS 的所有字符串都存储在 Transifex 上,不会删除任何以前的字符串。这意味着随着时间的推移,Transifex 上的字符串数量只会增加,即使您从 iOS 项目中删除了其中的一些。如果您希望更改此行为,请在README中查找 –purge 选项,但要非常小心,因为您可能会从 Transifex 平台永久删除翻译。

在 Transifex 上翻译内容

此时,您项目中定义的所有源字符串都将到达 Transifex。请注意,这包括在情节提要中找到的字符串。您的翻译团队现在可以开始翻译任何语言环境中的源字符串。如果您正在测试,您可以自己添加一些翻译。最好保留一些未翻译的字符串,以便观察 SDK 如何处理丢失的翻译。

在您的应用程序上显示翻译

前往您的 iOS 设备或模拟器并将系统区域设置更改为源以外的其他区域;例如,fr_FR。现在运行您的应用程序。

第一次这样做时,您会发现没有任何区别。但是,SDK 在后台向 CDS 发出请求,下载所有可用的翻译,并将它们存储在设备上。如果您关闭应用程序并再次运行它,您现在应该会看到所有已翻译的字符串都以法语显示。确保这是一个新的会话,例如,通过停止模拟器并再次运行应用程序

注意:SDK 需要一个会话来下载新内容并需要另一个会话来显示它的原因是,最好不要在显示应用程序内容之前等待翻译,并且不要使用不同的翻译更新 UI,而应用程序正在运行。前者可能会引入不希望的延迟,而后者可能会让用户感到困惑。如果您想要与默认行为不同的行为,您可以通过在初始化期间提供自定义缓存来轻松实现。

您在 Transifex 上未翻译的任何字符串都应以源语言英语显示。这是默认“缺失策略”的行为,但还有更多选择。

如果您更改 Transifex 上的任何翻译并使用新会话再次运行您的应用程序,新的翻译将出现在您的应用程序中,就像那样!

CDS 翻译缓存

为了确保出色的性能,CDS 具有缓存机制,大约 1 小时内不会从 Transifex 获取新鲜内容。如果您想看到新的翻译立即出现在您的应用程序上,您可以通过运行以下命令使缓存无效:

txios-cli invalidate --token <transifex_token>

捆绑翻译

将翻译捆绑在 iOS 应用程序中是很常见的,以确保即使在第一次启动应用程序时没有 Internet 连接,它们也可用。

为了在您的应用程序中捆绑翻译,您可以使用 CLI 工具,如下所示:

txios-cli pull --token <transifex_token> --translated-locales <translated_locale_list> --output <output_directory>

这将从 CDS 下载所有指定语言环境的翻译,并将它们存储在指定输出目录内的 txstrings.json 文件中。这是您将在整个 Transifex Native 流程中与文件交互的唯一情况。

输出目录可以是本地文件系统中的任何目录,最好是 Xcode 项目所在的目录。

下载 txstrings.json 文件后,您必须将其拖放到 Xcode 项目中,确保选择了“添加到目标:”列表中的主应用程序目标,并启用了“如果需要则复制项目”选项。

上述操作只需执行一次,即可将文件包含在应用程序包中。为了确认是这种情况,在 Xcode 中导航到主应用程序目标,然后到“Build Phases”并在“Copy Bundle Resources”部分下,确保包含 txstrings.json 文件。

如果下载了新版本的 txstrings.json 文件,则可以通过用文件系统中的新文件覆盖旧版本的文件来简单地更新现有的捆绑文件,或者只需指定捆绑的 Xcode 项目的目录txstrings.json 驻留在 txios-cli 工具的 pull 命令中。

本地化的高级 iOS 设置Transifex Native

通过执行此处的步骤,您已经设置了一个涵盖所有重要本地化需求的 iOS 应用程序,只需最少的工作量和开箱即用的 Over The Air 支持。如果您想深入了解 SDK 的工作原理并了解如何进一步自定义 SDK 以满足更高级的需求,请继续阅读!

缺少政策

默认情况下,当字符串在所选语言环境中不可用时,将改为显示源字符串。但是,这种行为很容易改变。只需在初始化 SDK 时提供不同的缺失策略。

TXNative.initialize(
    locales: TXLocaleState(sourceLocale: "en", 
                           appLocales: ["en", "el", "fr"]),
    token: "<transifex_token>",
    secret: "<transifex_secret>",
    missingPolicy: TXCompositePolicy(
        TXPseudoTranslationPolicy(),
        TXWrappedStringPolicy(start: "[[", end: "]]")
    )
)

使用上面定义的策略,源字符串“The quick brown fox”将变为“[[Ťȟê ʠüıċǩ ƀȓøẁñ ƒøẋ]]”。

如果现有策略对您来说还不够,您可以轻松创建自己的策略。只需继承 TXMissingPolicy并提供适合您需求的自定义实现。

错误政策

您最不想从 SDK 中得到的就是导致您的应用程序崩溃。iOS SDK 的构建方式实际上使您的应用程序在呈现字符串时 不会崩溃。

默认错误策略将返回原始源字符串。您可以通过继承 TXErrorPolicy轻松创建自己的策略。

缓存

iOS SDK 使用强大的缓存系统,具有广泛的功能、丰富的 API 以及对其行为方式的完全控制。

使用的默认缓存在TXStandardCache中定义,它包括以下功能:

  • 在其核心中,它使用一个 MemoryCache 对象,这意味着下载的翻译存储在运行时内存中。
  • 当应用程序启动时,这个内存缓存会填充在包中找到的任何翻译。之后,如果 SDK 之前下载了任何翻译(并存储在主应用程序的沙箱目录中),则内存缓存将使用这些更新。根据使用的默认 TXCacheUpdatePolicy (replaceAll),从包中加载的所有先前翻译都将被完全删除。
  • 获取新翻译后,它们会存储在应用程序沙箱中,但不会存储在内存缓存中。这可确保它们仅在下一次应用启动时可用,此时上述流程将再次运行。

自定义缓存

如果您的应用需要与上述不同的行为,您可以提供自定义缓存对象。例如,如果您希望使用新下载的翻译立即更新内存缓存,您可以使用以下代码。它与默认实现相同,但删除了 TXReadonlyCacheDecorator 包装(downloadURL、providers 和 updatePolicy 取自 TXStandardCache):

let cache = TXFileOutputCacheDecorator(
    fileURL: downloadURL,
    internalCache: TXProviderBasedCache(
        providers: providers,
        internalCache: TXStringUpdateFilterCache(
            policy: updatePolicy,
            internalCache: TXMemoryCache()
        )
    )
)
TXNative.initialize(locales: localeState, token: token, cache: cache)

此外,还有一个额外的更新策略可供选择,称为updateUsingTranslated。它仅使用具有非空翻译的新条目更新现有缓存,而忽略其余部分。

源翻译

值得一提的是,对于 Native SDK,源语言环境的行为几乎与任何其他语言环境完全相同。这意味着您的翻译人员可以为源语言环境提供新的翻译,SDK 将下载并显示在应用程序中。作为开发人员,您不必关心更新应用程序内的源字符串;相反,翻译人员将负责任何必要的更新,而不是代码。

引擎盖下的 SDK

在这篇文章中讨论的第一件事是安装和使用 Transifex Native iOS SDK 非常简单,除了初始化 SDK 之外,不需要更改代码库。

为了允许开发人员保留标准的 iOS 本地化挂钩,如 NSLocalizedString、String.localizedStringWithFormat(format:…) 和 NSString.localizedStringWithFormat(format:…),SDK 需要做一些魔术。这种魔法的核心是Swizzler

它包含一个在运行时自动激活的 SwizzledBundle 类,它可以调动(即覆盖,猴子补丁)所有由情节提要文件或通过使用 NSLocalizedString() 进行的 localizedString() 调用。swizzled 的本地化String() 方法将所有内容委托给 Native SDK,而不是让它通过 iOS 的本地化框架。

为什么选择 Transifex Native

Transifex 提供了许多不同的方式来与其平台集成。那么,为什么您会选择Native SDK而不是其他东西来本地化您的移动应用程序呢?

轻松安装

开始使用 Transifex Native 非常简单,因为您可以在几分钟内启动并运行所有内容。这可以说是本地化 iOS 应用程序最直接且不那么痛苦的方法。 

专注于真正重要的事情

如您所知,将您的应用程序的新版本发布到 App Store 需要花费大量时间和精力,并且涉及到许多不同的团队和人员。使用 Transifex Native,您不必担心对应用程序内容的翻译所做的更改。通过无线更新,工程团队以外的人员可以与他们的翻译团队一起修复拼写错误或更改内容,而无需打扰您;您可以继续努力在您的应用程序中构建出色的功能。

保持有效的工作流程

一个典型的工程部门有多个团队或多个人在同一个应用程序上工作,通常是从一个主 Git 分支分支出来并并行工作。使用 Transifex Native,您可以像以前一样继续使用功能分支,而不必担心本地化文件中的冲突(请记住,没有带有 Native 的文件!)。

您在应用程序中添加甚至修改的每个字符串都将成为 Transifex 上的新字符串。CLI 工具的 push 命令将始终将字符串附加到 Transifex,从不替换现有字符串。所以每个团队或个人都可以做自己的工作,而不必担心影响其他人的工作或引入冲突。

早点发布,晚点翻译

因为您可以根据需要尽早将新的源字符串推送到 Transifex,本地化团队可以根据需要尽早开始翻译过程。他们不一定要等到您的拉取请求被合并,直到质量检查完成,甚至直到一个特性的所有字符串都被添加到应用程序中;他们可以在他们认为合适的时候开始翻译,从而减少潜在发布的瓶颈。

另一方面,您的团队不必等到某个语言环境的所有字符串都 100% 翻译后才发布到 App Store。他们可以继续发布应用程序,翻译人员可以在此过程的后期完成他们的工作,因为内容将通过无线方式到达。

扩展您的需求

构建 Native SDK 架构的人希望确保它允许您自定义所有重要部分。有很多现成的东西可供选择,但 SDK 的 API 可让您轻松构建自己的功能。

此外,Transifex Native 的开源性质和广泛的文档使您可以轻松地深入研究其代码、进行更改并将其贡献给社区。

下一步在哪里

这篇文章应该可以帮助您开始使用 Transifex Native for iOS。有关更多信息,您可以查看大量文档。我们很乐意回答您的任何问题并在GitHub 上查看您的 PR !

这篇文章的作者是 Dimitrios Bendilas。

localize-your-ios-applications-with-transifex-native-a-how-to-guide-tn3w37hi