---
title: "在 Kotlin Multiplatform SDK 中使用本地化和语言区域代码"
description: "在 Kotlin Multiplatform 应用中管理本地化和语言区域代码，覆盖全球受众。"
---

## 为什么这很重要 \{#why-this-is-important\}

在某些场景下，语言区域代码会发挥关键作用——例如，当你需要根据应用当前的本地化设置来获取对应的付费墙时。

由于语言区域代码较为复杂，且在不同平台之间可能存在差异，我们为所有支持的平台制定了统一的内部标准。但正因为这些代码比较复杂，了解你究竟向服务器发送了什么内容、以及服务器如何处理这些内容就显得尤为重要——这样你才能始终获得预期的本地化结果。
## Adapty 的语言区域代码标准 \{#locale-code-standard-at-adapty\}

Adapty 的语言区域代码采用略经修改的 [BCP 47 标准](https://en.wikipedia.org/wiki/IETF_language_tag)：每个代码由小写子标签组成，以连字符分隔。示例：`en`（英语）、`pt-br`（葡萄牙语（巴西））、`zh`（简体中文）、`zh-hant`（繁体中文）。
## 语言代码匹配 \{#locale-code-matching\}

当 Adapty 收到客户端 SDK 传来的语言代码并开始查找对应的付费墙本地化版本时，处理流程如下：

1. 将传入的语言代码字符串转换为小写，并将所有下划线（`_`）替换为连字符（`-`）
2. 查找与完整语言代码完全匹配的本地化版本
3. 如果未找到匹配项，则截取第一个连字符之前的子字符串（例如 `pt-br` 取 `pt`），并查找匹配的本地化版本
4. 如果仍未找到匹配项，则返回默认的 `en` 本地化版本
这样，发送了 `'pt_BR'` 的 iOS 设备、发送了 `pt-BR` 的 Android 设备，以及发送了 `pt-br` 的另一台设备，都会得到相同的结果。
## 实现本地化：推荐方式 \{#implementing-localizations-recommended-way\}

如果你在考虑本地化的问题，很可能你的项目中已经在处理本地化字符串资源了。如果是这样，我们建议在每个对应语言的资源文件中，添加一个键值对，将 Adapty 的语言区域代码作为其值。然后在调用 SDK 时，提取该键对应的值，示例如下：
```kotlin showLineNumbers
// 1. 将 Adapty 语言代码添加到你的 Compose Multiplatform 资源中

/*
composeResources/values/strings.xml（默认 — 英语）
*/
<string name="adapty_paywalls_locale">en</string>

/*
composeResources/values-es/strings.xml（西班牙语）
*/
<string name="adapty_paywalls_locale">es</string>

/*
composeResources/values-pt-rBR/strings.xml（葡萄牙语 — 巴西）
*/
<string name="adapty_paywalls_locale">pt-br</string>

// 2. 提取并使用语言代码

suspend fun fetchPaywall() {
    val locale = getString(Res.string.adapty_paywalls_locale)
    Adapty.getPaywall(
        placementId = "YOUR_PLACEMENT_ID",
        locale = locale
    ).onSuccess { paywall ->
        // 请求到的付费墙
    }.onError { error ->
        // 处理错误
    }
}
```
这样，您就能完全掌控应用中每位用户获取到的本地化内容。

如果您没有使用 Compose Multiplatform 资源，同样的思路也适用于您所使用的任何本地化库（例如 [moko-resources](https://github.com/icerockdev/moko-resources)）——将 Adapty 语言区域代码作为字符串存储在每个语言包的资源文件中，并在调用 SDK 前读取该值。
## 实现本地化：另一种方式 \{#implementing-localizations-the-other-way\}

你可以不为每个本地化显式定义语言区域代码，同样能达到类似（但不完全相同）的效果。这种方式是直接从设备上提取语言区域代码——由于 `commonMain` 中没有共享的语言区域 API，因此需要用到 `expect`/`actual` 声明：
```kotlin showLineNumbers
// commonMain
expect fun currentLocaleTag(): String

// androidMain
actual fun currentLocaleTag(): String = Locale.getDefault().toLanguageTag()

// iosMain
actual fun currentLocaleTag(): String = NSLocale.currentLocale.localeIdentifier

// commonMain — pass the locale code to Adapty

suspend fun fetchPaywall() {
    Adapty.getPaywall(
        placementId = "YOUR_PLACEMENT_ID",
        locale = currentLocaleTag()
    ).onSuccess { paywall ->
        // the requested paywall
    }.onError { error ->
        // handle the error
    }
}
```
请注意，由于以下几个原因，我们不建议使用此方法：
1. 在 iOS 上，用户的首选语言与设备的地区语言环境并不相同。`NSLocale.currentLocale.localeIdentifier` 返回的是地区语言环境，可能与用户实际阅读应用时使用的语言不一致。使用本地化字符串文件的 iOS 应用依赖 Apple 的解析逻辑来综合两者——这在上述推荐方案中可以开箱即用。
2. 很难预测设备会返回什么，以及它是否与 Adapty 的某个本地化配置匹配。设备语言环境可能包含你未在 Adapty 中配置的扩展或地区代码，在这种情况下，SDK 会回退到第一个子标签匹配，最终回退到 `en`。
如果您仍决定采用此方案，请确保已覆盖所有相关的使用场景。