可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am using Silex and Twig for a website and I want to allow the user to change the langage of the site.
My problem
Right now, it works if I change the locale in the URL :
/my-account
: my page content is in English (default _locale)
/fr/my-account
: my page content is in French
/en/my-account
: my page content is in English
How can I do the do the same by clicking on an html element?
I am looking for some idea to solve my problem and some good practice to do this "the right way" if possible.
My code
Here is the Silex component I use to manage the multilangue :
// 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;
});
Here is my html for the user to change the langage:
<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>
Now my jQuery to get the value :
$(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);
}
});
});
});
My Ajax controller :
$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');
If I do this, my Ajax success console.log(resp);
give me en
as I want.
Some ideas / questions about how to do it
- Is it a good idea to do it with an Ajax call?
- If I change
fr
by en
in my url it works, is it a good idea to try to do it in javascript using window.location.href
for example? (I think not but still asking)
- I saw this solution for an other problem and try it in my controller but I get this error :
500 (Internal Server Error)
(I did the same, with $new_langue
instead of $app['defaultLanguage']
and with the right name for my homepage).
It's the first time I create a full website with Silex and I'm beginner with php framework so if someone can help to achieve what I want...thanks by advance !
EDIT :
According to the anwser I get and what I want to achieve, is it possible to change the locale and staying in the same page with Silex / Twig?
For example, this give me the current route : global.request.get('_route')
and this global.request.get('_locale')
give me the locale.
If I take the example of my Home Page, this is how my controller look right now (I just show the template) :
$app->match('/', function (Request $request) use ($app) {
return $app['twig']->render('home.html.twig');
})->bind('home');
As you can see, I have no {_locale} param in my URL. So can I keep this "clean URL" without the {_locale} and make a click that stay in the same page + change the current langage?
I'd like to make somehting like this : <a href="{{ path(global.request.get('_route')), global.request.set('_locale', 'FR') }}">FR</a>
But it won't work for sure...can I do this?
回答1:
So, from your message, i can extract your goal is to allow the language to be changed when you click on an HTML element.
The usage of the a tag defines a hyperlink, which is used to link from one page to another and can be used to achieve what you want.
I've done multilang sites previously and you can achieve this in a variety of ways.
///////////////////////////////Method 1: define the location in the HTML attribute href
In your HTML code you've used hash - # within the hyperlink .
Hyperlinks require the href property, because it specifies a location.
Looking at your code, you have the tag but it's missing the link to the specific location you want to redirect the user to.
Let's say you want it to go to my-account
page in french.
So, your HTML code should be:
<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>
To note: substitute yourwebsite.com with your website's domain.
///////////////////////////////end of Method 1
In your HTML code you mention // Could be nice to change the langue staying on the same page
.
That can be done using AJAX, yes.
But I don't suggest you to do that because from looking at bigger companies that also have websites in multiple languages such as SAP or Apple they all redirect to a different page.
///////////////////////////////UPDATE: the answer until now was created because I thought your need was simply to allow the language to be changed when you click on an HTML element.
Apparently, your goal is slightly more complex than that.
Accordingly to Silex documentation, the usage of _locale
is the way to go.
In 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();
回答2:
In you case its just the matter of adding proper links to allow users so they can switch language. Rest of the work is already done by you. The language switcher dropdown must contain all supported languages including English. See below am example image.
Instead of redirecting the users to http://yourwebsite.com/[fr]/my-account
you must redirect to a special method like http://www.yourwebsite.com/language_change?lang=fr
. You will get HTTP_REFERRER
in $_SERVER
variable so you can redirect users back to the original page they were at. This way you can preserve users current visiting page/url.
Secondly, Ajax vs Redirect: Its better to use a redirect instead of AJAX. If you use AJAX you will increase the complicity to yourself.
When working with multilingual website, we must follow these best practices.
Specific routes per language
Menus, labels and forms
The content of the website
Extra: translate FOSUserBundle
回答3:
The simple idea here is: how your application determines the language to be used to render the pages.
solution #1 (your current solution) based on a URL parameter (that's _locale
), and fallback to some default value in case no URL-parameter given.
So in this solution the translation component always looks for the selected language in the parameters bag prepared by the router component.
Solution #2 put your language identifier inside a session variable.
Your /new-langue
page will have to set this session variable with the value it receives. and your router will populate the _locale
parameter from that session variable.
I may be able to provide some code snippets a bit later.
回答4:
I finally find a solution to do what I want, using pmaxs/silex-locale
(https://github.com/pmaxs/silex-locale).
As I said in my question, I already used it for my translation but I didn't used the "Url generation" as I should...So here is a recap of how to use it (read the documentation if you use Silex v1.x):
1/ Loading Provider
$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/ Usage
Here is my home route controller :
// 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');
As you can see, I have no {_locale}
variable in my routing, but still can use it to change the langage of my page.
3/ Url generator
Now, here is how I change my langage :
{% 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>
I'm using the "Url Generator", it works like this : locale_generate('es', $name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
(more details in the documentation).
This way, when I come in my website I'm in english (my default locale) with my "clean Url" /
. Then by clicking on FR
my url become /fr/
and my content is translate in French with a new selection menu (current-langue = FR and I can select "EN").