Drupal has good multilingual support out of the box and it allows to creation of multilingual sites easily. In normal circumstances translation process is easy, but there are some cases where you may want to update translations programmatically.
In this article, I will show how to import configuration and interface translations programmatically. You can find the example functions and integrate them into your workflow.
Importing configuration translations
Normally you would use configuration synchronization to import configuration translations, but there may be use cases where you can't use it, for example, you are building a platform that has a lot of instances and a lot of different modules and configurations on each. Or you have a module that provides configuration translations and you need to update them.
Next, we have an example function that will do what we need - import configuration based on config name and language code. It also tries to handle common errors like the config file is missing or empty in which case you would not want to continue.
The language manager is responsible for managing configuration translations and you can call \Drupal::languageManager()->getLanguageConfigOverride($langcode, $config_name);
to get the current version of the translation and then start to modify it. In my function, it is used setData()
to overwrite it, but you can implement additional logic if you want to update specific config value(s). You can also make it more dynamic, for example add arguments for module name and config type (install/optional).
<?php
use Drupal\Core\Config\FileStorage;
function import_config_translation(string $config_name, string $langcode): void {
$config_path = Drupal::service('extension.list.module')->getpath('my_module') . '/config/install';
$language_config_path = $config_path . '/language/' . $langcode;
$source = new FileStorage($language_config_path);
try {
$source_config = $source->read($config_name);
// Check if we have valid translation file we can actually use.
if (empty($source_config)) {
\Drupal::logger('my_module')->error('Unable to import config @config_name translation, either the file does not exist or is empty.',
['@config_name' => $config_name]);
// Do not continue.
return;
}
/** @var \Drupal\language\Config\LanguageConfigOverride $config_override */
$config_override = \Drupal::languageManager()->getLanguageConfigOverride($langcode, $config_name);
$config_override->setData($source_config);
$config_override->save();
}
catch (Drupal\Core\Config\UnsupportedDataTypeConfigException $e) {
\Drupal::logger('my_module')->error('Unsupported config translation type!');
}
}
Import interface translations
Importing interface translations in Drupal is usually managed by *.po files or they are downloaded from the translation server automatically. In some cases, you want to do this through an update hook to import simple strings and not mess around with *.po files.
Next, you can find an example function to import strings, it also does support context. To support plural forms, use PoItem::DELIMITER
as a separator inside the strings. It will create translation if it does not exist.
/**
* Add a user interface translation to the translation storage.
*
* @param string $source_string
* English string.
* @param string $langcode
* Language to translate to.
* @param string $translated_string
* Translated string.
* @param string|null $context
* Context of the translation.
*/
function my_module_add_translation($source_string, $langcode, $translated_string, $context = NULL) {
try {
// Find existing source string.
$storage = \Drupal::service('locale.storage');
$string = $storage->findString(['source' => $source_string, 'context' => $context ?: '']);
if ($string === NULL) {
$string = new SourceString();
$string->setString($source_string);
$string->setStorage($storage);
$string->setValues(['context' => $context]);
$string->save();
}
// Create translation. If one already exists, it will be replaced.
$translation = $storage->createTranslation([
'lid' => $string->lid,
'language' => $langcode,
'translation' => $translated_string,
]);
$translation->save();
}
catch (\Drupal\locale\StringStorageException $e) {
Drupal::logger('my_module')->warning(t('Add translation failed!'));
}
}