Symfony 3,检测浏览器语言

sim*_*100 4 browser lang symfony

我使用Symfony 3.我的网站有两种语言,法语和英语,人们可以通过选择表单切换.默认语言是法语.主要URL是:example.com/fr用于法语版,example.com/en用于英语版

那么,现在,我想在用户到达网站时检测他的浏览器语言并自动重定向到正确的语言.例如,如果浏览器是法语,则会被重定向到法语版本:example.com/fr Else他被重定向到英文版本:example.com/en

有没有办法正确地做到这一点?

谢谢您的帮助

dbr*_*ann 9

如果您不想依赖JMSI18nRoutingBundle 等其他捆绑包,您必须熟悉Symfony的Event系统,例如通过阅读HttpKernel.

对于您的情况,您想要参与kernel.request活动.

典型目的:向Request添加更多信息,初始化系统的各个部分,或者尽可能返回Response(例如,拒绝访问的安全层).

在自定义EventListener中,您可以侦听该事件,将信息添加到路由器中使用的Request-object.它可能看起来像这样:

class LanguageListener implements EventSubscriberInterface
{
    private $supportedLanguages;

    public function __construct(array $supportedLanguages)
    {
        if (empty($supportedLanguages)) {
            throw new \InvalidArgumentException('At least one supported language must be given.');
        }

        $this->supportedLanguages = $supportedLanguages;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::REQUEST  => ['redirectToLocalizedHomepage', 100],
        ];
    }

    public function redirectToLocalizedHomepage(GetResponseEvent $event)
    {
        // Do not modify sub-requests
        if (KernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
            return;
        }
        // Assume all routes except the frontpage use the _locale parameter
        if ($event->getRequest()->getPathInfo() !== '/') {
            return;
        }

        $language = $this->supportedLanguages[0];
        if (null !== $acceptLanguage = $event->getRequest()->headers->get('Accept-Language')) {
            $negotiator = new LanguageNegotiator();
            $best       = $negotiator->getBest(
                $event->getRequest()->headers->get('Accept-Language'),
                $this->supportedLanguages
            );

            if (null !== $best) {
                $language = $best->getType();
            }
        }

        $response = new RedirectResponse('/' . $language);
        $event->setResponse($response);
    }
}
Run Code Online (Sandbox Code Playgroud)

此侦听器将检查Accept-Language请求的标头,并使用Negotiation\LanguageNegotiator确定最佳区域设置.小心,因为我没有添加use语句,但它们应该相当明显.

对于更高级的版本,您只需从JMSI18nRoutingBundle 读取LocaleChoosingListener的源代码即可.

通常只对首页执行此操作,这就是我发布的示例和JMSBundle中的示例都排除所有其他路径的原因.对于那些您可以使用_locale文档中描述的特殊参数:

https://symfony.com/doc/current/translation/locale.html#the-locale-and-the-url

Symfony文档还包含一个示例,说明如何使用监听器读取语言环境并使其在会话中粘滞:https://symfony.com/doc/current/session/locale_sticky_session.html 此示例还说明了如何在以下位置注册监听器你的services.yml.

  • 很好的答案!在 Symfony 4 中,`GetResponseEvent` 已被弃用,请使用 `RequestEvent` 代替。 (3认同)
  • 抱歉,省略了这一点。完整的类名是`\Negotiation\LanguageNegotiator`。这不是 Symfony 的一部分,而是来自 3rd 方库。您可以使用`willdurand/negotiation`(通过composer)与作曲家一起要求它。请参阅:https://packagist.org/packages/willdurand/negotiation 和 https://williamdurand.fr/Negotiation/ (2认同)