8

Is there a way to programmatically add translations for strings (user interface translation), for example in hook_update_N()?

With Drupal 7, I could use the following code.

/**
 * Helper to manually add a single translation string.
 *
 * After adding strings use locale_clear_cache() for clearing caches.
 */
function locale_add_translation($source, $langcode, $translation, $context = '', $textgroup = 'default') {
  require_once DRUPAL_ROOT . '/includes/locale.inc';
 
  $report = &drupal_static(__FUNCTION__, array('additions' => 0, 'updates' => 0, 'deletes' => 0, 'skips' => 0));
  _locale_import_one_string_db($report, $langcode, $context, $source, $translation, $textgroup, 'Manual import via helper ' . __FUNCTION__ .'().', LOCALE_IMPORT_OVERWRITE);
}
 
/**
 * Helper to clear the locale cache.
 */
function locale_clear_cache() {
  require_once DRUPAL_ROOT . '/includes/locale.inc';
  // Clear locale cache.
  _locale_invalidate_js();
  cache_clear_all('locale:', 'cache', TRUE);
}

3 Answers 3

14

Put the following helper function in your custom module.

use \Drupal\locale\SourceString;

function mymodule_add_translation($source_string, $translated_string, $langcode) {
  // Find the existing source string.
  $storage = \Drupal::service('locale.storage');
  $string = $storage->findString(array('source' => $source_string));
  if (is_null($string)) {
    $string = new SourceString();
    $string->setString($source_string);
    $string->setStorage($storage);
    $string->save();
  }
  // Create the translation. If it already exists, it will be replaced.
  $storage->createTranslation(array(
    'lid' => $string->lid,
    'language' => $langcode,
    'translation' => $translated_string,
  ))->save();
}
1
  • There is a better variant of this code in the history of this answer that shows how to add an optional translation context and is up-to-date with current coding practices for Drupal 10.
    – pfrenssen
    Dec 5, 2023 at 19:19
1

Here is a function to create plural translations.

use Drupal\Component\Gettext\PoItem;
use Drupal\locale\SourceString;

function mymodule_add_plural_translation(array $source_strings, array $translated_strings, string $langcode): void {
  /** @var \Drupal\locale\StringStorageInterface $storage */
  $storage = \Drupal::service('locale.storage');

  $source_string = implode(PoItem::DELIMITER, $source_strings);

  $string = $storage->findString(['source' => $source_string]);

  // If the string is not yet translated, create a new source string.
  if (is_null($string)) {
    $string = new SourceString();
    $string->setString($source_string);
    $string->setStorage($storage);
    $string->save();
  }

  // Create translation. If one already exists, it will be replaced.
  $translation = $storage->createTranslation([
    'lid' => $string->lid,
    'language' => $langcode,
  ]);
  $translation->setPlurals($translated_strings);
  $translation->save();
}

Use it like this:

$source_strings = [
  'Discounted product',  // Singular string first.
  'Discounted products', // Plural string second.
];
$translated_strings = [
  'Reduziertes Produkt', // Singular string first.
  'Reduzierte Produkte', // Plural string second.
];
$langcode = 'de';

mymodule_add_plural_translation($source_strings, $translated_strings, $langcode);
1
  • 1
    Sorry for the accidental roll-back of your edit to the other answer, I wasn't seeing at first that the $context was optional and was afraid this answer wouldn't work anymore when people use it without context. Then saw it and immediately rolled the roll-back back.
    – leymannx
    Jan 31, 2023 at 14:43
0

Another sample with string context, like from $this->t('Weight', [], ['context' => 'Physical weight']).

use Drupal\locale\SourceString;

/**
 * Fix "weight" translation.
 */
function MYMODULE_update_N(&$sandbox) {
  $source_string = 'Weight';
  $context = 'Physical weight';
  $langcode = 'de';
  $translated_string = 'Gewicht';

  // Find existing source string. If it doesn't exist, it will be created.
  $storage = \Drupal::service('locale.storage');
  $string = $storage->findString(['source' => $source_string, 'context' => $context]);
  if (is_null($string)) {
    $string = new SourceString();
    $string
      ->setString($source_string)
      ->setValues(['context' => $context])
      ->setStorage($storage)
      ->save();
  }

  // Create translation. If one already exists, it will be replaced.
  $translation = $storage->createTranslation([
    'lid' => $string->getId(),
    'language' => $langcode,
    'translation' => $translated_string,
    'context' => $context,
  ])->save();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.