diff --git a/core/modules/content_translation/content_translation.install b/core/modules/content_translation/content_translation.install
index a8d4c49..c253bbe 100644
--- a/core/modules/content_translation/content_translation.install
+++ b/core/modules/content_translation/content_translation.install
@@ -5,9 +5,6 @@
* Installation functions for Content Translation module.
*/
-use Drupal\Core\Language\LanguageInterface;
-use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
-
/**
* Implements hook_install().
*/
@@ -15,6 +12,11 @@ function content_translation_install() {
// Assign a fairly low weight to ensure our implementation of
// hook_module_implements_alter() is run among the last ones.
module_set_weight('content_translation', 10);
+
+ // Initialize the Content Translation form language type configuration.
+ /** @var \Drupal\language\LanguageNegotiatorInterface $negotiator */
+ $negotiator = \Drupal::service('language_negotiator');
+ $negotiator->updateConfiguration([]);
}
/**
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 3b29ecc..a6d0850 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -13,6 +13,7 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\content_translation\Plugin\LanguageNegotiation\ContentTranslationFormLanguage;
/**
* Implements hook_help().
@@ -52,16 +53,37 @@ function content_translation_help($route_name, RouteMatchInterface $route_match)
*/
function content_translation_module_implements_alter(&$implementations, $hook) {
switch ($hook) {
- // Move some of our hook implementations to the end of the list.
+ // Move our entity_type_alter hook implementation to the end of the list.
case 'entity_type_alter':
$group = $implementations['content_translation'];
unset($implementations['content_translation']);
$implementations['content_translation'] = $group;
break;
+ // Move our entity_prepare_form hook implementation to the beginning of the
+ // list, so that the entity in the form object is exchanged with its
+ // requested translation before any other hook implementations have had
+ // access on it.
+ case 'entity_prepare_form':
+ $group = $implementations['content_translation'];
+ unset($implementations['content_translation']);
+ $implementations = array_merge(array('content_translation' => $group), $implementations);
+ break;
}
}
/**
+ * Implements hook_language_types_info().
+ */
+function content_translation_language_types_info() {
+ return [
+ ContentTranslationFormLanguage::TYPE => array(
+ 'fixed' => [ContentTranslationFormLanguage::METHOD_ID],
+ 'locked' => TRUE,
+ ),
+ ];
+}
+
+/**
* Implements hook_language_type_info_alter().
*/
function content_translation_language_types_info_alter(array &$language_types) {
@@ -307,6 +329,32 @@ function content_translation_form_alter(array &$form, FormStateInterface $form_s
}
/**
+ * Implements hook_entity_prepare_form().
+ */
+function content_translation_entity_prepare_form(EntityInterface $entity, $operation, FormStateInterface $form_state) {
+ // If the Content Translation form language differs from the current form
+ // language and we are editing an entity translation, we need to update the
+ // form language to match the specified value.
+ $langcode = NULL;
+ $prepare_translation =
+ $entity instanceof ContentEntityInterface &&
+ count($entity->getTranslationLanguages()) > 1 &&
+ !$form_state->get(['content_translation', 'source']) &&
+ !$form_state->get(['content_translation', 'translation_form']) &&
+ ($langcode = \Drupal::languageManager()->getCurrentLanguage(ContentTranslationFormLanguage::TYPE)->getId()) &&
+ $entity->language()->getId() != $langcode
+ && $entity->hasTranslation($langcode);
+
+ if ($prepare_translation) {
+ /** @var \Drupal\Core\Entity\EntityFormInterface $form_object*/
+ $form_object = $form_state->getFormObject();
+ $translation = $entity->getTranslation($langcode);
+ $form_object->setEntity($translation);
+ $form_state->set('langcode', $langcode);
+ }
+}
+
+/**
* Implements hook_language_fallback_candidates_OPERATION_alter().
*
* Performs language fallback for inaccessible translations.
diff --git a/core/modules/content_translation/src/Controller/ContentTranslationController.php b/core/modules/content_translation/src/Controller/ContentTranslationController.php
index bae6a94..c82eda3 100644
--- a/core/modules/content_translation/src/Controller/ContentTranslationController.php
+++ b/core/modules/content_translation/src/Controller/ContentTranslationController.php
@@ -8,6 +8,7 @@
namespace Drupal\content_translation\Controller;
use Drupal\content_translation\ContentTranslationManagerInterface;
+use Drupal\content_translation\Plugin\LanguageNegotiation\ContentTranslationFormLanguage;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Language\LanguageInterface;
@@ -67,8 +68,9 @@ public function prepareTranslation(ContentEntityInterface $entity, LanguageInter
* The route match.
* @param string $entity_type_id
* (optional) The entity type ID.
+ *
* @return array Array of page elements to render.
- * Array of page elements to render.
+ * Array of page elements to render.
*/
public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
@@ -77,6 +79,7 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
$handler = $this->entityManager()->getHandler($entity_type_id, 'translation');
$manager = $this->manager;
$entity_type = $entity->getEntityType();
+ $destination = $this->getDestinationArray();
$languages = $this->languageManager()->getLanguages();
$original = $entity->getUntranslated()->language()->getId();
@@ -167,16 +170,17 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
// the entity form, otherwise if we are not dealing with the original
// language we point the link to the translation form.
if ($entity->access('update') && $entity_type->hasLinkTemplate('edit-form')) {
- $links['edit']['url'] = $entity->urlInfo('edit-form');
- $links['edit']['language'] = $language;
+ $url = $entity->urlInfo('edit-form');
+ $url->setOption('query', [ContentTranslationFormLanguage::QUERY_PARAMETER => $langcode] + $destination);
+ $links['edit']['url'] = $url;
}
elseif (!$is_original && $handler->getTranslationAccess($entity, 'update')->isAllowed()) {
$links['edit']['url'] = $edit_url;
}
-
if (isset($links['edit'])) {
$links['edit']['title'] = $this->t('Edit');
}
+
$status = array('data' => array(
'#type' => 'inline_template',
'#template' => '{% if status %}{{ "Published"|t }}{% else %}{{ "Not published"|t }}{% endif %}{% if outdated %} {{ "outdated"|t }}{% endif %}',
@@ -193,17 +197,15 @@ public function overview(RouteMatchInterface $route_match, $entity_type_id = NUL
else {
$source_name = isset($languages[$source]) ? $languages[$source]->getName() : $this->t('n/a');
if ($entity->access('delete') && $entity_type->hasLinkTemplate('delete-form')) {
- $links['delete'] = array(
- 'title' => $this->t('Delete'),
- 'url' => $entity->urlInfo('delete-form'),
- 'language' => $language,
- );
+ $url = $entity->urlInfo('delete-form');
+ $url->setOption('query', [ContentTranslationFormLanguage::QUERY_PARAMETER => $langcode] + $destination);
+ $links['delete']['url'] = $url;
}
elseif ($handler->getTranslationAccess($entity, 'delete')->isAllowed()) {
- $links['delete'] = array(
- 'title' => $this->t('Delete'),
- 'url' => $delete_url,
- );
+ $links['delete']['url'] = $delete_url;
+ }
+ if (isset($links['delete'])) {
+ $links['delete']['title'] = $this->t('Delete');
}
}
}
diff --git a/core/modules/content_translation/src/Plugin/LanguageNegotiation/ContentTranslationFormLanguage.php b/core/modules/content_translation/src/Plugin/LanguageNegotiation/ContentTranslationFormLanguage.php
new file mode 100644
index 0000000..4e77d96
--- /dev/null
+++ b/core/modules/content_translation/src/Plugin/LanguageNegotiation/ContentTranslationFormLanguage.php
@@ -0,0 +1,50 @@
+get(static::QUERY_PARAMETER);
+ return $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
+ }
+
+}
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
index bf781fb..d9c6f51 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationUITestBase.php
@@ -7,6 +7,7 @@
namespace Drupal\content_translation\Tests;
+use Drupal\content_translation\Plugin\LanguageNegotiation\ContentTranslationFormLanguage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
@@ -42,6 +43,7 @@ function testTranslationUI() {
$this->doTestPublishedStatus();
$this->doTestAuthoringInfo();
$this->doTestTranslationEdit();
+ $this->doTestFormLanguageSwitch();
$this->doTestTranslationChanged();
$this->doTestTranslationDeletion();
}
@@ -132,16 +134,19 @@ protected function doTestBasicTranslation() {
*/
protected function doTestTranslationOverview() {
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
- $this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
+ $translate_url = $entity->urlInfo('drupal:content-translation-overview');
+ $this->drupalGet($translate_url);
+ $translate_url->setAbsolute(FALSE);
foreach ($this->langcodes as $langcode) {
if ($entity->hasTranslation($langcode)) {
$language = new Language(array('id' => $langcode));
- $view_path = $entity->url('canonical', array('language' => $language));
- $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_path));
+ $view_url = $entity->url('canonical', ['language' => $language]);
+ $elements = $this->xpath('//table//a[@href=:href]', array(':href' => $view_url));
$this->assertEqual((string) $elements[0], $entity->getTranslation($langcode)->label(), format_string('Label correctly shown for %language translation.', array('%language' => $langcode)));
- $edit_path = $entity->url('edit-form', array('language' => $language));
- $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_path));
+ $query = [ContentTranslationFormLanguage::QUERY_PARAMETER => $langcode, 'destination' => $translate_url->toString()];
+ $edit_url = $entity->url('edit-form', ['query' => $query]);
+ $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', array(':href' => $edit_url));
$this->assertEqual((string) $elements[0], t('Edit'), format_string('Edit link correct for %language translation.', array('%language' => $langcode)));
}
}
@@ -249,6 +254,20 @@ protected function doTestAuthoringInfo() {
}
/**
+ * Tests the form language switch functionality.
+ */
+ protected function doTestFormLanguageSwitch() {
+ $entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
+
+ $message = 'The form language can be switched to @langcode through a query string parameter';
+ foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+ $url = $entity->urlInfo('edit-form', ['query' => ['content_translation_target' => $langcode]]);
+ $this->drupalGet($url);
+ $this->assertRaw($entity->getTranslation($langcode)->{$this->fieldName}->value, format_string($message, array('@langcode' => $langcode)));
+ }
+ }
+
+ /**
* Tests translation deletion.
*/
protected function doTestTranslationDeletion() {
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
index 3de797e..0193188 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
@@ -7,6 +7,7 @@
namespace Drupal\content_translation\Tests;
+use Drupal\content_translation\Plugin\LanguageNegotiation\ContentTranslationFormLanguage;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
@@ -185,8 +186,10 @@ protected function doTestWorkflows(UserInterface $user, $expected_status) {
$this->clickLink('Edit', 2);
// An editor should be pointed to the entity form in multilingual mode.
// We need a new expected edit path with a new language.
- $expected_edit_path = $this->entity->url('edit-form', $options);
- $this->assertUrl($expected_edit_path, [], 'The translation overview points to the edit form for editors when editing translations.');
+ $translate_url = $this->entity->url('drupal:content-translation-overview', ['language' => $languages[$this->langcodes[1]], 'absolute' => FALSE]);
+ $options = ['query' => [ContentTranslationFormLanguage::QUERY_PARAMETER => $langcode, 'destination' => $translate_url]];
+ $expected_edit_url = $this->entity->url('edit-form', $options);
+ $this->assertUrl($expected_edit_url, [], 'The translation overview points to the edit form for editors when editing translations.');
}
else {
$this->clickLink('Edit');