diff --git a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php index 9537aad..51f6463 100644 --- a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php +++ b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php @@ -70,7 +70,18 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */ $mapper = $this->configMapperManager->createInstance($route->getDefault('plugin_id')); $mapper->populateFromRouteMatch($route_match); - $this->sourceLanguage = $this->languageManager->getLanguage($mapper->getLangcode()); + + try { + $langcode = $mapper->getLangcode(); + } + catch (\RuntimeException $exception) { + // ConfigTranslationController and ConfigTranslationFormBase show a + // helpful message if the language codes do not match, so do not let that + // prevent granting access. + $langcode = 'en'; + } + + $this->sourceLanguage = $this->languageManager->getLanguage($langcode); // Allow access to the translation overview if the proper permission is // granted, the configuration has translatable pieces, and the source diff --git a/core/modules/config_translation/src/ConfigNamesMapper.php b/core/modules/config_translation/src/ConfigNamesMapper.php index 5d15dd5..8efeb16 100644 --- a/core/modules/config_translation/src/ConfigNamesMapper.php +++ b/core/modules/config_translation/src/ConfigNamesMapper.php @@ -385,14 +385,7 @@ public function getTypeLabel() { * {@inheritdoc} */ public function getLangcode() { - $config_factory = $this->configFactory; - $langcodes = array_map(function($name) use ($config_factory) { - // Default to English if no language code was provided in the file. - // Although it is a best practice to include a language code, if the - // developer did not think about a multilingual use-case, we fall back - // on assuming the file is English. - return $config_factory->get($name)->get('langcode') ?: 'en'; - }, $this->getConfigNames()); + $langcodes = array_map([$this, 'getLangcodeFromConfig'], $this->getConfigNames()); if (count(array_unique($langcodes)) > 1) { throw new \RuntimeException('A config mapper can only contain configuration for a single language.'); @@ -402,6 +395,23 @@ public function getLangcode() { } /** + * Returns the language code of a configuration object given its name. + * + * @param string $config_name + * The name of the configuration object. + * + * @return string + * The language code of the configuration object. + */ + public function getLangcodeFromConfig($config_name) { + // Default to English if no language code was provided in the file. + // Although it is a best practice to include a language code, if the + // developer did not think about a multilingual use-case, we fall back + // on assuming the file is English. + return $this->configFactory->get($config_name)->get('langcode') ?: 'en'; + } + + /** * {@inheritdoc} */ public function setLangcode($langcode) { diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php index cb49084..42d0b9e 100644 --- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php +++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php @@ -8,7 +8,9 @@ namespace Drupal\config_translation\Form; use Drupal\config_translation\ConfigMapperManagerInterface; +use Drupal\config_translation\ConfigNamesMapper; use Drupal\Core\Config\TypedConfigManagerInterface; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Core\Form\BaseFormIdInterface; @@ -52,6 +54,13 @@ protected $languageManager; /** + * The renderer. + * + * @var \Drupal\Core\Render\RendererInterface + */ + protected $renderer; + + /** * The language of the configuration translation. * * @var \Drupal\Core\Language\LanguageInterface @@ -81,11 +90,13 @@ * The configuration mapper manager. * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager * The configurable language manager. + * @param \Drupal\Core\Render\RendererInterface */ - public function __construct(TypedConfigManagerInterface $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, ConfigurableLanguageManagerInterface $language_manager) { + public function __construct(TypedConfigManagerInterface $typed_config_manager, ConfigMapperManagerInterface $config_mapper_manager, ConfigurableLanguageManagerInterface $language_manager, RendererInterface $renderer) { $this->typedConfigManager = $typed_config_manager; $this->configMapperManager = $config_mapper_manager; $this->languageManager = $language_manager; + $this->renderer = $renderer; } /** @@ -95,7 +106,8 @@ public static function create(ContainerInterface $container) { return new static( $container->get('config.typed'), $container->get('plugin.manager.config_translation.mapper'), - $container->get('language_manager') + $container->get('language_manager'), + $container->get('renderer') ); } @@ -143,7 +155,30 @@ public function buildForm(array $form, FormStateInterface $form_state, RouteMatc $this->mapper = $mapper; $this->language = $language; - $this->sourceLanguage = $this->languageManager->getLanguage($this->mapper->getLangcode()); + + try { + $langcode = $this->mapper->getLangcode(); + } + catch (\RuntimeException $exception) { + $message = ''; + if ($mapper instanceof ConfigNamesMapper) { + $items = []; + foreach ($mapper->getconfigNames() as $config_name) { + $langcode = $mapper->getLangcodeFromConfig($config_name); + $items[] = $config_name .': ' . $this->languageManager->getLanguage($langcode)->getName(); + } + $message = [ + 'message' => ['#markup' => t('Configuration objects have different language codes:')], + 'items' => [ + '#theme' => 'item_list', + '#items' => $items, + ] + ]; + } + drupal_set_message($this->renderer->renderRoot($message), 'warning'); + } + + $this->sourceLanguage = $this->languageManager->getLanguage($langcode); // Get base language configuration to display in the form before setting the // language to use for the form. This avoids repetitively settings and diff --git a/core/modules/node/src/Tests/NodeTypeTranslationTest.php b/core/modules/node/src/Tests/NodeTypeTranslationTest.php index 10c6865..a473233 100644 --- a/core/modules/node/src/Tests/NodeTypeTranslationTest.php +++ b/core/modules/node/src/Tests/NodeTypeTranslationTest.php @@ -24,7 +24,9 @@ class NodeTypeTranslationTest extends WebTestBase { * @var array */ public static $modules = array( + 'block', 'config_translation', + 'field_ui', 'node', ); @@ -54,6 +56,8 @@ protected function setUp() { $admin_permissions = array( 'administer content types', + 'administer node fields', + 'administer languages', 'administer site configuration', 'administer themes', 'translate configuration', @@ -139,6 +143,28 @@ public function testNodeTypeTitleLabelTranslation() { $this->assertRaw(t('Edited title')); $this->drupalGet("$langcode/node/add/$type"); $this->assertRaw(t('Translated title')); + + // Add an e-mail field. + $this->drupalPostForm("admin/structure/types/manage/$type/fields/add-field", array('new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email'), 'Save and continue'); + $this->drupalPostForm(NULL, array(), 'Save field settings'); + $this->drupalPostForm(NULL, array(), 'Save settings'); + + $type = Unicode::strtolower($this->randomMachineName(16)); + $name = $this->randomString(); + $this->drupalCreateContentType(array('type' => $type, 'name' => $name)); + + // Set tabs. + $this->drupalPlaceBlock('local_tasks_block', array('primary' => TRUE)); + + // Change default language. + $this->drupalPostForm('admin/config/regional/language', array('site_default_language' => 'es'), 'Save configuration'); + + // Try re-using the email field. + $this->drupalGet("es/admin/structure/types/manage/$type/fields/add-field"); + $this->drupalPostForm(NULL, array('existing_storage_name' => 'field_email', 'existing_storage_label' => 'Email'), 'Save and continue'); + $this->assertResponse(200); + $this->drupalGet("es/admin/structure/types/manage/$type/fields/node.$type.field_email/translate"); + $this->assertResponse(200); } }