Translate a Drupal 7 custom module via l10n_update

It is really a big deal to manage translations of custom module in Drupal 7 expecially if you have a multisite installation.

Problem

We want use a .po file to translate a custom module programmatically, i.e. without forcing a redactor to do dangerous manual operations.

Furthermore we want have our module always accompained by its translations.

Solution

First of all we need to have l10n_update module installed.

Than we can declare the hook “l10n_update_projects_alter” which allow to set a remote path where the .po file is hosted.

Normally the path should be a remote, indipendent one, but in most cases we would like to have the .po file inside the website itself (i.e. not a separeted environment).

Take a look to the code below in which I declare a .po file that is in the module folder, in particular in “translations” subfolder.

As you can see the file name contains the parameter %language. In this case the filename would be ModuleName.LanguageCode.po.

/**
 * Alter the list of project to be updated by Localization Update.
 *
 * L10n_update uses the same list of projects as update module. Using this hook
 * the list can be altered. This hook is typically used to alter the following
 * values from the .info file:
 *  - interface translation project
 *  - l10n path.
 *
 * @param array $projects
 *   Array of projects.
 */
function my_module_name_l10n_update_projects_alter(array &$projects) {
  // Setting module name.
  $name = 'my_module_name';
  // Setting the path of .po files.
  $pathToModule = drupal_get_path('module', $name);
  $pathToPo = $pathToModule . '/translations/';
  $poFileName = $name . '.%language.po';
  // Getting url to po
  $urlToPoFolder = file_create_url($pathToPo);
  $urlToPoFile = $urlToPoFolder . $poFileName;

  /**
   * In case of S3 filesystem uncomment the code below.
   */
  // Instead of the default ftp.drupal.org we use the file system of the test
  // instance to simulate a remote file location.
  //$wrapper = file_stream_wrapper_get_instance_by_uri('public://');
  //$remote_url = $wrapper->getExternalUrl() . '/remote/';

  // With this hook it is also possible to add a new project which does not
  // exist as a real module or theme project but is treated by the localization
  // update module as one. The below data is the minimum to be specified.
  // As in the previous example the 'l10n path' element is optional.
  $projects[$name] = array(
    'project_type'  => 'module',
    'name' => $name,
    'info' => array(
      'name' => 'My Module name',
      'interface translation project' => $name,
      'version' => '7.x-1.0',
      'core' => '7.x',
      'l10n path' => $urlToPoFile,
    ),
  );
}

Furthermore with the following snippet, I have manually (i.e. programmatically) forced the module to update its translations.

// Getting dependencies.
module_load_include('inc','l10n_update','l10n_update.translation');
module_load_include('inc','l10n_update','l10n_update.fetch');


$projects = ['my_module_name'];


$options = _l10n_update_default_update_options();
$options['customized'] = true;
$options['use_remote'] = true;
$options['overwrite_options']['customized'] = true;

l10n_update_clear_status();
$batch = l10n_update_batch_update_build($projects, [], $options);
batch_set($batch);

The .po files have been extracted thanks to Translation Template Extractor.