How to use formatted strings together with placeholders in Android?

For the simple case where you want to replace a placeholder without number formatting (i.e. leading zeros, numbers after comma) you can use Square Phrase library.

The usage is very simple: first you have to change the placeholders in your string resource to this simpler format:

<string name="underlined_number">My number is <u> {number} </u></string>

then you can make the replacement like this:

CharSequence formatted = Phrase.from(getResources(), R.string.underlined_number)
   .put("number", 5)
   .format()

The formatted CharSequence is also styled. If you need to format your numbers, you can always pre-format them using String.format("%03d", 5) and then use the resulting string in the .put() function.


<resources>
  <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
</resources>


Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
CharSequence styledText = Html.fromHtml(text);

More Infos here: http://developer.android.com/guide/topics/resources/string-resource.html


Kotlin extension function that

  • works with all API versions
  • handles multiple arguments

Example usage

textView.text = context.getText(R.string.html_formatted, "Hello in bold")

HTML string resource wrapped in a CDATA section

<string name="html_formatted"><![CDATA[ bold text: <B>%1$s</B>]]></string>

Result

bold text: Hello in bold

Code

/**
* Create a formatted CharSequence from a string resource containing arguments and HTML formatting
*
* The string resource must be wrapped in a CDATA section so that the HTML formatting is conserved.
*
* Example of an HTML formatted string resource:
* <string name="html_formatted"><![CDATA[ bold text: <B>%1$s</B> ]]></string>
*/
fun Context.getText(@StringRes id: Int, vararg args: Any?): CharSequence =
    HtmlCompat.fromHtml(String.format(getString(id), *args), HtmlCompat.FROM_HTML_MODE_COMPACT)

Finally I managed to find a working solution and wrote my own method for replacing placeholders, preserving formatting:

public static CharSequence getText(Context context, int id, Object... args) {
    for(int i = 0; i < args.length; ++i)
        args[i] = args[i] instanceof String? TextUtils.htmlEncode((String)args[i]) : args[i];
    return Html.fromHtml(String.format(Html.toHtml(new SpannedString(context.getText(id))), args));
}

This approach does not require to escape HTML tags manually neither in a string being formatted nor in strings that replace placeholders.