PHP and Symfony (a lot of!)

Welcome to Strangebuzz!

Implement a "Read in your language" link with Symfony

Published on 2019-04-18 •
Modified on 2019-04-19

In this post we will see how to implement a "Read in your language" link in your pages. The goal will be to detect the user browser preferred language and show him a link if the current page is available in his language. Let's go! 😎

Configuration

The code snippets you see in this post are used by this website, so you are sure "It works ™". This project uses the following components:

Symfony 4.3.0-BETA1

PHP 7.2

i18n setup

The posts you are reading on this blog are all available in both English and French. First, let's have a look at the parameters related to i18n (internationalization) in this project:

We have three related parameters in our config/services.yaml file. The default locale that we will use as the reference. Then we build two parameters that will help us to get the list of available locales. Now, let's have a look at the main blog controller:

In the route annotation, we can see two main things. First the locale slug /{_locale} will prefix all URLs of the blog so it's easy to identify the locale of a given resource. (we have two separate trees: /en and /fr) Then, we have a requirement that limits the available locales. So in this case we inject the locales_requirements parameter we have seen in the previous section. It contains: en|fr. Try to access /es (spanish), you will get a 404 error as this locale is not available. (Javier, if you read me! 😁) Now, let's see how to build our switch language link.

Getting the user preferred language

The first thing to do is to detect the user language. Symfony already provides a function for that, it can be accessed through the Request object. Let's see the main application controller that handles the root URL of this website:

As you can see, we are getting the preferred language of the user. We are passing the activated locales as an argument. If the user preferred language matches one of theses values then it will return it, otherwise it will return the default locale. Then a redirection is made to the locale homepage: /en or /fr. This was an example to show how the preferred language function works. Now let's have a look on how to use this inside templates. You can use the following functions directly on the request object:

We introduce several pre-computed global variables: the current route, the current page locale, the alternative locale and the user preferred locale. The alternative locale variable will be the opposite of the current language as the blog only handles two. The user preferred locale uses the same call we used before, we have to pass the activated locales argument. Now, we can call these global variables in all our templates:

Twig global

Twig call

Result

The current route

{{ route }}

blog_show

The current locale

{{ locale }}

en

The alternate locale

{{ alt_locale }}

fr

The user preferred locale

{{ user_locale }}

en

Now that we have these variables, we can check if we should propose a link. It fact we will show it if the alternate language matches the user's locale. Let's look at the code:

Some explanations. First we use a specific translation domain "locale". I am using this so I can show you the content of two translation files I am using. (see below). The main test is explicit. I have added an "or" condition to force the box to be displayed with a get parameter. After that, we set two variables: the first one will contain the translated slug of the article and the second one will contain the alternate URL. Note that we pass "alt_locale" as an argument to the trans Twig function because we don't want to use the current locale of the page but the users preferred one to encourage them to click. Then we create the link with some explanation texts. There are two cases: you can see the box, or (if you don’t see it) click on the link below. It will add the special get parameter to force its display.

You don't see the link box because your lang is en and the current article locale in en. (or you don't have the ?force=1 get parameter in the url). To see it, click on the link below.

# translations/locale.en.yaml
read_in_your_lang: >
We noticed that your browser is using English.
Do you want to read this post in this language?
alt_lang_detected: English language detected! 🇬🇧
read_in_your_lang_button: Read the english version 🇬🇧