22

I have a String in my strings.xml file such as

  <string name="my_text">Hello <b>$%1$s</b>, android is cool <b>bold me</b></string>

The only way to retrieve the text with styling for bolding is using resources.getText(R.string.my_text);

Although the issue is getText does not take additional parameters for the arguments I wish to provide such as the method getString that takes arguments such as resources.getString(R.string.my_text, "I WILL BE BOLDED")

If I use getString I lose the bold, if I use getText I cant pass arguments how do I obtain both?

2

7 Answers 7

19

To expand upon Sagar's answer, set up the string resource using CDATA:

<string name="test"><![CDATA[When no one was looking, Lex Luthor took <b>%s</b> cakes. He took %d cakes. That\'s as many as %s %s. And that\'s terrible.]]></string>

Then, retrieve the string resource using getString() and use HtmlCompat to handle the formatting:

HtmlCompat.fromHtml(getString(R.string.test, "forty", 40, "four", "tens"), HtmlCompat.FROM_HTML_MODE_COMPACT)

NOTE: The author of the answer can neither confirm nor deny that some number of cakes were consumed in the creation of this answer. However, no actual supervillains were involved, as far as you are aware.

Sign up to request clarification or add additional context in comments.

1 Comment

This helped me too but I've got problems in adding extra spacing to it. Do you happen to have a solution for this: stackoverflow.com/questions/75821567/…
11

With Kotlin you can create an extension function

fun Resources.getText(@StringRes id: Int, vararg formatArgs: Any?): CharSequence =
    getText(id).toSpanned().toHtml().format(*formatArgs).parseAsHtml()

and then your string from the strings.xml file such as

<string name="my_text">Hello <b>$%1$s</b>, android is cool <b>bold me</b> </string>

could be retrieved with

resources.getText(R.string.my_text, "I WILL BE BOLDED")

as the next text

Hello I WILL BE BOLDED, android is cool bold me

Comments

1

strings.xml

<string name="my_text">Hello &lt;b>$%1$s &lt;/b>, android is cool &lt;b>bold me &lt;/b></string>

code

String.format(res.getString(R.my_text.welcome_messages), "I WILL BE BOLDED");

Comments

0

You can achieve it as follows

String myText = resources.getString(R.string.my_text, "I WILL BE BOLDED");
textView.setText(Html.fromHtml(text));

1 Comment

You will lose the HTML tags in that way, since getString() calls toString() internally and will escape any styling.
0

Use this instead of context.getText(), and both formatting and placeholders will work.

public static CharSequence getTextWithArgs(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 removeTrailingNewLine(
                    Html.fromHtml(String.format(Html.toHtml(new SpannedString(context.getText(id))), args)));
        }

Comments

0

This is similar in part to other answers, but handles different corner cases:

import android.content.Context
import android.text.Spanned
import android.text.TextUtils
import androidx.annotation.StringRes
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
import androidx.core.text.HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
import androidx.core.text.htmlEncode
import androidx.core.text.parseAsHtml
import androidx.core.text.toHtml
import androidx.core.text.toSpanned

/**
 * Returns a [Spanned] from parsing [resId] text resource as HTML.
 *
 * Handles both:
 * - styled text resources that would normally be resolved with [Context.getText]
 * - HTML-escaped string resources that use escape characters or CDATA section
 *
 * In both cases placeholders can be used by passing [formatArgs],
 * they will be automatically escaped with [TextUtils.htmlEncode] before HTML formatting.
 */
@Suppress("SpreadOperator")
fun Context.getHtmlStyledText(@StringRes resId: Int, vararg formatArgs: Any): Spanned {
    val text = getText(resId)
    val html = if (text is Spanned) text.toHtml(TO_HTML_PARAGRAPH_LINES_INDIVIDUAL) else text.toString()
    val suffix = if (text is Spanned) "\n" else ""
    val encodedArgs = formatArgs.map { if (it is String) it.htmlEncode() else it }.toTypedArray()
    return html.format(*encodedArgs).parseAsHtml(FROM_HTML_MODE_COMPACT).removeSuffix(suffix).toSpanned()
}

Example:

<string name="my_text">Hello <b>world</b>, android is cool <b>bold me</b></string>
<string name="my_text_escape">Hello &lt;b&gt;world&lt;/b&gt;, android is cool &lt;b&gt;bold me&lt;/b&gt;</string>
<string name="my_text_cdata"><![CDATA[Hello <b>world</b>, android is cool <b>bold me</b>]]></string>
<string name="my_text_format">Hello <b>%1$s</b>, android is cool <b>bold me</b></string>
<string name="my_text_format_escape">Hello &lt;b&gt;%1$s&lt;/b&gt;, android is cool &lt;b&gt;bold me&lt;/b&gt;</string>
<string name="my_text_format_cdata"><![CDATA[Hello <b>%1$s</b>, android is cool <b>bold me</b>]]></string>

screenshot

See also:

Comments

-1

You could create a helper method which takes in a string key and a formatting type, and then returns the appropriate string. Something like this:

<resources>
    <string name="text_normal">Hello World</string>
    <string name="text_bold"><b>Hello World</b></string>
</resources>

public String getFormattedString(int key, int type) {
    String packageName = getPackageName();
    String resource = key + "_" + type;
    int resourceId = getResources().getIdentifier(resource, "string", packageName);

    return getString(resourceId);
}

// now use the helper method
getFormattedString("text", "bold");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.