Greasy Fork is available in English.
Translate strings by given translations
Dette script bør ikke installeres direkte. Det er et bibliotek, som andre scripts kan inkludere med metadirektivet // @require https://update.greasyfork.org/scripts/7081/28938/UserScript%20Translation%20Engine.js
// ==UserScript== // @name UserScript Translation Engine // @namespace org.jixun.us.translation // @description Translate strings by given translations // @version 1.0 // @run-at document-start // @grant none // ==/UserScript== var Translation = (function () { var _each = function (arr, eachCb, defValue) { if (!arr || !arr.length) return ; for (var i = arr.length, ret; i-- ; ) // If there's something to return, then return it. if (ret = eachCb (arr[i], i)) return ret; return defValue ; }; var _filterPop = function (arr, fn) { if (arr && arr.length) for (var i = arr.length; i--; ) if (fn(arr[i])) return arr[i]; }; var extend = function (src) { var args = arguments, argl = args.length; for (var i = 1; i < argl; i++) { for (var x in args[i]) { if (args[i].hasOwnProperty(x)) { if (src[x] instanceof Object) { extend (src[x], args[i][x]); } else { src[x] = args[i][x]; } } } } return src; }; var Translation = function (lang) { this.resetLang (); this.setLang (lang); }; // 获取浏览器预设语言 Translation.getLang = function (lang) { var x = _filterPop(navigator.languages.slice().reverse(), function (x) { return lang[x] }); return lang[x] || {}; }; Translation.prototype = { run: function (node) { var self = this; node = node || document.body || document; this.mo = new MutationObserver (function (m) { _each (m, function (q) { _each (q.addedNodes, function (e) { // Firebug keep injects their stuff, ignore if (e.className && e.className.indexOf ('firebug') != -1) return ; self.translateNode (e); }); if (q.type == 'attributes') { var x = self.findAttrTranslation (q.target, q.attributeName, q.target.getAttribute(q.attributeName)); if (x) { q.target.setAttribute (q.attributeName, x); } } }); }); this.mo.observe (node, { childList: true, subtree: true, characterData: true, attributes: true }); this.translateNode (node); }, excludeTags: ['code', 'pre', 'script', 'style', 'link', 'meta'], excludeFromTag: function (node, tagName) { var n = node; while (n = n.parentNode) if (-1 != this.excludeTags.indexOf(n)) return true; return false; }, translateNode: function (node) { _each(node.getElementsByTagName('*'), this.applyAttr.bind(this)); var self = this; var walker = document.createTreeWalker (node, 4 /* NodeFilter.SHOW_TEXT */, function (textNode) { return ( self.excludeFromTag(textNode.parentNode) || textNode.nodeValue.trim() === '' ? 2 /* NodeFilter.FILTER_REJECT */ : 1 /* NodeFilter.FILTER_ACCEPT */ ); }, false); // Loop through text nodes. while (node = walker.nextNode()) this.applyNode (node); }, applyNode: function (node) { this.applyText (node); this.applyAttr (node.parentNode); }, findTranslation: function (lang, str) { var args = arguments; var stack = [ lang ]; var r = lang; for (var i = 2; i < args.length; i++) { r = r[args[i]]; if (!r) break; stack.push (r); } if (stack.length) { for (i = stack.length; i--; ) { if (stack[i][str] && 'string' == typeof stack[i][str]) { return stack[i][str]; } if (stack[i].regex) { r = _filterPop(stack[i].regex, function (re) { return re[0].test( str ); }); if (r) return str.replace(r[0], r[1]); } } } }, applyText: function (node) { var self = this; var v = node.nodeValue.trim(); if (!v) return ; var l = (this.findTranslation (this.lang.node, v, 'tag', node.parentNode.tagName) || this.findTranslation (this.lang.node, v, 'str')); if (l) node.nodeValue = l; }, findAttrTranslation: function (node, attrName, attrVal) { return (this.findTranslation (this.lang.attr, attrVal, 'tag', node.tagName, attrName) || this.findTranslation (this.lang.attr, attrVal, 'str', attrName)) }, applyAttr: function (node) { var self = this; var tag = node.tagName; var l; _each(node.attributes, function (attr) { l = self.findAttrTranslation (node, attr.name, attr.value); if (l) attr.value = l; }); }, /** * Set translation profile * @param {Object} lang Language translation hashmap. */ setLang: function (lang) { if (lang instanceof Object) extend (this.lang, lang); }, /** * Get translation * @return {Object} Language Translation hashmap */ getLang: function () { return extend({}, this.lang); }, resetLang: function () { this.lang = {node: {tag: {}, str: {}}, attr: {tag: {}, str: {}}}; } }; return Translation; })();