When to use st(), t() and get_t() in install and update functions

Last updated on
13 October 2016

Drupal does not have access to a database in the early stages of the installation process, so any interface strings which might be generated before the database is available cannot be translated via the usual database-based Localization API. Instead, Drupal looks for a single PO file under the translations directory in the current install profile used. This PO file is read in and parsed to be used in the request. Since interface text required for the installer is relatively short, this works acceptably. However, when Drupal is installed, and the database is available, thousands of strings await being translated when required, so the database is being used to access translations. Drupal imports PO files and stores them in the database, so the Drupal runtime is just using PO files as a transport mechanism, not directly as a data source.

Functions to use in install code: st() and get_t()

Because there are two backends, developers need to mark strings used in one or the other. The only translation function available in the installer as of Drupal 6 is st(). It works the same as you would use t(), but gets its input from the mentioned PO file, not the database. Other means of localization are not available in the installer. As soon as the runtime is running on the database (that is after the database tables were created in the first batch process in the Drupal 6 installer), t() can be used to translate single strings.

There are often places in your installation code when you need to write logic which would run both in the installer and runtime. A hook_requirements() implementation checking for your installer and runtime requirements is a good example. There, depending on whether Drupal runs the installer or the database backend, you need to choose from the two translation functions. To make this easy, get_t() is provided, so for code which might run in both the installer and runtime, you should use $t = get_t() and then wrap strings in $t(). Do use the $t name, since the Translation template extractor will only find such strings with this marker. An example:

/**
 * Implementation of hook_requirements().
 */
function example_requirements($phase) {
  $requirements = array();
  $t = get_t();
  
  $tar_library = @file_get_contents('Archive/Tar.php', TRUE);
  $tar_available = !empty($tar_library);
  $requirements['tar_library'] = array(
    'title' => $t('Compression functionality'),
    'value' => $t('Archive/Tar.php available'),
  );
  if (!$tar_available) {
    $requirements['tar_library']['description'] = $t('The PEAR Archive/Tar.php library is missing. Please obtain it and put it on the include path.');
    $requirements['tar_library']['severity'] = REQUIREMENT_ERROR;
    $requirements['tar_library']['value'] = $t('Not available');
  }
  return $requirements;
}

One notable case is hook_schema(), which runs at install time as well as at runtime. 6.x releases of Drupal core (up to Drupal 6.8 inclusive) and contributed modules alike used t() for descriptions of tables and fields. However, translations of these descriptions, if they existed, would only ever be seen in Drupal’s interface if you used the contributed schema module to generate documentation of the database structure. (Note that the installer does not use these descriptions, and if the locale module is not available, such as in the early stages of installation when tables are being created, then strings such as the table and field descriptions simply pass through t() untranslated.)

For a number of reasons (see http://drupal.org/node/332123), including website performance and the desire avoid encouraging translators to spend time on work of possibly limited value, Drupal 7 and also Drupal 6.9 and later no longer use t() on these strings. You should include schema table and field descriptions as verbatim strings without wrapping them in localization code.

/**
 * Implementation of hook_schema() to demonstrate that t() is not used.
 */
function example_schema() {
  $schema['example_table'] = array(
    'description' => 'This table stores example stuff.',
    'fields' => array(
      'eid' => array(
        'description' => 'Example identifier.',
        'type' => 'serial',
        'not null' => TRUE,
      ),
      'value' => array(
        'description' => 'Value of the example. Can be a string or a serialized array.',
        'type' => 'text',
        'not null' => TRUE
      )
    ),
    'primary key' => array('eid'),
  );
  return $schema;
}

Messages and other strings in update functions

Update functions are special because of two reasons. One is that they usually modify the database, so you should always refrain from using functions which actually use the database. It could happen that a later update in a module alters the database structure for Drupal locale tables, and calling t() which would expect the latest database structure would end up with big red errors and a failed call. The other is that the strings (such as user messages) you would generally include in update functions are by nature new to the system and they will most probably have no translation in the database.

You should refrain from using functions such as t() to avoid database problems, and it would be pointless to do the call anyway, since the strings would not be in the database. Because update functions run only once, saving the string for later translation is also a useless operation. Therefore, the general guideline for update functions is that you should just use plain English strings without any attempt to translate them.

function example_update_6345() {
  variable_set('example_awesomeness', TRUE);
  // Note that we DID NOT use any localization function here.
  drupal_set_message('Enabled example awesomeness.');
  return array();
}