diff --git a/packages/drupal/custom/src/EventSubscriber/EntityLanguageRedirectSubscriber.php b/packages/drupal/custom/src/EventSubscriber/EntityLanguageRedirectSubscriber.php index 63016e2af..92d194316 100644 --- a/packages/drupal/custom/src/EventSubscriber/EntityLanguageRedirectSubscriber.php +++ b/packages/drupal/custom/src/EventSubscriber/EntityLanguageRedirectSubscriber.php @@ -36,6 +36,28 @@ public static function getSubscribedEvents() { } public function onKernelRequest(RequestEvent $event): void { + $redirect = $this->getMissingDefaultRevisionRedirect($event) + ?? $this->getMissingTranslationRedirect($event); + if ($redirect) { + // Add the necessary cache contexts to the response, as redirect + // responses are cached as well. + $metadata = new CacheableMetadata(); + $metadata->addCacheContexts([ + 'languages:language_interface', + 'url.query_args', + 'user', + ]); + $redirect->addCacheableDependency($metadata); + if ($this->routeMatch->getRouteName() === 'entity.node.canonical') { + $node = $this->routeMatch->getCurrentRouteMatch()->getParameter('node'); + $redirect->addCacheableDependency($node); + } + + $event->setResponse($redirect); + } + } + + private function getMissingTranslationRedirect(RequestEvent $event): ?TrustedRedirectResponse { // In case the user tries to access a node in a language entity is not // translated to, we redirect to the entity in the original language and // display a warning message. @@ -57,16 +79,43 @@ public function onKernelRequest(RequestEvent $event): void { } $urlString = $url->toString() . '?' . $queryString . 'content_language_not_available=true&requested_language=' . $requestedLanguageId; - // Add the necessary cache contexts to the response, as redirect - // responses are cached as well. - $metadata = new CacheableMetadata(); - $metadata->addCacheContexts(['languages:language_interface', 'url.query_args']); - $response = new TrustedRedirectResponse($urlString); - $response->addCacheableDependency($entity); - $response->addCacheableDependency($metadata); + return new TrustedRedirectResponse($urlString); + } + } - $event->setResponse($response); + return NULL; + } + + private function getMissingDefaultRevisionRedirect(RequestEvent $event): ?TrustedRedirectResponse { + // This spaghetti code detects if user is trying to view a translation that + // is a draft only and does not have a published revision on the canonical + // route. + // Why do we do it: The content translation overview page links to + // `/{lang}/node/{nid}`, but in the case mentioned above, the canonical + // route displays the content in the original language. Which is quite + // confusing. + if ($this->routeMatch->getRouteName() === 'entity.node.canonical') { + $entity = $this->routeMatch->getCurrentRouteMatch()->getParameter('node'); + $requestedLanguageId = $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId(); + if ($entity->language()->getId() != $requestedLanguageId) { + $storage = \Drupal::entityTypeManager()->getStorage('node'); + $latestRevisionId = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $requestedLanguageId); + if ($latestRevisionId) { + /** @var \Drupal\Core\Entity\ContentEntityInterface $latestRevision */ + $latestRevision = $storage->loadRevision($latestRevisionId); + $translations = $latestRevision->getTranslationLanguages(); + if (array_key_exists($requestedLanguageId, $translations)) { + $latestRevision = $latestRevision->getTranslation($requestedLanguageId); + // Bingo! We found the target case. Redirect to the latest revision. + if ($latestRevision->access('view')) { + $url = $latestRevision->toUrl('latest-version')->toString(); + return new TrustedRedirectResponse($url); + } + } + } } } + return NULL; } + }