How to print translation supported text with HTML URL

Since esc_html_e will escape HTML link (hence will show the HTML anchor as plain text), you’ll need to segment the text and escape the non-HTML part with esc_html_e or esc_html__, and print the HTML LINK part without HTML escaping.

Method-1 (just for your understanding):

You may do it in parts, like this:

esc_html_e( 'Dear Guest, with Your information we could not find any room at the moment.', 'text-domain' );
echo "<br><br>";

printf(
    esc_html__( '%1$s %2$s', 'text-domain' ),
    esc_html__( 'Please contact us on our', 'text-domain' ),
    sprintf(
        '<a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
        esc_url( 'http://www.example.com/contact-us/' ),
        esc_html__( 'Contact Page', 'text-domain' )
    )
);

printf(
    ' or <a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
    esc_url( 'mailto:[email protected]', array( 'mailto' ) ),
    esc_html__( 'Email', 'text-domain' )
);

Method-2 (just for your understanding):

Obviously, different languages will have different ordering of texts, so to give translators more flexibility (with escaping and ordering of text), you may do it in the following way instead:

printf(
    esc_html__( '%1$s%2$s%3$s%4$s%5$s', 'text-domain' ),
    esc_html__( 'Dear Guest, with Your information we could not find any room at the moment.', 'text-domain' ),
    nl2br( esc_html__( "\n\n", 'text-domain' ) ),
    sprintf(
        esc_html__( '%1$s %2$s', 'text-domain' ),
        esc_html__( 'Please contact us on our', 'text-domain' ),
        sprintf(
            '<a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
            esc_url( 'http://www.example.com/contact-us/' ),
            esc_html__( 'Contact Page', 'text-domain' )
        )
    ),
    esc_html__( ' or ', 'text-domain' ),
    sprintf(
        '<a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
        esc_url( 'mailto:[email protected]', array( 'mailto' ) ),
        esc_html__( 'Email', 'text-domain' )
    )
);

This way of doing it will:

  1. Escape all the necessary translated texts.

  2. Allow the HTML for link, email (with mailto: syntax) etc.

  3. Allow translators to have all sorts of different ordering of texts for different languages. The argument swapping notation (%1$s, %2$s etc.) is used so that the translators may reorder the translated text where needed.


Method-3 (Updated & Recommended):

As @shea rightly pointed out, Method-2 above works fine, but it may be difficult for the translators to add support for different languages. So we need a solution that:

  1. Keeps the sentences intact (doesn’t break sentences).

  2. Does proper escaping.

  3. Provides ways to have different ordering for contact & email links (or anything similar) within the translated sentence.

So to avoid the complication of method-2, the solution below keeps the translatable sentences intact and does the proper URL escaping & argument swapping at the same time (more notes within CODE comments):

// sample contact url (may be from an unsafe place like user input)
$contact_url="http://www.example.com/contact-us/";
// escaping $contact_url
$contact_url = esc_url( $contact_url );

// sample contact email (may be from an unsafe place like user input)
$contact_email="[email protected]";
// escaping, sanitizing & hiding $contact_email.
// Yes, you may still need to sanitize & escape email while using antispambot() function
$contact_email = esc_url( sprintf( 'mailto:%s', antispambot( sanitize_email( $contact_email ) ) ), array( 'mailto' ) );

esc_html_e( 'Dear Guest, with Your information we could not find any room at the moment.', 'text-domain' );
echo "<br><br>";

printf(
    esc_html__( 'Please contact us on our %1$s or per %2$s.', 'text-domain' ),
    sprintf(
        '<a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
        $contact_url,
        esc_html__( 'Contact Page', 'text-domain' )
        ),
    sprintf(
        '<a href="https://wordpress.stackexchange.com/questions/260512/%s">%s</a>',
        $contact_email,
        esc_html__( 'Email', 'text-domain' )
        )
    );

This way of doing it will give translators two full sentences & two separate words to translate. So a translators will only have to worry about the following simple lines (while the CODE takes care of the rest):

esc_html_e( 'Dear Guest, with Your information we could not find any room at the moment.', 'text-domain' );
// ...
esc_html__( 'Please contact us on our %1$s or per %2$s', 'text-domain' )
// ...
esc_html__( 'Contact Page', 'text-domain' )
// ...
esc_html__( 'Email', 'text-domain' )

That’s it, simple structure and does proper escaping and argument swapping as well.


Read more about internationalization for themes & internationalization for plugins.

Leave a Comment