Strings at well-known places: built-in menus, permissions, log messages and .info files

Last updated on
22 December 2016

Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites

As with format_plural(), Drupal has functions where you don't explicitly use t(), but the provided strings are still translated. In some cases, the ability to provide translation for strings in "well-known" places is included as a convenience to the developer; in other cases, it is simply the easiest and most direct method of making the strings available for translation.

Titles and descriptions of built-in menu items with hook_menu()

The Drupal 6 and 7 menu system stores menu item titles and descriptions in English. This allows the system to cache the data, but display to users using various languages on demand. For this to work, you should not use t() on the title or description of menu items in your hook_menu() implementation. Additionally, you should attempt to use a literal string (rather than a dynamic string) for these two keys, so the translation template extractor can find the string you used. A best practice example:

function example_menu() {
  $items = array();
  $items['admin/settings/example'] = array(
    // Do not use t()!
    'title' => 'Example configuration',
    // Do not use t()!
    'description' => 'Setup good examples for localization of modules'
    'page callback' => 'example_good_localization_page',
    // ...
  );
  return $items;
}

Again, we use plain English so that the menu system can store the English text and translate as required, benefiting performance. If, instead, we use t(), the menu system would store the menu item titles and descriptions in the language of the first visitor when the menu cache was rebuilt, which would not work as a base for translations on a multilingual site.

If you need placeholder values in menu titles, or create custom menu titles based on your own callback functions, see Menu item title and description callbacks, localization.

Permission names with hook_perm()

Drupal uses hook_perm() to gather available permissions from all enabled modules. This is used to build the permissions administration table and to store names of permissions granted to specific user roles. Just as with menu items, the permissions should be stored in English, and hook_perm() is expected to return permission names as English strings. Drupal automatically translates these strings via t() when the permissions administration page is displayed.

function example_perm() {
  return array('administer localization examples', 'access localization examples');
}

This structure is required so that the translation template extractor can extract your permission names, Drupal can store and uses the English names internally, and you can invoke t() on them only as required. Composite permission names, such as per-content-type permissions, are not compatible with the translation template extractor. The extractor can only work based on a static code analysis of your module, and a dynamic permission name that is dependent on values from the database cannot be gathered in this way. Drupal 7 solves this issue with its revamped hook_perm() structure. Until then, your composite permissions are translatable but will not appear in the translation templates.

Log messages with watchdog()

Signature: watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL)

A good practice in Drupal modules is to store log messages as certain actions occur, like the addition or deletion of nodes. The watchdog() function sends these messages to Drupal's logging mechanism, and depending on your site's configuration, they are either stored in the database or sent to the system logger utility on the webserver machine.

On a multilingual site, log messages can be generated on pages originally displayed in English, German, French, Chinese, etc. If you don't understand all these languages, or if you'd like to be able to search in the messages consistently, the messages must be stored and handled in English. Therefore, Drupal stores the log message in English, and automatically translates it at display time. You should not use any translation function on the messages, but simply supply a literal English string to the logging functions. Replacement parameters (to construct dynamic strings) are allowed just as with other translation functions.

Drupal translates both the $type and $message of a watchdog log message with $variables replaced in $message, if provided.

  watchdog('example', 'Example module is unable to find the file @filename.', array('@filename' => $filename));

As soon as you attempt to express counts of things, dates, time intervals, etc. in a log message, you'll stumble onto the limitation of this implementation. watchdog() unfortunately only supports t(), and in Drupal 6, no other function in the localization API may be used with it. This is a limitation which may be fixed in a later version. For now, you can either resort to using format_plural() and friends anyway (which would store these strings translated), or opt to do language-wise weak workarounds like:

  watchdog('example', 'Example found images (@count in total) in the upload directory.', array('@count' => $count));

This is unfortunate, but there is no other way to address this issue in Drupal 6 log messages. Similarly, you might want to reuse some code with a drupal_set_message() and a watchdog() call using the same text. Unfortunately, you cannot do this, because the former requires you to use the localization API functions, while the latter prevents you, due to the English text storage requirement.

  $DONT_DO_THIS = t('Developer notices counter examples are a good thing after all.');
  drupal_set_message($DONT_DO_THIS);
  watchdog('example', $DONT_DO_THIS);

Instead you should do:

  drupal_set_message(t('Developer notices counter examples are a good thing after all.'));
  watchdog('example', 'Developer notices counter examples are a good thing after all.');

This allows the log message to be stored in English, but the user-facing message to be correctly displayed in a language appropriate for the actual user viewing the generated page. Yes, you need to repeat the same string for best language support.

Items from your .info files

Drupal displays certain information from module and theme .info files on the user interface. These strings are not marked in any special way in the .info files themselves, but are translated nonetheless. The list of these keys are: the module or theme name, description, package name, and the theme's regions. So in the following example, title, description and package will be translatable:

; Contents of example.info
title = Example module
description = Localization API examples to help you write better Drupal code.
package = Examples
core = 6.x

Help improve this page

Page status: No known problems

You can: