在 iOS SDK 中使用本地化和语言区域代码
为什么这很重要
当 Adapty 为流程或用户引导选择本地化版本,以及当你为自定义付费墙读取远程配置时,都会用到语言区域代码。
语言区域代码较为复杂,且在不同平台上可能存在差异,因此 Adapty 在其所支持的所有平台上统一采用一套内部标准。了解这一标准,有助于你预判用户将收到哪个本地化版本。
Adapty 的区域代码标准
对于区域代码,Adapty 使用略经修改的 BCP 47 标准:每个代码由小写子标签组成,以连字符分隔。示例:en(英语)、pt-br(葡萄牙语(巴西))、zh(简体中文)、zh-hant(繁体中文)。
语言区域代码匹配
在 SDK v4 中,流程与用户引导的语言区域代码匹配方式不同:流程由 SDK 在设备端本地化,而用户引导则由 Adapty 服务器负责本地化。
流程与付费墙编辑工具构建的付费墙
在 SDK v4 中,用付费墙编辑工具构建的付费墙会以流程的形式下发,因此下面的规则同时适用于两者。
匹配规则是严格精确的。SDK 会将你传入的代码与流程的本地化代码逐字符比对:不会转换大小写,不会将下划线(_)替换为连字符(-),也不会回退到语言子标签。对于带有 pt-br 本地化的流程,只有 pt-br 能匹配成功:pt-BR、pt_BR 和 pt-PT 均无法命中。
当代码未匹配到任何本地化时,流程会以其默认语言环境静默渲染——SDK 不会返回错误,也不会记录警告。
当代码匹配成功时,Adapty 会将该本地化与默认本地化合并:匹配到的本地化中未定义的字符串和资源,将从默认本地化中获取。
省略语言区域代码与请求流程的默认本地化不同:SDK 会固定替换为 en。若一个流程的默认语言区域为 de,但同时存在 en 本地化版本,则仍会以 en 渲染;只有在没有 en 本地化时,才会回退到 de。
请严格按照看板中配置的格式传递语言区域代码——小写子标签之间用连字符分隔。请勿直接传递系统语言区域标识符:Locale.current.identifier 返回 pt_BR,Locale.current.identifier(.bcp47) 返回 pt-BR,两者都会回退到默认本地化。请在传递之前在应用中转换该值。
用户引导
用户引导在服务端进行本地化,服务端规则支持多种格式。当你向 getOnboarding 传入 locale 时:
- locale 字符串会被转换为小写,并将所有下划线(
_)替换为连字符(-) - Adapty 会查找与完整 locale 代码完全匹配的本地化内容
- 如果未找到匹配项,Adapty 会截取第一个连字符之前的子字符串(例如
pt-br取pt),并查找匹配的本地化内容 - 如果仍未找到匹配项,Adapty 将返回该用户引导默认 locale 的内容
这样,pt_BR、pt-BR 和 pt-br 都会解析到同一个用户引导本地化内容。
实现本地化
在 SDK v4 中,获取流程时无需传入语言区域代码——getFlow 会返回包含所有本地化内容的流程。
- 在编辑工具中构建的流程:SDK 不会读取设备语言设置,因此请在应用中自行解析并通过
AdaptyUI.getFlowConfiguration(forFlow:locale:)传入。该参数为可选项——省略后流程将以en渲染,若流程没有en本地化,则使用其默认语言。 - 自定义(远程配置)付费墙:
getFlow会在flow.remoteConfigs中返回所有已配置的本地化版本。每条记录包含locale代码和配置内容(jsonString或已解析的dictionary)。请自行实现回退逻辑,选择与用户匹配的记录:
do {
let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
let config = flow.remoteConfigs.first(where: { $0.locale == "en" })
?? flow.remoteConfigs.first
// read your values from config?.dictionary
} catch {
// handle the error
}Adapty 以 Adapty 中的语言区域代码标准 中描述的格式存储 locale 代码。SDK 不会将远程配置与语言区域进行匹配,因此具体应用哪个条目由您的应用自行决定。
为什么这很重要
有几种场景会涉及到语言区域代码——例如,当你需要为应用当前的本地化版本获取正确的付费墙时。
由于语言区域代码比较复杂,且在不同平台之间可能存在差异,我们为所有支持的平台制定了统一的内部标准。正因为这些代码较为复杂,你必须清楚地了解自己向服务器发送的具体内容,以及服务器如何处理这些内容——这样才能确保每次都能收到预期的本地化结果。
Adapty 中的区域代码标准
在区域代码方面,Adapty 使用略经修改的 BCP 47 标准:每个代码由小写子标签组成,以连字符分隔。示例:en(英语)、pt-br(葡萄牙语(巴西))、zh(简体中文)、zh-hant(繁体中文)。
语言区域代码匹配
当 Adapty 收到来自客户端 SDK 的语言区域代码请求,并开始查找付费墙对应的本地化版本时,会按以下步骤处理:
- 传入的语言区域字符串转换为小写,所有下划线(
_)替换为连字符(-) - 查找与完整语言区域代码完全匹配的本地化版本
- 如果未找到匹配项,则截取第一个连字符之前的子字符串(例如
pt-br取pt),再次查找匹配的本地化版本 - 如果仍未找到匹配项,则返回该付费墙默认语言区域的内容
这样,发送 'pt_BR' 的 iOS 设备、发送 pt-BR 的 Android 设备,以及发送 pt-br 的其他设备,都会得到相同的结果。
实现本地化:推荐方式
如果你正在考虑本地化问题,很可能已经在项目中处理过本地化字符串文件了。如果是这样,我们建议在每个本地化文件中添加一个键值对,键对应预期的 Adapty 语言代码。然后在调用 SDK 时提取该键的值,示例如下:
// 1. Modify your Localizable.strings files
/*
Localizable.strings - Spanish
*/
adapty_paywalls_locale = "es";
/*
Localizable.strings - Portuguese (Brazil)
*/
adapty_paywalls_locale = "pt-br";
// 2. Extract and use the locale code
let locale = NSLocalizedString("adapty_paywalls_locale", comment: "")
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method这样,你就能完全掌控应用中每位用户所获取的本地化内容。
实现本地化的另一种方式
你也可以不为每个本地化显式指定语言代码,同样能获得相近(但不完全相同)的效果。这种方式是从平台提供的其他对象中提取语言代码,例如:
let locale = Locale.current.identifier
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method不过,我们不建议使用这种方式,原因如下:
- 在 iOS 上,首选语言与当前区域设置并不相同。如果希望正确选取本地化内容,你需要依赖 Apple 的内置逻辑(如果你使用的是推荐的本地化字符串文件方式,该逻辑开箱即用),或者自行重新实现该逻辑。
- 很难预测 Adapty 服务器究竟会收到什么。例如,在 iOS 上,设备可能返回类似
ar_OM@numbers='latn'这样的区域标识符,并将其发送给我们的服务器。对于这个请求,你得到的不会是预期中的ar-om本地化内容,而是ar,这很可能出乎意料。
Should you decide to use this approach anyway — make sure you’ve covered all the relevant use cases.