字符串资源用于为应用提供具有可选文本样式和格式设置的文本字符串。有三种类型的资源可为应用提供字符串:
所有字符串都能应用某些样式设置标记和格式设置参数。如需了解有关样式和格式设置字符串的信息,请参阅 格式和样式设置部分。
String
可从应用代码(例如可组合函数)或其他资源文件引用的单个字符串。
- 文件位置:
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>
- 元素:
- 示例:
- 保存在
res/values/strings.xml的 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>
- 元素:
- 示例:
- 保存在
res/values/strings.xml的 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 book”被翻译为“1 knyga”,“101 books”被翻译为“101 knyga”,与此同时,“a book”被翻译“knyga”,“many books”则被翻译为“daug knygų”。如果英语复数消息包含“a book”(单数)和“many books”(复数),但却没有实际数字,则可翻译为“knyga”(a book)/“daug knygų”(many books),不过根据立陶宛语的规则,系统会在数字为 101 时,显示“knyga”(a single book)。
通常,您可以利用“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>
- 元素:
- 示例:
保存在
res/values/strings.xml的 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>
保存在
res/values-pl/strings.xml的 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参数会选择合适的复数字符串, 第二个count参数会插入%d占位符内。如果您的复数字符串没有字符串格式设置,则无需向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 全角空格)会合拢为一个空格
(" "),因为它们在文件解析为 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) }
对于单语言应用或 Compose 中的静态文本,建议直接构建 AnnotatedString。不过,对于需要本地化的带样式文本,请参阅下一部分中详细介绍的 XML <annotation> 方法。
使用注解设置已翻译字符串的样式
对于需要自定义样式 和 翻译的字符串,请在每个语言区域的 strings.xml 中定义
<annotation> 标记。无论注解在句子中的位置如何,翻译人员都会保留该注解。使用
context.resources.getText() 读取字符串,遍历其 Annotation span,并将结果转换为
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> 标记保持不变。只有检索代码不同。翻译人员仍会移动标记,以在每种语言中封装正确的字词。
其他资源
如需详细了解字符串资源,请参阅以下其他资源: