Reputation: 1404
What I want to do is create a language switcher template which outputs a list of links, like so:
<div class="language-switcher">
<ul>
{% for locale in allowed_locales %}
<li>
<a href="{{ path($get current route name here $, { '_locale': locale }) }}">
{{ locale|upper }}
</a>
</li>
{% endfor %}
</ul>
</div>
The main problem I'm having is - Twig's built-in path
function accepts a route NAME, which there seems to be no way of retrieving in Symfony 3.
The other problem is - the route might have additional parameters, which need to be merged with the _locale parameter. From the code I've found on the internet (all for symfony v2, of course), making this work makes for very ugly code which definitely does not belong in a template.
I think the best way to achieve this is to make a Twig extension with a new route generation function for this purpose, but it seems that might be problematic as well because the path() function is located in another extension, which I don't know how to access from my own extension (and I'm not so sure it's a good idea either).
How could I make this thing?
Edit: I also don't want to pass the data to the template in each action because that's not DRY at all.
Upvotes: 2
Views: 3974
Reputation: 4401
@jurchick's link to the localized_path
function no longer works, so I whipped up a pure-Twig implementation:
{% set req = app.request %}
{% for locale in allowed_locales %}
{% if locale != req.getLocale() %}
<link rel="alternate" hreflang="{{ locale }}" href="{{
absolute_url(
path(
req.attributes.get('_route'),
req.attributes.get('_route_params')|merge({'_locale': locale})
)
) }}" />
{% endif %}
{% endfor %}
This block actually generates alternate language links for the current page. Feel free to use it in your base HTML block.
Upvotes: 7
Reputation: 1404
I've made a fairly short and simple solution: make a localized version of the path()/url() Twig functions, which auto-detects the current route and attempts to find a localized version of it and replace the _locale parameter.
https://gist.github.com/jurchiks/3b4e1bd249d7e8c1b60e
Essentially, you have something like this template somewhere in header or footer:
<h1>Current language: {{ app.request.getLocale() }}</h1>
<div class="language-switcher">
<ul>
{# allowed_locales comes from config #}
{% for locale in allowed_locales %}
<li>
<a href="{{ localized_path('__current__', locale) }}">
{{ locale|upper }}
</a>
</li>
{% endfor %}
</ul>
</div>
Alternatively, you can do this:
<a href="{{ localized_path('route_name') }}">
And it will output that specific route in current locale.
With a route like this:
@Route("/", name="home")
@Route("/{_locale}/", name="home_lang", requirements={"_locale"="%allowed_locales%"})
public function indexAction()
...
@Route("/{_locale}/foo/", name="foo", requirements={"_locale"="%allowed_locales%"})
public function fooAction()
...
If you open http://127.0.0.1:8000/
, it will output Current language: en
, /en/, /ru/, /tk/
. For fooAction(), only explicit locale is allowed, and the output is the same.
Obviously, explicit locale will be set correctly, this is done by the route matcher in Symfony.
Upvotes: 0
Reputation: 849
How about having a route action which changes the locale then redirects back to the orginal page via the referer in the request header (this will get your previous url):
public function localeChangerAction(Request $request, $locale)
{
return $this->redirect($request->headers->get('referer'));
}
This is untested but I have impletmented this before - I've just tapped this out on my mobile from memory.
I did implement the 'sticky' locale from the cookbook to handle the locale switch: http://symfony.com/doc/current/cookbook/session/locale_sticky_session.html
This may help you out, it'll work for all routes!
Upvotes: 1