「ゼロ」の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以外の数値(「ゼロブック」、「1ブック」、「2ブック」など)であるためです。 on)
ByteMe 2012年

1
悲しいことに、すべての言語が英語と同じというわけではありません
Armand

2
これは、文法は別として、99%の確率でこれを使用する必要があったという意味で、バグだと思います。不足している機能が必要でした。ですから、はい、これはGoogleがおそらく修正することのないバグだと思います。そのため、回避策が必要です。ご覧のとおり、APIは、消費者を支援し、物事を成し遂げるためのものであり、現実世界からの抽象的な概念を排他的に表すためのものではありません。ゼロが箱から出してサポートされていたとしたら、両方のグループ(文法の正確さを必要とするグループと必要としないグループ)は、別のものを使用せずに逃げることができました。
Martin Marconcini 2018

回答:


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));

MessageFormatjavadocsでフォーマット文字列の詳細を読むことができます


7
良い回避策。私は今、私のアプリケーションを翻訳する人々が私のファイルにどのような混乱を
もたらす

1
「少数の」数値(2、3、4で終わるが、12、13、14で終わらない数値)のフォーマット文字列を作成するにはどうすればよいですか?
vokilam 2013

3
うわー、それは醜いです。このようなロジックは、翻訳ではなくコードに含める必要があります。複数形は、数字の言語の違いにのみ役立つはずです。「少数」の推奨により、ロジックを翻訳に、翻訳をロジックに正常に移動できました。
DennisK 2014年

2
それは確かに良い回避策ではありません。no_itemsの文字列とif句を前に追加するだけです。If(items.count == 0){文字列を使用} else {複数形を使用}そして翻訳者にstrings.xmlファイルの問題を処理させます…
Martin Marconcini 2014

2
@MartínMarconciniあなたは正しいです... 3年以上後:
GreyBeardedGeek 2018

47

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

選択は文法上の必要性に基づいて行われることに注意してください。英語のゼロの文字列は、数量が0であっても無視されます。これは、0が2と文法的に異ならないため、または1以外の数値(「ゼロブック」、「1ブック」、「2ブック」など)であるためです。オン)。たとえば、2つの音は数量2にしか適用できないように聞こえるという事実にも惑わされないでください。言語では、2、12、102(など)がすべて互いに同じように扱われる必要がありますが、他とは異なります。量。あなたの翻訳者に頼って、彼らの言語が実際にどのような違いを主張しているかを知ってください。

結論として、「ゼロ」は特定の言語にのみ使用されます(「2」「少数」などにも同じことが言えます)。他の言語には特別な結合がないため、「ゼロ」フィールドは不要と見なされます。


4
「英語のゼロの文字列は、数量が0であっても無視されます。これは、0が2と文法的に異ならないためです」...「果物がない」と「リンゴとオレンジがある」はどうですか?
Jeffrey Blattman 2012年

4
0と2を表現するには、さまざまな方法があります。しかし、これらのリソースの背後にある考え方は、数字とともに使用することです。つまり、次のようなものです。リンゴは0個あります。私はリンゴを1つ持っています。私はリンゴを2つ持っています。
byteMe 2012年

4
それは残念です。彼らは言語固有の仮定をすることを試みるべきではありませんでした。複数形を使用していることを知っている人は皆、これに混乱しています。
Jeffrey Blattman 2012年

2
@ miracle2k:メッセージはカテゴリ別に翻訳されていないため、ある言語のカテゴリやメッセージが別の言語に影響を与えることはありません。したがって、英語でゼロカウントのみの「ゼロ」クラスメッセージがあり、別の言語が「ゼロ」クラスメッセージを翻訳しないため、カウント10,100に「ゼロ」クラスを使用している場合は問題ありません。一方、英語で0カウントの個別のメッセージリソースを作成する場合、そのケースはすでにその言語の元の「ゼロ」クラスメッセージでカバーされているため、翻訳者のワークフローの問題が発生します。
バーゼルシシャニ2013年

2
便利な機能として英語で「ゼロ」カテゴリを有効にすることは可能ですが、それは「クリーン」ではなく、悪い行動を助長するだけです。ユーザーにアイテムを「ゼロ」文字列に追加するように促すテキストを配置するというアイデアが浮かぶかもしれません。そうすると、翻訳できない可能性があります。厳密に言えば、OPの例(「アイテムなし」)はすでにその問題を示しています。これは、翻訳者が0の場合も単語を使用して表現したい場合があるためです。「%sitem」を「%sitems」の単数バージョンと見なし、「Noitems」を言語的にまったく異なるものと見なす場合はワークフローの問題ではありません。
miracle2k 2013年

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を読みやすくしながら作業を完了できます。


これを使用すると、「<itemquantity = "zero">」は実際には使用されませんか?
Androidデベロッパー

4
正しい「<itemquantity = "zero">」は使用されません。ゼロの値の使用目的を明確にするのに役立つと思うので、そこにあります。
Justin Fiedler 2016

そう思った。翻訳者が何が起こっているのかを理解するのに役立つかもしれません。
Androidデベロッパー

13

AndroidはCLDR複数形システムを使用していますが、これは動作方法ではありません(したがって、これが変更されることを期待しないでください)。

システムの説明は次のとおりです。

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

つまり、「1」は数字1を意味しないことを理解することが重要です。代わりに、これらのキーワードはカテゴリであり、各カテゴリに属する​​特定の数字nは、CLDRデータベースのルールによって定義されます。

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

0以外に「ゼロ」を使用する言語はないように見えますが、「1」に0を割り当てる言語はあります。「2」に2以外の数字が含まれている場合は確かにたくさんあります。

Androidで意図したことを実行できる場合、アプリケーションは、より複雑な複数形のルールを使用して、任意の数の言語に適切に翻訳できませんでした。


5
複数の質問に対する定型/逐語的な回答のコピーと貼り付けを投稿するときは注意してください。これらはコミュニティによって「スパム」としてフラグが立てられる傾向があります。これを行っている場合は、通常、質問が重複していることを意味するため、代わりにそのようにフラグを付けます:stackoverflow.com/questions/8473816
Kev

3

考えられるすべてのシナリオを処理するために、Kotlin拡張機能を作成しました。

私はzeroResIdオプションとして持っているので、「0アイテム」ではなく「アイテムなし」を表示してゼロを処理したい場合があります。

英語はゼロを文法的に複数形として扱います。

使用する文字列の選択は、文法上の必要性のみに基づいて行われます。

英語では、数量が0であっても、0は2、または1以外の数値(「ゼロの本」、「1冊の本」、「2冊の本」など)と文法的に異ならないため、ゼロの文字列は無視されます。オン)。

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}"/>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.