字串資源提供應用程式所用的文字字串,並可選擇文字樣式和格式。有三種類型的資源可為應用程式提供字串:
所有字串都可以套用樣式標記和格式化引數。如需樣式和格式化字串的相關資訊,請參閱「格式化和樣式」一節。
字串
可從應用程式程式碼 (例如可組合函式) 或其他資源檔案參照的單一字串。
- 檔案位置:
res/values/filename.xml
您可以使用任意檔案名稱。<string>元素的name會做資源 ID 使用。- 編譯資源資料類型:
String的資源指標。- 資源參照:
-
Kotlin:
R.string.string_name
XML:@string/string_name - 語法:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- 元素:
- 例如:
- XML 檔案儲存在
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
此應用程式程式碼會使用
stringResource()從可組合函式內擷取字串:@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
注意:如要在可組合函式外部擷取字串,請使用
您也可以從其他 XML 檔案 (例如context.getString(R.string.hello)。AndroidManifest.xml) 參照字串資源:<activity android:name=".MainActivity" android:label="@string/hello" />
字串陣列
可從應用程式參照的字串陣列。
- 檔案位置:
res/values/filename.xml
您可以使用任意檔案名稱。<string-array>元素的name會做資源 ID 使用。- 編譯資源資料類型:
String陣列的資源指標。- 資源參照:
-
Kotlin:
R.array.string_array_name
XML:@[package:]array/string_array_name - 語法:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- 元素:
- 例如:
- XML 檔案儲存在
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>
此應用程式程式碼會從可組合函式內擷取字串陣列 (使用
stringArrayResource()):@Composable fun PlanetList() { val planets: Array
= stringArrayResource(R.array.planets_array) // Render the array, e.g. inside a LazyColumn. } 注意:如要在可組合函式外部擷取字串陣列,請使用
context.resources.getStringArray(R.array.planets_array)。
數量字串 (複數)
不同的語言,對於數量的文法一致性有不同的規則。以英文為例,數量 1 是一種特殊情況。我們會寫「1 Book」,但如果是其他數量,則會寫「n Books」。單數與複數的區別非常重要,但其他語言則需採用更精細的方式。Android 支援的完整組合為 zero、one、two、few、many 和 other。
決定特定語言和數量的使用方式規則可能會很複雜,因此 Android 提供 pluralStringResource() 等方式,協助您選擇合適的資源。
雖然過去稱為「數量字串」(在 API 中依然如此稱呼),但數量字串「只能」用於複數形式。舉例來說,您不應該使用數量字串實作如 Gmail 的「Inbox」(收件匣) 與有未讀郵件時顯示的「Inbox (12)」這類的項目。使用數量字串而不是 if 陳述式,也許看起來很方便,但一定要注意的一點是某些語言 (例如中文) 就完全沒有單複數的文法差別,因此一律會取得 other 字串。
選擇要使用的字串時,這完全是根據文法的「必要性」而決定。對英文來說,即使數量為 0,也會忽略 zero 的字串,這是因為 0 與 2,或是任何其他除了 1 以外的數字並沒有文法上的差異 (「Zero Books」、「One Book」、「Two Books」等等)。反之,在韓文中,「只會」用到 other 字串。
不過,別誤以為 two 只能套用至數量為 2 的情況:在某種語言中,有可能必須將 2、12、102 等數量視為同一種情況,並採取與其他數量不同的處理方式。如要瞭解語言規則的差異,請諮詢翻譯人員。
如果訊息中不含數量,就可能不適合使用複數。以立陶宛語為例,1 和 101 都使用單數形式,因此「1 本書」會翻譯為「1 knyga」,「101 本書」會翻譯為「101 knyga」。而「一本書」是「knyga」,「許多本書」則是「daug knygų」。如果英文複數訊息包含「a book」(單數) 和「many books」(複數),但沒有實際數字,則可翻譯為「knyga」(一本書)/「daug knygų」(許多書),但根據立陶宛文規則,如果數字剛好是 101,則會顯示「knyga」(一本書)。
通常來說,使用「Books: 1」等數量中立的寫法,就可以避免使用數量字串。如果應用程式可以接受使用這種樣式,您和您的翻譯人員都會輕鬆很多。
在 API 24 以上版本中,您可以改用功能更強大的 ICU MessageFormat 類別。
- 檔案位置:
res/values/filename.xml
您可以使用任意檔案名稱。<plurals>元素的name會做資源 ID 使用。- 資源參照:
-
在 Kotlin 中:
R.plurals.plural_name - 語法:
-
<?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>
- 元素:
- 例如:
XML 檔案儲存在
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>
XML 檔案儲存在
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>
此應用程式程式碼會從可組合函式內擷取複數字串 (使用
pluralStringResource()):@Composable fun SongCount(count: Int) { Text( text = pluralStringResource( R.plurals.numberOfSongsAvailable, count, count, ) ) }
使用
pluralStringResource()函式時,如果您的字串包含有數字的字串格式,您就必須傳遞count兩次。舉例來說,如果是%d songs found字串,第一個count參數會選取適當的複數字串,並在%d預留位置插入第二個count參數。如果複數字串不包含字串格式,則不需要傳遞第三個參數至pluralStringResource。注意:如要在可組合函式外擷取複數字串,請使用
context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count)。
格式與樣式
以下是有關正確設定字串資源格式和樣是的幾點重要注意事項。
處理特殊字元
如果字串包含 XML 中有特殊用途的字元,您就必須根據標準 XML/HTML 逸出規則逸出字元。如果需要逸出 Android 中具有特殊意義的字元,則應於前面加上反斜線。
根據預設,Android 會將空白字元的序列收合在單一空格中。使用雙引號括住字串的相關部分,就可以避免出現此情況。在這種情況下,所有空白字元 (包括換行符號) 都會保留在引號內的區域中。雙引號也可讓您使用一般的單一未逸出引號。
| 字元 | 逸出形式 |
|---|---|
| @ | \@ |
| ? | \? |
| 換行 | \n |
| Tab 鍵 | \t |
| U+XXXX 萬國碼 (Unicode) 字元 | \uXXXX |
單引號 (') |
下列任何項目:
|
雙引號 (") |
\"
請注意,使用單引號括住字串並沒有效果。 |
以 XML 剖析資源檔案後,就會收合空白字元,且 Android 會逸出。也就是說,<string>      </string> (空格、標點符號空格、萬國碼 (Unicode) Em 空格) 全部會收合成單一空格 (" "),這是因為以 XML 剖析檔案之後,這些項目都會是萬國碼 (Unicode) 空格。如要保留這些空格,您可以加上引號 (<string>"      "</string>) 或使用 Android 逸出功能 (<string> \u0032 \u8200 \u8195</string>)。
格式化字串
如要格式化字串,可以在字串資源中加入格式引數,如下方範例資源所示。
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
此應用程式程式碼會將引數直接傳遞至 stringResource(),在可組合函式內格式化字串:
@Composable fun WelcomeMessage(username: String, mailCount: Int) { Text( text = stringResource( R.string.welcome_messages, username, mailCount, ) ) }
使用 HTML 標記設定樣式
您可以使用 HTML 標記,在字串中加入樣式。例如:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
系統支援下列 HTML 元素:
- 粗體:
<b> - 斜體:
<i>、<cite>、<dfn>、<em> - 文字放大 25%:
<big> - 縮小 20% 的文字:
<small> - 設定字型屬性:
<font face="font_family" color="hex_color">。可能的字型系列範例包括monospace、serif和sans_serif。 - 設定等寬字型系列:
<tt> - 刪除線:
<s>、<strike>、<del> - 底線:
<u> - 上標:
<sup> - 下標:
<sub> - 項目符號:
<ul>、<li> - 換行符號:
<br> - 除號:
<div> - CSS 樣式:
<span style="color|background_color|text-decoration"> - 段落:
<p dir="rtl | ltr" style="…">
在某些情況下,您也許會想建立也會做格式字串使用的樣式文字資源。一般而言,這並不會發揮作用,因為格式化方法 (例如 stringResource()) 會去除字串中的所有樣式資訊。解決方法是編寫有逸出實體的 HTML 標記,然後在格式化後使用 AnnotatedString.fromHtml() 進行復原。例如:
- 儲存樣式文字資源為 HTML 逸出字串:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
在此格式字串中,系統會加入
<b>元素。請注意,左括號是使用<標記法的 HTML 逸出。 - 然後依照一般方式格式化字串,不過也要呼叫
AnnotatedString.fromHtml(),將 HTML 文字轉換為樣式 Compose 字串。
由於 fromHtml() 會格式化所有 HTML 實體,因此請務必在搭配格式化文字的字串中使用 TextUtils.htmlEncode() 逸出任何可能的 HTML 字元。
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) ) }
使用 AnnotatedString 設定樣式
AnnotatedString 是 Compose 文字物件,您可以使用顏色和字體粗細等屬性設定樣式。使用 buildAnnotatedString 和 withStyle 以程式輔助方式建構樣式文字。
這段應用程式程式碼會建立具有混合樣式的單一文字元素:
@Composable fun StyledGreeting() { val styled = buildAnnotatedString { append("Welcome to ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append("Android") } append("!") } Text(text = styled) }
如要套用顏色、字型大小和文字裝飾,請使用 SpanStyle。如要套用段落層級的樣式 (例如對齊方式或行高),請使用 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) }
建議您直接建構 AnnotatedString,適用於單一語言的應用程式,或 Compose 中的靜態文字。不過,如要翻譯需要本地化的樣式文字,請參閱下一節詳述的 XML <annotation> 方法。
使用註解設定翻譯字串的樣式
如要為字串自訂樣式並翻譯,請在每個語言代碼的 strings.xml 中定義 <annotation> 標記。無論註解在句子中的位置為何,譯者都會保留註解。使用 context.resources.getText() 讀取字串、走訪其 Annotation 範圍,並將結果轉換為 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) }
XML 中的 <annotation> 標記維持不變。只有取回代碼不同。翻譯人員仍須移動標記,在每種語言中包住正確的字詞。
其他資源
如要進一步瞭解字串資源,請參閱下列其他資源: