I've seen different ways of doing making a text with a hyperlink translatable. However, I have been unable to find a single best practice.
So, here are some of the solutions I found:
// METHOD 1
sprintf( __( 'Please read %1$sthis%2$s.', 'tacoverdo-example-domain' ), '<a target="_blank" href="' . esc_url( '' ) . '">', '</a>' );
// METHOD 2
echo '<a target="_blank" href="' . esc_url( '' ) . '">';
_e( 'Please read this.', 'tacoverdo-example-domain' );
echo '</a>';
// METHOD 3
sprintf( __( 'Please read <a href="%s">this</a>.', 'tacoverdo-example-domain' ), esc_url( '' ) );
// METHOD 4
sprintf( __( 'Please read %sthis%s.', 'tacoverdo-example-domain' ), '<a target="_blank" href="' . esc_url( '' ) . '">', '</a>' );
// METHOD 5
_e( 'Please read <a target="_blank" href="' . esc_url( '' ) . '">this</a>', 'tacoverdo-example-domain' );
My first thought would be that method 1 would be best. It does not require your translators to know HTML. But it also doesn't allow the ones that do to mess with it. It is also quite DRY (Don't Repeat Yourself) since you don't have to translate the whole HTML-part over and over again.
However, when posting this question on twitter, people replied that method 3 would be best as you can see here.
So, how should I make a text with hyperlink translatable in WordPress?
I've seen different ways of doing making a text with a hyperlink translatable. However, I have been unable to find a single best practice.
So, here are some of the solutions I found:
// METHOD 1
sprintf( __( 'Please read %1$sthis%2$s.', 'tacoverdo-example-domain' ), '<a target="_blank" href="' . esc_url( 'https://goo.gl' ) . '">', '</a>' );
// METHOD 2
echo '<a target="_blank" href="' . esc_url( 'https://goo.gl' ) . '">';
_e( 'Please read this.', 'tacoverdo-example-domain' );
echo '</a>';
// METHOD 3
sprintf( __( 'Please read <a href="%s">this</a>.', 'tacoverdo-example-domain' ), esc_url( 'https://goo.gl' ) );
// METHOD 4
sprintf( __( 'Please read %sthis%s.', 'tacoverdo-example-domain' ), '<a target="_blank" href="' . esc_url( 'https://goo.gl' ) . '">', '</a>' );
// METHOD 5
_e( 'Please read <a target="_blank" href="' . esc_url( 'https://goo.gl' ) . '">this</a>', 'tacoverdo-example-domain' );
My first thought would be that method 1 would be best. It does not require your translators to know HTML. But it also doesn't allow the ones that do to mess with it. It is also quite DRY (Don't Repeat Yourself) since you don't have to translate the whole HTML-part over and over again.
However, when posting this question on twitter, people replied that method 3 would be best as you can see here.
So, how should I make a text with hyperlink translatable in WordPress?
This is a very faceted issue. It combines inherent HTML content issues with whole new load of translation challenges, such as scanning for strings, translation process itself, and its verification.
So we have to combine:
We also need to consider familiarity and prior art, in other words — what would core do. Ok, it doesn't help that from quick check the core does this in most (if not all) of these ways.
From these factors and surrounding discussion I would say there are three buckets of approaches, depending on needs and priorities.
__( 'Please read <a href="https://goo.gl">this</a>', 'example-domain' );
sprintf(
__( 'Please read <a href="%s">this</a>', 'example-domain' ),
esc_url( 'https://goo.gl' )
);
sprintf(
__( 'Please read %1$sthis%2$s.', 'example-domain' ),
'<a href="' . esc_url( 'https://goo.gl' ) . '">',
'</a>'
);
or via concatenation
'<a href="' . esc_url( 'https://goo.gl' ) . '">'
. __( 'Please read this.', 'example-domain' );
. '</a>';
These days I work with many multilanguages websites, and I have to say:
__()
but always esc_html__()
/ esc_attr__()
. Which means that string to be translated can't contain HTML of any sort.*_x()
variant of translating functions.%1$sthis%2$s
a non technical translator does not understand that the s
just before this
is necessary for proper rendering, and may also think that the developer wanted to type this
but had a typo and wrote sthis
.For all this reasons "properly" translating text that contains links is hard. The only viable solution that takes into account all said above is:
$anchor = esc_html_x( 'Google', 'link text for google', 'txt-domain' );
$domain = esc_url( __( 'google', 'txt-domain' ) );
$link = sprintf( '<a href="https://%s">%s</a>', $domain, $anchor );
/* translators: 1 is a link with text "Google" and URL google */
echo sprintf( esc_html__( 'Use %1$s to search.', 'example-domain' ), $link );
Which is safe and easy to be translated by non-technical people, but also verbose and a PITA to implement, especially if this has to be done for several links...
However, for a code released in the wild with thousand of (real or potential) users speaking many languages, this is the way I would take.
This is actually the way I take even for internal-use-only code, but that's me.
Note:
It may appear too much to make the word "Google" translatable separately, and that's probably true for this specific case. But sometimes even assume brand names is wrong. Just to name an example, in Italy we have the brand "Algida" which is known with ~30 different names around the world.
In such case, hardcoding the URL and/or the brand name, will cause issues.
Provide context for the translation will help the translators decide if they need to translate the brand name or not.
You have to keep the markup in the translatable string, because the translators have to know there is a link. In some languages the resulting link text might span multiple words, there could even be a comma (or an equivalent) inside or other markup that needs to be nested correctly.
It is also important to build a speaking link text, not this or here.
2 or 3 are the only translatable options, but you should make the URL translatable too.