![[Translate to English:] [Translate to English:]](/fileadmin/_processed_/b/a/csm_Lang-switch_0ab63c5718.webp)
Automatic Language Switch
...is not only a tongue twister that pushes me personally to the edge of my linguistic abilities, but also a feature that has made it into a trainee project. This means that I once again have the opportunity to give you an insight into my work as a trainee at F7. In the following lines, I would like to explain to you how I made my way through this project, from the initial planning to the final technical realisation.
What is the Language Switch?
The basic idea of the language switch is that users receive the translation that suits their preference on a multilingual website. Our F7.de is maintained in both German and English, the corresponding requirements are:
- The website automatically displays the German version if the user prefers German-language content.
- Alternatively (default), the English version of the page is displayed (if available).
- Regardless of the entry point (e.g. "https://f7.de/en/agency/sustainability"), the user is redirected to the appropriate page
- The appropriate redirect status is sent
- The user can switch the language manually and this selection is retained.
The Approach of my Implementation
I have divided these requirements into three points: Specifying the “correct” language, saving the language and the redirect itself. Before I forget, I would like to point out that a solution could of course have been built specifically for this case of German-English bilingualism, but I decided from the outset to implement the project in a scalable way. In other words, a language switch that can be integrated into any TYPO3 project and works regardless of which or how many languages are maintained. This decision is based on the principles of how I am taught to programme here and the plan to make my solution available in the TYPO3 Extension Repository in the future.
How do I find the right Language?
Back to the first challenge, determining the “right” language, during my research I came across two options for assigning a suitable language to users. It is possible to make a geographical assignment via the IP address, but this is very unattractive at the data protection level and also relatively vulnerable to errors. Take Switzerland, for example, with its four official languages German, French, Italian and Rhaeto-Romanic, plus all the people who are only staying in Switzerland temporarily and the fact that there are people all over the world who use English on the Internet regardless of their native language is also another of many ways to make the location unsuitable for my purposes. The second option is the “HTTP accept-language request header”, which was introduced precisely for the purpose of responding to requests in the correct language. This header is sent with every HTTP request in all conventional browsers and looks similar to this:
en-GB,en;q=0.9,de;q=0.8
The length and content differ, but the structure always remains the same. If we now gradually compare the values in the header with the available translations in our system, we can assume that we have found the most suitable language for our users in the event of a match. The algorithm itself is a little more complex, as the locality must also be taken into account in addition to the language and partial matches also play a role. There is no 100% correct approach for this; it is partly a question of believing what you expect as a result with the most absurd header constellations. If no match is found, the stored default value (=English) is used. If a language has already been selected via the language menu on the user side, this choice is prioritised, which means that we can skip looking at the header.
Saving the selected Language
I had to think much less about saving the language; it quickly became clear that the reference should be written to a cookie. This is set by JavaScript with an on-click event via the language menu. Originally, I took the approach of also setting this cookie via PHP in order to save the result from the header comparison. However, after consultation with the team, we came to the conclusion that a cookie would not be technically necessary at this point and that it would not save any significant processing power whether you call the cookie with every request or run through the PHP code, so I rejected this approach.
The Redirect
Let's move on to the third point, the redirect, for the status I originally ended up with the 302, but after a colleague gave me a tip, I learnt that a 307 is the better alternative here. Redirects with the older 302 status are able to change the method (primarily GET or POST) of the request, whereas the newer 307 alternative retains this. As both methods have their advantages and disadvantages, they are usually deliberately chosen by developers, especially with regard to data security. Changing this choice at a later time could at worst result in security risks. When implementing the redirect, there was initially a choice between “header location” in PHP and “window.location” in JavaScript. As the appropriate time for the redirect is before the page is rendered, JavaScript disqualified itself here, but I was aware from the start that TYPO3 would have its own handling for redirects, which I just had to find in the documentation.
The technical Implementation
Technically, the whole thing looks as follows after realisation: I have created my own class as a middleware interface in which I can access the HTTP requests as request objects thanks to TYPO3. These have all the information I need in their properties and make them easily accessible to me. Here I start with two break conditions, which check whether a language header exists and whether the call goes to the 404 page. The first is important for dealing with crawlers and browsers that do not provide a language header as a matter of principle or due to individual settings. In this context, break means that the request is processed as it is, without a redirect. I do the second step so that 404 errors are reliably returned as such, otherwise it could happen that I redirect them with a different status. In the next step, the target language for the response is defined and compared with that of the request; if they match, the third break condition takes effect. The fourth break condition checks whether the target page exists in the target language, a scenario that I forgot about for a long time in my implementation and only adapted very late on. At this point it is clear that a redirect will be executed, I used the TYPO3 Uri-Builder to build the URL and initialise the Response Factory Interface, with which I create a response object from the URL and the 307 status. This response object is processed instead of the original request object.
My Summary and a Look ahead
This project gave me a lot of joy and I had to deal with many functions within TYPO3 for the first time and therefore learnt a lot. There were many small hurdles in the implementation that I had to discover and deal with in order to find a good solution. The further plan is to add an interface for the backend to the extension and, should it turn out to be necessary, to implement minor code optimisations. So that the whole thing is then ready to be made available in the TYPO3 extension repository, which would make me a little bit proud.