JavaScript for detecting browser language preference
Solution 1
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
Solution 2
var language = window.navigator.userLanguage || window.navigator.language;
alert(language); //works IE/SAFARI/CHROME/FF
window.navigator.userLanguage
is IE only and it's the language set in Windows Control Panel - Regional Options and NOT browser language, but you could suppose that a user using a machine with Window Regional settings set to France is probably a French user.
navigator.language
is FireFox and all other browser.
Some language code: 'it'
= italy, 'en-US'
= english US, etc.
As pointed out by rcoup and The WebMacheter in comments below, this workaround won't let you discriminate among English dialects when users are viewing website in browsers other than IE.
window.navigator.language
(Chrome/FF/Safari) returns always browser language and not browser's preferred language, but: "it's pretty common for English speakers (gb, au, nz, etc) to have an en-us version of Firefox/Chrome/Safari." Hence window.navigator.language
will still return en-US
even if the user preferred language is en-GB
.
Solution 3
Update of year 2014.
Now there is a way to get Accept-Languages in Firefox and Chrome using navigator.languages (works in Chrome >= 32 and Firefox >= 32)
Also, navigator.language in Firefox these years reflects most preferred language of content, not language of UI. But since this notion is yet to be supported by other browsers, it is not very useful.
So, to get most preferred content language when possible, and use UI language as fallback:
navigator.languages
? navigator.languages[0]
: (navigator.language || navigator.userLanguage)
Solution 4
I came across this piece of code to detect browser's language in Angular Translate module, which you can find the source here. I slightly modified the code by replacing angular.isArray with Array.isArray to make it independent of Angular library.
var getFirstBrowserLanguage = function () {
var nav = window.navigator,
browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'],
i,
language;
// support for HTML 5.1 "navigator.languages"
if (Array.isArray(nav.languages)) {
for (i = 0; i < nav.languages.length; i++) {
language = nav.languages[i];
if (language && language.length) {
return language;
}
}
}
// support for other well known properties in browsers
for (i = 0; i < browserLanguagePropertyKeys.length; i++) {
language = nav[browserLanguagePropertyKeys[i]];
if (language && language.length) {
return language;
}
}
return null;
};
console.log(getFirstBrowserLanguage());
Solution 5
let lang = window.navigator.languages ? window.navigator.languages[0] : null;
lang = lang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage;
let shortLang = lang;
if (shortLang.indexOf('-') !== -1)
shortLang = shortLang.split('-')[0];
if (shortLang.indexOf('_') !== -1)
shortLang = shortLang.split('_')[0];
console.log(lang, shortLang);
I only needed the primary component for my needs, but you can easily just use the full string. Works with latest Chrome, Firefox, Safari and IE10+.
Comments
-
Abhishek Habbu almost 2 years
I have been trying to detect the browser language preference using JavaScript.
If I set the browser language in IE in
Tools>Internet Options>General>Languages
, how do I read this value using JavaScript?Same problem for Firefox. I'm not able to detect the setting for
tools>options>content>languages
usingnavigator.language
.Using
navigator.userLanguage
, it detects the setting done thruStart>ControlPanel>RegionalandLanguageOptions>Regional Options
tab.I have tested with
navigator.browserLanguage
andnavigator.systemLanguage
but neither returns the value for the first setting(Tools>InternetOptions>General>Languages
)I found a link which discusses this in detail, but the question remains unanswered :(
-
Paul McMillan over 14 yearsKeep in mind that this is not a particularly reliable way of serving the "correct" language to the user. Many users will want an alternate option - don't leave them stranded!
-
Mihai Nita over 14 years100% agree. Using that info it a best guess. You should allow the user to override it, if you get it wrong. And if there is a possibility that the user returns, you might remember that choice in a cookie. If the site requires authentication, you might have that info in a user profile.
-
DanSingerman about 13 years@msec I have posted the Python appengine script as requested. Note, if server side is available, this should be pretty simple in any language - this service really only needs to exist for those that don't have (or don't want to have) a server side component.
-
mate64 almost 13 yearshi dan, this question gots 14k views and still counting - maybe you want to release your script on github? regards, msec
-
moey almost 13 yearsDoes
navigator.language
always return the same value for a particular language (e.g.ja-jp
for Japanese)? Or, the value / format varies across browsers / OS? -
Marco Demaio almost 13 yearsI'm not sure, but you can check for a substring of it, i.e.
if(language.indexOf('jp') !== -1) alert('this is japanese')
-
Deckard over 12 yearsAre there other reliable sites that return HTTP request headers like Google? What I'm trying to do is redirecting user to their browswer language settings, and my site is global. So I need to rely on the site globally available and permenant.
-
DanSingerman over 12 years@deckard ummm - the Internet is global. The appengine script should work fine anywhere on the Internet. However - this is really a hack for devs without a backend available - it should not be used in a 'real' site where you have control of a the back end.
-
Matthew Flaschen almost 12 years@DanSingerman, interesting script. However,you should use
application/javascript
for JSONP. Also, this is not technically valid JSONP, since you're using simple quotes, but that shouldn't matter for most purposes. -
Matthew Flaschen almost 12 yearsHis plugin uses JSONP, so I don't think this will be compatible.
-
DanSingerman almost 12 years@MatthewFlaschen you're quite right (In my defence I wrote the script in about 5 minutes 2 years ago.) I'll fix it up when I have a chance.
-
Matthew Flaschen almost 12 years@DanSingerman, thanks. "simple quotes" should have been "single quotes".
-
thomaux about 11 yearsThis is not correct. Calling
navigator.language
in Chrome will return the language Chrome is displayed in, NOT the user's preferred language (which is the language at the top of the languages list). -
Marco Demaio about 11 years@Anzeo: low are chances of having you site visited by users that speak in one language, but install a browser in another language and later they also set another preferred language. As said by others there is no decent way, my answer is a simple short workaround for a task that usually does not end up into fatal errors. If you have to be absolutely sure of what language the user uses you could always ask him by adding on your site a select list and save its choice into a cookie.
-
thomaux about 11 years@MarcoDemaio the OP asks a solution to detect the preference of the user. As Chrome is confusing in these settings, I added the note for future reference. We had the problem recently on our project and had to use the accepted answer. It's to determine the default, because our users can also set their preferred language on the platform. However this setting might be missing, hence the need of a default.
-
jezzarax over 10 years@MarcoDemaio it's pretty common for English speakers (gb, au, nz, etc) to have an en-us version of Firefox/Chrome/Safari. Sometimes en-gb builds exist but they're not popular, and there's certainly none for other en variants.
-
Marco Demaio over 10 years@rcoup: sorry, but i don't unsertsand youyr comment. Brits, Aussies, etc. they do all speak in English, and the 'Browser Language Preference' detected by my code will be exactly 'English'.
-
AGamePlayer over 10 yearsJust wondering, what is the different between
navigator.language
andAccept-Language
... -
Ronny over 10 years@AwQiruiGuo the former is usually the browser's UI language, while the latter is an ordered list of languages the user prefers to view content in.
-
Endless almost 10 yearsIf the third party service should be more safe it should enable CORS ;)
-
Marco Demaio over 9 years+1, but where did you read that
navigator.browserLanguage
is deprecated? It's not written in the links to the MSDN articles in you answer, and I just tested it in IE11 and it works! I don't have IE8 anymore, but I tested it with the IE8 simulator and it works (I know the IE8 simulator is not the best option to test things). -
anddoutoi over 9 yearsHmm, yeah that seems weird. But I have no clue how I came to that conclusion 5 years ago >.<
-
Austin Thompson over 9 yearsIn case it helps anyone else, I had thought this would work in Safari in iOS 8 since I thought it fell in the modern category. I was wrong.
-
Dave over 9 yearsAn alternative implementation which gets the preferred list of languages, or falls back to the UI language (both as arrays) is:
window.navigator.languages || [window.navigator.language || window.navigator.userLanguage]
-
Yaba over 9 yearsNote that this does not work in our 'most-favorite' browser, IE (tested with IE 11).
-
user959690 over 9 yearsI think you might be confusing the browser's configured language with the browser's language preference. The first controls the menus, etc on the browser, the later affects the languages that the browser sends in the header to servers asking for those languages in response. So if the server denies your language and resorts to English you'd want to use English, not the browser's language.
-
Justin almost 9 yearsHis answer works fine in IE (tested 8-11). This should be the accepted answer.
-
Evan Lin almost 9 yearsPlease note header['Accept-Language'] will get different result base on your browser.
-
Mousey almost 9 yearsa much better cross-browser solution is now available, see @MarcoDemaio's answer, explained here gu.illau.me/posts/…
-
Styx over 8 yearsChrome has
window.navigator.languages
with array of user preferred languages. -
Oleksandr over 8 yearsGetting language with
navigator.languages[0]
is bad idea. My system's default language is Russian andnavigator.language
returns correct lang code "ru". Butnavigator.languages
returns["en-US", "en", "ru", "uk"]
. So getting language with 0 index will give you "en-US" which is incorrect for my system. Please don't use navigator.languages to detect current system's language. -
Oleksandr over 8 yearsAnd one more thing:
navigator.languages
represents alphabetically(!) sorted list of languages available for text input in user's system. They are not sorted in order of user's preference. -
Oleksandr over 8 years@Styx
window.navigator.languages
represents alphabetically sorted list of languages available in system for text input. For example: my system's UI and Chrome language is "ru". Also my native languages are "ru" (Russian) and "uk" (Ukrainian), so I have enabled keyboard layouts for these languages (as well as English layout) and Chrome forwindow.navigator.languages
returns ["en-US", "en", "ru", "uk"]. Absolutely different order than my preference and language of my UI. -
Oleksandr over 8 yearsDue to said above, navigator.languages can't be used for any kind of strict detection for user's language preference order. It can be used to obtain generic information about user, not his preferences.
-
Tim Babych over 8 years@stunpix this is not about system's language, but about in-browser preference. Which might or might not coincide with system's language, depending on which browser was installed. I suggest you take a look at your browser's settings. Firefox: Preferences-Content-Languages, Chrome: Settings (advanced) - Languages
-
Styx over 8 years@stunpix - maybe Chrome auto add keybord layouts to preferred languages. But you can edit this list and
window.navigator.languages
has ordered list of languages from preferences:chrome://settings/languages
-
Oleksandr over 8 years@Styx yep, seems Chrome do this at install time, since any changes in keyboard layout settings later do not change that Chrome setting. Anyway, average user do not change these language settings in browser, so no one should rely on them as on user's languages that are sorted by user preference. That's not true.
-
Oleksandr over 8 yearsAnother observation with Chrome: for pages with foreign languages browser asks to translate these pages to one of languages defined in settings, but once you click in popped bar "never translate this language" – this language will be added to you language list. So when user is getting annoyed with this translation bar, he can press "never translate" button to just stop it popping. Is this preferred user language in such case? I think no.
-
elQueFaltaba almost 8 yearsJust run your script, got
en-US
, on osX El Capitan in Spanish, Chrome set in Spanish, from Barcelona .. The list of allowed languages, and picking up the first of itnavigator.languages[0]
, is not the actual language the user is using. -
StanE over 7 years@stunpix No, this is not correct. The order of prefered languages in the array reflects the order set by user: developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/…
-
Oleksandr over 7 years@StanE For some reason this was correct on moment of writing, because I had setup that always returned me sorted array, despite of my settings (I double checked that). Now it's no longer correct and I can't reproduce my previous statement, so it's no longer correct.
-
Oleksandr over 7 yearsBTW, navigator.language[s] have unstable behavior across browsers and you should consider this behavior:
navigator.language
is a browser's UI lang. Chrome automatically sets its UI lang to system's, but FF doesn't do that automatically, so FF's lang could be != system's lang (for example freshly installed Ubuntu has FF with only english UI and other langs must be installed manually).navigator.languages
– user's order preference. Chrome changes this list by pushing current system's lang to top of list, but FF still has a static list which should be sorted manually. -
MrCroft over 7 yearsAll good. I've just checked myself (hate to do that, as you have to restart the browser - at least chrome). 1.
navigator.languages
- array is in the order you arrange your languages in browser settings (chrome is less intuitive that you can order them, as there is no indicator that you can drag the items in the list; Firefox has move up/down buttons) 2. navigator.language - returns the current language (the one set as default) Of course, I've tried in Chrome and Firefox, not sure about IE and whatnavigator.userLanguage
returns... but I'm not even opening "that" (ie IE) :))) -
EamonnM about 7 yearsThis seems more reliable than other JS answers, e.g. the check on language.length means it will skip empty items in the languages array (if that even happens?)
-
Jaume Mussons Abad over 6 yearsTo support older browsers when detecting that nav.languages is an array, you should use: Object.prototype.toString.call(nav.languages) === '[object Array]'
-
Patrick Oscity about 6 yearsI have my OS language (i.e. Chrome's UI language) set to en_US, preferred browser languages set to de, en_US, en_GB, en in that order.
navigator.language
returns"de"
for me, so it seems to be equivalent tonavigator.languages[0]
, at least in more recent versions of Chrome. -
Tim Babych about 6 yearsYes, can confirm it works now in Chrome 65 on Mac. Interestingly the bug about navigator.language is not closed yet bugs.chromium.org/p/chromium/issues/detail?id=101138
-
Armin Šupuk almost 6 years@anddoutoi It is not available in IE 8, because it was introduced in IE 9, so it's exactly the opposite of what you though.
-
Stefan Steiger almost 6 yearsTo clarify: older browsers = ( IE <=8.0 )
-
EamonnM almost 6 yearsIt works on every browser I've tested - desktop and mobile. Which browser are you having problems with?
-
Jry9972 almost 6 years'browserLanguage', 'systemLanguage and, 'userLanguage' are not properties of chrome and firefox.. but 'language' is present in all browsers.. My bad that I didn't see that it would return first short code which answers the question.. Deleting my previous comment..
-
9ilsdx 9rvj 0lo over 5 yearsIt is pretty common for aware non-native-english speakers to install browser in English language to be able to troubleshoot easier, and still prefer another language for non-technical stuff.
-
Vitim.us over 5 yearsOne liner is
const langs = [].concat(navigator.languages, navigator.language, navigator.userLanguage, navigator.browserLanguage, navigator.systemLanguage).filter(Boolean);
-
Null over 5 yearsEamonnM's edit of this code is probably more optimal, see: stackoverflow.com/a/46514247/9314312
-
MrMesees about 5 yearsI like this. It's chrome specific, but doesn't electron use chromium under the hood? Does this work for just chrome, or any chromium project
-
warrickh about 5 yearsThis is only available from within a Chrome Extension. Its not available in Chrome on a regular web page. I'm not sure about Electron.
-
Marcel Waldvogel about 5 years@CodeGust: The link no longer works. Can you find a replacement?
-
CodeGust about 5 years@MarcelWaldvogel web.archive.org/web/20170616234605/http://blog.ksol.fr/… cached version
-
Berkyjay over 4 years@thomaux, no longer true. Now
navigator.language
in Chrome returns the first element of the listnavigator.languages
. This change makes it now impossible to know for sure the language of the browser's UI. -
Brent about 4 yearsHow common is it a problem people have preferences in the order ["en", "en-GB"] but want the preferences the other way around. I thought the languages were meant to be in the order of user preference. if it were ["fr", "en-GB"], wouldn't the preference be for French?
-
EamonnM about 4 years@Brent That's a good point. It would depend on what you need from it. For ["en", "en-GB"] I would want to get "en-GB" as it's a more specific version of the same language. ["fr", "en-GB"] is different as they are different languages, and "fr" could be a better result.
-
Miguel almost 4 yearsThe Accept-Language HTTP header in every HTTP request from the user's browser uses the same value for the navigator.languages property except for the extra qvalues (quality values) field (e.g. en-US;q=0.8). from developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/…
-
RollingInTheDeep over 2 yearsI guess this might be out of date, because changing the language definitely did change the navigation.languages value. Also if you add a new language and move it to the top of the list, then you will get that value when you query on navigation.language. Also note that IE / Edge have been using the same engine as chrome for quite some time now, so it should be enough to use navigator.langauge (primary language) or navigator.languages (array of all languages)
-
RollingInTheDeep over 2 yearsdeveloper.mozilla.org/en-US/docs/Web/API/Navigator/languages Clearly states that navigator.language is the first element in the navigator.languages array.
-
Khom Nazid about 2 yearsIs there a non Jquery version of this?