您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
将页面上的汉字转换为简体字,需要手动添加包含的网站以启用
当前为
- // ==UserScript==
- // @name Han Simplify
- // @name:zh 汉字转换为简体字
- // @description 将页面上的汉字转换为简体字,需要手动添加包含的网站以启用
- // @namespace https://github.com/tiansh
- // @version 1.0
- // @resource t2s https://tiansh.github.io/reader/data/han/t2s.json
- // @include *
- // @exclude *
- // @grant GM_getResourceURL
- // @grant GM.getResourceUrl
- // @run-at document-start
- // @license MIT
- // @supportURL https://github.com/tiansh/us-han-simplify/issues
- // ==/UserScript==
- /* eslint-env browser, greasemonkey */
- ; (async function () {
- /** @type {'t2s'|'s2t'} */
- const RULE = 't2s';
- const fetchTable = async function (url) {
- return (await fetch(url)).json();
- };
- const loadTable = async function () {
- try {
- return fetchTable(GM_getResourceURL(RULE));
- } catch {
- return fetchTable(await GM.getResourceUrl(RULE));
- }
- };
- /** @type {{ [ch: string]: [string, number] }[]} */
- const table = await loadTable();
- /** @param {string} text */
- const translate = function (text) {
- let output = '';
- let state = 0;
- const hasOwnProperty = Object.prototype.hasOwnProperty;
- for (let char of text) {
- while (true) {
- const current = table[state];
- const hasMatch = hasOwnProperty.call(current, char);
- if (!hasMatch && state === 0) {
- output += char;
- break;
- }
- if (hasMatch) {
- const [adding, next] = current[char];
- if (adding) output += adding;
- state = next;
- break;
- }
- const [adding, next] = current[''];
- if (adding) output += adding;
- state = next;
- }
- }
- while (state !== 0) {
- const current = table[state];
- const [adding, next] = current[''];
- if (adding) output += adding;
- state = next;
- }
- return output;
- };
- const correctLangTags = function () {
- [...document.querySelectorAll('[lang]:not([hanconv-lang])')].forEach(element => {
- const lang = element.getAttribute('lang');
- element.setAttribute('hanconv-lang', lang);
- if (RULE === 't2s' && /^zh\b(?:(?!.*-Hans)-(?:TW|HK|MO)|.*-Hant|$)/i.test(lang)) {
- element.setAttribute('lang', 'zh-Hans');
- }
- if (RULE === 's2t' && /^zh\b(?:(?!.*-Hant)-(?:CN|SG|MY)|.*-Hans|$)/i.test(lang)) {
- element.setAttribute('lang', 'zh-Hant');
- }
- if (!/^(?:ja|ko|vi)\b/i.test(lang)) {
- element.setAttribute('hanconv-apply', 'apply');
- }
- });
- };
- /** @type {WeakMap<Text|Attr, string>} */
- const translated = new WeakMap();
- /** @param {Element} element */
- const needTranslateElement = function (element) {
- if (element.matches('script, style')) return false;
- if (element.closest('svg, math, .notranslate, [translate="no"], code:not([translate="yes"]), var:not([translate="yes"])')) return false;
- const lang = element.closest('[lang]');
- return lang == null || lang.hasAttribute('hanconv-apply');
- };
- /** @param {Text|Attr} node */
- const needTranslate = function (node) {
- if (translated.has(node) && translated.get(node) === node.nodeValue) return false;
- if (/^\s*$/.test(node.nodeValue)) return false;
- const element = node instanceof Text ? node.parentElement : node.ownerElement;
- if (!element) return true;
- return needTranslateElement(element);
- };
- /** @param {Text|Attr} node */
- const translateNode = function (node) {
- if (!needTranslate(node)) return;
- const result = translate(node.nodeValue);
- translated.set(node, result);
- node.nodeValue = result;
- };
- const translateContainer = function (container) {
- if (container instanceof Text || container instanceof Attr) {
- translateNode(container);
- } else if (container instanceof Element) {
- const nodes = document.evaluate([
- // Translate text
- '//text()',
- // Translate attributes
- '(//applet|//area|//img|//input)/@alt',
- '(//a|//area)/@download',
- '//@title',
- '//@aria-label', '//@aria-description',
- ].join('|'), container, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- for (let index = 0; index < nodes.snapshotLength; index++) {
- translateNode(nodes.snapshotItem(index));
- }
- }
- };
- let timeout = null;
- const updateInterval = 200;
- const translateTargets = new Set();
- const observer = new MutationObserver(function onMutate(records) {
- correctLangTags();
- records.forEach(record => {
- if (record.type === 'childList') {
- [...record.addedNodes].forEach(node => translateTargets.add(node));
- } else {
- translateTargets.add(record.target);
- }
- });
- if (!timeout) {
- const targets = [...translateTargets].filter((node, _, arr) => !arr.some(other => other !== node && other.contains(node)));
- translateTargets.clear();
- targets.forEach(translateContainer);
- timeout = setTimeout(() => { timeout = null; onMutate([]); }, updateInterval);
- }
- });
- observer.observe(document, { subtree: true, childList: true, characterData: true, attributes: true });
- }());