Greasy Fork

Language Switcher for Google™

a port of Language Switcher for Google™ to userscript.js

目前为 2021-01-13 提交的版本。查看 最新版本

// ==UserScript==
// @name        Language Switcher for Google™
// @author      gb.ianni
// @namespace   gb.ianni
// @version     2.2.1
// @copyright   Copyright 2015 gb.ianni
// @description a port of Language Switcher for Google™ to userscript.js
// @include *://www.google.com/*
// @include *://www.google.ad/*
// @include *://www.google.ae/*
// @include *://www.google.com.af/*
// @include *://www.google.com.ag/*
// @include *://www.google.com.ai/*
// @include *://www.google.am/*
// @include *://www.google.co.ao/*
// @include *://www.google.com.ar/*
// @include *://www.google.as/*
// @include *://www.google.at/*
// @include *://www.google.com.au/*
// @include *://www.google.az/*
// @include *://www.google.ba/*
// @include *://www.google.com.bd/*
// @include *://www.google.be/*
// @include *://www.google.bf/*
// @include *://www.google.bg/*
// @include *://www.google.com.bh/*
// @include *://www.google.bi/*
// @include *://www.google.bj/*
// @include *://www.google.com.bn/*
// @include *://www.google.com.bo/*
// @include *://www.google.com.br/*
// @include *://www.google.bs/*
// @include *://www.google.co.bw/*
// @include *://www.google.by/*
// @include *://www.google.com.bz/*
// @include *://www.google.ca/*
// @include *://www.google.cd/*
// @include *://www.google.cf/*
// @include *://www.google.cg/*
// @include *://www.google.ch/*
// @include *://www.google.ci/*
// @include *://www.google.co.ck/*
// @include *://www.google.cl/*
// @include *://www.google.cm/*
// @include *://www.google.cn/*
// @include *://www.google.com.co/*
// @include *://www.google.co.cr/*
// @include *://www.google.com.cu/*
// @include *://www.google.cz/*
// @include *://www.google.de/*
// @include *://www.google.dj/*
// @include *://www.google.dk/*
// @include *://www.google.dm/*
// @include *://www.google.com.do/*
// @include *://www.google.dz/*
// @include *://www.google.com.ec/*
// @include *://www.google.ee/*
// @include *://www.google.com.eg/*
// @include *://www.google.es/*
// @include *://www.google.com.et/*
// @include *://www.google.fi/*
// @include *://www.google.com.fj/*
// @include *://www.google.fm/*
// @include *://www.google.fr/*
// @include *://www.google.ga/*
// @include *://www.google.ge/*
// @include *://www.google.gg/*
// @include *://www.google.com.gh/*
// @include *://www.google.com.gi/*
// @include *://www.google.gl/*
// @include *://www.google.gm/*
// @include *://www.google.gp/*
// @include *://www.google.gr/*
// @include *://www.google.com.gt/*
// @include *://www.google.gy/*
// @include *://www.google.com.hk/*
// @include *://www.google.hn/*
// @include *://www.google.hr/*
// @include *://www.google.ht/*
// @include *://www.google.hu/*
// @include *://www.google.co.id/*
// @include *://www.google.ie/*
// @include *://www.google.co.il/*
// @include *://www.google.im/*
// @include *://www.google.co.in/*
// @include *://www.google.iq/*
// @include *://www.google.is/*
// @include *://www.google.it/*
// @include *://www.google.je/*
// @include *://www.google.com.jm/*
// @include *://www.google.jo/*
// @include *://www.google.co.jp/*
// @include *://www.google.co.ke/*
// @include *://www.google.com.kh/*
// @include *://www.google.ki/*
// @include *://www.google.kg/*
// @include *://www.google.co.kr/*
// @include *://www.google.com.kw/*
// @include *://www.google.kz/*
// @include *://www.google.la/*
// @include *://www.google.com.lb/*
// @include *://www.google.li/*
// @include *://www.google.lk/*
// @include *://www.google.co.ls/*
// @include *://www.google.lt/*
// @include *://www.google.lu/*
// @include *://www.google.lv/*
// @include *://www.google.com.ly/*
// @include *://www.google.co.ma/*
// @include *://www.google.md/*
// @include *://www.google.me/*
// @include *://www.google.mg/*
// @include *://www.google.mk/*
// @include *://www.google.ml/*
// @include *://www.google.mn/*
// @include *://www.google.ms/*
// @include *://www.google.com.mt/*
// @include *://www.google.mu/*
// @include *://www.google.mv/*
// @include *://www.google.mw/*
// @include *://www.google.com.mx/*
// @include *://www.google.com.my/*
// @include *://www.google.co.mz/*
// @include *://www.google.com.na/*
// @include *://www.google.com.nf/*
// @include *://www.google.com.ng/*
// @include *://www.google.com.ni/*
// @include *://www.google.ne/*
// @include *://www.google.nl/*
// @include *://www.google.no/*
// @include *://www.google.com.np/*
// @include *://www.google.nr/*
// @include *://www.google.nu/*
// @include *://www.google.co.nz/*
// @include *://www.google.com.om/*
// @include *://www.google.com.pa/*
// @include *://www.google.com.pe/*
// @include *://www.google.com.ph/*
// @include *://www.google.com.pk/*
// @include *://www.google.pl/*
// @include *://www.google.pn/*
// @include *://www.google.com.pr/*
// @include *://www.google.ps/*
// @include *://www.google.pt/*
// @include *://www.google.com.py/*
// @include *://www.google.com.qa/*
// @include *://www.google.ro/*
// @include *://www.google.ru/*
// @include *://www.google.rw/*
// @include *://www.google.com.sa/*
// @include *://www.google.com.sb/*
// @include *://www.google.sc/*
// @include *://www.google.se/*
// @include *://www.google.com.sg/*
// @include *://www.google.sh/*
// @include *://www.google.si/*
// @include *://www.google.sk/*
// @include *://www.google.com.sl/*
// @include *://www.google.sn/*
// @include *://www.google.sm/*
// @include *://www.google.st/*
// @include *://www.google.com.sv/*
// @include *://www.google.td/*
// @include *://www.google.tg/*
// @include *://www.google.co.th/*
// @include *://www.google.com.tj/*
// @include *://www.google.tk/*
// @include *://www.google.tl/*
// @include *://www.google.tm/*
// @include *://www.google.tn/*
// @include *://www.google.to/*
// @include *://www.google.com.tr/*
// @include *://www.google.tt/*
// @include *://www.google.com.tw/*
// @include *://www.google.co.tz/*
// @include *://www.google.com.ua/*
// @include *://www.google.co.ug/*
// @include *://www.google.co.uk/*
// @include *://www.google.com.uy/*
// @include *://www.google.co.uz/*
// @include *://www.google.com.vc/*
// @include *://www.google.co.ve/*
// @include *://www.google.vg/*
// @include *://www.google.co.vi/*
// @include *://www.google.com.vn/*
// @include *://www.google.vu/*
// @include *://www.google.ws/*
// @include *://www.google.rs/*
// @include *://www.google.co.za/*
// @include *://www.google.co.zm/*
// @include *://www.google.co.zw/*
// ==/UserScript==

var debug = false;

cLog("Start");

//
// Parses and puts in a hash map CGI URL parameters.
//
cLog("Window href:"+window.location.href);

//debugLayer = { 'FORM3' : 1, 'PROF' : 1 };
debugLayer = { 'INJ' : 1 };

var vars = null;
function getUrlVars()

{
	if (!vars) {
		vars = [];
		var hash;
		var positionQ = window.location.href.indexOf('?');
		var positionS = window.location.href.indexOf('#');

		if (positionQ > 0 && positionS > 0)
			position = Math.min(positionQ,positionS);
		else if (positionQ > 0)
			position = positionQ;
		else position = positionS;

		var hashes = window.location.href.slice(position+1).split(/&|#/);

	    for(var i = 0; i < hashes.length; i++)
	    {
	        cLog('VALUE:'+hashes[i]);
	        hash = hashes[i].split('=');
	        //vars.push(hash[0]);
	        vars[hash[0]] = hash[1];

	    }
	    // Possibly missing hl value is filled with languages value corresponding to TLD value
	    if (!vars['hl'])
	    	vars['hl'] = domainsToLang[getTLD()];
        // Possibly missing lr value is filled with languages value corresponding to TLD value
	    if (!vars['lr'])
	    	vars['lr'] = "lang_" + domainsToLang[getTLD()];
	}
    return vars;
}

function getTLD()
{
	var tld = window.location.href.match(/\.(\w+?)(\/|$)/)[1];
	cLog('TLD='+tld);
	return tld;
}
cLog('TLD:'+getTLD());

//
// Main
//


//var addPath = "/html/body/div/*/div/div[2]/div";
//var addPath = "/html/body/div/div/div[2]/div[@id='resultStats']";
//var addPath = "/html/body/div[@id='main']/div[@id='cnt']/div[@id='subform_ctrl']";
//var addSelector = '#resultStats';
var addPaths = [ "//*[@id='resultStats']", "//*[@id='gbx1']" ];

//
// Add Possible Injection points below
//
// Places where to try injection of Language switcher box
var addSelectors = { "#resultStats" : 1, "#slim_appbar" : 1, "#extabar" : 1, "#topabar" : 1, ".med" : 1, ".g" : 1, ".appbar" : 1};
var languageVars = [ "hl", "#hl" ];
var documentFormName = 'gbqf';

/*
 *   Injected Code for querying as a different language
 */
var labels = ["en-US", "it", "fr","de","es","cn/hk","jp","ru","nl"];
//,"nl","ru","gr","jp","tr","cn","arb","il");

var languages = ["en","it","fr","de","es","zh-CN","ja","ru","nl"];
//,"nl","ru","el","ja","tr","zh-CN","ar","iw");

var domains = ["com", "it", "fr", "de", "es", "com.hk", "co.jp","ru","nl"];
var tlds = ["com", "it", "fr", "de", "es", "cn", "jp","ru","nl"];

var wikipediaDomains = ["en", "it","fr","de","es","zh","ja","ru","nl"];

var domainsToLang = [];

for (var i = 0; i < domains.length; i++)
	{
		domainsToLang[tlds[i]] = languages[i];
	}

var injectedObjectName = 'AGB_language_switcher';

var status = new Array();

var radioOn = "checked=\"checked\"";
var radioOff = "";

for (var i = 0; i < labels.length; i++)
{
   if ("lang_" + languages[i] != getUrlVars()["lr"] )
      status[languages[i]] = radioOff;
   else
      status[languages[i]] = radioOn;
}

cLog("GetURlVars="+getUrlVars());
cLog("n_lang is="+getUrlVars()["n_lang"]);
cLog("hl is="+getUrlVars()["hl"]);
cLog("lr is="+getUrlVars()["lr"]);
cLog("q is="+getUrlVars()["q"]);
cLog("Languages[n_lang] is="+status[getUrlVars()["hl"]]);


var inject = "<div id='"+injectedObjectName+"' class='q qs', style='float:right'><br>Ask again on another local version: \
<table  width='100%' border='0' cellpadding='0' cellspacing='0' style='position:static'><td> \
<table border='0' cellpadding='0' cellspacing='0'> \
<tbody><tr><th scope='row' align='left'>Google:</th>";

//
// Prepare code for radio buttons to be injected in Google page results
//



for (var i = 0; i < languages.length; i++)
{
   //var clicInject = "document."+documentFormName+".hl.value ='"+languages[i]+"'; document."+documentFormName+".submit(); ";
    cLog("Injecting "+domains[i]+" code");
	var clicInject =
	    "console.log('clic"+domains[i]+"'); var a = window.location.href.slice(0); " +
   		"console.log(a); a = a.replace(/google\\.(.*?)\\//,'google."+domains[i]+"/');" +
   		"console.log(a); if (!a.match( /(\\?|\\&)hl=/ )) a = a + '&hl='; " +
        "console.log(a); if (!a.match( /(\\?|\\&)lr=/ )) a = a + '&lr='; " +
   		"a = a.replace(/hl=(.*?)(&|$)/,'hl="+languages[i]+"$2'); " +
        "a = a.replace(/lr=(.*?)(&|$)/,'lr=lang_"+languages[i]+"$2'); " +
   	    "console.log(a); " +
   	    "window.location.href =a; " +
   	    "console.log('clac"+domains[i]+"');";
   var checked = ("lang_" + languages[i] == getUrlVars()["lr"]) && (tlds[i] == getTLD() || true);

   inject += "<td nowrap valign='middle'><label for=il \
        onClick=\""+clicInject+"\" style=\"font-size:large;\"><input id='g_"+languages[i]+"' "+(checked ? ' checked ' :'')+"type=radio name=n_lang value='"+languages[i]+"'>"+labels[i]+"</label></td>";
}
inject += "<td>&nbsp;&nbsp;&nbsp;</td>";
cLog("This is what I'm injecting:"+inject);
/*
function getClicFunction(i)
{
	return function() { document[documentFormName].hl.value = languages[i]; document[documentFormName].submit(); };
}
for (var i = 0; i < languages.length; i++)
	{
		inject.append($('<td>').attr({ 'valign' : 'middle' })
							.append($('<input>').attr( { id : 'g_'+languages[i], type : 'radio', name : 'n_lang', value : languages[i]}
							)
					  ));
	}
*/
//
// Adds Wikipedia radio buttons. Constructs xx.wikipedia.org for xx taken from wikipediaDomains[]
//
  inject += "</tr><tr><th scope='row' align='left'>Wikipedia:</th>";
  var query = getUrlVars()["q"];
  for (var i = 0; i < languages.length; i++)
  {
     var clicWikiInject = "window.location = 'http://"+wikipediaDomains[i]+".wikipedia.org/?search="+query+"';";

    inject += "<td nowrap valign='middle'><input id=g_w"+languages[i]+" type=radio name=n_lang value='w"+languages[i]+"' \
                             onClick=\""+clicWikiInject+"\"><label for=il>"+labels[i]+"</label></td>";

  }
   inject += "<td>&nbsp;&nbsp;&nbsp;</td></tr></tbody></table></td></table>";

   tryInjection();
   document.addEventListener("DOMNodeInserted", function(event){
       var element = event.target;
       //cLog("Node INSERTED "+element.name);
       //if (element.className == 'med') {
       	tryInjection();
       //}
   });

var alreadyInjected = false;
function tryInjection()
{
   if (alreadyInjected) return;
   var placeToInject = null;
     if (!document.getElementById(injectedObjectName)) {
         lLog("Starting injection","INJ");

    	 for (var selector in addSelectors) {
	    	  lLog("Attempting injection point: "+selector,"INJ");
	    	  if (placeToInject = document.querySelectorAll(selector)[0])
	    	  {
	    		  lLog("Matched Selector:"+selector,"INJ"); break;
	    	  }
	      }
	      lLog("Place to inject:"+placeToInject,"INJ");
			if (placeToInject)
			{
                  //placeToInject.innerHTML = "<td>"+inject+"</td></div>" + placeToInject.innerHTML;
				  document.querySelectorAll(selector).forEach(el => el.after(new DOMParser().parseFromString(inject, "text/html").body.firstChild));
			      alreadyInjected = true;
			}
		      lLog("Ending injection","INJ");

         }
         else lLog("Looks like there is already a language_switcher here.","INJ2");
}

function cLog(str)
{
  if (debug) console.log(str);
}

/**
 * main logging function
 * @param str  String to be printed
 * @param level debugLayer triggering the printout. Will be printed only if level is in the currently active debugLayers
 */

function lLog(str, level) {
	//console.log("Logging:"+str);
	if (!isNaN(level))
		str += " USING NUMBERS FOR DEBUG LEVELS IS DEPRECATED - ";
	else if (level.match(/PROF/))
		{
		   str = this.debug.getPace()  + "\n" + str;
		};
//	console.log("mid Logging:"+this.debugLayer+" "+this.localLog);

		if (debugLayer == level || debugLayer == "ALL" || (debugLayer instanceof Object && debugLayer[level]) )
		{ cLog(str); }
	//console.log("end Logging:"+str);

};

//
// XPath evaluation wrapping function.
//
function xpath(query,node) {
    return document.evaluate(query, node, null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}

//
// Returns the first element of a given XPath query
//
function fXPath(query,node)
   {
      var elements = xpath(query,node);
      return elements.snapshotItem(0);
   }

//
// Returns the last element of a given XPath query
//
function lXPath(query,node)
   {
      cLog("Asking for "+query);
      var elements = xpath(query,node);
      cLog("Elements are "+elements.snapshotLength);
      return elements.snapshotItem(elements.snapshotLength-1);
   }

//
// 0-ize NaN and non-number strings
//
function normalize(str) {
       var temp = (str != null) ? parseInt(str) : 0;
       return (isNaN(temp)) ? 0 : temp;
}