How do I change the browser language with Javascript - javascript

I want to access the user browser settings and change the browser language, is this possible using Javascript?
If it's possible, how can I access this? (sample code please)

You can detect, but cannot set.
var lang = navigator.language || navigator.userLanguage;
// navigator.language : Netscape & Firefox
// navigator.userLanguage : Internet Explorer
If you want to output different languages, the best way is to do it server-side. Either:
use an AJAX call to dynamically load the appropriate page
use a session variable to load the initial page correctly

This is impossible and a bad idea. A better idea is to detect the browser's language, which is possible to do reasonably well, and ask the user to change it (assuming the change is absolutely necessary).

No that is not possible. How would you find it if you open a page, and your browser turns Arabic (or some other language you can't read)?

This is possible if you do it from within a Chrome extension.
Check this answer to a similar question & contentScript.js of locale-switcher Chrome extension:
let locale = null;
chrome.storage.local.get(["locale"], result => {
if (result) {
locale = result.locale;
}
if (locale) embedScript();
});
const embedScript = () => {
const code = `
(() => {
Object.defineProperties(Navigator.prototype, {
language: {
value: '${locale}',
configurable: false,
enumerable: true,
writable: false
},
languages: {
value: ['${locale}'],
configurable: false,
enumerable: true,
writable: false
}
});
})();`;
const script = document.createElement("script");
script.textContent = code;
document.documentElement.prepend(script);
script.remove();
};
I'm aware of timing (this question was asked 10 years before this answer) & that would be particularly fun if you are the author of this extension.

If what you actually want to do is detect the language the user is using, which is what you want to do, because nothing will annoy your visitors more that their browser preferences getting changed, on the server-side, read the Accept-Language HTTP request header that all modern browsers send, it should contain all the info you need. If it is absent, assume the language of your largest audience.
Check out RFC2616 Section 14.4 for more information on Accept-Language and it's use.

This is definitely not possible using JavaScript on a web page.
A browser Extension might have the rights to change this - I'm not sure, it will also depend on the browser. However, building such an extension would require a fair amount of skill and work.

Related

Overriding Browser API's

I am developing a webextension in javascript for Firefox, Chrome etc.
It is designed to prevent the users browser from being fingerprinted.
Since the majority of information used to build browser fingerprints comes from javascript API's in the browser itself, is it possible to change/spoof the values that common API's might return from within a webextension/addon?
If this is not directly possible then is there any way to control what values these API's return to the website doing the fingerprinting to protect the users privacy?
Examples of API's I am talking about are:
user agent
screen print
color depth
current resolution
available resolution
device XDPI
device YDPI
plugin list
font list
local storage
session storage
timezone
language
system language
cookies
canvas print
You can try using Object.defineProperty():
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
console.log(window.screen.colorDepth); // 24
Object.defineProperty(window.screen, 'colorDepth', {
value: 'hello world',
configurable: true
});
console.log(window.screen.colorDepth); // hello world
In the above we're using Object.defineProperty to change the value of the property window.screen.colorDepth. This is where you would spoof the values using whatever method you want. You can use this same logic for modifying whichever properties you want to spoof (navigator.userAgent for example)
But there is a separation between the page's global object and the plugins global object. You should be able to overcome that by injecting the script into the document:
var code = function() {
console.log(window.screen.colorDepth); // 24
Object.defineProperty(window.screen, 'colorDepth', {
value: 'hello world',
configurable: true
});
console.log(window.screen.colorDepth); // hello world
};
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
See here and here for more info.
You can download a working chrome extension using the above code here (unzip the folder, navigate to chrome://extensions in chrome and drop the folder into the window)

How does this JavaScript open Windows Settings in Firefox?

After a new install of Firefox 45 Developer Edition, I saw this page. It has a button ("Let's do it") that when clicked, somehow opens up the Choose default apps settings page in Windows 10.
https://www.mozilla.org/en-US/firefox/windows-10/welcome/?utm_source=firefox-browser&utm_medium=firefox-browser
How is this done? I couldn't find anything through the Developer Console in the labyrinthine code on that page. Besides, I would have thought browsers don't allow JavaScript to open something as sensitive as the Settings app.
The page fires a custom event of type mozUITour on the document. This event is handled in the browser by content-UITour.js, which shovels out most of the actual processing to UITour.jsm. The unobfuscated client-side code can be viewed in UITour-lib.js.
Cutting through all the client-side abstraction, this is what’s happening:
document.dispatchEvent(new CustomEvent('mozUITour', {
bubbles: true,
detail: {
action: 'setConfiguration',
data: {
configuration: 'defaultBrowser'
}
}
}));
Then in the browser, it handles the event, dispatches the event in another internal event queue, where it will be processed by calling into nsIShellService::setDefaultBrowser, implemented by nsWindowsShellService.cpp. On what’s currently line 943, we have:
if (IsWin10OrLater()) {
rv = LaunchModernSettingsDialogDefaultApps();
} else {
rv = LaunchControlPanelDefaultsSelectionUI();
}
And LaunchModernSettingsDialogDefaultApps, I think, is a pretty descriptive function name.
Now, from your comment, “in a way that one could use it on their own page, for example”? Not so likely. content-UITour.js checks that the page has the uitour permission. From browser/app/permissions, we have:
# UITour
origin uitour 1 https://www.mozilla.org
origin uitour 1 https://self-repair.mozilla.org
origin uitour 1 https://support.mozilla.org
origin uitour 1 about:home
So unless you’re www.mozilla.org, self-repair.mozilla.org, support.mozilla.org, or about:home, you can’t do it, at least not by default. Before Firefox 15 (17 with a manual settings change, see this bug for more information), you might be able to use netscape.security.PrivilegeManager.enablePrivilege to request extra permissions from the browser, but that’s not around any more, and I’m not sure that even touches the same permission mechanism.

Detect Search Crawlers via JavaScript

I am wondering how would I go abouts in detecting search crawlers? The reason I ask is because I want to suppress certain JavaScript calls if the user agent is a bot.
I have found an example of how to to detect a certain browser, but am unable to find examples of how to detect a search crawler:
/MSIE (\d+\.\d+);/.test(navigator.userAgent); //test for MSIE x.x
Example of search crawlers I want to block:
Google
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Googlebot/2.1 (+http://www.googlebot.com/bot.html)
Googlebot/2.1 (+http://www.google.com/bot.html)
Baidu
Baiduspider+(+http://www.baidu.com/search/spider_jp.html)
Baiduspider+(+http://www.baidu.com/search/spider.htm)
BaiDuSpider
This is the regex the ruby UA agent_orange library uses to test if a userAgent looks to be a bot. You can narrow it down for specific bots by referencing the bot userAgent list here:
/bot|crawler|spider|crawling/i
For example you have some object, util.browser, you can store what type of device a user is on:
util.browser = {
bot: /bot|googlebot|crawler|spider|robot|crawling/i.test(navigator.userAgent),
mobile: ...,
desktop: ...
}
Try this. It's based on the crawlers list on available on https://github.com/monperrus/crawler-user-agents
var botPattern = "(googlebot\/|bot|Googlebot-Mobile|Googlebot-Image|Google favicon|Mediapartners-Google|bingbot|slurp|java|wget|curl|Commons-HttpClient|Python-urllib|libwww|httpunit|nutch|phpcrawl|msnbot|jyxobot|FAST-WebCrawler|FAST Enterprise Crawler|biglotron|teoma|convera|seekbot|gigablast|exabot|ngbot|ia_archiver|GingerCrawler|webmon |httrack|webcrawler|grub.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|bibnum.bnf|findlink|msrbot|panscient|yacybot|AISearchBot|IOI|ips-agent|tagoobot|MJ12bot|dotbot|woriobot|yanga|buzzbot|mlbot|yandexbot|purebot|Linguee Bot|Voyager|CyberPatrol|voilabot|baiduspider|citeseerxbot|spbot|twengabot|postrank|turnitinbot|scribdbot|page2rss|sitebot|linkdex|Adidxbot|blekkobot|ezooms|dotbot|Mail.RU_Bot|discobot|heritrix|findthatfile|europarchive.org|NerdByNature.Bot|sistrix crawler|ahrefsbot|Aboundex|domaincrawler|wbsearchbot|summify|ccbot|edisterbot|seznambot|ec2linkfinder|gslfbot|aihitbot|intelium_bot|facebookexternalhit|yeti|RetrevoPageAnalyzer|lb-spider|sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web-archive-net.com.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|seokicks-robot|it2media-domain-crawler|ip-web-crawler.com|siteexplorer.info|elisabot|proximic|changedetection|blexbot|arabot|WeSEE:Search|niki-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|Lipperhey SEO Service|CC Metadata Scaper|g00g1e.net|GrapeshotCrawler|urlappendbot|brainobot|fr-crawler|binlar|SimpleCrawler|Livelapbot|Twitterbot|cXensebot|smtbot|bnf.fr_bot|A6-Indexer|ADmantX|Facebot|Twitterbot|OrangeBot|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|SemrushBot|yoozBot|lipperhey|y!j-asr|Domain Re-Animator Bot|AddThis)";
var re = new RegExp(botPattern, 'i');
var userAgent = navigator.userAgent;
if (re.test(userAgent)) {
console.log('the user agent is a crawler!');
}
The following regex will match the biggest search engines according to this post.
/bot|google|baidu|bing|msn|teoma|slurp|yandex/i
.test(navigator.userAgent)
The matches search engines are:
Baidu
Bingbot/MSN
DuckDuckGo (duckduckbot)
Google
Teoma
Yahoo!
Yandex
Additionally, I've added bot as a catchall for smaller crawlers/bots.
This might help to detect the robots user agents while also keeping things more organized:
Javascript
const detectRobot = (userAgent) => {
const robots = new RegExp([
/bot/,/spider/,/crawl/, // GENERAL TERMS
/APIs-Google/,/AdsBot/,/Googlebot/, // GOOGLE ROBOTS
/mediapartners/,/Google Favicon/,
/FeedFetcher/,/Google-Read-Aloud/,
/DuplexWeb-Google/,/googleweblight/,
/bing/,/yandex/,/baidu/,/duckduck/,/yahoo/, // OTHER ENGINES
/ecosia/,/ia_archiver/,
/facebook/,/instagram/,/pinterest/,/reddit/, // SOCIAL MEDIA
/slack/,/twitter/,/whatsapp/,/youtube/,
/semrush/, // OTHER
].map((r) => r.source).join("|"),"i"); // BUILD REGEXP + "i" FLAG
return robots.test(userAgent);
};
Typescript
const detectRobot = (userAgent: string): boolean => {
const robots = new RegExp(([
/bot/,/spider/,/crawl/, // GENERAL TERMS
/APIs-Google/,/AdsBot/,/Googlebot/, // GOOGLE ROBOTS
/mediapartners/,/Google Favicon/,
/FeedFetcher/,/Google-Read-Aloud/,
/DuplexWeb-Google/,/googleweblight/,
/bing/,/yandex/,/baidu/,/duckduck/,/yahoo/, // OTHER ENGINES
/ecosia/,/ia_archiver/,
/facebook/,/instagram/,/pinterest/,/reddit/, // SOCIAL MEDIA
/slack/,/twitter/,/whatsapp/,/youtube/,
/semrush/, // OTHER
] as RegExp[]).map((r) => r.source).join("|"),"i"); // BUILD REGEXP + "i" FLAG
return robots.test(userAgent);
};
Use on server:
const userAgent = req.get('user-agent');
const isRobot = detectRobot(userAgent);
Use on "client" / some phantom browser a bot might be using:
const userAgent = navigator.userAgent;
const isRobot = detectRobot(userAgent);
Overview of Google crawlers:
https://developers.google.com/search/docs/advanced/crawling/overview-google-crawlers
isTrusted property could help you.
The isTrusted read-only property of the Event interface is a Boolean
that is true when the event was generated by a user action, and false
when the event was created or modified by a script or dispatched via
EventTarget.dispatchEvent().
eg:
isCrawler() {
return event.isTrusted;
}
⚠ Note that IE isn't compatible.
Read more from doc: https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
People might light to check out the new navigator.webdriver property, which allows bots to inform you that they are bots:
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver
The webdriver read-only property of the navigator interface indicates whether the user agent is controlled by automation.
It defines a standard way for co-operating user agents to inform the document that it is controlled by WebDriver, for example, so that alternate code paths can be triggered during automation.
It is supported by all major browsers and respected by major browser automation software like Puppeteer. Users of automation software can of course disable it, and so it should only be used to detect "good" bots.
I combined some of the above and removed some redundancy. I use this in .htaccess on a semi-private site:
(google|bot|crawl|spider|slurp|baidu|bing|msn|teoma|yandex|java|wget|curl|Commons-HttpClient|Python-urllib|libwww|httpunit|nutch|biglotron|convera|gigablast|archive|webmon|httrack|grub|netresearchserver|speedy|fluffy|bibnum|findlink|panscient|IOI|ips-agent|yanga|Voyager|CyberPatrol|postrank|page2rss|linkdex|ezooms|heritrix|findthatfile|Aboundex|summify|ec2linkfinder|facebook|slack|instagram|pinterest|reddit|twitter|whatsapp|yeti|RetrevoPageAnalyzer|sogou|wotbox|ichiro|drupact|coccoc|integromedb|siteexplorer|proximic|changedetection|WeSEE|scrape|scaper|g00g1e|binlar|indexer|MegaIndex|ltx71|BUbiNG|Qwantify|lipperhey|y!j-asr|AddThis)
The "test for MSIE x.x" example is just code for testing the userAgent against a Regular Expression. In your example the Regexp is the
/MSIE (\d+\.\d+);/
part. Just replace it with your own Regexp you want to test the user agent against. It would be something like
/Google|Baidu|Baiduspider/.test(navigator.userAgent)
where the vertical bar is the "or" operator to match the user agent against all of your mentioned robots. For more information about Regular Expression you can refer to this site since javascript uses perl-style RegExp.
I found this isbot package that has the built-in isbot() function. It seams to me that the package is properly maintained and that they keep everything up-to-date.
USAGE:
const isBot = require('isbot');
...
isBot(req.get('user-agent'));
Package: https://www.npmjs.com/package/isbot

Automatic Language Selection without click on flag [duplicate]

This question already has answers here:
Get visitors language & country code with javascript (client-side) [duplicate]
(3 answers)
How to determine user's locale within browser?
(10 answers)
Closed 4 years ago.
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 using navigator.language.
Using navigator.userLanguage , it detects the setting done thru
Start>ControlPanel>RegionalandLanguageOptions>Regional Options tab.
I have tested with navigator.browserLanguage and navigator.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 :(
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
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.
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)
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());
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+.
var language = navigator.languages && navigator.languages[0] || // Chrome / Firefox
navigator.language || // All browsers
navigator.userLanguage; // IE <= 10
console.log(language);
https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages
https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language
Try PWA Template https://github.com/StartPolymer/progressive-web-app-template
navigator.userLanguage for IE
window.navigator.language for firefox/opera/safari
I've been using Hamid's answer for a while, but it in cases where the languages array is like ["en", "en-GB", "en-US", "fr-FR", "fr", "en-ZA"] it will return "en", when "en-GB" would be a better match.
My update (below) will return the first long format code e.g. "en-GB", otherwise it will return the first short code e.g. "en", otherwise it will return null.
function getFirstBrowserLanguage() {
var nav = window.navigator,
browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'],
i,
language,
len,
shortLanguage = null;
// support for HTML 5.1 "navigator.languages"
if (Array.isArray(nav.languages)) {
for (i = 0; i < nav.languages.length; i++) {
language = nav.languages[i];
len = language.length;
if (!shortLanguage && len) {
shortLanguage = language;
}
if (language && len>2) {
return language;
}
}
}
// support for other well known properties in browsers
for (i = 0; i < browserLanguagePropertyKeys.length; i++) {
language = nav[browserLanguagePropertyKeys[i]];
//skip this loop iteration if property is null/undefined. IE11 fix.
if (language == null) { continue; }
len = language.length;
if (!shortLanguage && len) {
shortLanguage = language;
}
if (language && len > 2) {
return language;
}
}
return shortLanguage;
}
console.log(getFirstBrowserLanguage());
Update: IE11 was erroring when some properties were undefined. Added a check to skip those properties.
I've just come up with this. It combines newer JS destructuring syntax with a few standard operations to retrieve the language and locale.
var [lang, locale] = (
(
(
navigator.userLanguage || navigator.language
).replace(
'-', '_'
)
).toLowerCase()
).split('_');
Hope it helps someone
There is no decent way to get that setting, at least not something browser independent.
But the server has that info, because it is part of the HTTP request header (the Accept-Language field, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
So the only reliable way is to get an answer back from the server. You will need something that runs on the server (like .asp, .jsp, .php, CGI) and that "thing" can return that info.
Good examples here: http://www.developershome.com/wap/detection/detection.asp?page=readHeader
I can't find a single reference that state that it's possible without involving the serverside.
MSDN on:
navigator.browserLanguage
navigator.systemLanguage
navigator.userLanguage
From browserLanguage:
In Microsoft Internet Explorer 4.0 and
earlier, the browserLanguage property
reflects the language of the installed
browser's user interface. For example,
if you install a Japanese version of
Windows Internet Explorer on an
English operating system,
browserLanguage would be ja.
In Internet Explorer 5 and later,
however, the browserLanguage property
reflects the language of the operating
system regardless of the installed
language version of Internet Explorer.
However, if Microsoft Windows 2000
MultiLanguage version is installed,
the browserLanguage property indicates
the language set in the operating
system's current menus and dialogs, as
found in the Regional Options of the
Control Panel. For example, if you
install a Japanese version of Internet
Explorer 5 on an English (United
Kingdom) operating system,
browserLanguage would be en-gb. If you
install Windows 2000 MultiLanguage
version and set the language of the
menus and dialogs to French,
browserLanguage would be fr, even
though you have a Japanese version of
Internet Explorer.
Note This property does not indicate
the language or languages set by the
user in Language Preferences, located
in the Internet Options dialog box.
Furthermore, it looks like browserLanguage is deprecated cause IE8 doesn't list it
I had the same problem, and I wrote the following front-end only library that wraps up the code for multiple browsers. It's not much code, but nice to not have to copy and paste the same code across multiple websites.
Get it: acceptedlanguages.js
Use it:
<script src="acceptedlanguages.js"></script>
<script type="text/javascript">
console.log('Accepted Languages: ' + acceptedlanguages.accepted);
</script>
It always returns an array, ordered by users preference. In Safari & IE the array is always single length. In FF and Chrome it may be more than one language.
I would like to share my code, because it works and it is different than the others given anwers.
In this example, if you speak French (France, Belgium or other French language) you are redirected on the French page, otherwise on the English page, depending on the browser configuration:
<script type="text/javascript">
$(document).ready(function () {
var userLang = navigator.language || navigator.userLanguage;
if (userLang.startsWith("fr")) {
window.location.href = '../fr/index.html';
}
else {
window.location.href = '../en/index.html';
}
});
</script>
If you only need to support certain modern browsers then you can now use:
navigator.languages
which returns an array of the user's language preferences in the order specified by the user.
As of now (Sep 2014) this works on:
Chrome (v37),
Firefox (v32) and
Opera (v24)
But not on:
IE (v11)
Javascript way:
var language = window.navigator.userLanguage || window.navigator.language;//returns value like 'en-us'
If you are using jQuery.i18n plugin, you can use:
jQuery.i18n.browserLang();//returns value like '"en-US"'
If you are developing a Chrome App / Extension use the chrome.i18n API.
chrome.i18n.getAcceptLanguages(function(languages) {
console.log(languages);
// ["en-AU", "en", "en-US"]
});
DanSingerman has a very good solution for this question.
The only reliable source for the language is in the HTTP-request header.
So you need a server-side script to reply the request-header or at least the Accept-Language field back to you.
Here is a very simple Node.js server which should be compatible with DanSingermans jQuery plugin.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(JSON.stringify(req.headers));
}).listen(80,'0.0.0.0');
For what it's worth, Wikimedia's Universal Language Selector library has hooks for doing this:
https://www.mediawiki.org/wiki/Extension:UniversalLanguageSelector
See the function getFrequentLanguageList in resources/js/ext.uls.init.js . Direct link:
https://gerrit.wikimedia.org/r/gitweb?p=mediawiki/extensions/UniversalLanguageSelector.git;a=blob;f=resources/js/ext.uls.init.js;hb=HEAD
It still depends on the server, or more specifically, the MediaWiki API. The reason I'm showing it is that it may provide a good example of getting all the useful information about the user's language: browser language, Accept-Language, geolocation (with getting country/language info from the CLDR), and of course, user's own site preferences.
Dan Singerman's answer has an issue that the header fetched has to be used right away, due to the asynchronous nature of jQuery's ajax. However, with his google app server, I wrote the following, such that the header is set as part of the initial set up and can be used at later time.
<html>
<head>
<script>
var bLocale='raw'; // can be used at any other place
function processHeaders(headers){
bLocale=headers['Accept-Language'];
comma=bLocale.indexOf(',');
if(comma>0) bLocale=bLocale.substring(0, comma);
}
</script>
<script src="jquery-1.11.0.js"></script>
<script type="application/javascript" src="http://ajaxhttpheaders.appspot.com?callback=processHeaders"></script>
</head>
<body>
<h1 id="bLocale">Should be the browser locale here</h1>
</body>
<script>
$("#bLocale").text(bLocale);
</script>
</html>
If you don't want to rely on an external server and you have one of your own you can use a simple PHP script to achieve the same behavior as #DanSingerman answer.
languageDetector.php:
<?php
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
echo json_encode($lang);
?>
And just change this lines from the jQuery script:
url: "languageDetector.php",
dataType: 'json',
success: function(language) {
nowDoSomethingWithIt(language);
}
If you have control of a backend and are using django, a 4 line implementation of Dan's idea is:
def get_browser_lang(request):
if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
return JsonResponse({'response': request.META['HTTP_ACCEPT_LANGUAGE']})
else:
return JsonResponse({'response': settings.DEFAULT_LANG})
then in urls.py:
url(r'^browserlang/$', views.get_browser_lang, name='get_browser_lang'),
and on the front end:
$.get(lg('SERVER') + 'browserlang/', function(data){
var lang_code = data.response.split(',')[0].split(';')[0].split('-')[0];
});
(you have to set DEFAULT_LANG in settings.py of course)
Based on the answer here Accessing the web page's HTTP Headers in JavaScript I built the following script to get the browser language:
var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
var contentLanguage = headers.match( /^content-language\:(.*)$/gm );
if(contentLanguage[0]) {
return contentLanguage[0].split(":")[1].trim().toUpperCase();
}
If you are using ASP .NET MVC and you want to get the Accepted-Languages header from JavaScript then here is a workaround example that does not involve any asynchronous requests.
In your .cshtml file, store the header securely in a div's data- attribute:
<div data-languages="#Json.Encode(HttpContext.Current.Request.UserLanguages)"></div>
Then your JavaScript code can access the info, e.g. using JQuery:
<script type="text/javascript">
$('[data-languages]').each(function () {
var languages = $(this).data("languages");
for (var i = 0; i < languages.length; i++) {
var regex = /[-;]/;
console.log(languages[i].split(regex)[0]);
}
});
</script>
Of course you can use a similar approach with other server technologies as others have mentioned.
For who are looking for Java Server solution
Here is RestEasy
#GET
#Path("/preference-language")
#Consumes({"application/json", "application/xml"})
#Produces({"application/json", "application/xml"})
public Response getUserLanguagePreference(#Context HttpHeaders headers) {
return Response.status(200)
.entity(headers.getAcceptableLanguages().get(0))
.build();
}
i had a diffrent approach, this might help someone in the future:
the customer wanted a page where you can swap languages.
i needed to format numbers by that setting (not the browser setting / not by any predefined setting)
so i set an initial setting depending on the config settings (i18n)
$clang = $this->Session->read('Config.language');
echo "<script type='text/javascript'>var clang = '$clang'</script>";
later in the script i used a function to determine what numberformating i need
function getLangsettings(){
if(typeof clang === 'undefined') clang = navigator.language;
//console.log(clang);
switch(clang){
case 'de':
case 'de-de':
return {precision : 2, thousand : ".", decimal : ","}
case 'en':
case 'en-gb':
default:
return {precision : 2, thousand : ",", decimal : "."}
}
}
so i used the set language of the page and as a fallback i used the browser settings.
which should be helpfull for testing purposes aswell.
depending on your customers you might not need that settings.
I have a hack that I think uses very little code and is quite reliable.
Put your site's files in a subdirectory. SSL into your server and create symlinks to that subdirectory where your files are stored that indicate your languages.
Something like this:
ln -s /var/www/yourhtml /var/www/en
ln -s /var/www/yourhtml /var/www/sp
ln -s /var/www/yourhtml /var/www/it
Use your web server to read HTTP_ACCEPT_LANGUAGE and redirect to these "different subdirectories" according to the language value it provides.
Now you can use Javascript's window.location.href to get your url and use it in conditionals to reliably identify the preferred language.
url_string = window.location.href;
if (url_string = "http://yoursite.com/it/index.html") {
document.getElementById("page-wrapper").className = "italian";
}

Can javascript access a filesystem? [duplicate]

This question already has answers here:
Local file access with JavaScript
(14 answers)
Closed 8 years ago.
I was pretty sure the answer was NO, and hence google gears, adobe AIR, etc.
If I was right, then how does http://tiddlywiki.com work? It is persistent and written in javascript. It is also just a single HTML file that has no external (serverside) dependencies. WTF? Where/how does it store its state?
Tiddlywiki has several methods of saving data, depending on which browser is used. As you could see in the source.
If ActiveX is enabled, it uses Scripting.FileSystemObject.
On Gecko-based browsers, it tries to use UniversalXPConnect.
If Java is enabled, it uses the TiddlySaver Java applet.
If Java LiveConnect is enabled, it tries to use Java's file classes.
HTML5's File[1], FileWriter[2], and FileSystem[3] APIs are available in the latest Developer channel of Google Chrome. The FileSystem API lets you read/write to a sandbox filesystem within a space the browser knows about. You cannot, for example, open 'My Pictures' folder on the user's local FS and read/write to that. That's something in the works, but it won't be ready for a while. Example of writing a file:
window.requestFileSystem(
TEMPORARY, // persistent vs. temporary storage
1024 * 1024, // 1MB. Size (bytes) of needed space
initFs, // success callback
opt_errorHandler // opt. error callback, denial of access
);
function initFs(fs) {
fs.root.getFile('logFile.txt', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) { // FileWriter
writer.onwrite = function(e) {
console.log('Write completed.');
};
writer.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var bb = new BlobBuilder();
bb.append('Lorem ipsum');
writer.write(bb.getBlob('text/plain'));
}, errorHandler);
}
}
Check out this HTML5 Storage slide deck for more code snippets.
It uses a java file references like this:
drivers.tiddlySaver = {
name: "tiddlySaver",
deferredInit: function() {
if(!document.applets["TiddlySaver"] && !$.browser.mozilla && !$.browser.msie && document.location.toString().substr(0,5) == "file:") {
$(document.body).append("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1'height='1'></applet>");
}
},
isAvailable: function() {
return !!document.applets["TiddlySaver"];
},
loadFile: function(filePath) {
var r;
try {
if(document.applets["TiddlySaver"]) {
r = document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8");
return (r === undefined || r === null) ? null : String(r);
}
} catch(ex) {
}
return null;
},
saveFile: function(filePath,content) {
try {
if(document.applets["TiddlySaver"])
return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
} catch(ex) {
}
return null;
}
}
Technically you can do
netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite');
in a netscape-compatible browser (Firefox, Mozilla, Netscape), and it will ask the user* whether or not to allow filesystem access, but this is not portable.
*once per browser process
Can javascript access a filesystem?
Not outside of the sandbox area mentioned above, to the best of my knowledge. However, it can access a signed java applet that has callable public methods which can get to all files. I have done it and it works fine and is cross browser.
The signing part is somewhat involved and for professional use you might need to pay for a code signing certificate which authorises your identity. Get it from some place like Verisign. That way users at least know who the applet is written by (if that helps). You can sign it yourself for free but one of those "possible security risk" popups will occur at first use for authorisation by the user.
You would think that such signed applets for file writing would exist already for download but I couldn't find any via searching. If they did, you could just plug it in your page, learn the API and off you go.
The answer is indeed NO. Java applets, and the dreaded ActiveX plugins are usually used if this is required

Categories