Mor*_*ing 6 internationalization symfony
我正在尝试建立一个国际化的网站,我翻译的每种语言都有一个URL前缀(例如./fr/my/page或/it/my/page).
我尝试了JMSI18nRoutingBundle,它几乎没有其他配置,效果很好.但我真的想自动确定用户首选语言.用户最喜欢的语言被传输到Accept-LanguageHTTP标头,我想选择我翻译的第一种语言.
这是我的JMSI18nRouting配置:
jms_i18n_routing:
default_locale: en
locales: [fr, en]
strategy: prefix_except_default
Run Code Online (Sandbox Code Playgroud)
我想要这种行为:
http://mywebsite.com/my/page执行自动语言检测,然后重定向到/xx/...(xx用户喜欢的语言),因为URL中未指定语言 - 目前默认语言为EN.
http://mywebsite.com/XX/my/page 以XX语言显示页面 - 目前,工作正常.
有没有想过这样做?配置好吗?
哦,如果有人有解决方案在纯Symfony中做同样的事情(没有JMSI18nRoutingBundle),我的耳朵是敞开的.
编辑/找到一种方法,使用JMSI18nRoutingBundle进行智能重定向,以尊重用户最喜欢的语言或让用户强制显示语言.看我的回答.
最后,我回答我的问题。
我开发了一个小“补丁”,它使用JMSI18nRoutingBundle 并检测用户的首选语言,还让用户强制使用一种语言。
YourBundle/EventListener/LocaleListener.php如果用户的首选语言环境与 Symfony 或 JMSI18nRoutingBundle 定义的语言环境不同,则此侦听器将更改 URL。通过这种方式,您有两种不同语言的两种不同内容的两个 URL:它对 SEO 友好。
您还可以创建的链接组成的语言选择hrefing到?setlang=xx哪里xx是用户想要显示的语言。侦听器将检测setlang查询并强制显示xxlang,包括在下一个请求中。
注意$this->translatable = [...数组。它让您定义网站的哪些部分是翻译/可翻译的。可以从供应商到操作方法定义粒度。您还可以创建一个配置节点来定义您的可翻译供应商/捆绑包/控制器,出于性能考虑,我没有这样做。
<?php
namespace YourVendor\YourBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleListener implements EventSubscriberInterface
{
private $defaultLocale;
private $acceptedLocales;
private $translatable;
public function __construct($router, $defaultLocale, $acceptedLocales)
{
$this->router = $router;
$this->defaultLocale = $defaultLocale;
$this->acceptedLocales = $acceptedLocales;
$this->translatable = [
'Vendor1',
'Vendor2\Bundle1',
'Vendor2\Bundle2\Controller1',
'Vendor2\Bundle2\Controller2::myPageAction',
];
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$route = $request->get('_route');
if(!empty($newLocale = $request->query->get('setlang'))) {
if(in_array($newLocale, $this->acceptedLocales)) {
$cookie = new Cookie('force_lang', $newLocale, time() + 3600 * 24 * 7);
$url = $this->router->generate($route, ['_locale' => $newLocale] + $request->attributes->get('_route_params'));
$response = new RedirectResponse($url);
$response->headers->setCookie($cookie);
$event->setResponse($response);
}
} else if($this->translatable($request->attributes->get('_controller'))) {
$preferred = empty($force = $request->cookies->get('force_lang')) ? $request->getPreferredLanguage($this->acceptedLocales) : $force;
if($preferred && $request->attributes->get('_locale') != $preferred) {
$url = $this->router->generate($route, ['_locale' => $preferred] + $request->attributes->get('_route_params'));
$event->setResponse(new RedirectResponse($url));
}
}
}
private function translatable($str)
{
foreach($this->translatable as $t) {
if(strpos($str, $t) !== false) return true;
}
return false;
}
public static function getSubscribedEvents()
{
return [ KernelEvents::REQUEST => [['onKernelRequest', 200]] ];
}
}
Run Code Online (Sandbox Code Playgroud)
编辑您的services.yml文件。
services:
app.event_listener.locale_listener:
class: YourVendor\YourBundle\EventListener\LocaleListener
arguments: ["@router", "%kernel.default_locale%", "%jms_i18n_routing.locales%"]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Run Code Online (Sandbox Code Playgroud)
JMSI18nRoutingBundle你没有什么可以改变的。例子:
# JMS i18n Routing Configuration
jms_i18n_routing:
default_locale: "%locale%"
locales: [fr, en]
strategy: prefix_except_default
Run Code Online (Sandbox Code Playgroud)