Get visitors language & country code with javascript (client-side) [duplicate]
Asked Answered
U

3

45

Question: Is there a javascript (client-side) code to get visitors country/language code, that is accurate and is cross-"modern"-browser ? I am looking for results like 'en-US', 'sv-SE', 'nl-NL', etc.

Related questions to this have been asked before (some SO links: 1,2,3,4, among others) but I didn't find answer and some of the answers are some yearls old and in some cases referring to even more old articles, which makes me think there are new solutions for this.

I tried :

var language = window.navigator.userLanguage || window.navigator.language;
console.log(language);

and got "sv" in Chrome and "en-GB" in Firefox, in the same machine, same place.

Unionist answered 16/7, 2013 at 15:11 Comment(0)
C
32

navigator.language isn't reliable as one of your linked questions states.

The reason this is asked a lot, but you're still searching says something about the problem. That language detection purely on the client side is not anything close to reliable.

First of all language preferences should only be used to detect language preferences - i.e. not location. My browser is set to en_US, because I wanted the English version. But I'm in the UK, so would have to alter this to en_GB to have my country detected via my browser settings. As the 'customer' that's not my problem. That's fine for language, but no good if all the prices on your site are in $USD.

To detect language you really do need access to a server side script. If you're not a back end dev and want to do as much as possible on the client side (as your question), all you need is a one line PHP script that echos back the Accept-Language header. At its simplest it could just be:

<?php
echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; 
// e.g. "en-US,en;q=0.8"

You could get this via Ajax and parse the text response client side, e.g (using jQuery):

$.ajax( { url: 'script.php', success: function(raw){
    var prefs = raw.split(',');
    // process language codes ....
} } );

If you were able to generate your HTML via a back end, you could avoid using Ajax completely by simply printing the language preferences into your page, e.g.

<script>
    var prefs = <?php echo json_encode($_SERVER['HTTP_ACCEPT_LANGUAGE'])?>;
</script>

If you had no access to the server but could get a script onto another server, a simple JSONP service would look like:

<?php
$prefs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$jsonp = 'myCallback('.json_encode($prefs).')';

header('Content-Type: application/json; charset=UTF-8', true );
header('Content-Length: '.strlen($jsonp), true );
echo $jsonp;

Using jQuery for your Ajax you'd do something like:

function myCallback( raw ){
    var prefs = raw.split(',');
    // process language codes ....
}
$.ajax( {
    url: 'http://some.domain/script.php',
    dataType: 'jsonp'
} );

Country detection is another matter. On the client side there is navigator.geolocation, but it will most likely prompt your user for permission, so no good for a seamless user experience.

To do invisibly, you're limited to geo IP detection. By the same token as above, don't use language to imply country either.

To do country detection on the client side, you'll also need a back end service in order to get the client IP address and access a database of IP/location mappings. Maxmind's GeoIP2 JavaScript client appears to wrap this all up in a client-side bundle for you, so you won't need your own server (although I'm sure it will use a remote jsonp service). There's also freegeoip.net, which is probably less hassle than MaxMind in terms of signing up, and it appears to be open source too.

Caliber answered 17/7, 2013 at 9:40 Comment(5)
UPDATE: Looks like the experimental navigator.languages (plural) gives the same language preferences that the browser sends in the headers.Caliber
You can also check the timezone to help guess country client-side without doing IP detection.Almire
UK is in the same timezone as Portugal.Caliber
Yes, but try Intl.DateTimeFormat().resolvedOptions().timeZone. When I do, I see "America/Los_Angeles". Therefore, my country code is US, not CA even though Canada is in the same timezone.Almire
Fair enough. That's not guessing so much. I get Europe/LondonCaliber
F
40

Using jQuery, this line will display your user's country code.

  $.getJSON('https://freegeoip.net/json/', function(result) {
    alert(result.country_code);
  });
Fluidextract answered 10/3, 2015 at 9:43 Comment(8)
I get XMLHttpRequest cannot load https://freegeoip.net/json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'my.domain.com' is therefore not allowed access.Wavelength
This URL is no longer valid.Betoken
This URL is validTingle
The URL is valid and the service works. Just make sure you are using https if you're on a secure site.Fictive
be careful, it leaves cookiesWooded
it will stop working on July 2018 since they re-launch another api: https://ipstack.com/Teuton
use ipinfo.io/json insteadAuberbach
DON'T assume that you can detect the user language knowing it IP location, this just don't work: e.g. I am traveling in a foreign country; e.g I am living in India/Switzerland/Canada where there are several languages; e.g. I live in a country but I did not learned yet that language.; Just DON'T!Threesquare
C
32

navigator.language isn't reliable as one of your linked questions states.

The reason this is asked a lot, but you're still searching says something about the problem. That language detection purely on the client side is not anything close to reliable.

First of all language preferences should only be used to detect language preferences - i.e. not location. My browser is set to en_US, because I wanted the English version. But I'm in the UK, so would have to alter this to en_GB to have my country detected via my browser settings. As the 'customer' that's not my problem. That's fine for language, but no good if all the prices on your site are in $USD.

To detect language you really do need access to a server side script. If you're not a back end dev and want to do as much as possible on the client side (as your question), all you need is a one line PHP script that echos back the Accept-Language header. At its simplest it could just be:

<?php
echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; 
// e.g. "en-US,en;q=0.8"

You could get this via Ajax and parse the text response client side, e.g (using jQuery):

$.ajax( { url: 'script.php', success: function(raw){
    var prefs = raw.split(',');
    // process language codes ....
} } );

If you were able to generate your HTML via a back end, you could avoid using Ajax completely by simply printing the language preferences into your page, e.g.

<script>
    var prefs = <?php echo json_encode($_SERVER['HTTP_ACCEPT_LANGUAGE'])?>;
</script>

If you had no access to the server but could get a script onto another server, a simple JSONP service would look like:

<?php
$prefs = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$jsonp = 'myCallback('.json_encode($prefs).')';

header('Content-Type: application/json; charset=UTF-8', true );
header('Content-Length: '.strlen($jsonp), true );
echo $jsonp;

Using jQuery for your Ajax you'd do something like:

function myCallback( raw ){
    var prefs = raw.split(',');
    // process language codes ....
}
$.ajax( {
    url: 'http://some.domain/script.php',
    dataType: 'jsonp'
} );

Country detection is another matter. On the client side there is navigator.geolocation, but it will most likely prompt your user for permission, so no good for a seamless user experience.

To do invisibly, you're limited to geo IP detection. By the same token as above, don't use language to imply country either.

To do country detection on the client side, you'll also need a back end service in order to get the client IP address and access a database of IP/location mappings. Maxmind's GeoIP2 JavaScript client appears to wrap this all up in a client-side bundle for you, so you won't need your own server (although I'm sure it will use a remote jsonp service). There's also freegeoip.net, which is probably less hassle than MaxMind in terms of signing up, and it appears to be open source too.

Caliber answered 17/7, 2013 at 9:40 Comment(5)
UPDATE: Looks like the experimental navigator.languages (plural) gives the same language preferences that the browser sends in the headers.Caliber
You can also check the timezone to help guess country client-side without doing IP detection.Almire
UK is in the same timezone as Portugal.Caliber
Yes, but try Intl.DateTimeFormat().resolvedOptions().timeZone. When I do, I see "America/Los_Angeles". Therefore, my country code is US, not CA even though Canada is in the same timezone.Almire
Fair enough. That's not guessing so much. I get Europe/LondonCaliber
S
7

Getting the Country Code with ipdata.co

This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.

$.get("https://api.ipdata.co?api-key=test", function (response) {
    $("#response").html(response.country_code);
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="response"></pre>
Salicaceous answered 18/2, 2018 at 12:5 Comment(2)
as 2018, requests up to 1500 is free. Sounds wellTeuton
DON'T assume that you can detect the user language knowing it IP location, this just don't work: e.g. I am traveling in a foreign country; e.g I am living in India/Switzerland/Canada where there are several languages; e.g. I live in a country but I did not learned yet that language.; Just DON'T!Threesquare

© 2022 - 2024 — McMap. All rights reserved.