- // ==UserScript==
- // @name ACT.Google.DM.NCR
- // @name:zh-CN ACT.谷歌.DM.NCR
- // @description No country redirect, easy to switch region/language.
- // @description:zh-CN 没有国家重定向,轻松切换区域/语言。
- // @author ACTCD
- // @version 20231206.1
- // @license GPL-3.0-or-later
- // @namespace ACTCD/Userscripts
- // @supportURL https://github.com/ACTCD/Userscripts#contact
- // @homepageURL https://github.com/ACTCD/Userscripts
- // @match *://*.google.com/*
- // @match *://*.google.ad/*
- // @match *://*.google.ae/*
- // @match *://*.google.com.af/*
- // @match *://*.google.com.ag/*
- // @match *://*.google.com.ai/*
- // @match *://*.google.al/*
- // @match *://*.google.am/*
- // @match *://*.google.co.ao/*
- // @match *://*.google.com.ar/*
- // @match *://*.google.as/*
- // @match *://*.google.at/*
- // @match *://*.google.com.au/*
- // @match *://*.google.az/*
- // @match *://*.google.ba/*
- // @match *://*.google.com.bd/*
- // @match *://*.google.be/*
- // @match *://*.google.bf/*
- // @match *://*.google.bg/*
- // @match *://*.google.com.bh/*
- // @match *://*.google.bi/*
- // @match *://*.google.bj/*
- // @match *://*.google.com.bn/*
- // @match *://*.google.com.bo/*
- // @match *://*.google.com.br/*
- // @match *://*.google.bs/*
- // @match *://*.google.bt/*
- // @match *://*.google.co.bw/*
- // @match *://*.google.by/*
- // @match *://*.google.com.bz/*
- // @match *://*.google.ca/*
- // @match *://*.google.cd/*
- // @match *://*.google.cf/*
- // @match *://*.google.cg/*
- // @match *://*.google.ch/*
- // @match *://*.google.ci/*
- // @match *://*.google.co.ck/*
- // @match *://*.google.cl/*
- // @match *://*.google.cm/*
- // @match *://*.google.cn/*
- // @match *://*.google.com.co/*
- // @match *://*.google.co.cr/*
- // @match *://*.google.com.cu/*
- // @match *://*.google.cv/*
- // @match *://*.google.com.cy/*
- // @match *://*.google.cz/*
- // @match *://*.google.de/*
- // @match *://*.google.dj/*
- // @match *://*.google.dk/*
- // @match *://*.google.dm/*
- // @match *://*.google.com.do/*
- // @match *://*.google.dz/*
- // @match *://*.google.com.ec/*
- // @match *://*.google.ee/*
- // @match *://*.google.com.eg/*
- // @match *://*.google.es/*
- // @match *://*.google.com.et/*
- // @match *://*.google.fi/*
- // @match *://*.google.com.fj/*
- // @match *://*.google.fm/*
- // @match *://*.google.fr/*
- // @match *://*.google.ga/*
- // @match *://*.google.ge/*
- // @match *://*.google.gg/*
- // @match *://*.google.com.gh/*
- // @match *://*.google.com.gi/*
- // @match *://*.google.gl/*
- // @match *://*.google.gm/*
- // @match *://*.google.gr/*
- // @match *://*.google.com.gt/*
- // @match *://*.google.gy/*
- // @match *://*.google.hk/*
- // @match *://*.google.com.hk/*
- // @match *://*.google.hn/*
- // @match *://*.google.hr/*
- // @match *://*.google.ht/*
- // @match *://*.google.hu/*
- // @match *://*.google.co.id/*
- // @match *://*.google.ie/*
- // @match *://*.google.co.il/*
- // @match *://*.google.im/*
- // @match *://*.google.co.in/*
- // @match *://*.google.iq/*
- // @match *://*.google.is/*
- // @match *://*.google.it/*
- // @match *://*.google.je/*
- // @match *://*.google.com.jm/*
- // @match *://*.google.jo/*
- // @match *://*.google.jp/*
- // @match *://*.google.co.jp/*
- // @match *://*.google.co.ke/*
- // @match *://*.google.com.kh/*
- // @match *://*.google.ki/*
- // @match *://*.google.kg/*
- // @match *://*.google.co.kr/*
- // @match *://*.google.com.kw/*
- // @match *://*.google.kz/*
- // @match *://*.google.la/*
- // @match *://*.google.com.lb/*
- // @match *://*.google.li/*
- // @match *://*.google.lk/*
- // @match *://*.google.co.ls/*
- // @match *://*.google.lt/*
- // @match *://*.google.lu/*
- // @match *://*.google.lv/*
- // @match *://*.google.com.ly/*
- // @match *://*.google.co.ma/*
- // @match *://*.google.md/*
- // @match *://*.google.me/*
- // @match *://*.google.mg/*
- // @match *://*.google.mk/*
- // @match *://*.google.ml/*
- // @match *://*.google.com.mm/*
- // @match *://*.google.mn/*
- // @match *://*.google.ms/*
- // @match *://*.google.com.mt/*
- // @match *://*.google.mu/*
- // @match *://*.google.mv/*
- // @match *://*.google.mw/*
- // @match *://*.google.com.mx/*
- // @match *://*.google.com.my/*
- // @match *://*.google.co.mz/*
- // @match *://*.google.com.na/*
- // @match *://*.google.com.ng/*
- // @match *://*.google.com.ni/*
- // @match *://*.google.ne/*
- // @match *://*.google.nl/*
- // @match *://*.google.no/*
- // @match *://*.google.com.np/*
- // @match *://*.google.nr/*
- // @match *://*.google.nu/*
- // @match *://*.google.co.nz/*
- // @match *://*.google.com.om/*
- // @match *://*.google.com.pa/*
- // @match *://*.google.com.pe/*
- // @match *://*.google.com.pg/*
- // @match *://*.google.com.ph/*
- // @match *://*.google.com.pk/*
- // @match *://*.google.pl/*
- // @match *://*.google.pn/*
- // @match *://*.google.com.pr/*
- // @match *://*.google.ps/*
- // @match *://*.google.pt/*
- // @match *://*.google.com.py/*
- // @match *://*.google.com.qa/*
- // @match *://*.google.ro/*
- // @match *://*.google.ru/*
- // @match *://*.google.rw/*
- // @match *://*.google.com.sa/*
- // @match *://*.google.com.sb/*
- // @match *://*.google.sc/*
- // @match *://*.google.se/*
- // @match *://*.google.com.sg/*
- // @match *://*.google.sh/*
- // @match *://*.google.si/*
- // @match *://*.google.sk/*
- // @match *://*.google.com.sl/*
- // @match *://*.google.sn/*
- // @match *://*.google.so/*
- // @match *://*.google.sm/*
- // @match *://*.google.sr/*
- // @match *://*.google.st/*
- // @match *://*.google.com.sv/*
- // @match *://*.google.td/*
- // @match *://*.google.tg/*
- // @match *://*.google.co.th/*
- // @match *://*.google.com.tj/*
- // @match *://*.google.tl/*
- // @match *://*.google.tm/*
- // @match *://*.google.tn/*
- // @match *://*.google.to/*
- // @match *://*.google.com.tr/*
- // @match *://*.google.tt/*
- // @match *://*.google.com.tw/*
- // @match *://*.google.co.tz/*
- // @match *://*.google.com.ua/*
- // @match *://*.google.co.ug/*
- // @match *://*.google.co.uk/*
- // @match *://*.google.com.uy/*
- // @match *://*.google.co.uz/*
- // @match *://*.google.com.vc/*
- // @match *://*.google.co.ve/*
- // @match *://*.google.vg/*
- // @match *://*.google.co.vi/*
- // @match *://*.google.com.vn/*
- // @match *://*.google.vu/*
- // @match *://*.google.ws/*
- // @match *://*.google.rs/*
- // @match *://*.google.co.za/*
- // @match *://*.google.co.zm/*
- // @match *://*.google.co.zw/*
- // @match *://*.google.cat/*
- // @grant none
- // @inject-into content
- // @run-at document-start
- // @noframes
- // ==/UserScript==
- // https://www.google.com/supported_domains
-
- (function () {
- "use strict";
-
- if (window.top !== window.self) return; // @noframes
- if (location.pathname == "/url") return;
- const plang = navigator.language; // Preferred language // 首选语言
- const slang = "en-US"; // Second language // 第二语言
- const is_zh = ["ZH", "ZH-CN"].includes(plang.toUpperCase());
- const o_url = new URL(location);
- let url;
- // captcha
- if (location.pathname.startsWith("/sorry/index")) {
- const _continue = o_url.searchParams.get("continue");
- if (!_continue) return;
- url = new URL(_continue);
- } else {
- url = new URL(location);
- }
- let pfull = plang;
- let region = "AUTO"; // Current Region // 当前区域
- if (plang.length == 5 && plang[2] == "-") {
- region = plang.slice(-2).toUpperCase();
- url.searchParams.set("gl", region);
- } else {
- pfull = plang + "-" + region;
- url.searchParams.delete("gl");
- }
- url.searchParams.set("hl", plang);
- url.searchParams.delete("client");
- const _index = url.hostname.indexOf("google.");
- if (_index < 0) return;
- const current_domian = url.hostname.slice(_index);
- const default_domain = "google.com";
- if (current_domian === default_domain) {
- if (location.pathname.startsWith("/sorry/index")) return; // captcha
- } else {
- if (navigator.cookieEnabled) {
- url.hostname = location.hostname.replace(current_domian, default_domain);
- url.href = "https://www.google.com/ncr#ncr:" + encodeURIComponent(url);
- window.stop();
- location.replace(url);
- return;
- } else {
- if (is_zh) {
- alert(
- "[ACT.谷歌.DM.NCR]:\nCookie 已禁用,NCR 功能将不会生效。请检查浏览器设置。",
- );
- } else {
- alert(
- "[ACT.Google.DM.NCR]:\nCookies disabled, the NCR feature will not be active. Please check the browser settings.",
- );
- }
- }
- }
- if (o_url.hash.slice(0, 5) == "#ncr:") {
- location.hash = "";
- window.stop();
- location.replace(decodeURIComponent(o_url.hash.slice(5)));
- return;
- }
-
- const r1 = region;
- const r2 = region == slang.toUpperCase().slice(-2) ? "AUTO" : slang.slice(-2);
- const l1 = plang;
- const l2 = plang.toUpperCase() == slang.toUpperCase() ? "AUTO" : slang;
- const langbar = document.createElement("div");
- const langbar_ = document.createElement("div");
- const langbar_r = document.createElement("div");
- const langbar_r_r1 = document.createElement("span");
- const langbar_r_r2 = document.createElement("span");
- const langbar_l = document.createElement("div");
- const langbar_l_l1 = document.createElement("span");
- const langbar_l_l2 = document.createElement("span");
- const langbar_s = document.createElement("div");
- const langbar_s_t = document.createElement("span");
- langbar.className = "act_langbar appbar mnr-c";
- langbar_.className = "card-section mnr-c";
- langbar_r.textContent = is_zh ? "区域:" : "REGION:";
- langbar_l.textContent = is_zh ? "语言:" : "LANGUAGE:";
- langbar_s.textContent = is_zh ? "区域&语言:" : "R&L:";
- langbar_r_r1.textContent = r1.toUpperCase();
- langbar_r_r2.textContent = r2.toUpperCase();
- langbar_l_l1.textContent = l1.toUpperCase();
- langbar_l_l2.textContent = l2.toUpperCase();
- langbar_r.append(langbar_r_r1, langbar_r_r2);
- langbar_l.append(langbar_l_l1, langbar_l_l2);
- langbar_s.append(langbar_s_t);
- langbar_.append(langbar_r, langbar_l, langbar_s);
- langbar.append(langbar_);
- let gl = r1,
- hl = plang,
- ss = 0;
- const ogl = o_url.searchParams.get("gl");
- const ohl = o_url.searchParams.get("hl");
- const safe_echo = (s) =>
- (s.match(/^[a-zA-Z]{2}(?:-[a-zA-Z]{2})?$/)?.[0] || "N/A").toUpperCase();
- switch (
- ogl?.toUpperCase() // Region
- ) {
- case r1.toUpperCase():
- langbar_r_r1.className = "act";
- gl = r2;
- break;
- case r2.toUpperCase():
- langbar_r_r2.className = "act";
- gl = r1;
- break;
- case undefined:
- r1 == "AUTO"
- ? ((langbar_r_r1.className = "act"), (gl = r2))
- : ((langbar_r_r2.className = "act"),
- (langbar_r_r2.textContent = "AUTO"),
- ss++);
- break;
- default:
- langbar_r_r2.className = "act";
- langbar_r_r2.textContent = safe_echo(ogl);
- ss++;
- }
- switch (
- ohl?.toUpperCase() // Language
- ) {
- case plang.toUpperCase():
- langbar_l_l1.className = "act";
- hl = l2;
- langbar_s_t.textContent = slang.toUpperCase();
- break;
- case slang.toUpperCase():
- langbar_l_l2.className = "act";
- hl = l1;
- langbar_s_t.textContent = pfull.toUpperCase();
- break;
- case undefined:
- langbar_l_l2.className = "act";
- langbar_l_l2.textContent = "AUTO";
- ss++;
- break;
- default:
- langbar_l_l2.className = "act";
- langbar_l_l2.textContent = safe_echo(ohl);
- ss++;
- }
- let sgl = gl,
- shl = hl;
- if ([r2, l2].includes("AUTO")) {
- ss > 1 &&
- ((sgl = r1), (shl = l1), (langbar_s_t.textContent = l1.toUpperCase()));
- ss < 2 && langbar_s.remove();
- } else {
- ss &&
- ((sgl = r2), (shl = l2), (langbar_s_t.textContent = l2.toUpperCase()));
- ss || hl.endsWith(gl) || langbar_s.remove();
- }
- url = new URL(location);
- langbar_r.addEventListener(
- "click",
- (event) => {
- gl == "AUTO"
- ? url.searchParams.delete("gl")
- : url.searchParams.set("gl", gl);
- location.replace(url);
- },
- true,
- );
- langbar_l.addEventListener(
- "click",
- (event) => {
- if (langbar_l_l2.textContent === "") return;
- hl == "AUTO"
- ? url.searchParams.delete("hl")
- : url.searchParams.set("hl", hl);
- location.replace(url);
- },
- true,
- );
- langbar_s.addEventListener(
- "click",
- (event) => {
- sgl == "AUTO"
- ? url.searchParams.delete("gl")
- : url.searchParams.set("gl", sgl);
- shl == "AUTO"
- ? url.searchParams.delete("hl")
- : url.searchParams.set("hl", shl);
- location.replace(url);
- },
- true,
- );
- const langbar_style = document.createElement("style");
- langbar_style.textContent = `
- .act_langbar {
- line-height: 2;
- margin-bottom: 6px;
- user-select: none;
- -webkit-user-select: none;
- }
- .act_langbar>div {
- white-space: nowrap;
- overflow-x: scroll !important;
- scrollbar-width: none;
- mask-image: linear-gradient(to left, transparent, red 25px);
- -webkit-mask-image: linear-gradient(to left, transparent, red 25px);
- }
- .act_langbar>div::-webkit-scrollbar { display: none; }
- .act_langbar>div>div {
- display: inline-block;
- padding: 0px 10px;
- margin-block: 3px;
- margin-inline: 0 15px;
- border: 1.5px solid;
- border-radius: 20px;
- cursor: pointer;
- opacity: 0.8;
- }
- .act_langbar>div>div:hover { opacity: 1; }
- .act_langbar span {
- margin-left: 10px;
- }
- .act_langbar span.act {
- padding: 1px 5px;
- border: 1px solid;
- border-radius: 20px;
- }
- `;
-
- if (document.head) {
- document.head.append(langbar_style);
- } else {
- new MutationObserver((mutationList, observer) => {
- document.head &&
- (observer.disconnect(), document.head.append(langbar_style));
- }).observe(document, { subtree: true, childList: true });
- }
-
- if (document.querySelector("#appbar")) {
- document.querySelector("#appbar")?.after(langbar);
- } else {
- new MutationObserver((mutationList, observer) => {
- if (document.querySelector("#appbar")) {
- observer.disconnect();
- document.querySelector("#appbar")?.after(langbar);
- }
- document.readyState == "complete" && observer.disconnect();
- }).observe(document, { subtree: true, childList: true });
- }
- })();