是否可能在string.xml中的字符串值中有占位符,可以在运行时分配值?
例子:
PLACEHOLDER1一些字符串
是否可能在string.xml中的字符串值中有占位符,可以在运行时分配值?
例子:
PLACEHOLDER1一些字符串
当前回答
格式和样式
是的,请参阅下面的字符串资源:格式和样式
If you need to format your strings using String.format(String, Object...), then you can do so by putting your format arguments in the string resource. For example, with the following resource: <string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string> In this example, the format string has two arguments: %1$s is a string and %2$d is a decimal number. You can format the string with arguments from your application like this: 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);
有关更多细节,请参阅字符串资源:复数。
其他回答
一直在寻找同样的方法,最后找到了下面这个非常简单的方法。最好的:它可以开箱即用。 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、名称、数);
其中c是上下文,名称是一个字符串变量和计数你的int变量
你需要包括
<resources xmlns:xliff="http://schemas.android.com/apk/res-auto">
在res/strings.xml中。 对我有用。:)
如果你想写百分比(%),复制它:
<string name="percent">%1$d%%</string>
label.text = getString(R.string.percent, 75) // Output: 75%.
如果你只写%1$d%,你会得到一个错误:格式字符串'percent'不是一个有效的格式字符串,所以它不应该被传递给string . Format。
或者使用格式化=false"代替。
但是,你也应该阅读Elias Mårtenson关于Android复数处理“零”的回答。对某些值(如“零”)的解释存在问题。
当你想使用实际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文件中。
多语言项目
作为一个曾经致力于大型白标解决方案的人,我可以说有很多需要考虑的地方。 除了文本方向,语法本身也会让你头疼。 例如,项目的顺序可以改变这样
<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>
然后在你的变体中,变体/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变量一个文件。
还有一个数字语法的问题。这可以用复数来解决,但这里xml文件的复杂性又增加了。而且,正如所指出的,零并不像人们所期望的那样工作。但你也可能想要限制你的应用的计数,因为显示大小限制或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!"
由于语言特定资源文件的简单性,可以使用部署工具从电子表格或公司自己的服务器端点等生成它们。
我希望你喜欢我疯狂地进入Android动态字符串资源的世界,并希望你不是可怜的傻瓜,必须在产品的iOS端获得相同的功能,根据我的经验,需要python脚本来修改.xcodeproj文件并生成swift代码。