upgrades core to 8.4.2

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 16:09:54 +01:00
parent bd60eff9b3
commit c2b4e25be4
3504 changed files with 140306 additions and 38684 deletions
@@ -0,0 +1,126 @@
/**
* @file
* Content Translation admin behaviors.
*/
(function ($, Drupal, drupalSettings) {
/**
* Forces applicable options to be checked as translatable.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches content translation dependent options to the UI.
*/
Drupal.behaviors.contentTranslationDependentOptions = {
attach(context) {
const $context = $(context);
const options = drupalSettings.contentTranslationDependentOptions;
let $fields;
let dependent_columns;
function fieldsChangeHandler($fields, dependent_columns) {
return function (e) {
Drupal.behaviors.contentTranslationDependentOptions.check($fields, dependent_columns, $(e.target));
};
}
// We're given a generic name to look for so we find all inputs containing
// that name and copy over the input values that require all columns to be
// translatable.
if (options && options.dependent_selectors) {
for (const field in options.dependent_selectors) {
if (options.dependent_selectors.hasOwnProperty(field)) {
$fields = $context.find(`input[name^="${field}"]`);
dependent_columns = options.dependent_selectors[field];
$fields.on('change', fieldsChangeHandler($fields, dependent_columns));
Drupal.behaviors.contentTranslationDependentOptions.check($fields, dependent_columns);
}
}
}
},
check($fields, dependent_columns, $changed) {
let $element = $changed;
let column;
function filterFieldsList(index, field) {
return $(field).val() === column;
}
// A field that has many different translatable parts can also define one
// or more columns that require all columns to be translatable.
for (const index in dependent_columns) {
if (dependent_columns.hasOwnProperty(index)) {
column = dependent_columns[index];
if (!$changed) {
$element = $fields.filter(filterFieldsList);
}
if ($element.is(`input[value="${column}"]:checked`)) {
$fields.prop('checked', true)
.not($element).prop('disabled', true);
}
else {
$fields.prop('disabled', false);
}
}
}
},
};
/**
* Makes field translatability inherit bundle translatability.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches content translation behavior.
*/
Drupal.behaviors.contentTranslation = {
attach(context) {
// Initially hide all field rows for non translatable bundles and all
// column rows for non translatable fields.
$(context).find('table .bundle-settings .translatable :input').once('translation-entity-admin-hide').each(function () {
const $input = $(this);
const $bundleSettings = $input.closest('.bundle-settings');
if (!$input.is(':checked')) {
$bundleSettings.nextUntil('.bundle-settings').hide();
}
else {
$bundleSettings.nextUntil('.bundle-settings', '.field-settings').find('.translatable :input:not(:checked)').closest('.field-settings').nextUntil(':not(.column-settings)').hide();
}
});
// When a bundle is made translatable all of its fields should inherit
// this setting. Instead when it is made non translatable its fields are
// hidden, since their translatability no longer matters.
$('body').once('translation-entity-admin-bind').on('click', 'table .bundle-settings .translatable :input', (e) => {
const $target = $(e.target);
const $bundleSettings = $target.closest('.bundle-settings');
const $settings = $bundleSettings.nextUntil('.bundle-settings');
const $fieldSettings = $settings.filter('.field-settings');
if ($target.is(':checked')) {
$bundleSettings.find('.operations :input[name$="[language_alterable]"]').prop('checked', true);
$fieldSettings.find('.translatable :input').prop('checked', true);
$settings.show();
}
else {
$settings.hide();
}
})
.on('click', 'table .field-settings .translatable :input', (e) => {
const $target = $(e.target);
const $fieldSettings = $target.closest('.field-settings');
const $columnSettings = $fieldSettings.nextUntil('.field-settings, .bundle-settings');
if ($target.is(':checked')) {
$columnSettings.show();
}
else {
$columnSettings.hide();
}
});
},
};
}(jQuery, Drupal, drupalSettings));
@@ -209,7 +209,7 @@ function _content_translation_preprocess_language_content_settings_table(&$varia
$rows[] = [
'data' => [
[
'data' => drupal_render($field_element),
'data' => \Drupal::service('renderer')->render($field_element),
'class' => ['translatable'],
],
[
@@ -243,7 +243,7 @@ function _content_translation_preprocess_language_content_settings_table(&$varia
$rows[] = [
'data' => [
[
'data' => drupal_render($column_element[$key]),
'data' => \Drupal::service('renderer')->render($column_element[$key]),
'class' => ['translatable'],
],
[
@@ -1,26 +1,17 @@
/**
* @file
* Content Translation admin behaviors.
*/
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal, drupalSettings) {
'use strict';
/**
* Forces applicable options to be checked as translatable.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches content translation dependent options to the UI.
*/
Drupal.behaviors.contentTranslationDependentOptions = {
attach: function (context) {
attach: function attach(context) {
var $context = $(context);
var options = drupalSettings.contentTranslationDependentOptions;
var $fields;
var dependent_columns;
var $fields = void 0;
var dependent_columns = void 0;
function fieldsChangeHandler($fields, dependent_columns) {
return function (e) {
@@ -28,9 +19,6 @@
};
}
// We're given a generic name to look for so we find all inputs containing
// that name and copy over the input values that require all columns to be
// translatable.
if (options && options.dependent_selectors) {
for (var field in options.dependent_selectors) {
if (options.dependent_selectors.hasOwnProperty(field)) {
@@ -43,16 +31,14 @@
}
}
},
check: function ($fields, dependent_columns, $changed) {
check: function check($fields, dependent_columns, $changed) {
var $element = $changed;
var column;
var column = void 0;
function filterFieldsList(index, field) {
return $(field).val() === column;
}
// A field that has many different translatable parts can also define one
// or more columns that require all columns to be translatable.
for (var index in dependent_columns) {
if (dependent_columns.hasOwnProperty(index)) {
column = dependent_columns[index];
@@ -62,44 +48,27 @@
}
if ($element.is('input[value="' + column + '"]:checked')) {
$fields.prop('checked', true)
.not($element).prop('disabled', true);
}
else {
$fields.prop('checked', true).not($element).prop('disabled', true);
} else {
$fields.prop('disabled', false);
}
}
}
}
};
/**
* Makes field translatability inherit bundle translatability.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches content translation behavior.
*/
Drupal.behaviors.contentTranslation = {
attach: function (context) {
// Initially hide all field rows for non translatable bundles and all
// column rows for non translatable fields.
attach: function attach(context) {
$(context).find('table .bundle-settings .translatable :input').once('translation-entity-admin-hide').each(function () {
var $input = $(this);
var $bundleSettings = $input.closest('.bundle-settings');
if (!$input.is(':checked')) {
$bundleSettings.nextUntil('.bundle-settings').hide();
}
else {
} else {
$bundleSettings.nextUntil('.bundle-settings', '.field-settings').find('.translatable :input:not(:checked)').closest('.field-settings').nextUntil(':not(.column-settings)').hide();
}
});
// When a bundle is made translatable all of its fields should inherit
// this setting. Instead when it is made non translatable its fields are
// hidden, since their translatability no longer matters.
$('body').once('translation-entity-admin-bind').on('click', 'table .bundle-settings .translatable :input', function (e) {
var $target = $(e.target);
var $bundleSettings = $target.closest('.bundle-settings');
@@ -109,23 +78,19 @@
$bundleSettings.find('.operations :input[name$="[language_alterable]"]').prop('checked', true);
$fieldSettings.find('.translatable :input').prop('checked', true);
$settings.show();
}
else {
} else {
$settings.hide();
}
})
.on('click', 'table .field-settings .translatable :input', function (e) {
var $target = $(e.target);
var $fieldSettings = $target.closest('.field-settings');
var $columnSettings = $fieldSettings.nextUntil('.field-settings, .bundle-settings');
if ($target.is(':checked')) {
$columnSettings.show();
}
else {
$columnSettings.hide();
}
});
}).on('click', 'table .field-settings .translatable :input', function (e) {
var $target = $(e.target);
var $fieldSettings = $target.closest('.field-settings');
var $columnSettings = $fieldSettings.nextUntil('.field-settings, .bundle-settings');
if ($target.is(':checked')) {
$columnSettings.show();
} else {
$columnSettings.hide();
}
});
}
};
})(jQuery, Drupal, drupalSettings);
})(jQuery, Drupal, drupalSettings);
@@ -8,8 +8,8 @@ package: Multilingual
# core: 8.x
configure: language.content_settings_page
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -5,7 +5,9 @@
* Installation functions for Content Translation module.
*/
use \Drupal\Core\Url;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
/**
* Implements hook_install().
@@ -44,3 +46,57 @@ function content_translation_update_8001() {
function content_translation_update_8002() {
\Drupal::service('plugin.manager.field.field_type')->clearCachedDefinitions();
}
/**
* Fix the initial values for content translation metadata fields.
*/
function content_translation_update_8400() {
$database = \Drupal::database();
/** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
$content_translation_manager = \Drupal::service('content_translation.manager');
/** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
$last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
$entity_type_manager = \Drupal::entityTypeManager();
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
foreach ($content_translation_manager->getSupportedEntityTypes() as $entity_type_id => $entity_type_definition) {
$storage = $entity_type_manager->getStorage($entity_type_id);
if ($storage instanceof SqlEntityStorageInterface) {
$entity_type = $entity_definition_update_manager->getEntityType($entity_type_id);
$storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
// Since the entity type is managed by Content Translation, we can assume
// that it is translatable, so we use the data and revision data tables.
$tables_to_update = [$entity_type->getDataTable()];
if ($entity_type->isRevisionable()) {
$tables_to_update += [$entity_type->getRevisionDataTable()];
}
foreach ($tables_to_update as $table_name) {
// Fix the values of the 'content_translation_source' field.
if (isset($storage_definitions['content_translation_source'])) {
$database->update($table_name)
->fields(['content_translation_source' => LanguageInterface::LANGCODE_NOT_SPECIFIED])
->isNull('content_translation_source')
->execute();
}
// Fix the values of the 'content_translation_outdated' field.
if (isset($storage_definitions['content_translation_outdated'])) {
$database->update($table_name)
->fields(['content_translation_outdated' => 0])
->isNull('content_translation_outdated')
->execute();
}
// Fix the values of the 'content_translation_status' field.
if (isset($storage_definitions['content_translation_status'])) {
$database->update($table_name)
->fields(['content_translation_status' => 1])
->isNull('content_translation_status')
->execute();
}
}
}
}
}
@@ -116,6 +116,7 @@ class ContentTranslationHandler implements ContentTranslationHandlerInterface, E
->setLabel(t('Translation source'))
->setDescription(t('The source language from which this translation was created.'))
->setDefaultValue(LanguageInterface::LANGCODE_NOT_SPECIFIED)
->setInitialValue(LanguageInterface::LANGCODE_NOT_SPECIFIED)
->setRevisionable(TRUE)
->setTranslatable(TRUE);
@@ -123,6 +124,7 @@ class ContentTranslationHandler implements ContentTranslationHandlerInterface, E
->setLabel(t('Translation outdated'))
->setDescription(t('A boolean indicating whether this translation needs to be updated.'))
->setDefaultValue(FALSE)
->setInitialValue(FALSE)
->setRevisionable(TRUE)
->setTranslatable(TRUE);
@@ -142,6 +144,7 @@ class ContentTranslationHandler implements ContentTranslationHandlerInterface, E
->setLabel(t('Translation status'))
->setDescription(t('A boolean indicating whether the translation is visible to non-translators.'))
->setDefaultValue(TRUE)
->setInitialValue(TRUE)
->setRevisionable(TRUE)
->setTranslatable(TRUE);
}
@@ -196,14 +196,16 @@ class ContentTranslationController extends ControllerBase {
if (isset($links['edit'])) {
$links['edit']['title'] = $this->t('Edit');
}
$status = ['data' => [
'#type' => 'inline_template',
'#template' => '<span class="status">{% if status %}{{ "Published"|t }}{% else %}{{ "Not published"|t }}{% endif %}</span>{% if outdated %} <span class="marker">{{ "outdated"|t }}</span>{% endif %}',
'#context' => [
'status' => $metadata->isPublished(),
'outdated' => $metadata->isOutdated(),
$status = [
'data' => [
'#type' => 'inline_template',
'#template' => '<span class="status">{% if status %}{{ "Published"|t }}{% else %}{{ "Not published"|t }}{% endif %}</span>{% if outdated %} <span class="marker">{{ "outdated"|t }}</span>{% endif %}',
'#context' => [
'status' => $metadata->isPublished(),
'outdated' => $metadata->isOutdated(),
],
],
]];
];
if ($is_original) {
$language_name = $this->t('<strong>@language_name (Original language)</strong>', ['@language_name' => $language_name]);
@@ -9,8 +9,8 @@ dependencies:
- language
- entity_test
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -5,7 +5,7 @@
* Helper module for the Content Translation tests.
*/
use \Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_form_BASE_FORM_ID_alter().
@@ -8,8 +8,8 @@ dependencies:
- content_translation
- views
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -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.');
}
}
@@ -73,12 +73,12 @@ class ContentTranslationLanguageChangeTest extends NodeTestBase {
$edit = [
'title[0][value]' => 'english_title',
];
$this->drupalPostForm(NULL, $edit, t('Save and publish'));
$this->drupalPostForm(NULL, $edit, t('Save'));
// Create a translation in French.
$this->clickLink('Translate');
$this->clickLink('Add');
$this->drupalPostForm(NULL, [], t('Save and keep published (this translation)'));
$this->drupalPostForm(NULL, [], t('Save (this translation)'));
$this->clickLink('Translate');
// Edit English translation.
@@ -90,7 +90,7 @@ class ContentTranslationLanguageChangeTest extends NodeTestBase {
'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 and keep published (this translation)'));
$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');
@@ -109,13 +109,13 @@ class ContentTranslationLanguageChangeTest extends NodeTestBase {
'title[0][value]' => 'english_title',
'test_field_only_en_fr' => 'node created',
];
$this->drupalPostForm(NULL, $edit, t('Save and publish'));
$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 and keep published (this translation)'));
$this->drupalPostForm(NULL, [], t('Save (this translation)'));
$this->clickLink('Translate');
// Edit English translation.
@@ -137,7 +137,7 @@ class ContentTranslationLanguageChangeTest extends NodeTestBase {
'langcode[0][value]' => 'en',
'field_image_field[0][alt]' => 'alternative_text'
];
$this->drupalPostForm(NULL, $edit, t('Save and keep published (this translation)'));
$this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
// Check that the translation languages are correct.
$node = $this->getNodeByTitle('english_title');
@@ -11,7 +11,7 @@ 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.
@@ -0,0 +1,259 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Component\Utility\SafeMarkup;
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'], SafeMarkup::format('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'], SafeMarkup::format('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'], SafeMarkup::format('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'], SafeMarkup::format('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'], SafeMarkup::format('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'], SafeMarkup::format('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,100 @@
<?php
namespace Drupal\Tests\content_translation\Functional\Update;
use Drupal\Core\Language\LanguageInterface;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\system\Tests\Entity\EntityDefinitionTestTrait;
/**
* Tests the upgrade path for the Content Translation module.
*
* @group Update
*/
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,72 @@
<?php
namespace Drupal\Tests\content_translation\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests that contextual links are available for content translation.
*
* @group content_translation
*/
class ContentTranslationContextualLinksTest extends JavascriptTestBase {
/**
* 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'));
}
}
@@ -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) {
@@ -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',
],
],
],
];
}