From fea90fbda223e99668ae94ff392c2116eab525ed Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 24 Jul 2015 15:29:23 +0100
Subject: [PATCH] =?UTF-8?q?Issue=20#2409701=20by=20tstoeckler,=20Leksat,?=
 =?UTF-8?q?=20Schnitzel,=20=5Fnolocation,=20G=C3=A1bor=20Hojtsy,=20xjm:=20?=
 =?UTF-8?q?Field=20storage=20configuration=20is=20not=20exposed=20to=20con?=
 =?UTF-8?q?fig=20translation=20UI?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/ConfigEntityMapper.php                |  11 +-
 .../src/ConfigFieldMapper.php                 |  20 +++
 .../src/Tests/ConfigTranslationUiTest.php     |  58 ++++++++-
 .../tests/src/Unit/ConfigEntityMapperTest.php |  10 +-
 .../tests/src/Unit/ConfigFieldMapperTest.php  | 116 ++++++++++++++++++
 .../config/schema/field_test.schema.yml       |   6 +
 .../src/Plugin/Field/FieldType/TestItem.php   |   2 +
 7 files changed, 216 insertions(+), 7 deletions(-)
 create mode 100644 core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php

diff --git a/core/modules/config_translation/src/ConfigEntityMapper.php b/core/modules/config_translation/src/ConfigEntityMapper.php
index 269bfac86390..4a6d275db424 100644
--- a/core/modules/config_translation/src/ConfigEntityMapper.php
+++ b/core/modules/config_translation/src/ConfigEntityMapper.php
@@ -8,8 +8,8 @@
 namespace Drupal\config_translation;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Routing\RouteMatch;
@@ -43,7 +43,7 @@ class ConfigEntityMapper extends ConfigNamesMapper {
   /**
    * Loaded entity instance to help produce the translation interface.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\Core\Config\Entity\ConfigEntityInterface
    */
   protected $entity;
 
@@ -125,13 +125,13 @@ public function populateFromRequest(Request $request) {
    * configuration names to use to check permissions or display a translation
    * screen.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity to set.
+   * @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
+   *   The configuration entity to set.
    *
    * @return bool
    *   TRUE, if the entity was set successfully; FALSE otherwise.
    */
-  public function setEntity(EntityInterface $entity) {
+  public function setEntity(ConfigEntityInterface $entity) {
     if (isset($this->entity)) {
       return FALSE;
     }
@@ -143,6 +143,7 @@ public function setEntity(EntityInterface $entity) {
     // page with more names if form altering added more configuration to an
     // entity. This is not a Drupal 8 best practice (ideally the configuration
     // would have pluggable components), but this may happen as well.
+    /** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type_info */
     $entity_type_info = $this->entityManager->getDefinition($this->entityType);
     $this->addConfigName($entity_type_info->getConfigPrefix() . '.' . $entity->id());
 
diff --git a/core/modules/config_translation/src/ConfigFieldMapper.php b/core/modules/config_translation/src/ConfigFieldMapper.php
index e9d48e4e7550..a593fffd2a9d 100644
--- a/core/modules/config_translation/src/ConfigFieldMapper.php
+++ b/core/modules/config_translation/src/ConfigFieldMapper.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\config_translation;
 
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
 /**
  * Configuration mapper for fields.
  *
@@ -49,4 +51,22 @@ public function getTypeLabel() {
     return $this->t('@label fields', array('@label' => $base_entity_info->getLabel()));
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function setEntity(ConfigEntityInterface $entity) {
+    if (parent::setEntity($entity)) {
+
+      // Field storage config can also contain translatable values. Add the name
+      // of the config as well to the list of configs for this entity.
+      /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
+      $field_storage = $this->entity->getFieldStorageDefinition();
+      /** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type_info */
+      $entity_type_info = $this->entityManager->getDefinition($field_storage->getEntityTypeId());
+      $this->addConfigName($entity_type_info->getConfigPrefix() . '.' . $field_storage->id());
+      return TRUE;
+    }
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index 4bbb408d7db9..a05f7e70a876 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -13,6 +13,8 @@
 use Drupal\Core\Config\FileStorage;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\simpletest\WebTestBase;
 
@@ -28,7 +30,21 @@ class ConfigTranslationUiTest extends WebTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'contact', 'contact_test', 'config_translation', 'config_translation_test', 'views', 'views_ui', 'contextual', 'filter', 'filter_test');
+  public static $modules = [
+    'config_translation',
+    'config_translation_test',
+    'contact',
+    'contact_test',
+    'contextual',
+    'entity_test',
+    'field_test',
+    'field_ui',
+    'filter',
+    'filter_test',
+    'node',
+    'views',
+    'views_ui',
+  ];
 
   /**
    * Languages to enable.
@@ -700,6 +716,46 @@ public function testPluralConfigStrings() {
     $this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]', "$field_value_plural 3 SL");
   }
 
+  /**
+   * Tests the translation of field and field storage configuration.
+   */
+  public function testFieldConfigTranslation() {
+    // Add a test field which has a translatable field setting and a
+    // translatable field storage setting.
+    $field_name = strtolower($this->randomMachineName());
+    $field_storage = FieldStorageConfig::create([
+      'field_name' => $field_name,
+      'entity_type' => 'entity_test',
+      'type' => 'test_field',
+    ]);
+
+    $translatable_storage_setting = $this->randomString();
+    $field_storage->setSetting('translatable_storage_setting', $translatable_storage_setting);
+    $field_storage->save();
+
+    $bundle = strtolower($this->randomMachineName());
+    entity_test_create_bundle($bundle);
+    $field = FieldConfig::create([
+      'field_name' => $field_name,
+      'entity_type' => 'entity_test',
+      'bundle' => $bundle,
+    ]);
+
+    $translatable_field_setting = $this->randomString();
+    $field->setSetting('translatable_field_setting', $translatable_field_setting);
+    $field->save();
+
+    $this->drupalLogin($this->translatorUser);
+
+    $this->drupalGet("/entity_test/structure/$bundle/fields/entity_test.$bundle.$field_name/translate");
+    $this->clickLink('Add');
+
+    $this->assertText('Translatable field setting');
+    $this->assertRaw(SafeMarkup::checkPlain($translatable_field_setting));
+    $this->assertText('Translatable storage setting');
+    $this->assertRaw(SafeMarkup::checkPlain($translatable_storage_setting));
+  }
+
   /**
    * Test translation storage in locale storage.
    */
diff --git a/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php
index 8a2fc59e6007..804193197fa2 100644
--- a/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php
+++ b/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php
@@ -57,7 +57,7 @@ class ConfigEntityMapperTest extends UnitTestCase {
   protected function setUp() {
     $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
 
-    $this->entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
+    $this->entity = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityInterface');
 
     $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
 
@@ -109,6 +109,10 @@ public function testSetEntity() {
       ->will($this->returnValue('entity_id'));
 
     $entity_type = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityTypeInterface');
+    $entity_type
+      ->expects($this->any())
+      ->method('getConfigPrefix')
+      ->will($this->returnValue('config_prefix'));
     $this->entityManager
       ->expects($this->once())
       ->method('getDefinition')
@@ -118,6 +122,10 @@ public function testSetEntity() {
     $result = $this->configEntityMapper->setEntity($this->entity);
     $this->assertTrue($result);
 
+    // Ensure that the configuration name was added to the mapper.
+    $plugin_definition = $this->configEntityMapper->getPluginDefinition();
+    $this->assertTrue(in_array('config_prefix.entity_id', $plugin_definition['names']));
+
     // Make sure setEntity() returns FALSE when called a second time.
     $result = $this->configEntityMapper->setEntity($this->entity);
     $this->assertFalse($result);
diff --git a/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php
new file mode 100644
index 000000000000..740b7226cefa
--- /dev/null
+++ b/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\config_translation\Unit\ConfigFieldMapperTest.
+ */
+
+namespace Drupal\Tests\config_translation\Unit;
+
+use Drupal\config_translation\ConfigFieldMapper;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the functionality provided by the configuration field mapper.
+ *
+ * @group config_translation
+ *
+ * @coversDefaultClass \Drupal\config_translation\ConfigFieldMapper
+ */
+class ConfigFieldMapperTest extends UnitTestCase {
+
+  /**
+   * The configuration field mapper to test.
+   *
+   * @var \Drupal\config_translation\ConfigFieldMapper
+   */
+  protected $configFieldMapper;
+
+  /**
+   * The field config instance used for testing.
+   *
+   * @var \Drupal\field\FieldConfigInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entity;
+
+  /**
+   * The entity manager used for testing.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+    $this->entity = $this->getMock('Drupal\field\FieldConfigInterface');
+
+    $definition = array(
+      'class' => '\Drupal\config_translation\ConfigFieldMapper',
+      'base_route_name' => 'entity.field_config.node_field_edit_form',
+      'title' => '!label field',
+      'names' => array(),
+      'entity_type' => 'field_config',
+    );
+
+    $locale_config_manager = $this->getMockBuilder('Drupal\locale\LocaleConfigManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->configFieldMapper = new ConfigFieldMapper(
+      'node_fields',
+      $definition,
+      $this->getConfigFactoryStub(),
+      $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface'),
+      $locale_config_manager,
+      $this->getMock('Drupal\config_translation\ConfigMapperManagerInterface'),
+      $this->getMock('Drupal\Core\Routing\RouteProviderInterface'),
+      $this->getStringTranslationStub(),
+      $this->entityManager,
+      $this->getMock('Drupal\Core\Language\LanguageManagerInterface')
+    );
+  }
+
+  /**
+   * Tests ConfigFieldMapper::setEntity().
+   *
+   * @covers ::setEntity
+   */
+  public function testSetEntity() {
+    $entity_type = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityTypeInterface');
+    $entity_type
+      ->expects($this->any())
+      ->method('getConfigPrefix')
+      ->will($this->returnValue('config_prefix'));
+
+    $this->entityManager
+      ->expects($this->any())
+      ->method('getDefinition')
+      ->will($this->returnValue($entity_type));
+
+    $field_storage = $this->getMock('Drupal\field\FieldStorageConfigInterface');
+    $field_storage
+      ->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue('field_storage_id'));
+
+    $this->entity
+      ->expects($this->any())
+      ->method('getFieldStorageDefinition')
+      ->will($this->returnValue($field_storage));
+
+    $result = $this->configFieldMapper->setEntity($this->entity);
+    $this->assertTrue($result);
+
+    // Ensure that the configuration name was added to the mapper.
+    $plugin_definition = $this->configFieldMapper->getPluginDefinition();
+    $this->assertTrue(in_array('config_prefix.field_storage_id', $plugin_definition['names']));
+
+    // Make sure setEntity() returns FALSE when called a second time.
+    $result = $this->configFieldMapper->setEntity($this->entity);
+    $this->assertFalse($result);
+  }
+
+}
diff --git a/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml b/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
index 48f5dcf37be5..8e06db17b4b5 100644
--- a/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
+++ b/core/modules/field/tests/modules/field_test/config/schema/field_test.schema.yml
@@ -65,6 +65,9 @@ field.storage_settings.test_field:
     config_data_from_storage_setting:
       type: boolean
       label: 'Test FieldItemInterface::storageSettingsToConfigData()'
+    translatable_storage_setting:
+      type: label
+      label: 'Translatable storage setting'
 
 field.storage_settings.test_field_with_dependencies:
   type: field.storage_settings.test_field
@@ -88,6 +91,9 @@ field.field_settings.test_field:
     config_data_from_field_setting:
       type: boolean
       label: 'Test FieldItemInterface::fieldSettingsToConfigData()'
+    translatable_field_setting:
+      type: label
+      label: 'Translatable field setting'
 
 field.field_settings.test_field_with_dependencies:
   type: field.field_settings.test_field
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
index 9886b0307944..42eb11e8d807 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldType/TestItem.php
@@ -33,6 +33,7 @@ public static function defaultStorageSettings() {
       'test_field_storage_setting' => 'dummy test string',
       'changeable' => 'a changeable field storage setting',
       'unchangeable' => 'an unchangeable field storage setting',
+      'translatable_storage_setting' => 'a translatable field storage setting',
     ) + parent::defaultStorageSettings();
   }
 
@@ -42,6 +43,7 @@ public static function defaultStorageSettings() {
   public static function defaultFieldSettings() {
     return array(
       'test_field_setting' => 'dummy test string',
+      'translatable_field_setting' => 'a translatable field setting',
     ) + parent::defaultFieldSettings();
   }
 
-- 
GitLab