今天在某前端羣看到一個插件,激動萬分啊!我就把插件使用實現的步驟分享一下!css
在插件佈置完成後,不免有點小激動!我將chrome插件Tampermonkey_v4.0.25.crx移除後,直接將main.js添加新腳本,也漢化了,感受沒什麼差別!html
嫌github下載做者的該插件速度慢的童鞋直接將main.js代碼按上面的步驟直接添加到新腳本試試吧!前端
附上main.js:node
// ==UserScript== // @name GitHub 漢化插件 // @description 漢化 GitHub 界面的部分菜單及內容。 // @copyright 2016, 樓教主 (http://www.52cik.com/) // @icon https://assets-cdn.github.com/pinned-octocat.svg // @version 1.6.3 // @author 樓教主 // @license MIT // @homepageURL https://github.com/52cik/github-hans // @match http://*.github.com/* // @match https://*.github.com/* // @require https://52cik.github.io/github-hans/locals.js?v1.6.3 // @run-at document-end // @grant none // ==/UserScript== (function (window, document, undefined) { 'use strict'; var lang = 'zh'; // 中文 // 2016-04-18 github 將 jquery 以 amd 加載,不暴露到全局了。 var $ = require('github/jquery')['default']; // 要翻譯的頁面 var page = getPage(); transTitle(); // 頁面標題翻譯 timeElement(); // 時間節點翻譯 contributions(); // 貢獻日曆翻譯 (日曆是內嵌或ajax的, 因此基於回調事件處理) walk(document.body); // 當即翻譯頁面 $(document).ajaxComplete(function () { transTitle(); walk(document.body); // ajax 請求後再次翻譯頁面 }); /** * 遍歷節點 * * @param {Element} node 節點 */ function walk(node) { var nodes = node.childNodes; for (var i = 0, len = nodes.length; i < len; i++) { var el = nodes[i]; // todo 1. 修復多屬性翻譯問題; 2. 添加事件翻譯, 如論預覽信息; if (el.nodeType === Node.ELEMENT_NODE) { // 元素節點處理 // 元素節點屬性翻譯 if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') { // 輸入框 按鈕 文本域 if (el.type === 'button' || el.type === 'submit') { transElement(el, 'value'); } else { transElement(el, 'placeholder'); } } else if (el.hasAttribute('aria-label')) { // 帶提示的元素,相似 tooltip 效果的 transElement(el, 'aria-label', true); if (el.hasAttribute('data-copied-hint')) { // 複製成功提示 transElement(el.dataset, 'copiedHint'); } } else if (el.tagName === 'OPTGROUP') { // 翻譯 <optgroup> 的 label 屬性 transElement(el, 'label'); } if (el.hasAttribute('data-disable-with')) { // 按鈕等待提示 transElement(el.dataset, 'disableWith'); } // 跳過 readme, 文件列表, 代碼顯示 if (el.id !== 'readme' && !I18N.conf.reIgnore.test(el.className)) { walk(el); // 遍歷子節點 } } else if (el.nodeType === Node.TEXT_NODE) { // 文本節點翻譯 transElement(el, 'data'); } } } /** * 獲取翻譯頁面 */ function getPage() { // 先匹配 body 的 class var page = document.body.className.match(I18N.conf.rePageClass); if (!page) { // 擴展 url 匹配 page = location.href.match(I18N.conf.rePageUrl); } if (!page) { // 擴展 pathname 匹配 page = location.pathname.match(I18N.conf.rePagePath); } return page ? page[1] || 'homepage' : false; // 取頁面 key } /** * 翻譯頁面標題 */ function transTitle() { var title = translate(document.title, 'title'); if (title === false) { // 無翻譯則退出 return false; } document.title = title; } /** * 翻譯節點對應屬性內容 * * @param {object} el 對象 * @param {string} field 屬性字段 * @param {boolean} isAttr 是不是 attr 屬性 * * @returns {boolean} */ function transElement(el, field, isAttr) { var transText = false; // 翻譯後的文本 if (isAttr === undefined) { // 非屬性翻譯 transText = translate(el[field], page); } else { transText = translate(el.getAttribute(field), page); } if (transText === false) { // 無翻譯則退出 return false; } // 替換翻譯後的內容 if (isAttr === undefined) { el[field] = transText; } else { el.setAttribute(field, transText); } } /** * 翻譯文本 * * @param {string} text 待翻譯字符串 * @param {string} page 頁面字段 * * @returns {string|boolean} */ function translate(text, page) { // 翻譯 var str; var _key = text.trim(); // 去除首尾空格的 key var _key_neat = _key .replace(/\xa0/g, ' ') // 替換 空格致使的 bug .replace(/\s{2,}/g, ' '); // 去除多餘換行空格等字符,(試驗測試階段,有問題再恢復) if (_key_neat === '') { return false; } // 內容爲空不翻譯 str = transPage('pubilc', _key_neat); // 公共翻譯 if (str !== false && str !== _key_neat) { // 公共翻譯完成 str = transPage('pubilc', str) || str; // 二次公共翻譯(爲了彌補正則部分翻譯的狀況) return text.replace(_key, str); // 替換原字符,保留空白部分 } if (page === false) { return false; } // 未知頁面不翻譯 str = transPage(page, _key_neat); // 翻譯已知頁面 if (str === false || str === '') { return false; } // 未知內容不翻譯 str = transPage('pubilc', str) || str; // 二次公共翻譯(爲了彌補正則部分翻譯的狀況) return text.replace(_key, str); // 替換原字符,保留空白部分 } /** * 翻譯頁面內容 * * @param {string} page 頁面 * @param {string} key 待翻譯內容 * * @returns {string|boolean} */ function transPage(page, key) { var str; // 翻譯結果 var res; // 正則數組 // 靜態翻譯 str = I18N[lang][page]['static'][key]; if (str) { return str; } // 正則翻譯 res = I18N[lang][page].regexp; if (res) { for (var i = 0, len = res.length; i < len; i++) { str = key.replace(res[i][0], res[i][1]); if (str !== key) { return str; } } } return false; // 沒有翻譯條目 } /** * 時間節點翻譯 */ function timeElement() { if (!window.RelativeTimeElement) { // 防止報錯 return; } var RelativeTimeElement$getFormattedDate = RelativeTimeElement.prototype.getFormattedDate; var TimeAgoElement$getFormattedDate = TimeAgoElement.prototype.getFormattedDate; // var LocalTimeElement$getFormattedDate = LocalTimeElement.prototype.getFormattedDate; var RelativeTime = function (str, el) { // 相對時間解析 if (/^on ([\w ]+)$/.test(str)) { return '於 ' + el.title.replace(/ .+$/, ''); } // 使用字典公共翻譯的第二個正則翻譯相對時間 var time_ago = I18N[lang].pubilc.regexp[1]; return str.replace(time_ago[0], time_ago[1]); }; RelativeTimeElement.prototype.getFormattedDate = function () { var str = RelativeTimeElement$getFormattedDate.call(this); return RelativeTime(str, this); }; TimeAgoElement.prototype.getFormattedDate = function () { var str = TimeAgoElement$getFormattedDate.call(this); return RelativeTime(str, this); }; LocalTimeElement.prototype.getFormattedDate = function () { return this.title.replace(/ .+$/, ''); }; // 遍歷 time 元素進行翻譯 // 2016-04-16 github 改版,再也不用 time 標籤了。 $('time, relative-time, time-ago, local-time').each(function (i, el) { if (el.getFormattedDate) { // 跳過未註冊的 time 元素 el.textContent = el.getFormattedDate(); } }); } /** * 貢獻日曆 基於事件翻譯 */ function contributions() { var tip = document.getElementsByClassName('svg-tip-one-line'); // 等待 IncludeFragmentElement 元素加載完畢後綁定事件 var observe = require('github/observe').observe; observe(".js-calendar-graph-svg", function () { setTimeout(function () { // 延時綁定 mouseover 事件,不然無法翻譯 var $calendar = $('.js-calendar-graph'); walk($calendar[0]); // 翻譯日曆部分 $calendar.on('mouseover', '.day', function () { if (tip.length === 0) { // 沒有 tip 元素時退出防止報錯 return true; } var data = $(this).data(); // 獲取節點上的 data var $tip = $(tip[0]); $tip.html(data.count + ' 次貢獻 ' + data.date); var rect = this.getBoundingClientRect(); // 獲取元素位置 var left = rect.left + window.pageXOffset - tip[0].offsetWidth / 2 + 5.5; $tip.css('left', left); }); }, 999); }); } })(window, document);
雖然翻譯的不是很徹底,可是基本使用仍是沒問題的。jquery
該插件做者也在不停的更新中,仍是關注下,有空就看看更新吧!git