What is the proper approach to building translation strings?

For example,

echo __( 'Hello ' . $first . ' you owe me money.' );
echo __( '<div><p>Top: ' . $t_margin . '</p>' . '<p>Bottom: ' . $b_margin . '</p></div>' )

Is it OK to add the strings and/or HTML or should it be done first and then run through translation like:

$html = '<div><p>Top: ' . $t_margin . '</p>' . '<p>Bottom: ' . $b_margin . '</p></div>';
echo __( $html ); 

2 Answers 2


There is a second argument in the __() function. It should be set to the domain you are are using for your plugin or theme. In the examples below I use 'text_domain'. Your domain string should be unique. It should not match any other domain string. Not using a text domain argument defaults to 'default' the WordPress domain name. See the link for more details.

Always use the string ('text_domain'). Never use a variable, function or constant with the string in it. Most (all?) translation programs will not see it without the string there.

Your code:

echo __( 'Hello ' . $first . ' you own me money.' );

Do not include variables in the string.

A better way:

echo sprintf( __( 'Hello %s you own me money.', 'text_domain' ), $first );

Or just:

printf( __( 'Hello %s you own me money.', 'text_domain' ), $first );

The %s placeholder tells the human translator that a string is going in there. Use %d for numbers. There are also other placeholders.

(This sentence is grammatically incorrect English. Use either 'Hello %s, you owe me money.' or 'Hello %s, you own my money.' depending on the meaning you were intending.)

Your code:

$html = '<div><p>Top: ' . $t_margin . '</p>' . <p>Bottom: ' . $b_margin . '</p></div>';

Don't translate HTML. It is the same in any language.

A better way:

$html = sprintf( '<div><p>%s</p><p>%s</p></div>', __( 'Top: ', 'text_domain' ) .  $t_margin, __( 'Bottom: ', 'text_domain' ) . $b_margin );

Or break it into multiple lines:

$html = sprintf(
    __( 'Top: ', 'text_domain' ) .  $t_margin,
    __( 'Bottom: ', 'text_domain' ) . $b_margin

If it is not apparent what Top and Bottom are you might use the _x() to explain the context of these terms.

You can find other translation cases here: Internationalization: You’re probably doing it wrong

  • You say don't translate HTML. Might I point out that it's not being translated, it's being looked up in an existing table/s of pre translated strings. Having HTML in the string makes no difference provided the translator didn't remove them. In fact, in some situations it's makes for better performance than regex search and replace.
    – Twifty
    Sep 15, 2013 at 7:12
  • 1
    Unrelated, but woth noting: the textdomain has to be a literal string, it cannot be a variable/constant/property.
    – brasofilo
    Sep 15, 2013 at 10:33
  • @brasofilo, that advice is written in the answer near the top, but bears repeating. I made this mistake in several custom plugins I wrote for customers. Sep 15, 2013 at 11:27
  • +1 for sprintf(). That's really the way around having HTML in the translatable string. Sep 15, 2013 at 11:31
  • I don't see how the use of sprintf() helps in any way other than maybe some more clean look. If you have a sentence with HTML inside like Some text with a <strong>strong</strong> word inside. how is it possible to translate the sentence as a whole and not translate Some text with a, strong and word inside individually (which makes no sense).
    – phpheini
    Jun 3, 2017 at 16:56

I won't address the issue of variables in the string since it's already been said.

You want to keep your string static, meaning that the content won't change. You also want to keep out unnecessary HTML.

__( '<p>Hello World!</p>' );
__( '<h1>Hello World!</h1>' );

The above will take up two rows in your table for what is essentially the same text. They can be rewritten as:

'<p>' . __( 'Hello World!' ) . '</p>'
'<h1>' . __( 'Hello World!' ) . '</h1>'

Reducing it to a single row.

Sometimes HTML in the text is unavoidable. Take for example:

__( 'You currently owe <b>%s</b> dollars' );

Since languages are grammatical, splitting the text would cause problems for whoever is translating.

Rule of thumb. HTML text formatting tags mid sentence are OK. Sentences beginning and ending with HTML just waste space.

  • 2
    In the last example, you could wrap the bold tags around the argument that is inserted "<b>$string</b>". Then you can use 'You currently owe %s dollars'. But it might need to stay if you use it with the _n() function which requires a %d placeholder. Sep 15, 2013 at 11:36
  • @CharlesClarkson Good call. Perhaps I should have left out the %s to make it a little more clearer.
    – Twifty
    Sep 15, 2013 at 11:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.