jurchiks
jurchiks

Reputation: 1404

symfony 3 - generate current url with different locales

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

Answers (3)

aalaap
aalaap

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

jurchiks
jurchiks

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

MistaJase
MistaJase

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

Related Questions