Android复数处理“零”


83

如果在我的strings.xml中具有以下复数资源:

   <plurals name="item_shop">
        <item quantity="zero">No item</item>
        <item quantity="one">One item</item>
        <item quantity="other">%d items</item>
   </plurals>   

我正在使用以下方法向用户显示结果:

textView.setText(getQuantityString(R.plurals.item_shop, quantity, quantity));

与1及更高版本配合使用时效果很好,但是如果数量为0,则显示为“ 0件”。如文档所示,仅阿拉伯语支持“零”值吗?还是我错过了什么?


21
此问题在此处code.google.com/p/android/issues/detail?id=8287报告。尚未解决:/
OcuS 2011年

5
我认为这不是一个错误:请注意,选择是基于语法的必要性。即使数量为0,也会忽略英语中的零字符串,因为0在语法上与2或除1之外的任何其他数字在语法上都没有区别(“零本书”,“一本书”,“两本书”等上)
ByteMe,2012年

1
遗憾的是,并非所有语言都与英语完全相同
Armand

2
我认为这是一个错误,从某种意义上说,除语法外,我需要99%的时间使用此功能,而我需要缺少的功能。因此,是的,我相信这可能是Google永远无法修复的错误。因此,需要一种解决方法。您会发现,API可以帮助消费者完成工作,而不是专门代表现实世界中的抽象概念。如果可以立即使用零,那么这两组(需要语法正确性的人和不需要语法正确性的人)都可以逃脱而不必使用其他方法。
Martin Marconcini

Answers:


90

Android资源国际化的方法非常有限。使用该标准我获得了更好的成功java.text.MessageFormat

基本上,您所需要做的就是使用标准字符串资源,如下所示:

<resources>
    <string name="item_shop">{0,choice,0#No items|1#One item|1&lt;{0} items}</string>
</resources>

然后,从代码中执行的所有操作如下:

String fmt = getResources().getText(R.string.item_shop).toString();
textView.setText(MessageFormat.format(fmt, amount));

您可以在Javadocs中获取有关MessageFormat的格式字符串的更多信息


7
不错的解决方法。我可以想像一下,现在翻译我的应用程序的人会在我的文件中放什么样的混乱……:)
OcuS 2011年

1
如何为“少量”数字(数字以2,3,4结尾但不以12,13,14结尾)组成格式字符串?
vokilam 2013年

3
哇,真丑。这样的逻辑应该包含在代码中,而不是翻译中。复数仅应有助于数字的语言差异。有了“很少”的建议,您现在已经成功地将逻辑转换为翻译,并将翻译转换为逻辑。
DennisK 2014年

2
当然,这不是一个很好的解决方法。只需在no_items和if子句之前添加一个字符串。如果(items.count == 0){使用字符串} else {使用复数},然后让翻译人员处理strings.xml文件中的问题……
Martin Marconcini 2014年

2
@MartínMarconcini,您是正确的...超过3年后:-)
GreyBeardedGeek

47

来自http://developer.android.com/guide/topics/resources/string-resource.html#Plurals

注意,选择是基于语法必要性进行的。即使数量为0,也会忽略英语中的零字符串,因为0在语法上与2或除1以外的其他任何数字在语法上都没有区别(“零本书”,“一本书”,“两本书”等上)。也不要被这样的事实所误导,例如,两个声音仅适用于数量2:一种语言可能会要求将2,12,102(依此类推)全部视为彼此一样,但要区别对待数量。依靠您的翻译者知道他们的语言真正坚持的区别是什么。

总之,“零”仅用于某些语言(“两种”,“很少”等也是如此),因为其他语言没有特殊的共轭形式,因此“零”字段被认为是不必要的


4
“即使数量为0,也将忽略英语中的零字符串,因为0在语法上与2并无区别”……“我没有水果”与“我有苹果​​和橙子”怎么样?
杰弗里·布拉特曼

4
使用0和2进行字处理的方法有很多,但是这些资源背后的想法是将它们与数字一起使用。像这样:我有0个苹果。我有一个苹果。我有两个苹果。
ByteMe

4
这太糟糕了。他们不应该尝试做出特定于语言的假设。我知道使用复数的每个人对此都感到困惑。
杰弗里·布拉特曼

2
@ miracle2k:消息不会按类别翻译,因此,使用一种语言的任何类别或消息都不会影响另一种语言。因此,如果您在英语中仅对零计数使用“零”类消息,而另一种语言对计数10,100使用“零”类则没有关系,因为您不会翻译“零”类消息。另一方面:如果您为英语中的0计数创建单独的消息资源,那么您正在为翻译人员创建工作流问题,因为这种情况已经被其语言中的原始“零”类消息所涵盖。
巴塞尔Shishani

2
确实可以启用英语中的“零”类别作为便利功能,但这不是“干净”的做法,只会助长不良行为。您可能会想到放置文本以鼓励用户将项目添加到“零”字符串中,然后可能无法翻译。严格来说,OP的示例(“无项目”)已经出现了该问题,因为翻译人员可能也希望使用单词来表达0格。如果您将“%s项目”视为单数版本的“%s项目”,而将“无项目”视为在语言上完全不同,则不是工作流程问题。
miracle2k

15

这是我用来解决此问题而不切换到MessageFormat的一种解决方法。

首先,我将“零”字符串提取到其自己的字符串资源中。

<string name="x_items_zero">No items.</string>
<plurals name="x_items">
    <!-- NOTE: This "zero" value is never accessed but is kept here to show the intended usage of the "zero" string -->
    <item quantity="zero">@string/x_items_zero</item>
    <item quantity="one">One item.</item>
    <item quantity="other">%d items.</item>
</plurals>

然后我在自己的ResourcesUtil中有一些方便的方法

public static String getQuantityStringZero(Resources resources, int resId, int zeroResId, int quantity) {
    if (quantity == 0) {
        return resources.getString(zeroResId);
    } else {
        return resources.getQuantityString(resId, quantity, quantity);
    }
}

public static String getQuantityStringZero(Resources resources, int resId, int zeroResId, int quantity, Object... formatArgs) {
    if (quantity == 0) {
        return resources.getString(zeroResId);
    } else {
        return resources.getQuantityString(resId, quantity, formatArgs);
    }
}

现在,无论何时我想使用特定的字符串表示数量为零,我都会调用:

String pluralString = ResourcesUtil.getQuantityStringZero(
     getContext().getResources(),
     R.plural.x_items,
     R.string.x_items_zero,
     quantity
);

我希望有更好的方法,但这至少可以完成工作,同时保持字符串资源XML清晰易读。


使用这个,实际上不会使用“ <项目数量=“ zero”>”吗?
Android开发人员

4
正确的“ <项目数量=“零”>”将不会被使用。之所以在这里,是因为我认为它有助于弄清该值对于零的预期用途。
贾斯汀·菲德勒

是这么认为的。它可以帮助翻译人员了解正在发生的事情。
Android开发人员

13

Android正在使用CLDR复数系统,而这并不是它的工作方式(因此请不要期望这种情况会改变)。

系统说明如下:

http://cldr.unicode.org/index/cldr-spec/plural-rules

简而言之,重要的是要理解“一个”并不表示数字1。相反,这些关键字是类别,并且属于每个类别的特定数字n由CLDR数据库中的规则定义:

http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html

虽然似乎没有语言使用0以外的任何东西来表示“零”,但是有些语言将0分配给“一”。当然,在很多情况下,“ 2”包含的数字不只是2。

如果Android允许您按照自己的意愿去做,那么您的应用程序将无法正确地翻译为具有更复杂的复数规则的多种语言。


5
发布针对多个问题的复制/粘贴样板/普通答案时要小心,这些问题通常会被社区标记为“垃圾邮件”。如果您这样做,通常意味着问题是重复的,因此应将其标记为:stackoverflow.com/questions/8473816
Kev 2012年

3

我写了一个Kotlin扩展来处理我能想到的所有场景。

我具有zeroResId可选功能,因此有时我们希望通过显示“无项目”而不是“ 0项目”来处理零。

英语在语法上将零视为复数。

仅根据语法需要来选择要使用的字符串。

用英语,即使数量为0,也将忽略一个零字符串,因为0在语法上与2或除1以外的任何其他数字在语法上都没有区别(“零本书”,“一本书”,“两本书”等上)。

https://developer.android.com/guide/topics/resources/string-resource.html#Plurals

fun Context.getQuantityStringZero(
    quantity: Int, 
    pluralResId: Int, 
    zeroResId: Int? = null
): String {
    return if (zeroResId != null && quantity == 0) {
        resources.getString(zeroResId)
    } else {
        resources.getQuantityString(pluralResId, quantity, quantity)
    }
}

2

如果您正在使用数据绑定,则可以使用以下方法解决此问题:

<TextView ... 
android:text="@{collection.size() > 0 ? @plurals/plural_str(collection.size(), collection.size()) : @string/zero_str}"/>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.