如何使用 Android 数量字符串(复数)

How to use Android quantity strings (plurals)

我正在尝试使用 getQuantityString method in Resources to retrieve quantity strings (plurals) based on Android Developer guidelines Quantity string (plurals)

我得到的错误是

Error:(604) Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?
Error:(604) Found tag where is expected

当我如下设置复数时

<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, 位置, 大小));

一种解决方法是将字符串拆分为仅对字符串的最后部分使用复数形式,然后将这两部分连接起来。但我尽量避免这样做。

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

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

至于 getQuantityString 方法,有两种重载:一种只有资源 ID 和数量,另一种带有额外的 Object... formatArgs 参数。

对于情况1.,可以使用getQuantityString(@PluralsRes int id, int quantity)方法。

对于所有其他情况,i。 e.如果您有 any 参数,则需要 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

数量classes:理解quantity参数

如上所述,关键是要明白getQuantityStringquantity参数不是用来代替%d%1$d等占位符的。相反,它用于根据 plurals 本身并结合资源文件的区域设置来确定适当的 item

但是请注意,这是一个不如属性名称及其可能值(zeroonetwofewmany, other) 可能会建议。例如,提供额外的 <item quantity="zero"> will not work (at least not in English),即使 quantity 参数的值为 0.

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

  • 使用了哪些数量 class,并且
  • 哪些数值映射到它们

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

重要的是要理解这两个问题仅由 语法必要性 决定。以下是一些示例:

  • 在中文或韩语中,只使用 other,因为在这些语言中,句子不会根据给定的数量在语法上有所不同。
  • 在英语中,有两个 classes:one 表示文字值 1,other 表示所有其他值,包括 0。
  • 在爱尔兰语中,1 映射为 one,2 映射为 two,3-6 为 few,7-10 为 many,0 和11+ 是 other.
  • 在斯洛文尼亚语中,值 1 所有值 ending 在 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 是 many 而 12035374 是 few。)
  • 亚美尼亚语与英语相似,不同之处在于值 0 也映射到 one,因为这就是他们语法的工作方式。从这个例子中可以看出,数量 class one 甚至不一定只代表一个数字。

如您所见,确定正确的数量 class 会变得相当复杂。这就是为什么 getQuantityString 已经根据 quantity 参数和资源文件的语言环境为您做了这些。规则 Android(大部分)由 Language Plural Rules of the Unicode Common Locale Data Repository 定义。这也是数量 classes 的名称来源。

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

结论

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将是数量为classother的中文、韩文、英文、斯洛文尼亚语和亚美尼亚语资源文件,爱尔兰语 few,波兰语 many


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

非整数数量

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

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

注意:根据Language Plural Rules应该是这样的。唉,Android 目前没有现成的 floatdouble 方法。

一个字符串中的多个数量

如果您的显示文本有多个数量,例如。 G。 %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,然后为第三个调用另一个 getString,前两个易于本地化的字符串为 formatArgs .

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