Silex :允许用户通过单击 html 元素并保持清洁 URL 来更改语言

Silex : allow user to change langage by clicking on html element and keeping clean URL

我正在为网站使用 Silex 和 Twig,我希望允许用户更改网站的语言。

我的问题

现在,如果我在 URL 中更改区域设置,它会起作用:

/my-account: 我的页面内容是英文的(默认_locale)

/fr/my-account: 我的页面内容是法语

/en/my-account: 我的页面内容是英文的

如何通过单击 html 元素来执行相同的操作?

如果可能的话,我正在寻找解决我的问题的想法和一些好的做法"the right way"。

我的代码

这是我用来管理多语言的 Silex 组件:

// TRANSLATION
$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new Silex\Provider\TranslationServiceProvider());
$app->register(new \Pmaxs\Silex\Locale\Provider\LocaleServiceProvider(), [
    'locale.locales' => ['en', 'fr'],
    'locale.default_locale' => 'en',
    'locale.resolve_by_host' => false,
    'locale.exclude_routes' => ['^_']
]);
$app->extend('translator', function($translator, $app) {
    $translator->addLoader('yaml', new YamlFileLoader());

    $translator->addResource('yaml', __DIR__.'/../src/locales/en.yml', 'en');
    $translator->addResource('yaml', __DIR__.'/../src/locales/fr.yml', 'fr');

    return $translator;
});

这是我的 html 用户更改语言:

<li id="drop-langue" data-lg="en">
    <span id="current-lg">EN</span> // My current langue
    <div class="drop-langue">
        // The list of langage the user can choose : here ONE -> FR
        <div id="list_langue">
          <a class="change_langue" href="#" data-lg="fr"> <span>FR</span></a> // Could be nice to change the langue staying on the same page
        </div>
    </div>
</li>

现在我的 jQuery 得到值 :

$(document).ready(function() {
    $(".change_langue").on("click", function() {
        var new_langue = $(this).data("lg");

        $.ajax({
            url: "{{ path('new-langue') }}",
            type: 'POST',
            data: {'langue': new_langue},
            success: function (resp) {
                console.log(resp);
            },
            error: function (resp) {
                console.log(resp);
            }
        });
    });
});

我的 Ajax 控制器:

$app->match('/new-langue', function (Request $request) use ($app) {
    $new_langue = $request->get('langue');

    // some code to change the langage

    return New Response($new_langue);
})->bind('new-langue');

如果我这样做,我的 Ajax 成功 console.log(resp); 给我 en 我想要的。

关于如何做的一些想法/问题

  1. 通过 Ajax 调用是个好主意吗?
  2. 如果我在 url 中将 fr 更改为 en 它有效,尝试在 javascript 中使用 window.location.href 例如? (我觉得不是但还是问)
  3. 我看到 的另一个问题,并在我的控制器中尝试它,但我得到这个错误:500 (Internal Server Error)(我做了同样的事情,用 $new_langue 而不是 $app['defaultLanguage'] 并使用正确的主页名称)。

这是我第一次使用 Silex 创建一个完整的网站,我是 php 框架的初学者,所以如果有人可以帮助实现我想要的...提前感谢!

编辑:

根据我得到的答案和我想要实现的目标,是否可以更改语言环境并与 Silex / Twig 保持在同一页面?

例如,这给了我当前的路线:global.request.get('_route') 而这个 global.request.get('_locale') 给了我语言环境。

如果我以我的主页为例,这就是我的控制器现在的样子(我只显示模板):

$app->match('/', function (Request $request) use ($app) {
    return $app['twig']->render('home.html.twig');
})->bind('home');

如您所见,我的 URL 中没有 {_locale} 参数。 那么我可以在没有 {_locale} 的情况下保留这个 "clean URL" 并进行停留在同一页面的点击 + 更改当前语言吗?

我想做这样的事情:<a href="{{ path(global.request.get('_route')), global.request.set('_locale', 'FR') }}">FR</a>

但这肯定行不通...我可以这样做吗?

因此,从您的消息中,我可以提取您的目标是 允许在您单击 HTML 元素时更改语言

a标签的用法定义了一个hyperlink,用来link从一页到另一页,可以用来实现你想要什么。

我以前做过多语言网站,您可以通过多种方式实现。

//////////////////////////////////方法一:定义HTML 属性 href

中的位置

在您的 HTML 代码中,您使用了哈希 - # 在 hyperlink .

Hyperlinks 需要 href 属性,因为它指定了一个位置。

查看您的代码,您有标签,但缺少指向您要将用户重定向到的特定位置的 link。

假设您希望它转到 my-account 法语页面。

所以,您的 HTML 代码应该是:

<li id="drop-langue" data-lg="en">
    <span id="current-lg">EN</span> // My current langue
    <div class="drop-langue">
        // The list of langage the user can choose : here ONE -> FR
        <div id="list_langue">
          <a class="change_langue" href="http://yourwebsite.com/fr/my-account" data-lg="fr"><span>FR</span></a> 
        </div>
    </div>
</li>

注意:yourwebsite.com 替换为您网站的域名。

///////////////////////////////////方法 1 结束

在您的 HTML 代码中您提到了 // Could be nice to change the langue staying on the same page

这可以使用 AJAX 来完成,是的。

但我不建议你这样做,因为从查看也有多种语言网站的大公司来看,例如 SAP or Apple 他们都会重定向到不同的页面。

//////////////////////////////////更新: 答案until now 之所以创建是因为我认为您的需要只是允许在单击 HTML 元素时更改语言。

显然,您的目标比那个稍微复杂一些。

根据 Silex 文档,_locale 的用法是 the way to go

this question you can see working code中:

<?php

require_once __DIR__.'/../vendor/autoload.php';

$app = new Silex\Application();
$app['debug'] = true;

$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\TwigServiceProvider(), array(
    'twig.path' => __DIR__.'/../views',
));

$app->register(new Silex\Provider\TranslationServiceProvider(array(
    'locale_fallbacks' => array('hr'),
)));


$app['translator'] = $app->share($app->extend('translator', function($translator) {

    $translator->addLoader('xlf', new \Symfony\Component\Translation\Loader\XliffFileLoader());

    $translator->addResource('xlf', __DIR__.'/../locales/hr.xlf', 'hr');
    $translator->addResource('xlf', __DIR__.'/../locales/en.xlf', 'en');
    $translator->addResource('xlf', __DIR__.'/../locales/sl.xlf', 'sl');

    return $translator;
}));


$app->get('/', function () use ($app) {

    $app['translator']->setLocale('hr');

    return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));

});


$app->get('/{_locale}/', function() use ($app) {
    $app['translator']->setLocale($app['request']->get('locale'));

    return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));
});



$app->run();

在您的情况下,只需添加适当的链接以允许用户切换语言即可。其余的工作已经由您完成。语言切换器下拉列表必须包含所有支持的语言,包括英语。请参阅下面的示例图片。

您必须将用户重定向到 http://www.yourwebsite.com/language_change?lang=fr 等特殊方法,而不是将用户重定向到 http://yourwebsite.com/[fr]/my-account。您将在 $_SERVER 变量中获得 HTTP_REFERRER,这样您就可以将用户重定向回他们所在的原始页面。通过这种方式,您可以保留当前访问 page/url.

的用户

其次,Ajax vs 重定向:最好使用重定向而不是 AJAX。如果你使用 AJAX 你会增加对你自己的同谋。

在使用多语言网站时,我们必须遵循这些最佳做法。

  • 每种语言的特定路线

  • 菜单、标签和表格

  • 网站内容

  • 额外:翻译 FOSUserBundle

这里的简单想法是:您的应用程序如何确定用于呈现页面的语言。

解决方案 #1 (您当前的解决方案) 基于 URL 参数(即 _locale ) , 并在未给出 URL-parameter 的情况下回退到某个默认值。
因此在该解决方案中,翻译组件始终在路由器组件准备的参数包中查找所选语言。

解决方案 #2 将您的语言标识符放在会话变量中。 您的 /new-langue 页面必须使用它接收到的值来设置此会话变量。您的路由器将从该会话变量填充 _locale 参数。

稍后我可以提供一些代码片段。

我终于找到了一个解决方案来做我想做的事情,使用 pmaxs/silex-locale (https://github.com/pmaxs/silex-locale)。

正如我在问题中所说,我已经将它用于我的翻译,但我没有按我应该的方式使用 "Url generation"...所以这里是如何使用它的概述(阅读如果您使用 Silex v1.x):

1/加载供应商

$app->register(new \Pmaxs\Silex\Locale\Provider\LocaleServiceProvider(), [
    'locale.locales' => ['en', 'fr'],  //I want to translate my site in English and French
    'locale.default_locale' => 'en',   // By default, the locale is "en"
    'locale.resolve_by_host' => false,
    'locale.exclude_routes' => ['^_']
]);
$app->register(new Silex\Provider\LocaleServiceProvider());

2/用法

这是我的主路由控制器:

// this page is accessible by urls '/', '/fr/' or '/en/'
$app->match('/', function (Request $request) use ($app) {

    // my code

     return $app['twig']->render('home.html.twig');
})->bind('home');

如您所见,我的路由中没有 {_locale} 变量,但仍然可以使用它来更改页面的语言。

3/Url生成器

现在,这是我更改语言的方法:

{% set locale_list = ["en", "fr"] %} // the list of all langage in my website
{% set current_locale = global.request.getLocale() %} // the current langage of my page

<li id="drop-langue">
    // I display the current langage
    <span id="current-lg">{{ current_locale|upper }}</span> 
    <div class="drop-langue">
        <div id="list_langue">
            {% for locale in locale_list %}
                {% if locale != current_locale %}
                    // I create one link to change the langage according to all the langage I want, minus the current langage
                    <a class="change_langue" href="{{ locale_generate(locale , global.request.get('_route')) }}" >
                        <span>{{ locale|upper }}</span>
                    </a>
                 {% endif %}
             {% endfor %}
         </div>
     </div>
 </li>

我正在使用 "Url Generator",它的工作方式如下:locale_generate('es', $name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)(文档中有更多详细信息)。

这样,当我进入我的网站时,我的 "clean Url" / 是英语(我的默认语言环境)。然后点击 FR,我的 url 变成 /fr/,我的内容被翻译成法语,带有新的 selection 菜单(current-langue = FR,我可以 select "EN").