К сожалению, элементы управляемого_файла не могут быть переведены из коробки в ядре Drupal;здесь его нет в списке https://www.drupal.org/docs/8/multilingual/translating-configuration.
Для пользовательской конфигурации модуля мне пришлось реализовать настраиваемое изменение формы и обработчик отправки настраиваемой формы, чтобы добавить переведенный элемент формы и его значение.
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
use Drupal\file\FileUsage\FileUsageInterface;
/**
* Implements hook_form_alter().
*
* Add managed_file form elements to config_translation add and edit forms to
* allow users to translate the mymodule_image
* configuration value.
*
* The managed_file form elements as file entity references are not translatable
* by Drupal core config_translation module.
*
* @Todo: Save translated configuration only when the mymodule_image
* is translated. When no other config is translated, config is not saved in
* Drupal\config_translation\Form\ConfigTranslationFormBase::submitForm()
*/
function kraken_settings_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (in_array($form_id, ['config_translation_add_form', 'config_translation_edit_form'])) {
$mapper = $form_state->get('config_translation_mapper');
// For the mymodule settings, add new header image form element to the
// config translation form.
$config_name = 'mymodule.settings';
if (is_array($mapper->getConfigNames()) && in_array($config_name, $mapper->getConfigNames())) {
$config = \Drupal::config($config_name);
$element_name = 'mymodule_image';
$lang = $form_state->get('config_translation_language')->getId();
// Add these to form_state for use in the submit handler.
$form_state->setFormState([
'config_name' => $config_name,
'language' => $lang,
'element_name' => $element_name,
]);
// Create new form elements for source and translation elements.
$element = [
'#title' => t('My Module Image'),
'#type' => 'managed_file',
'#default_value' => '',
'#description' => t('My Module Configuration Image'),
'#upload_location' => 'public://mymodule-image/',
];
// Add the source form elements and set defaults. Wrap
// elements in markup from to resemble other translated form elements.
// @see config_translation_manage_form_element.html.twig
$source_value = $config->get($element_name);
// Check if null to avoid php notices.
$source_default = isset($source_value) ? $source_value : '';
$form['mymodule_config_trans_source_div'] = [
'#type' => 'container',
'#prefix' => '<div class="translation-set clearfix"><div class="layout-column layout-column--half translation-set__source">',
'#suffix' => '</div>',
'#weight' => -10,
];
$form['mymodule_config_trans_source_div']['mymodule_config_trans_source'] = $element;
$form['mymodule_config_trans_source_div']['mymodule_config_trans_source']['#default_value'] = $source_default;
// @Todo: Render the a preview of the source image instead of rendering
// as disabled managed_file form element.
$form['mymodule_config_trans_source_div']['mymodule_config_trans_source']['#disabled'] = TRUE;
$form['mymodule_config_trans_source_div']['mymodule_config_trans_source']['#description'] = t('The original source file. Can not remove.');
// Add translated form element much like the source.
$trans_value = $config->get('translations.' . $lang . '.' . $element_name);
// Check if null to avoid throwing php notices. If set, add as an array
// for Drupal\file\Element\ManagedFile.
$trans_default = (isset($trans_value)) ? [$trans_value] : '';
$form['mymodule_config_trans_div'] = [
'#type' => 'container',
'#prefix' => '<div class="layout-column layout-column--half translation-set__translated">',
'#suffix' => '</div>',
'#weight' => -10,
];
$form['mymodule_config_trans_div']['mymodule_config_trans'] = $element;
$form['mymodule_config_trans_div']['mymodule_config_trans']['#default_value'] = $trans_default;
// Add custom submit handler to manage the translated value first.
array_unshift($form['#submit'], 'mymodule_config_translation_submit');
}
}
}
/**
* Submit handler to save translated mymodule_image image.
*/
function mymodule_config_translation_submit(array $form, FormStateInterface $form_state) {
$config = \Drupal::configFactory()->getEditable($form_state->get('config_name'));
$translations = $config->get('translations');
$element_name = $form_state->get('element_name');
$language = $form_state->get('language');
$trans_value = $form_state->getValue('mymodule_config_trans');
$file_usage = \Drupal::service('file.usage');
// Check for array keys to avoid Notice: Undefined index warnings.
if (isset($translations[$language][$element_name])) {
$trans_config = $translations[$language][$element_name];
}
else {
$trans_config = NULL;
}
// If there's a submitted form value and its different from the saved config,
// then process changed value.
if (!empty($trans_value[0])) {
// Delete previous trans config file usage if set and different.
if (isset($trans_config) && $trans_value[0] !== $trans_config) {
$old_file = File::load($trans_config);
$file_usage->delete($old_file, 'mymodule', 'file', $trans_config);
// Save new file as permanent and record its usage.
mymodule_config_trans_file_save($file_usage, $trans_value[0]);
// Save new translation value within existing translation values.
// Key array by language to manage multiple language translations.
$translations[$language][$element_name] = $trans_value[0];
$config->set('translations', $translations)->save();
}
// If config is not set, save new value.
if (!isset($trans_config)) {
mymodule_config_trans_file_save($file_usage, $trans_value[0]);
// Save new translation value within existing translation values.
// Key array by language to manage multiple language translations.
$translations[$language][$element_name] = $trans_value[0];
$config->set('translations', $translations)->save();
}
}
else {
// If submitted value is empty and configuration isset, remove file usage
// and stored configuration value.
if (isset($trans_config)) {
$old_file = File::load($trans_config);
// Note, removing all file usages will not change file status to temporary
// per file.settings.make_unused_managed_files_temporary setting.
// @see https://www.drupal.org/project/drupal/issues/2801777#comment-12221514.
// @see \Drupal\file\FileUsage\FileUsageBase::delete().
$file_usage->delete($old_file, 'mymodule', 'file', $trans_config);
// Clear specific config key, leaving other possible translated language
// configuration in place.
$config->clear('translations.' . $language . '.' . $element_name);
$config->save();
}
}
}
/**
* Save new file usage.
*
* @param \Drupal\file\FileUsage\FileUsageInterface $file_usage
* The file.usage service.
* @param int $fid
* A file id.
*/
function mymodule_config_trans_file_save(FileUsageInterface $file_usage, $fid) {
$file = File::load($fid);
$file->setPermanent();
$file->save();
$file_usage->add($file, 'mymodule', 'file', $fid);
}