3 namespace Drupal\Tests\content_translation\Functional;
5 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
6 use Drupal\comment\Tests\CommentTestTrait;
7 use Drupal\Core\Field\Entity\BaseFieldOverride;
8 use Drupal\Core\Language\Language;
9 use Drupal\field\Entity\FieldConfig;
10 use Drupal\language\Entity\ContentLanguageSettings;
11 use Drupal\Tests\BrowserTestBase;
14 * Tests the content translation settings UI.
16 * @group content_translation
18 class ContentTranslationSettingsTest extends BrowserTestBase {
27 public static $modules = ['language', 'content_translation', 'node', 'comment', 'field_ui', 'entity_test'];
29 protected function setUp() {
32 // Set up two content types to test fields shared between different
34 $this->drupalCreateContentType(['type' => 'article']);
35 $this->drupalCreateContentType(['type' => 'page']);
36 $this->addDefaultCommentField('node', 'article', 'comment_article', CommentItemInterface::OPEN, 'comment_article');
37 $this->addDefaultCommentField('node', 'page', 'comment_page');
39 $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']);
40 $this->drupalLogin($admin_user);
44 * Tests that the settings UI works as expected.
46 public function testSettingsUI() {
47 // Check for the content_translation_menu_links_discovered_alter() changes.
48 $this->drupalGet('admin/config');
49 $this->assertLink('Content language and translation');
50 $this->assertText('Configure language and translation support for content.');
51 // Test that the translation settings are ignored if the bundle is marked
52 // translatable but the entity type is not.
53 $edit = ['settings[comment][comment_article][translatable]' => TRUE];
54 $this->assertSettings('comment', NULL, FALSE, $edit);
56 // Test that the translation settings are ignored if only a field is marked
57 // as translatable and not the related entity type and bundle.
58 $edit = ['settings[comment][comment_article][fields][comment_body]' => TRUE];
59 $this->assertSettings('comment', NULL, FALSE, $edit);
61 // Test that the translation settings are not stored if an entity type and
62 // bundle are marked as translatable but no field is.
64 'entity_types[comment]' => TRUE,
65 'settings[comment][comment_article][translatable]' => TRUE,
66 // Base fields are translatable by default.
67 'settings[comment][comment_article][fields][changed]' => FALSE,
68 'settings[comment][comment_article][fields][created]' => FALSE,
69 'settings[comment][comment_article][fields][homepage]' => FALSE,
70 'settings[comment][comment_article][fields][hostname]' => FALSE,
71 'settings[comment][comment_article][fields][mail]' => FALSE,
72 'settings[comment][comment_article][fields][name]' => FALSE,
73 'settings[comment][comment_article][fields][status]' => FALSE,
74 'settings[comment][comment_article][fields][subject]' => FALSE,
75 'settings[comment][comment_article][fields][uid]' => FALSE,
77 $this->assertSettings('comment', 'comment_article', FALSE, $edit);
78 $xpath_err = '//div[contains(@class, "error")]';
79 $this->assertTrue($this->xpath($xpath_err), 'Enabling translation only for entity bundles generates a form error.');
81 // Test that the translation settings are not stored if a non-configurable
82 // language is set as default and the language selector is hidden.
84 'entity_types[comment]' => TRUE,
85 'settings[comment][comment_article][settings][language][langcode]' => Language::LANGCODE_NOT_SPECIFIED,
86 'settings[comment][comment_article][settings][language][language_alterable]' => FALSE,
87 'settings[comment][comment_article][translatable]' => TRUE,
88 'settings[comment][comment_article][fields][comment_body]' => TRUE,
90 $this->assertSettings('comment', 'comment_article', FALSE, $edit);
91 $this->assertTrue($this->xpath($xpath_err), 'Enabling translation with a fixed non-configurable language generates a form error.');
93 // Test that a field shared among different bundles can be enabled without
94 // needing to make all the related bundles translatable.
96 'entity_types[comment]' => TRUE,
97 'settings[comment][comment_article][settings][language][langcode]' => 'current_interface',
98 'settings[comment][comment_article][settings][language][language_alterable]' => TRUE,
99 'settings[comment][comment_article][translatable]' => TRUE,
100 'settings[comment][comment_article][fields][comment_body]' => TRUE,
101 // Override both comment subject fields to untranslatable.
102 'settings[comment][comment_article][fields][subject]' => FALSE,
103 'settings[comment][comment][fields][subject]' => FALSE,
105 $this->assertSettings('comment', 'comment_article', TRUE, $edit);
106 $definition = $this->entityManager()->getFieldDefinitions('comment', 'comment_article')['comment_body'];
107 $this->assertTrue($definition->isTranslatable(), 'Article comment body is translatable.');
108 $definition = $this->entityManager()->getFieldDefinitions('comment', 'comment_article')['subject'];
109 $this->assertFalse($definition->isTranslatable(), 'Article comment subject is not translatable.');
111 $definition = $this->entityManager()->getFieldDefinitions('comment', 'comment')['comment_body'];
112 $this->assertFalse($definition->isTranslatable(), 'Page comment body is not translatable.');
113 $definition = $this->entityManager()->getFieldDefinitions('comment', 'comment')['subject'];
114 $this->assertFalse($definition->isTranslatable(), 'Page comment subject is not translatable.');
116 // Test that translation can be enabled for base fields.
118 'entity_types[entity_test_mul]' => TRUE,
119 'settings[entity_test_mul][entity_test_mul][translatable]' => TRUE,
120 'settings[entity_test_mul][entity_test_mul][fields][name]' => TRUE,
121 'settings[entity_test_mul][entity_test_mul][fields][user_id]' => FALSE,
123 $this->assertSettings('entity_test_mul', 'entity_test_mul', TRUE, $edit);
124 $field_override = BaseFieldOverride::loadByName('entity_test_mul', 'entity_test_mul', 'name');
125 $this->assertTrue($field_override->isTranslatable(), 'Base fields can be overridden with a base field bundle override entity.');
126 $definitions = $this->entityManager()->getFieldDefinitions('entity_test_mul', 'entity_test_mul');
127 $this->assertTrue($definitions['name']->isTranslatable() && !$definitions['user_id']->isTranslatable(), 'Base field bundle overrides were correctly altered.');
129 // Test that language settings are correctly stored.
130 $language_configuration = ContentLanguageSettings::loadByEntityTypeBundle('comment', 'comment_article');
131 $this->assertEqual($language_configuration->getDefaultLangcode(), 'current_interface', 'The default language for article comments is set to the interface text language selected for page.');
132 $this->assertTrue($language_configuration->isLanguageAlterable(), 'The language selector for article comments is shown.');
134 // Verify language widget appears on comment type form.
135 $this->drupalGet('admin/structure/comment/manage/comment_article');
136 $this->assertField('language_configuration[content_translation]');
137 $this->assertFieldChecked('edit-language-configuration-content-translation');
139 // Verify that translation may be enabled for the article content type.
141 'language_configuration[content_translation]' => TRUE,
143 // Make sure the checkbox is available and not checked by default.
144 $this->drupalGet('admin/structure/types/manage/article');
145 $this->assertField('language_configuration[content_translation]');
146 $this->assertNoFieldChecked('edit-language-configuration-content-translation');
147 $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
148 $this->drupalGet('admin/structure/types/manage/article');
149 $this->assertFieldChecked('edit-language-configuration-content-translation');
151 // Test that the title field of nodes is available in the settings form.
153 'entity_types[node]' => TRUE,
154 'settings[node][article][settings][language][langcode]' => 'current_interface',
155 'settings[node][article][settings][language][language_alterable]' => TRUE,
156 'settings[node][article][translatable]' => TRUE,
157 'settings[node][article][fields][title]' => TRUE
159 $this->assertSettings('node', NULL, TRUE, $edit);
161 foreach ([TRUE, FALSE] as $translatable) {
162 // Test that configurable field translatability is correctly switched.
163 $edit = ['settings[node][article][fields][body]' => $translatable];
164 $this->assertSettings('node', 'article', TRUE, $edit);
165 $field = FieldConfig::loadByName('node', 'article', 'body');
166 $definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'article');
167 $this->assertEqual($definitions['body']->isTranslatable(), $translatable, 'Field translatability correctly switched.');
168 $this->assertEqual($field->isTranslatable(), $definitions['body']->isTranslatable(), 'Configurable field translatability correctly switched.');
170 // Test that also the Field UI form behaves correctly.
171 $translatable = !$translatable;
172 $edit = ['translatable' => $translatable];
173 $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.body', $edit, t('Save settings'));
174 \Drupal::entityManager()->clearCachedFieldDefinitions();
175 $field = FieldConfig::loadByName('node', 'article', 'body');
176 $definitions = \Drupal::entityManager()->getFieldDefinitions('node', 'article');
177 $this->assertEqual($definitions['body']->isTranslatable(), $translatable, 'Field translatability correctly switched.');
178 $this->assertEqual($field->isTranslatable(), $definitions['body']->isTranslatable(), 'Configurable field translatability correctly switched.');
181 // Test that the order of the language list is similar to other language
182 // lists, such as in Views UI.
183 $this->drupalGet('admin/config/regional/content-language');
185 $expected_elements = [
193 $elements = $this->xpath('//select[@id="edit-settings-node-article-settings-language-langcode"]/option');
194 // Compare values inside the option elements with expected values.
195 for ($i = 0; $i < count($elements); $i++) {
196 $this->assertEqual($elements[$i]->getValue(), $expected_elements[$i]);
201 * Tests the language settings checkbox on account settings page.
203 public function testAccountLanguageSettingsUI() {
204 // Make sure the checkbox is available and not checked by default.
205 $this->drupalGet('admin/config/people/accounts');
206 $this->assertField('language[content_translation]');
207 $this->assertNoFieldChecked('edit-language-content-translation');
210 'language[content_translation]' => TRUE,
212 $this->drupalPostForm('admin/config/people/accounts', $edit, t('Save configuration'));
213 $this->drupalGet('admin/config/people/accounts');
214 $this->assertFieldChecked('edit-language-content-translation');
216 // Make sure account settings can be saved.
217 $this->drupalPostForm('admin/config/people/accounts', ['anonymous' => 'Save me please!'], 'Save configuration');
218 $this->assertFieldByName('anonymous', 'Save me please!', 'Anonymous name has been changed.');
219 $this->assertText('The configuration options have been saved.');
223 * Asserts that translatability has the expected value for the given bundle.
225 * @param string $entity_type
226 * The entity type for which to check translatability.
227 * @param string $bundle
228 * The bundle for which to check translatability.
229 * @param bool $enabled
230 * TRUE if translatability should be enabled, FALSE otherwise.
232 * An array of values to submit to the content translation settings page.
235 * TRUE if the assertion succeeded, FALSE otherwise.
237 protected function assertSettings($entity_type, $bundle, $enabled, $edit) {
238 $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
239 $args = ['@entity_type' => $entity_type, '@bundle' => $bundle, '@enabled' => $enabled ? 'enabled' : 'disabled'];
240 $message = format_string('Translation for entity @entity_type (@bundle) is @enabled.', $args);
241 \Drupal::entityManager()->clearCachedDefinitions();
242 return $this->assertEqual(\Drupal::service('content_translation.manager')->isEnabled($entity_type, $bundle), $enabled, $message);
246 * Tests that field setting depends on bundle translatability.
248 public function testFieldTranslatableSettingsUI() {
249 // At least one field needs to be translatable to enable article for
250 // translation. Create an extra field to be used for this purpose. We use
251 // the UI to test our form alterations.
253 'new_storage_type' => 'text',
255 'field_name' => 'article_text',
257 $this->drupalPostForm('admin/structure/types/manage/article/fields/add-field', $edit, 'Save and continue');
259 // Tests that field doesn't have translatable setting if bundle is not
261 $path = 'admin/structure/types/manage/article/fields/node.article.field_article_text';
262 $this->drupalGet($path);
263 $this->assertFieldByXPath('//input[@id="edit-translatable" and @disabled="disabled"]');
264 $this->assertText('To configure translation for this field, enable language support for this type.', 'No translatable setting for field.');
266 // Tests that field has translatable setting if bundle is translatable.
267 // Note: this field is not translatable when enable bundle translatability.
269 'entity_types[node]' => TRUE,
270 'settings[node][article][settings][language][language_alterable]' => TRUE,
271 'settings[node][article][translatable]' => TRUE,
272 'settings[node][article][fields][field_article_text]' => TRUE,
274 $this->assertSettings('node', 'article', TRUE, $edit);
275 $this->drupalGet($path);
276 $this->assertFieldByXPath('//input[@id="edit-translatable" and not(@disabled) and @checked="checked"]');
277 $this->assertNoText('To enable translation of this field, enable language support for this type.', 'Translatable setting for field available.');
281 * Tests the translatable settings checkbox for untranslatable entities.
283 public function testNonTranslatableTranslationSettingsUI() {
284 $this->drupalGet('admin/config/regional/content-language');
285 $this->assertNoField('settings[entity_test][entity_test][translatable]');
289 * Returns the entity manager.
291 * @return \Drupal\Core\Entity\EntityManagerInterface
292 * The entity manager;
294 protected function entityManager() {
295 return $this->container->get('entity.manager');