Lựa chọn ưu tiên về tài khoản

Lựa chọn ưu tiên về tài khoản
Ngôn ngữ cho mỗi ứng dụng trong phần cài đặt hệ thống

Trong nhiều trường hợp, người dùng đa ngôn ngữ đặt ngôn ngữ hệ thống của họ thành một ngôn ngữ (chẳng hạn như tiếng Anh). Tuy nhiên, họ muốn chọn các ngôn ngữ khác cho những ứng dụng cụ thể, chẳng hạn như tiếng Hà Lan, tiếng Trung hoặc tiếng Hindi. Nhằm giúp ứng dụng mang lại trải nghiệm tốt hơn cho những người dùng này, Android 13 ra mắt các tính năng sau cho các ứng dụng hỗ trợ nhiều ngôn ngữ:

  • Cài đặt hệ thống: Một vị trí tập trung mà người dùng có thể chọn một ngôn ngữ ưa thích cho mỗi ứng dụng.

    Ứng dụng phải khai báo thuộc tính android:localeConfig trong tệp kê khai của ứng dụng để cho hệ thống biết rằng ứng dụng này hỗ trợ nhiều ngôn ngữ. Để tìm hiểu thêm, hãy xem hướng dẫn tạo một tệp tài nguyên và khai báo tệp này trong tệp kê khai của ứng dụng.

  • API bổ sung: Những API công khai này, chẳng hạn như các phương thức setApplicationLocales()getApplicationLocales() trong LocaleManager, cho phép ứng dụng đặt một ngôn ngữ khác với ngôn ngữ hệ thống vào thời gian chạy.

    Các API này tự động đồng bộ hoá với chế độ cài đặt hệ thống; do đó, những ứng dụng dùng các API này để tạo bộ chọn ngôn ngữ tuỳ chỉnh trong ứng dụng sẽ đảm bảo mang đến cho người dùng một trải nghiệm nhất quán, bất kể họ chọn các lựa chọn ưu tiên về ngôn ngữ ở đâu. Các API công khai cũng giúp bạn giảm số lượng mã nguyên mẫu, hỗ trợ APK phân tách và hỗ trợ tính năng Tự động sao lưu đối với ứng dụng để lưu trữ chế độ cài đặt ngôn ngữ của người dùng ở cấp ứng dụng.

    Để tương thích ngược với các phiên bản Android trước, các API tương đương cũng có trong AndroidX. Bạn nên sử dụng Appcompat 1.6.0-beta01 trở lên.

Tổng quan về việc triển khai tính năng này

Bảng sau đây cho thấy các cách triển khai được đề xuất dựa trên các trường hợp sử dụng khác nhau.

Trường hợp sử dụngCách triển khai được đề xuất
Ứng dụng của bạn không có bộ chọn ngôn ngữ trong ứng dụng
  1. Sử dụng thuộc tính android:localeConfig trong tệp kê khai ứng dụng để thêm ngôn ngữ của ứng dụng vào chế độ cài đặt trên điện thoại.
  2. Nếu muốn thêm bộ chọn ngôn ngữ trong ứng dụng (không bắt buộc), hãy sử dụng thư viện AndroidX và chọn triển khai API để hỗ trợ khả năng tương thích ngược thông qua autoStoreLocales.
Ứng dụng của bạn đã có bộ chọn ngôn ngữ trong ứng dụng
  1. Sử dụng thuộc tính android:localeConfig trong tệp kê khai ứng dụng để thêm ngôn ngữ của ứng dụng vào chế độ cài đặt trên điện thoại.
  2. Di chuyển logic tuỳ chỉnh của ứng dụng để sử dụng các API công khai nhằm đảm bảo người dùng thấy được trải nghiệm nhất quán.
  3. Xử lý các trường hợp góc sau:
    1. Gọi AppCompatDelegate.setApplicationLocales() trong lần đầu tiên ứng dụng của bạn chạy trên thiết bị Android 13.
    2. Gọi AppCompatDelegate.setApplicationLocales() để cung cấp ngôn ngữ có sẵn mà người dùng yêu cầu cho hệ thống trong các trường hợp sau:
      • Nếu bạn chọn sử dụng tính năng tự động lưu trữ cho Android 12 (API cấp 32) trở xuống
      • Nếu ứng dụng của bạn cần di chuyển dữ liệu từ một vị trí bộ nhớ sao lưu tuỳ chỉnh

Chế độ cài đặt hệ thống cho người dùng

Bắt đầu từ Android 13, Android sẽ bao gồm một vị trí tập trung trong phần cài đặt của điện thoại để đặt tuỳ chọn ngôn ngữ cho mỗi ứng dụng. Để đảm bảo ngôn ngữ của ứng dụng có thể được định cấu hình trong phần cài đặt hệ thống trên các thiết bị chạy Android 13 trở lên, hãy tạo một tệp XML locales_config và thêm tệp đó vào tệp kê khai của ứng dụng bằng thuộc tính android:localeConfig. Việc bỏ qua mục nhập tệp kê khai android:localeConfig báo hiệu rằng người dùng sẽ không thể đặt ngôn ngữ của ứng dụng độc lập với ngôn ngữ hệ thống trong phần cài đặt của điện thoại.

Dùng android:localeConfig để thêm các ngôn ngữ được hỗ trợ vào phần cài đặt trên điện thoại

Cách thêm ngôn ngữ được hỗ trợ của ứng dụng vào cài đặt điện thoại của người dùng:

  1. Tạo một tệp có tên là res/xml/locales_config.xml và chỉ định ngôn ngữ của ứng dụng, bao gồm cả ngôn ngữ dự phòng tối ưu, là ngôn ngữ được chỉ định trong res/values/strings.xml.

    Để tạo tên ngôn ngữ, hãy kết hợp mã ngôn ngữ với tập lệnh tuỳ chọn và mã vùng, phân tách mỗi mã bằng một dấu gạch ngang.

    • Ngôn ngữ: Sử dụng mã gồm hai hoặc ba chữ cái theo ISO 639-1.

    • Tập lệnh (không bắt buộc): Sử dụng mã theo ISO 15924.

    • Khu vực (không bắt buộc): Sử dụng mã gồm hai chữ cái ISO 3166-1-alpha-2 hoặc mã gồm ba chữ số UN_M.49.

    Hãy xem định dạng đề xuất trong tệp locale_config.xml mẫu để biết danh sách các ngôn ngữ thường dùng nhất.

    Ví dụ: định dạng tệp locales_config.xml như thế này cho một ứng dụng hỗ trợ các ngôn ngữ sau:

    • Tiếng Anh (Mỹ) là ngôn ngữ dự phòng tối ưu
    • Tiếng Anh (Anh)
    • Tiếng Pháp
    • Tiếng Nhật
    • Tiếng Trung (Giản thể, Macau)
    • Tiếng Trung (Phồn thể, Macau)
    <?xml version="1.0" encoding="utf-8"?>
    <locale-config xmlns:android="http://schemas.android.com/apk/res/android">
       <locale android:name="en"/>
       <locale android:name="en-GB"/>
       <locale android:name="fr"/>
       <locale android:name="ja"/>
       <locale android:name="zh-Hans-MO"/>
       <locale android:name="zh-Hant-MO"/>
    </locale-config>
    
  2. Trong tệp kê khai, hãy thêm một dòng trỏ đến tệp mới này:

    <manifest>
        ...
        <application
            ...
            android:localeConfig="@xml/locales_config">
        </application>
    </manifest>
    

Chỉ định ngôn ngữ được hỗ trợ trong Gradle

Nếu chưa có, hãy chỉ định cùng một ngôn ngữ bằng cách sử dụng thuộc tính resConfigs trong tệp build.gradle cấp mô-đun của ứng dụng:

Groovy

  android {
      defaultConfig {
          ...
          resConfigs "en", "en-GB", "fr", "ja", "zh-Hans-MO", "zh-Hant-MO"
      }
  }
  

Kotlin

  android {
      defaultConfig {
          ...
          resConfigs("en", "en-GB", "fr", "ja", "zh-Hans-MO", "zh-Hant-MO")
      }
  }
  

Khi có sẵn thuộc tính resConfigs, hệ thống xây dựng chỉ đưa tài nguyên ngôn ngữ vào APK cho các ngôn ngữ được chỉ định này, ngăn việc đưa chuỗi dịch vào từ các thư viện khác có thể hỗ trợ ngôn ngữ mà ứng dụng của bạn không hỗ trợ. Để biết thêm thông tin, xem phần nội dung Chỉ định ngôn ngữ được ứng dụng của bạn hỗ trợ.

Cách người dùng chọn một ngôn ngữ ứng dụng trong phần cài đặt hệ thống

Người dùng có thể chọn ngôn ngữ ưu tiên của họ cho từng ứng dụng thông qua phần cài đặt hệ thống. Họ có thể truy cập các cài đặt này theo hai cách khác nhau:

  • Truy cập thông qua phần cài đặt Hệ thống

    Cài đặt > Hệ thống > Ngôn ngữ và phương thức nhập > Ngôn ngữ ứng dụng > (chọn ứng dụng)

  • Truy cập thông qua phần cài đặt Ứng dụng

    Cài đặt > Ứng dụng > (chọn ứng dụng) > Ngôn ngữ

Vấn đề đã biết

Dưới đây là các vấn đề đã biết cần lưu ý khi kiểm thử ứng dụng:

  • Nếu đang sử dụng trình bổ trợ Android cho Gradle (AGP) phiên bản 7.3.0-alpha07 đến 7.3.0-beta02 hoặc 7.4.0-alpha01 đến 7.4.0-alpha03, thì bạn có thể gặp phải vấn đề khiến tài nguyên không liên kết được khi bạn khai báo android:localeConfig trong tệp kê khai của ứng dụng. Vấn đề này đã được giải quyết trong các phiên bản sau của AGP và SDK Android. Nếu bạn gặp phải vấn đề này, hãy sử dụng AGP 7.3.0-beta04 trở lên hoặc AGP 7.4.0-alpha05 trở lên với SDK phiên bản 33 (compileSdk = 33).

Xử lý bộ chọn ngôn ngữ trong ứng dụng

Đối với những ứng dụng đã có bộ chọn ngôn ngữ trong ứng dụng hoặc muốn sử dụng một bộ chọn này, hãy sử dụng API công khai thay vì logic ứng dụng tuỳ chỉnh để xử lý chế độ cài đặt và nhận ngôn ngữ ưu tiên của người dùng cho ứng dụng. Nếu bạn sử dụng API công khai cho bộ chọn ngôn ngữ trong ứng dụng, thì chế độ cài đặt hệ thống của thiết bị sẽ tự động được cập nhật cho phù hợp với ngôn ngữ mà người dùng chọn thông qua trải nghiệm trong ứng dụng.

Để tương thích ngược với các phiên bản Android trước, bạn nên sử dụng thư viện hỗ trợ AndroidX khi triển khai một bộ chọn ngôn ngữ trong ứng dụng. Tuy nhiên, bạn cũng có thể triển khai các API khung trực tiếp nếu cần.

Triển khai bằng thư viện hỗ trợ AndroidX

Sử dụng các phương thức setApplicationLocales()getApplicationLocales() trong Appcompat 1.6.0-beta01 trở lên.

Ví dụ: để đặt ngôn ngữ ưu tiên của người dùng, bạn sẽ yêu cầu người dùng chọn một ngôn ngữ trong bộ chọn ngôn ngữ, sau đó đặt giá trị này trong hệ thống:

Kotlin

val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY")
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale)

Java

LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("xx-YY");
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale);

Lưu ý rằng việc gọi setApplicationLocales() sẽ tạo lại Activity, trừ phi ứng dụng của bạn tự xử lý các thay đổi về cấu hình ngôn ngữ.

Hãy dùng AppCompatDelegate.getApplicationLocales() để truy xuất ngôn ngữ ưu tiên của người dùng. Người dùng có thể đã chọn ngôn ngữ ứng dụng trong phần cài đặt hệ thống hoặc trên bộ chọn ngôn ngữ trong ứng dụng của bạn.

Hỗ trợ Android 12 trở xuống

Để hỗ trợ các thiết bị chạy Android 12 (API cấp độ 32) trở xuống, hãy yêu cầu AndroidX xử lý bộ nhớ ngôn ngữ bằng cách đặt giá trị autoStoreLocales thành trueandroid:enabled thành false trong mục nhập tệp kê khai cho dịch vụ AppLocalesMetadataHolderService của ứng dụng, như minh hoạ trong đoạn mã sau:

<application
  ...
  <service
    android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
    android:enabled="false"
    android:exported="false">
    <meta-data
      android:name="autoStoreLocales"
      android:value="true" />
  </service>
  ...
</application>

Lưu ý rằng việc đặt giá trị autoStoreLocales thành true gây ra hiện tượng đọc theo tuần tự trên luồng chính, đồng thời có thể gây ra lỗi vi phạm StrictMode diskReaddiskWrite nếu bạn đang ghi lại các lỗi vi phạm trong luồng. Vui lòng xem AppCompatDelegate.setApplicationLocales() để biết thêm thông tin.

Xử lý bộ nhớ tuỳ chỉnh

Việc bỏ qua mục nhập tệp kê khai hoặc đặt autoStoreLocales thành false báo hiệu rằng bạn đang xử lý bộ nhớ của riêng mình. Trong trường hợp này, bạn phải cung cấp các ngôn ngữ được lưu trữ trước onCreate trong vòng đời hoạt động và các lệnh gọi cổng đến AppCompatDelegate.setApplicationLocales() trong Android 12 (API cấp 32) trở xuống.

Nếu ứng dụng của bạn có vị trí bộ nhớ ngôn ngữ tuỳ chỉnh, thì bạn nên sử dụng lệnh chuyển đổi một lần giữa giải pháp bộ nhớ ngôn ngữ tuỳ chỉnh và autoStoreLocales để người dùng tiếp tục tận hưởng ứng dụng của bạn bằng ngôn ngữ họ muốn. Điều này đặc biệt phù hợp trong trường hợp ứng dụng của bạn chạy lần đầu sau khi thiết bị đã nâng cấp lên Android 13. Trong trường hợp này, bạn có thể cung cấp các ngôn ngữ có sẵn mà người dùng yêu cầu bằng cách truy xuất ngôn ngữ từ bộ nhớ tuỳ chỉnh của bạn và chuyển các ngôn ngữ đó vào AppCompatDelegate.setApplicationLocales().

Triển khai bằng các API khung Android

Mặc dù bạn nên sử dụng thư viện hỗ trợ AndroidX để triển khai bộ chọn ngôn ngữ trong ứng dụng, nhưng bạn cũng có thể dùng các phương thức setApplicationLocales()getApplicationLocales() trong khung Android dành cho các thiết bị chạy Android 13.

Ví dụ: để đặt ngôn ngữ ưu tiên của người dùng, bạn sẽ yêu cầu người dùng chọn một ngôn ngữ trong bộ chọn ngôn ngữ, sau đó đặt giá trị này trong hệ thống:

// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its locale
mContext.getSystemService(LocaleManager.class
    ).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language

Để hiển thị ngôn ngữ ưu tiên hiện tại của người dùng trong bộ chọn ngôn ngữ, ứng dụng của bạn có thể lấy lại giá trị từ hệ thống:

// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales =
    mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user

Các phương pháp hay nhất khác

Hãy lưu ý các phương pháp hay nhất dưới đây.

Cân nhắc ngôn ngữ khi gọi một ý định trong ứng dụng khác

Ý định tập trung vào ngôn ngữ có thể cho phép bạn chỉ định ngôn ngữ mà bạn muốn ứng dụng được gọi. Một ví dụ có thể kể đến là tính năng EXTRA_LANGUAGE trong API Trình nhận dạng lời nói.

Hãy cân nhắc thêm Tiêu đề Ngôn ngữ Chấp nhận thông qua Browser.EXTRA_HEADERS để mở trang web bằng ngôn ngữ của ứng dụng khi gọi thẻ Tuỳ chỉnh Chrome.

Tệp mẫu locale_config.xml

Theo mặc định, Android sẽ bao gồm các bản dịch cấp hệ thống trong Dự án nguồn mở Android (AOSP) cho một tập hợp chuẩn các ngôn ngữ được sử dụng phổ biến nhất. Tệp locale_config.xml mẫu có trong phần này cho biết định dạng đề xuất cho từng ngôn ngữ trong số này. Tham chiếu tệp mẫu này để giúp bạn tạo tệp locale_config.xml của riêng mình cho tập hợp các ngôn ngữ mà ứng dụng hỗ trợ.

<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
   <locale android:name="af"/> <!-- Afrikaans -->
   <locale android:name="am"/> <!-- Amharic -->
   <locale android:name="ar"/> <!-- Arabic -->
   <locale android:name="as"/> <!-- Assamese -->
   <locale android:name="az"/> <!-- Azerbaijani -->
   <locale android:name="be"/> <!-- Belarusian -->
   <locale android:name="bg"/> <!-- Bulgarian -->
   <locale android:name="bn"/> <!-- Bengali -->
   <locale android:name="bs"/> <!-- Bosnian -->
   <locale android:name="ca"/> <!-- Catalan -->
   <locale android:name="cs"/> <!-- Czech -->
   <locale android:name="da"/> <!-- Danish -->
   <locale android:name="de"/> <!-- German -->
   <locale android:name="el"/> <!-- Greek -->
   <locale android:name="en-AU"/> <!-- English (Australia) -->
   <locale android:name="en-CA"/> <!-- English (Canada) -->
   <locale android:name="en-GB"/> <!-- English (United Kingdom) -->
   <locale android:name="en-IN"/> <!-- English (India) -->
   <locale android:name="en-US"/> <!-- English (United States) -->
   <locale android:name="en-XA"/> <!-- English (Pseudo-Accents) -->
   <locale android:name="es"/> <!-- Spanish (Spain) -->
   <locale android:name="es-US"/> <!-- Spanish (United States) -->
   <locale android:name="et"/> <!-- Estonian -->
   <locale android:name="eu"/> <!-- Basque -->
   <locale android:name="fa"/> <!-- Farsi -->
   <locale android:name="fi"/> <!-- Finnish -->
   <locale android:name="fr"/> <!-- French (France) -->
   <locale android:name="fr-CA"/> <!-- French (Canada) -->
   <locale android:name="gl"/> <!-- Galician -->
   <locale android:name="gu"/> <!-- Gujarati -->
   <locale android:name="hi"/> <!-- Hindi -->
   <locale android:name="hr"/> <!-- Croatian -->
   <locale android:name="hu"/> <!-- Hungarian -->
   <locale android:name="hy"/> <!-- Armenian -->
   <locale android:name="in"/> <!-- Indonesian -->
   <locale android:name="is"/> <!-- Icelandic -->
   <locale android:name="it"/> <!-- Italian -->
   <locale android:name="iw"/> <!-- Hebrew -->
   <locale android:name="ja"/> <!-- Japanese -->
   <locale android:name="ka"/> <!-- Georgian -->
   <locale android:name="kk"/> <!-- Kazakh -->
   <locale android:name="km"/> <!-- Khmer -->
   <locale android:name="kn"/> <!-- Kannada -->
   <locale android:name="ko"/> <!-- Korean -->
   <locale android:name="ky"/> <!-- Kyrgyz -->
   <locale android:name="lo"/> <!-- Lao -->
   <locale android:name="lt"/> <!-- Lithuanian -->
   <locale android:name="lv"/> <!-- Latvian -->
   <locale android:name="mk"/> <!-- Macedonian -->
   <locale android:name="ml"/> <!-- Malayalam -->
   <locale android:name="mn"/> <!-- Mongolian -->
   <locale android:name="mr"/> <!-- Marathi -->
   <locale android:name="ms"/> <!-- Malay -->
   <locale android:name="my"/> <!-- Burmese -->
   <locale android:name="my-MM"/> <!-- Burmese (Myanmar) -->
   <locale android:name="nb"/> <!-- Norwegian -->
   <locale android:name="ne"/> <!-- Nepali -->
   <locale android:name="nl"/> <!-- Dutch -->
   <locale android:name="or"/> <!-- Odia -->
   <locale android:name="pa"/> <!-- Punjabi -->
   <locale android:name="pl"/> <!-- Polish -->
   <locale android:name="pt-BR"/> <!-- Portuguese (Brazil) -->
   <locale android:name="pt-PT"/> <!-- Portuguese (Portugal) -->
   <locale android:name="ro"/> <!-- Romanian -->
   <locale android:name="ru"/> <!-- Russian -->
   <locale android:name="si"/> <!-- Sinhala -->
   <locale android:name="sk"/> <!-- Slovak -->
   <locale android:name="sl"/> <!-- Slovenian -->
   <locale android:name="sq"/> <!-- Albanian -->
   <locale android:name="sr"/> <!-- Serbian (Cyrillic) -->
   <locale android:name="sr-Latn"/> <!-- Serbian (Latin) -->
   <locale android:name="sv"/> <!-- Swedish -->
   <locale android:name="sw"/> <!-- Swahili -->
   <locale android:name="ta"/> <!-- Tamil -->
   <locale android:name="te"/> <!-- Telugu -->
   <locale android:name="th"/> <!-- Thai -->
   <locale android:name="tl"/> <!-- Filipino -->
   <locale android:name="tr"/> <!-- Turkish -->
   <locale android:name="uk"/> <!-- Ukrainian -->
   <locale android:name="ur"/> <!-- Urdu -->
   <locale android:name="uz"/> <!-- Uzbek -->
   <locale android:name="vi"/> <!-- Vietnamese -->
   <locale android:name="zh-CN"/> <!-- Chinese (Simplified) -->
   <locale android:name="zh-HK"/> <!-- Chinese (Hong Kong) -->
   <locale android:name="zh-TW"/> <!-- Chinese (Traditional) -->
   <locale android:name="zu"/> <!-- Zulu -->
</locale-config>