Android

複数形リソースを使う場合の注意(otherについて)

More than 3 years have passed since last update.

冷静に考えれば、そりゃそうなるわな、という話なんですが、ハマったので整理しつつメモ。

結論

  • 複数形リソース(Quantity Strings (Plurals))を使う場合は、必ずotherは定義すること。
    • 端末が日本語設定の場合は常にotherしか使用されない。
    • other以外を使う言語の場合でも、数詞に対応する文字列リソースがなければotherを使うようfallbackしてくれる。
    • otherすら無ければ、Resources.NotFoundExceptionで落ちる。
  • Lintでも怒ってくれない様子。

複数形に対応しようとして、 res/values/string.xml に以下のように書いている。

res/values/string.xml
<plurals name="plural_book">
    <item quantity="one">Buy one book</item>
    <item quantity="other">Buy %1$d books</item>
</plurals>

非日本語ユーザーに対して、とりあえず英語で表示されるように、デフォルトの文字列リソースは英語にしてある。
日本語リソースはまだ作っていない状態。

この時、本体の言語設定を「日本語」にして実際に実行してみると、指定する数量に関係なく常にotherの方が使われる。

getResources().getQuantityString(R.plurals.plural_book, 1);    // → Buy %1$d books
getResources().getQuantityString(R.plurals.plural_book, 4, 4); // → Buy 4 books

なぜかというと日本語設定だから。
日本語には複数形がないので、常にotherが使われる。

端末の言語設定を英語にして動かしてみると、ちゃんと切り替わる。

実際にアプリを作っている最中に、とりあえずoneだけ定義してコードの方も数量が常に1になる状態で動かしたら、otherが無くて落ちてしまった事があった。

仕様

APIリファレンス

APIリファレンスにも、第2引数に渡された数に応じて、現在の言語に応じて適切なものを選択すると書いてある。

quantity The number used to get the correct string for the current language's plural rules.
https://developer.android.com/reference/android/content/res/Resources.html#getQuantityString(int, int)

Common Locale Data Repository

どの数詞を使うかは、UnicodeのCommon Locale Data Repositoryのルールに基づいて選択される。
この表では、Japaneseは常にotherが使われる事になっている事が解る。

http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html

実際のリソースの選択には、International Components for UnicodePluralRulesクラスが使用されている(Resourcesクラスの実装参照)。

Resources#getQuantityText

ドキュメントに明記されている箇所を見つけることは出来なかったが、実装上はzerooneなどに対応するリソースを見つけられない場合はotherを使用するようになっている。
otherすら見つけられない場合はResources.NotFoundExceptionになる。

https://android.googlesource.com/platform/frameworks/base/+/android-4.4.4_r1/core/java/android/content/res/Resources.java#248

実用例

拙作の絵文字入力アプリでは、入力しようとしている文字数に応じてメッセージを切り替えるために複数形リソースを使用している。

先の例と同様に、デフォルトの言語リソースは英語で作成している。
oneの数詞が無い言語(中国語とか)では、文字数に関係なく常に「Use Emojis」と複数形で表示されてしまうが、キリがないので気にしていない。

res/values/strings.xml
<plurals name="message_use_emojis">
    <item quantity="one">Use Emoji</item>
    <item quantity="other">Use Emojis</item>
</plurals>

日本語用のリソースではotherだけ定義してある。

res/values-ja/strings.xml
<plurals name="message_use_emojis">
    <item quantity="other">絵文字を使う</item>
</plurals>

参考