zoukankan      html  css  js  c++  java
  • 【转】GitHub汉化脚本(谷歌浏览器)

      1 // ==UserScript==
      2 // @name         GitHub 汉化插件
      3 // @description  汉化 GitHub 界面的部分菜单及内容。
      4 // @copyright    2016, 楼教主 (http://www.52cik.com/)
      5 // @icon         https://assets-cdn.github.com/pinned-octocat.svg
      6 // @version      1.6.4
      7 // @author       楼教主
      8 // @license      MIT
      9 // @homepageURL  https://github.com/52cik/github-hans
     10 // @match        http://*.github.com/*
     11 // @match        https://*.github.com/*
     12 // @require      https://52cik.github.io/github-hans/locals.js?v1.6.4
     13 // @run-at       document-end
     14 // @grant        none
     15 // ==/UserScript==
     16 
     17 (function (window, document, undefined) {
     18     'use strict';
     19 
     20     var lang = 'zh'; // 中文
     21 
     22     // 2016-04-18 github 将 jquery 以 amd 加载,不暴露到全局了。
     23     // var $ = require('github/jquery')['default'];
     24 
     25     // 要翻译的页面
     26     var page = getPage();
     27 
     28     transTitle(); // 页面标题翻译
     29     timeElement(); // 时间节点翻译
     30     // setTimeout(contributions, 100); // 贡献日历翻译 (日历是内嵌或ajax的, 所以基于回调事件处理)
     31     walk(document.body); // 立即翻译页面
     32 
     33     // 2017-03-19 github 屏蔽 require 改为 Promise 形式的 ghImport
     34     define('github-hans-ajax', ['./jquery'], function($) {
     35         $(document).ajaxComplete(function () {
     36             transTitle();
     37             walk(document.body); // ajax 请求后再次翻译页面
     38         });
     39     });
     40     ghImport('github-hans-ajax')['catch'](function(e) {
     41         setTimeout(function() { throw e });
     42     });
     43 
     44     /**
     45      * 遍历节点
     46      *
     47      * @param {Element} node 节点
     48      */
     49     function walk(node) {
     50         var nodes = node.childNodes;
     51 
     52         for (var i = 0, len = nodes.length; i < len; i++) {
     53             var el = nodes[i];
     54             // todo 1. 修复多属性翻译问题; 2. 添加事件翻译, 如论预览信息;
     55 
     56             if (el.nodeType === Node.ELEMENT_NODE) { // 元素节点处理
     57 
     58                 // 元素节点属性翻译
     59                 if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') { // 输入框 按钮 文本域
     60                     if (el.type === 'button' || el.type === 'submit') {
     61                         transElement(el, 'value');
     62                     } else {
     63                         transElement(el, 'placeholder');
     64                     }
     65                 } else if (el.hasAttribute('aria-label')) { // 带提示的元素,类似 tooltip 效果的
     66                     transElement(el, 'aria-label', true);
     67 
     68                     if (el.hasAttribute('data-copied-hint')) { // 复制成功提示
     69                         transElement(el.dataset, 'copiedHint');
     70                     }
     71                 } else if (el.tagName === 'OPTGROUP') { // 翻译 <optgroup> 的 label 属性
     72                     transElement(el, 'label');
     73                 }
     74 
     75                 if (el.hasAttribute('data-disable-with')) { // 按钮等待提示
     76                     transElement(el.dataset, 'disableWith');
     77                 }
     78 
     79                 // 跳过 readme, 文件列表, 代码显示
     80                 if (el.id !== 'readme' && !I18N.conf.reIgnore.test(el.className)) {
     81                     walk(el); // 遍历子节点
     82                 }
     83             } else if (el.nodeType === Node.TEXT_NODE) { // 文本节点翻译
     84                 transElement(el, 'data');
     85             }
     86 
     87         }
     88     }
     89 
     90     /**
     91      * 获取翻译页面
     92      */
     93     function getPage() {
     94         // 先匹配 body 的 class
     95         var page = document.body.className.match(I18N.conf.rePageClass);
     96 
     97         if (!page) { // 扩展 url 匹配
     98             page = location.href.match(I18N.conf.rePageUrl);
     99         }
    100 
    101         if (!page) { // 扩展 pathname 匹配
    102             page = location.pathname.match(I18N.conf.rePagePath);
    103         }
    104 
    105         return page ? page[1] || 'homepage' : false; // 取页面 key
    106     }
    107 
    108     /**
    109      * 翻译页面标题
    110      */
    111     function transTitle() {
    112         var title = translate(document.title, 'title');
    113 
    114         if (title === false) { // 无翻译则退出
    115             return false;
    116         }
    117 
    118         document.title = title;
    119     }
    120 
    121 
    122     /**
    123      * 翻译节点对应属性内容
    124      *
    125      * @param {object} el 对象
    126      * @param {string} field 属性字段
    127      * @param {boolean} isAttr 是否是 attr 属性
    128      *
    129      * @returns {boolean}
    130      */
    131     function transElement(el, field, isAttr) {
    132         var transText = false; // 翻译后的文本
    133 
    134         if (isAttr === undefined) { // 非属性翻译
    135             transText = translate(el[field], page);
    136         } else {
    137             transText = translate(el.getAttribute(field), page);
    138         }
    139 
    140         if (transText === false) { // 无翻译则退出
    141             return false;
    142         }
    143 
    144         // 替换翻译后的内容
    145         if (isAttr === undefined) {
    146             el[field] = transText;
    147         } else {
    148             el.setAttribute(field, transText);
    149         }
    150     }
    151 
    152 
    153     /**
    154      * 翻译文本
    155      *
    156      * @param {string} text 待翻译字符串
    157      * @param {string} page 页面字段
    158      *
    159      * @returns {string|boolean}
    160      */
    161     function translate(text, page) { // 翻译
    162         var str;
    163         var _key = text.trim(); // 去除首尾空格的 key
    164         var _key_neat = _key
    165             .replace(/xa0/g, ' ') // 替换 &nbsp; 空格导致的 bug
    166             .replace(/s{2,}/g, ' '); // 去除多余换行空格等字符,(试验测试阶段,有问题再恢复)
    167 
    168         if (_key_neat === '') {
    169             return false;
    170         } // 内容为空不翻译
    171 
    172         str = transPage('pubilc', _key_neat); // 公共翻译
    173 
    174         if (str !== false && str !== _key_neat) { // 公共翻译完成
    175             str = transPage('pubilc', str) || str;  // 二次公共翻译(为了弥补正则部分翻译的情况)
    176             return text.replace(_key, str);  // 替换原字符,保留空白部分
    177         }
    178 
    179         if (page === false) {
    180             return false;
    181         } // 未知页面不翻译
    182 
    183         str = transPage(page, _key_neat); // 翻译已知页面
    184         if (str === false || str === '') {
    185             return false;
    186         } // 未知内容不翻译
    187 
    188         str = transPage('pubilc', str) || str; // 二次公共翻译(为了弥补正则部分翻译的情况)
    189         return text.replace(_key, str); // 替换原字符,保留空白部分
    190     }
    191 
    192 
    193     /**
    194      * 翻译页面内容
    195      *
    196      * @param {string} page 页面
    197      * @param {string} key 待翻译内容
    198      *
    199      * @returns {string|boolean}
    200      */
    201     function transPage(page, key) {
    202         var str; // 翻译结果
    203         var res; // 正则数组
    204 
    205         // 静态翻译
    206         str = I18N[lang][page]['static'][key];
    207         if (str) {
    208             return str;
    209         }
    210 
    211         // 正则翻译
    212         res = I18N[lang][page].regexp;
    213         if (res) {
    214             for (var i = 0, len = res.length; i < len; i++) {
    215                 str = key.replace(res[i][0], res[i][1]);
    216                 if (str !== key) {
    217                     return str;
    218                 }
    219             }
    220         }
    221 
    222         return false; // 没有翻译条目
    223     }
    224 
    225 
    226     /**
    227      * 时间节点翻译
    228      */
    229     function timeElement() {
    230         if (!window.RelativeTimeElement) { // 防止报错
    231             return;
    232         }
    233 
    234         var RelativeTimeElement$getFormattedDate = RelativeTimeElement.prototype.getFormattedDate;
    235         var TimeAgoElement$getFormattedDate = TimeAgoElement.prototype.getFormattedDate;
    236         // var LocalTimeElement$getFormattedDate = LocalTimeElement.prototype.getFormattedDate;
    237 
    238         var RelativeTime = function (str, el) { // 相对时间解析
    239             if (/^on ([w ]+)$/.test(str)) {
    240                 return '于 ' + el.title.replace(/ .+$/, '');
    241             }
    242 
    243             // 使用字典公共翻译的第二个正则翻译相对时间
    244             var time_ago = I18N[lang].pubilc.regexp[1];
    245             return str.replace(time_ago[0], time_ago[1]);
    246         };
    247 
    248         RelativeTimeElement.prototype.getFormattedDate = function () {
    249             var str = RelativeTimeElement$getFormattedDate.call(this);
    250             return RelativeTime(str, this);
    251         };
    252 
    253         TimeAgoElement.prototype.getFormattedDate = function () {
    254             var str = TimeAgoElement$getFormattedDate.call(this);
    255             return RelativeTime(str, this);
    256         };
    257 
    258         LocalTimeElement.prototype.getFormattedDate = function () {
    259             return this.title.replace(/ .+$/, '');
    260         };
    261 
    262         // 遍历 time 元素进行翻译
    263         // 2016-04-16 github 改版,不再用 time 标签了。
    264         var times = document.querySelectorAll('time, relative-time, time-ago, local-time');
    265         Array.prototype.forEach.call(times, function (el) {
    266             if (el.getFormattedDate) { // 跳过未注册的 time 元素
    267                 el.textContent = el.getFormattedDate();
    268             }
    269         });
    270     }
    271 
    272 
    273     /**
    274      * 贡献日历 基于事件翻译
    275      */
    276     function contributions() {
    277         var tip = document.getElementsByClassName('svg-tip-one-line');
    278 
    279         // 等待 IncludeFragmentElement 元素加载完毕后绑定事件
    280         // var observe = require('github/observe').observe;
    281 
    282         define('github/hans-contributions', ['./observe'], function (observe) {
    283             observe(".js-calendar-graph-svg", function () {
    284                 setTimeout(function () { // 延时绑定 mouseover 事件,否则没法翻译
    285                     var $calendar = $('.js-calendar-graph');
    286                     walk($calendar[0]); // 翻译日历部分
    287 
    288                     $calendar.on('mouseover', '.day', function () {
    289                         if (tip.length === 0) { // 没有 tip 元素时退出防止报错
    290                             return true;
    291                         }
    292 
    293                         var data = $(this).data(); // 获取节点上的 data
    294                         var $tip = $(tip[0]);
    295 
    296                         $tip.html(data.count + ' 次贡献 ' + data.date);
    297 
    298                         var rect = this.getBoundingClientRect(); // 获取元素位置
    299                         var left = rect.left + window.pageXOffset - tip[0].offsetWidth / 2 + 5.5;
    300 
    301                         $tip.css('left', left);
    302                     });
    303                 }, 999);
    304             });
    305         });
    306 
    307         ghImport('github/hans-contributions')['catch'](function(e) {
    308             setTimeout(function() { throw e });
    309         });
    310     }
    311 
    312 })(window, document);

    转载于楼教主GitHub:https://github.com/52cik/github-hans/blob/gh-pages/main.js


  • 相关阅读:
    css引入方式
    HTML标签
    动态导入模块impoerlib
    pymysql连接数据库
    创建数据库表之引擎
    IO多路复用互动聊天,select函数监听
    欧拉筛法求素数个数
    与三角形相关的问题 WITH 有向面积
    时间复杂度的计算
    折半查找
  • 原文地址:https://www.cnblogs.com/xiaostudy/p/9622262.html
Copyright © 2011-2022 走看看