Perform a language translation

This function enables you to specify static text as the argument, and that text becomes translatable (for each language) with ProcessWire’s built-in language translation tools. This function also works just fine if you do not have multi-language support installed, though in that case it just returns the text that it is given.

For full documentation, please see the Code Internationalization (i18n) documentation page at

This function is very similar to the GNU gettext _('text'); function and essentially does the same thing, except that it is native to ProcessWire and not using GNU gettext.

Use this __('text') function for common translations, use the _x('text', 'context') function for translations that also require additional context, and use the _n('singular', 'plural', $n) function for translations that should changed based on whether a value $n would require a singular or plural tense.

Additional behaviors

  • You can optionally specify a “textdomain” as the second argument. The textdomain represents the source file of the translation. Most often it would be the current file, so the argument can be omitted, or you can specify __FILE__. But in some cases you may want to use a translation from another file, and the textdomain argument enables you to.

  • When in a class (or module) it is preferable to use $this->_('text'); rather than __('text');, as it is slightly more efficient to do so.

  • A PHP comment, i.e. // comment that appears somewhere after a translation call (on the same line) is used as an additional description for the person translating text. Another comment after that, i.e. // comment1 // comment2 is used as an additional secondary note for the person translating the text.


  • The function call (and translatable text within it) cannot span more than one line. If your translatable text is long enough to require multiple lines, split them into multiple calls (like one per sentence).

  • There cannot be more than one __('text') function call per line in the PHP code.

  • The provided text argument must be one string of static text. It cannot contain PHP variables or concatenation. To populate dynamic values you should use PHP’s sprintf() (see examples below).

Advanced features

The following features are for specific cases and supported in ProcessWire 3.0.125+ only.

You can use this function to get or set specific options that affect future calls by specifying boolean true for the first argument, option name for the second argument, and option value for the third argument. Currently there are just two options, “entityEncode” and “translations”. The “entityEncode” option enables you to control whether future calls return entity encoded text or not (see advanced examples).

If given an array for the second argument then it is assumed that it is a list of predefined fallback translations you want to define. These translations will be used if the text is not translated in the admin. The translations are not specific to any textdomain and thus can serve as a fallback for any file. These are intended for front-end site usage and not recommended for use in modules. As such, they are not supported by the $this->_('text'); function either. The array you provide should be associative, where the keys contain the text to translate, and the values contain the translation (see advanced examples).


// COMMON USAGE EXAMPLES --------------------------------------------------------------

echo __('This is translatable text');
echo __('Translatable with current file as textdomain (optional)', __FILE__);
echo __('Translatable with other file as textdomain', '/site/templates/_init.php');

// using placeholders to populate dynamic values in translatable text:
echo sprintf(__('You are reading the %s page'), $page->title);
echo sprintf(__('%d is the current page ID'), $page->id);
echo sprintf(__('Today is %1$s and the time is %2$s'), date('l'), date('g:i a'));

// providing a note via PHP comment to the person doing translation
echo __('Welcome friend!'); // A friendly welcome message for new users

// ADVANCED EXAMPLES (3.0.125+) -------------------------------------------------------

// using the entityEncode option
// true=always encode, 1=encode only if not already, false=never encode, null=undefined
__(true, 'entityEncode', true);

// get current entityEncode option value
$val = __(true, 'entityEncode');

// Setting predefined translations
if($user->language->name == 'es') {
  __(true, [
    'Hello' => 'Hola',
    'World' => 'Mundo'

// Setting predefined translations with context
__(true, [
  // would apply only to a _x('Search', 'nav'); call (context)
  'Search' => [ 'Buscar', 'nav' ]


// basic usage
$string = __($text);

// usage with all arguments
$string = __($text, $textdomain = null, $context = '');


textstring, bool

Text for translation.

textdomain (optional)string, array

Textdomain for the text, may be class name, filename, or something made up by you. If omitted, a debug backtrace will attempt to determine it automatically.

context (optional)string, bool, array

Name of context - DO NOT USE with this function for translation as it will not be parsed for translation. Use only with the _x() function, which will be parsed.

Return value

string array

Translated text or original text if translation not available. Returns array only if getting/setting options.

See Also

Functions methods and properties

API reference based on ProcessWire core version 3.0.133

Twitter updates

  • ProcessWire 3.0.133 adds a useful new Page::meta() method for a new type of page-specific persistent data storage, adds the ability for users to create their own bookmarks in Lister, and has a handy and time saving update for the asmSelect input type— More
    14 June 2019
  • New post: This week we’ll take a look at 3 different WEBP image strategies that you can use in ProcessWire 3.0.132+. Then we’ll dive into a major update for the Google Client API module, and finish up by outlining some useful new updates in FormBuilder— More
    31 May 2019
  • New post: This week we've added WEBP support in ProcessWire thanks to a GitHub pull request from Horst Nogajski. This enables you to have highly optimized image output in PW and I think you’ll really like the difference it makes— More
    24 May 2019

Latest news

  • ProcessWire Weekly #267
    In the 267th issue of ProcessWire Weekly we're going to cover the latest changes in the development branch of ProcessWire, introduce a new module called MarkupMenu, and highlight a brand new site of the week. Read on! / 22 June 2019
  • ProcessWire 3.0.133 core updates
    ProcessWire 3.0.133 adds a useful new $page->meta() method for a new type of page-specific persistent data storage, adds the ability for users to create their own bookmarks in Lister, and has a handy and time saving update for the asmSelect input type. Read on for all the details, examples and screenshots.
    Blog / 14 June 2019
  • Subscribe to weekly ProcessWire news

“I am currently managing a ProcessWire site with 2 million+ pages. It’s admirably fast, and much, much faster than any other CMS we tested.” —Nickie, Web developer