Tài nguyên chuỗi cung cấp chuỗi văn bản cho ứng dụng bằng định dạng và định kiểu văn bản tuỳ chọn. Có 3 loại tài nguyên có thể cung cấp chuỗi cho ứng dụng của bạn:
- String
- Tài nguyên XML cung cấp một chuỗi đơn.
- Mảng chuỗi
- Tài nguyên XML cung cấp một mảng chuỗi.
- Chuỗi số lượng (số nhiều)
- Tài nguyên XML chứa các chuỗi khác nhau để số hoá.
Tất cả chuỗi đều có khả năng áp dụng một số đối số định dạng và đánh dấu kiểu. Để biết thông tin về cách định kiểu và định dạng các chuỗi, hãy xem phần Định dạng và định kiểu.
Chuỗi
Một chuỗi đơn có thể được tham chiếu từ mã xử lý ứng dụng (chẳng hạn như hàm composable) hoặc từ các tệp tài nguyên khác.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.namecủa phần tử<string>được dùng làm mã nhận dạng tài nguyên.- loại dữ liệu tài nguyên được biên dịch:
- Con trỏ tài nguyên đến
String. - mã tham chiếu tài nguyên:
-
Trong Kotlin:
R.string.string_name
Trong XML:@string/string_name - cú pháp:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- phần tử:
- ví dụ:
- Tệp XML được lưu vào
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Mã xử lý ứng dụng này truy xuất một chuỗi từ bên trong một thành phần kết hợp bằng
stringResource():@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
Lưu ý: Để truy xuất một chuỗi bên ngoài hàm composable, hãy dùng
Bạn cũng có thể tham chiếu các tài nguyên chuỗi từ các tệp XML khác, chẳng hạn nhưcontext.getString(R.string.hello).AndroidManifest.xml:<activity android:name=".MainActivity" android:label="@string/hello" />
Mảng chuỗi
Một mảng chuỗi có thể được tham chiếu từ ứng dụng.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.namecủa phần tử<string-array>được dùng làm mã nhận dạng tài nguyên.- loại dữ liệu tài nguyên được biên dịch:
- Con trỏ tài nguyên đến một mảng
String. - mã tham chiếu tài nguyên:
-
Trong Kotlin:
R.array.string_array_name
Trong XML:@[package:]array/string_array_name - cú pháp:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- phần tử:
- ví dụ:
- Tệp XML được lưu vào
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="planets_array"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> <item>Mars</item> </string-array> </resources>
Mã xử lý ứng dụng này truy xuất một mảng chuỗi từ bên trong một thành phần kết hợp bằng
stringArrayResource():@Composable fun PlanetList() { val planets: Array
= stringArrayResource(R.array.planets_array) // Render the array, e.g. inside a LazyColumn. } Lưu ý: Để truy xuất một mảng chuỗi bên ngoài hàm composable, hãy dùng
context.resources.getStringArray(R.array.planets_array).
Chuỗi số lượng (số nhiều)
Mỗi ngôn ngữ có những quy tắc riêng đối với thoả thuận ngữ pháp về số lượng. Chẳng hạn như trong tiếng Anh, số lượng 1 là một trường hợp đặc biệt. Chúng tôi viết "1 cuốn sách", nhưng đối với bất kỳ số lượng nào khác, chúng tôi sẽ viết "n cuốn sách". Sự khác biệt giữa số ít và số nhiều này rất phổ biến, nhưng các ngôn ngữ khác cũng giúp phân biệt rõ hơn. Tập hợp đầy đủ do Android hỗ trợ là zero, one, two, few, many và other.
Quy tắc quyết định trường hợp sử dụng cho một ngôn ngữ và số lượng nhất định có thể rất phức tạp, vì vậy, Android cung cấp cho bạn các phương thức như pluralStringResource() để chọn tài nguyên phù hợp cho bạn.
Mặc dù trước đây được gọi là "chuỗi số lượng" (và vẫn được gọi như vậy trong API), nhưng bạn chỉ nên sử dụng chuỗi số lượng cho số nhiều. Chẳng hạn sẽ là một sai lầm nếu bạn sử dụng chuỗi số lượng để triển khai một số mục như "Hộp thư đến" của Gmail so với "Hộp thư đến (12)" khi có thư chưa đọc. Việc sử dụng chuỗi số lượng thay vì một câu lệnh if có vẻ thuận tiện, nhưng quan trọng là bạn cần lưu ý một số ngôn ngữ (chẳng hạn như tiếng Trung) không tạo ra khác biệt nào về ngữ pháp. Vì vậy, bạn sẽ luôn nhận chuỗi other.
Việc lựa chọn chuỗi cần sử dụng chỉ dựa trên sự cần thiết về mặt ngữ pháp. Trong tiếng Anh, một chuỗi cho zero sẽ bị bỏ qua ngay cả khi số lượng là 0, vì số 0 không khác về mặt ngữ pháp với số 2 hoặc bất kỳ số nào khác trừ số 1 ("0 cuốn sách", "một cuốn sách", "2 cuốn sách", v.v.). Ngược lại, trong tiếng Hàn, chỉ chuỗi other được là sử dụng.
Cũng đừng nhầm lẫn bởi thực tế two có vẻ như chỉ có thể áp dụng cho số lượng 2: một ngôn ngữ có thể yêu cầu xử lý số 2, 12, 102 (v.v.) như nhau, nhưng khác với các số lượng khác. Hãy bám sát vào người biên dịch để biết ngôn ngữ của họ thực sự nhấn mạnh đến những điểm khác biệt nào.
Nếu thông báo của bạn không chứa số lượng, thì đó có thể không phải là lựa chọn phù hợp cho số nhiều. Ví dụ: trong tiếng Lithuania, dạng số ít được dùng cho cả 1 và 101, vì vậy "1 cuốn sách" được dịch thành "1 knyga" và "101 cuốn sách" được dịch thành "101 knyga". Trong khi đó, "một cuốn sách" là "knyga" và "nhiều cuốn sách" là "daug knygų". Nếu một thông báo số nhiều bằng tiếng Anh có chứa "a book" (số ít) và "many books" (số nhiều) mà không có số lượng thực tế, thì thông báo đó có thể được dịch là "knyga" (một cuốn sách)/"daug knygų" (nhiều cuốn sách), nhưng theo quy tắc của tiếng Lithuania, thông báo đó sẽ hiển thị "knyga" (một cuốn sách) khi số lượng là 101.
Bạn cũng có thể tránh các chuỗi số lượng bằng cách sử dụng các công thức trung lập về số lượng, chẳng hạn như "Sách: 1". Việc này giúp cuộc sống của bạn và những người biên dịch trở nên dễ chịu hơn nếu đó là phong cách chấp nhận được cho ứng dụng của bạn.
Thay vào đó, trên API cấp 24 trở lên, bạn có thể sử dụng lớp ICU MessageFormat mạnh mẽ hơn nhiều.
- vị trí tệp:
res/values/filename.xml
Bạn có thể tuỳ ý đặt tên tệp.namecủa phần tử<plurals>được dùng làm mã nhận dạng tài nguyên.- mã tham chiếu tài nguyên:
-
Trong Kotlin:
R.plurals.plural_name - cú pháp:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="plural_name"> <item quantity=["zero" | "one" | "two" | "few" | "many" | "other"] >text_string</item> </plurals> </resources>
- phần tử:
- ví dụ:
Tệp XML được lưu vào
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <!-- As a developer, you should always supply "one" and "other" strings. Your translators will know which strings are actually needed for their language. Always include %d in "one" because translators will need to use %d for languages where "one" doesn't mean 1 (as explained above). --> <item quantity="one">%d song found.</item> <item quantity="other">%d songs found.</item> </plurals> </resources>
Tệp XML được lưu vào
res/values-pl/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <item quantity="one">Znaleziono %d piosenkę.</item> <item quantity="few">Znaleziono %d piosenki.</item> <item quantity="other">Znaleziono %d piosenek.</item> </plurals> </resources>
Mã xử lý ứng dụng này truy xuất một chuỗi số nhiều từ bên trong một thành phần kết hợp bằng
pluralStringResource():@Composable fun SongCount(count: Int) { Text( text = pluralStringResource( R.plurals.numberOfSongsAvailable, count, count, ) ) }
Khi sử dụng hàm
pluralStringResource(), bạn cần phải truyềncounthai lần nếu chuỗi của bạn mang định dạng chuỗi có số. Chẳng hạn như đối với chuỗi%d songs found, tham sốcountđầu tiên sẽ chọn chuỗi số nhiều phù hợp, và tham sốcountthứ hai được chèn vào phần giữ chỗ%d. Nếu các chuỗi số nhiều không chứa định dạng chuỗi thì bạn không cần truyền tham số thứ ba tớipluralStringResource.Lưu ý: Để truy xuất một chuỗi số nhiều bên ngoài một hàm composable, hãy sử dụng
context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count).
Định dạng và kiểu
Dưới đây là một số điều quan trọng mà bạn nên biết về cách định dạng và định kiểu đúng cách cho tài nguyên chuỗi.
Xử lý các ký tự đặc biệt
Khi một chuỗi chứa các ký tự có cách sử dụng đặc biệt trong XML, bạn phải thoát các ký tự theo quy tắc thoát XML/HTML chuẩn. Nếu cần thoát một ký tự có ý nghĩa đặc biệt trong Android, bạn nên sử dụng dấu gạch chéo ngược phía trước.
Theo mặc định, Android sẽ thu gọn các chuỗi ký tự có khoảng trắng thành một dấu cách. Bạn có thể tránh trường hợp này bằng cách đặt phần liên quan của chuỗi trong dấu ngoặc kép. Trong trường hợp này, mọi ký tự có khoảng trắng (kể cả các dòng mới) sẽ được giữ nguyên trong vùng đã được đóng ngoặc. Dấu ngoặc kép cũng sẽ cho phép bạn sử dụng dấu nháy đơn lẻ thông thường.
| Nhân vật | (Các) Biểu mẫu thoát |
|---|---|
| @ | \@ |
| ? | \? |
| Dòng mới | \n |
| Thẻ | \t |
| Ký tự Unicode U+XXXX | \uXXXX |
Dấu nháy đơn (') |
Bất kỳ trường hợp nào sau đây:
|
Dấu ngoặc kép (") |
\"
Lưu ý là bạn không thể bao quanh chuỗi bằng dấu nháy đơn. |
Việc thu gọn khoảng trắng và ký tự thoát trên Android sẽ xảy ra sau khi tệp tài nguyên của bạn được phân tích cú pháp dưới dạng XML. Tức là <string>      </string> (dấu cách, dấu chấm câu, dấu cách Unicode Em) đều thu gọn thành một dấu cách duy nhất (" "), vì tất cả đều là dấu cách Unicode sau khi tệp được phân tích cú pháp dưới dạng XML.
Để giữ nguyên các dấu cách đó, bạn có thể trích dẫn các dấu cách đó (<string>"      "</string>) hoặc sử dụng ký tự thoát của Android (<string> \u0032 \u8200 \u8195</string>).
Định dạng chuỗi
Nếu cần định dạng chuỗi, bạn có thể thực hiện bằng cách đặt các đối số định dạng vào tài nguyên chuỗi, như được minh hoạ bằng tài nguyên ví dụ sau.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Mã xử lý ứng dụng này định dạng chuỗi từ bên trong một thành phần kết hợp bằng cách truyền trực tiếp các đối số vào stringResource():
@Composable fun WelcomeMessage(username: String, mailCount: Int) { Text( text = stringResource( R.string.welcome_messages, username, mailCount, ) ) }
Tạo kiểu bằng mã đánh dấu HTML
Bạn có thể thêm kiểu cho chuỗi bằng mã đánh dấu HTML. Ví dụ:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Các phần tử HTML sau được hỗ trợ:
- In đậm:
<b> - In nghiêng:
<i>,<cite>,<dfn>,<em> - Văn bản lớn hơn 25%:
<big> - Văn bản nhỏ hơn 20%:
<small> - Đặt thuộc tính phông chữ:
<font face="font_family" color="hex_color">. Ví dụ về các bộ phông chữ có thể có:monospace,serifvàsans_serif. - Đặt một bộ phông chữ đơn cách:
<tt> - Gạch ngang chữ:
<s>,<strike>,<del> - Gạch dưới:
<u> - Chỉ số trên:
<sup> - Chỉ số dưới:
<sub> - Dấu đầu dòng:
<ul>,<li> - Ngắt dòng:
<br> - Phân chia:
<div> - Kiểu CSS:
<span style="color|background_color|text-decoration"> - Đoạn văn:
<p dir="rtl | ltr" style="…">
Trong một số trường hợp, có thể bạn muốn tạo một tài nguyên văn bản được định kiểu cũng được dùng làm chuỗi định dạng. Thường thì cách này không hiệu quả vì các phương thức định dạng, chẳng hạn như stringResource(), sẽ tách mọi thông tin về kiểu khỏi chuỗi.
Giải pháp cho trường hợp này là viết các thẻ HTML chứa các thực thể thoát, sau đó được khôi phục bằng AnnotatedString.fromHtml() sau khi định dạng. Ví dụ:
- Lưu trữ tài nguyên văn bản đã được tạo kiểu dưới dạng chuỗi thoát HTML:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
Trong chuỗi được định dạng này, phần tử
<b>sẽ được thêm. Lưu ý dấu ngoặc mở là ký tự thoát HTML, sử dụng ký hiệu<. - Sau đó, định dạng chuỗi như bình thường, nhưng cũng gọi
AnnotatedString.fromHtml()để chuyển đổi văn bản HTML thành một chuỗi Compose được tạo kiểu.
Vì fromHtml() định dạng mọi thực thể HTML, hãy nhớ thoát mọi ký tự HTML có thể có trong chuỗi mà bạn sử dụng bằng văn bản đã định dạng, bằng cách sử dụng TextUtils.htmlEncode().
import android.text.TextUtils import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.fromHtml @Composable fun WelcomeHtmlMessage(username: String, mailCount: Int) { // Escape the username in case it contains characters like "<" or "&" val escapedUsername = TextUtils.htmlEncode(username) val text = stringResource( R.string.welcome_messages, escapedUsername, mailCount, ) Text( text = AnnotatedString.fromHtml(text) ) }
Tạo kiểu bằng AnnotatedString
AnnotatedString là một đối tượng văn bản Compose mà bạn có thể tạo kiểu bằng các thuộc tính như màu sắc và độ đậm của phông chữ. Tạo văn bản có kiểu theo phương thức lập trình bằng cách sử dụng buildAnnotatedString và withStyle.
Mã xử lý ứng dụng này tạo một phần tử văn bản duy nhất có nhiều kiểu kết hợp:
@Composable fun StyledGreeting() { val styled = buildAnnotatedString { append("Welcome to ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append("Android") } append("!") } Text(text = styled) }
Để áp dụng màu sắc, cỡ chữ và hiệu ứng trang trí văn bản, hãy sử dụng SpanStyle. Để áp dụng kiểu ở cấp đoạn văn (chẳng hạn như căn chỉnh hoặc chiều cao dòng), hãy sử dụng ParagraphStyle:
@Composable fun RichText() { val text = buildAnnotatedString { withStyle(ParagraphStyle(lineHeight = 24.sp, textAlign = TextAlign.Center)) { withStyle(SpanStyle(color = Color.Gray)) { append("Hello, ") } withStyle( SpanStyle( fontWeight = FontWeight.Bold, color = Color.Red, ) ) { append("world") } append("!") } } Text(text = text) }
Cách tốt nhất là tạo AnnotatedString trực tiếp cho các ứng dụng một ngôn ngữ hoặc văn bản tĩnh trong Compose. Tuy nhiên, đối với văn bản có kiểu cần bản địa hoá, hãy xem phương pháp <annotation> XML được trình bày chi tiết trong phần tiếp theo.
Tạo kiểu cho chuỗi đã dịch bằng chú thích
Đối với những chuỗi cần có kiểu tuỳ chỉnh và bản dịch, hãy xác định thẻ <annotation> trong strings.xml của từng ngôn ngữ. Người dịch giữ nguyên chú thích bất kể chú thích xuất hiện ở đâu trong câu. Đọc chuỗi bằng context.resources.getText(), đi qua các khoảng Annotation và chuyển đổi kết quả thành AnnotatedString:
@Composable fun AnnotatedTitle() { val context = LocalContext.current val source = context.resources.getText(R.string.title) as SpannedString val text = buildAnnotatedString { append(source.toString()) source.getSpans(0, source.length, Annotation::class.java) .forEach { annotation -> if (annotation.key == "font" && annotation.value == "title_emphasis") { addStyle( SpanStyle( fontFamily = FontFamily( Font(R.font.permanent_marker) ) ), source.getSpanStart(annotation), source.getSpanEnd(annotation), ) } } } Text(text = text) }
Thẻ <annotation> trong XML của bạn không thay đổi. Chỉ có mã truy xuất là khác nhau. Người dịch vẫn di chuyển thẻ để bao bọc từ chính xác trong mỗi ngôn ngữ.
Tài nguyên khác
Để biết thêm thông tin về tài nguyên chuỗi, hãy xem các tài nguyên bổ sung sau đây: