Android复数处理“零”

时间:2011-04-13 15:40:00

标签: android

如果我的strings.xml中有以下多个ressource:

   <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项”。 是否只有阿拉伯语支持“零”值,因为文档似乎表明了这一点? 或者我错过了什么?

7 个答案:

答案 0 :(得分:77)

国际化的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 for MessageFormat

中详细了解格式字符串

答案 1 :(得分:39)

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

请注意,选择是基于语法上的必要性。即使数量为0,也会忽略英语为零的字符串,因为0在语法上与2不同,或者除1以外的任何其他数字(“零书”,“一本书”,“两本书”等等)上)。不要因为两个声音只能应用于数量2这一事实而被误导:一种语言可能要求2,12,102(等等)都被视为彼此相似但与其他不同数量。依靠你的翻译来了解他们的语言实际上坚持的区别。

总之,'零'仅用于某些语言(同样适用于'两个''少数'等),因为其他语言没有特殊的共轭,因此“零”字段被认为是不必要的

答案 2 :(得分: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分配给“1”。当然有很多情况下“两个”包含的其他数字不仅仅是2个。

如果Android允许您执行您的预期操作,则无法将您的应用程序正确翻译为任何数量的复杂多语言语言。

答案 3 :(得分:9)

这是我用来处理此问题而不切换到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清晰。

答案 4 :(得分: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)
    }
}

答案 5 :(得分:0)

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

RowFilter

答案 6 :(得分:0)

Android 的实现似乎与 iOS 不同(请参阅详细信息 here)。

正确的实现方式应该是在MessageFormat中,这意味着对于非语法类别,您应该添加明确的规则(使用数字而不是类别)。正确的实现可能看起来如下:

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

在这里看到您使用的是数字 0 而不是复数类别 zero,后者不适用于英语。

使用 MessageFormat,这将转化为(您可以测试 here):

{messageNumber, plural, =0 {No item.} =1 {One item.} one {# item.} other {# items.}}

在英语中,类别 one 等于 1,因此在示例中永远不应使用 one,但这并非适用于所有语言,并且在拼写数字时,您最好确保您知道哪种 plural rule 适用于该语言。