60

我正在尝试使用资源中的getQuantityString方法来检索基于 Android 开发人员指南的数量字符串(复数)数量字符串(复数)

我得到的错误是

错误:(604) 以非位置格式指定了多个替换;您是要添加 formatted="false" 属性吗?
错误:(604)在预期的位置找到标签

当我如下设置复数时

<plurals name="productCount">
    <item quantity="one" formatted="true">%1$d of %2$d product</item>
    <item quantity="other" formatted="true">%1$d of %2$d products</item>
</plurals>

并尝试如下阅读 productIndexCountText.setText(getResources().getQuantityString(R.plurals.productCount, position, size));

一种解决方法是将字符串分解为仅对字符串的最后一部分使用复数并将这两个部分连接起来。但如果可能的话,我会尽量避免这样做。

4

1 回答 1

133

您不需要为任何这些项目设置“格式化”属性。使用数量字符串时,只有三种可能:

  1. 资源字符串是纯文本,不包含任何参数
  2. 资源字符串只包含一个参数(很可能是数量);使用%d或您需要的任何格式
  3. 资源字符串包含多个参数;所有参数都必须通过它们的位置显式访问,例如%1$d

至于getQuantityString方法,有两种重载:一种只有资源id和数量,另一种是附加Object... formatArgs参数。

对于案例 1.,您可以使用该getQuantityString(@PluralsRes int id, int quantity)方法。

对于所有其他情况,即如果您有任何参数,则需要getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)重载。注意:所有参数都必须存在于参数数组中。这意味着,如果资源字符串显示数量,数量变量将两次传递给函数。

那是因为quantity在解析资源字符串的位置参数时不考虑方法本身的参数。

所以如果这些是你的资源,

<resources>
    <plurals name="test0">
        <item quantity="one">Test ok</item>
        <item quantity="other">Tests ok</item>
    </plurals>
    <plurals name="test1">
        <item quantity="one">%d test ok</item>
        <item quantity="other">%d tests ok</item>
    </plurals>
    <plurals name="test2">
        <item quantity="one">%2$s: %1$d test ok</item>
        <item quantity="other">%2$s: %1$d tests ok</item>
    </plurals>
    <plurals name="test3">
        <item quantity="one">%3$s: %1$d test out of %2$d ok</item>
        <item quantity="other">%3$s: %1$d tests out of %2$d ok</item>
    </plurals>
</resources>

那么适当的调用getQuantityString是:

int success = 1;
int total = 10;
String group = "Group name";

getResources().getQuantityString(R.plurals.test0, success)
// Test ok
getResources().getQuantityString(R.plurals.test1, success, success)
// 1 test ok
getResources().getQuantityString(R.plurals.test2, success, success, group)
// Group name: 1 test ok
getResources().getQuantityString(R.plurals.test3, success, success, total, group)
// Group name: 1 test out of 10 ok

success = 5;
getResources().getQuantityString(R.plurals.test0, success)
// Tests ok
getResources().getQuantityString(R.plurals.test1, success, success)
// 5 tests ok
getResources().getQuantityString(R.plurals.test2, success, success, group)
// Group name: 5 tests ok
getResources().getQuantityString(R.plurals.test3, success, success, total, group)
// Group name: 5 tests out of 10 ok

数量类:理解quantity参数

如上所述,关键是要了解quantity参数 ofgetQuantityString不是用来代替%dor之类的占位符%1$d。相反,它用于itemplurals自身确定合适的,并结合资源文件的语言环境。

但请注意,与属性名称及其可能值 ( zero, one, two, few, many, other) 可能暗示的相比,这是一个不太直接的映射。例如,即使参数的值为 0 ,也<item quantity="zero"> 无法提供附加功能(至少不是英文) 。quantity

原因是pluralsAndroid中的工作方式是通过数量类的概念。数量类是在给定语言中具有相同语法规则的一组数量值。这至关重要地意味着

  • 使用了哪些数量类别,以及
  • 哪些数值映射到它们

取决于相应资源文件的语言环境。

重要的是要了解这两个问题仅由语法必要性决定。这里有些例子:

  • 在中文或韩文中,other使用 only,因为在这些语言中,句子不会根据给定的数量在语法上有所不同。
  • 在英语中,有两个类:one用于字面值 1,以及other用于包括 0 在内的所有其他值。
  • 在爱尔兰语中,1 映射到one,2 映射到two,3-6 是few,7-10 是many,0 和 11+ 是other
  • 在斯洛文尼亚语中,值 1所有以 01结尾的值都映射到one(1, 101, 3001, ...)。2 和以 02 结尾的值映射到two(2, 302, 1002, ...)。3, 4 和以 03 或 04 结尾的值映射到few(3, 4, 6004, ...)。其他的都是other(0, 11, 48, 312, ...)。
  • 在波兰语中,5-19 和以 05-19 结尾的值映射到many(5, 12, 216, 4711, ...)。以 2、3 或 4 结尾的值(包括 2-4 本身)映射到few(3, 42, 103, 12035374, ...)。然而,这尊重 12、13 和 14 是该规则的例外,因为它们被映射到many. (旁注:是的,从语法上讲,5很多,而 12035374很少。)
  • 亚美尼亚语就像英语,除了值 0 也映射到one,因为这就是他们的语法工作方式。你可以从这个例子中看到,数量类one甚至不一定只代表一个数字。

如您所见,确定正确的数量类别可能会变得相当复杂。这就是为什么getQuantityString已经根据quantity参数和资源文件的语言环境为您执行此操作的原因。Android(主要)使用的规则在Unicode Common Locale Data Repository的Language Plural Rules中定义。这也是数量类名称的来源。

这意味着翻译任何数量字符串所需的数量类集可能因语言而异(中文只需要other,英语需要oneother,爱尔兰语只需要zero,等等)。然而,在一种语言中,plurals每个人都应该有相同数量的项目,涵盖该特定语言所需的所有数量类别。

结论

调用getQuantityString可以这样理解:

int success = 5;
int total = 10;
String group = "Group name";

getResources().getQuantityString(R.plurals.test3, success, success, total, group)
//                               \_____________/  \_____/  \___________________/
//                                      |            |               |
//         id: used to get the plurals resource      |               |
//   quantity: used to determine the appropriate quantity class      |
// formatArgs: used to positionally replace the placeholders %1, %2 and %3

quantity参数值“5”表示使用的将item是具有other中文、韩语、英语、斯洛文尼亚语和亚美尼亚语资源文件、few爱尔兰语和many波兰语的数量类的那个。


我还要简要提及两种特殊情况:

非整数数量

基本上,选择的类再次取决于特定于语言的规则。如何选择一个类既不是通用的,也不能保证覆盖所有整数规则所需的任何类也可用于任何非整数。这里有一些例子:

  • 对于英语,任何带小数的值都将始终映射到other.
  • 对于斯洛文尼亚语,任何带小数的值将始终映射到few.
  • 对于爱尔兰语,选择取决于整数部分。
  • 对于波兰语,与整数的复杂规则相比,非整数总是映射到other英语中的 like。

注意:这是根据语言复数规则应该是这样的。唉,Android 目前没有现成的方法。floatdouble

一个字符串中的多个数量

如果您的显示文本有多个数量,例如%d match(es) found in %d file(s).,将其拆分为三个单独的资源:

  1. %d match(es)plurals项目)
  2. %d file(s)plurals项目)
  3. %1$s found in %2$s.(普通参数化strings项)

然后,您可以对 1 和 2 进行适当的调用,然后对第三个getQuantityString进行另一个调用,前两个易于本地化的字符串为.getStringformatArgs

原因是允许翻译者在语言需要时切换第三资源中的参数顺序。例如,如果假设语言中唯一有效的句法是In %d file(s) it found %d match(es).,则翻译者可以照常翻译复数,然后翻译第三个资源In %2$s it found %1$s.以说明交换的顺序。

于 2017-03-19T08:59:13.103 回答