Lexim/Seo/etc/frontend/events.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <!-- Detect 404 page and switch store --> <!-- event controller_action_predispatch_cms_noroute_index. It will call only for 404 pages. --> <event name="controller_action_predispatch_cms_noroute_index"> <observer name="check_404_and_redirect_to_fr" instance="Lexim\Seo\Observer\NotFoundRedirectHandler" /> </event> </config>
Lexim/Seo/Observer/NotFoundRedirectHandler.php
<?php declare(strict_types=1); namespace Lexim\Seo\Observer; use Magento\Framework\App\ActionFlag; use Magento\Framework\App\ActionInterface; use Magento\Framework\App\Request\Http; use Magento\Framework\App\ResponseInterface; use Magento\Framework\App\Http\Context as HttpContext; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Api\StoreCookieManagerInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; /** * Class NotFoundRedirectHandler * * @package Lexim\Seo\Observer */ class NotFoundRedirectHandler implements ObserverInterface { /** @var ResponseInterface */ private $_responseInterface; /** @var Http */ private $_request; /** @var ActionFlag */ private $_actionFlag; /** @var StoreManagerInterface */ private $_storeManagerInterface; /** @var UrlFinderInterface */ private $_urlFinder; /** @var HttpContext */ private $_httpContext; /** @var StoreCookieManagerInterface */ private $_storeCookieManager; /** * NotFoundRedirectHandler constructor. * * @param Http $request * @param ActionFlag $actionFlag * @param ResponseInterface $responseInterface * @param StoreManagerInterface $_storeManagerInterface * @param UrlFinderInterface $_urlFinder * @param HttpContext $_httpContext * @param StoreCookieManagerInterface $_storeCookieManager */ public function __construct( Http $request, ActionFlag $actionFlag, ResponseInterface $responseInterface, StoreManagerInterface $_storeManagerInterface, UrlFinderInterface $_urlFinder, HttpContext $_httpContext, StoreCookieManagerInterface $_storeCookieManager, ) { $this->_request = $request; $this->_actionFlag = $actionFlag; $this->_responseInterface = $responseInterface; $this->_storeManagerInterface = $_storeManagerInterface; $this->_urlFinder = $_urlFinder; $this->_httpContext = $_httpContext; $this->_storeCookieManager = $_storeCookieManager; } /** * @param Observer $observer * * @return void */ public function execute(Observer $observer) { $getFullActionName = $this->_request->getFullActionName(); // _noroute_index, cms_noroute_index $getRequestString = $this->_request->getRequestString(); // "/what-is-adaptive-clothing-fr" $getRequestString = ltrim($getRequestString, "/"); $isAjax = intval($this->_request->isAjax()); // 0, 1 $storeCode = $this->getCurrentStoreCode(); if ( in_array($getFullActionName, ['cms_noroute_index', '_noroute_index']) && $isAjax == 0 && $storeCode === 'english' ) { $allStores = $this->getAllStores(); $frenchCode = 'french'; $frenchStore = $allStores[$frenchCode] ?? null; if ($frenchStore) { $frenchId = $frenchStore->getId(); $frRewrite = $this->findOneData($getRequestString, $frenchId); if ($frRewrite) { // Switch CA Store from english to french $this->_httpContext->setValue('store', $frenchCode, $frenchCode); $this->_storeCookieManager->setStoreCookie($frenchStore); // Prevent the default action from being executed $this->_actionFlag->set('', ActionInterface::FLAG_NO_DISPATCH, true); // Redirect to the current URL in french $this->_responseInterface->setRedirect($getRequestString); } } } } /** * @param $requestPath * @param $storeId * * @return UrlRewrite|null */ protected function findOneData($requestPath, $storeId) { return $this->_urlFinder->findOneByData( [ UrlRewrite::REQUEST_PATH => $requestPath, UrlRewrite::STORE_ID => $storeId ] ); } /** * @return StoreInterface[] */ protected function getAllStores(): array { $stores = $this->_storeManagerInterface->getStores(true, true); if (isset($stores['admin'])) { // remove admin store unset($stores['admin']); } return $stores; } /** * @return string * @throws NoSuchEntityException */ protected function getCurrentStoreCode(): string { $curStore = $this->getCurrentStore(); return $curStore->getCode(); // english, french, us } /** * @return StoreInterface * @throws NoSuchEntityException */ protected function getCurrentStore() { return $this->_storeManagerInterface->getStore(); } }