Я пытаюсь реализовать перевод на основе URL в Zend Framework, чтобы мой сайт был оптимизирован для SEO. Это означает, что мне нужны URL-адреса, подобные приведенным ниже, в дополнение к маршрутам по умолчанию.
zend.local/en/module zend.local/en/controller zend.local/en/module/controller zend.local/en/controller/action
Выше были те, с которыми у меня сейчас проблемы; остальное должно быть в порядке. Я добавил плагин контроллера, который извлекает параметр lang
чтобы я мог установить язык и объект перевода в методе preDispatch
. Вот некоторые из моих маршрутов (хранятся в файле .ini):
; Language + module ; Language + controller resources.router.routes.lang1.type = "Zend_Controller_Router_Route_Regex" resources.router.routes.lang1.route = "(^[a-zA-Z]{2})/(\w+$)" resources.router.routes.lang1.defaults.controller = index resources.router.routes.lang1.defaults.action = index resources.router.routes.lang1.map.1 = "lang" resources.router.routes.lang1.map.2 = "module" ; Language + module + controller ; Language + controller + action resources.router.routes.lang2.type = "Zend_Controller_Router_Route_Regex" resources.router.routes.lang2.route = "(^[a-zA-Z]{2})/(\w+)/(\w+$)" resources.router.routes.lang2.defaults.module = default resources.router.routes.lang2.defaults.action = index resources.router.routes.lang2.map.1 = "lang" resources.router.routes.lang2.map.2 = "controller" resources.router.routes.lang2.map.3 = "action"
Как видно из комментариев, несколько структур URL будут соответствовать одному и тому же маршруту, что делает мое приложение неверным образом интерпретирует формат. Например, следующие два URL-адреса будут сопоставляться маршрутом lang1
:
zend.local/en/mymodule zend.local/en/mycontroller
В первом URL-адресе «mymodule» используется как имя модуля, что является правильным. Однако во втором URL-адресе «mycontroller» используется как имя модуля, чего я не хочу. Здесь я хочу, чтобы он использовал модуль «default» и «mycontroller» в качестве контроллера. То же самое относится к предыдущему маршруту lang2
. Поэтому я не знаю, как различать, является ли URL-адрес структуры /en/module
или /en/controller
.
Чтобы исправить это, я экспериментировал с кодом ниже в моем плагине контроллера.
// Get module names as array $dirs = Zend_Controller_Front::getInstance()->getControllerDirectory(); $modules = array_keys($dirs); // Module variable contains a module that does not exist if (!in_array($request->getModuleName(), $modules)) { // Try to use it as controller name instead $request->setControllerName($request->getModuleName()); $request->setModuleName('default'); }
по// Get module names as array $dirs = Zend_Controller_Front::getInstance()->getControllerDirectory(); $modules = array_keys($dirs); // Module variable contains a module that does not exist if (!in_array($request->getModuleName(), $modules)) { // Try to use it as controller name instead $request->setControllerName($request->getModuleName()); $request->setModuleName('default'); }
Это хорошо работает в сценариях, которые я тестировал, но тогда мне пришлось бы сделать что-то подобное, чтобы сделать lang2
маршрута lang2
(что, возможно, включает в себя сканирование каталогов для получения списка контроллеров). Это похоже на плохое решение, поэтому, если это возможно, я бы хотел выполнить все это только с помощью маршрутов (или простого кода, который не так «взломан»). Я мог бы также создавать маршруты для каждого раза, когда я хочу /en/controller
, например, но это компромисс, который я бы предпочел не использовать. Итак, если кто-нибудь знает, как это решить, или знать другой подход, чтобы выполнить одно и то же, я все уши!
Я воспроизвел вашу проблему здесь и выхожу со следующим (не используя файлы конфигурации):
/** * Initializes the router * @return Zend_Controller_Router_Interface */ protected function _initRouter() { $locale = Zend_Registry::get('Zend_Locale'); $routeLang = new Zend_Controller_Router_Route( ':lang', array( 'lang' => $locale->getLanguage() ), array('lang' => '[az]{2}_?([az]{2})?') ); $frontController = Zend_Controller_Front::getInstance(); $router = $frontController->getRouter(); // Instantiate default module route $routeDefault = new Zend_Controller_Router_Route_Module( array(), $frontController->getDispatcher(), $frontController->getRequest() ); // Chain it with language route $routeLangDefault = $routeLang->chain($routeDefault); // Add both language route chained with default route and // plain language route $router->addRoute('default', $routeLangDefault); // Register plugin to handle language changes $frontController->registerPlugin(new Plugin_Language()); return $router; }
/** * Language controller plugin */ class Plugin_Language extends Zend_Controller_Plugin_Abstract { /** * @var array The available languages */ private $languages = array('en', 'pt'); /** * Check the URI before starting the route process * @param Zend_Controller_Request_Abstract $request */ public function routeStartup(Zend_Controller_Request_Abstract $request) { $translate = Zend_Registry::get('Zend_Translate'); $lang = $translate->getLocale(); // Extracts the URI (part of the URL after the project public folder) $uri = str_replace($request->getBaseUrl() . '/', '', $request->getRequestUri()); $langParam = substr($uri, 0, 3); // Fix: Checks if the language was specified (if not, set it on the URI) if((isset($langParam[2]) && $langParam[2] !== '/') || !in_array(substr($langParam, 0, 2), $this->languages)) { { $request->setRequestUri($request->getBaseUrl() . '/' . $lang . "/" . $uri); $request->setParam('lang', $lang); } } }
В принципе, существует цепочка маршрутов для применения языковых настроек в маршруте по умолчанию модуля. В качестве исправления мы гарантируем, что URI будет содержать язык, если пользователь оставит его.
Вам нужно будет его адаптировать, поскольку я использую Zend_Registry::get('Zend_Locale')
и Zend_Registry::get('Zend_Translate')
. Измените его на фактические ключи приложения.
Что касается маршрута lang: [az]{2}_?([az]{2})?
это позволит использовать такие языки, как pt_BR
: pt_BR
Дайте мне знать, если это сработает для вас.