Sử dụng localizations và locale codes trong React Native SDK

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

Mã ngôn ngữ (locale code) được 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ù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 được hỗ trợ. Hiểu được tiêu chuẩn đó giúp bạn dự đoán bản dịch nào người dùng sẽ nhận được.

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

Đối với mã ngôn ngữ, Adapty sử dụng tiêu chuẩn BCP 47 được chỉnh sửa nhẹ: mỗi mã bao gồm các subtag viết thường, phân cách bằng dấu gạch nối. 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 SDK bản địa hóa ngay trên thiết bị, còn onboarding được bản địa hóa bởi máy chủ Adapty.

Flow và paywall

Paywall mà Adapty render đượ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.

Sự 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ự 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 fallback về language subtag. Với một flow có localization 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ẽ hiển thị theo ngôn ngữ mặc định một cách âm thầm — 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 không được định nghĩa trong bản địa hóa khớp sẽ được lấy từ bản địa hóa mặc định.

Bỏ qua mã ngôn ngữ không đồng nghĩa với việc yêu cầu bản dịch mặc định của flow: SDK sẽ thay thế bằng en cố định. Một flow có ngôn ngữ mặc định là de vẫn hiển thị bằng en nếu nó có bản dịch en, và chỉ dùng de làm dự phòng khi không có.

Warning

Truyền mã ngôn ngữ chính xác như cách nó được cấu hình trong 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 định danh locale của thiết bị: getLocales()[0].languageTag từ react-native-localize trả về pt-BR, và nó sẽ fallback về 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 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:

  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 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 từ pt-br) và tìm bản địa hóa phù hợp
  4. Nếu vẫn không tìm thấy, Adapty trả về nội dung theo ngôn ngữ mặc định của onboarding

Điều này giúp pt_BR, pt-BRpt-br đều phân giải về 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ã locale khi tải flow — getFlow trả về flow cùng với tất cả các bản địa hóa, và Adapty sẽ áp dụng một bản khi view của flow được xây dựng.

  • Flow được xây dựng trong builder: SDK không tự đọc locale của thiết bị, vì vậy hãy xử lý trong app của bạn và truyền vào qua tham số locale của createFlowView, hoặc qua prop params của component AdaptyFlowView nhúng vào. Tham số này không bắt buộc — nếu bỏ qua, flow sẽ hiển thị theo ngôn ngữ en, hoặc theo ngôn ngữ mặc định nếu flow không có bản dịch en.

    import { createFlowView } from 'react-native-adapty';
    
    const view = await createFlowView(flow, { locale: 'es' });

view.locale báo cáo ngôn ngữ bản địa hóa mà view thực sự được xây dựng với — ngôn ngữ bạn yêu cầu nếu ngôn ngữ đó tồn tại, và ngôn ngữ mặc định của flow trong trường hợp ngược lại. Cả tham số locale lẫn view.locale đều yêu cầu React Native SDK 4.0.2 trở lên, và view.locale sẽ là undefined trên các phiên bản cũ hơn.

Component AdaptyFlowView nhúng sẵn tự tạo view của riêng nó, vì vậy không có gì để code của bạn đọc locale từ đó. Thay vào đó, hãy lấy thông tin bản địa hóa từ đối tượng mà trình xử lý onAppeared của nó nhận được:

  <AdaptyFlowView
    flow={flow}
    params={{ locale: 'es' }}
    onAppeared={(view) => setScreenLocale(view.locale)}
  />

Tham số onAppeared yêu cầu React Native SDK 4.0.3 trở lên.

  • 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ã lang và đối tượng data. Chọn mục phù hợp với người dùng, kèm theo fallback của riêng bạn:

const flow = await adapty.getFlow('placement_id');
const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0];
// read your values from config?.data

Adapty lưu trữ các mã lang theo định dạng được mô tả trong Tiêu chuẩn mã ngôn ngữ tại Adapty. SDK không tự động 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 tình huống mà mã locale phát huy vai trò — chẳng hạn, khi bạn cần lấy đúng paywall theo 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 từng nền tảng, chúng tôi sử dụng một tiêu chuẩn nội bộ chung 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 địa hóa, và điều gì xảy ra tiếp theo — để luôn nhận được kết quả như mong đợi.

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 đượ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, được phân tách bằng dấu gạch ngang. Một vài 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 theo mã ngôn ngữ và bắt đầu tìm kiếm bản dịch tương ứng của paywall, quá trình diễn ra như sau:

  1. Chuỗi ngôn ngữ đầu vào được chuyển thành chữ thường và tất cả cá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 dịch có mã ngôn ngữ 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 (ví dụ pt từ pt-br) và tìm kiếm bản dịch khớp với chuỗi đó
  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

Theo cách nà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 sẽ nhận được cùng một kết quả.

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

// 1. Modify your localization files (e.g., using react-i18next)

/*
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

const MyComponent = () => {
  const { t } = useTranslation();
  
  const fetchPaywall = async () => {
    const locale = t('adapty_paywalls_locale');
    // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
    const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
  };
};

Bằng cách này, bạn có thể đảm bảo rằng mình hoàn toàn kiểm soát được bản dịch nào sẽ được truy xuất cho từng người dùng trong ứng dụng của bạn.

Triển khai bản địa hóa: cách khác

Bạn có thể đạt được kết quả tương tự (nhưng không hoàn toàn giống nhau) mà không cần phải xác định rõ mã ngôn ngữ cho từng bản địa hóa. Thay vào đó, bạn có thể trích xuất mã ngôn ngữ từ thiết bị, ví dụ thông qua react-native-localize:


const fetchPaywall = async () => {
  // getLocales() returns the user's preferred locales in BCP-47 format (e.g., 'en-US', 'pt-BR')
  const locale = RNLocalize.getLocales()[0].languageTag;
  // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
  const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
};

Lưu ý rằng chúng tôi không khuyến nghị cách tiếp cận này vì một số lý do:

  1. Trên iOS, ngôn ngữ ưu tiên và locale khu vực hiện tại không giống nhau. Nếu bạn muốn bản địa hóa được chọn đúng, bạn cần dựa vào logic phân giải của Apple — hoạt động tự động khi bạn dùng cách tiếp cận được khuyến nghị với các file chuỗi đã bản địa hóa — hoặc tự xây dựng lại logic đó.
  2. Locale của thiết bị có thể không khớp với bất kỳ bản địa hóa nào bạn đã cấu hình trong Adapty. Trong trường hợp đó, SDK sẽ dùng kết quả khớp theo subtag đầu tiên, hoặc cuối cùng là en — có thể không phải ngôn ngữ mặc định bạn muốn hiển thị cho người dùng đó.

Should you decide to use this approach anyway — make sure you’ve covered all the relevant use cases.