I know I can format a number to a String with decimal separators like:
NumberFormat.getInstance().format(1000)
and receive the String 1,000.
How can I apply this to formated Strings from strings.xml resources?
Example:
<string name="number_of_results">%1$d results</string>
Calling
getString(R.string.number_of_results, 1000)
will return 1000 results. How can I get 1,000 results?
Android string resources are not that smart. If you need sophisticated formatting you should do it yourself, and then insert it as a string:
<string name="number_of_results">%1$s results</string>
And then
getString(R.string.number_of_results, NumberFormat.getInstance().format(1000));
The formatting libraries usually provide you interface for the locale setup, so your numbers will be properly localized, no worries here.
Related
I am developing an app where I have in some parts of code a
textview.setText(R.string.resource1 + progress + R.string.resource2);
but when I run the app, instead of showing the strings as words (these are words translated in some languages) the app shows something like in the textview
2131755168 106(this is okay, is the variable progress) 62131755102
those numbers should be words in English
You are getting that result because you are concatenating values with mixed types, the R.string.resource1 is an int lookup value for retrieving text (it's not the text itself). When concatenating, Java will just 'toString' those int values.
You have two options...
Option 1 (Recommended):
Define a string resource that uses format arguments, then pass the progress in. It is cleaner at the call site and more flexible than option 2 below.
<string name="progress_label">Before %1$d After</string>
textView.setText(getString(R.string.progress_label, progress));
Option 2:
This is less ideal because it doesn't allow you to adapt the phrasing (if needed) for the translation.
<string name="progress_before">Before</string>
<string name="progress_after">After</string>
String before = getString(R.string.progress_before);
String after = getString(R.string.progress_after);
textView.setText(String.format("%1$s %2$d %3$s", before, progress, after));
My business problem is as follows: I have a currency code (e.g. "USD") and a number (either float or integer, I can parse either way) and I need to format this number to a currency string using the currency code. For example, 124.3222 and "USD" should create the string "$124.32".
I can create a Currency instance using Currency.getInstance(String), which gives me the symbol and some other information. However, it does not provide any way to format the number as a string. On the other side of the problem, NumberFormat contains several static methods that return a NumberFormat instance capable of doing what I need (e.g. NumberFormat.getCurrencyInstance()).
The problem with NumberFormat is they are all centered around either the default locale, or a passed-in Locale. Given the nature of this app, locale is meaningless. There is no correlation between locale and the currency I need to format as a string. I can use neither the default locale, nor do I have any sort of locale identifier ISO value. All I have is the currency code.
It seems like I'm so close yet so far. There is (in my opinion) an odd disconnect between Currency and the NumberFormat.getCurrencyInstance. Currency can parse a currency code but not locale and cannot format strings, while Locale cannot parse a currency code but can format strings. Am I missing something here?
Edit: I should clarify that I can manually format the number using the symbol and decimal count provided by Currency instance, but I don't see how to figure out where to put the symbol in the string. At any rate, it seems like I should use the built-in currency formatting whenever possible.
I discovered there is a setCurrency() method on NumberFormat. So what I am doing is calling NumberFormat.getCurrencyInstance() so I get a formatter for my locale, and then calling setCurrency() on it for the currency I need to format. This seems to do what I need.
It is known that Androd string resources support xliff namespace to annotate non-translatable string formatting placeholders, like this
<string name="max_file_size_exceeded_template">File
<xliff:g example="some_image.jpg" id="file_name">%1$s</xliff:g>
is too big and could not be uploaded.</string>
It helps translators to undestand what parts of string should not be modified. But sometimes I need to annotate some strings max length it they are used in UI control with limited size. What I want is add text length limit to warn translators about this. Something like max-length="24" max-lines="2" length-unit="char" Maybe, xliff supports such thing or it can be achieved in other way.
I use Weblate for translations if it matters.
You can set this in Weblate, the Andoid format does not support this directly.
Click on edit (pencil) icon next to flags on the string.
Enter max-length:LENGTH as check flag.
See also https://docs.weblate.org/en/latest/admin/translating.html#additional-information-on-source-strings
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 question already has answers here:
Is it possible to have placeholders in strings.xml for runtime values?
(14 answers)
Closed 5 years ago.
In my Android app I'am going to implement my strings with internationalization. I have a problem with the grammar and the way sentences build in different languages.
For example:
"5 minutes ago" - English
"vor 5 Minuten" - German
Can I do something like the following in strings.xml?
<string name="timeFormat">{0} minutes ago</string>
And then some magic like
getString(R.id.timeFormat, dynamicTimeValue)
This behaviour would solve the other problem with different word orders as well.
Yes, just format your strings in the standard String.format() way.
See the method Context.getString(int, Object...) and the Android or Java Formatter documentation.
In your case, the string definition would be:
<string name="timeFormat">%1$d minutes ago</string>
If you need two variables in the XML, you can use:
%1$d text... %2$d or %1$s text... %2$s for string variables.
Example :
strings.xml
<string name="notyet">Website %1$s isn\'t yet available, I\'m working on it, please wait %2$s more days</string>
activity.java
String site = "site.tld";
String days = "11";
//Toast example
String notyet = getString(R.string.notyet, site, days);
Toast.makeText(getApplicationContext(), notyet, Toast.LENGTH_LONG).show();
If you need to format your strings using String.format(String, Object...), then you can do so by putting your format arguments in the string resource. For example, with the following resource:
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
In this example, the format string has two arguments: %1$s is a string and %2$d is a decimal number. You can format the string with arguments from your application like this:
Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
If you wish more look at: http://developer.android.com/intl/pt-br/guide/topics/resources/string-resource.html#FormattingAndStyling
There is many ways to use it and i recomend you to see this documentation about String Format.
http://developer.android.com/intl/pt-br/reference/java/util/Formatter.html
But, if you need only one variable, you'll need to use %[type] where [type] could be any Flag (see Flag types inside site above). (i.e. "My name is %s" or to set my name UPPERCASE, use this "My name is %S")
<string name="welcome_messages">Hello, %1$S! You have %2$d new message(s) and your quote is %3$.2f%%.</string>
Hello, ANDROID! You have 1 new message(s) and your quote is 80,50%.
Note that for this particular application there's a standard library function, android.text.format.DateUtils.getRelativeTimeSpanString().