64

I am using Plurals to simplify my code. e.g., I used to have

<string name="cat">Cat</string>
<string name="cats">Cats</string>

Using Plurals instead of multiple strings, I now have

<plurals name="cats">
    <item quantity="one">Cat</item>
    <item quantity="other">Cats</item>
</plurals>

However, I used to retrieve strings to use as titles or summaries in my XML. e.g.,

android:title="@string/cats"

Having removed that string in favor of a Plural, I am now unsure how to retrieve my string from XML. I did make a naive attempt with

android:title="@plurals/cats"

but this just gives me @1234567890 instead of Cats (or Cat).

Anyone know if it is possible to retrieve a string out of a Plural from XML?

Duke
  • 843
  • 1
  • 8
  • 10
  • https://developer.android.com/guide/topics/resources/string-resource.html#Plurals – Atul Bhardwaj Oct 21 '16 at 07:44
  • 3
    The plural fucntion isn't to simlpify the Engish plurals; but to support any language's pural rules. French would be "0 cat", and Russian "21 cat". Don't forget to include the %d so the number can be moved in translations; if needed. – Liggliluff Dec 05 '16 at 11:56

7 Answers7

64

You have to set it by code:

...setText(yourContext.getResources().getQuantityString(R.plurals.cats, catsCountVar));
Adam Johns
  • 35,397
  • 25
  • 123
  • 176
gwvatieri
  • 5,133
  • 1
  • 29
  • 29
  • I am hoping this is not the only option, since then I would need to find many views at runtime which I otherwise wouldn't spend CPU time on. If no one else responds within a couple days then I will accept this answer as essentially "not possible from XML" – Duke Jul 03 '13 at 22:30
  • 2
    Here the doc: http://developer.android.com/guide/topics/resources/string-resource.html#Plurals – gwvatieri Jul 03 '13 at 22:38
  • I'm not actually interested in (displaying) a count - I just want to have a Singular and Plural form of the word, while supporting multiple languages. Because finding views (by id) is expensive, I don't want to need to make a (second) pass over every view in my list/menu/etc in code to set the displayed string, which Android by default has already done for me when the view(s) is first inflated/created. With 2 strings instead of a Plural resource, I don't need to do anything in my code on these views. (So from what I see, Plurals will harm my performance for minimal maintenance gain.) – Duke Jul 04 '13 at 02:13
  • 1
    Then simply plurals are not what you are looking for. Plurals are meant to be used when you want to display a value and change the label based on it. Anyway if you use list/adapter in the proper way by using a wrapper, finding views by id is only performed x times with x equals to the number of views that fit on screen. – gwvatieri Jul 04 '13 at 02:53
  • 3
    The reason it must be done programmatically is that plurals are different depending on the language. In Arabic, there is singular, plural, and many. In Russian, there is singular, few (2-4) and many. The Russian version also applies to 22-24, 32-34, etc. It is because languages are so different that it needs to be done at runtime. – Nashenas Mar 15 '14 at 00:20
15

You can have the run-time benefits of Plurals and the static benefit of string resources by leaving your string resources where they are and referring to them in your plural resources.

From https://developer.android.com/guide/topics/resources/string-resource.html#Plurals (emphasis added).

<item>

A plural or singular string. The value can be a reference to another string resource. Must be a child of a element. Beware that you must escape apostrophes and quotation marks. See Formatting and Styling, below, for information about to properly style and format your strings. Example:

<string name="cat">Cat</string>
<string name="cats">Cats</string>

<plurals name="cats">
    <item quantity="one">@string/cat</item>
    <item quantity="other">@string/cats</item>
</plurals>

Now you can use android:title="@string/cats" in XML files and also use

getQuantityString(R.plurals.cats, numberOfCats)

at runtime.

Clement Cherlin
  • 387
  • 6
  • 13
15

This can now be done in XML, using a data binding expression:

android:text="@{@plurals/cats(catCount)}"

See this page in the docs for more information: https://developer.android.com/topic/libraries/data-binding/expressions#resources

Andrew Briggs
  • 475
  • 5
  • 16
11

This is now possible from xml. If you have arguments in the plural forms, you have to remember to pass the quantity variable twice. Like in the below example.

<plurals name="number_of_students_in_topic">
    <item quantity="zero">None are currently in this topic.</item>
    <item quantity="one">One student is currently in this topic.</item>
    <item quantity="other">%d students are currently in this topic.</item>
</plurals>

In xml with data binding.

android:text="@{@plurals/number_of_students_in_topic(count, count)}"

This is because, the plurals with arguments are converted in code (In *BindingImpl classes) using getResources().getQuantityString(int id, int quantity, Object... formatArgs)

The first count is to select the right plural form, and the second one is to format the String with right values.

krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
6

If your string includes string formatting with a number then you need to sent the integer variable twice, example

strings.xml

<resources>
    <plurals name="numberOfMinute">
        <item quantity="one">%d minute</item>
        <item quantity="other">%d minutes</item>
    </plurals>
</resources>

in java

int min = getNumberOfMinute();
Resources res = getResources();
String formattedStr = res.getQuantityString(
                         R.plurals.numberOfMinute,
                         min,
                         min
                       ); //this will return "20 minutes" or "1 minute" depending on variable

Kotlin File

resources.getQuantityString(
    R.plurals.numberOfMinute, //plural from strings.xml file
    min, //quantity 
    min //var arg  
)
Sanjeev
  • 4,255
  • 3
  • 28
  • 37
  • 1
    For Kotlin, I think this is the cleanest version I've seen so far, tested May 2021. This should be the accepted answer. Cheers – ralphgabb May 20 '21 at 08:35
1

Here is a way to use a plural resource as an attribute of your custom View.

src/main/res/xml/layout.xml

<com.mypackage.MyView
    app:foo="@plurals/cats"/>

src/main/res/values/attrs.xml

<resources>
    <declare-styleable name="MyView">
        <attr name="foo"/>
    </declare-styleable>
</resources>

MyView.java

public class MyView extends View {

    private int fooResId;
    private int quantity;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
        fooResId = a.getResourceId(R.styleable.MyView_foo, 0);
        a.recycle();
    }

    // this will return "Cat" or "Cats" depending on the value of quantity
    private String getFooString() {
        return getContext().getResources().getQuantityString(fooResId, quantity);
    }
}
cambunctious
  • 8,391
  • 5
  • 34
  • 53
1

updated answer for Kotlin

strings.xml

<plurals name="lbl_items_selected">
    <item quantity="one">%d item Selected</item>
    <item quantity="other">%d items Selected</item>
</plurals>

Kotlin File

resources.getQuantityString(
    R.plurals.lbl_items_selected, //plural from strings.xml file
    size, //quantity 
    size //var arg  
)

this will return :

if size = 1 : 1 item selected

if size = 2 (or more) : 2(given size) items selected

akshay bhange
  • 2,320
  • 2
  • 28
  • 46