Get visitors language & country code with javascript (client-side)
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.
How to detect browser country in client site?
There are multiple options to determine the locale. In descending order of usefulness, these are:
- Look up the IP address, with an IP geolocation service like Maxmind GeoIP. This is the location the request is coming from, i.e. if an American vacations in Italy and uses a Swedish VPN, it will return
Sweden
.
- Look up the precise location on Earth from the browser with the geolocation API. An American vacationing in Italy using a Swedish VPN will register as Italy.
- Look in the
Accept-Language
header on the server (or with the help of the server), and extract the locale information. An American vacationing in Italy using a Swedish VPN will register as USA.
en-US
settings in order to avoid machine-translated text. On modern browsers (as of writing not IE/Edge, and only Safari 11+), you can also request navigator.languages.navigator.language
is the first element of thenavigator.languages
header. All of the considerations of navigator.languages apply. On top, this information can sometimes be just the language without any locale (i.e.en
instead ofen-US
).Use another, third-party service. For instance, if the user signs in via a Single-Sign-On system such Facebook connect, you can request the hometown of the user. This information is typically very unreliable, and requires a third party.
Getting the user's region with navigator.language
Regex found here: https://github.com/gagle/node-bcp47/blob/master/lib/index.js
var re = /^(?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))$|^((?:[a-z]{2,3}(?:(?:-[a-z]{3}){1,3})?)|[a-z]{4}|[a-z]{5,8})(?:-([a-z]{4}))?(?:-([a-z]{2}|\d{3}))?((?:-(?:[\da-z]{5,8}|\d[\da-z]{3}))*)?((?:-[\da-wy-z](?:-[\da-z]{2,8})+)*)?(-x(?:-[\da-z]{1,8})+)?$|^(x(?:-[\da-z]{1,8})+)$/i;
let foo = re.exec('de-AT'); // German in Austria
let bar = re.exec('zh-Hans-CN'); // Simplified Chinese using Simplified script in mainland China
console.log(`region ${foo[5]}`); // 'region AT'
console.log(`region ${bar[5]}`); // 'region CN'
How to get visitor's location (i.e. country) using geolocation?
You don't need to locate the user if you only need their country. You can look their IP address up in any IP-to-location service (like maxmind, ipregistry or ip2location). This will be accurate most of the time.
Here is a client-side example with Ipregistry (disclaimer, I am working for):
fetch('https://api.ipregistry.co/?key=tryout')
.then(function (response) {
return response.json();
})
.then(function (payload) {
console.log(payload.location.country.name + ', ' + payload.location.city);
});
If you really need to get their location, you can get their lat/lng with that method, then query Google's or Yahoo's reverse geocoding service. JavaScript for detecting browser language preference
I think the main problem here is that the browser settings don't actually affect the navigator.language
property that is obtained via javascript.
What they do affect is the HTTP 'Accept-Language' header, but it appears this value is not available through javascript at all. (Probably why @anddoutoi states he can't find a reference for it that doesn't involve server side.)
I have coded a workaround: I've knocked up a google app engine script at http://ajaxhttpheaders.appspot.com that will return you the HTTP request headers via JSONP.
(Note: this is a hack only to be used if you do not have a back end available that can do this for you. In general you should not be making calls to third party hosted javascript files in your pages unless you have a very high level of trust in the host.)
I intend to leave it there in perpetuity so feel free to use it in your code.
Here's some example code (in jQuery) for how you might use it
$.ajax({
url: "http://ajaxhttpheaders.appspot.com",
dataType: 'jsonp',
success: function(headers) {
language = headers['Accept-Language'];
nowDoSomethingWithIt(language);
}
});
Hope someone finds this useful.Edit: I have written a small jQuery plugin on github that wraps this functionality: https://github.com/dansingerman/jQuery-Browser-Language
Edit 2: As requested here is the code that is running on AppEngine (super trivial really):
class MainPage(webapp.RequestHandler):
def get(self):
headers = self.request.headers
callback = self.request.get('callback')
if callback:
self.response.headers['Content-Type'] = 'application/javascript'
self.response.out.write(callback + "(")
self.response.out.write(headers)
self.response.out.write(")")
else:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("I need a callback=")
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=False)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Edit3: Have open sourced the app engine code here: https://github.com/dansingerman/app-engine-headers Get country code using javascript
According to the docs on the website, you should be able to retrieve the country code with ipinfo. try using $.getJSON instead of $.get
var country_code = null;
$.getJSON('http://ipinfo.io/' + userip, function(data){
country_code = data.country;
alert(country_code);
});
How to determine user's locale within browser?
The proper way is to look at the HTTP Accept-Language header sent to the server. This contains the ordered, weighted list of languages the user has configured their browser to prefer.
Unfortunately this header is not available for reading inside JavaScript; all you get is navigator.language
, which tells you what localised version of the web browser was installed. This is not necessarily the same thing as the user's preferred language(s). On IE you instead get systemLanguage
(OS installed language), browserLanguage
(same as language
) and userLanguage
(user configured OS region), which are all similarly unhelpful.
If I had to choose between those properties, I'd sniff for userLanguage
first, falling back to language
and only after that (if those didn't match any available language) looking at browserLanguage
and finally systemLanguage
.
If you can put a server-side script somewhere else on the net that simply reads the Accept-Language header and spits it back out as a JavaScript file with the header value in the string, eg.:
var acceptLanguage= 'en-gb,en;q=0.7,de;q=0.3';
then you could include a <script src> pointing at that external service in the HTML, and use JavaScript to parse the language header. I don't know of any existing library code to do this, though, since Accept-Language parsing is almost always done on the server side.Whatever you end up doing, you certainly need a user override because it will always guess wrong for some people. Often it's easiest to put the language setting in the URL (eg. http://www.example.com/en/site vs http://www.example.com/de/site), and let the user click links between the two. Sometimes you do want a single URL for both language versions, in which case you have to store the setting in cookies, but this may confuse user agents with no support for cookies and search engines.
Related Topics
JavaScript Add Method to Object
How to Trigger Click on Page Load
JavaScript Get Object Key Name
How to Check "Checkbox" Dynamically - Jquery Mobile
Single Plus Operator in JavaScript
Adding a Slide Effect to Bootstrap Dropdown
Adding Script Tags in Angular Component Template
How to Load a JSON Object from a File with Ajax
Loading Local Files with JavaScript Without a Web Server
Domnodeinserted Equivalent in Ie
How to Get Month and Date of JavaScript in 2 Digit Format
Jquery Smooth Scroll to an Anchor
Validating User's Utf-8 Name in JavaScript
How to Reset the Scale/Zoom of a Web App on an Orientation Change on the Iphone
Select a Complete Table with JavaScript (To Be Copied to Clipboard)
Why Does This Foreach Return Undefined When Using a Return Statement