Sử dụng bản địa hóa và mã ngôn ngữ trong Android SDK

Tại sao điều này quan trọng

Mã ngôn ngữ được sử dụng khi Adapty chọn bản dịch cho một flow hoặc onboarding, và khi bạn đọc Remote Config cho một paywall tùy chỉnh.

Mã ngôn ngữ khá phức tạp và có thể khác nhau giữa các nền tảng, vì vậy Adapty dựa trên một tiêu chuẩn nội bộ thống nhất cho mọi nền tảng mà nó hỗ trợ. Hiểu rõ tiêu chuẩn đó giúp bạn dự đoán được bản dịch nào người dùng sẽ nhận được.

Chuẩn locale code tại Adapty

Đối với locale codes, Adapty sử dụng phiên bản điều chỉnh nhẹ của chuẩn BCP 47: mỗi code gồm các subtag viết thường, phân cách bằng dấu gạch ngang. Một số ví dụ: en (tiếng Anh), pt-br (tiếng Bồ Đào Nha (Brazil)), zh (tiếng Trung giản thể), zh-hant (tiếng Trung phồn thể).

Khớp mã ngôn ngữ

Trong SDK v4, flow và onboarding khớp mã ngôn ngữ theo các cách khác nhau: flow được bản địa hóa bởi SDK trên thiết bị, còn onboarding được bản địa hóa bởi máy chủ Adapty.

Flow và paywall được tạo bằng Paywall Builder

Paywall được tạo trong Paywall Builder sẽ được phân phối dưới dạng flow trong SDK v4, vì vậy quy tắc dưới đây áp dụng cho cả hai.

Khớp là chính xác tuyệt đối. SDK so sánh mã bạn truyền vào với mã ngôn ngữ của flow theo từng ký tự: không thay đổi chữ hoa/thường, không thay thế dấu gạch dưới (_) bằng dấu gạch ngang (-), và không quay về subtag ngôn ngữ. Với một flow có ngôn ngữ pt-br, chỉ pt-br mới khớp: pt-BR, pt_BR, và pt-PT đều không khớp.

Khi mã không khớp với bất kỳ bản địa hóa nào, flow sẽ tự động hiển thị theo ngôn ngữ mặc định — SDK không trả về lỗi và không ghi cảnh báo.

Khi mã khớp, Adapty sẽ hợp nhất bản địa hóa đó với bản mặc định: các chuỗi và tài nguyên mà bản địa hóa được khớp không định nghĩa sẽ được lấy từ bản địa hóa mặc định.

Bỏ qua mã locale không giống với việc yêu cầu localization mặc định của flow: SDK sẽ thay thế bằng en cố định. Một flow có locale mặc định là de vẫn hiển thị bằng en nếu nó có localization en, và chỉ dự phòng về de khi không có. Điều này áp dụng cho Android SDK 4.0.1 trở lên — trong 4.0.0, bỏ qua mã locale sẽ hiển thị localization mặc định của flow.

Warning

Truyền mã ngôn ngữ chính xác như cách đã cấu hình trong dashboard — các subtag viết thường và cách nhau bằng dấu gạch ngang. Đừng truyền trực tiếp locale identifier của hệ thống: Locale.getDefault().toLanguageTag() trả về pt-BRLocale.getDefault().toString() trả về pt_BR, và cả hai đều sẽ dùng bản ngôn ngữ mặc định. Hãy chuyển đổi giá trị trong ứng dụng của bạn trước khi truyền vào.

Onboardings

Onboardings được bản địa hóa trên máy chủ, và các quy tắc máy chủ chấp nhận nhiều định dạng khác nhau. Khi bạn truyền locale vào getOnboarding:

  1. Chuỗi locale được chuyển thành chữ thường và tất cả dấu gạch dưới (_) được thay thế bằng dấu gạch ngang (-)
  2. Adapty tìm kiếm bản địa hóa có mã locale khớp hoàn toàn
  3. Nếu không tìm thấy, Adapty lấy chuỗi con trước dấu gạch ngang đầu tiên (pt trong pt-br) và tìm kiếm bản địa hóa khớp
  4. Nếu vẫn không tìm thấy, Adapty trả về nội dung theo locale mặc định của onboarding

Theo cách này, pt_BR, pt-BRpt-br đều phân giải thành cùng một bản dịch onboarding.

Triển khai bản địa hóa

Trong SDK v4, bạn không cần truyền mã ngôn ngữ khi tải một flow — getFlow trả về flow cùng với tất cả các bản địa hóa của nó.

  • Flow được xây dựng trong builder: SDK không đọc locale của thiết bị, vì vậy hãy xác định locale trong ứng dụng của bạn và truyền nó vào đối số locale của AdaptyUI.getFlowConfiguration. Đối số này là tùy chọn — bỏ qua nó và flow sẽ hiển thị bằng en, hoặc bằng locale mặc định khi flow không có bản địa hóa en.
  • Paywall tùy chỉnh (remote config): getFlow trả về tất cả các bản địa hóa đã cấu hình trong flow.remoteConfigs. Mỗi mục có một mã locale và nội dung config (jsonString, hoặc dataMap đã được phân tích cú pháp). Chọn mục phù hợp với người dùng, với phương án dự phòng của riêng bạn:
Adapty.getFlow("YOUR_PLACEMENT_ID") { result ->
    when (result) {
        is AdaptyResult.Success -> {
            val flow = result.value
            val config = flow.remoteConfigs.firstOrNull { it.locale == "en" }
                ?: flow.remoteConfigs.firstOrNull()
            // read your values from config?.dataMap
        }
        is AdaptyResult.Error -> {
            // handle the error
        }
    }
}

Adapty lưu trữ các mã locale theo định dạng được mô tả trong Tiêu chuẩn mã ngôn ngữ tại Adapty. SDK không so khớp Remote Config với ngôn ngữ, vì vậy việc áp dụng mục nào là tùy thuộc vào ứng dụng của bạn.

Tại sao điều này quan trọng

Có một vài trường hợp mà mã ngôn ngữ (locale code) có vai trò quan trọng — ví dụ, khi bạn cần lấy đúng paywall cho ngôn ngữ hiện tại của ứng dụng.

Vì mã ngôn ngữ khá phức tạp và có thể khác nhau giữa các nền tảng, chúng tôi sử dụng một tiêu chuẩn nội bộ thống nhất cho tất cả các nền tảng được hỗ trợ. Tuy nhiên, chính vì sự phức tạp đó, bạn cần hiểu rõ mình đang gửi gì lên server để nhận đúng bản ngôn ngữ mong muốn — và điều gì sẽ xảy ra tiếp theo.

Tiêu chuẩn mã ngôn ngữ tại Adapty

Đối với mã ngôn ngữ, Adapty sử dụng phiên bản được điều chỉnh nhẹ của tiêu chuẩn BCP 47: mỗi mã gồm các subtag viết thường, ngăn cách nhau bằng dấu gạch ngang. Ví dụ: en (tiếng Anh), pt-br (tiếng Bồ Đào Nha (Brazil)), zh (tiếng Trung giản thể), zh-hant (tiếng Trung phồn thể).

Khớp mã ngôn ngữ

Khi Adapty nhận được lệnh gọi từ SDK phía client kèm mã ngôn ngữ và bắt đầu tìm kiếm bản localization tương ứng của một paywall, quá trình diễn ra như sau:

  1. Chuỗi locale đầu vào được chuyển thành chữ thường và tất cả dấu gạch dưới (_) được thay bằng dấu gạch ngang (-)
  2. Hệ thống tìm kiếm bản localization có mã locale khớp hoàn toàn
  3. Nếu không tìm thấy, hệ thống lấy chuỗi con trước dấu gạch ngang đầu tiên (pt từ pt-br) và tiếp tục tìm kiếm bản localization khớp
  4. Nếu vẫn không tìm thấy, hệ thống trả về nội dung theo ngôn ngữ mặc định của paywall

Nhờ đó, một thiết bị iOS gửi 'pt_BR', một thiết bị Android gửi pt-BR, và một thiết bị khác gửi pt-br đều nhận được kết quả giống nhau.

Nếu bạn đang quan tâm đến localizations, rất có thể bạn đã làm việc với các file chuỗi đã được dịch trong dự án. Trong trường hợp đó, chúng tôi khuyến nghị bạn thêm một cặp key-value chứa Adapty locale code tương ứng vào từng file localization. Sau đó, trích xuất giá trị của key đó khi gọi SDK, như sau:

// 1. Modify your strings.xml files

/*
strings.xml - Spanish
*/
<string name="adapty_paywalls_locale">es</string>

/*
strings.xml - Portuguese (Brazil)
*/
<string name="adapty_paywalls_locale">pt-br</string>

// 2. Extract and use the locale code

val localeCode = context.getString(R.string.adapty_paywalls_locale)
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

Cách này giúp bạn kiểm soát hoàn toàn localization nào sẽ được tải về cho từng người dùng trong ứng dụng của bạn.

Cách triển khai localizations khác

Bạn cũng có thể đạt được kết quả tương tự (nhưng không hoàn toàn giống) mà không cần định nghĩa tường minh locale codes cho từng localization. Cách này có nghĩa là trích xuất locale code từ các đối tượng mà nền tảng của bạn cung cấp, như sau:

val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
    context.resources.configuration.locales[0]
else
    context.resources.configuration.locale

val localeCode = locale.toLanguageTag()
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

Lưu ý rằng chúng tôi không khuyến nghị cách tiếp cận này vì khó dự đoán chính xác máy chủ của Adapty sẽ nhận được gì.

Nếu bạn vẫn quyết định sử dụng cách này — hãy đảm bảo rằng bạn đã xử lý tất cả các trường hợp sử dụng liên quan.