comparison core/modules/content_translation/content_translation.module @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents a9cd425dd02b
children
comparison
equal deleted inserted replaced
4:a9cd425dd02b 5:12f9dff5fda9
3 /** 3 /**
4 * @file 4 * @file
5 * Allows entities to be translated into different languages. 5 * Allows entities to be translated into different languages.
6 */ 6 */
7 7
8 use Drupal\Core\Url;
8 use Drupal\content_translation\BundleTranslationSettingsInterface; 9 use Drupal\content_translation\BundleTranslationSettingsInterface;
9 use Drupal\content_translation\ContentTranslationManager; 10 use Drupal\content_translation\ContentTranslationManager;
10 use Drupal\Core\Access\AccessResult; 11 use Drupal\Core\Access\AccessResult;
11 use Drupal\Core\Entity\ContentEntityFormInterface; 12 use Drupal\Core\Entity\ContentEntityFormInterface;
12 use Drupal\Core\Entity\ContentEntityInterface; 13 use Drupal\Core\Entity\ContentEntityInterface;
14 use Drupal\Core\Entity\EntityTypeInterface; 15 use Drupal\Core\Entity\EntityTypeInterface;
15 use Drupal\Core\Form\FormStateInterface; 16 use Drupal\Core\Form\FormStateInterface;
16 use Drupal\Core\Language\LanguageInterface; 17 use Drupal\Core\Language\LanguageInterface;
17 use Drupal\Core\Routing\RouteMatchInterface; 18 use Drupal\Core\Routing\RouteMatchInterface;
18 use Drupal\Core\StringTranslation\TranslatableMarkup; 19 use Drupal\Core\StringTranslation\TranslatableMarkup;
20 use Drupal\language\ContentLanguageSettingsInterface;
19 21
20 /** 22 /**
21 * Implements hook_help(). 23 * Implements hook_help().
22 */ 24 */
23 function content_translation_help($route_name, RouteMatchInterface $route_match) { 25 function content_translation_help($route_name, RouteMatchInterface $route_match) {
24 switch ($route_name) { 26 switch ($route_name) {
25 case 'help.page.content_translation': 27 case 'help.page.content_translation':
26 $output = ''; 28 $output = '';
27 $output .= '<h3>' . t('About') . '</h3>'; 29 $output .= '<h3>' . t('About') . '</h3>';
28 $output .= '<p>' . t('The Content Translation module allows you to translate content, comments, custom blocks, taxonomy terms, users and other <a href=":field_help" title="Field module help, with background on content entities">content entities</a>. Together with the modules <a href=":language">Language</a>, <a href=":config-trans">Configuration Translation</a>, and <a href=":locale">Interface Translation</a>, it allows you to build multilingual websites. For more information, see the <a href=":translation-entity">online documentation for the Content Translation module</a>.', [':locale' => (\Drupal::moduleHandler()->moduleExists('locale')) ? \Drupal::url('help.page', ['name' => 'locale']) : '#', ':config-trans' => (\Drupal::moduleHandler()->moduleExists('config_translation')) ? \Drupal::url('help.page', ['name' => 'config_translation']) : '#', ':language' => \Drupal::url('help.page', ['name' => 'language']), ':translation-entity' => 'https://www.drupal.org/documentation/modules/translation', ':field_help' => \Drupal::url('help.page', ['name' => 'field'])]) . '</p>'; 30 $output .= '<p>' . t('The Content Translation module allows you to translate content, comments, custom blocks, taxonomy terms, users and other <a href=":field_help" title="Field module help, with background on content entities">content entities</a>. Together with the modules <a href=":language">Language</a>, <a href=":config-trans">Configuration Translation</a>, and <a href=":locale">Interface Translation</a>, it allows you to build multilingual websites. For more information, see the <a href=":translation-entity">online documentation for the Content Translation module</a>.', [':locale' => (\Drupal::moduleHandler()->moduleExists('locale')) ? Url::fromRoute('help.page', ['name' => 'locale'])->toString() : '#', ':config-trans' => (\Drupal::moduleHandler()->moduleExists('config_translation')) ? Url::fromRoute('help.page', ['name' => 'config_translation'])->toString() : '#', ':language' => Url::fromRoute('help.page', ['name' => 'language'])->toString(), ':translation-entity' => 'https://www.drupal.org/documentation/modules/translation', ':field_help' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '</p>';
29 $output .= '<h3>' . t('Uses') . '</h3>'; 31 $output .= '<h3>' . t('Uses') . '</h3>';
30 $output .= '<dl>'; 32 $output .= '<dl>';
31 $output .= '<dt>' . t('Enabling translation') . '</dt>'; 33 $output .= '<dt>' . t('Enabling translation') . '</dt>';
32 $output .= '<dd>' . t('In order to translate content, the website must have at least two <a href=":url">languages</a>. When that is the case, you can enable translation for the desired content entities on the <a href=":translation-entity">Content language</a> page. When enabling translation you can choose the default language for content and decide whether to show the language selection field on the content editing forms.', [':url' => \Drupal::url('entity.configurable_language.collection'), ':translation-entity' => \Drupal::url('language.content_settings_page'), ':language-help' => \Drupal::url('help.page', ['name' => 'language'])]) . '</dd>'; 34 $output .= '<dd>' . t('In order to translate content, the website must have at least two <a href=":url">languages</a>. When that is the case, you can enable translation for the desired content entities on the <a href=":translation-entity">Content language</a> page. When enabling translation you can choose the default language for content and decide whether to show the language selection field on the content editing forms.', [':url' => Url::fromRoute('entity.configurable_language.collection')->toString(), ':translation-entity' => Url::fromRoute('language.content_settings_page')->toString(), ':language-help' => Url::fromRoute('help.page', ['name' => 'language'])->toString()]) . '</dd>';
33 $output .= '<dt>' . t('Enabling field translation') . '</dt>'; 35 $output .= '<dt>' . t('Enabling field translation') . '</dt>';
34 $output .= '<dd>' . t('You can define which fields of a content entity can be translated. For example, you might want to translate the title and body field while leaving the image field untranslated. If you exclude a field from being translated, it will still show up in the content editing form, but any changes made to that field will be applied to <em>all</em> translations of that content.') . '</dd>'; 36 $output .= '<dd>' . t('You can define which fields of a content entity can be translated. For example, you might want to translate the title and body field while leaving the image field untranslated. If you exclude a field from being translated, it will still show up in the content editing form, but any changes made to that field will be applied to <em>all</em> translations of that content.') . '</dd>';
35 $output .= '<dt>' . t('Translating content') . '</dt>'; 37 $output .= '<dt>' . t('Translating content') . '</dt>';
36 $output .= '<dd>' . t('If translation is enabled you can translate a content entity via the Translate tab (or Translate link). The Translations page of a content entity gives an overview of the translation status for the current content and lets you add, edit, and delete its translations. This process is similar for every translatable content entity on your site.') . '</dd>'; 38 $output .= '<dd>' . t('If translation is enabled you can translate a content entity via the Translate tab (or Translate link). The Translations page of a content entity gives an overview of the translation status for the current content and lets you add, edit, and delete its translations. This process is similar for every translatable content entity on your site.') . '</dd>';
37 $output .= '<dt>' . t('Changing the source language for a translation') . '</dt>'; 39 $output .= '<dt>' . t('Changing the source language for a translation') . '</dt>';
42 return $output; 44 return $output;
43 45
44 case 'language.content_settings_page': 46 case 'language.content_settings_page':
45 $output = ''; 47 $output = '';
46 if (!\Drupal::languageManager()->isMultilingual()) { 48 if (!\Drupal::languageManager()->isMultilingual()) {
47 $output .= '<p>' . t('Before you can translate content, there must be at least two languages added on the <a href=":url">languages administration</a> page.', [':url' => \Drupal::url('entity.configurable_language.collection')]) . '</p>'; 49 $output .= '<p>' . t('Before you can translate content, there must be at least two languages added on the <a href=":url">languages administration</a> page.', [':url' => Url::fromRoute('entity.configurable_language.collection')->toString()]) . '</p>';
48 } 50 }
49 return $output; 51 return $output;
50 } 52 }
51 } 53 }
52 54
168 $entity_type->addConstraint('ContentTranslationSynchronizedFields'); 170 $entity_type->addConstraint('ContentTranslationSynchronizedFields');
169 } 171 }
170 } 172 }
171 173
172 /** 174 /**
175 * Implements hook_ENTITY_TYPE_insert().
176 *
177 * Installs Content Translation's field storage definitions for the target
178 * entity type, if required.
179 *
180 * Also clears the bundle information cache so that the bundle's translatability
181 * will be set properly.
182 *
183 * @see content_translation_entity_bundle_info_alter()
184 * @see \Drupal\content_translation\ContentTranslationManager::isEnabled()
185 */
186 function content_translation_language_content_settings_insert(ContentLanguageSettingsInterface $settings) {
187 if ($settings->getThirdPartySetting('content_translation', 'enabled', FALSE)) {
188 _content_translation_install_field_storage_definitions($settings->getTargetEntityTypeId());
189 }
190
191 \Drupal::service('entity_type.bundle.info')->clearCachedBundles();
192 }
193
194 /**
195 * Implements hook_ENTITY_TYPE_update().
196 *
197 * Installs Content Translation's field storage definitions for the target
198 * entity type, if required.
199 *
200 * Also clears the bundle information cache so that the bundle's translatability
201 * will be changed properly.
202 *
203 * @see content_translation_entity_bundle_info_alter()
204 * @see \Drupal\content_translation\ContentTranslationManager::isEnabled()
205 */
206 function content_translation_language_content_settings_update(ContentLanguageSettingsInterface $settings) {
207 $original_settings = $settings->original;
208 if ($settings->getThirdPartySetting('content_translation', 'enabled', FALSE)
209 && !$original_settings->getThirdPartySetting('content_translation', 'enabled', FALSE)
210 ) {
211 _content_translation_install_field_storage_definitions($settings->getTargetEntityTypeId());
212 }
213 \Drupal::service('entity_type.bundle.info')->clearCachedBundles();
214 }
215
216 /**
217 * Installs Content Translation's fields for a given entity type.
218 *
219 * @param string $entity_type_id
220 * The entity type ID.
221 *
222 * @todo Generalize this code in https://www.drupal.org/node/2346013.
223 */
224 function _content_translation_install_field_storage_definitions($entity_type_id) {
225 /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
226 $field_manager = \Drupal::service('entity_field.manager');
227 /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $schema_repository */
228 $schema_repository = \Drupal::service('entity.last_installed_schema.repository');
229 $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
230
231 $field_manager->useCaches(FALSE);
232 $storage_definitions = $field_manager->getFieldStorageDefinitions($entity_type_id);
233 $field_manager->useCaches(TRUE);
234 $installed_storage_definitions = $schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
235 foreach (array_diff_key($storage_definitions, $installed_storage_definitions) as $storage_definition) {
236 /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition */
237 if ($storage_definition->getProvider() == 'content_translation') {
238 $definition_update_manager->installFieldStorageDefinition($storage_definition->getName(), $entity_type_id, 'content_translation', $storage_definition);
239 }
240 }
241 }
242
243 /**
173 * Implements hook_entity_bundle_info_alter(). 244 * Implements hook_entity_bundle_info_alter().
174 */ 245 */
175 function content_translation_entity_bundle_info_alter(&$bundles) { 246 function content_translation_entity_bundle_info_alter(&$bundles) {
176 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */ 247 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */
177 $content_translation_manager = \Drupal::service('content_translation.manager'); 248 $content_translation_manager = \Drupal::service('content_translation.manager');
197 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */ 268 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
198 $manager = \Drupal::service('content_translation.manager'); 269 $manager = \Drupal::service('content_translation.manager');
199 $entity_type_id = $entity_type->id(); 270 $entity_type_id = $entity_type->id();
200 if ($manager->isSupported($entity_type_id)) { 271 if ($manager->isSupported($entity_type_id)) {
201 $definitions = $manager->getTranslationHandler($entity_type_id)->getFieldDefinitions(); 272 $definitions = $manager->getTranslationHandler($entity_type_id)->getFieldDefinitions();
202 $installed_storage_definitions = \Drupal::entityManager()->getLastInstalledFieldStorageDefinitions($entity_type_id); 273 $installed_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions($entity_type_id);
203 // We return metadata storage fields whenever content translation is enabled 274 // We return metadata storage fields whenever content translation is enabled
204 // or it was enabled before, so that we keep translation metadata around 275 // or it was enabled before, so that we keep translation metadata around
205 // when translation is disabled. 276 // when translation is disabled.
206 // @todo Re-evaluate this approach and consider removing field storage 277 // @todo Re-evaluate this approach and consider removing field storage
207 // definitions and the related field data if the entity type has no bundle 278 // definitions and the related field data if the entity type has no bundle
248 function content_translation_entity_operation(EntityInterface $entity) { 319 function content_translation_entity_operation(EntityInterface $entity) {
249 $operations = []; 320 $operations = [];
250 if ($entity->hasLinkTemplate('drupal:content-translation-overview') && content_translation_translate_access($entity)->isAllowed()) { 321 if ($entity->hasLinkTemplate('drupal:content-translation-overview') && content_translation_translate_access($entity)->isAllowed()) {
251 $operations['translate'] = [ 322 $operations['translate'] = [
252 'title' => t('Translate'), 323 'title' => t('Translate'),
253 'url' => $entity->urlInfo('drupal:content-translation-overview'), 324 'url' => $entity->toUrl('drupal:content-translation-overview'),
254 'weight' => 50, 325 'weight' => 50,
255 ]; 326 ];
256 } 327 }
257 return $operations; 328 return $operations;
258 } 329 }
414 '#access' => $field->getFieldStorageDefinition()->isTranslatable(), 485 '#access' => $field->getFieldStorageDefinition()->isTranslatable(),
415 ]; 486 ];
416 487
417 // Provide helpful pointers for administrators. 488 // Provide helpful pointers for administrators.
418 if (\Drupal::currentUser()->hasPermission('administer content translation') && !$bundle_is_translatable) { 489 if (\Drupal::currentUser()->hasPermission('administer content translation') && !$bundle_is_translatable) {
419 $toggle_url = \Drupal::url('language.content_settings_page', [], [ 490 $toggle_url = Url::fromRoute('language.content_settings_page', [], [
420 'query' => \Drupal::destination()->getAsArray(), 491 'query' => \Drupal::destination()->getAsArray(),
421 ]); 492 ])->toString();
422 $form['translatable']['#description'] = t('To configure translation for this field, <a href=":language-settings-url">enable language support</a> for this type.', [ 493 $form['translatable']['#description'] = t('To configure translation for this field, <a href=":language-settings-url">enable language support</a> for this type.', [
423 ':language-settings-url' => $toggle_url, 494 ':language-settings-url' => $toggle_url,
424 ]); 495 ]);
425 } 496 }
426 497
436 507
437 /** 508 /**
438 * Implements hook_entity_presave(). 509 * Implements hook_entity_presave().
439 */ 510 */
440 function content_translation_entity_presave(EntityInterface $entity) { 511 function content_translation_entity_presave(EntityInterface $entity) {
441 if ($entity instanceof ContentEntityInterface && $entity->isTranslatable() && !$entity->isNew()) { 512 if ($entity instanceof ContentEntityInterface && $entity->isTranslatable() && !$entity->isNew() && isset($entity->original)) {
442 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */ 513 /** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
443 $manager = \Drupal::service('content_translation.manager'); 514 $manager = \Drupal::service('content_translation.manager');
444 if (!$manager->isEnabled($entity->getEntityTypeId(), $entity->bundle())) { 515 if (!$manager->isEnabled($entity->getEntityTypeId(), $entity->bundle())) {
445 return; 516 return;
446 }
447 // If we are creating a new translation we need to use the source language
448 // as original language, since source values are the only ones available to
449 // compare against.
450 if (!isset($entity->original)) {
451 $entity->original = \Drupal::entityTypeManager()
452 ->getStorage($entity->entityType())->loadUnchanged($entity->id());
453 } 517 }
454 $langcode = $entity->language()->getId(); 518 $langcode = $entity->language()->getId();
455 $source_langcode = !$entity->original->hasTranslation($langcode) ? $manager->getTranslationMetadata($entity)->getSource() : NULL; 519 $source_langcode = !$entity->original->hasTranslation($langcode) ? $manager->getTranslationMetadata($entity)->getSource() : NULL;
456 \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $langcode, $source_langcode); 520 \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $langcode, $source_langcode);
457 } 521 }
565 $context = $form_state->get(['language', $key]); 629 $context = $form_state->get(['language', $key]);
566 $enabled = $form_state->getValue([$key, 'content_translation']); 630 $enabled = $form_state->getValue([$key, 'content_translation']);
567 631
568 if (\Drupal::service('content_translation.manager')->isEnabled($context['entity_type'], $context['bundle']) != $enabled) { 632 if (\Drupal::service('content_translation.manager')->isEnabled($context['entity_type'], $context['bundle']) != $enabled) {
569 \Drupal::service('content_translation.manager')->setEnabled($context['entity_type'], $context['bundle'], $enabled); 633 \Drupal::service('content_translation.manager')->setEnabled($context['entity_type'], $context['bundle'], $enabled);
570 \Drupal::entityManager()->clearCachedDefinitions(); 634 \Drupal::entityTypeManager()->clearCachedDefinitions();
571 \Drupal::service('router.builder')->setRebuildNeeded(); 635 \Drupal::service('router.builder')->setRebuildNeeded();
572 } 636 }
573 } 637 }
574 638
575 /** 639 /**