Greasy Fork

简繁转换(中国大陆、台湾、香港、日本新字体)

调用 opencc-rust-wasm 转换中文

目前为 2022-08-17 提交的版本。查看 最新版本

// ==UserScript==
// @name	简繁转换(中国大陆、台湾、香港、日本新字体)
// @namespace	Forbidden Siren
// @version	  0.9.19
// @description 调用 opencc-rust-wasm 转换中文
// @include	*
// @grant	GM_getResourceText
// @grant	GM_getResourceURL
// @grant GM_addValueChangeListener
// @grant	GM_registerMenuCommand
// @grant	GM_unregisterMenuCommand
// @grant	GM_getValue
// @grant	GM_setValue
// @license MIT
// @run-at document-start
// @require https://greasyfork.org/scripts/448529-opencc-rust-lib/code/opencc-rust-lib.js?version=1074680
// @require https://greasyfork.org/scripts/448197-elementgetter/code/ElementGetter.js?version=1072378
// @resource opencc_wasm https://cdn.jsdelivr.net/gh/polyproline/opencc-wasm@main/opencc_gc.wasm
// @resource  HKVariants	https://cdn.jsdelivr.net/npm/opencc-data/data/HKVariants.txt
// @resource  HKVariantsRev	https://cdn.jsdelivr.net/npm/opencc-data/data/HKVariantsRev.txt
// @resource  HKVariantsRevPhrases	https://cdn.jsdelivr.net/npm/opencc-data/data/HKVariantsRevPhrases.txt
// @resource  JPShinjitaiCharacters	https://cdn.jsdelivr.net/npm/opencc-data/data/JPShinjitaiCharacters.txt
// @resource  JPShinjitaiPhrases	https://cdn.jsdelivr.net/npm/opencc-data/data/JPShinjitaiPhrases.txt
// @resource  JPVariants	https://cdn.jsdelivr.net/npm/opencc-data/data/JPVariants.txt
// @resource  JPVariantsRev	https://cdn.jsdelivr.net/npm/opencc-data/data/JPVariantsRev.txt
// @resource  STCharacters	https://cdn.jsdelivr.net/npm/opencc-data/data/STCharacters.txt
// @resource  STPhrases	https://cdn.jsdelivr.net/npm/opencc-data/data/STPhrases.txt
// @resource  TSCharacters	https://cdn.jsdelivr.net/npm/opencc-data/data/TSCharacters.txt
// @resource  TSPhrases	https://cdn.jsdelivr.net/npm/opencc-data/data/TSPhrases.txt
// @resource  TWPhrasesIT	https://cdn.jsdelivr.net/npm/opencc-data/data/TWPhrasesIT.txt
// @resource  TWPhrasesName	https://cdn.jsdelivr.net/npm/opencc-data/data/TWPhrasesName.txt
// @resource  TWPhrasesOther	https://cdn.jsdelivr.net/npm/opencc-data/data/TWPhrasesOther.txt
// @resource  TWPhrasesRev	https://cdn.jsdelivr.net/npm/opencc-data/data/TWPhrasesRev.txt
// @resource  TWVariants	https://cdn.jsdelivr.net/npm/opencc-data/data/TWVariants.txt
// @resource  TWVariantsRev	https://cdn.jsdelivr.net/npm/opencc-data/data/TWVariantsRev.txt
// @resource  TWVariantsRevPhrases	https://cdn.jsdelivr.net/npm/opencc-data/data/TWVariantsRevPhrases.txt
// ==/UserScript==

"use strict";

const ToSimple = [["HKVariantsRevPhrases", "HKVariantsRev"], ["TWPhrasesRev", "TWVariantsRevPhrases", "TWVariantsRev"], ["TSPhrases", "TSCharacters"]];// to Simple Chinese
const ToTraditional = [["TWVariantsRevPhrases", "TWVariantsRev"], ["HKVariantsRevPhrases", "HKVariantsRev"], ["JPShinjitaiPhrases", "JPShinjitaiCharacters", "JPVariantsRev"], ["STPhrases", "STCharacters"]];
const ToTaiwan = [["STPhrases", "STCharacters"], "TWVariants", "TWPhrases"];
const ToHongKong = [["STPhrases", "STCharacters"], "HKVariants"];
const ExcludeTag = new RegExp("SCRIPT|TEXTAREA|META|BASE|NOSCRIPT|OBJECT");
const ExcludeType = new RegExp("text|search|hidden");
const Base64 = new RegExp("(?<=base64,).*");
const NODE_DICT = ToSimple;

let AutoTranslate = GM_getValue("AutoTranslate", false);
let ListenEvent = GM_getValue("ListenEvent", false);
let auto_translate = GM_registerMenuCommand((AutoTranslate ? "Disable" : "Enable") + " Auto Translate", set_auto_translate);

if (AutoTranslate) {
	load_func();
} else {
	let loadid = GM_registerMenuCommand("Start translate", () => {
		GM_unregisterMenuCommand(loadid);
		load_func();
	});
}
function set_auto_translate() {
	GM_unregisterMenuCommand(auto_translate);
	AutoTranslate = !AutoTranslate;
	GM_setValue("AutoTranslate", AutoTranslate);
	auto_translate = GM_registerMenuCommand((AutoTranslate ? "Disable" : "Enable") + " Auto Translate", set_auto_translate);
}

function load_func() {
	const elmGetter = new ElementGetter();
	const wasm = (async () => {
		const url = GM_getResourceURL("opencc_wasm", false);
		let arr;
		if (url.startsWith('data:')) {
			const base64String = Base64.exec(url)[0];
			const rawData = window.atob(base64String);
			arr = new Uint8Array(rawData);
		} else {
			const req = await fetch(url);
			const buf = await req.arrayBuffer();
			arr = new Uint8Array(buf);
		}
		return arr;
	})();
	init(wasm).then(() => {
		let build = ConverterBuild.new();
		NODE_DICT.forEach(item => {
			if (Array.isArray(item)) {
				item.forEach(function (item) {
					console.assert(typeof item == "string");
					build.adddict(GM_getResourceText(item));
				});
			} else {
				console.assert(typeof item == "string");
				build.adddict(GM_getResourceText(item));
			}
			build.group();
		});
		const converter = build.build();
		const translate_body = () => { elmGetter.get("body").then(item => translate(item)); };
		const translate_head = () => { elmGetter.get("head").then(item => translate(item)); };
		const translate_all = () => { translate_head(); translate_body(); };
		translate_all();
		GM_registerMenuCommand("Translate", translate_all);
		//setTimeout(translate,5*1000);
		{
			const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
			let observer = new MutationObserver(records =>{
				records.forEach(record => {
					switch (record.type) {
						case 'childList':
							record.addedNodes.forEach(translate)
							break;
						case 'characterData':
							if (record.target.data) {
								converter.convert(record.target.data).then(text => {
									if (text != record.target.data) {
										record.target.data = text;
									}
								});
							}
							break;
					}
				})
			});
			const option = {
				"childList": true,
				"subtree": true,
				"characterData": true
			};
			let id = GM_registerMenuCommand("Listen event", listen_event);
			function listen_event() {
				GM_unregisterMenuCommand(id);
				translate_body();
				elmGetter.get("body").then(body => {
					observer.observe(document.body, option);
					id = GM_registerMenuCommand("Unlisten event", unlisten_event);
				});
			}
			function unlisten_event() {
				GM_unregisterMenuCommand(id);
				observer.disconnect();
				id = GM_registerMenuCommand("Listen event", listen_event);
			}
		}

		function translate(pNode) {
			let stack = [];
			do {
				pNode.childNodes.forEach(child => {
					if (child.tagName && ExcludeTag.test(child.tagName))
						return;
					if (child.title) {
						converter.convert(child.title).then(text => {
							if (child.title != text) {
								child.title = text;
							}
						});
					}
					if (child.alt) {
						converter.convert(child.alt).then(text => {
							if (child.alt != text) {
								child.alt = text;
							}
						});
					}
					if (child.tagName == "INPUT" && !ExcludeType.test(child.type)) {
						if (child.value) {
							converter.convert(child.value).then(text => {
								if (child.value != text) {
									child.value = text;
								}
							});
						}
						if (child.placeholder) {
							converter.convert(child.placeholder).then(text => {
								if (child.placeholder != text) {
									child.placeholder = text;
								}
							});
						}
					} else if (child.nodeType == 3) {
						if (child.data) {
							converter.convert(child.data).then(text => {
								if (child.data != text) {
									child.data = text;
								}
							});
						}
					}
					if (child.nodeType == 1) {
						stack.push(child);
					}
				});
			} while (pNode = stack.pop());
		}
	});
}