function ContentTranslationController::overview

Same name in other branches
  1. 9 core/modules/content_translation/src/Controller/ContentTranslationController.php \Drupal\content_translation\Controller\ContentTranslationController::overview()
  2. 8.9.x core/modules/content_translation/src/Controller/ContentTranslationController.php \Drupal\content_translation\Controller\ContentTranslationController::overview()
  3. 11.x core/modules/content_translation/src/Controller/ContentTranslationController.php \Drupal\content_translation\Controller\ContentTranslationController::overview()

Builds the translations overview page.

Parameters

\Drupal\Core\Routing\RouteMatchInterface $route_match: The route match.

string $entity_type_id: (optional) The entity type ID.

Return value

array Array of page elements to render.

File

core/modules/content_translation/src/Controller/ContentTranslationController.php, line 137

Class

ContentTranslationController
Base class for entity translation controllers.

Namespace

Drupal\content_translation\Controller

Code

public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL) {
    
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $route_match->getParameter($entity_type_id);
    $account = $this->currentUser();
    $handler = $this->entityTypeManager()
        ->getHandler($entity_type_id, 'translation');
    $manager = $this->manager;
    $entity_type = $entity->getEntityType();
    $use_latest_revisions = $entity_type->isRevisionable() && ContentTranslationManager::isPendingRevisionSupportEnabled($entity_type_id, $entity->bundle());
    // Start collecting the cacheability metadata, starting with the entity and
    // later merge in the access result cacheability metadata.
    $cacheability = CacheableMetadata::createFromObject($entity);
    $languages = $this->languageManager()
        ->getLanguages();
    $original = $entity->getUntranslated()
        ->language()
        ->getId();
    $translations = $entity->getTranslationLanguages();
    $field_ui = $this->moduleHandler()
        ->moduleExists('field_ui') && $account->hasPermission('administer ' . $entity_type_id . ' fields');
    $rows = [];
    $show_source_column = FALSE;
    
    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
    $storage = $this->entityTypeManager()
        ->getStorage($entity_type_id);
    $default_revision = $storage->load($entity->id());
    if ($this->languageManager()
        ->isMultilingual()) {
        // Determine whether the current entity is translatable.
        $translatable = FALSE;
        foreach ($this->entityFieldManager
            ->getFieldDefinitions($entity_type_id, $entity->bundle()) as $instance) {
            if ($instance->isTranslatable()) {
                $translatable = TRUE;
                break;
            }
        }
        // Show source-language column if there are non-original source langcodes.
        $additional_source_langcodes = array_filter(array_keys($translations), function ($langcode) use ($entity, $original, $manager) {
            $source = $manager->getTranslationMetadata($entity->getTranslation($langcode))
                ->getSource();
            return $source != $original && $source != LanguageInterface::LANGCODE_NOT_SPECIFIED;
        });
        $show_source_column = !empty($additional_source_langcodes);
        foreach ($languages as $language) {
            $language_name = $language->getName();
            $langcode = $language->getId();
            // If the entity type is revisionable, we may have pending revisions
            // with translations not available yet in the default revision. Thus we
            // need to load the latest translation-affecting revision for each
            // language to be sure we are listing all available translations.
            if ($use_latest_revisions) {
                $entity = $default_revision;
                $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $langcode);
                if ($latest_revision_id) {
                    
                    /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */
                    $latest_revision = $storage->loadRevision($latest_revision_id);
                    // Make sure we do not list removed translations, i.e. translations
                    // that have been part of a default revision but no longer are.
                    if (!$latest_revision->wasDefaultRevision() || $default_revision->hasTranslation($langcode)) {
                        $entity = $latest_revision;
                    }
                }
                $translations = $entity->getTranslationLanguages();
            }
            $options = [
                'language' => $language,
            ];
            $add_url = $entity->toUrl('drupal:content-translation-add', $options)
                ->setRouteParameter('source', $original)
                ->setRouteParameter('target', $language->getId());
            $edit_url = $entity->toUrl('drupal:content-translation-edit', $options)
                ->setRouteParameter('language', $language->getId());
            $delete_url = $entity->toUrl('drupal:content-translation-delete', $options)
                ->setRouteParameter('language', $language->getId());
            $operations = [
                'data' => [
                    '#type' => 'operations',
                    '#links' => [],
                ],
            ];
            $links =& $operations['data']['#links'];
            if (array_key_exists($langcode, $translations)) {
                // Existing translation in the translation set: display status.
                $translation = $entity->getTranslation($langcode);
                $metadata = $manager->getTranslationMetadata($translation);
                $source = $metadata->getSource() ?: LanguageInterface::LANGCODE_NOT_SPECIFIED;
                $is_original = $langcode == $original;
                $label = $entity->getTranslation($langcode)
                    ->label() ?? $entity->id();
                $link = [
                    'url' => $entity->toUrl(),
                ];
                if (!empty($link['url'])) {
                    $link['url']->setOption('language', $language);
                    $row_title = Link::fromTextAndUrl($label, $link['url'])->toString();
                }
                if (empty($link['url'])) {
                    $row_title = $is_original ? $label : $this->t('n/a');
                }
                // If the user is allowed to edit the entity we point the edit link to
                // the entity form, otherwise if we are not dealing with the original
                // language we point the link to the translation form.
                $update_access = $entity->access('update', NULL, TRUE);
                $translation_access = $handler->getTranslationAccess($entity, 'update');
                $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($update_access))
                    ->merge(CacheableMetadata::createFromObject($translation_access));
                if ($update_access->isAllowed() && $entity_type->hasLinkTemplate('edit-form')) {
                    $links['edit']['url'] = $entity->toUrl('edit-form');
                    $links['edit']['language'] = $language;
                }
                elseif (!$is_original && $translation_access->isAllowed()) {
                    $links['edit']['url'] = $edit_url;
                }
                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(),
                        ],
                    ],
                ];
                if ($is_original) {
                    $language_name = $this->t('<strong>@language_name (Original language)</strong>', [
                        '@language_name' => $language_name,
                    ]);
                    $source_name = $this->t('n/a');
                }
                else {
                    
                    /** @var \Drupal\Core\Access\AccessResultInterface $delete_route_access */
                    $delete_route_access = \Drupal::service('content_translation.delete_access')->checkAccess($translation);
                    $cacheability->addCacheableDependency($delete_route_access);
                    if ($delete_route_access->isAllowed()) {
                        $source_name = isset($languages[$source]) ? $languages[$source]->getName() : $this->t('n/a');
                        $delete_access = $entity->access('delete', NULL, TRUE);
                        $translation_access = $handler->getTranslationAccess($entity, 'delete');
                        $cacheability->addCacheableDependency($delete_access)
                            ->addCacheableDependency($translation_access);
                        if ($delete_access->isAllowed() && $entity_type->hasLinkTemplate('delete-form')) {
                            $links['delete'] = [
                                'title' => $this->t('Delete'),
                                'url' => $entity->toUrl('delete-form'),
                                'language' => $language,
                            ];
                        }
                        elseif ($translation_access->isAllowed()) {
                            $links['delete'] = [
                                'title' => $this->t('Delete'),
                                'url' => $delete_url,
                            ];
                        }
                    }
                    else {
                        $this->messenger()
                            ->addWarning($this->t('The "Delete translation" action is only available for published translations.'), FALSE);
                    }
                }
            }
            else {
                // No such translation in the set yet: help user to create it.
                $row_title = $source_name = $this->t('n/a');
                $source = $entity->language()
                    ->getId();
                $create_translation_access = $handler->getTranslationAccess($entity, 'create');
                $cacheability = $cacheability->merge(CacheableMetadata::createFromObject($create_translation_access));
                if ($source != $langcode && $create_translation_access->isAllowed()) {
                    if ($translatable) {
                        $links['add'] = [
                            'title' => $this->t('Add'),
                            'url' => $add_url,
                        ];
                    }
                    elseif ($field_ui) {
                        $url = new Url('language.content_settings_page');
                        // Link directly to the fields tab to make it easier to find the
                        // setting to enable translation on fields.
                        $links['nofields'] = [
                            'title' => $this->t('No translatable fields'),
                            'url' => $url,
                        ];
                    }
                }
                $status = $this->t('Not translated');
            }
            if ($show_source_column) {
                $rows[] = [
                    $language_name,
                    $row_title,
                    $source_name,
                    $status,
                    $operations,
                ];
            }
            else {
                $rows[] = [
                    $language_name,
                    $row_title,
                    $status,
                    $operations,
                ];
            }
        }
    }
    if ($show_source_column) {
        $header = [
            $this->t('Language'),
            $this->t('Translation'),
            $this->t('Source language'),
            $this->t('Status'),
            $this->t('Operations'),
        ];
    }
    else {
        $header = [
            $this->t('Language'),
            $this->t('Translation'),
            $this->t('Status'),
            $this->t('Operations'),
        ];
    }
    $build['#title'] = $this->t('Translations of %label', [
        '%label' => $entity->label() ?? $entity->id(),
    ]);
    // Add metadata to the build render array to let other modules know about
    // which entity this is.
    $build['#entity'] = $entity;
    $cacheability->addCacheTags($entity->getCacheTags())
        ->applyTo($build);
    $build['content_translation_overview'] = [
        '#theme' => 'table',
        '#header' => $header,
        '#rows' => $rows,
    ];
    return $build;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.