Hỗ trợ nhiều ngôn ngữ và văn hoá

Ứng dụng bao gồm những tài nguyên có thể chỉ dành cho một nền văn hoá cụ thể. Ví dụ: một ứng dụng có thể bao gồm các chuỗi dành riêng cho văn hoá cụ thể được dịch sang ngôn ngữ của ngôn ngữ hiện tại.

Phương pháp tốt là tách biệt các tài nguyên dành riêng cho ngôn ngữ và văn hoá cụ thể với phần còn lại của ứng dụng. Android phân chia tài nguyên dành riêng cho ngôn ngữ và văn hoá cụ thể dựa trên tuỳ chọn cài đặt ngôn ngữ của hệ thống. Bạn có thể hỗ trợ nhiều ngôn ngữ bằng cách sử dụng thư mục tài nguyên trong dự án Android.

Bạn có thể chỉ định tài nguyên phù hợp với văn hoá của người dùng ứng dụng. Bạn có thể cung cấp mọi loại tài nguyên phù hợp với ngôn ngữ và văn hoá của người dùng. Ví dụ: ảnh chụp màn hình sau đây cho thấy một ứng dụng hiển thị chuỗi và tài nguyên có thể vẽ bằng ngôn ngữ en_US mặc định của thiết bị và ngôn ngữ es_ES Tây Ban Nha.

Ứng dụng hiển thị một văn bản và biểu tượng khác tuỳ thuộc vào ngôn ngữ hiện tại

Hình 1. Ứng dụng dùng tài nguyên khác nhau tuỳ thuộc vào ngôn ngữ hiện tại.

Khi bạn tạo một dự án bằng Bộ công cụ SDK Android, các công cụ này sẽ tạo một thư mục res/ ở cấp cao nhất của dự án. Trong thư mục res/ này, có nhiều thư mục con dành cho nhiều loại tài nguyên. Ngoài ra, còn có một số tệp mặc định, chẳng hạn như tệp res/values/strings.xml, chứa các giá trị chuỗi của bạn.

Việc hỗ trợ nhiều ngôn ngữ không chỉ dựa trên tài nguyên dành riêng cho từng ngôn ngữ. Một số người dùng chọn ngôn ngữ viết từ phải sang trái (RTL), như tiếng Ả Rập hoặc Do Thái, cho ngôn ngữ trên giao diện người dùng của họ. Những người dùng khác đặt ngôn ngữ trên giao diện người dùng thành một ngôn ngữ sử dụng chữ viết LTR, chẳng hạn như tiếng Anh, có thể xem hoặc tạo nội dung bằng ngôn ngữ sử dụng chữ viết RTL. Để hỗ trợ cả hai loại người dùng này, ứng dụng của bạn cần làm những việc sau:

  • Sử dụng bố cục của giao diện người dùng RTL cho ngôn ngữ RTL.
  • Phát hiện và khai báo hướng của dữ liệu văn bản hiển thị bên trong tin nhắn có định dạng. Thông thường, bạn có thể gọi một phương thức, như mô tả trong hướng dẫn này, giúp xác định hướng của dữ liệu văn bản cho bạn.

Tạo thư mục ngôn ngữ và tệp tài nguyên

Để hỗ trợ nhiều ngôn ngữ khác, hãy tạo thêm thư mục bên trong res/. Tên của mỗi thư mục phải tuân theo định dạng sau:

<resource type>-b+<language code>[+<country code>]

Ví dụ: values-b+es/ chứa tài nguyên chuỗi cho các ngôn ngữ có mã ngôn ngữ es. Tương tự, mipmap-b+es+ES/ chứa biểu tượng dành cho ngôn ngữ có mã ngôn ngữ es và mã quốc gia ES.

Android tải các tài nguyên phù hợp theo chế độ cài đặt ngôn ngữ của thiết bị trong thời gian chạy. Để biết thêm thông tin, hãy xem phần Cung cấp tài nguyên thay thế.

Sau khi bạn quyết định những ngôn ngữ cần hỗ trợ, hãy tạo thư mục con và tệp tài nguyên. Ví dụ:

MyProject/
    res/
       values/
           strings.xml
       values-b+es/
           strings.xml
       mipmap/
           country_flag.png
       mipmap-b+es+ES/
           country_flag.png

Điền sẵn các tài nguyên đã bản địa hoá vào tệp tài nguyên. Sau đây là ví dụ về các tệp tài nguyên chuỗi và hình ảnh đã bản địa hoá:

Chuỗi tiếng Anh (ngôn ngữ mặc định) trong /values/strings.xml:

<resources>
    <string name="hello_world">Hello World!</string>
</resources>

Chuỗi tiếng Tây Ban Nha (ngôn ngữ es) trong /values-b+es/strings.xml:

<resources>
    <string name="hello_world">¡Hola Mundo!</string>
</resources>

Biểu tượng cờ Hoa Kỳ (ngôn ngữ mặc định) trong /mipmap/country_flag.png:

Biểu tượng cờ của Hoa Kỳ

Hình 2. Biểu tượng dùng cho ngôn ngữ (en_US) mặc định.

Biểu tượng cờ Tây Ban Nha (ngôn ngữ es_ES) trong /mipmap-b+es+ES/country_flag.png:

Biểu tượng cờ của Tây Ban Nha

Hình 3. Biểu tượng dùng cho ngôn ngữ es_ES.

Lưu ý: Bạn có thể dùng chuỗi định tính cấu hình, chẳng hạn như bộ hạn định ngôn ngữ, trên bất kỳ loại tài nguyên nào. Ví dụ: bạn nên cung cấp các phiên bản đã bản địa hoá của đối tượng bitmap có thể vẽ. Để biết thêm thông tin, hãy xem bài viết Bản địa hoá ứng dụng.

Dùng tài nguyên trong ứng dụng của bạn

Tham chiếu tài nguyên trong mã nguồn và tệp XML khác bằng cách sử dụng thuộc tính name của từng tài nguyên: R.<resource type>.<resource name>. Có nhiều phương thức chấp nhận tài nguyên theo cách này, như minh hoạ trong các ví dụ sau:

Kotlin

// Get a string resource
val hello = resources.getString(R.string.hello_world)

// Or supply a string resource to a method that requires a string
TextView(this).apply {
    setText(R.string.hello_world)
}

Java

// Get a string resource
String hello = getResources().getString(R.string.hello_world);

// Or supply a string resource to a method that requires a string
TextView textView = new TextView(this);
textView.setText(R.string.hello_world);

Trong tệp XML, bạn có thể tham chiếu đến một tài nguyên theo cú pháp @<resource type>/<resource name> bất cứ khi nào thuộc tính XML chấp nhận một giá trị tương thích, như minh hoạ trong ví dụ sau:

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@mipmap/country_flag" />

Lưu ý: Để đảm bảo chế độ cài đặt ngôn ngữ của người dùng được ưu tiên chính xác, hãy chỉ định ngôn ngữ mà ứng dụng của bạn hỗ trợ bằng thuộc tính resConfigs. Để biết thêm thông tin, hãy xem phần Chỉ định ngôn ngữ mà ứng dụng của bạn hỗ trợ.

Định dạng văn bản trong thông báo

Một trong những nhiệm vụ phổ biến nhất trong ứng dụng là định dạng văn bản. Thông báo đã bản địa hoá được định dạng bằng cách chèn dữ liệu dạng văn bản và số vào các vị trí thích hợp. Rất tiếc, khi xử lý dữ liệu RTL hoặc giao diện người dùng RTL, định dạng đơn giản có thể hiển thị đầu ra văn bản không chính xác hoặc thậm chí không thể đọc được.

Các ngôn ngữ như tiếng Ả Rập, Do Thái, Ba Tư và Urdu được viết từ phải sang trái (RTL). Tuy nhiên, một số thành phần, chẳng hạn như số và văn bản LTR nhúng, lại được viết từ trái sang phải (LTR) trong văn bản theo hướng RTL. Các ngôn ngữ sử dụng chữ viết LTR, gồm cả tiếng Anh, cũng có hai chiều vì các chữ viết này có thể chứa các chữ viết RTL nhúng cần được hiển thị theo hướng RTL.

Ứng dụng thường tạo các thực thể của loại văn bản nhúng theo hướng ngược lại này, chẳng hạn như bằng cách chèn dữ liệu văn bản của một ngôn ngữ tuỳ ý và hướng văn bản tuỳ ý vào các thông báo đã bản địa hoá. Việc kết hợp các hướng này thường không bao gồm chỉ báo rõ ràng về nơi văn bản theo hướng ngược lại bắt đầu và kết thúc, vì vậy, văn bản do ứng dụng tạo có thể gây ra trải nghiệm kém cho người dùng.

Dù cách xử lý mặc định đối với văn bản hai chiều của hệ thống thường hiển thị văn bản như dự kiến, nhưng văn bản có thể không hiển thị chính xác khi ứng dụng của bạn chèn văn bản đó vào một thông báo đã bản địa hoá. Sau đây là ví dụ về các trường hợp mà văn bản có khả năng hiển thị không chính xác:

  • Văn bản được chèn vào đầu thông báo:

    PERSON_NAME đang gọi bạn

  • Văn bản bắt đầu bằng một số, chẳng hạn như địa chỉ hoặc số điện thoại:

    987 654-3210

  • Văn bản bắt đầu bằng dấu chấm câu, chẳng hạn như số điện thoại:

    +19876543210

  • Văn bản kết thúc bằng dấu chấm câu:

    Bạn có chắc chắn không?

  • Văn bản đã chứa cả hai hướng:

    Từ בננה nghĩa là chuối trong tiếng Do Thái.

Ví dụ

Giả sử một ứng dụng đôi khi cần hiển thị thông báo "Ý của bạn là %s?", với một địa chỉ được chèn vào %s trong thời gian chạy. Ứng dụng hỗ trợ nhiều ngôn ngữ trên giao diện người dùng, vì vậy, thông báo đến từ một tài nguyên dành riêng cho từng ngôn ngữ và sử dụng hướng RTL khi thiết bị được đặt thành ngôn ngữ RTL. Ví dụ: đối với một giao diện người dùng tiếng Do Thái, thông báo sẽ xuất hiện như sau:

האם התכוונת ל %s?

Tuy nhiên, địa chỉ đề xuất có thể đến từ một cơ sở dữ liệu không bao gồm văn bản bằng ngôn ngữ đó. Ví dụ: nếu địa chỉ là của một địa điểm tại California, thì địa chỉ đó sẽ xuất hiện trong cơ sở dữ liệu bằng văn bản tiếng Anh. Nếu bạn chèn địa chỉ "15 Bay Street, Laurel, CA" vào thông báo RTL mà không cung cấp bất kỳ gợi ý nào về hướng văn bản, thì kết quả sẽ không như mong đợi hoặc không chính xác:

האם התכוונת ל 15 Bay Street, Laurel, CA?

Số nhà hiện ở bên phải địa chỉ, chứ không phải ở bên trái như dự kiến. Việc này khiến số nhà càng trông như một mã bưu chính lạ. Vấn đề tương tự có thể xảy ra nếu bạn đưa văn bản RTL vào một thông báo sử dụng hướng văn bản LTR.

Giải thích và giải pháp

Vấn đề trong ví dụ này xảy ra do trình định dạng văn bản không chỉ định rằng "15" là một phần của địa chỉ, vì vậy, hệ thống không thể xác định liệu "15" có phải là một phần của văn bản RTL đứng trước hoặc văn bản LTR đứng sau nó không.

Để giải quyết vấn đề này, hãy sử dụng phương thức unicodeWrap() từ lớp BidiFormatter. Phương thức này phát hiện hướng của một chuỗi và gói chuỗi đó trong các ký tự theo định dạng Unicode để khai báo hướng đó.

Đoạn mã sau đây minh hoạ cách sử dụng unicodeWrap():

Kotlin

val mySuggestion = "15 Bay Street, Laurel, CA"
val myBidiFormatter: BidiFormatter = BidiFormatter.getInstance()

// The "did_you_mean" localized string resource includes
// a "%s" placeholder for the suggestion.
String.format(getString(R.string.did_you_mean), myBidiFormatter.unicodeWrap(mySuggestion))

Java

String mySuggestion = "15 Bay Street, Laurel, CA";
BidiFormatter myBidiFormatter = BidiFormatter.getInstance();

// The "did_you_mean" localized string resource includes
// a "%s" placeholder for the suggestion.
String.format(getString(R.string.did_you_mean),
        myBidiFormatter.unicodeWrap(mySuggestion));

Vì lúc này "15" xuất hiện bên trong văn bản được khai báo là LTR, nên "15" hiển thị ở đúng vị trí:

האם התכוונת ל 15 Bay Street, Laurel, CA?

Sử dụng phương thức unicodeWrap() trên mọi đoạn văn bản bạn chèn vào một thông báo đã bản địa hoá, trừ phi một trong các điều kiện sau áp dụng:

  • Văn bản được chèn vào một chuỗi có thể đọc được bằng máy, chẳng hạn như một URI hoặc một truy vấn SQL.
  • Bạn biết rằng đoạn văn bản đã được gói đúng cách.

Lưu ý: Nếu ứng dụng của bạn nhắm đến Android 4.3 (API cấp 18) trở lên, hãy dùng phiên bản BidiFormatter có trong Khung Android. Nếu không, sử dụng phiên bản BidiFormatter có trong Thư viện hỗ trợ.

Định dạng số

Dùng chuỗi định dạng, chứ không phải lệnh gọi phương thức, để chuyển đổi số thành các chuỗi trong logic của ứng dụng:

Kotlin

var myIntAsString = "$myInt"

Java

String myIntAsString = String.format("%d", myInt);

Hàm này sẽ định dạng các số theo cách phù hợp với ngôn ngữ của bạn, có thể bao gồm cả việc sử dụng một bộ chữ số khác.

Khi bạn sử dụng String.format() để tạo một truy vấn SQL trên thiết bị được đặt thành một ngôn ngữ sử dụng bộ chữ số riêng, chẳng hạn như tiếng Ba Tư và hầu hết tiếng Ả Rập, sự cố sẽ xảy ra nếu bất kỳ tham số nào đến truy vấn là số. Nguyên nhân là do số được định dạng trong các chữ số của ngôn ngữ và các chữ số này lại không hợp lệ trong SQL.

Để duy trì các số được định dạng theo ASCII và giữ cho truy vấn SQL hợp lệ, bạn cần sử dụng phiên bản nạp chồng của String.format() có chứa một ngôn ngữ làm tham số đầu tiên. Sử dụng Locale.US của đối số ngôn ngữ.

Hỗ trợ phản chiếu bố cục

Những người sử dụng chữ viết RTL thích giao diện người dùng RTL hơn, chẳng hạn như các trình đơn căn phải, văn bản căn phải và mũi tên tiến lên chỉ sang trái.

Hình 4 cho thấy sự tương phản giữa phiên bản LTR của một màn hình trong ứng dụng Cài đặt và phiên bản RTL của ứng dụng:

Khu vực thông báo được căn phải, nằm gần góc trên cùng bên phải, nút menu trên thanh ứng dụng ở gần góc trên cùng bên trái, nội dung trong phần chính của màn hình được căn trái và hiển thị LTR còn nút quay lại nằm gần góc dưới cùng bên trái và chỉ về bên trái. Khu vực thông báo được căn trái ở gần góc trên cùng bên trái, nút menu trên thanh ứng dụng ở gần góc trên cùng bên phải, nội dung trong phần chính của màn hình được căn phải và hiển thị RTL, còn nút quay lại ở gần góc dưới cùng bên phải và chỉ về bên phải
Hình 4. Các biến thể LTR và RTL của màn hình chế độ cài đặt.

Khi thêm tính năng hỗ trợ RTL vào ứng dụng, hãy lưu ý những điểm sau:

  • Tính năng phản chiếu văn bản RTL chỉ được hỗ trợ trong những ứng dụng được dùng trên thiết bị chạy Android 4.2 (API cấp 17) trở lên. Để tìm hiểu cách hỗ trợ tính năng phản chiếu văn bản trên thiết bị cũ, hãy xem phần Cung cấp tính năng hỗ trợ các ứng dụng cũ trong hướng dẫn này.
  • Để kiểm thử xem ứng dụng của bạn có hỗ trợ hướng văn bản RTL hay không, hãy kiểm thử bằng cách sử dụng tuỳ chọn cho nhà phát triển theo mô tả trong hướng dẫn này và mời người dùng chữ viết RTL dùng ứng dụng của bạn.

Lưu ý: Để xem các nguyên tắc thiết kế khác liên quan đến tính năng phản chiếu bố cục, bao gồm cả danh sách các phần tử phù hợp và không phù hợp để phản chiếu, hãy xem nguyên tắc Material Design về Bidirectionality (Tính hai chiều).

Để phản chiếu bố cục của giao diện người dùng trong ứng dụng để bố cục hiển thị RTL bằng ngôn ngữ RTL, hãy hoàn tất các bước trong những phần sau.

Sửa đổi tệp bản dựng và tệp kê khai

Sửa đổi tệp build.gradle của mô-đun ứng dụng và tệp kê khai ứng dụng như sau:

build.gradle (Module: app)

Groovy

android {
    ...
    defaultConfig {
        targetSdkVersion 17 // Or higher
        ...
    }
}

Kotlin

android {
    ...
    defaultConfig {
        targetSdkVersion(17) // Or higher
        ...
    }
}

AndroidManifest.xml

<manifest ... >
    ...
    <application ...
        android:supportsRtl="true">
    </application>
</manifest>

Lưu ý: Nếu ứng dụng nhắm đến Android 4.1.1 (API cấp 16) trở xuống, thì thuộc tính android:supportsRtl sẽ bị bỏ qua, cùng với mọi giá trị thuộc tính startend xuất hiện trong tệp bố cục của ứng dụng. Trong trường hợp này, việc phản chiếu bố cục RTL không tự động xảy ra trong ứng dụng của bạn.

Cập nhật tài nguyên hiện có

Lần lượt chuyển đổi left, right thành startend trong các tệp tài nguyên bố cục hiện có. Việc này cho phép khung căn chỉnh các phần tử trên giao diện người dùng của ứng dụng dựa trên chế độ cài đặt ngôn ngữ của người dùng.

Lưu ý: Trước khi cập nhật tài nguyên, hãy tìm hiểu cách hỗ trợ các ứng dụng cũ hoặc ứng dụng nhắm đến Android 4.1.1 (API cấp 16) trở xuống.

Để sử dụng khả năng căn chỉnh RTL của khung, thay đổi các thuộc tính trong các tệp bố cục nằm trong Bảng 1.

Bảng 1. Thuộc tính cần sử dụng khi ứng dụng của bạn hỗ trợ hướng đa văn bản

Thuộc tính chỉ hỗ trợ LTR Thuộc tính hỗ trợ LTR và RTL
android:gravity="left" android:gravity="start"
android:gravity="right" android:gravity="end"
android:layout_gravity="left" android:layout_gravity="start"
android:layout_gravity="right" android:layout_gravity="end"
android:paddingLeft android:paddingStart
android:paddingRight android:paddingEnd
android:drawableLeft android:drawableStart
android:drawableRight android:drawableEnd
android:layout_alignLeft android:layout_alignStart
android:layout_alignRight android:layout_alignEnd
android:layout_marginLeft android:layout_marginStart
android:layout_marginRight android:layout_marginEnd
android:layout_alignParentLeft android:layout_alignParentStart
android:layout_alignParentRight android:layout_alignParentEnd
android:layout_toLeftOf android:layout_toStartOf
android:layout_toRightOf android:layout_toEndOf

Bảng 2 cho thấy cách hệ thống xử lý các thuộc tính căn chỉnh giao diện người dùng trên phiên bản SDK mục tiêu, liệu thuộc tính leftright lẫn thuộc tính startend đã được xác định hay chưa.

Bảng 2. Hành vi căn chỉnh phần tử giao diện người dùng dựa trên phiên bản SDK mục tiêu và các thuộc tính đã xác định

Có nhắm đến Android 4.2
(API cấp 17) trở lên không?
Bên trái và bên phải được xác định chưa? Bắt đầu và kết thúc được xác định chưa? Kết quả
startend được dùng, ghi đè leftright
Không leftright được dùng
Không startend được dùng
Không leftright được dùng (startend bị bỏ qua)
Không Không leftright được dùng
Không Không startend phân giải thành leftright

Thêm tài nguyên theo hướng và ngôn ngữ cụ thể

Bước này bao gồm bổ sung các phiên bản cụ thể của tệp bố cục, có thể vẽ và giá trị tài nguyên có chứa giá trị tuỳ chỉnh cho các ngôn ngữ và hướng văn bản khác nhau.

Trong Android 4.2 (API cấp 17) trở lên, bạn có thể sử dụng bộ hạn định tài nguyên -ldrtl (layout-direction-right-to-left) và -ldltr (layout-direction-left-to-right). Để duy trì khả năng tương thích ngược với các tài nguyên hiện có, phiên bản Android cũ sẽ sử dụng các tham số định tính ngôn ngữ của tài nguyên để suy ra hướng văn bản chính xác.

Giả sử bạn muốn thêm tệp bố cục cụ thể để hỗ trợ chữ viết RTL, như tiếng Do Thái, tiếng Ả Rập và tiếng Ba Tư. Để thực hiện việc này, hãy thêm một thư mục layout-ldrtl/ vào thư mục res/, như minh hoạ trong ví dụ sau:

res/
    layout/
        main.xml This layout file is loaded by default.
    layout-ldrtl/
        main.xml This layout file is loaded for languages using an
                 RTL text direction, including Arabic, Persian, and Hebrew.

Nếu bạn muốn thêm phiên bản cụ thể của bố cục chỉ được thiết kế cho văn bản tiếng Ả Rập, thì cấu trúc thư mục của bạn sẽ có dạng như sau:

res/
    layout/
        main.xml This layout file is loaded by default.
    layout-ar/
        main.xml This layout file is loaded for Arabic text.
    layout-ldrtl/
        main.xml This layout file is loaded only for non-Arabic
                 languages that use an RTL text direction.

Lưu ý: Tài nguyên dành riêng cho ngôn ngữ được ưu tiên hơn tài nguyên dành riêng cho hướng bố cục. Tài nguyên này lại được ưu tiên hơn tài nguyên mặc định.

Sử dụng tiện ích được hỗ trợ

Kể từ Android 4.2 (API cấp 17), hầu hết các phần tử giao diện người dùng của khung đều tự động hỗ trợ hướng văn bản RTL. Tuy nhiên, một số phần tử khung, như ViewPager, không hỗ trợ hướng văn bản RTL.

Các tiện ích trên màn hình chính hỗ trợ hướng văn bản RTL, miễn là tệp kê khai tương ứng của tiện ích đó bao gồm việc gán thuộc tính android:supportsRtl="true".

Hỗ trợ các ứng dụng cũ

Nếu ứng dụng của bạn nhắm đến Android 4.1.1 (API cấp 16) trở xuống, thì ngoài startend, bạn còn phải thêm các thuộc tính leftright.

Để kiểm tra xem bố cục của bạn có cần sử dụng hướng văn bản RTL hay không, hãy sử dụng logic sau:

Kotlin

private fun shouldUseLayoutRtl(): Boolean {
    return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
        View.LAYOUT_DIRECTION_RTL == layoutDirection
    } else {
        false
    }
}

Java

private boolean shouldUseLayoutRtl() {
    if (android.os.Build.VERSION.SDK_INT >=
            android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return View.LAYOUT_DIRECTION_RTL == getLayoutDirection();
    } else {
        return false;
    }
}

Lưu ý: Để tránh các vấn đề về khả năng tương thích, sử dụng phiên bản 23.0.1 trở lên của Công cụ xây dựng SDK Android.

Kiểm thử bằng cách sử dụng tuỳ chọn cho nhà phát triển

Trên thiết bị chạy Android 4.4 (API cấp 19) trở lên, bạn có thể bật Buộc hướng bố cục RTL trong các tuỳ chọn cho nhà phát triển trên thiết bị. Chế độ cài đặt này cho phép bạn xem văn bản sử dụng chữ viết LTR, chẳng hạn như văn bản tiếng Anh, ở chế độ RTL.

Cập nhật logic của ứng dụng

Phần này mô tả các khía cạnh cụ thể của logic ứng dụng để cập nhật khi điều chỉnh ứng dụng cho việc xử lý nhiều hướng văn bản.

Các thay đổi về thuộc tính

Để xử lý thay đổi trong các thuộc tính có liên quan đến RTL – chẳng hạn như hướng bố cục, tham số bố cục, khoảng đệm, hướng văn bản, căn chỉnh văn bản hoặc vị trí có thể vẽ, hãy sử dụng lệnh gọi lại onRtlPropertiesChanged(). Lệnh gọi lại này cho phép bạn lấy hướng bố cục hiện tại và cập nhật các đối tượng View của hoạt động cho phù hợp.

Khung hiển thị

Nếu bạn đang tạo tiện ích giao diện người dùng mà không trực tiếp nằm trong hệ phân cấp chế độ xem của hoạt động, chẳng hạn như hộp thoại hoặc phần tử giao diện người dùng kiểu thông báo ngắn, thì đặt hướng bố cục chính xác tuỳ thuộc vào ngữ cảnh. Đoạn mã sau đây cho thấy cách hoàn tất quy trình này:

Kotlin

val config: Configuration = context.resources.configuration
view.layoutDirection = config.layoutDirection

Java

final Configuration config =
    getContext().getResources().getConfiguration();
view.setLayoutDirection(config.getLayoutDirection());

Một số phương thức của lớp View cần được xem xét thêm:

onMeasure()
Kích thước khung hiển thị có thể thay đổi tuỳ theo hướng văn bản.
onLayout()
Nếu tự tạo phương thức triển khai bố cục riêng, thì bạn cần gọi super() trong phiên bản của onLayout() và điều chỉnh logic tuỳ chỉnh để hỗ trợ chữ viết RTL.
onDraw()
Nếu đang triển khai khung hiển thị tuỳ chỉnh hoặc thêm chức năng nâng cao vào một bản vẽ, thì bạn sẽ cần cập nhật mã để hỗ trợ chữ viết RTL. Sử dụng mã sau để xác định liệu tiện ích của bạn có đang ở chế độ RTL hay không:

Kotlin

// On devices running Android 4.1.1 (API level 16) and lower,
// you can call the isLayoutRtl() system method directly.
fun isLayoutRtl(): Boolean = layoutDirection == LAYOUT_DIRECTION_RTL

Java

// On devices running Android 4.1.1 (API level 16) and lower,
// you can call the isLayoutRtl() system method directly.
public boolean isLayoutRtl() {
    return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
}

Đối tượng có thể vẽ

Nếu một đối tượng có thể vẽ cần được phản chiếu cho bố cục RTL, hãy hoàn thành một trong các bước sau dựa trên phiên bản Android đang chạy trên thiết bị:

  • Trên các thiết bị chạy Android 4.3 (API cấp 18) trở xuống, hãy thêm và xác định các tệp tài nguyên -ldrtl.
  • Trên Android 4.4 (API cấp 19) trở lên, hãy sử dụng android:autoMirrored="true" khi xác định đối tượng có thể vẽ để cho phép hệ thống xử lý việc phản chiếu bố cục RTL cho bạn.

    Lưu ý: Thuộc tính android:autoMirrored chỉ hoạt động đối với các đối tượng có thể vẽ đơn giản mà chế độ phản chiếu hai chiều của đối tượng đó chỉ là phản chiếu đồ hoạ của toàn bộ đối tượng có thể vẽ. Nếu đối tượng có thể vẽ chứa nhiều phần tử hoặc nếu việc phản ánh đối tượng có thể vẽ của bạn làm thay đổi phần diễn giải của đối tượng, thì bạn có thể tự thực hiện việc phản chiếu. Mỗi khi có thể, hãy trao đổi với một chuyên gia hai chiều để xác định liệu các đối tượng có thể vẽ được phản chiếu có phù hợp với người dùng hay không.

Gravity (Trọng lực)

Nếu mã bố cục của ứng dụng dùng Gravity.LEFT hoặc Gravity.RIGHT, hãy thay đổi các giá trị này thành Gravity.STARTGravity.END tương ứng.

Nếu có mã Kotlin hoặc Java phụ thuộc vào các thuộc tính Gravity.LEFT hoặc Gravity.RIGHT, bạn có thể điều chỉnh mã đó để hoạt động với sự thay đổi này bằng cách đặt absoluteGravity cho khớp với layoutDirection.

Ví dụ: nếu bạn đang sử dụng mã sau:

Kotlin

when (gravity and Gravity.HORIZONTAL_GRAVITY_MASK) {
    Gravity.LEFT -> {
        // Handle objects that are left-aligned.
    }
    Gravity.RIGHT -> {
        // Handle objects that are right-aligned.
    }
}

Java

switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    case Gravity.LEFT:
        // Handle objects that are left-aligned.
        break;
    case Gravity.RIGHT:
        // Handle objects that are right-aligned.
        break;
}

Hãy thay đổi thành như sau:

Kotlin

val absoluteGravity: Int = Gravity.getAbsoluteGravity(gravity, layoutDirection)
when (absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK) {
    Gravity.LEFT -> {
        // Handle objects that are left-aligned.
    }
    Gravity.RIGHT -> {
        // Handle objects that are right-aligned.
    }
}

Java

final int layoutDirection = getLayoutDirection();
final int absoluteGravity =
        Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
    case Gravity.LEFT:
        // Handle objects that are left-aligned.
        break;
    case Gravity.RIGHT:
        // Handle objects that are right-aligned.
        break;
}

Điều này nghĩa là bạn có thể giữ mã hiện có để xử lý các giá trị được căn trái và được căn phải, ngay cả khi bạn đang sử dụng startend cho các giá trị trọng lực của mình.

Lưu ý: Khi áp dụng chế độ cài đặt trọng lực, hãy sử dụng phiên bản quá tải của Gravity.apply() gồm cả đối số layoutDirection.

Lề và khoảng đệm

Để hỗ trợ chữ viết RTL trong ứng dụng của bạn, hãy làm theo các phương pháp hay nhất liên quan đến giá trị lề và khoảng đệm:

  • Sử dụng getMarginStart()getMarginEnd() thay vì đối số tương đương của thuộc tính hướng cụ thể: leftMarginrightMargin.
  • Khi sử dụng setMargins(), hãy hoán đổi các giá trị của đối số leftright nếu ứng dụng của bạn phát hiện chữ viết RTL.
  • Nếu ứng dụng của bạn chứa logic khoảng đệm tuỳ chỉnh, hãy ghi đè setPadding()setPaddingRelative().

Hỗ trợ lựa chọn ưu tiên về ngôn ngữ cho mỗi ứng dụ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) nhưng lại 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 phù hợp 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ữ:

  • Chế độ 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 dùng 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 để 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 cách 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 ứng dụng dùng bộ chọn ngôn ngữ tuỳ chỉnh trong ứng dụng có thể sử dụng các API này để cung cấp cho người dùng trải nghiệm nhất quán, bất kể họ chọn 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 và hỗ trợ APK phân tách. Các API này cũng hỗ trợ tính năng Tự động sao lưu cho ứ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, những API tương đương cũng có trong AndroidX. Bạn nên sử dụng Appcompat 1.6.0-beta01 trở nên.

    Để tìm hiểu thêm, hãy xem hướng dẫn về cách triển khai API mới.

Xem thêm

Tài nguyên khác

Để tìm hiểu thêm về cách hỗ trợ thiết bị cũ, xem các tài nguyên sau:

Bài đăng trên blog