Edit translations with update hook

Add, remove or edit translations with drush updb

Sometimes you need to update a translation on mulitiple site installs. In that case it can be useful to use a update hook and a translation file.

The update function

First the update hook.
function modulename_update_N()
The N is the number of the update, see api.drupal.org for more information about this. In the table “system” this number is tracked per module, so it is easy to roll it back to test your update.

We’re going to use a function from the (core) Locale module, so we first need to require this module.
require_once DRUPAL_ROOT . '/includes/locale.inc';

To import the language file we’re going to use:
_locale_import_po($file, $lang_code, $op, $group);

More on api.drupal.org, in short: $file is a file object, it needs a filename, uri and filemime property. The $langcode is the two-letter language code the translation is in. $op is the operation, either LOCALE_IMPORT_OVERWRITE or LOCALE_IMPORT_KEEP, the first overwrites all translations, the last only adds new translation strings, leaving the existing ones untouched. Finally $group, this is the translation group you want the translation to be part of. This defaults to default.

OK, let’s create a $file object:

$module_root = drupal_get_path('module', 'modulename');
$file = new stdClass();
$file->filename = 'filename.po';
$file->uri = $module_root . '/translation_updates/' . $file->filename;
$file->filemime = 'application/octet-stream';

I decided to keep the translation file inside the update module, hence we use drupal_get_path.

Finally we need the _locale_import_po() function. in our case the translations were Dutch and I wanted to overwrite the existing translations, so we get this:
$success = _locale_import_po($file, 'nl', LOCALE_IMPORT_OVERWRITE, 'default');

We return $success and the update can go on. So our code is like this:

* Update translations
function modulename_update_N() {
require_once DRUPAL_ROOT . '/includes/locale.inc';
$module_root = drupal_get_path('module', 'modulename');
// make a new $file object
$file = new stdClass();
$file->filename = 'filename.po';
$file->uri = $module_root . '/translation_updates/' . $file->filename;
$file->filemime = 'application/octet-stream';
// import the .po-file, use OVERWRITE, with KEEP only new translations are imported
$success = _locale_import_po($file, 'nl', LOCALE_IMPORT_OVERWRITE, 'default');
return $succes;

The translation file

Than of course you need a translation file. You can export you’re current translations from /admin/config/regional/translate/export
It will look something like this:

# Dutch translation of Sitename
# Generated by admin
# add only the changed, new or deleted translations

msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"POT-Creation-Date: 2014-11-13 13:56+0100\n"
"PO-Revision-Date: 2014-11-13 13:56+0100\n"
"Last-Translator: NAME \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"

msgid "The field %field is required."
msgstr ""
"Er is geen %field ingevuld. Dit hebben wij wel van u nodig. Vul a.u.b. "
"het veld %field in."

With as much msgid en msgstr combinations as needed.


There might be a problem with this, if the $file somehow cannot be read (for instance because the path is incorrect) the translation will not apply, but the update is still run.
Furthermore, if only a few translation strings need to be updated this could also be done with _locale_import_one_string, but I couldn’t get that working.

So anyone with suggestions is welcomed in the comment section.