JMSI18nRoutingBundle可以使用HTTP Accept-Language数组吗?

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进行智能重定向,以尊重用户最喜欢的语言或让用户强制显示语言.看我的回答.

Mor*_*ing 6

最后,我回答我的问题。

我开发了一个小“补丁”,它使用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)

在 HTTP 内核上绑定您的侦听器。

编辑您的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)