Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -5,6 +5,6 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- content_translation
|
||||
- language
|
||||
- entity_test
|
||||
- drupal:content_translation
|
||||
- drupal:language
|
||||
- drupal:entity_test
|
||||
|
|
|
@ -5,7 +5,39 @@
|
|||
* Helper module for the Content Translation tests.
|
||||
*/
|
||||
|
||||
use \Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_entity_bundle_info_alter().
|
||||
*/
|
||||
function content_translation_test_entity_bundle_info_alter(&$bundles) {
|
||||
// Store the initial status of the "translatable" property for the
|
||||
// "entity_test_mul" bundle.
|
||||
$translatable = !empty($bundles['entity_test_mul']['entity_test_mul']['translatable']);
|
||||
\Drupal::state()->set('content_translation_test.translatable', $translatable);
|
||||
// Make it translatable if Content Translation did not. This will make the
|
||||
// entity object translatable even if it is disabled in Content Translation
|
||||
// settings.
|
||||
if (!$translatable) {
|
||||
$bundles['entity_test_mul']['entity_test_mul']['translatable'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_access().
|
||||
*/
|
||||
function content_translation_test_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
$access = \Drupal::state()->get('content_translation.entity_access.' . $entity->getEntityTypeId());
|
||||
if (!empty($access[$operation])) {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
else {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_BASE_FORM_ID_alter().
|
||||
|
|
|
@ -5,5 +5,5 @@ package: Testing
|
|||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- content_translation
|
||||
- views
|
||||
- drupal:content_translation
|
||||
- drupal:views
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
/**
|
||||
* Tests the test content translation UI with the test entity.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTestTranslationUITest extends ContentTranslationUITestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $testHTMLEscapeForAllLanguages = TRUE;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'entity_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Use the entity_test_mul as this has multilingual property support.
|
||||
$this->entityTypeId = 'entity_test_mul_changed';
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTranslatorPermissions() {
|
||||
return array_merge(parent::getTranslatorPermissions(), ['administer entity_test content', 'view test entity']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that contextual links are available for content translation.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationContextualLinksTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* The bundle being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bundle;
|
||||
|
||||
/**
|
||||
* The content type being tested.
|
||||
*
|
||||
* @var \Drupal\node\Entity\NodeType
|
||||
*/
|
||||
protected $contentType;
|
||||
|
||||
/**
|
||||
* The 'translator' user to use during testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
* The enabled languages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $langcodes;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['content_translation', 'contextual', 'node'];
|
||||
|
||||
/**
|
||||
* The profile to install as a basis for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing';
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
// Set up an additional language.
|
||||
$this->langcodes = [\Drupal::languageManager()->getDefaultLanguage()->getId(), 'es'];
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
|
||||
// Create a content type.
|
||||
$this->bundle = $this->randomMachineName();
|
||||
$this->contentType = $this->drupalCreateContentType(['type' => $this->bundle]);
|
||||
|
||||
// Add a field to the content type. The field is not yet translatable.
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => 'field_test_text',
|
||||
'entity_type' => 'node',
|
||||
'type' => 'text',
|
||||
'cardinality' => 1,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'field_test_text',
|
||||
'bundle' => $this->bundle,
|
||||
'label' => 'Test text-field',
|
||||
])->save();
|
||||
entity_get_form_display('node', $this->bundle, 'default')
|
||||
->setComponent('field_test_text', [
|
||||
'type' => 'text_textfield',
|
||||
'weight' => 0,
|
||||
])
|
||||
->save();
|
||||
|
||||
// Create a translator user.
|
||||
$permissions = [
|
||||
'access contextual links',
|
||||
'administer nodes',
|
||||
"edit any $this->bundle content",
|
||||
'translate any entity',
|
||||
];
|
||||
$this->translator = $this->drupalCreateUser($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a contextual link is available for translating a node.
|
||||
*/
|
||||
public function testContentTranslationContextualLinks() {
|
||||
// Create a node.
|
||||
$title = $this->randomString();
|
||||
$this->drupalCreateNode(['type' => $this->bundle, 'title' => $title, 'langcode' => 'en']);
|
||||
$node = $this->drupalGetNodeByTitle($title);
|
||||
|
||||
// Use a UI form submission to make the node type and field translatable.
|
||||
// This tests that caches are properly invalidated.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][' . $this->bundle . '][settings][language][language_alterable]' => TRUE,
|
||||
'settings[node][' . $this->bundle . '][translatable]' => TRUE,
|
||||
'settings[node][' . $this->bundle . '][fields][field_test_text]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Check that the link leads to the translate page.
|
||||
$this->drupalLogin($this->translator);
|
||||
$translate_link = 'node/' . $node->id() . '/translations';
|
||||
$this->drupalGet($translate_link);
|
||||
$this->assertRaw(t('Translations of %label', ['%label' => $node->label()]), 'The contextual link leads to the translate page.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Test disabling content translation module.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationDisableSettingTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'menu_link_content',
|
||||
'language',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests that entity schemas are up-to-date after enabling translation.
|
||||
*/
|
||||
public function testDisableSetting() {
|
||||
// Define selectors.
|
||||
$group_checkbox = 'entity_types[menu_link_content]';
|
||||
$translatable_checkbox = 'settings[menu_link_content][menu_link_content][translatable]';
|
||||
$language_alterable = 'settings[menu_link_content][menu_link_content][settings][language][language_alterable]';
|
||||
|
||||
$user = $this->drupalCreateUser([
|
||||
'administer site configuration',
|
||||
'administer content translation',
|
||||
'create content translations',
|
||||
'administer languages',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$assert = $this->assertSession();
|
||||
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
|
||||
$assert->checkboxNotChecked('entity_types[menu_link_content]');
|
||||
|
||||
$edit = [
|
||||
$group_checkbox => TRUE,
|
||||
$translatable_checkbox => TRUE,
|
||||
$language_alterable => TRUE,
|
||||
];
|
||||
$this->submitForm($edit, t('Save configuration'));
|
||||
|
||||
$assert->pageTextContains(t('Settings successfully updated.'));
|
||||
|
||||
$assert->checkboxChecked($group_checkbox);
|
||||
|
||||
$edit = [
|
||||
$group_checkbox => FALSE,
|
||||
$translatable_checkbox => TRUE,
|
||||
$language_alterable => TRUE,
|
||||
];
|
||||
$this->submitForm($edit, t('Save configuration'));
|
||||
|
||||
$assert->pageTextContains(t('Settings successfully updated.'));
|
||||
|
||||
$assert->checkboxNotChecked($group_checkbox);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Test enabling content translation module.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationEnableTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['entity_test', 'menu_link_content', 'node'];
|
||||
|
||||
/**
|
||||
* Tests that entity schemas are up-to-date after enabling translation.
|
||||
*/
|
||||
public function testEnable() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
// Enable modules and make sure the related config entity type definitions
|
||||
// are installed.
|
||||
$edit = [
|
||||
'modules[content_translation][enable]' => TRUE,
|
||||
'modules[language][enable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/modules', $edit, t('Install'));
|
||||
|
||||
// Status messages are shown.
|
||||
$this->assertText(t('This site has only a single language enabled. Add at least one more language in order to translate content.'));
|
||||
$this->assertText(t('Enable translation for content types, taxonomy vocabularies, accounts, or any other element you wish to translate.'));
|
||||
|
||||
// No pending updates should be available.
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$requirement_value = $this->cssSelect("details.system-status-report__entry summary:contains('Entity/field definitions') + div");
|
||||
$this->assertEqual(t('Up to date'), trim($requirement_value[0]->getText()));
|
||||
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
// The node entity type should not be an option because it has no bundles.
|
||||
$this->assertNoRaw('entity_types[node]');
|
||||
// Enable content translation on entity types that have will have a
|
||||
// content_translation_uid.
|
||||
$edit = [
|
||||
'entity_types[menu_link_content]' => TRUE,
|
||||
'settings[menu_link_content][menu_link_content][translatable]' => TRUE,
|
||||
'entity_types[entity_test_mul]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][translatable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
|
||||
// No pending updates should be available.
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$requirement_value = $this->cssSelect("details.system-status-report__entry summary:contains('Entity/field definitions') + div");
|
||||
$this->assertEqual(t('Up to date'), trim($requirement_value[0]->getText()));
|
||||
|
||||
// Create a node type and check the content translation settings are now
|
||||
// available for nodes.
|
||||
$edit = [
|
||||
'name' => 'foo',
|
||||
'title_label' => 'title for foo',
|
||||
'type' => 'foo',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/types/add', $edit, t('Save content type'));
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertRaw('entity_types[node]');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\node\Functional\NodeTestBase;
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests the content translation language that is set.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationLanguageChangeTest extends NodeTestBase {
|
||||
|
||||
use TestFileCreationTrait {
|
||||
getTestFiles as drupalGetTestFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'content_translation_test', 'node', 'block', 'field_ui', 'image'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$langcodes = ['de', 'fr'];
|
||||
foreach ($langcodes as $langcode) {
|
||||
ConfigurableLanguage::createFromLangcode($langcode)->save();
|
||||
}
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
$user = $this->drupalCreateUser([
|
||||
'administer site configuration',
|
||||
'administer nodes',
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'delete any article content',
|
||||
'administer content translation',
|
||||
'translate any entity',
|
||||
'create content translations',
|
||||
'administer languages',
|
||||
'administer content types',
|
||||
'administer node fields',
|
||||
]);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Enable translation for article.
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][article][translatable]' => TRUE,
|
||||
'settings[node][article][settings][language][language_alterable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
|
||||
// Add an image field.
|
||||
$this->drupalGet('admin/structure/types/manage/article/fields/add-field');
|
||||
$edit = [
|
||||
'new_storage_type' => 'image',
|
||||
'field_name' => 'image_field',
|
||||
'label' => 'image_field',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and continue'));
|
||||
$this->drupalPostForm(NULL, [], t('Save field settings'));
|
||||
$this->drupalPostForm(NULL, [], t('Save settings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the source language is properly set when changing.
|
||||
*/
|
||||
public function testLanguageChange() {
|
||||
// Create a node in English.
|
||||
$this->drupalGet('node/add/article');
|
||||
$edit = [
|
||||
'title[0][value]' => 'english_title',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
|
||||
// Create a translation in French.
|
||||
$this->clickLink('Translate');
|
||||
$this->clickLink('Add');
|
||||
$this->drupalPostForm(NULL, [], t('Save (this translation)'));
|
||||
$this->clickLink('Translate');
|
||||
|
||||
// Edit English translation.
|
||||
$this->clickLink('Edit');
|
||||
// Upload and image after changing the node language.
|
||||
$images = $this->drupalGetTestFiles('image')[1];
|
||||
$edit = [
|
||||
'langcode[0][value]' => 'de',
|
||||
'files[field_image_field_0]' => $images->uri,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Upload'));
|
||||
$this->drupalPostForm(NULL, ['field_image_field[0][alt]' => 'alternative_text'], t('Save (this translation)'));
|
||||
|
||||
// Check that the translation languages are correct.
|
||||
$node = $this->getNodeByTitle('english_title');
|
||||
$translation_languages = array_keys($node->getTranslationLanguages());
|
||||
$this->assertTrue(in_array('fr', $translation_languages));
|
||||
$this->assertTrue(in_array('de', $translation_languages));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that title does not change on ajax call with new language value.
|
||||
*/
|
||||
public function testTitleDoesNotChangesOnChangingLanguageWidgetAndTriggeringAjaxCall() {
|
||||
// Create a node in English.
|
||||
$this->drupalGet('node/add/article', ['query' => ['test_field_only_en_fr' => 1]]);
|
||||
$edit = [
|
||||
'title[0][value]' => 'english_title',
|
||||
'test_field_only_en_fr' => 'node created',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertEqual('node created', \Drupal::state()->get('test_field_only_en_fr'));
|
||||
|
||||
// Create a translation in French.
|
||||
$this->clickLink('Translate');
|
||||
$this->clickLink('Add');
|
||||
$this->drupalPostForm(NULL, [], t('Save (this translation)'));
|
||||
$this->clickLink('Translate');
|
||||
|
||||
// Edit English translation.
|
||||
$node = $this->getNodeByTitle('english_title');
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
// Test the expected title when loading the form.
|
||||
$this->assertRaw('<title>Edit Article english_title | Drupal</title>');
|
||||
// Upload and image after changing the node language.
|
||||
$images = $this->drupalGetTestFiles('image')[1];
|
||||
$edit = [
|
||||
'langcode[0][value]' => 'de',
|
||||
'files[field_image_field_0]' => $images->uri,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Upload'));
|
||||
// Test the expected title after triggering an ajax call with a new
|
||||
// language selected.
|
||||
$this->assertRaw('<title>Edit Article english_title | Drupal</title>');
|
||||
$edit = [
|
||||
'langcode[0][value]' => 'en',
|
||||
'field_image_field[0][alt]' => 'alternative_text',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
|
||||
// Check that the translation languages are correct.
|
||||
$node = $this->getNodeByTitle('english_title');
|
||||
$translation_languages = array_keys($node->getTranslationLanguages());
|
||||
$this->assertTrue(in_array('fr', $translation_languages));
|
||||
$this->assertTrue(!in_array('de', $translation_languages));
|
||||
}
|
||||
|
||||
}
|
|
@ -98,14 +98,14 @@ class ContentTranslationOperationsTest extends NodeTestBase {
|
|||
'access content' => TRUE,
|
||||
]
|
||||
);
|
||||
$node->setPublished(FALSE)->save();
|
||||
$node->setUnpublished()->save();
|
||||
$this->drupalGet($node->urlInfo('drupal:content-translation-overview'));
|
||||
$this->assertResponse(403);
|
||||
$this->drupalLogout();
|
||||
|
||||
// Ensure the 'Translate' local task does not show up anymore when disabling
|
||||
// translations for a content type.
|
||||
$node->setPublished(TRUE)->save();
|
||||
$node->setPublished()->save();
|
||||
user_role_change_permissions(
|
||||
Role::AUTHENTICATED_ID,
|
||||
[
|
||||
|
@ -136,7 +136,7 @@ class ContentTranslationOperationsTest extends NodeTestBase {
|
|||
$this->assertFalse(content_translation_translate_access($node)->isAllowed());
|
||||
$access_control_handler->resetCache();
|
||||
|
||||
$node->setPublished(TRUE);
|
||||
$node->setPublished();
|
||||
$node->save();
|
||||
$this->assertTrue(content_translation_translate_access($node)->isAllowed());
|
||||
$access_control_handler->resetCache();
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the "Flag as outdated" functionality with revision translations.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationOutdatedRevisionTranslationTest extends ContentTranslationPendingRevisionTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->enableContentModeration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that outdated revision translations work correctly.
|
||||
*/
|
||||
public function testFlagAsOutdatedHidden() {
|
||||
// Create a test node.
|
||||
$values = [
|
||||
'title' => 'Test 1.1 EN',
|
||||
'moderation_state' => 'published',
|
||||
];
|
||||
$id = $this->createEntity($values, 'en');
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->storage->load($id);
|
||||
|
||||
// Add a published Italian translation.
|
||||
$add_translation_url = Url::fromRoute("entity.{$this->entityTypeId}.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $id,
|
||||
'source' => 'en',
|
||||
'target' => 'it',
|
||||
],
|
||||
[
|
||||
'language' => ConfigurableLanguage::load('it'),
|
||||
'absolute' => FALSE,
|
||||
]
|
||||
);
|
||||
$this->drupalGet($add_translation_url);
|
||||
$this->assertFlagWidget();
|
||||
$edit = [
|
||||
'title[0][value]' => 'Test 1.2 IT',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
|
||||
// Add a published French translation.
|
||||
$add_translation_url = Url::fromRoute("entity.{$this->entityTypeId}.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $id,
|
||||
'source' => 'en',
|
||||
'target' => 'fr',
|
||||
],
|
||||
[
|
||||
'language' => ConfigurableLanguage::load('fr'),
|
||||
'absolute' => FALSE,
|
||||
]
|
||||
);
|
||||
$this->drupalGet($add_translation_url);
|
||||
$this->assertFlagWidget();
|
||||
$edit = [
|
||||
'title[0][value]' => 'Test 1.3 FR',
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
|
||||
// Create an English draft.
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$en_edit_url = $this->getEditUrl($entity);
|
||||
$this->drupalGet($en_edit_url);
|
||||
$this->assertFlagWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the flag widget is displayed.
|
||||
*/
|
||||
protected function assertFlagWidget() {
|
||||
$this->assertSession()->pageTextNotContains('Flag other translations as outdated');
|
||||
$this->assertSession()->pageTextContains('Translations cannot be flagged as outdated when content is moderated.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
|
||||
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
|
||||
|
||||
/**
|
||||
* Base class for pending revision translation tests.
|
||||
*/
|
||||
abstract class ContentTranslationPendingRevisionTestBase extends ContentTranslationTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
use ContentModerationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'content_moderation', 'node'];
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* Permissions common to all test accounts.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $commonPermissions;
|
||||
|
||||
/**
|
||||
* The current test account.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentAccount;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityTypeId = 'node';
|
||||
$this->bundle = 'article';
|
||||
|
||||
$this->commonPermissions = [
|
||||
'view any unpublished content',
|
||||
"translate {$this->bundle} {$this->entityTypeId}",
|
||||
"create content translations",
|
||||
'use editorial transition create_new_draft',
|
||||
'use editorial transition publish',
|
||||
'use editorial transition archive',
|
||||
'use editorial transition archived_draft',
|
||||
'use editorial transition archived_published',
|
||||
];
|
||||
|
||||
parent::setUp();
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$this->storage = $entity_type_manager->getStorage($this->entityTypeId);
|
||||
|
||||
// @todo Remove this line once https://www.drupal.org/node/2945928 is fixed.
|
||||
$this->config('node.settings')->set('use_admin_theme', '1')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables content moderation for the test entity type and bundle.
|
||||
*/
|
||||
protected function enableContentModeration() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$workflow_id = 'editorial';
|
||||
$this->drupalGet('/admin/config/workflow/workflows');
|
||||
$edit['bundles[' . $this->bundle . ']'] = TRUE;
|
||||
$this->drupalPostForm('admin/config/workflow/workflows/manage/' . $workflow_id . '/type/' . $this->entityTypeId, $edit, t('Save'));
|
||||
// Ensure the parent environment is up-to-date.
|
||||
// @see content_moderation_workflow_insert()
|
||||
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
|
||||
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
|
||||
/** @var \Drupal\Core\Routing\RouteBuilderInterface $router_builder */
|
||||
$router_builder = $this->container->get('router.builder');
|
||||
$router_builder->rebuildIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditorPermissions() {
|
||||
$editor_permissions = [
|
||||
"edit any {$this->bundle} content",
|
||||
"delete any {$this->bundle} content",
|
||||
"view {$this->bundle} revisions",
|
||||
"delete {$this->bundle} revisions",
|
||||
];
|
||||
return array_merge($editor_permissions, $this->commonPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTranslatorPermissions() {
|
||||
return array_merge(parent::getTranslatorPermissions(), $this->commonPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setupBundle() {
|
||||
parent::setupBundle();
|
||||
$this->createContentType(['type' => $this->bundle]);
|
||||
$this->createEditorialWorkflow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the active revision translation for the specified entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity being edited.
|
||||
* @param string $langcode
|
||||
* The translation language code.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface|null
|
||||
* The active revision translation or NULL if none could be identified.
|
||||
*/
|
||||
protected function loadRevisionTranslation(ContentEntityInterface $entity, $langcode) {
|
||||
// Explicitly invalidate the cache for that node, as the call below is
|
||||
// statically cached.
|
||||
$this->storage->resetCache([$entity->id()]);
|
||||
$revision_id = $this->storage->getLatestTranslationAffectedRevisionId($entity->id(), $langcode);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
|
||||
$revision = $revision_id ? $this->storage->loadRevision($revision_id) : NULL;
|
||||
return $revision && $revision->hasTranslation($langcode) ? $revision->getTranslation($langcode) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edit URL for the specified entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity being edited.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The edit URL.
|
||||
*/
|
||||
protected function getEditUrl(ContentEntityInterface $entity) {
|
||||
if ($entity->access('update', $this->loggedInUser)) {
|
||||
$url = $entity->toUrl('edit-form');
|
||||
}
|
||||
else {
|
||||
$url = $entity->toUrl('drupal:content-translation-edit');
|
||||
$url->setRouteParameter('language', $entity->language()->getId());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delete translation URL for the specified entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity being edited.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The delete translation URL.
|
||||
*/
|
||||
protected function getDeleteUrl(ContentEntityInterface $entity) {
|
||||
if ($entity->access('delete', $this->loggedInUser)) {
|
||||
$url = $entity->toUrl('delete-form');
|
||||
}
|
||||
else {
|
||||
$url = $entity->toUrl('drupal:content-translation-delete');
|
||||
$url->setRouteParameter('language', $entity->language()->getId());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests that revision translation deletion is handled correctly.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationRevisionTranslationDeletionTest extends ContentTranslationPendingRevisionTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->enableContentModeration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that translation overview handles pending revisions correctly.
|
||||
*/
|
||||
public function testOverview() {
|
||||
$index = 1;
|
||||
$accounts = [
|
||||
$this->rootUser,
|
||||
$this->editor,
|
||||
$this->translator,
|
||||
];
|
||||
foreach ($accounts as $account) {
|
||||
$this->currentAccount = $account;
|
||||
$this->doTestOverview($index++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a test run.
|
||||
*
|
||||
* @param int $index
|
||||
* The test run index.
|
||||
*/
|
||||
public function doTestOverview($index) {
|
||||
$this->drupalLogin($this->currentAccount);
|
||||
|
||||
// Create a test node.
|
||||
$values = [
|
||||
'title' => "Test $index.1 EN",
|
||||
'moderation_state' => 'published',
|
||||
];
|
||||
$id = $this->createEntity($values, 'en');
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->storage->load($id);
|
||||
|
||||
// Add a draft translation and check that it is available only in the latest
|
||||
// revision.
|
||||
$add_translation_url = Url::fromRoute("entity.{$this->entityTypeId}.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $id,
|
||||
'source' => 'en',
|
||||
'target' => 'it',
|
||||
],
|
||||
[
|
||||
'language' => ConfigurableLanguage::load('it'),
|
||||
'absolute' => FALSE,
|
||||
]
|
||||
);
|
||||
$add_translation_href = $add_translation_url->toString();
|
||||
$this->drupalGet($add_translation_url);
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.2 IT",
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertFalse($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
|
||||
// Check that translations cannot be deleted in drafts.
|
||||
$overview_url = $entity->toUrl('drupal:content-translation-overview');
|
||||
$this->drupalGet($overview_url);
|
||||
$it_delete_url = $this->getDeleteUrl($it_revision);
|
||||
$it_delete_href = $it_delete_url->toString();
|
||||
$this->assertSession()->linkByHrefNotExists($it_delete_href);
|
||||
$warning = 'The "Delete translation" action is only available for published translations.';
|
||||
$this->assertSession()->pageTextContains($warning);
|
||||
$this->drupalGet($this->getEditUrl($it_revision));
|
||||
$this->assertSession()->buttonNotExists('Delete translation');
|
||||
|
||||
// Publish the translation and verify it can be deleted.
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.3 IT",
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertTrue($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefExists($it_delete_href);
|
||||
$this->assertSession()->pageTextNotContains($warning);
|
||||
$this->drupalGet($this->getEditUrl($it_revision));
|
||||
$this->assertSession()->buttonExists('Delete translation');
|
||||
|
||||
// Create an English draft and verify the published translation was
|
||||
// preserved.
|
||||
$this->drupalLogin($this->editor);
|
||||
$en_revision = $this->loadRevisionTranslation($entity, 'en');
|
||||
$this->drupalGet($this->getEditUrl($en_revision));
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.4 EN",
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertTrue($entity->hasTranslation('it'));
|
||||
$en_revision = $this->loadRevisionTranslation($entity, 'en');
|
||||
$this->assertTrue($en_revision->hasTranslation('it'));
|
||||
$this->drupalLogin($this->currentAccount);
|
||||
|
||||
// Delete the translation and verify that it is actually gone and that it is
|
||||
// possible to create it again.
|
||||
$this->drupalGet($it_delete_url);
|
||||
$this->drupalPostForm(NULL, [], 'Delete Italian translation');
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertFalse($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->wasDefaultRevision());
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
$this->assertTrue($it_revision->getRevisionId() < $entity->getRevisionId());
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefNotExists($this->getEditUrl($it_revision)->toString());
|
||||
$this->assertSession()->linkByHrefExists($add_translation_href);
|
||||
|
||||
// Publish the English draft and verify the translation is not accidentally
|
||||
// restored.
|
||||
$this->drupalLogin($this->editor);
|
||||
$en_revision = $this->loadRevisionTranslation($entity, 'en');
|
||||
$this->drupalGet($this->getEditUrl($en_revision));
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.6 EN",
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertFalse($entity->hasTranslation('it'));
|
||||
$this->drupalLogin($this->currentAccount);
|
||||
|
||||
// Create a published translation again and verify it could be deleted.
|
||||
$this->drupalGet($add_translation_url);
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.7 IT",
|
||||
'moderation_state[0][state]' => 'published',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertTrue($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefExists($it_delete_href);
|
||||
|
||||
// Create a translation draft again and verify it cannot be deleted.
|
||||
$this->drupalGet($this->getEditUrl($it_revision));
|
||||
$edit = [
|
||||
'title[0][value]' => "Test $index.8 IT",
|
||||
'moderation_state[0][state]' => 'draft',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertTrue($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefNotExists($it_delete_href);
|
||||
|
||||
// Delete the translation draft and verify the translation can be deleted
|
||||
// again, since the active revision is now a default revision.
|
||||
$this->drupalLogin($this->editor);
|
||||
$this->drupalGet($it_revision->toUrl('version-history'));
|
||||
$revision_deletion_url = Url::fromRoute('node.revision_delete_confirm', [
|
||||
'node' => $id,
|
||||
'node_revision' => $it_revision->getRevisionId(),
|
||||
],
|
||||
[
|
||||
'language' => ConfigurableLanguage::load('it'),
|
||||
'absolute' => FALSE,
|
||||
]
|
||||
);
|
||||
$revision_deletion_href = $revision_deletion_url->toString();
|
||||
$this->getSession()->getDriver()->click("//a[@href='$revision_deletion_href']");
|
||||
$this->drupalPostForm(NULL, [], 'Delete');
|
||||
$this->drupalLogin($this->currentAccount);
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefExists($it_delete_href);
|
||||
|
||||
// Verify that now the translation can be deleted.
|
||||
$this->drupalGet($it_delete_url);
|
||||
$this->drupalPostForm(NULL, [], 'Delete Italian translation');
|
||||
$entity = $this->storage->loadUnchanged($id);
|
||||
$this->assertFalse($entity->hasTranslation('it'));
|
||||
$it_revision = $this->loadRevisionTranslation($entity, 'it');
|
||||
$this->assertTrue($it_revision->wasDefaultRevision());
|
||||
$this->assertTrue($it_revision->hasTranslation('it'));
|
||||
$this->assertTrue($it_revision->getRevisionId() < $entity->getRevisionId());
|
||||
$this->drupalGet($overview_url);
|
||||
$this->assertSession()->linkByHrefNotExists($this->getEditUrl($it_revision)->toString());
|
||||
$this->assertSession()->linkByHrefExists($add_translation_href);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Core\Field\Entity\BaseFieldOverride;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\language\Entity\ContentLanguageSettings;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the content translation settings UI.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationSettingsTest extends BrowserTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'node', 'comment', 'field_ui', 'entity_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Set up two content types to test fields shared between different
|
||||
// bundles.
|
||||
$this->drupalCreateContentType(['type' => 'article']);
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->addDefaultCommentField('node', 'article', 'comment_article', CommentItemInterface::OPEN, 'comment_article');
|
||||
$this->addDefaultCommentField('node', 'page', 'comment_page');
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['access administration pages', 'administer languages', 'administer content translation', 'administer content types', 'administer node fields', 'administer comment fields', 'administer comments', 'administer comment types', 'administer account settings']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the settings UI works as expected.
|
||||
*/
|
||||
public function testSettingsUI() {
|
||||
// Check for the content_translation_menu_links_discovered_alter() changes.
|
||||
$this->drupalGet('admin/config');
|
||||
$this->assertLink('Content language and translation');
|
||||
$this->assertText('Configure language and translation support for content.');
|
||||
// Test that the translation settings are ignored if the bundle is marked
|
||||
// translatable but the entity type is not.
|
||||
$edit = ['settings[comment][comment_article][translatable]' => TRUE];
|
||||
$this->assertSettings('comment', NULL, FALSE, $edit);
|
||||
|
||||
// Test that the translation settings are ignored if only a field is marked
|
||||
// as translatable and not the related entity type and bundle.
|
||||
$edit = ['settings[comment][comment_article][fields][comment_body]' => TRUE];
|
||||
$this->assertSettings('comment', NULL, FALSE, $edit);
|
||||
|
||||
// Test that the translation settings are not stored if an entity type and
|
||||
// bundle are marked as translatable but no field is.
|
||||
$edit = [
|
||||
'entity_types[comment]' => TRUE,
|
||||
'settings[comment][comment_article][translatable]' => TRUE,
|
||||
// Base fields are translatable by default.
|
||||
'settings[comment][comment_article][fields][changed]' => FALSE,
|
||||
'settings[comment][comment_article][fields][created]' => FALSE,
|
||||
'settings[comment][comment_article][fields][homepage]' => FALSE,
|
||||
'settings[comment][comment_article][fields][hostname]' => FALSE,
|
||||
'settings[comment][comment_article][fields][mail]' => FALSE,
|
||||
'settings[comment][comment_article][fields][name]' => FALSE,
|
||||
'settings[comment][comment_article][fields][status]' => FALSE,
|
||||
'settings[comment][comment_article][fields][subject]' => FALSE,
|
||||
'settings[comment][comment_article][fields][uid]' => FALSE,
|
||||
];
|
||||
$this->assertSettings('comment', 'comment_article', FALSE, $edit);
|
||||
$xpath_err = '//div[contains(@class, "error")]';
|
||||
$this->assertTrue($this->xpath($xpath_err), 'Enabling translation only for entity bundles generates a form error.');
|
||||
|
||||
// Test that the translation settings are not stored if a non-configurable
|
||||
// language is set as default and the language selector is hidden.
|
||||
$edit = [
|
||||
'entity_types[comment]' => TRUE,
|
||||
'settings[comment][comment_article][settings][language][langcode]' => Language::LANGCODE_NOT_SPECIFIED,
|
||||
'settings[comment][comment_article][settings][language][language_alterable]' => FALSE,
|
||||
'settings[comment][comment_article][translatable]' => TRUE,
|
||||
'settings[comment][comment_article][fields][comment_body]' => TRUE,
|
||||
];
|
||||
$this->assertSettings('comment', 'comment_article', FALSE, $edit);
|
||||
$this->assertTrue($this->xpath($xpath_err), 'Enabling translation with a fixed non-configurable language generates a form error.');
|
||||
|
||||
// Test that a field shared among different bundles can be enabled without
|
||||
// needing to make all the related bundles translatable.
|
||||
$edit = [
|
||||
'entity_types[comment]' => TRUE,
|
||||
'settings[comment][comment_article][settings][language][langcode]' => 'current_interface',
|
||||
'settings[comment][comment_article][settings][language][language_alterable]' => TRUE,
|
||||
'settings[comment][comment_article][translatable]' => TRUE,
|
||||
'settings[comment][comment_article][fields][comment_body]' => TRUE,
|
||||
// Override both comment subject fields to untranslatable.
|
||||
'settings[comment][comment_article][fields][subject]' => FALSE,
|
||||
'settings[comment][comment][fields][subject]' => FALSE,
|
||||
];
|
||||
$this->assertSettings('comment', 'comment_article', TRUE, $edit);
|
||||
$definition = $this->entityManager()->getFieldDefinitions('comment', 'comment_article')['comment_body'];
|
||||
$this->assertTrue($definition->isTranslatable(), 'Article comment body is translatable.');
|
||||
$definition = $this->entityManager()->getFieldDefinitions('comment', 'comment_article')['subject'];
|
||||
$this->assertFalse($definition->isTranslatable(), 'Article comment subject is not translatable.');
|
||||
|
||||
$definition = $this->entityManager()->getFieldDefinitions('comment', 'comment')['comment_body'];
|
||||
$this->assertFalse($definition->isTranslatable(), 'Page comment body is not translatable.');
|
||||
$definition = $this->entityManager()->getFieldDefinitions('comment', 'comment')['subject'];
|
||||
$this->assertFalse($definition->isTranslatable(), 'Page comment subject is not translatable.');
|
||||
|
||||
// Test that translation can be enabled for base fields.
|
||||
$edit = [
|
||||
'entity_types[entity_test_mul]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][translatable]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][fields][name]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][fields][user_id]' => FALSE,
|
||||
];
|
||||
$this->assertSettings('entity_test_mul', 'entity_test_mul', TRUE, $edit);
|
||||
$field_override = BaseFieldOverride::loadByName('entity_test_mul', 'entity_test_mul', 'name');
|
||||
$this->assertTrue($field_override->isTranslatable(), 'Base fields can be overridden with a base field bundle override entity.');
|
||||
$definitions = $this->entityManager()->getFieldDefinitions('entity_test_mul', 'entity_test_mul');
|
||||
$this->assertTrue($definitions['name']->isTranslatable() && !$definitions['user_id']->isTranslatable(), 'Base field bundle overrides were correctly altered.');
|
||||
|
||||
// Test that language settings are correctly stored.
|
||||
$language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_article');
|
||||
$this->assertEqual($language_configuration->getDefaultLangcode(), 'current_interface', 'The default language for article comments is set to the interface text language selected for page.');
|
||||
$this->assertTrue($language_configuration->isLanguageAlterable(), 'The language selector for article comments is shown.');
|
||||
|
||||
// Verify language widget appears on comment type form.
|
||||
$this->drupalGet('admin/structure/comment/manage/comment_article');
|
||||
$this->assertField('language_configuration[content_translation]');
|
||||
$this->assertFieldChecked('edit-language-configuration-content-translation');
|
||||
|
||||
// Verify that translation may be enabled for the article content type.
|
||||
$edit = [
|
||||
'language_configuration[content_translation]' => TRUE,
|
||||
];
|
||||
// Make sure the checkbox is available and not checked by default.
|
||||
$this->drupalGet('admin/structure/types/manage/article');
|
||||
$this->assertField('language_configuration[content_translation]');
|
||||
$this->assertNoFieldChecked('edit-language-configuration-content-translation');
|
||||
$this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
|
||||
$this->drupalGet('admin/structure/types/manage/article');
|
||||
$this->assertFieldChecked('edit-language-configuration-content-translation');
|
||||
|
||||
// Test that the title field of nodes is available in the settings form.
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][article][settings][language][langcode]' => 'current_interface',
|
||||
'settings[node][article][settings][language][language_alterable]' => TRUE,
|
||||
'settings[node][article][translatable]' => TRUE,
|
||||
'settings[node][article][fields][title]' => TRUE,
|
||||
];
|
||||
$this->assertSettings('node', NULL, TRUE, $edit);
|
||||
|
||||
foreach ([TRUE, FALSE] as $translatable) {
|
||||
// Test that configurable field translatability is correctly switched.
|
||||
$edit = ['settings[node][article][fields][body]' => $translatable];
|
||||
$this->assertSettings('node', 'article', TRUE, $edit);
|
||||
$field = FieldConfig::loadByName('node', 'article', 'body');
|
||||
$definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'article');
|
||||
$this->assertEqual($definitions['body']->isTranslatable(), $translatable, 'Field translatability correctly switched.');
|
||||
$this->assertEqual($field->isTranslatable(), $definitions['body']->isTranslatable(), 'Configurable field translatability correctly switched.');
|
||||
|
||||
// Test that also the Field UI form behaves correctly.
|
||||
$translatable = !$translatable;
|
||||
$edit = ['translatable' => $translatable];
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.body', $edit, t('Save settings'));
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
$field = FieldConfig::loadByName('node', 'article', 'body');
|
||||
$definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'article');
|
||||
$this->assertEqual($definitions['body']->isTranslatable(), $translatable, 'Field translatability correctly switched.');
|
||||
$this->assertEqual($field->isTranslatable(), $definitions['body']->isTranslatable(), 'Configurable field translatability correctly switched.');
|
||||
}
|
||||
|
||||
// Test that the order of the language list is similar to other language
|
||||
// lists, such as in Views UI.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
|
||||
$expected_elements = [
|
||||
'site_default',
|
||||
'current_interface',
|
||||
'authors_default',
|
||||
'en',
|
||||
'und',
|
||||
'zxx',
|
||||
];
|
||||
$elements = $this->xpath('//select[@id="edit-settings-node-article-settings-language-langcode"]/option');
|
||||
// Compare values inside the option elements with expected values.
|
||||
for ($i = 0; $i < count($elements); $i++) {
|
||||
$this->assertEqual($elements[$i]->getValue(), $expected_elements[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the language settings checkbox on account settings page.
|
||||
*/
|
||||
public function testAccountLanguageSettingsUI() {
|
||||
// Make sure the checkbox is available and not checked by default.
|
||||
$this->drupalGet('admin/config/people/accounts');
|
||||
$this->assertField('language[content_translation]');
|
||||
$this->assertNoFieldChecked('edit-language-content-translation');
|
||||
|
||||
$edit = [
|
||||
'language[content_translation]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/people/accounts', $edit, t('Save configuration'));
|
||||
$this->drupalGet('admin/config/people/accounts');
|
||||
$this->assertFieldChecked('edit-language-content-translation');
|
||||
|
||||
// Make sure account settings can be saved.
|
||||
$this->drupalPostForm('admin/config/people/accounts', ['anonymous' => 'Save me please!'], 'Save configuration');
|
||||
$this->assertFieldByName('anonymous', 'Save me please!', 'Anonymous name has been changed.');
|
||||
$this->assertText('The configuration options have been saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that translatability has the expected value for the given bundle.
|
||||
*
|
||||
* @param string $entity_type
|
||||
* The entity type for which to check translatability.
|
||||
* @param string $bundle
|
||||
* The bundle for which to check translatability.
|
||||
* @param bool $enabled
|
||||
* TRUE if translatability should be enabled, FALSE otherwise.
|
||||
* @param array $edit
|
||||
* An array of values to submit to the content translation settings page.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertSettings($entity_type, $bundle, $enabled, $edit) {
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
$args = ['@entity_type' => $entity_type, '@bundle' => $bundle, '@enabled' => $enabled ? 'enabled' : 'disabled'];
|
||||
$message = format_string('Translation for entity @entity_type (@bundle) is @enabled.', $args);
|
||||
\Drupal::entityManager()->clearCachedDefinitions();
|
||||
return $this->assertEqual(\Drupal::service('content_translation.manager')->isEnabled($entity_type, $bundle), $enabled, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that field setting depends on bundle translatability.
|
||||
*/
|
||||
public function testFieldTranslatableSettingsUI() {
|
||||
// At least one field needs to be translatable to enable article for
|
||||
// translation. Create an extra field to be used for this purpose. We use
|
||||
// the UI to test our form alterations.
|
||||
$edit = [
|
||||
'new_storage_type' => 'text',
|
||||
'label' => 'Test',
|
||||
'field_name' => 'article_text',
|
||||
];
|
||||
$this->drupalPostForm('admin/structure/types/manage/article/fields/add-field', $edit, 'Save and continue');
|
||||
|
||||
// Tests that field doesn't have translatable setting if bundle is not
|
||||
// translatable.
|
||||
$path = 'admin/structure/types/manage/article/fields/node.article.field_article_text';
|
||||
$this->drupalGet($path);
|
||||
$this->assertFieldByXPath('//input[@id="edit-translatable" and @disabled="disabled"]');
|
||||
$this->assertText('To configure translation for this field, enable language support for this type.', 'No translatable setting for field.');
|
||||
|
||||
// Tests that field has translatable setting if bundle is translatable.
|
||||
// Note: this field is not translatable when enable bundle translatability.
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][article][settings][language][language_alterable]' => TRUE,
|
||||
'settings[node][article][translatable]' => TRUE,
|
||||
'settings[node][article][fields][field_article_text]' => TRUE,
|
||||
];
|
||||
$this->assertSettings('node', 'article', TRUE, $edit);
|
||||
$this->drupalGet($path);
|
||||
$this->assertFieldByXPath('//input[@id="edit-translatable" and not(@disabled) and @checked="checked"]');
|
||||
$this->assertNoText('To enable translation of this field, enable language support for this type.', 'Translatable setting for field available.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the translatable settings checkbox for untranslatable entities.
|
||||
*/
|
||||
public function testNonTranslatableTranslationSettingsUI() {
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertNoField('settings[entity_test][entity_test][translatable]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity manager.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityManagerInterface
|
||||
* The entity manager;
|
||||
*/
|
||||
protected function entityManager() {
|
||||
return $this->container->get('entity.manager');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests the field synchronization behavior for the image field.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationSyncImageTest extends ContentTranslationTestBase {
|
||||
|
||||
use TestFileCreationTrait {
|
||||
getTestFiles as drupalGetTestFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cardinality of the image field.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $cardinality;
|
||||
|
||||
/**
|
||||
* The test image files.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'entity_test', 'image', 'field_ui'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->files = $this->drupalGetTestFiles('image');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the test image field.
|
||||
*/
|
||||
protected function setupTestFields() {
|
||||
$this->fieldName = 'field_test_et_ui_image';
|
||||
$this->cardinality = 3;
|
||||
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'type' => 'image',
|
||||
'cardinality' => $this->cardinality,
|
||||
])->save();
|
||||
|
||||
FieldConfig::create([
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'field_name' => $this->fieldName,
|
||||
'bundle' => $this->entityTypeId,
|
||||
'label' => 'Test translatable image field',
|
||||
'third_party_settings' => [
|
||||
'content_translation' => [
|
||||
'translation_sync' => [
|
||||
'file' => FALSE,
|
||||
'alt' => 'alt',
|
||||
'title' => 'title',
|
||||
],
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditorPermissions() {
|
||||
// Every entity-type-specific test needs to define these.
|
||||
return ['administer entity_test_mul fields', 'administer languages', 'administer content translation'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image field field synchronization.
|
||||
*/
|
||||
public function testImageFieldSync() {
|
||||
// Check that the alt and title fields are enabled for the image field.
|
||||
$this->drupalLogin($this->editor);
|
||||
$this->drupalGet('entity_test_mul/structure/' . $this->entityTypeId . '/fields/' . $this->entityTypeId . '.' . $this->entityTypeId . '.' . $this->fieldName);
|
||||
$this->assertFieldChecked('edit-third-party-settings-content-translation-translation-sync-alt');
|
||||
$this->assertFieldChecked('edit-third-party-settings-content-translation-translation-sync-title');
|
||||
$edit = [
|
||||
'third_party_settings[content_translation][translation_sync][alt]' => FALSE,
|
||||
'third_party_settings[content_translation][translation_sync][title]' => FALSE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save settings'));
|
||||
|
||||
// Check that the content translation settings page reflects the changes
|
||||
// performed in the field edit page.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
|
||||
$this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
|
||||
$edit = [
|
||||
'settings[entity_test_mul][entity_test_mul][fields][field_test_et_ui_image]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][alt]' => TRUE,
|
||||
'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][title]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
|
||||
$errors = $this->xpath('//div[contains(@class, "messages--error")]');
|
||||
$this->assertFalse($errors, 'Settings correctly stored.');
|
||||
$this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
|
||||
$this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
|
||||
$this->drupalLogin($this->translator);
|
||||
|
||||
$default_langcode = $this->langcodes[0];
|
||||
$langcode = $this->langcodes[1];
|
||||
|
||||
// Populate the test entity with some random initial values.
|
||||
$values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'user_id' => mt_rand(1, 128),
|
||||
'langcode' => $default_langcode,
|
||||
];
|
||||
$entity = entity_create($this->entityTypeId, $values);
|
||||
|
||||
// Create some file entities from the generated test files and store them.
|
||||
$values = [];
|
||||
for ($delta = 0; $delta < $this->cardinality; $delta++) {
|
||||
// For the default language use the same order for files and field items.
|
||||
$index = $delta;
|
||||
|
||||
// Create the file entity for the image being processed and record its
|
||||
// identifier.
|
||||
$field_values = [
|
||||
'uri' => $this->files[$index]->uri,
|
||||
'uid' => \Drupal::currentUser()->id(),
|
||||
'status' => FILE_STATUS_PERMANENT,
|
||||
];
|
||||
$file = File::create($field_values);
|
||||
$file->save();
|
||||
$fid = $file->id();
|
||||
$this->files[$index]->fid = $fid;
|
||||
|
||||
// Generate the item for the current image file entity and attach it to
|
||||
// the entity.
|
||||
$item = [
|
||||
'target_id' => $fid,
|
||||
'alt' => $default_langcode . '_' . $fid . '_' . $this->randomMachineName(),
|
||||
'title' => $default_langcode . '_' . $fid . '_' . $this->randomMachineName(),
|
||||
];
|
||||
$entity->{$this->fieldName}[] = $item;
|
||||
|
||||
// Store the generated values keying them by fid for easier lookup.
|
||||
$values[$default_langcode][$fid] = $item;
|
||||
}
|
||||
$entity = $this->saveEntity($entity);
|
||||
|
||||
// Create some field translations for the test image field. The translated
|
||||
// items will be one less than the original values to check that only the
|
||||
// translated ones will be preserved. In fact we want the same fids and
|
||||
// items order for both languages.
|
||||
$translation = $entity->addTranslation($langcode);
|
||||
for ($delta = 0; $delta < $this->cardinality - 1; $delta++) {
|
||||
// Simulate a field reordering: items are shifted of one position ahead.
|
||||
// The modulo operator ensures we start from the beginning after reaching
|
||||
// the maximum allowed delta.
|
||||
$index = ($delta + 1) % $this->cardinality;
|
||||
|
||||
// Generate the item for the current image file entity and attach it to
|
||||
// the entity.
|
||||
$fid = $this->files[$index]->fid;
|
||||
$item = [
|
||||
'target_id' => $fid,
|
||||
'alt' => $langcode . '_' . $fid . '_' . $this->randomMachineName(),
|
||||
'title' => $langcode . '_' . $fid . '_' . $this->randomMachineName(),
|
||||
];
|
||||
$translation->{$this->fieldName}[] = $item;
|
||||
|
||||
// Again store the generated values keying them by fid for easier lookup.
|
||||
$values[$langcode][$fid] = $item;
|
||||
}
|
||||
|
||||
// Perform synchronization: the translation language is used as source,
|
||||
// while the default language is used as target.
|
||||
$this->manager->getTranslationMetadata($translation)->setSource($default_langcode);
|
||||
$entity = $this->saveEntity($translation);
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
|
||||
// Check that one value has been dropped from the original values.
|
||||
$assert = count($entity->{$this->fieldName}) == 2;
|
||||
$this->assertTrue($assert, 'One item correctly removed from the synchronized field values.');
|
||||
|
||||
// Check that fids have been synchronized and translatable column values
|
||||
// have been retained.
|
||||
$fids = [];
|
||||
foreach ($entity->{$this->fieldName} as $delta => $item) {
|
||||
$value = $values[$default_langcode][$item->target_id];
|
||||
$source_item = $translation->{$this->fieldName}->get($delta);
|
||||
$assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', ['@fid' => $item->target_id]));
|
||||
$fids[$item->target_id] = TRUE;
|
||||
}
|
||||
|
||||
// Check that the dropped value is the right one.
|
||||
$removed_fid = $this->files[0]->fid;
|
||||
$this->assertTrue(!isset($fids[$removed_fid]), format_string('Field item @fid has been correctly removed.', ['@fid' => $removed_fid]));
|
||||
|
||||
// Add back an item for the dropped value and perform synchronization again.
|
||||
$values[$langcode][$removed_fid] = [
|
||||
'target_id' => $removed_fid,
|
||||
'alt' => $langcode . '_' . $removed_fid . '_' . $this->randomMachineName(),
|
||||
'title' => $langcode . '_' . $removed_fid . '_' . $this->randomMachineName(),
|
||||
];
|
||||
$translation->{$this->fieldName}->setValue(array_values($values[$langcode]));
|
||||
$entity = $this->saveEntity($translation);
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
|
||||
// Check that the value has been added to the default language.
|
||||
$assert = count($entity->{$this->fieldName}->getValue()) == 3;
|
||||
$this->assertTrue($assert, 'One item correctly added to the synchronized field values.');
|
||||
|
||||
foreach ($entity->{$this->fieldName} as $delta => $item) {
|
||||
// When adding an item its value is copied over all the target languages,
|
||||
// thus in this case the source language needs to be used to check the
|
||||
// values instead of the target one.
|
||||
$fid_langcode = $item->target_id != $removed_fid ? $default_langcode : $langcode;
|
||||
$value = $values[$fid_langcode][$item->target_id];
|
||||
$source_item = $translation->{$this->fieldName}->get($delta);
|
||||
$assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
|
||||
$this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', ['@fid' => $item->target_id]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the passed entity and reloads it, enabling compatibility mode.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to be saved.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The saved entity.
|
||||
*/
|
||||
protected function saveEntity(EntityInterface $entity) {
|
||||
$entity->save();
|
||||
$entity = entity_test_mul_load($entity->id(), TRUE);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
@ -138,7 +139,7 @@ abstract class ContentTranslationTestBase extends BrowserTestBase {
|
|||
* Returns an array of permissions needed for the administrator.
|
||||
*/
|
||||
protected function getAdministratorPermissions() {
|
||||
return array_merge($this->getEditorPermissions(), $this->getTranslatorPermissions(), ['administer content translation']);
|
||||
return array_merge($this->getEditorPermissions(), $this->getTranslatorPermissions(), ['administer languages', 'administer content translation']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,4 +237,24 @@ abstract class ContentTranslationTestBase extends BrowserTestBase {
|
|||
return $entity->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edit URL for the specified entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
|
||||
* The entity being edited.
|
||||
*
|
||||
* @return \Drupal\Core\Url
|
||||
* The edit URL.
|
||||
*/
|
||||
protected function getEditUrl(ContentEntityInterface $entity) {
|
||||
if ($entity->access('update', $this->loggedInUser)) {
|
||||
$url = $entity->toUrl('edit-form');
|
||||
}
|
||||
else {
|
||||
$url = $entity->toUrl('drupal:content-translation-edit');
|
||||
$url->setRouteParameter('language', $entity->language()->getId());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class ContentTranslationUISkipTest extends BrowserTestBase {
|
|||
$admin_user = $this->drupalCreateUser([
|
||||
'translate any entity',
|
||||
'administer content translation',
|
||||
'administer languages'
|
||||
'administer languages',
|
||||
]);
|
||||
$this->drupalLogin($admin_user);
|
||||
// Visit the content translation.
|
||||
|
|
|
@ -10,8 +10,7 @@ use Drupal\Core\Language\Language;
|
|||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* Tests the Content Translation UI.
|
||||
|
@ -35,8 +34,7 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
protected $testLanguageSelector = TRUE;
|
||||
|
||||
/**
|
||||
* Flag that tells whether the HTML escaping of all languages works or not
|
||||
* after SafeMarkup change.
|
||||
* Flag to determine if "all languages" rendering is tested.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -111,12 +109,11 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $entity->id(),
|
||||
'source' => $default_langcode,
|
||||
'target' => $langcode
|
||||
'target' => $langcode,
|
||||
], ['language' => $language]);
|
||||
$this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode));
|
||||
|
||||
// Assert that HTML is escaped in "all languages" in UI after SafeMarkup
|
||||
// change.
|
||||
// Assert that HTML is not escaped unexpectedly.
|
||||
if ($this->testHTMLEscapeForAllLanguages) {
|
||||
$this->assertNoRaw('<span class="translation-entity-all-languages">(all languages)</span>');
|
||||
$this->assertRaw('<span class="translation-entity-all-languages">(all languages)</span>');
|
||||
|
@ -139,10 +136,10 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
$author_field_name = $entity->hasField('content_translation_uid') ? 'content_translation_uid' : 'uid';
|
||||
if ($entity->getFieldDefinition($author_field_name)->isTranslatable()) {
|
||||
$this->assertEqual($metadata_target_translation->getAuthor()->id(), $this->translator->id(),
|
||||
SafeMarkup::format('Author of the target translation @langcode correctly stored for translatable owner field.', ['@langcode' => $langcode]));
|
||||
new FormattableMarkup('Author of the target translation @langcode correctly stored for translatable owner field.', ['@langcode' => $langcode]));
|
||||
|
||||
$this->assertNotEqual($metadata_target_translation->getAuthor()->id(), $metadata_source_translation->getAuthor()->id(),
|
||||
SafeMarkup::format('Author of the target translation @target different from the author of the source translation @source for translatable owner field.',
|
||||
new FormattableMarkup('Author of the target translation @target different from the author of the source translation @source for translatable owner field.',
|
||||
['@target' => $langcode, '@source' => $default_langcode]));
|
||||
}
|
||||
else {
|
||||
|
@ -152,7 +149,7 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
$created_field_name = $entity->hasField('content_translation_created') ? 'content_translation_created' : 'created';
|
||||
if ($entity->getFieldDefinition($created_field_name)->isTranslatable()) {
|
||||
$this->assertTrue($metadata_target_translation->getCreatedTime() > $metadata_source_translation->getCreatedTime(),
|
||||
SafeMarkup::format('Translation creation timestamp of the target translation @target is newer than the creation timestamp of the source translation @source for translatable created field.',
|
||||
new FormattableMarkup('Translation creation timestamp of the target translation @target is newer than the creation timestamp of the source translation @source for translatable created field.',
|
||||
['@target' => $langcode, '@source' => $default_langcode]));
|
||||
}
|
||||
else {
|
||||
|
@ -176,7 +173,7 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $entity->id(),
|
||||
'source' => $default_langcode,
|
||||
'target' => $langcode
|
||||
'target' => $langcode,
|
||||
], ['language' => $language]);
|
||||
// This does not save anything, it merely reloads the form and fills in the
|
||||
// fields with the values from the different source language.
|
||||
|
@ -190,7 +187,7 @@ abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
|
|||
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $entity->id(),
|
||||
'source' => $source_langcode,
|
||||
'target' => $langcode
|
||||
'target' => $langcode,
|
||||
], ['language' => $language]);
|
||||
$this->drupalPostForm($add_url, $edit, $this->getFormSubmitActionForNewTranslation($entity, $langcode));
|
||||
$storage->resetCache([$this->entityId]);
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the untranslatable fields behaviors.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationUntranslatableFieldsTest extends ContentTranslationPendingRevisionTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['field_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Configure one field as untranslatable.
|
||||
$this->drupalLogin($this->administrator);
|
||||
$edit = [
|
||||
'settings[' . $this->entityTypeId . '][' . $this->bundle . '][fields][' . $this->fieldName . ']' => 0,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/content-language', $edit, 'Save configuration');
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
|
||||
$entity_field_manager = $this->container->get('entity_field.manager');
|
||||
$entity_field_manager->clearCachedFieldDefinitions();
|
||||
$definitions = $entity_field_manager->getFieldDefinitions($this->entityTypeId, $this->bundle);
|
||||
$this->assertFalse($definitions[$this->fieldName]->isTranslatable());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setupTestFields() {
|
||||
parent::setupTestFields();
|
||||
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'field_multilingual',
|
||||
'type' => 'test_field',
|
||||
'entity_type' => $this->entityTypeId,
|
||||
'cardinality' => 1,
|
||||
]);
|
||||
$field_storage->save();
|
||||
FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'bundle' => $this->bundle,
|
||||
'label' => 'Untranslatable-but-visible test field',
|
||||
'translatable' => FALSE,
|
||||
])->save();
|
||||
entity_get_form_display($this->entityTypeId, $this->bundle, 'default')
|
||||
->setComponent('field_multilingual', [
|
||||
'type' => 'test_field_widget_multilingual',
|
||||
])
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that hiding untranslatable field widgets works correctly.
|
||||
*/
|
||||
public function testHiddenWidgets() {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
|
||||
$entity_type_manager = $this->container->get('entity_type.manager');
|
||||
$id = $this->createEntity(['title' => $this->randomString()], 'en');
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $entity_type_manager
|
||||
->getStorage($this->entityTypeId)
|
||||
->load($id);
|
||||
|
||||
// Check that the untranslatable field widget is displayed on the edit form
|
||||
// and no translatability clue is displayed yet.
|
||||
$en_edit_url = $entity->toUrl('edit-form');
|
||||
$this->drupalGet($en_edit_url);
|
||||
$field_xpath = '//input[@name="' . $this->fieldName . '[0][value]"]';
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$clue_xpath = '//label[@for="edit-' . strtr($this->fieldName, '_', '-') . '-0-value"]/span[text()="(all languages)"]';
|
||||
$this->assertEmpty($this->xpath($clue_xpath));
|
||||
$this->assertSession()->pageTextContains('Untranslatable-but-visible test field');
|
||||
|
||||
// Add a translation and check that the untranslatable field widget is
|
||||
// displayed on the translation and edit forms along with translatability
|
||||
// clues.
|
||||
$add_url = Url::fromRoute("entity.{$this->entityTypeId}.content_translation_add", [
|
||||
$entity->getEntityTypeId() => $entity->id(),
|
||||
'source' => 'en',
|
||||
'target' => 'it',
|
||||
]);
|
||||
$this->drupalGet($add_url);
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertNotEmpty($this->xpath($clue_xpath));
|
||||
$this->assertSession()->pageTextContains('Untranslatable-but-visible test field');
|
||||
$this->drupalPostForm(NULL, [], 'Save');
|
||||
|
||||
// Check that the widget is displayed along with its clue in the edit form
|
||||
// for both languages.
|
||||
$this->drupalGet($en_edit_url);
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertNotEmpty($this->xpath($clue_xpath));
|
||||
$it_edit_url = $entity->toUrl('edit-form', ['language' => ConfigurableLanguage::load('it')]);
|
||||
$this->drupalGet($it_edit_url);
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertNotEmpty($this->xpath($clue_xpath));
|
||||
|
||||
// Configure untranslatable field widgets to be hidden on non-default
|
||||
// language edit forms.
|
||||
$settings_key = 'settings[' . $this->entityTypeId . '][' . $this->bundle . '][settings][content_translation][untranslatable_fields_hide]';
|
||||
$settings_url = 'admin/config/regional/content-language';
|
||||
$this->drupalPostForm($settings_url, [$settings_key => 1], 'Save configuration');
|
||||
|
||||
// Verify that the widget is displayed in the default language edit form,
|
||||
// but no clue is displayed.
|
||||
$this->drupalGet($en_edit_url);
|
||||
$field_xpath = '//input[@name="' . $this->fieldName . '[0][value]"]';
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertEmpty($this->xpath($clue_xpath));
|
||||
$this->assertSession()->pageTextContains('Untranslatable-but-visible test field');
|
||||
|
||||
// Verify no widget is displayed on the non-default language edit form.
|
||||
$this->drupalGet($it_edit_url);
|
||||
$this->assertEmpty($this->xpath($field_xpath));
|
||||
$this->assertEmpty($this->xpath($clue_xpath));
|
||||
$this->assertSession()->pageTextContains('Untranslatable-but-visible test field');
|
||||
|
||||
// Verify a warning is displayed.
|
||||
$this->assertSession()->pageTextContains('Fields that apply to all languages are hidden to avoid conflicting changes.');
|
||||
$edit_path = $entity->toUrl('edit-form')->toString();
|
||||
$link_xpath = '//a[@href=:edit_path and text()="Edit them on the original language form"]';
|
||||
$elements = $this->xpath($link_xpath, [':edit_path' => $edit_path]);
|
||||
$this->assertNotEmpty($elements);
|
||||
|
||||
// Configure untranslatable field widgets to be displayed on non-default
|
||||
// language edit forms.
|
||||
$this->drupalPostForm($settings_url, [$settings_key => 0], 'Save configuration');
|
||||
|
||||
// Check that the widget is displayed along with its clue in the edit form
|
||||
// for both languages.
|
||||
$this->drupalGet($en_edit_url);
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertNotEmpty($this->xpath($clue_xpath));
|
||||
$this->drupalGet($it_edit_url);
|
||||
$this->assertNotEmpty($this->xpath($field_xpath));
|
||||
$this->assertNotEmpty($this->xpath($clue_xpath));
|
||||
|
||||
// Enable content moderation and verify that widgets are hidden despite them
|
||||
// being configured to be displayed.
|
||||
$this->enableContentModeration();
|
||||
$this->drupalGet($it_edit_url);
|
||||
$this->assertEmpty($this->xpath($field_xpath));
|
||||
$this->assertEmpty($this->xpath($clue_xpath));
|
||||
|
||||
// Verify a warning is displayed.
|
||||
$this->assertSession()->pageTextContains('Fields that apply to all languages are hidden to avoid conflicting changes.');
|
||||
$elements = $this->xpath($link_xpath, [':edit_path' => $edit_path]);
|
||||
$this->assertNotEmpty($elements);
|
||||
|
||||
// Verify that checkboxes on the language content settings page are checked
|
||||
// and disabled for moderated bundles.
|
||||
$this->drupalGet($settings_url);
|
||||
$input_xpath = '//input[@name="settings[' . $this->entityTypeId . '][' . $this->bundle . '][settings][content_translation][untranslatable_fields_hide]" and @value=1 and @disabled="disabled"]';
|
||||
$elements = $this->xpath($input_xpath);
|
||||
$this->assertNotEmpty($elements);
|
||||
$this->drupalPostForm(NULL, [$settings_key => 0], 'Save configuration');
|
||||
$elements = $this->xpath($input_xpath);
|
||||
$this->assertNotEmpty($elements);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Tests the content translation workflows for the test entity.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationWorkflowsTest extends ContentTranslationTestBase {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* The entity used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'content_translation', 'entity_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->setupEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTranslatorPermissions() {
|
||||
$permissions = parent::getTranslatorPermissions();
|
||||
$permissions[] = 'view test entity';
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditorPermissions() {
|
||||
return ['administer entity_test content'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test entity and translate it.
|
||||
*/
|
||||
protected function setupEntity() {
|
||||
$default_langcode = $this->langcodes[0];
|
||||
|
||||
// Create a test entity.
|
||||
$user = $this->drupalCreateUser();
|
||||
$values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'user_id' => $user->id(),
|
||||
$this->fieldName => [['value' => $this->randomMachineName(16)]],
|
||||
];
|
||||
$id = $this->createEntity($values, $default_langcode);
|
||||
$storage = $this->container->get('entity_type.manager')
|
||||
->getStorage($this->entityTypeId);
|
||||
$storage->resetCache([$id]);
|
||||
$this->entity = $storage->load($id);
|
||||
|
||||
// Create a translation.
|
||||
$this->drupalLogin($this->translator);
|
||||
$add_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_add", [$this->entityTypeId => $this->entity->id(), 'source' => $default_langcode, 'target' => $this->langcodes[2]]);
|
||||
$this->drupalPostForm($add_translation_url, [], t('Save'));
|
||||
$this->rebuildContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test simple and editorial translation workflows.
|
||||
*/
|
||||
public function testWorkflows() {
|
||||
// Test workflows for the editor.
|
||||
$expected_status = [
|
||||
'edit' => 200,
|
||||
'delete' => 200,
|
||||
'overview' => 403,
|
||||
'add_translation' => 403,
|
||||
'edit_translation' => 403,
|
||||
'delete_translation' => 403,
|
||||
];
|
||||
$this->doTestWorkflows($this->editor, $expected_status);
|
||||
|
||||
// Test workflows for the translator.
|
||||
$expected_status = [
|
||||
'edit' => 403,
|
||||
'delete' => 403,
|
||||
'overview' => 200,
|
||||
'add_translation' => 200,
|
||||
'edit_translation' => 200,
|
||||
'delete_translation' => 200,
|
||||
];
|
||||
$this->doTestWorkflows($this->translator, $expected_status);
|
||||
|
||||
// Test workflows for the admin.
|
||||
$expected_status = [
|
||||
'edit' => 200,
|
||||
'delete' => 200,
|
||||
'overview' => 200,
|
||||
'add_translation' => 200,
|
||||
'edit_translation' => 403,
|
||||
'delete_translation' => 403,
|
||||
];
|
||||
$this->doTestWorkflows($this->administrator, $expected_status);
|
||||
|
||||
// Check that translation permissions allow the associated operations.
|
||||
$ops = ['create' => t('Add'), 'update' => t('Edit'), 'delete' => t('Delete')];
|
||||
$translations_url = $this->entity->urlInfo('drupal:content-translation-overview');
|
||||
foreach ($ops as $current_op => $item) {
|
||||
$user = $this->drupalCreateUser([$this->getTranslatePermission(), "$current_op content translations", 'view test entity']);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet($translations_url);
|
||||
|
||||
// Make sure that the user.permissions cache context and the cache tags
|
||||
// for the entity are present.
|
||||
$this->assertCacheContext('user.permissions');
|
||||
foreach ($this->entity->getCacheTags() as $cache_tag) {
|
||||
$this->assertCacheTag($cache_tag);
|
||||
}
|
||||
|
||||
foreach ($ops as $op => $label) {
|
||||
if ($op != $current_op) {
|
||||
$this->assertNoLink($label, format_string('No %op link found.', ['%op' => $label]));
|
||||
}
|
||||
else {
|
||||
$this->assertLink($label, 0, format_string('%op link found.', ['%op' => $label]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that workflows have the expected behaviors for the given user.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user to test the workflow behavior against.
|
||||
* @param array $expected_status
|
||||
* The an associative array with the operation name as key and the expected
|
||||
* status as value.
|
||||
*/
|
||||
protected function doTestWorkflows(UserInterface $user, $expected_status) {
|
||||
$default_langcode = $this->langcodes[0];
|
||||
$languages = $this->container->get('language_manager')->getLanguages();
|
||||
$args = ['@user_label' => $user->getUsername()];
|
||||
$options = ['language' => $languages[$default_langcode], 'absolute' => TRUE];
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Check whether the user is allowed to access the entity form in edit mode.
|
||||
$edit_url = $this->entity->urlInfo('edit-form', $options);
|
||||
$this->drupalGet($edit_url, $options);
|
||||
$this->assertResponse($expected_status['edit'], new FormattableMarkup('The @user_label has the expected edit access.', $args));
|
||||
|
||||
// Check whether the user is allowed to access the entity delete form.
|
||||
$delete_url = $this->entity->urlInfo('delete-form', $options);
|
||||
$this->drupalGet($delete_url, $options);
|
||||
$this->assertResponse($expected_status['delete'], new FormattableMarkup('The @user_label has the expected delete access.', $args));
|
||||
|
||||
// Check whether the user is allowed to access the translation overview.
|
||||
$langcode = $this->langcodes[1];
|
||||
$options['language'] = $languages[$langcode];
|
||||
$translations_url = $this->entity->url('drupal:content-translation-overview', $options);
|
||||
$this->drupalGet($translations_url);
|
||||
$this->assertResponse($expected_status['overview'], new FormattableMarkup('The @user_label has the expected translation overview access.', $args));
|
||||
|
||||
// Check whether the user is allowed to create a translation.
|
||||
$add_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_add", [$this->entityTypeId => $this->entity->id(), 'source' => $default_langcode, 'target' => $langcode], $options);
|
||||
if ($expected_status['add_translation'] == 200) {
|
||||
$this->clickLink('Add');
|
||||
$this->assertUrl($add_translation_url->toString(), [], 'The translation overview points to the translation form when creating translations.');
|
||||
// Check that the translation form does not contain shared elements for
|
||||
// translators.
|
||||
if ($expected_status['edit'] == 403) {
|
||||
$this->assertNoSharedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->drupalGet($add_translation_url);
|
||||
}
|
||||
$this->assertResponse($expected_status['add_translation'], new FormattableMarkup('The @user_label has the expected translation creation access.', $args));
|
||||
|
||||
// Check whether the user is allowed to edit a translation.
|
||||
$langcode = $this->langcodes[2];
|
||||
$options['language'] = $languages[$langcode];
|
||||
$edit_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_edit", [$this->entityTypeId => $this->entity->id(), 'language' => $langcode], $options);
|
||||
if ($expected_status['edit_translation'] == 200) {
|
||||
$this->drupalGet($translations_url);
|
||||
$editor = $expected_status['edit'] == 200;
|
||||
|
||||
if ($editor) {
|
||||
$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.');
|
||||
}
|
||||
else {
|
||||
$this->clickLink('Edit');
|
||||
// While a translator should be pointed to the translation form.
|
||||
$this->assertUrl($edit_translation_url->toString(), [], 'The translation overview points to the translation form for translators when editing translations.');
|
||||
// Check that the translation form does not contain shared elements.
|
||||
$this->assertNoSharedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->drupalGet($edit_translation_url);
|
||||
}
|
||||
$this->assertResponse($expected_status['edit_translation'], new FormattableMarkup('The @user_label has the expected translation edit access.', $args));
|
||||
|
||||
// Check whether the user is allowed to delete a translation.
|
||||
$langcode = $this->langcodes[2];
|
||||
$options['language'] = $languages[$langcode];
|
||||
$delete_translation_url = Url::fromRoute("entity.$this->entityTypeId.content_translation_delete", [$this->entityTypeId => $this->entity->id(), 'language' => $langcode], $options);
|
||||
if ($expected_status['delete_translation'] == 200) {
|
||||
$this->drupalGet($translations_url);
|
||||
$editor = $expected_status['delete'] == 200;
|
||||
|
||||
if ($editor) {
|
||||
$this->clickLink('Delete', 2);
|
||||
// An editor should be pointed to the entity deletion form in
|
||||
// multilingual mode. We need a new expected delete path with a new
|
||||
// language.
|
||||
$expected_delete_path = $this->entity->url('delete-form', $options);
|
||||
$this->assertUrl($expected_delete_path, [], 'The translation overview points to the delete form for editors when deleting translations.');
|
||||
}
|
||||
else {
|
||||
$this->clickLink('Delete');
|
||||
// While a translator should be pointed to the translation deletion
|
||||
// form.
|
||||
$this->assertUrl($delete_translation_url->toString(), [], 'The translation overview points to the translation deletion form for translators when deleting translations.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->drupalGet($delete_translation_url);
|
||||
}
|
||||
$this->assertResponse($expected_status['delete_translation'], new FormattableMarkup('The @user_label has the expected translation deletion access.', $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current page does not contain shared form elements.
|
||||
*/
|
||||
protected function assertNoSharedElements() {
|
||||
$language_none = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
return $this->assertNoFieldByXPath("//input[@name='field_test_text[$language_none][0][value]']", NULL, 'Shared elements are not available on the translation form.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional\Update;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait;
|
||||
|
||||
/**
|
||||
* Tests the upgrade path for the Content Translation module.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
*/
|
||||
class ContentTranslationUpdateTest extends UpdatePathTestBase {
|
||||
|
||||
use EntityDefinitionTestTrait;
|
||||
|
||||
/**
|
||||
* The database connection used.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The entity definition update manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
|
||||
*/
|
||||
protected $entityDefinitionUpdateManager;
|
||||
|
||||
/**
|
||||
* The entity manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The state service.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->database = \Drupal::database();
|
||||
$this->entityDefinitionUpdateManager = \Drupal::entityDefinitionUpdateManager();
|
||||
$this->entityManager = \Drupal::entityManager();
|
||||
$this->state = \Drupal::state();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.0.0-rc1-filled.standard.entity_test_update_mul.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that initial values for metadata fields are populated correctly.
|
||||
*/
|
||||
public function testContentTranslationUpdate8400() {
|
||||
$this->updateEntityTypeToTranslatable();
|
||||
|
||||
// The test database dump contains NULL values for
|
||||
// 'content_translation_source', 'content_translation_outdated' and
|
||||
// 'content_translation_status' for the first 50 test entities.
|
||||
// @see _entity_test_update_create_test_entities()
|
||||
$first_entity_record = $this->database->select('entity_test_update_data', 'etud')
|
||||
->fields('etud')
|
||||
->condition('etud.id', 1)
|
||||
->execute()
|
||||
->fetchAllAssoc('id');
|
||||
$this->assertNull($first_entity_record[1]->content_translation_source);
|
||||
$this->assertNull($first_entity_record[1]->content_translation_outdated);
|
||||
$this->assertNull($first_entity_record[1]->content_translation_status);
|
||||
|
||||
$this->runUpdates();
|
||||
|
||||
// After running the updates, all those fields should be populated with
|
||||
// their default values.
|
||||
$first_entity_record = $this->database->select('entity_test_update_data', 'etud')
|
||||
->fields('etud')
|
||||
->condition('etud.id', 1)
|
||||
->execute()
|
||||
->fetchAllAssoc('id');
|
||||
$this->assertEqual(LanguageInterface::LANGCODE_NOT_SPECIFIED, $first_entity_record[1]->content_translation_source);
|
||||
$this->assertEqual(0, $first_entity_record[1]->content_translation_outdated);
|
||||
$this->assertEqual(1, $first_entity_record[1]->content_translation_status);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional\Views;
|
||||
|
||||
use Drupal\Tests\views_ui\Functional\UITestBase;
|
||||
|
||||
/**
|
||||
* Tests the views UI when content_translation is enabled.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationViewsUITest extends UITestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_view'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['content_translation'];
|
||||
|
||||
/**
|
||||
* Tests the views UI.
|
||||
*/
|
||||
public function testViewsUI() {
|
||||
$this->drupalGet('admin/structure/views/view/test_view/edit');
|
||||
$this->assertTitle(t('@label (@table) | @site-name', ['@label' => 'Test view', '@table' => 'Views test data', '@site-name' => $this->config('system.site')->get('name')]));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Functional\Views;
|
||||
|
||||
use Drupal\Tests\content_translation\Functional\ContentTranslationTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests the content translation overview link field handler.
|
||||
*
|
||||
* @group content_translation
|
||||
* @see \Drupal\content_translation\Plugin\views\field\TranslationLink
|
||||
*/
|
||||
class TranslationLinkTest extends ContentTranslationTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_entity_translations_link'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['content_translation_test_views'];
|
||||
|
||||
protected function setUp() {
|
||||
// @todo Use entity_type once it is has multilingual Views integration.
|
||||
$this->entityTypeId = 'user';
|
||||
|
||||
parent::setUp();
|
||||
|
||||
// Assign user 1 a language code so that the entity can be translated.
|
||||
$user = User::load(1);
|
||||
$user->langcode = 'en';
|
||||
$user->save();
|
||||
|
||||
// Assign user 2 LANGCODE_NOT_SPECIFIED code so entity can't be translated.
|
||||
$user = User::load(2);
|
||||
$user->langcode = Language::LANGCODE_NOT_SPECIFIED;
|
||||
$user->save();
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['content_translation_test_views']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTranslatorPermissions() {
|
||||
$permissions = parent::getTranslatorPermissions();
|
||||
$permissions[] = 'access user profiles';
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the content translation overview link field handler.
|
||||
*/
|
||||
public function testTranslationLink() {
|
||||
$this->drupalGet('test-entity-translations-link');
|
||||
$this->assertLinkByHref('user/1/translations');
|
||||
$this->assertNoLinkByHref('user/2/translations', 'The translations link is not present when content_translation_translate_access() is FALSE.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests that contextual links are available for content translation.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationContextualLinksTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* The 'translator' user to use during testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['content_translation', 'contextual', 'node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Set up an additional language.
|
||||
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||
|
||||
// Create a content type.
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
|
||||
// Enable content translation.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$edit = [
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][page][translatable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Create a translator user.
|
||||
$permissions = [
|
||||
'access contextual links',
|
||||
'administer nodes',
|
||||
'edit any page content',
|
||||
'translate any entity',
|
||||
];
|
||||
$this->translator = $this->drupalCreateUser($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a contextual link is available for translating a node.
|
||||
*/
|
||||
public function testContentTranslationContextualLinks() {
|
||||
$node = $this->drupalCreateNode(['type' => 'page', 'title' => 'Test']);
|
||||
|
||||
// Check that the translate link appears on the node page.
|
||||
$this->drupalLogin($this->translator);
|
||||
$this->drupalGet('node/' . $node->id());
|
||||
$link = $this->assertSession()->waitForElement('css', '[data-contextual-id^="node:node=1"] .contextual-links a:contains("Translate")');
|
||||
$this->assertContains('node/1/translations', $link->getAttribute('href'));
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,7 @@ class ContentTranslationConfigImportTest extends KernelTestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig(['system']);
|
||||
$this->installEntitySchema('entity_test_mul');
|
||||
$this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
|
||||
|
||||
|
@ -74,7 +75,7 @@ class ContentTranslationConfigImportTest extends KernelTestBase {
|
|||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [
|
||||
'module' => ['content_translation']
|
||||
'module' => ['content_translation'],
|
||||
],
|
||||
'id' => $config_id,
|
||||
'target_entity_type_id' => 'entity_test_mul',
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\entity_test\Entity\EntityTestMul;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the Content Translation bundle info logic.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationEntityBundleInfoTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user', 'language', 'content_translation_test', 'content_translation', 'entity_test'];
|
||||
|
||||
/**
|
||||
* The content translation manager.
|
||||
*
|
||||
* @var \Drupal\content_translation\ContentTranslationManagerInterface
|
||||
*/
|
||||
protected $contentTranslationManager;
|
||||
|
||||
/**
|
||||
* The bundle info service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfo
|
||||
*/
|
||||
protected $bundleInfo;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->contentTranslationManager = $this->container->get('content_translation.manager');
|
||||
$this->bundleInfo = $this->container->get('entity_type.bundle.info');
|
||||
|
||||
$this->installEntitySchema('entity_test_mul');
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that modules can know whether bundles are translatable.
|
||||
*/
|
||||
public function testHookInvocationOrder() {
|
||||
$this->contentTranslationManager->setEnabled('entity_test_mul', 'entity_test_mul', TRUE);
|
||||
$this->bundleInfo->clearCachedBundles();
|
||||
$this->bundleInfo->getAllBundleInfo();
|
||||
|
||||
// Verify that the test module comes first in the module list, which would
|
||||
// normally make its hook implementation to be invoked first.
|
||||
/** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
|
||||
$module_handler = $this->container->get('module_handler');
|
||||
$module_list = $module_handler->getModuleList();
|
||||
$expected_modules = [
|
||||
'content_translation_test',
|
||||
'content_translation',
|
||||
];
|
||||
$actual_modules = array_keys(array_intersect_key($module_list, array_flip($expected_modules)));
|
||||
$this->assertEquals($expected_modules, $actual_modules);
|
||||
|
||||
// Check that the "content_translation_test" hook implementation has access
|
||||
// to the "translatable" bundle info property.
|
||||
/** @var \Drupal\Core\State\StateInterface $state */
|
||||
$state = $this->container->get('state');
|
||||
$this->assertTrue($state->get('content_translation_test.translatable'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that field synchronization is skipped for disabled bundles.
|
||||
*/
|
||||
public function testFieldSynchronizationWithDisabledBundle() {
|
||||
$entity = EntityTestMul::create();
|
||||
$entity->save();
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $translation */
|
||||
$translation = $entity->addTranslation('it');
|
||||
$translation->save();
|
||||
|
||||
$this->assertTrue($entity->isTranslatable());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,482 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Kernel;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityConstraintViolationListInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests the field synchronization logic when revisions are involved.
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class ContentTranslationFieldSyncRevisionTest extends EntityKernelTestBase {
|
||||
|
||||
use TestFileCreationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['file', 'image', 'language', 'content_translation', 'simpletest', 'content_translation_test'];
|
||||
|
||||
/**
|
||||
* The synchronized field name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName = 'sync_field';
|
||||
|
||||
/**
|
||||
* The content translation manager.
|
||||
*
|
||||
* @var \Drupal\content_translation\ContentTranslationManagerInterface|\Drupal\content_translation\BundleTranslationSettingsInterface
|
||||
*/
|
||||
protected $contentTranslationManager;
|
||||
|
||||
/**
|
||||
* The test entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$entity_type_id = 'entity_test_mulrev';
|
||||
$this->installEntitySchema($entity_type_id);
|
||||
$this->installEntitySchema('file');
|
||||
$this->installSchema('file', ['file_usage']);
|
||||
|
||||
ConfigurableLanguage::createFromLangcode('it')->save();
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
/** @var \Drupal\field\Entity\FieldStorageConfig $field_storage */
|
||||
$field_storage_config = FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'type' => 'image',
|
||||
'entity_type' => $entity_type_id,
|
||||
'cardinality' => 1,
|
||||
'translatable' => 1,
|
||||
]);
|
||||
$field_storage_config->save();
|
||||
|
||||
$field_config = FieldConfig::create([
|
||||
'entity_type' => $entity_type_id,
|
||||
'field_name' => $this->fieldName,
|
||||
'bundle' => $entity_type_id,
|
||||
'label' => 'Synchronized field',
|
||||
'translatable' => 1,
|
||||
]);
|
||||
$field_config->save();
|
||||
|
||||
$property_settings = [
|
||||
'alt' => 'alt',
|
||||
'title' => 'title',
|
||||
'file' => 0,
|
||||
];
|
||||
$field_config->setThirdPartySetting('content_translation', 'translation_sync', $property_settings);
|
||||
$field_config->save();
|
||||
|
||||
$this->entityManager->clearCachedDefinitions();
|
||||
|
||||
$this->contentTranslationManager = $this->container->get('content_translation.manager');
|
||||
$this->contentTranslationManager->setEnabled($entity_type_id, $entity_type_id, TRUE);
|
||||
|
||||
$this->storage = $this->entityManager->getStorage($entity_type_id);
|
||||
|
||||
foreach ($this->getTestFiles('image') as $file) {
|
||||
$entity = File::create((array) $file + ['status' => 1]);
|
||||
$entity->save();
|
||||
}
|
||||
|
||||
$this->state->set('content_translation.entity_access.file', ['view' => TRUE]);
|
||||
|
||||
$account = User::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'status' => 1,
|
||||
]);
|
||||
$account->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that field synchronization works as expected with revisions.
|
||||
*
|
||||
* @covers \Drupal\content_translation\Plugin\Validation\Constraint\ContentTranslationSynchronizedFieldsConstraintValidator::create
|
||||
* @covers \Drupal\content_translation\Plugin\Validation\Constraint\ContentTranslationSynchronizedFieldsConstraintValidator::validate
|
||||
* @covers \Drupal\content_translation\Plugin\Validation\Constraint\ContentTranslationSynchronizedFieldsConstraintValidator::hasSynchronizedPropertyChanges
|
||||
* @covers \Drupal\content_translation\FieldTranslationSynchronizer::getFieldSynchronizedProperties
|
||||
* @covers \Drupal\content_translation\FieldTranslationSynchronizer::synchronizeFields
|
||||
* @covers \Drupal\content_translation\FieldTranslationSynchronizer::synchronizeItems
|
||||
*/
|
||||
public function testFieldSynchronizationAndValidation() {
|
||||
// Test that when untranslatable field widgets are displayed, synchronized
|
||||
// field properties can be changed only in default revisions.
|
||||
$this->setUntranslatableFieldWidgetsDisplay(TRUE);
|
||||
$entity = $this->saveNewEntity();
|
||||
$entity_id = $entity->id();
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [1, 1, 1, 'Alt 1 EN']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
|
||||
$en_revision = $this->createRevision($entity, FALSE);
|
||||
$en_revision->get($this->fieldName)->target_id = 2;
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
|
||||
$it_translation = $entity->addTranslation('it', $entity->toArray());
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
|
||||
$it_revision = $this->createRevision($it_translation, FALSE);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->target_id = 2;
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 2 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
$it_revision->isDefaultRevision(TRUE);
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [2, 2, 2, 'Alt 1 EN', 'Alt 2 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($en_revision, FALSE);
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 3 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [3, 2, 2, 'Alt 3 EN', 'Alt 2 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision, FALSE);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 4 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [4, 2, 2, 'Alt 1 EN', 'Alt 4 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($en_revision);
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 5 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [5, 2, 2, 'Alt 5 EN', 'Alt 2 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($en_revision);
|
||||
$en_revision->get($this->fieldName)->target_id = 6;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 6 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [6, 6, 6, 'Alt 6 EN', 'Alt 2 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 7 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [7, 6, 6, 'Alt 6 EN', 'Alt 7 IT']);
|
||||
|
||||
// Test that when untranslatable field widgets are hidden, synchronized
|
||||
// field properties can be changed only when editing the default
|
||||
// translation. This may lead to temporarily desynchronized values, when
|
||||
// saving a pending revision for the default translation that changes a
|
||||
// synchronized property (see revision 11).
|
||||
$this->setUntranslatableFieldWidgetsDisplay(FALSE);
|
||||
$entity = $this->saveNewEntity();
|
||||
$entity_id = $entity->id();
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [8, 1, 1, 'Alt 1 EN']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
|
||||
$en_revision = $this->createRevision($entity, FALSE);
|
||||
$en_revision->get($this->fieldName)->target_id = 2;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 2 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [9, 2, 2, 'Alt 2 EN']);
|
||||
|
||||
$it_translation = $entity->addTranslation('it', $entity->toArray());
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
|
||||
$it_revision = $this->createRevision($it_translation, FALSE);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->target_id = 3;
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
$it_revision->isDefaultRevision(TRUE);
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
|
||||
$it_revision = $this->createRevision($it_translation);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 3 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [10, 1, 1, 'Alt 1 EN', 'Alt 3 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($en_revision, FALSE);
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 4 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [11, 2, 1, 'Alt 4 EN', 'Alt 3 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision, FALSE);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 5 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [12, 1, 1, 'Alt 1 EN', 'Alt 5 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($en_revision);
|
||||
$en_revision->get($this->fieldName)->target_id = 6;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 6 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [13, 6, 6, 'Alt 6 EN', 'Alt 3 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision);
|
||||
$it_revision->get($this->fieldName)->target_id = 7;
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 7 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [14, 6, 6, 'Alt 6 EN', 'Alt 7 IT']);
|
||||
|
||||
// Test that creating a default revision starting from a pending revision
|
||||
// having changes to synchronized properties, without introducing new
|
||||
// changes works properly.
|
||||
$this->setUntranslatableFieldWidgetsDisplay(FALSE);
|
||||
$entity = $this->saveNewEntity();
|
||||
$entity_id = $entity->id();
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [15, 1, 1, 'Alt 1 EN']);
|
||||
|
||||
$it_translation = $entity->addTranslation('it', $entity->toArray());
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
|
||||
$it_revision = $this->createRevision($it_translation);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 2 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [16, 1, 1, 'Alt 1 EN', 'Alt 2 IT']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
|
||||
$en_revision = $this->createRevision($entity);
|
||||
$en_revision->get($this->fieldName)->target_id = 3;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 3 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [17, 3, 3, 'Alt 3 EN', 'Alt 2 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($entity, FALSE);
|
||||
$en_revision->get($this->fieldName)->target_id = 4;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 4 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [18, 4, 3, 'Alt 4 EN', 'Alt 2 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($entity);
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [19, 4, 4, 'Alt 4 EN', 'Alt 2 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 6 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [20, 4, 4, 'Alt 4 EN', 'Alt 6 IT']);
|
||||
|
||||
// Check that we are not allowed to perform changes to multiple translations
|
||||
// in pending revisions when synchronized properties are involved.
|
||||
$this->setUntranslatableFieldWidgetsDisplay(FALSE);
|
||||
$entity = $this->saveNewEntity();
|
||||
$entity_id = $entity->id();
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [21, 1, 1, 'Alt 1 EN']);
|
||||
|
||||
$it_translation = $entity->addTranslation('it', $entity->toArray());
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
|
||||
$it_revision = $this->createRevision($it_translation);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 2 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [22, 1, 1, 'Alt 1 EN', 'Alt 2 IT']);
|
||||
|
||||
$en_revision = $this->createRevision($entity, FALSE);
|
||||
$en_revision->get($this->fieldName)->target_id = 2;
|
||||
$en_revision->getTranslation('it')->get($this->fieldName)->alt = 'Alt 3 IT';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertViolations($violations);
|
||||
|
||||
// Test that when saving a new default revision starting from a pending
|
||||
// revision, outdated synchronized properties do not override more recent
|
||||
// ones.
|
||||
$this->setUntranslatableFieldWidgetsDisplay(TRUE);
|
||||
$entity = $this->saveNewEntity();
|
||||
$entity_id = $entity->id();
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [23, 1, 1, 'Alt 1 EN']);
|
||||
|
||||
$it_translation = $entity->addTranslation('it', $entity->toArray());
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
|
||||
$it_revision = $this->createRevision($it_translation, FALSE);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($it_revision);
|
||||
$metadata->setSource('en');
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 2 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [24, 1, 1, 'Alt 1 EN', 'Alt 2 IT']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
|
||||
$en_revision = $this->createRevision($entity);
|
||||
$en_revision->get($this->fieldName)->target_id = 3;
|
||||
$en_revision->get($this->fieldName)->alt = 'Alt 3 EN';
|
||||
$violations = $en_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($en_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [25, 3, 3, 'Alt 3 EN', 'Alt 2 IT']);
|
||||
|
||||
$it_revision = $this->createRevision($it_revision);
|
||||
$it_revision->get($this->fieldName)->alt = 'Alt 4 IT';
|
||||
$violations = $it_revision->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($it_revision);
|
||||
$this->assertLatestRevisionFieldValues($entity_id, [26, 3, 3, 'Alt 3 EN', 'Alt 4 IT']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets untranslatable field widgets' display status.
|
||||
*
|
||||
* @param bool $display
|
||||
* Whether untranslatable field widgets should be displayed.
|
||||
*/
|
||||
protected function setUntranslatableFieldWidgetsDisplay($display) {
|
||||
$entity_type_id = $this->storage->getEntityTypeId();
|
||||
$settings = ['untranslatable_fields_hide' => !$display];
|
||||
$this->contentTranslationManager->setBundleTranslationSettings($entity_type_id, $entity_type_id, $settings);
|
||||
/** @var \Drupal\Core\Entity\EntityTypeBundleInfo $bundle_info */
|
||||
$bundle_info = $this->container->get('entity_type.bundle.info');
|
||||
$bundle_info->clearCachedBundles();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
protected function saveNewEntity() {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = EntityTestMulRev::create([
|
||||
'uid' => 1,
|
||||
'langcode' => 'en',
|
||||
$this->fieldName => [
|
||||
'target_id' => 1,
|
||||
'alt' => 'Alt 1 EN',
|
||||
],
|
||||
]);
|
||||
$metadata = $this->contentTranslationManager->getTranslationMetadata($entity);
|
||||
$metadata->setSource(LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
$violations = $entity->validate();
|
||||
$this->assertEmpty($violations);
|
||||
$this->storage->save($entity);
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new revision starting from the latest translation-affecting one.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\ContentEntityInterface $translation
|
||||
* The translation to be revisioned.
|
||||
* @param bool $default
|
||||
* (optional) Whether the new revision should be marked as default. Defaults
|
||||
* to TRUE.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\ContentEntityInterface
|
||||
* An entity revision object.
|
||||
*/
|
||||
protected function createRevision(ContentEntityInterface $translation, $default = TRUE) {
|
||||
if (!$translation->isNewTranslation()) {
|
||||
$langcode = $translation->language()->getId();
|
||||
$revision_id = $this->storage->getLatestTranslationAffectedRevisionId($translation->id(), $langcode);
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
|
||||
$revision = $this->storage->loadRevision($revision_id);
|
||||
$translation = $revision->getTranslation($langcode);
|
||||
}
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
|
||||
$revision = $this->storage->createRevision($translation, $default);
|
||||
return $revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the expected violations were found.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations
|
||||
* A list of violations.
|
||||
*/
|
||||
protected function assertViolations(EntityConstraintViolationListInterface $violations) {
|
||||
$entity_type_id = $this->storage->getEntityTypeId();
|
||||
$settings = $this->contentTranslationManager->getBundleTranslationSettings($entity_type_id, $entity_type_id);
|
||||
$message = !empty($settings['untranslatable_fields_hide']) ?
|
||||
'Non-translatable field elements can only be changed when updating the original language.' :
|
||||
'Non-translatable field elements can only be changed when updating the current revision.';
|
||||
|
||||
$list = [];
|
||||
foreach ($violations as $violation) {
|
||||
if ((string) $violation->getMessage() === $message) {
|
||||
$list[] = $violation;
|
||||
}
|
||||
}
|
||||
$this->assertCount(1, $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the latest revision has the expected field values.
|
||||
*
|
||||
* @param $entity_id
|
||||
* The entity ID.
|
||||
* @param array $expected_values
|
||||
* An array of expected values in the following order:
|
||||
* - revision ID
|
||||
* - target ID (en)
|
||||
* - target ID (it)
|
||||
* - alt (en)
|
||||
* - alt (it)
|
||||
*/
|
||||
protected function assertLatestRevisionFieldValues($entity_id, array $expected_values) {
|
||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
|
||||
$entity = $this->storage->loadRevision($this->storage->getLatestRevisionId($entity_id));
|
||||
@list($revision_id, $target_id_en, $target_id_it, $alt_en, $alt_it) = $expected_values;
|
||||
$this->assertEquals($revision_id, $entity->getRevisionId());
|
||||
$this->assertEquals($target_id_en, $entity->get($this->fieldName)->target_id);
|
||||
$this->assertEquals($alt_en, $entity->get($this->fieldName)->alt);
|
||||
if ($entity->hasTranslation('it')) {
|
||||
$it_translation = $entity->getTranslation('it');
|
||||
$this->assertEquals($target_id_it, $it_translation->get($this->fieldName)->target_id);
|
||||
$this->assertEquals($alt_it, $it_translation->get($this->fieldName)->alt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -59,7 +59,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->synchronizer = new FieldTranslationSynchronizer($this->container->get('entity.manager'));
|
||||
$this->synchronizer = new FieldTranslationSynchronizer($this->container->get('entity.manager'), $this->container->get('plugin.manager.field.field_type'));
|
||||
$this->synchronized = ['sync1', 'sync2'];
|
||||
$this->columns = array_merge($this->synchronized, ['var1', 'var2']);
|
||||
$this->langcodes = ['en', 'it', 'fr', 'de', 'es'];
|
||||
|
@ -181,13 +181,21 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
|
|||
// their delta.
|
||||
$delta_callbacks = [
|
||||
// Continuous field values: all values are equal.
|
||||
function($delta) { return TRUE; },
|
||||
function ($delta) {
|
||||
return TRUE;
|
||||
},
|
||||
// Alternated field values: only the even ones are equal.
|
||||
function($delta) { return $delta % 2 !== 0; },
|
||||
function ($delta) {
|
||||
return $delta % 2 !== 0;
|
||||
},
|
||||
// Sparse field values: only the "middle" ones are equal.
|
||||
function($delta) { return $delta === 1 || $delta === 2; },
|
||||
function ($delta) {
|
||||
return $delta === 1 || $delta === 2;
|
||||
},
|
||||
// Sparse field values: only the "extreme" ones are equal.
|
||||
function($delta) { return $delta === 0 || $delta === 3; },
|
||||
function ($delta) {
|
||||
return $delta === 0 || $delta === 3;
|
||||
},
|
||||
];
|
||||
|
||||
foreach ($delta_callbacks as $delta_callback) {
|
||||
|
@ -241,7 +249,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
|
|||
for ($delta = 0; $delta < $this->cardinality; $delta++) {
|
||||
foreach ($this->columns as $column) {
|
||||
// If the column is synchronized, the value should have been synced,
|
||||
// for unsychronized columns, the value must not change.
|
||||
// for unsynchronized columns, the value must not change.
|
||||
$expected_value = in_array($column, $this->synchronized) ? $changed_items[$delta][$column] : $this->unchangedFieldValues[$langcode][$delta][$column];
|
||||
$this->assertEqual($field_values[$langcode][$delta][$column], $expected_value, "Differing Item $delta column $column for langcode $langcode synced correctly");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
|
||||
/**
|
||||
* Test migration of translated taxonomy terms.
|
||||
*
|
||||
* @group migrate_drupal_6
|
||||
*/
|
||||
class MigrateTaxonomyTermTranslationTest extends MigrateDrupal6TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'menu_ui',
|
||||
// Required for translation migrations.
|
||||
'migrate_drupal_multilingual',
|
||||
'node',
|
||||
'taxonomy',
|
||||
];
|
||||
|
||||
/**
|
||||
* The cached taxonomy tree items, keyed by vid and tid.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $treeData = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(static::$modules);
|
||||
$this->executeMigrations([
|
||||
'd6_node_type',
|
||||
'd6_field',
|
||||
'd6_taxonomy_vocabulary',
|
||||
'd6_field_instance',
|
||||
'd6_taxonomy_term',
|
||||
'd6_taxonomy_term_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a migrated term contains the expected values.
|
||||
*
|
||||
* @param int $id
|
||||
* Entity ID to load and check.
|
||||
* @param string $expected_language
|
||||
* The language code for this term.
|
||||
* @param string $expected_label
|
||||
* The label the migrated entity should have.
|
||||
* @param string $expected_vid
|
||||
* The parent vocabulary the migrated entity should have.
|
||||
* @param string $expected_description
|
||||
* The description the migrated entity should have.
|
||||
* @param string $expected_format
|
||||
* The format the migrated entity should have.
|
||||
* @param int $expected_weight
|
||||
* The weight the migrated entity should have.
|
||||
* @param array $expected_parents
|
||||
* The parent terms the migrated entity should have.
|
||||
* @param int $expected_field_integer_value
|
||||
* The value the migrated entity field should have.
|
||||
* @param int $expected_term_reference_tid
|
||||
* The term reference ID the migrated entity field should have.
|
||||
*/
|
||||
protected function assertEntity($id, $expected_language, $expected_label, $expected_vid, $expected_description = '', $expected_format = NULL, $expected_weight = 0, $expected_parents = [], $expected_field_integer_value = NULL, $expected_term_reference_tid = NULL) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $entity */
|
||||
$entity = Term::load($id);
|
||||
$this->assertInstanceOf(TermInterface::class, $entity);
|
||||
$this->assertSame($expected_language, $entity->language()->getId());
|
||||
$this->assertSame($expected_label, $entity->label());
|
||||
$this->assertSame($expected_vid, $entity->bundle());
|
||||
$this->assertSame($expected_description, $entity->getDescription());
|
||||
$this->assertSame($expected_format, $entity->getFormat());
|
||||
$this->assertSame($expected_weight, $entity->getWeight());
|
||||
$this->assertHierarchy($expected_vid, $id, $expected_parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a term is present in the tree storage, with the right parents.
|
||||
*
|
||||
* @param string $vid
|
||||
* Vocabulary ID.
|
||||
* @param int $tid
|
||||
* ID of the term to check.
|
||||
* @param array $parent_ids
|
||||
* The expected parent term IDs.
|
||||
*/
|
||||
protected function assertHierarchy($vid, $tid, array $parent_ids) {
|
||||
if (!isset($this->treeData[$vid])) {
|
||||
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree($vid);
|
||||
$this->treeData[$vid] = [];
|
||||
foreach ($tree as $item) {
|
||||
$this->treeData[$vid][$item->tid] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey($tid, $this->treeData[$vid], "Term $tid exists in taxonomy tree");
|
||||
$term = $this->treeData[$vid][$tid];
|
||||
$this->assertEquals($parent_ids, array_filter($term->parents), "Term $tid has correct parents in taxonomy tree");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 6 i18n taxonomy term to Drupal 8 migration.
|
||||
*/
|
||||
public function testTranslatedTaxonomyTerms() {
|
||||
$this->assertEntity(1, 'zu', 'zu - term 1 of vocabulary 1', 'vocabulary_1_i_0_', 'zu - description of term 1 of vocabulary 1', NULL, '0', []);
|
||||
$this->assertEntity(2, 'fr', 'fr - term 2 of vocabulary 2', 'vocabulary_2_i_1_', 'fr - description of term 2 of vocabulary 2', NULL, '3', []);
|
||||
$this->assertEntity(3, 'fr', 'fr - term 3 of vocabulary 2', 'vocabulary_2_i_1_', 'fr - description of term 3 of vocabulary 2', NULL, '4', ['2']);
|
||||
$this->assertEntity(4, 'en', 'term 4 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 4 of vocabulary 3', NULL, '6', []);
|
||||
$this->assertEntity(5, 'en', 'term 5 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 5 of vocabulary 3', NULL, '7', ['4']);
|
||||
$this->assertEntity(6, 'en', 'term 6 of vocabulary 3', 'vocabulary_3_i_2_', 'description of term 6 of vocabulary 3', NULL, '8', ['4', '5']);
|
||||
$this->assertEntity(7, 'fr', 'fr - term 2 of vocabulary 1', 'vocabulary_1_i_0_', 'fr - desc of term 2 vocab 1', NULL, '0', []);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration of entity translation settings.
|
||||
*
|
||||
* @group migrate_drupal_7
|
||||
*/
|
||||
class MigrateEntityTranslationSettingsTest extends MigrateDrupal7TestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'language',
|
||||
'menu_ui',
|
||||
// Required for translation migrations.
|
||||
'migrate_drupal_multilingual',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'text',
|
||||
'user',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installConfig([
|
||||
'comment',
|
||||
'content_translation',
|
||||
'node',
|
||||
'taxonomy',
|
||||
'user',
|
||||
]);
|
||||
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
$this->executeMigrations([
|
||||
'd7_comment_type',
|
||||
'd7_node_type',
|
||||
'd7_taxonomy_vocabulary',
|
||||
'd7_entity_translation_settings',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity translation settings migration.
|
||||
*/
|
||||
public function testEntityTranslationSettingsMigration() {
|
||||
// Tests 'comment_node_test_content_type' entity translation settings.
|
||||
$config = $this->config('language.content_settings.comment.comment_node_test_content_type');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'comment');
|
||||
$this->assertSame($config->get('target_bundle'), 'comment_node_test_content_type');
|
||||
$this->assertSame($config->get('default_langcode'), 'current_interface');
|
||||
$this->assertFalse((bool) $config->get('language_alterable'));
|
||||
$this->assertTrue((bool) $config->get('third_party_settings.content_translation.enabled'));
|
||||
$this->assertFalse((bool) $config->get('third_party_settings.content_translation.bundle_settings.untranslatable_fields_hide'));
|
||||
|
||||
// Tests 'test_content_type' entity translation settings.
|
||||
$config = $this->config('language.content_settings.node.test_content_type');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'node');
|
||||
$this->assertSame($config->get('target_bundle'), 'test_content_type');
|
||||
$this->assertSame($config->get('default_langcode'), LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
$this->assertTrue((bool) $config->get('language_alterable'));
|
||||
$this->assertTrue((bool) $config->get('third_party_settings.content_translation.enabled'));
|
||||
$this->assertFalse((bool) $config->get('third_party_settings.content_translation.bundle_settings.untranslatable_fields_hide'));
|
||||
|
||||
// Tests 'test_vocabulary' entity translation settings.
|
||||
$config = $this->config('language.content_settings.taxonomy_term.test_vocabulary');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'taxonomy_term');
|
||||
$this->assertSame($config->get('target_bundle'), 'test_vocabulary');
|
||||
$this->assertSame($config->get('default_langcode'), LanguageInterface::LANGCODE_SITE_DEFAULT);
|
||||
$this->assertFalse((bool) $config->get('language_alterable'));
|
||||
$this->assertTrue((bool) $config->get('third_party_settings.content_translation.enabled'));
|
||||
$this->assertFalse((bool) $config->get('third_party_settings.content_translation.bundle_settings.untranslatable_fields_hide'));
|
||||
|
||||
// Tests 'user' entity translation settings.
|
||||
$config = $this->config('language.content_settings.user.user');
|
||||
$this->assertSame($config->get('target_entity_type_id'), 'user');
|
||||
$this->assertSame($config->get('target_bundle'), 'user');
|
||||
$this->assertSame($config->get('default_langcode'), LanguageInterface::LANGCODE_SITE_DEFAULT);
|
||||
$this->assertFalse((bool) $config->get('language_alterable'));
|
||||
$this->assertTrue((bool) $config->get('third_party_settings.content_translation.enabled'));
|
||||
$this->assertFalse((bool) $config->get('third_party_settings.content_translation.bundle_settings.untranslatable_fields_hide'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\content_translation\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests entity translation settings source plugin.
|
||||
*
|
||||
* @covers \Drupal\content_translation\Plugin\migrate\source\d7\EntityTranslationSettings
|
||||
*
|
||||
* @group content_translation
|
||||
*/
|
||||
class EntityTranslationSettingsTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = [
|
||||
'content_translation',
|
||||
'language',
|
||||
'migrate_drupal',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// Source data when there's no entity type that uses entity translation.
|
||||
$tests[0]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'entity_translation_entity_types',
|
||||
'value' => 'a:4:{s:7:"comment";i:0;s:4:"node";i:0;s:13:"taxonomy_term";i:0;s:4:"user";i:0;}',
|
||||
],
|
||||
];
|
||||
|
||||
// Source data when there's no bundle settings variables.
|
||||
$tests[1]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'entity_translation_entity_types',
|
||||
'value' => 'a:4:{s:7:"comment";s:7:"comment";s:4:"node";s:4:"node";s:13:"taxonomy_term";s:13:"taxonomy_term";s:4:"user";s:4:"user";}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_taxonomy',
|
||||
'value' => 'a:3:{s:6:"forums";b:1;s:4:"tags";b:1;s:4:"test";b:0;}',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_article',
|
||||
'value' => 's:1:"2";',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_forum',
|
||||
'value' => 's:1:"4";',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_page',
|
||||
'value' => 's:1:"4";',
|
||||
],
|
||||
];
|
||||
|
||||
// Source data when there's bundle settings variables.
|
||||
$tests[2]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'entity_translation_entity_types',
|
||||
'value' => 'a:4:{s:7:"comment";s:7:"comment";s:4:"node";s:4:"node";s:13:"taxonomy_term";s:13:"taxonomy_term";s:4:"user";s:4:"user";}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_comment__comment_node_forum',
|
||||
'value' => 'a:5:{s:16:"default_language";s:12:"xx-et-author";s:22:"hide_language_selector";i:1;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:0;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_comment__comment_node_page',
|
||||
'value' => 'a:5:{s:16:"default_language";s:12:"xx-et-author";s:22:"hide_language_selector";i:0;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:1;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_node__forum',
|
||||
'value' => 'a:5:{s:16:"default_language";s:12:"xx-et-author";s:22:"hide_language_selector";i:0;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:0;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_node__page',
|
||||
'value' => 'a:5:{s:16:"default_language";s:13:"xx-et-default";s:22:"hide_language_selector";i:1;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:1;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_taxonomy_term__forums',
|
||||
'value' => 'a:5:{s:16:"default_language";s:13:"xx-et-current";s:22:"hide_language_selector";i:0;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:1;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_taxonomy_term__tags',
|
||||
'value' => 'a:5:{s:16:"default_language";s:13:"xx-et-current";s:22:"hide_language_selector";i:1;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:0;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_settings_user__user',
|
||||
'value' => 'a:5:{s:16:"default_language";s:12:"xx-et-author";s:22:"hide_language_selector";i:1;s:21:"exclude_language_none";i:0;s:13:"lock_language";i:0;s:27:"shared_fields_original_only";i:1;}',
|
||||
],
|
||||
[
|
||||
'name' => 'entity_translation_taxonomy',
|
||||
'value' => 'a:3:{s:6:"forums";b:1;s:4:"tags";b:1;s:4:"test";b:0;}',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_article',
|
||||
'value' => 's:1:"2";',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_forum',
|
||||
'value' => 's:1:"4";',
|
||||
],
|
||||
[
|
||||
'name' => 'language_content_type_page',
|
||||
'value' => 's:1:"4";',
|
||||
],
|
||||
];
|
||||
|
||||
// Source data when taxonomy terms are translatable but the
|
||||
// 'entity_translation_taxonomy' variable is not set.
|
||||
$tests[3]['source_data']['variable'] = [
|
||||
[
|
||||
'name' => 'entity_translation_entity_types',
|
||||
'value' => 'a:4:{s:7:"comment";i:0;s:4:"node";i:0;s:13:"taxonomy_term";i:1;s:4:"user";i:0;}',
|
||||
],
|
||||
];
|
||||
|
||||
// Expected data when there's no entity type that uses entity translation.
|
||||
$tests[0]['expected_data'] = [];
|
||||
|
||||
// Expected data when there's no bundle settings variables.
|
||||
$tests[1]['expected_data'] = [
|
||||
[
|
||||
'id' => 'node.forum',
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'forum',
|
||||
'default_langcode' => 'und',
|
||||
'language_alterable' => TRUE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'node.page',
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'page',
|
||||
'default_langcode' => 'und',
|
||||
'language_alterable' => TRUE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'comment.comment_forum',
|
||||
'target_entity_type_id' => 'comment',
|
||||
'target_bundle' => 'comment_forum',
|
||||
'default_langcode' => 'xx-et-current',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'comment.comment_node_page',
|
||||
'target_entity_type_id' => 'comment',
|
||||
'target_bundle' => 'comment_node_page',
|
||||
'default_langcode' => 'xx-et-current',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'taxonomy_term.forums',
|
||||
'target_entity_type_id' => 'taxonomy_term',
|
||||
'target_bundle' => 'forums',
|
||||
'default_langcode' => 'xx-et-default',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'taxonomy_term.tags',
|
||||
'target_entity_type_id' => 'taxonomy_term',
|
||||
'target_bundle' => 'tags',
|
||||
'default_langcode' => 'xx-et-default',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'user.user',
|
||||
'target_entity_type_id' => 'user',
|
||||
'target_bundle' => 'user',
|
||||
'default_langcode' => 'xx-et-default',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
];
|
||||
|
||||
// Expected data when there's bundle settings variables.
|
||||
$tests[2]['expected_data'] = [
|
||||
[
|
||||
'id' => 'node.forum',
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'forum',
|
||||
'default_langcode' => 'xx-et-author',
|
||||
'language_alterable' => TRUE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'node.page',
|
||||
'target_entity_type_id' => 'node',
|
||||
'target_bundle' => 'page',
|
||||
'default_langcode' => 'xx-et-default',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => TRUE,
|
||||
],
|
||||
[
|
||||
'id' => 'comment.comment_forum',
|
||||
'target_entity_type_id' => 'comment',
|
||||
'target_bundle' => 'comment_forum',
|
||||
'default_langcode' => 'xx-et-author',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'comment.comment_node_page',
|
||||
'target_entity_type_id' => 'comment',
|
||||
'target_bundle' => 'comment_node_page',
|
||||
'default_langcode' => 'xx-et-author',
|
||||
'language_alterable' => TRUE,
|
||||
'untranslatable_fields_hide' => TRUE,
|
||||
],
|
||||
[
|
||||
'id' => 'taxonomy_term.forums',
|
||||
'target_entity_type_id' => 'taxonomy_term',
|
||||
'target_bundle' => 'forums',
|
||||
'default_langcode' => 'xx-et-current',
|
||||
'language_alterable' => TRUE,
|
||||
'untranslatable_fields_hide' => TRUE,
|
||||
],
|
||||
[
|
||||
'id' => 'taxonomy_term.tags',
|
||||
'target_entity_type_id' => 'taxonomy_term',
|
||||
'target_bundle' => 'tags',
|
||||
'default_langcode' => 'xx-et-current',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => FALSE,
|
||||
],
|
||||
[
|
||||
'id' => 'user.user',
|
||||
'target_entity_type_id' => 'user',
|
||||
'target_bundle' => 'user',
|
||||
'default_langcode' => 'xx-et-author',
|
||||
'language_alterable' => FALSE,
|
||||
'untranslatable_fields_hide' => TRUE,
|
||||
],
|
||||
];
|
||||
|
||||
// Expected data when taxonomy terms are translatable but the
|
||||
// 'entity_translation_taxonomy' variable is not set.
|
||||
$tests[3]['expected_data'] = [];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
|
@ -49,20 +49,30 @@ class ContentTranslationLocalTasksTest extends LocalTaskIntegrationTestBase {
|
|||
*/
|
||||
public function providerTestBlockAdminDisplay() {
|
||||
return [
|
||||
['entity.node.canonical', [[
|
||||
'content_translation.local_tasks:entity.node.content_translation_overview',
|
||||
[
|
||||
'entity.node.canonical',
|
||||
'entity.node.edit_form',
|
||||
'entity.node.delete_form',
|
||||
'entity.node.version_history',
|
||||
]]],
|
||||
['entity.node.content_translation_overview', [[
|
||||
'content_translation.local_tasks:entity.node.content_translation_overview',
|
||||
'entity.node.canonical',
|
||||
'entity.node.edit_form',
|
||||
'entity.node.delete_form',
|
||||
'entity.node.version_history',
|
||||
]]],
|
||||
[
|
||||
[
|
||||
'content_translation.local_tasks:entity.node.content_translation_overview',
|
||||
'entity.node.canonical',
|
||||
'entity.node.edit_form',
|
||||
'entity.node.delete_form',
|
||||
'entity.node.version_history',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity.node.content_translation_overview',
|
||||
[
|
||||
[
|
||||
'content_translation.local_tasks:entity.node.content_translation_overview',
|
||||
'entity.node.canonical',
|
||||
'entity.node.edit_form',
|
||||
'entity.node.delete_form',
|
||||
'entity.node.version_history',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue