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
byen
in my url it works, is it a good idea to try to do it in javascript usingwindow.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?
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
2/ Usage
Here is my home route controller :
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 :
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 onFR
my url become/fr/
and my content is translate in French with a new selection menu (current-langue = FR and I can select "EN").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 likehttp://www.yourwebsite.com/language_change?lang=fr
. You will getHTTP_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
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:
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:
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.