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. * @param {object} el 对象
  125. * @param {string} field 属性字段
  126. * @param {boolean} isAttr 是否是 attr 属性
  127. *
  128. * @returns {boolean}
  129. */
  130. function transElement(el, field, isAttr) {
  131. var transText = false; // 翻译后的文本
  132.  
  133. if (isAttr === undefined) { // 非属性翻译
  134. transText = translate(el[field], page);
  135. } else {
  136. transText = translate(el.getAttribute(field), page);
  137. }
  138.  
  139. if (transText === false) { // 无翻译则退出
  140. return false;
  141. }
  142.  
  143. // 替换翻译后的内容
  144. if (isAttr === undefined) {
  145. el[field] = transText;
  146. } else {
  147. el.setAttribute(field, transText);
  148. }
  149. }
  150.  
  151. /**
  152. * 翻译文本
  153. *
  154. * @param {string} text 待翻译字符串
  155. * @param {string} page 页面字段
  156. *
  157. * @returns {string|boolean}
  158. */
  159. function translate(text, page) { // 翻译
  160. var str;
  161. var _key = text.trim(); // 去除首尾空格的 key
  162. var _key_neat = _key
  163. .replace(/\xa0/g, ' ') // 替换 &nbsp; 空格导致的 bug
  164. .replace(/\s{2,}/g, ' '); // 去除多余换行空格等字符,(试验测试阶段,有问题再恢复)
  165.  
  166. if (_key_neat === '') {
  167. return false;
  168. } // 内容为空不翻译
  169.  
  170. str = transPage('pubilc', _key_neat); // 公共翻译
  171.  
  172. if (str !== false && str !== _key_neat) { // 公共翻译完成
  173. str = transPage('pubilc', str) || str; // 二次公共翻译(为了弥补正则部分翻译的情况)
  174. return text.replace(_key, str); // 替换原字符,保留空白部分
  175. }
  176.  
  177. if (page === false) {
  178. return false;
  179. } // 未知页面不翻译
  180.  
  181. str = transPage(page, _key_neat); // 翻译已知页面
  182. if (str === false || str === '') {
  183. return false;
  184. } // 未知内容不翻译
  185.  
  186. str = transPage('pubilc', str) || str; // 二次公共翻译(为了弥补正则部分翻译的情况)
  187. return text.replace(_key, str); // 替换原字符,保留空白部分
  188. }
  189.  
  190. /**
  191. * 翻译页面内容
  192. *
  193. * @param {string} page 页面
  194. * @param {string} key 待翻译内容
  195. *
  196. * @returns {string|boolean}
  197. */
  198. function transPage(page, key) {
  199. var str; // 翻译结果
  200. var res; // 正则数组
  201.  
  202. // 静态翻译
  203. str = I18N[lang][page]['static'][key];
  204. if (str) {
  205. return str;
  206. }
  207.  
  208. // 正则翻译
  209. res = I18N[lang][page].regexp;
  210. if (res) {
  211. for (var i = 0, len = res.length; i < len; i++) {
  212. str = key.replace(res[i][0], res[i][1]);
  213. if (str !== key) {
  214. return str;
  215. }
  216. }
  217. }
  218.  
  219. return false; // 没有翻译条目
  220. }
  221.  
  222. /**
  223. * 时间节点翻译
  224. */
  225. function timeElement() {
  226. if (!window.RelativeTimeElement) { // 防止报错
  227. return;
  228. }
  229.  
  230. var RelativeTimeElement$getFormattedDate = RelativeTimeElement.prototype.getFormattedDate;
  231. var TimeAgoElement$getFormattedDate = TimeAgoElement.prototype.getFormattedDate;
  232. // var LocalTimeElement$getFormattedDate = LocalTimeElement.prototype.getFormattedDate;
  233.  
  234. var RelativeTime = function (str, el) { // 相对时间解析
  235. if (/^on ([\w ]+)$/.test(str)) {
  236. return '于 ' + el.title.replace(/ .+$/, '');
  237. }
  238.  
  239. // 使用字典公共翻译的第二个正则翻译相对时间
  240. var time_ago = I18N[lang].pubilc.regexp[1];
  241. return str.replace(time_ago[0], time_ago[1]);
  242. };
  243.  
  244. RelativeTimeElement.prototype.getFormattedDate = function () {
  245. var str = RelativeTimeElement$getFormattedDate.call(this);
  246. return RelativeTime(str, this);
  247. };
  248.  
  249. TimeAgoElement.prototype.getFormattedDate = function () {
  250. var str = TimeAgoElement$getFormattedDate.call(this);
  251. return RelativeTime(str, this);
  252. };
  253.  
  254. LocalTimeElement.prototype.getFormattedDate = function () {
  255. return this.title.replace(/ .+$/, '');
  256. };
  257.  
  258. // 遍历 time 元素进行翻译
  259. // 2016-04-16 github 改版,不再用 time 标签了。
  260. var times = document.querySelectorAll('time, relative-time, time-ago, local-time');
  261. Array.prototype.forEach.call(times, function (el) {
  262. if (el.getFormattedDate) { // 跳过未注册的 time 元素
  263. el.textContent = el.getFormattedDate();
  264. }
  265. });
  266. }
  267.  
  268. /**
  269. * 贡献日历 基于事件翻译
  270. */
  271. function contributions() {
  272. var tip = document.getElementsByClassName('svg-tip-one-line');
  273.  
  274. // 等待 IncludeFragmentElement 元素加载完毕后绑定事件
  275. // var observe = require('github/observe').observe;
  276.  
  277. define('github/hans-contributions', ['./observe'], function (observe) {
  278. observe(".js-calendar-graph-svg", function () {
  279. setTimeout(function () { // 延时绑定 mouseover 事件,否则没法翻译
  280. var $calendar = $('.js-calendar-graph');
  281. walk($calendar[0]); // 翻译日历部分
  282.  
  283. $calendar.on('mouseover', '.day', function () {
  284. if (tip.length === 0) { // 没有 tip 元素时退出防止报错
  285. return true;
  286. }
  287.  
  288. var data = $(this).data(); // 获取节点上的 data
  289. var $tip = $(tip[0]);
  290.  
  291. $tip.html(data.count + ' 次贡献 ' + data.date);
  292.  
  293. var rect = this.getBoundingClientRect(); // 获取元素位置
  294. var left = rect.left + window.pageXOffset - tip[0].offsetWidth / 2 + 5.5;
  295.  
  296. $tip.css('left', left);
  297. });
  298. }, 999);
  299. });
  300. });
  301.  
  302. ghImport('github/hans-contributions')['catch'](function(e) {
  303. setTimeout(function() { throw e });
  304. });
  305. }
  306.  
  307. })(window, document);

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


【转】GitHub汉化脚本(谷歌浏览器)的更多相关文章

  1. ENGLISH抠脚童鞋的福利--GitHub汉化插件

    今天在某前端群看到一个插件,激动万分啊!我就把插件使用实现的步骤分享一下! 打开chrome浏览器输入地址:chrome://extensions/ : 跳转到其他页面,点击左上角--扩展程序: 将T ...

  2. 三步操作gitHub汉化插件安装--谷歌浏览器

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 一个好用基于chrome的插件,用来汉化gitHub,大致效果图如下: 步骤一: 首先下载谷歌 ...

  3. (汉化改进作品)BruteXSS:Xss漏洞扫描脚本

    今天给大家进行汉化改进的事一款脚本工具:BruteXSS,这款脚本能自动进行插入XSS,而且可以自定义攻击载荷. 该脚本也同时提供包含了一些绕过各种WAF(Web应用防护系统)的语句.   0×01简 ...

  4. EasyUI中控件汉化问题

    --BY ZYZ 我在使用EasyUI的过程中,遇到了控件无汉化的情况,如下图. 这么多洋文看着觉得挺烦的.时间居然是月日年格式的,这样可不行,得改. 重写控件代码?别,那能是我这种低级代码C-V客能 ...

  5. GitHub 网站汉化

    居然是一个中文Github网站!该不会是个假的吧? 2018-09-03 17:30 前几天分享了一篇文章——3个搜索技巧!在 GitHub上快速找到实用资源!眼尖心细的读者发现了文中的Github网 ...

  6. jmeter测试报告汉化及脚本编写

    在做接口自动化时,生成的测试报告页面是英文的,如现在我们优化成汉文.操作如下: 1,下载汉化包 下载路径:https://i.cnblogs.com/Files.aspx?order=1 2,解压汉化 ...

  7. InnoSetup汉化版打包工具下载-附带脚本模板

    InnoSetup汉化版打包工具下载地址: https://www.90pan.com/b1907264 脚本模板 ; 脚本用 Inno Setup 脚本向导 生成.; 查阅文档获取创建 INNO S ...

  8. 真正菜鸟用教程之WQSG Scrip Export WQSG (脚本导出导入工具,PSP、NDS汉化必备 )

    先扫盲WQSG是干什么用的 一些掌机类游戏汉化比方PSP NDS 汉化必备之物 它能够依据字典转换文本 假设你不知道这是啥玩意,快去充电染成茜色的坂道 文本提取(导出)方法 (下文称导出文章) 在导出 ...

  9. Github Atom汉化方式

    1.下载:Atom  https://atom.io/ 2.安装 3.菜单栏 -- Setting --- Install --- 搜索Chinese --安装汉化包 4.重启 生效.

随机推荐

  1. Spark源码分析 – Checkpoint

    CP的步骤 1. 首先如果RDD需要CP, 调用RDD.checkpoint()来mark 注释说了, 这个需要在Job被执行前被mark, 原因后面看, 并且最好选择persist这个RDD, 否则 ...

  2. 剑指Offer——构建乘积数组

    题目描述: 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]. ...

  3. 22.Atomicity and Transactions-官方文档摘录

    原子性和事务 1 在单个文档修改多个嵌入文档,写操作都在文档级别上都是原子的 2 在单个写操作修改多个文档时,每个文档的修改都具有原子性,但是,作为一个整体的操作,并不是原子的.其他操作可能有交互.使 ...

  4. Design Patterns Example Code (in C++)

    Overview Design patterns are ways to reuse design solutions that other software developers have crea ...

  5. 【我的Android进阶之旅】快速创建和根据不同的版本类型(Dev、Beta、Release)发布Android 开发库到Maven私服

    前言 由于项目越来越多,有很多公共的代码都可以抽取出一个开发库出来传到公司搭建好的Maven私服,以供大家使用. 之前搭建的Maven仓库只有Release和Snapshot两个仓库,最近由于开发库有 ...

  6. Linux(5)- MariaDB、mysql主从复制、初识redis

    一.MYSQL(mariadb) MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可. 开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL ...

  7. nodejs实战《一起学 Node.js》 使用 Express + MongoDB 搭建多人博客

    GitHub: https://github.com/nswbmw/N-blog N-blog 使用 Express + MongoDB 搭建多人博客 开发环境 Node.js: 6.9.1 Mong ...

  8. JavaWeb—Tomcat

    简介 Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台.安全域管理 ...

  9. 检查Linux服务器性能命令详解

    如果你的Linux服务器突然负载暴增,如何在最短时间内找出Linux性能问题所在? 通过执行以下命令,可以在1分钟内对系统资源使用情况有个大致的了解. uptime dmesg | tail vmst ...

  10. table添加横向滚动条

    <div style="width:1000px; height:200px; overflow:scroll;"> <table border=" r ...