
Global business
Software localization
When we want to implement reliable and accurate i18n and l10n support into a website, it is quite important to be able to detect the browser language preference using JavaScript. Our goal is to switch to the most preferred locale available for the user visiting a website at a certain moment.
There are a few ways we could do that, but not all of them are suitable and reliant. This guide will show you a pragmatic way of finding the best available solution for tackling the problem. Off we go!
Whenever trying to detect the browser language, you need to be aware of the following key things:
Speaking of location information, we could use an external service, such as https://ipdata.co/ or https://ipinfo.io/json to query some information. An example response would be:
{ "ip": "<IP>", "city": "Drogheda", "region": "Leinster", "country": "IE", "loc": "53.7189,-6.3478", "org": "AS15502 Vodafone Ireland Limited", "postal": "A92", "timezone": "Europe/Dublin", "readme": "https://ipinfo.io/missingauth" }
Based on that information, we can infer some locale preferences about the user. This could be a little bit more reliable than the user prompt, but it does have some other limitations. For example, users on a VPN may be listed in a different region. Also, relying on an external vendor (unless you want to pay for the service) is not a good idea in the long run as they may stop the service or introduce rate limits if your website generated lots of traffic.
What is particularly important is that there is a specific header that the client can send to the server, which is the Accept-Language. This header acts as a hint to the server about the client’s language preferences. However, there is no easy way to capture this value using JavaScript. The browser itself populates the headers with the appropriate values before sending them to the server.
For example, in Chrome, the following Accept-Language headers are sent by default:
accept-language: el,en-GB;q=0.9,en;q=0.8,en-US;q=0.7
If we change the language preference order, then the browser will send the following headers:
accept-language: en-GB,en;q=0.9,el;q=0.8,en-US;q=0.7
Here, the float values next to the language tag denote how much weight each language has.
If we want to get more control over that value, there is the navigator.languages API that is supposed to represent the preferred languages of the user, usually the language of the browser UI. One could think that the correct way to find it out is by querying it. As it turns out, the limitation is that there is a significant discrepancy between different browsers. For example, here are 3 different responses from the top 3 browsers:
Nevertheless, the preferred language list is entirely configurable within the browser settings. For example, we can reorder the list of available languages in Chrome or add new languages as shown in the screenshot bellow:
Then, using the navigator.language API I will get back "el" as the preferred language.
However, there is something missing here. Even if the clients get the first preferred language ("el") or all the available languages (["en-GB", "el", "en", "en-US"]), it only knows the preferred order and not how much weight each language has.
Out of all of the options available, this is the safest way, at least as a basis for determining the user locale in the browser as it plainly retrieves the value of the browser preferences.
Last updated on November 15, 2022.