Main menu

FAQ: How do I enter a link (or other HTML formatting) into a translation?

The short answer is "you just type the code into the editor". Loco Translate doesn't care whether your translation is HTML or plain text, or if it's complete nonsense. If you can type it, the editor will save it.

But..

The longer story is that this probably won't work unless the developer has allowed it.

As a general rule, if the source text isn't HTML then the translation probably shouldn't be HTML either. If you try to add it anyway you're very likely to run into a problem, because the code author is probably preventing unwanted HTML from being injected into their pages.

It's fundamentally insecure to display unsanitized HTML code from an untrusted source (which is what your translations are). So for security and simplicity the majority of localized strings in WordPress are expected to be plain text and will be escaped before they're displayed on your page.

Let's look in detail about what this means for adding formatting to translations.

Example

Suppose you have some text in your theme's footer that looks like this when rendered in the browser:

Design by WickedCoolThemes Inc.

And let's say you want it to display with a nice clickable link instead:

Design by these guys.

As far as Loco Translate is concerned you can just type HTML into the translation editor, like this:

img

You don't have to enable the code view as shown here. It doesn't change the content of your translation in any way, it just highlights the code so you can read it better.

Job done.

But wait! It doesn't work.

To your dismay, the footer now shows the actual code you typed in, or possibly some other problem like the formatting being stripped out.

If you see the code, it will be because the developer has done something like this in the theme code where the translation is displayed:

echo esc_html( __('Design by WickedCoolThemes Inc.','some-wicked-cool-theme') );

Their use of the esc_html function has escaped the text, and tells us they are not allowing HTML to be rendered here.

There are many possible variations of this code. For example, the esc_html_e function is a shortcut that does the same three things as the above - It translates, then escapes, then prints.

Critically, this causes any HTML code already in your translation to be escaped also. Which is why you see text as if it was your original HTML code. You can learn more about these techniques in the WordPress documentation.

Should I ask the developer to fix it?

You can try asking them to enable HTML formatting on particular string in their next release. If your request is reasonable they might oblige. But if you want to add <h1> tags all over their design, or inject <script> tags into their admin pages they will probably refuse.

The code from our simple example above could be re-written as follows:

echo wp_kses( __('Design by WickedCoolThemes Inc.','some-wicked-cool-theme'), ['a'=>['href'=>true]] );

Using wp_kses instead of esc_html allows simple links in the translation, while still protecting from other unwanted code. The developer may be happy to implement something like this if you ask them nicely.

How do I fix it myself?

If your boss/client/nemesis has insisted you fix this, your only option is to interfere with the sacred esc_html function. That means writing some code to filter on any text that passes through it.

WordPress has a very useful function called wp_kses that allows a subset of HTML to be rendered, while escaping anything else.

The following code will force a subset of HTML tags to display unescaped whenever the esc_html function is used to prevent that from happening. Our example below limits the allowed HTML to only <a> tags with href and target attributes. We also limit the list if protocols to avoid the use of javascript: links.

You probably won't want to run this code on every single string, so modify this code for your needs. Read the WordPress documentation first.

/* This filter ignores ALL escaped HTML, and allows links to render */
function hack_esc_html( $safe, $unsafe  ){
    return wp_kses( $unsafe, ['a'=>['href'=>true,'target'=>true]], ['http','https'] );
}
add_filter('esc_html','hack_esc_html',999,2);

This is a hack, and not a recommendation!

There are more reasons this is a bad idea than there are reasons it's a good one.

  • This will only work if the code author is using esc_html (or a function like esc_html_e that makes use of it).
  • Other plugins may also be filtering the output, which means (1) you might break their functionality, and (2) you're competing over who gets to run their code last.
  • In our tests it appeared that wp_kses doesn't call esc_html itself (which would produce an infinite loop) but we can't guarantee that's impossible (now or in the future) so code accordingly.

Why doesn't Loco Translate fix this?

Firstly on principle: If a developer doesn't want HTML in a translation we think that should be observed.

Secondly from a practical point of view: The underlying localization mechanisms of WordPress don't provide any way of adding type information to translation files, and no way to switch between rendering/escaping methods without the developer coding them in. The only techniques available for forcing HTML rendering are hacks. We don't want to introduce potential errors, security problems, or performance issues into our software. Until there's an official 'WordPress way' of doing it, we're not going to do it.

We've tried to offer an explanation, some links to further learning and some code to play with. However, we don't provide personal support for coding problems or issues relating to how your website displays translations.

If you're still struggling with this topic, please ask for help on a general WordPress forum or on StackExchange.