diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 699742d..585264c 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -166,10 +166,10 @@ public function buildForm(array $form, FormStateInterface $form_state, Request $
$form['#attached']['library'][] = 'config_translation/drupal.config_translation.admin';
- $form['config_names'] = array(
- '#type' => 'container',
- '#tree' => TRUE,
- );
+ // Even though this is a nested form, we do not set #tree to TRUE because
+ // the form value structure is generated by using #parents for each element.
+ // @see \Drupal\config_translation\FormElement\FormElementBase::getElements()
+ $form['config_names'] = array('#type' => 'container');
foreach ($this->mapper->getConfigNames() as $name) {
$form['config_names'][$name] = array('#type' => 'container');
$form['config_names'][$name] += $this->buildConfigForm($name, $this->typedConfigManager->get($name), $this->baseConfigData[$name], $config_factory->get($name)->get());
@@ -256,16 +256,7 @@ protected function buildConfigForm($name, ArrayElement $schema, $source_config,
if ($form_element = $this->createFormElement($schema)) {
$parents = array('config_names', $name);
- $key = '';
- $build = $form_element->getElements($this->sourceLanguage, $this->language, $source_config, $translation_config, $key, $parents);
- }
- else {
- $definition = $schema->getDefinition();
- $this->logger('config_translation')->notice("No form element class exists for config schema definition '@name'", array('@name', $definition->getLabel()));
- }
-
- if ($build) {
- $build[$key]['#open'] = TRUE;
+ $build = $form_element->getElements($this->sourceLanguage, $this->language, $source_config, $translation_config, $parents);
}
return $build;
@@ -277,19 +268,19 @@ protected function buildConfigForm($name, ArrayElement $schema, $source_config,
* @param \Drupal\Core\TypedData\TypedDataInterface $schema
* Schema definition of configuration.
*
- * @return \Drupal\config_translation\FormElement\ElementInterface|NULL
+ * @return \Drupal\config_translation\FormElement\ElementInterface|null
* The element builder object if possible.
*/
public static function createFormElement(TypedDataInterface $schema) {
$definition = $schema->getDataDefinition();
- if (!empty($definition['translatable']) || $schema instanceof ArrayElement) {
+ // Form element classes can be specified even for non-translatable elements
+ // such as the ListElement form element which used for for Mapping and List
+ // schema elements.
+ if (isset($definition['form_element_class'])) {
if (!$definition->getLabel()) {
$definition->setLabel(t('n/a'));
}
- if (isset($definition['form_element_class'])) {
- /** @var \Drupal\config_translation\FormElement\ElementInterface $form_element */
- return new $definition['form_element_class']($schema);
- }
+ return new $definition['form_element_class']($schema);
}
}
diff --git a/core/modules/config_translation/src/FormElement/DateFormat.php b/core/modules/config_translation/src/FormElement/DateFormat.php
index 49e0c12..729afee 100644
--- a/core/modules/config_translation/src/FormElement/DateFormat.php
+++ b/core/modules/config_translation/src/FormElement/DateFormat.php
@@ -27,7 +27,6 @@ public function getTranslationElement(LanguageInterface $translation_language, $
return array(
'#type' => 'textfield',
- '#title' => $this->t($definition->getLabel()) . ' (' . $language->name . ')',
'#description' => $description,
'#field_suffix' => '
' . $format . '
',
'#ajax' => array(
diff --git a/core/modules/config_translation/src/FormElement/ElementInterface.php b/core/modules/config_translation/src/FormElement/ElementInterface.php
index 47cd387..d0df738 100644
--- a/core/modules/config_translation/src/FormElement/ElementInterface.php
+++ b/core/modules/config_translation/src/FormElement/ElementInterface.php
@@ -28,15 +28,16 @@
* The configuration value of the element in the source language.
* @param mixed $translation_config
* The configuration value of the element in the language to translate to.
- * @param string $base_key
- * Base key to be used for the elements in the form.
* @param array $parents
* Parents array for the element in the form.
+ * @param string $base_key
+ * (optional) Base key to be used for the elements in the form. NULL for
+ * top-level form elements.
*
* @return array
* A render array for the source value.
*/
- public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $base_key, $parents);
+ public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $parents, $base_key = NULL);
/**
* Sets configuration based on a nested form value array.
diff --git a/core/modules/config_translation/src/FormElement/FormElementBase.php b/core/modules/config_translation/src/FormElement/FormElementBase.php
index 3881346..9caa7f7 100644
--- a/core/modules/config_translation/src/FormElement/FormElementBase.php
+++ b/core/modules/config_translation/src/FormElement/FormElementBase.php
@@ -50,8 +50,8 @@ public function __construct(TypedDataInterface $element) {
/**
* {@inheritdoc}
*/
- public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $base_key, $parents) {
- $build[$base_key]['#theme'] = 'config_translation_manage_form_element';
+ public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $parents, $base_key = NULL) {
+ $build['#theme'] = 'config_translation_manage_form_element';
// For accessibility we make source and translation appear next to each
// other in the source for each element, which is why we utilize the
@@ -61,11 +61,11 @@ public function getElements(LanguageInterface $source_language, LanguageInterfac
// configuration values in ConfigTranslationFormBase::setConfig().
// Therefore we make the 'source' and 'translation' keys the top-level
// keys in $form_state['values'].
- $build[$base_key]['source'] = $this->getSourceElement($source_language, $source_config);
- $build[$base_key]['translation'] = $this->getTranslationElement($translation_language, $source_config, $translation_config);
+ $build['source'] = $this->getSourceElement($source_language, $source_config);
+ $build['translation'] = $this->getTranslationElement($translation_language, $source_config, $translation_config);
- $build[$base_key]['source']['#parents'] = array_merge(array('source'), $parents);
- $build[$base_key]['translation']['#parents'] = array_merge(array('translation'), $parents);
+ $build['source']['#parents'] = array_merge(array('source'), $parents);
+ $build['translation']['#parents'] = array_merge(array('translation'), $parents);
return $build;
}
diff --git a/core/modules/config_translation/src/FormElement/ListElement.php b/core/modules/config_translation/src/FormElement/ListElement.php
index 0314a3c..18c0687 100644
--- a/core/modules/config_translation/src/FormElement/ListElement.php
+++ b/core/modules/config_translation/src/FormElement/ListElement.php
@@ -8,17 +8,19 @@
namespace Drupal\config_translation\FormElement;
use Drupal\Core\Config\Config;
-use Drupal\Core\Config\Schema\Element;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\config_translation\Form\ConfigTranslationFormBase;
-use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\TypedData\DataDefinitionInterface;
use Drupal\language\Config\LanguageConfigOverride;
/**
* Defines the list element for the configuration translation interface.
*/
-class ListElement extends FormElementBase {
+class ListElement implements ElementInterface {
+
+ use StringTranslationTrait;
/**
* The schema element this form is for.
@@ -28,19 +30,27 @@ class ListElement extends FormElementBase {
protected $element;
/**
+ * The data definition of the element this form element is for.
+ *
+ * @var \Drupal\Core\TypedData\ListDataDefinitionInterface
+ */
+ protected $definition;
+
+ /**
* Constructs a FormElementBase.
*
* @param \Drupal\Core\Config\Schema\ArrayElement $element
* The schema element this form element is for.
*/
public function __construct(ArrayElement $element) {
- parent::__construct($element);
+ $this->element = $element;
+ $this->definition = $element->getDataDefinition();
}
/**
* {@inheritdoc}
*/
- public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $base_key, $parents) {
+ public function getElements(LanguageInterface $source_language, LanguageInterface $translation_language, $source_config, $translation_config, $parents, $base_key = NULL) {
$build = array();
foreach ($this->element as $key => $element) {
$sub_build = array();
@@ -67,39 +77,23 @@ public function getElements(LanguageInterface $source_language, LanguageInterfac
// Therefore we make the 'source' and 'translation' keys the top-level
// keys in $form_state['values'].
$element_parents = array_merge($parents, array($key));
- $sub_build += $form_element->getElements($source_language, $translation_language, $source_config[$key], $translation_config[$key], $element_key, $element_parents);
+ $sub_build += $form_element->getElements($source_language, $translation_language, $source_config[$key], $translation_config[$key], $element_parents, $element_key);
+
+ if (empty($sub_build)) {
+ continue;
+ }
+
// Build sub-structure and include it with a wrapper in the form
// if there are any translatable elements there.
- if (!empty($sub_build) && $element instanceof ArrayElement) {
- // For some configuration elements the same element structure can
- // repeat multiple times, (like views displays, filters, etc.).
- // So try to find a more usable title for the details summary. First
- // check if there is an element which is called title or label, then
- // check if there is an element which contains these words.
- $title = '';
- if (isset($sub_build['title']['source'])) {
- $title = $sub_build['title']['source']['#markup'];
- }
- elseif (isset($sub_build['label']['source'])) {
- $title = $sub_build['label']['source']['#markup'];
- }
- else {
- foreach (array_keys($sub_build) as $title_key) {
- if (isset($sub_build[$title_key]['source']) && (strpos($title_key, 'title') !== FALSE || strpos($title_key, 'label') !== FALSE)) {
- $title = $sub_build[$title_key]['source']['#markup'];
- break;
- }
- }
- }
- $build[$base_key] = array(
+ $build[$key] = array();
+ if ($element instanceof ArrayElement) {
+ $build[$key] = array(
'#type' => 'details',
- '#title' => (!empty($title) ? (strip_tags($title) . ' ') : '') . $this->t($definition['label']),
- '#open' => FALSE,
- ) + $sub_build;
- }
- else {
- $build += $sub_build;
+ '#title' => $this->getGroupTitle($definition, $sub_build),
+ '#open' => empty($base_key),
+ );
}
+ $build[$key] += $sub_build;
}
}
@@ -126,4 +120,41 @@ public function setConfig(Config $base_config, LanguageConfigOverride $config_tr
}
}
+ /**
+ * Returns the title for the 'details' element of a group of schema elements.
+ *
+ * For some configuration elements the same element structure can be repeated
+ * multiple times (for example views displays, filters, etc.). Thus, we try to
+ * find a more usable title for the details summary. First check if there is
+ * an element which is called title or label and use its value, then check if
+ * there is an element which contains these words and use those. Fall back
+ * to the generic definition label if no such element is found.
+ *
+ * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+ * The defintion of the schema element.
+ * @param $group_build
+ * The renderable array for the group of schema elements.
+ *
+ * @return string
+ * The title for the group of schema elements.
+ */
+ protected function getGroupTitle(DataDefinitionInterface $definition, $group_build) {
+ $title = '';
+ if (isset($group_build['title']['source'])) {
+ $title = $group_build['title']['source']['#markup'];
+ }
+ elseif (isset($group_build['label']['source'])) {
+ $title = $group_build['label']['source']['#markup'];
+ }
+ else {
+ foreach (array_keys($group_build) as $title_key) {
+ if (isset($group_build[$title_key]['source']) && (strpos($title_key, 'title') !== FALSE || strpos($title_key, 'label') !== FALSE)) {
+ $title = $group_build[$title_key]['source']['#markup'];
+ break;
+ }
+ }
+ }
+ return (!empty($title) ? (strip_tags($title) . ' ') : '') . $this->t($definition['label']);
+ }
+
}
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index 6c29709..d33a565 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -671,7 +671,7 @@ public function testTextFormatTranslation() {
$config_factory = $this->container->get('config.factory');
$expected = array(
- 'value' => 'Hello World',
+ 'value' => 'Hello World
',
'format' => 'plain_text',
);
$actual = $config_factory
@@ -695,7 +695,7 @@ public function testTextFormatTranslation() {
// Update translatable fields.
$edit = array(
- 'translation[config_names][config_translation_test.content][content][value]' => 'Hello World - FR',
+ 'translation[config_names][config_translation_test.content][content][value]' => 'Hello World - FR
',
);
// Save language specific version of form.
@@ -703,7 +703,7 @@ public function testTextFormatTranslation() {
// Get translation and check we've got the right value.
$expected = array(
- 'value' => 'Hello World - FR',
+ 'value' => 'Hello World - FR
',
'format' => 'plain_text',
);
$this->container->get('language.config_factory_override')
@@ -751,7 +751,7 @@ public function testTextFormatTranslation() {
);
$this->drupalPostForm($translation_page_url, $edit, t('Save translation'));
$expected = array(
- 'value' => 'Hello World - FR',
+ 'value' => 'Hello World - FR
',
'format' => 'full_html',
);
$actual = $config_factory