I am trying to use the getQuantityString method in Resources to retrieve quantity strings (plurals) based on Android Developer guidelines Quantity string (plurals)
The error I am getting is
Error:(604) Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?
Error:(604) Found tag where is expected
when I set up plurals as below
<plurals name="productCount">
<item quantity="one" formatted="true">%1$d of %2$d product</item>
<item quantity="other" formatted="true">%1$d of %2$d products</item>
</plurals>
And trying to read it as below
productIndexCountText.setText(getResources().getQuantityString(R.plurals.productCount, position, size));
One workaround is to break the string up to use plural only for the last part of the string and concatenate the two parts. But I am trying to avoid doing that if possible.
You don't need to set the "formatted" attribute for any of those items. When using quantity strings, there are only three possibilities:
the resource string is plain text and does not contain any parameters
the resource string contains only one parameter (most likely the quantity); use %d or whatever format you need
the resource string contains multiple parameters; all parameters have to be explicitly accessed by their position, for example %1$d
As for the getQuantityString method, there are two overloads: one with only the resource id and the quantity, and one with an additional Object... formatArgs parameter.
For case 1., you can use the getQuantityString(#PluralsRes int id, int quantity) method.
For all other cases, i. e. if you have any parameters, you need the getQuantityString(#PluralsRes int id, int quantity, Object... formatArgs) overload. Note: all parameters have to be present in the parameter array. That means, if the resource string displays the quantity, the quantity variable will be passed twice to the function.
That is because the quantity parameter of the method itself is not considered when resolving the positional parameters of your resource string.
So if these are your resources,
<resources>
<plurals name="test0">
<item quantity="one">Test ok</item>
<item quantity="other">Tests ok</item>
</plurals>
<plurals name="test1">
<item quantity="one">%d test ok</item>
<item quantity="other">%d tests ok</item>
</plurals>
<plurals name="test2">
<item quantity="one">%2$s: %1$d test ok</item>
<item quantity="other">%2$s: %1$d tests ok</item>
</plurals>
<plurals name="test3">
<item quantity="one">%3$s: %1$d test out of %2$d ok</item>
<item quantity="other">%3$s: %1$d tests out of %2$d ok</item>
</plurals>
</resources>
then the appropriate calls to getQuantityString are:
int success = 1;
int total = 10;
String group = "Group name";
getResources().getQuantityString(R.plurals.test0, success)
// Test ok
getResources().getQuantityString(R.plurals.test1, success, success)
// 1 test ok
getResources().getQuantityString(R.plurals.test2, success, success, group)
// Group name: 1 test ok
getResources().getQuantityString(R.plurals.test3, success, success, total, group)
// Group name: 1 test out of 10 ok
success = 5;
getResources().getQuantityString(R.plurals.test0, success)
// Tests ok
getResources().getQuantityString(R.plurals.test1, success, success)
// 5 tests ok
getResources().getQuantityString(R.plurals.test2, success, success, group)
// Group name: 5 tests ok
getResources().getQuantityString(R.plurals.test3, success, success, total, group)
// Group name: 5 tests out of 10 ok
Quantity classes: understanding the quantity parameter
As stated above, the key is to understand that the quantity parameter of getQuantityString is not used to replace the placeholders like %d or %1$d. Instead, it is used to determine the appropriate item from the plurals itself, in combination with the locale of the resource file.
Beware however that this is a less direct mapping than the attribute's name and its possible values (zero, one, two, few, many, other) might suggest. For example, providing an additional <item quantity="zero"> will not work (at least not in English), even if the value of the quantity parameter is 0.
The reason is that the way plurals work in Android is by the concept of quantity classes. A quantity class is a set of quantity values that have the same grammatical rules in a given language. This crucially means that
which quantity classes are used, and
which numeric values are mapped to them
is dependent on the locale the respective resource file is for.
It is important to understand that both questions are decided only by grammatical necessity. Here are some examples:
In Chinese or Korean, only other is used, because in these languages sentences don't grammatically differ based on the given quantity.
In English, there's two classes: one for the literal value 1, and other for all other values including 0.
In Irish, 1 is mapped to one, 2 is mapped to two, 3-6 is few, 7-10 is many, 0 and 11+ is other.
In Slovenian, the value 1 and all values ending in 01 are mapped to one (1, 101, 3001, ...). 2 and values ending in 02 are mapped to two (2, 302, 1002, ...). 3, 4 and values ending in 03 or 04 are mapped to few (3, 4, 6004, ...). Anything else is other (0, 11, 48, 312, ...).
In Polish, 5-19 and values ending in 05-19 are mapped to many (5, 12, 216, 4711, ...). Values ending in 2, 3 or 4 including 2-4 themselves are mapped to few (3, 42, 103, 12035374, ...). This respects however that 12, 13 and 14 are exceptions from this rule because they are mapped to many. (Side note: yes, grammatically speaking, 5 is many while 12035374 is few.)
Armenian is like English, with the exception that the value 0 is also mapped to one, because that's how their grammar works. You can see from this example that the quantity class one doesn't even necessarily represent just one-ish numbers.
As you can see, it can get fairly complicated to determine the correct quantity class. That's why getQuantityString already does that for you, based on the quantity parameter and the resource file's locale. The rules Android (mostly) plays by are defined in the Language Plural Rules of the Unicode Common Locale Data Repository. That is also where the names of the quantity classes come from.
All that means that the set of quantity classes needed to translate any quantity string can differ from language to language (Chinese just needs other, English needs one and other, Irish needs all but zero, etc.). Within one language however, all plurals should each have the same number of items covering all quantity classes necessary for that particular language.
Conclusion
A call to getQuantityString can be understood like this:
int success = 5;
int total = 10;
String group = "Group name";
getResources().getQuantityString(R.plurals.test3, success, success, total, group)
// \_____________/ \_____/ \___________________/
// | | |
// id: used to get the plurals resource | |
// quantity: used to determine the appropriate quantity class |
// formatArgs: used to positionally replace the placeholders %1, %2 and %3
The quantity parameter's value of "5" will mean the used item will be the one with the quantity class other from Chinese, Korean, English, Slovenian and Armenian resource files, few for Irish, and many for Polish.
There are two special cases I'd also briefly mention:
Non-integer quantities
Basically, the chosen class depends on language-specific rules again. It is neither universal how a class is chosen, nor guaranteed that any class required to cover all rules for integers is also used for any non-integers. Here are a few examples:
For English, any value with decimals will always map to other.
For Slovenian, any value with decimals will always map to few.
For Irish, the choice depends on the integer part.
For Polish, in contrast to the complex rules for integers, non-integers are always mapped to other like in English.
Note: This is how it should be according to the Language Plural Rules. Alas, Android has no readily available method for float or double at the moment.
Multiple quantities in one string
If your display text has multiple quantities, e. g. %d match(es) found in %d file(s)., split it into three separate resources:
%d match(es) (plurals item)
%d file(s) (plurals item)
%1$s found in %2$s. (ordinary parameterized strings item)
You can then make the appropriate calls to getQuantityString for 1 and 2, and then another one to getString for the third, with the first two readily localized strings as formatArgs.
The reason is to allow translators to switch the parameter order in the third resource, should the language require it. E.g., if the only valid syntax in a hypothetical language was In %d file(s) it found %d match(es)., the translator could translate the plurals as usual, and then translate the third resource as In %2$s it found %1$s. to account for the swapped order.
I'm not sure this is the right forum to post this but I'm unsure how to organize my strings in certain scenarios where nouns in certain languages are inflected. It's easier to explain the problem with an example. Consider the following string:
<string name="my_string">Show you more information in context with each
<xliff:g id="item_name">%s</xliff:g></string>
The element <xliff:g id="item_name">%s</xliff:g> in this case can be replaced by, for example, "alarm" or "alert" depending on the context in my app. However, this doesn't work with languages that inflect the noun, such as Finnish.
In Finnish, %s is substituted with the word "hälytys" (=alarm) in the app though grammatically correct form in this case would be "hälytyksen" (an inflected form of singular alarm in Finnish, caused by a postposition and unfortunately no nice way to circumvent the inflection).
So it seems I can't have this sort of generic string element with replaceable nouns. Do you have any suggestions other than hard-coding the string elements for each possible value of %s?
Put your string this way in string.xml
<string name="my_string">Show you more information in context with each <xliff:g id=\"item_name\"> %s <\/xliff:g></string>
From Java
String s = String.format(getString(R.string.my_string,"alarm")); //put your dynamic value for alarm
Output would be :
Show you more information in context with each <xliff:g id="item_name"> alarm </xliff:g>
this is my first question :)
I'm developing an application that stores animal species in a database. The app must be multilanguage, so I tought to take advantage of using strings.xml resource files.
The idea is to store the english name of the species on the db, for example "cat", "dog" etc.. and then display to the user the actual translation, based on an xml like this (for italian):
<string name="dog">Cane</string>
<string name="cat">Gatto</string>
The problem is that R.string contains the name dog and cat, but they are actually int, so I'm searching a way to use the "dog" string to be used to compare the R.string.dog translated value.
I'm almost sure that my design is terribly wrong, but don't know what the correct way to doing this kind of work, since the app is now in a very early stage of development.
Thank you
EDIT with example
This example illustrates the problem:
Database data:
row1: id="1", value="dog"
row2: id="2", value="cat"
String file strings.xml:
<string name="dog">Dog</string>
<string name="cat">Cat</string>
String file strings-it.xml:
<string name="dog">Cane</string>
<string name="cat">Gatto</string>
My problem is: the user want to insert a specie in his native language (eg. "Cane"), and I want to search in the DB for its existence before inserting.
I should loop for every row on the DB (where values are stored in english), get the the translation of each row (eg: I found cat, then I translate to "Gatto") and compare with the user input.
Is it possible to do that?
If you have a string name you want to use, you can use getIdentifier() to get the string id. As an example, to find R.string.cat:
Resources res = getResources();
int stringId = res.getIdentifier("cat", "string", packageName);
In the above example, if there is no R.string.cat found, it will simply return 0. It's an easy test to see if a string exists.
Alternatively, you can get an array of all the string ids in your R.java by using something like:
Field[] fields = R.string.class.getFields();
int[] ids = new int[fields.length];
for(int i=0;i<field.length;i++)
ids[i] = field[i].getInt(null);
Of course, that will also look for any strings that you don't really intend as translations, such as dialog/window titles, label/button captions, etc. I wouldn't advise it in the general case. If I had to do it, I'd prefix the "translation" strings with something so I could easily tell what is what, something like "entry_cat".
Note that we're using reflection, and if you have a lot of strings, it could slow you down. If you are going to loop through R.java, I'd advise only doing it on start-up, and saving the values in some sort of array/list.
First read this.
http://developer.android.com/training/basics/supporting-devices/languages.html
You can create value folder with many language's i.e janapee,dutch etc
you can find out value folder inside the res folder in your project. and create new value folders.
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
JUST TRANSLATE YOUR WORDS BY GOOGLE TRANSLATOR IN ANY LANGUAGE AND PUT INSIDE THE STRING.XML FILE .
Well, first of all, start reading this here:
Suppose that your application's default language is English. Suppose
also that you want to localize all the text in your application to
French, and most of the text in your application (everything except
the application's title) to Japanese. In this case, you could create
three alternative strings.xml files, each stored in a locale-specific
resource directory:
res/values/strings.xml Contains English text for all the strings that
the application uses, including text for a string named title.
res/values-fr/strings.xml Contain French text for all the strings,
including title. res/values-ja/strings.xml Contain Japanese text for
all the strings except title. If your Java code refers to
R.string.title, here is what will happen at runtime:
If the device is set to any language other than French, Android will
load title from the res/values/strings.xml file. If the device is set
to French, Android will load title from the res/values-fr/strings.xml
file. Notice that if the device is set to Japanese, Android will look
for title in the res/values-ja/strings.xml file. But because no such
string is included in that file, Android will fall back to the
default, and will load title in English from the
res/values/strings.xml file.
I want to uses the plurals resource to produce a quoted number like "9".
In my plurals.xml:
<plurals name="posts">
<item quantity="other">\"%dd\"<\item>
</plurals>
The code:
String text = res.getQuantityString(R.plurals.posts, meUser.postCount);
When the postCount is 9, why does text turn out to be "%dd" and not "9"?
From the Android docs:
When using the getQuantityString() method, you need to pass the
count twice if your string includes string formatting with a number.
For example, for the string %d songs found, the first count
parameter selects the appropriate plural string and the second count
parameter is inserted into the %d placeholder. If your plural
strings do not include string formatting, you don't need to pass the
third parameter to getQuantityString.
ie res.getQuantityString(R.plurals.numberOfSongsAvailable, count, count);
Just in case anyone has a brain-fail like me today and still cannot get it working.
I had accidentally left my emulator in a non-English locale which meant my "one" translation was being ignored!
(Only the "other" entry was being used in my case)
I am facing an issue with "string.format" in android application. In my application when the user changes his language preferences from default (english) to any other foreign language (japanese,german etc) the variable string positioning is giving a force close error. Please refer the code below:
temp = String.format(locale,getResources().getString(R.string.temp_string), value, name);
where, temp_string = "The parcel number %1$d belongs to %2$s" for default selection (english)
when other languages are selected in some of them %2$s comes before %1$d . Due to which the the application force closes. Is there a way around to dynamically handle the variable strings(value,name).
I'd do something like:
temp = getResources().getString(R.string.temp_string, value, name);
As you see, getString() method can also receive parameters to format. Then, place different strings resources on different folders. For instance:
res/
values/
string.xml <--- here you put "The parcel number %1$d belongs to %2$s"
values-de/
string.xml <--- here you put "The parcel number %2$d belongs to %1$s"
I'm just giving you an example; I actually do not know how germany order is. I just want to explain what you actually have to try.