首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Symfony 3,检测浏览器语言

Symfony 3,检测浏览器语言
EN

Stack Overflow用户
提问于 2017-09-03 09:59:55
回答 2查看 6.2K关注 0票数 5

我使用Symfony 3。我的网站是两种语言,法语和英语,人们可以通过选择的形式切换。默认语言是法语。主要网址是: example.com/fr为法文本,example.com/en为英文版

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

有什么办法能做到这一点吗?

谢谢你的帮助

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-09-03 13:36:18

如果您不想依赖像JMSI18nRoutingBundle这样的其他包,那么您必须熟悉Symfony的事件系统,例如阅读HttpKernel

对于您的情况,您希望连接到kernel.request事件。

典型用途:向请求添加更多信息,初始化系统的部分,或在可能的情况下返回响应(例如拒绝访问的安全层)。

在您的自定义EventListener中,您可以侦听该事件,向路由器中使用的请求对象添加信息。它可能看起来像这样:

代码语言:javascript
复制
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);
    }
}

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

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

通常只需要对frontpage执行此操作,这就是为什么我发布的示例和JMSBundle中的示例都排除了所有其他路径的原因。对于这些用户,您只需使用文档中描述的特殊参数_locale

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

Symfony文档还包含一个示例,如何使用侦听器读取区域设置并使其在会话中粘稠:session.html --这个示例还展示了如何在services.yml中注册侦听器。

票数 13
EN

Stack Overflow用户

发布于 2021-12-13 22:45:35

对@dbrumann回答使用我的用例和设置所做的轻微更改:

可用区域设置列表在services.yml文件中定义:

代码语言:javascript
复制
parameters:
  available_locales:
    - nl
    - en
    - cs

我想在网站的任何登陆页面上确定地点。如果解析失败,则返回到_locale参数或默认参数。

代码语言:javascript
复制
class LocaleDetermineSubscriber implements EventSubscriberInterface
{
    private $defaultLocale;
    private $parameterBag;
    private $logger;

    public function __construct(ParameterBagInterface $parameterBag,
       LoggerInterface $logger, 
       $defaultLocale = 'en')
    {
        $this->defaultLocale = $defaultLocale;
        $this->parameterBag = $parameterBag;
        $this->logger = $logger;
    }

    public function onKernelRequest(RequestEvent $event)
    {
        $request = $event->getRequest();
        //do this on first request only
        if ($request->hasPreviousSession()) {
            return;
        }

        $allowedLocales = $this->parameterBag->get('available_locales'); //defined in services.yml
        $determinedLocale = null;

        // use locale from the user preference header
        $acceptLanguage = $event->getRequest()->headers->get('Accept-Language');
        if ($acceptLanguage != null) {
            $negotiator = new LanguageNegotiator();
            try {
                $best = $negotiator->getBest($acceptLanguage, $allowedLocales);

                if ($best != null) {
                    $language = $best->getType();
                    $request->setLocale($language);
                    $determinedLocale = $language;
                }
            } catch (Exception $e) {
                $this->logger->warning("Failed to determine language from Accept-Language header " . $e);
            }
        }

        //check if locale is set with _locale parameter if user preference header parsing not happened
        if($determinedLocale == null) {
            if ($locale = $request->attributes->get('_locale')) {
                if(in_array($locale, $allowedLocales)) {
                    $request->getSession()->set('_locale', $locale);
                } else {
                    $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
                }
            } else {
                //fallback to default
                $request->setLocale($this->defaultLocale);
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            // must be registered before (i.e. with a higher priority than) the default Locale listener
            KernelEvents::REQUEST => [['onKernelRequest', 25]],
        ];
    }
}

它使用了威尔杜兰特/协商包,因此需要首先安装:

代码语言:javascript
复制
composer require willdurand/negotiation

https://packagist.org/packages/willdurand/negotiation

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46022235

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档