Getting the user's region with navigator.language

Jeff picture Jeff · Aug 29, 2016 · Viewed 16.4k times · Source

For some time, I've been using something like this to get my user's country (ISO-3166):

const region = navigator.language.split('-')[1]; // 'US'

I've always assumed the string would be similar to en-US -- where the country would hold the 2nd position of the array.

I am thinking this assumption is incorrect. According to MDN docs, navigator.language returns: "string representing the language version as defined in BCP 47." Reading BCP 47, the primary language subtag is guaranteed to be first (e.g., 'en') but the region code is not guaranteed to be the 2nd subtag. There can be subtags that preceed and follow the region subtag.

For example "sr-Latn-RS" is a valid BCP 47 language tag:

sr                |  Latn           |  RS
primary language  |  script subtag  |  region subtag

Is the value returned from navigator.language a subset of BCP 47 containing only language and region? Or is there a library or regex that is commonly used to extract the region subtag from a language tag?

Answer

TimoStaudinger picture TimoStaudinger · Sep 1, 2016

Your solution is based on the false premise that the browser's language tag reliably matches the user's country. E.g., I have set my browser language to German, even though I am living nowhere near Germany at the moment, but rather in the United States.

Also, for example in Chrome, many language packs do not require you to specify the region modifier. Setting Chrome's display language to German

enter image description here

provides the following language tag:

> navigator.language
< "de"

No region tag at all, and a fairly common language.

Bottom line is, my browser setup results in language tag de, even though I live in the United States.


A more accurate and possibly reliable way to determine the user's location would be to derive it from the IP address associated with the request. There are numerous services that offer this service. ip-api.com is one of them:

$.get("http://ip-api.com/json", function(response) {
  console.log(response.country);     // "United States"
  console.log(response.countryCode); // "US"
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>