diff --git a/core/modules/content_translation/content_translation.permissions.yml b/core/modules/content_translation/content_translation.permissions.yml index 17b5b3d..c09c65a 100644 --- a/core/modules/content_translation/content_translation.permissions.yml +++ b/core/modules/content_translation/content_translation.permissions.yml @@ -8,6 +8,8 @@ delete content translations: title: 'Delete translations' translate any entity: title: 'Translate any entity' +mark translations as outdated: + title: 'Mark translations as outdated' permission_callbacks: - \Drupal\content_translation\ContentTranslationPermissions::contentPermissions diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php index c1688b9..c880371 100644 --- a/core/modules/content_translation/src/ContentTranslationHandler.php +++ b/core/modules/content_translation/src/ContentTranslationHandler.php @@ -231,8 +231,10 @@ protected function checkFieldStorageDefinitionTranslatability($field_name) { public function retranslate(EntityInterface $entity, $langcode = NULL) { $updated_langcode = !empty($langcode) ? $langcode : $entity->language()->getId(); foreach ($entity->getTranslationLanguages() as $langcode => $language) { - $this->manager->getTranslationMetadata($entity->getTranslation($langcode)) - ->setOutdated($langcode != $updated_langcode); + if ($langcode != $updated_langcode) { + $this->manager->getTranslationMetadata($entity->getTranslation($langcode)) + ->setOutdated(TRUE); + } } } @@ -266,6 +268,7 @@ public function getSourceLangcode(FormStateInterface $form_state) { * {@inheritdoc} */ public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) { + $account = \Drupal::currentUser(); $form_object = $form_state->getFormObject(); $form_langcode = $form_object->getFormLangcode($form_state); $entity_langcode = $entity->getUntranslated()->language()->getId(); @@ -422,23 +425,20 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En '#disabled' => !$enabled, ]; - $translate = !$new_translation && $metadata->isOutdated(); - if (!$translate) { + if ($account->hasPermission('mark translations as outdated')) { + $form['content_translation']['outdated'] = [ + '#type' => 'checkbox', + '#title' => t('This translation needs to be updated'), + '#default_value' => !$new_translation && $metadata->isOutdated(), + '#description' => t('When this option is checked, this translation needs to be updated. Uncheck when the translation is up to date again.'), + ]; $form['content_translation']['retranslate'] = [ '#type' => 'checkbox', '#title' => t('Flag other translations as outdated'), '#default_value' => FALSE, '#description' => t('If you made a significant change, which means the other translations should be updated, you can flag all translations of this content as outdated. This will not change any other property of them, like whether they are published or not.'), ]; - } - else { - $form['content_translation']['outdated'] = [ - '#type' => 'checkbox', - '#title' => t('This translation needs to be updated'), - '#default_value' => $translate, - '#description' => t('When this option is checked, this translation needs to be updated. Uncheck when the translation is up to date again.'), - ]; - $form['content_translation']['#open'] = TRUE; + $form['content_translation']['#open'] = $new_translation || $metadata->isOutdated(); } // Default to the anonymous user. diff --git a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php index e69329c..d979304 100644 --- a/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php +++ b/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php @@ -113,6 +113,10 @@ protected function doTestBasicTranslation() { 'source' => $default_langcode, 'target' => $langcode ], ['language' => $language]); + + $this->drupalGet($add_url); + $this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open]'), 'The translation tab is correctly expanded when adding a new translation.'); + $this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode)); // Assert that HTML is escaped in "all languages" in UI after SafeMarkup @@ -239,16 +243,18 @@ protected function doTestTranslationOverview() { * Tests up-to-date status tracking. */ protected function doTestOutdatedStatus() { + /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */ $storage = $this->container->get('entity_type.manager') ->getStorage($this->entityTypeId); $storage->resetCache([$this->entityId]); + /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $storage->load($this->entityId); $langcode = 'fr'; $languages = \Drupal::languageManager()->getLanguages(); // Mark translations as outdated. $edit = ['content_translation[retranslate]' => TRUE]; - $edit_path = $entity->urlInfo('edit-form', ['language' => $languages[$langcode]]); + $edit_path = $entity->toUrl('edit-form', ['language' => $languages[$langcode]]); $this->drupalPostForm($edit_path, $edit, $this->getFormSubmitAction($entity, $langcode)); $storage->resetCache([$this->entityId]); $entity = $storage->load($this->entityId); @@ -256,19 +262,27 @@ protected function doTestOutdatedStatus() { // Check that every translation has the correct "outdated" status, and that // the Translation fieldset is open if the translation is "outdated". foreach ($this->langcodes as $added_langcode) { - $url = $entity->urlInfo('edit-form', ['language' => ConfigurableLanguage::load($added_langcode)]); + $url = $entity->toUrl('edit-form', ['language' => ConfigurableLanguage::load($added_langcode)]); $this->drupalGet($url); + $this->assertTrue($this->xpath('//input[@name="content_translation[retranslate]" and not(@checked)]'), 'The retranslate flag is always shown as unchecked.'); if ($added_langcode == $langcode) { - $this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.'); - $this->assertFalse($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab should be collapsed by default.'); + + // This translation should be up-to-date. + $this->assertTrue($this->xpath('//input[@name="content_translation[outdated]" and not(@checked)]'), 'The outdated flag is not checked.'); + $this->assertTrue($this->xpath('//details[@id="edit-content-translation" and not(@open)]'), 'The translation tab should be collapsed if it is an existing up-to-date translation.'); } else { - $this->assertFieldByXPath('//input[@name="content_translation[outdated]"]', TRUE, 'The translate flag is checked by default.'); - $this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab is correctly expanded when the translation is outdated.'); + + // This translation should be outdated. + $this->assertTrue($this->xpath('//input[@name="content_translation[outdated]" and @checked]'), 'The outdated flag is checked.'); + $this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open]'), 'The translation tab is correctly expanded when the translation is outdated.'); + + // Flag translation as up-to-date. $edit = ['content_translation[outdated]' => FALSE]; $this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $added_langcode)); $this->drupalGet($url); - $this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.'); + + // Check if outdated flag was unset. $storage = $this->container->get('entity_type.manager') ->getStorage($this->entityTypeId); $storage->resetCache([$this->entityId]);