GitHub汉化插件

GitHub汉化插件,包含人机翻译

当前为 2020-08-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Internationalization
  3. // @name:zh-CN GitHub汉化插件
  4. // @name:ja GitHub日本語
  5. // @namespace https://github.com/k1995/github-i18n-plugin/
  6. // @version 0.7
  7. // @description Translate GitHub.com
  8. // @description:zh GitHub汉化插件,包含人机翻译
  9. // @description:zh-CN GitHub汉化插件,包含人机翻译
  10. // @description:ja GitHub日本語プラグイン
  11. // @author k1995
  12. // @match https://github.com/*
  13. // @grant GM_xmlhttpRequest
  14. // @grant GM_getResourceText
  15. // @resource zh-CN https://www.githubs.cn/raw-githubusercontent/k1995/github-i18n-plugin/master/locales/zh-CN.json
  16. // @resource ja https://raw.githubusercontent.com/k1995/github-i18n-plugin/master/locales/ja.json
  17. // @require https://cdn.bootcdn.net/ajax/libs/timeago.js/4.0.2/timeago.full.min.js
  18. // @require http://code.jquery.com/jquery-2.1.1.min.js
  19. // ==/UserScript==
  20.  
  21. (function() {
  22. 'use strict';
  23.  
  24. const SUPPORT_LANG = ["zh-CN", "ja"];
  25. const lang = (navigator.language || navigator.userLanguage);
  26. const locales = getLocales(lang)
  27.  
  28. translateByCssSelector();
  29. translateDesc();
  30. traverseElement(document.body);
  31. watchUpdate();
  32.  
  33. function getLocales(lang) {
  34. if(lang.startsWith("zh")) { // zh zh-TW --> zh-CN
  35. lang = "zh-CN";
  36. }
  37. if(SUPPORT_LANG.includes(lang)) {
  38. return JSON.parse(GM_getResourceText(lang));
  39. }
  40. return {
  41. css: [],
  42. dict: {}
  43. };
  44. }
  45.  
  46. function translateRelativeTimeEl(el) {
  47. const datetime = $(el).attr('datetime');
  48. $(el).text(timeago.format(datetime, lang.replace('-', '_')));
  49. }
  50.  
  51. function translateElement(el) {
  52. // Get the text field name
  53. let k;
  54. if(el.tagName === "INPUT") {
  55. if (el.type === 'button' || el.type === 'submit') {
  56. k = 'value';
  57. } else {
  58. k = 'placeholder';
  59. }
  60. } else {
  61. k = 'data';
  62. }
  63.  
  64. const txtSrc = el[k].trim();
  65. const key = txtSrc.toLowerCase()
  66. .replace(/\xa0/g, ' ') // replace ' '
  67. .replace(/\s{2,}/g, ' ');
  68.  
  69. if(locales.dict[key]) {
  70. el[k] = el[k].replace(txtSrc, locales.dict[key])
  71. }
  72. }
  73.  
  74. function shoudTranslateEl(el) {
  75. const blockIds = ["readme"];
  76. const blockTags = ["CODE", "SCRIPT", "LINK", "IMG", "svg"];
  77.  
  78. return !(el.id && blockIds.includes(el.id))
  79. && !(blockTags.includes(el.tagName));
  80. }
  81.  
  82. function traverseElement(el) {
  83. if(!shoudTranslateEl(el)) {
  84. return
  85. }
  86.  
  87. for(const child of el.childNodes) {
  88. if(["RELATIVE-TIME", "TIME-AGO"].includes(el.tagName)) {
  89. translateRelativeTimeEl(el);
  90. return;
  91. }
  92.  
  93. if(child.nodeType === Node.TEXT_NODE) {
  94. translateElement(child);
  95. }
  96. else if(child.nodeType === Node.ELEMENT_NODE) {
  97. if(child.tagName === "INPUT") {
  98. translateElement(child);
  99. } else {
  100. traverseElement(child);
  101. }
  102. } else {
  103. // pass
  104. }
  105. }
  106. }
  107.  
  108. function watchUpdate() {
  109. const m = window.MutationObserver || window.WebKitMutationObserver;
  110. const observer = new m(function (mutations, observer) {
  111. for(let mutationRecord of mutations) {
  112. for(let node of mutationRecord.addedNodes) {
  113. traverseElement(node);
  114. }
  115. }
  116. });
  117.  
  118. observer.observe(document.body, {
  119. subtree: true,
  120. characterData: true,
  121. childList: true,
  122. });
  123. }
  124.  
  125. // translate "about"
  126. function translateDesc() {
  127. $(".repository-content .f4").append("<br/>");
  128. $(".repository-content .f4").append("<a id='translate-me' href='#' style='color:rgb(27, 149, 224);font-size: small'>翻译</a>");
  129. $("#translate-me").click(function() {
  130. // get description text
  131. const desc = $(".repository-content .f4")
  132. .clone()
  133. .children()
  134. .remove()
  135. .end()
  136. .text()
  137. .trim();
  138.  
  139. if(!desc) {
  140. return;
  141. }
  142.  
  143. GM_xmlhttpRequest({
  144. method: "GET",
  145. url: `https://www.githubs.cn/translate?q=`+ encodeURIComponent(desc),
  146. onload: function(res) {
  147. if (res.status === 200) {
  148. $("#translate-me").hide();
  149. // render result
  150. const text = res.responseText;
  151. $(".repository-content .f4").append("<span style='font-size: small'>由 <a target='_blank' style='color:rgb(27, 149, 224);' href='https://www.githubs.cn'>GitHub中文社区</a> 翻译👇</span>");
  152. $(".repository-content .f4").append("<br/>");
  153. $(".repository-content .f4").append(text);
  154. } else {
  155. alert("翻译失败");
  156. }
  157. }
  158. });
  159. });
  160. }
  161.  
  162. function translateByCssSelector() {
  163. if(locales.css) {
  164. for(var css of locales.css) {
  165. if($(css.selector).length > 0) {
  166. if(css.key === '!html') {
  167. $(css.selector).html(css.replacement);
  168. } else {
  169. $(css.selector).attr(css.key, css.replacement);
  170. }
  171. }
  172. }
  173. }
  174. }
  175. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址