Skip Navigation
Updated
January 3, 2022

If a theme or plugin you created isn’t displaying translations correctly on the site, it may be because certain conditions have not been met. Here are some troubleshooting tips to ensure you can successfully translate a theme or plugin.

For these translations to appear on the site, the following conditions have to be met:

  • The text must be wrapped in gettext calls.
  • There must be a textdomain argument.

If you are creating a plugin or theme and you want it to be translatable, you have to wrap each string within a __() function. You also have to add a domain to which the string belongs to. This is important because you can have the same string appearing at several plugins or within different contexts.

In this example, we have a string, “Thank you!”, that belongs to the “my-plugin-domain” domain:

__( 'Thank you!', 'my-plugin-domain' );

If you need to echo a string to the browser, you should use the _e() function.

_e( 'Thank you!', 'my-plugin-domain' );

You can also combine this with your HTML code. If you want to echo your main heading that is translatable, you could use code like this one:

<h2><?php _e( 'Thank you!', 'my-plugin-domain' ); ?></h2>

If you have a link that is separated from the surrounding text, you should do something like this:

<a href="http://wpml.org/" ><?php esc_html_e( 'Translated with WPML', 'my-domain' ); ?></a>

If you have a link within your string, you can do the following:

Link within string
$url = __( 'https://domain.com/terms-of-service', 'my-domain' );

printf(
    esc_html__( 'By clicking on "Create an account" below, you are agreeing to the %sTerms of service%s', 'my-domain' ),
    '<a href="' . $url . '">',
    '</a>'
);

Best practices

You should never wrap a variable or a constant in a gettext function. The following code shows what should never be done:

The wrong way
<?php
// This is the wrong way
if ( $morning ) {
   $the_sentence = 'Good morning';
} else {
    $the_sentence = 'Good afternoon';
}

_e( $the_sentence, 'my-domain' );

// The wrong way with constants
if ( $morning ) {
   define( 'GREETING', 'Good morning' );
} else {
   define( 'GREETING', 'Good afternoon' );
}

_e( GREETING, 'my-domain' );
?>

There are two problems with the above code:

  • The strings are not scannable, and therefore the translator will never receive the strings that need to be translated.
  • The string is evaluated before it is considered for translation, and hence the gettext function will never find the translation for the string.

Instead, you should write the code as follows:

The right way
<?php
// This is the right way
if ( $morning ) {
   _e( 'Good morning', 'my-domain' );
} else {
   _e( 'Good afternoon', 'my-domain' );
}
?>

If a string is immediately rendered in the output, it should escape first. This can prevent XSS attacks where a translator added malicious translation. The corresponding functions are esc_html__ and esc_attr__.

Here is an example:

echo '<div>' . esc_html__( 'Back to homepage', 'my-domain' ) . '</div>';

It is also a good practice to add comments to your PHP code. This way translators will be able to get the context in which certain text or variable is appearing.

Add comments to your PHP
/* translators: “State” refers to status of the network connection */
printf(
esc_html__( 'State of your network is %1$s. Maximum download speed is %2$s. Mbit/s', 'my-plugin-domain' ),
$state, $speed
);

Read how to make the theme you created translatable.

For more in-depth information about gettext, please refer to the WordPress codex.