Sử dụng bản địa hóa và mã ngôn ngữ trong Unity SDK
Tại sao điều này quan trọng
Mã locale đượ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ã locale khá phức tạp và có thể khác nhau giữa các nền tảng, vì vậy Adapty sử dụng một tiêu chuẩn nội bộ thống nhất trên tất cả các nền tảng mà nó hỗ trợ. Hiểu được tiêu chuẩn đó giúp bạn dự đoán bản dịch nào mà người dùng sẽ nhận được.
Tiêu chuẩn mã locale tại Adapty
Đối với mã locale, 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, 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, các flow và onboarding khớp mã ngôn ngữ theo 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 Paywall Builder
Paywall được xây dựng 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.
Kết quả khớp là tuyệt đối chính xác. 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ự mộ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 tự động dùng 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ã ngôn ngữ không khớp với bất kỳ localization 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 nào.
Khi mã ngôn ngữ khớp, Adapty sẽ hợp nhất localization đó với localization mặc định: các chuỗi và tài nguyên mà localization được khớp không định nghĩa sẽ được lấy từ localization mặc định.
Bỏ qua mã locale không đồng nghĩa 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 khi nó có localization en, và chỉ fallback về de khi không có.
Truyền mã locale chính xác như cấu hình trên dashboard — các subtag viết thường, phân tách bằng dấu gạch ngang. Đừng truyền trực tiếp system locale identifier: CultureInfo.CurrentCulture.Name trả về pt-BR, và nó sẽ fallback về localization mặc định. Hãy chuyển đổi giá trị trong app trước khi truyền vào.
Onboardings
Onboardings được bản địa hóa trên server, và các quy tắc của server chấp nhận nhiều định dạng khác nhau. Khi bạn truyền Locale vào GetOnboarding:
- Chuỗi locale được chuyển về chữ thường và tất cả dấu gạch dưới (
_) được thay thế bằng dấu gạch ngang (-) - Adapty tìm kiếm bản địa hóa có mã locale khớp hoàn toàn
- Nếu không tìm thấy, Adapty lấy chuỗi con trước dấu gạch ngang đầu tiên (
pttrongpt-br) và tìm kiếm bản địa hóa phù hợp - 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-BR, và pt-br đều được phân giải thành cùng một bản địa hóa 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 lấy một flow — flow sẽ được bản địa hóa khi view của nó được tạo.
- Paywall được xây dựng bằng Flow Builder và Paywall Builder: SDK không đọc ngôn ngữ thiết bị, vì vậy hãy xử lý trong ứng dụng của bạn và truyền vào khi tạo view. Mã ngôn ngữ là tùy chọn — bỏ qua nó và flow sẽ hiển thị bằng
en, hoặc bằng ngôn ngữ mặc định khi flow không có bản dịchen. - Paywall tùy chỉnh (remote config):
GetFlowtrả về tất cả các bản dịch đã cấu hình trongflow.RemoteConfigs. Mỗi mục là mộtAdaptyRemoteConfigvới mãLocalevà mộtDictionarycác giá trị. Chọn mục phù hợp với người dùng, với logic dự phòng của riêng bạn:
using System.Linq;
using AdaptySDK;
Adapty.GetFlow("YOUR_PLACEMENT_ID", (flow, error) => {
if (error != null) {
// handle the error
return;
}
var config = flow.RemoteConfigs.FirstOrDefault(c => c.Locale == "en")
?? flow.RemoteConfigs.FirstOrDefault();
// read your values from config?.Dictionary
});Adapty lưu trữ các mã Locale theo định dạng được mô tả trong Tiêu chuẩn mã Locale tại Adapty. SDK không tự động khớp Remote Config với một locale, 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.
Chọn ngôn ngữ cho một flow
Để hiển thị một flow hoặc paywall với ngôn ngữ cụ thể, truyền mã locale vào SetLocale khi bạn tạo view:
var parameters = new AdaptyUICreateFlowViewParameters()
.SetLocale("pt-br");
AdaptyUI.CreateFlowView(flow, parameters, (view, error) => {
if (error != null) {
// handle the error
return;
}
// view.Locale — the localization the view was built with
});View báo cáo localization mà nó thực sự được xây dựng với trong view.Locale: localization bạn đã yêu cầu nếu localization đó tồn tại, và localization mặc định của flow nếu không có.
Tại sao điều này quan trọng
Có một số tình huống mà mã locale đóng 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ã locale khá phức tạp và có thể khác nhau tùy 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ì xảy ra tiếp theo — để luôn nhận được kết quả như kỳ vọng.
Tiêu chuẩn mã ngôn ngữ tại Adapty
Đối với mã ngôn ngữ, Adapty sử dụng một phiên bản tiêu chuẩn BCP 47 được chỉnh sửa nhẹ: mỗi mã gồm các subtag viết thường, ngăn cách nhau 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ữ
Khi Adapty nhận được yêu cầu từ SDK phía client kèm theo 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:
- Chuỗi ngôn ngữ đầu vào đượ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 (-) - Hệ thống tìm kiếm bản localization có mã ngôn ngữ khớp hoàn toàn
- Nếu không tìm thấy kết quả khớp, hệ thống lấy chuỗi con trước dấu gạch ngang đầu tiên (
pttrongpt-br) và tìm kiếm bản localization phù hợp - Nếu vẫn không tìm thấy kết quả khớp, hệ thống trả về nội dung theo ngôn ngữ mặc định của paywall
Nhờ vậy, 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ả như nhau.
Triển khai localization: cách khuyến nghị
Nếu bạn đang tìm hiểu về localization, nhiều khả năng bạn đã làm việc với các file chuỗi đã được localize trong dự án. Trong trường hợp đó, chúng tôi khuyến nghị thêm một cặp key-value chứa mã locale Adapty tương ứng vào mỗi file cho từng localization. Sau đó, trích xuất giá trị của key đó khi gọi SDK, như sau:
// 1. Modify your localization files (e.g., using Unity's Localization package)
/*
en.json
*/
{
"adapty_paywalls_locale": "en"
}
/*
es.json
*/
{
"adapty_paywalls_locale": "es"
}
/*
pt-BR.json
*/
{
"adapty_paywalls_locale": "pt-br"
}
// 2. Extract and use the locale code
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using AdaptySDK;
public class PaywallManager : MonoBehaviour
{
public async void FetchPaywall()
{
// Get the current locale from Unity's Localization system
var locale = LocalizationSettings.SelectedLocale;
var localeCode = GetAdaptyLocaleCode(locale);
// Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method
Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => {
if (error != null) {
// handle the error
return;
}
// Use the paywall
});
}
private string GetAdaptyLocaleCode(Locale locale)
{
// Convert Unity locale to Adapty format
var localeIdentifier = locale.Identifier.Code;
return localeIdentifier.ToLower().Replace('_', '-');
}
}Cách này giúp bạn kiểm soát hoàn toàn localization nào sẽ được trả về cho từng người dùng trong ứng dụng.
Triển khai localization: cách khác
Bạn có thể đạt kết quả tương tự (nhưng không hoàn toàn giống) mà không cần định nghĩa mã locale tường minh cho từng localization. Cách này có nghĩa là trích xuất mã locale từ các đối tượng khác mà nền tảng cung cấp, như sau:
using UnityEngine;
using System.Globalization;
using AdaptySDK;
public class PaywallManager : MonoBehaviour
{
public void FetchPaywall()
{
var localeCode = GetSystemLocaleCode();
// Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method
Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => {
if (error != null) {
// handle the error
return;
}
// Use the paywall
});
}
private string GetSystemLocaleCode()
{
// Get the system's current culture
var culture = CultureInfo.CurrentCulture;
var languageCode = culture.TwoLetterISOLanguageName;
var regionCode = culture.Name.Contains('-') ? culture.Name.Split('-')[1] : null;
if (!string.IsNullOrEmpty(regionCode))
{
return $"{languageCode}-{regionCode.ToLower()}";
}
return languageCode;
}
}Lưu ý rằng chúng tôi không khuyến nghị cách này vì một vài lý do:
- Trên iOS, ngôn ngữ ưu tiên và locale hiện tại không giống nhau. Nếu muốn localization được chọn đúng, bạn phải hoặc dựa vào logic của Apple (vốn hoạt động tự động nếu dùng cách khuyến nghị với các file chuỗi đã localize), hoặc tự tái tạo lại logic đó.
- Khó dự đoán chính xác máy chủ của Adapty sẽ nhận được gì. Chẳng hạn, trên iOS, có thể lấy được locale như
ar_OM@numbers='latn'từ thiết bị và gửi đến máy chủ. Với yêu cầu này, bạn sẽ không nhận được localizationar-omnhư mong đợi, mà thay vào đó làar— điều này có thể ngoài ý muốn.
Dù vậy, nếu bạn vẫn quyết định dùng cách này — hãy đảm bảo bạn đã xử lý tất cả các trường hợp liên quan.