在 string.xml
中,是否可以使用占位符来表示字符串值,在运行时将其赋值?
例如:
一些字符串 PLACEHOLDER1 更多的字符串
在 string.xml
中,是否可以使用占位符来表示字符串值,在运行时将其赋值?
例如:
一些字符串 PLACEHOLDER1 更多的字符串
是的,可以参考来自字符串资源:格式和样式的以下内容。
如果你需要使用
String.format(String, Object...)
格式化字符串,则可以通过将格式化参数放入字符串资源中来实现。例如,使用以下资源:在这个示例中,格式字符串有两个参数:
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
%1$s
是一个字符串,%2$d
是一个十进制数。你可以这样从你的应用程序中格式化带有参数的字符串:
Resources res = getResources(); String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
基本用法
getString
有一个重载,可以使用字符串作为格式字符串:
String text = res.getString(R.string.welcome_messages, username, mailCount);
复数形式
如果你需要处理复数形式,可以使用以下方法:
<plurals name="welcome_messages"> <item quantity="one">Hello, %1$s! You have a new message.</item> <item quantity="other">Hello, %1$s! You have %2$d new messages.</item> </plurals>
第一个
mailCount
参数用于确定使用哪种格式(单数或复数),其他参数是您的替换内容:
Resources res = getResources(); String text = res.getQuantityString(R.plurals.welcome_messages, mailCount, username, mailCount);
查看String Resources: Plurals了解更多细节。
当我第一次看到已接受的答案中的%1$s
和%2$d
时,它们毫无意义。这里有更多的解释。
它们被称为格式说明符。在XML字符串中,它们的形式为
%[parameter_index$][format_type]
%: 百分号标记了格式说明符的开始。
参数索引: 这是一个数字,后面跟着一个美元符号。如果您有三个参数要插入到字符串中,则它们将被称为1$
,2$
和3$
。您在资源字符串中放置它们的顺序并不重要,只有您提供参数的顺序才重要。
格式类型: 有很多种格式方式(请参见文档)。以下是一些常见的格式方式:
s
字符串
d
十进制整数
f
浮点数
我们将创建以下格式化字符串,其中灰色部分是以编程方式插入的。
我的姐姐
Mary
今年12
岁。
string.xml
<string name="my_xml_string">My sister %1$s is %2$d years old.</string>
我的活动.java
String myString = "Mary";
int myInt = 12;
String formatted = getString(R.string.my_xml_string, myString, myInt);
getString
。 如果不可用,可以使用context.getResources().getString(...)
。String.format()
也可以格式化字符串。1$
和2$
这些术语的顺序不需要按那个顺序使用。也就是说,2$
可以出现在1$
之前。当为使用不同单词顺序的语言本地化应用程序时,这很有用。%1$s
,可以在xml中多次使用它。%%
来获取实际的%
字符。$
的作用,现在我已经忘记了。 - Suragch如果你想要使用来自实际 strings.xml 文件中的参数,而无需使用任何 Java 代码:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
<!ENTITY appname "WhereDat">
<!ENTITY author "Oded">
]>
<resources>
<string name="app_name">&appname;</string>
<string name="description">The &appname; app was created by &author;</string>
</resources>
这种方法不适用于资源文件,即必须将变量复制到每个需要它们的 XML 文件中。
<!DOCTYPE... ]>
部分并将其包含在多个资源文件中?有什么技巧可以实现这一点吗? - prom85我在寻找同样的内容,最终找到了以下非常简单的解决方案。最好的是:它可以直接使用。
1. 修改您的字符串资源:
<string name="welcome_messages">Hello, <xliff:g name="name">%s</xliff:g>! You have
<xliff:g name="count">%d</xliff:g> new messages.</string>
2. 使用字符串替换:
c.getString(R.string.welcome_messages,name,count);
其中 c 是 Context,name 是一个字符串变量,count 是一个整型变量
你需要包含:
<resources xmlns:xliff="http://schemas.android.com/apk/res-auto">
在您的res/strings.xml文件中。
对我来说有效。
xliff
标签在格式说明符周围的作用是什么?与仅使用 %s
和 %d
说明符相比,它们提供了什么额外的价值? - Richard Le Mesurier如果你想要写百分号(%),需要将其复制一次:
<string name="percent">%1$d%%</string>
label.text = getString(R.string.percent, 75) // Output: 75%.
%1$d%
,您将会得到错误:Format string 'percent' is not a valid format string so it should not be passed to String.format
。formatted=false"
。<string name="song_number_and_title">"%1$d ~ %2$s"</string>
<TextView android:text="@string/song_number_and_title"/>
val song = database.use { // get your song from the database }
song_number_and_title.setText(resources.getString(R.string.song_number_and_title, song.number, song.title))
作为一名曾经参与过一个带有多种语言和配置变体的大型白标解决方案的人,我可以说这需要考虑很多因素。 除了文本方向之外,仅仅语法就足以让你头疼不已。 例如,项目中的项目顺序是否会发生变化,这也是需要考虑的。
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
应该优先选择
<string name="welcome_messages">Hello, %s! You have %d new messages.</string>
但是,一旦你与经常不知道什么是字符串或整数,更不用说每种类型使用什么格式字符的翻译人员合作,或者对于那些不知道代码中参数应用顺序的普通人,甚至是你自己忘记了,或者事情发生了变化,必须同时在多个地方更新,因此像MessageFormat
这样使用。
<string name="welcome_message">Hello, {0}! You have {1} new messages.</string>
MessageFormat(R.string.welcome_message).format("Name", numMessages)
如果使用不可行,而且让非技术人员尝试理解 xlift
的想法甚至都不能被接受,那么我目前知道的最好的解决方案是使用显式、命名的占位符,如下所示:
<string name="placeholder_data" translatable="false">DATA</string>
<string name="placeholder_data" translatable="false">$DATA</string>
<string name="placeholder_data" translatable="false">%DATA%</string>
......或者其他不会与文本冲突的内容。
而您可以使用DOCTYPE,例如
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
<!ENTITY placeholder_data "$DATA">
]>
<string name="text_with_data">Your data is &placeholder_data;.</string>
main/res/values/strings.xml
中,像这样提供占位符和默认字符串。<resources>
<string name="placeholder_data" translatable="false">$DATA</string>
<string name="placeholder_error" translatable="false">$ERROR</string>
<string name="app_name">The App</string>
<string name="content_loading">loading..</string>
<string name="content_success">success: $DATA</string>
<string name="content_error">error: $ERROR</string>
</resources>
然后在你的变体variant/res/values-de/strings.xml
中进行设置
<resources>
<string name="app_name">Die Applikation</string>
<string name="content_loading">Ladevorgang..</string>
<string name="content_success">Erfolg: $DATA</string>
<string name="content_error">Netzwerkkommunikationsfehler: $ERROR</string>
</resources>
要使用它,可以写出类似以下的内容:
textView.text = when (response) {
is Data -> getText(content_success).resolveData(response.data)
is Error -> getText(content_error).resolveError(response.error)
is Loading -> getText(content_loading)
}
fun CharSequence.resolveData(data: JsonObject) =
toString().replace(getString(placeholder_data), data.toString())
fun CharSequence.resolveError(error: Throwable) =
toString().replace(getString(placeholder_error), error.toString())
为了提供翻译文件和开发参考,每个构建风格不应该有默认文件。只需要一个单一的默认文件,然后是每种语言x变体的文件。
现在还有数字语法的问题。这可以通过使用plurals
来解决,但这会增加xml文件的复杂性。正如指出的那样,zero
并不能按照人们的预期工作。但是,您可能希望由于显示大小限制或UI预渲染图像数量的限制而对应用程序计数进行限制,并且需要显示99+
而不是100
。解决方法是使用一个辅助函数,例如:
fun Context.getText(
quantity: Int,
@PluralsRes resIdQuantity: Int,
@StringRes resIdNone: Int? = null,
@StringRes resIdMoreThan: Int? = null,
maxQuantity: Int? = null,
): CharSequence {
if (resIdMoreThan != null && maxQuantity != null && quantity > maxQuantity)
return getText(resIdMoreThan)
return if (resIdNone != null && quantity == 0) return getText(resIdNone)
else resources.getQuantityText(resIdQuantity, quantity)
}
覆盖并扩展复数解析器的行为。
如果您有每个变体的可选功能,则添加一个res/values/strings-beans.xml
,如下所示:
<resources>
<string name="placeholder_name" translatable="false">$NAME</string>
<string name="placeholder_count" translatable="false">$COUNT</string>
<string name="beans_content_bean_count_zero">Hello $NAME! You have no beans.</string>
<string name="beans_content_bean_count_one">Hello $NAME! You have one bean.</string>
<string name="beans_content_bean_count_many">Hello $NAME! You have $COUNT beans.</string>
<string name="beans_content_bean_count_more_than_9000">Hello $NAME! You have over $COUNT beans!</string>
<string name="beans_content_bean_count_two">@string/beans_content_bean_count_many</string>
<string name="beans_content_bean_count_few">@string/beans_content_bean_count_many</string>
<string name="beans_content_bean_count_other">@string/beans_content_bean_count_many</string>
<plurals name="beans_content_bean_count">
<item quantity="zero">@string/beans_content_bean_count_zero</item>
<item quantity="one">@string/beans_content_bean_count_one</item>
<item quantity="two">@string/beans_content_bean_count_two</item>
<item quantity="few">@string/beans_content_bean_count_few</item>
<item quantity="many">@string/beans_content_bean_count_many</item>
<item quantity="other">@string/beans_content_bean_count_other</item>
</plurals>
</resources>
而在variant-with-beans/res/value-en/strings-beans.xml
中的变量只需要包含以下内容:
<resources>
<string name="beans_content_bean_count_zero">Hello $NAME! You have no beans.</string>
<string name="beans_content_bean_count_one">Hello $NAME! You have one bean.</string>
<string name="beans_content_bean_count_many">Hello $NAME! You have $COUNT beans.</string>
<string name="beans_content_bean_count_more_than_9000">Hello $NAME! You have over 9000 beans!</string>
</resources>
并且可以在每个文件的基础上提供特定于语言的覆盖。为了使用它,代码可以如下所示:
val name = "Bob"
val beanCount = 3
val limit = 9000
text = getText(
beanCount,
beans_content_bean_count,
beans_content_bean_count_zero,
beans_content_bean_count_more_than_9000,
limit,
)
.resolveCount(beanCount)
.resolveName(name)
这将解析为输出结果
beanCount = 0 -> "Hello Bob! You have no beans."
beanCount = 1 -> "Hello Bob! You have one bean."
beanCount = 3 -> "Hello Bob! You have 3 beans."
beanCount = 9001 -> "Hello Bob! You have over 9000 beans!"
<string name="redeem_point"> You currently have %s points(%s points = 1 %s)</string>
在你的代码中相应地使用它
coinsTextTV.setText(String.format(getContext().getString(R.string.redeem_point), rewardPoints.getReward_points()
, rewardPoints.getConversion_rate(), getString(R.string.rs)));
MessageFormat
:<string name="customer_address">Wellcome: {0} {1}</string>
String text = MessageFormat(R.string.customer_address).format("Name","Family");
https://developer.android.com/reference/java/text/MessageFormat.html