SteamDB_CN

SteamDB汉化插件

当前为 2022-05-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name:zh-CN SteamDB汉化
  3. // @name SteamDB_CN
  4. // @namespace https://blog.chrxw.com
  5. // @supportURL https://blog.chrxw.com/scripts.html
  6. // @contributionURL https://afdian.net/@chr233
  7. // @version 1.32
  8. // @description SteamDB汉化插件
  9. // @description:zh-cn SteamDB汉化插件
  10. // @author Chr_
  11. // @match https://steamdb.info/*
  12. // @license AGPL-3.0
  13. // @icon https://blog.chrxw.com/favicon.ico
  14. // @resource data https://cf.chrxw.com/SteamDB/SteamDB_CN.json
  15. // @grant GM_addStyle
  16. // @grant GM_getResourceText
  17. // @grant GM_registerMenuCommand
  18. // ==/UserScript==
  19.  
  20.  
  21. (function () {
  22. "use strict";
  23. const DEBUG = window.localStorage["dbg_mode"] == "开";
  24. const OUTPUT = window.localStorage["out_word"] == "开";
  25.  
  26. GM_registerMenuCommand(`调试汉化文本: ${DEBUG ? "开" : "关"}】`, () => {
  27. window.localStorage["dbg_mode"] = DEBUG ? "关" : "开";
  28. window.location.reload();
  29. });
  30.  
  31. GM_registerMenuCommand(`在控制台输出未匹配文本: ${OUTPUT ? "开" : "关"}】`, () => {
  32. window.localStorage["out_word"] = OUTPUT ? "关" : "开";
  33. window.location.reload();
  34. });
  35.  
  36. document.querySelector("html").setAttribute("lang", "zh-CN");
  37.  
  38. let Locales;
  39.  
  40. if (DEBUG) {
  41. const template = `{"DOC":{"更新时间":"调试模式","贡献名单":["调试模式"]},\n"STATIC":\n{\n\n},\n"INPUT":\n{\n\n},\n"LABEL":\n{\n\n},\n"DYNAMIC":\n{\n\n}\n}`;
  42. const box = document.createElement("div");
  43. box.className = "sdc";
  44. const text = document.createElement("textarea");
  45. box.appendChild(text);
  46. const action = document.createElement("div");
  47. action.className = "sdc-links";
  48. box.appendChild(action);
  49. const btnSave = document.createElement("a");
  50. btnSave.innerText = "💾 保存并应用";
  51. btnSave.addEventListener("click", () => {
  52. const raw = text.value.trim();
  53. if (!raw) {
  54. alert("翻译文本不能为空!!!");
  55. } else {
  56. try {
  57. JSON.parse(raw);
  58. window.localStorage["sdb_lang"] = raw;
  59. window.location.reload();
  60. } catch (e) {
  61. alert("翻译文本不是有效的JSON格式!!!");
  62. }
  63. }
  64. });
  65. action.appendChild(btnSave);
  66. const btnReset = document.createElement("a");
  67. btnReset.textContent = "🗑️ 清空文本";
  68. btnReset.addEventListener("click", () => {
  69. window.localStorage["sdb_lang"] = template;
  70. window.location.reload();
  71. });
  72. action.appendChild(btnReset);
  73. const btnOnline = document.createElement("a");
  74. btnOnline.textContent = "📄 当前在线文本";
  75. btnOnline.addEventListener("click", () => {
  76. if (confirm("替换为在线版本后当前所做修改将会丢失, 确定要继续吗?")) {
  77. text.value = GM_getResourceText("data");
  78. }
  79. });
  80. action.appendChild(btnOnline);
  81. const about = document.createElement('a');
  82. about.href = "https://blog.chrxw.com"
  83. about.innerText = "🔗 By Chr_ © 2022";
  84. action.appendChild(about);
  85.  
  86. const father = document.getElementById("main");
  87. father.insertBefore(box, father.firstChild);
  88. const customLang = window.localStorage["sdb_lang"] ?? template;
  89. text.value = customLang;
  90. Locales = JSON.parse(customLang);
  91. } else {
  92. Locales = JSON.parse(GM_getResourceText("data"));
  93. }
  94.  
  95. //计时
  96. const Start = new Date().getTime();
  97.  
  98. {//静态元素
  99. for (const [css, dic] of Object.entries(Locales.STATIC)) {
  100. if (OUTPUT) { console.log(`〖${css}〗`); }
  101. const elements = document.querySelectorAll(css);
  102. if (elements.length > 0) {
  103. for (let i = 0; i < elements.length; i++) {
  104. const element = elements[i];
  105. if (element.childElementCount === 0) {//节点内部无其他元素
  106. const raw = element.innerText?.trim();
  107. if (!raw || raw.length <= 2) { continue; }
  108. const txt = dic[raw];
  109. if (txt) {
  110. element.innerText = txt;
  111. } else if (OUTPUT) {
  112. console.log(`"${raw}": "",`);
  113. }
  114. } else {//节点内部有其他元素
  115. const nodes = element.childNodes;
  116. for (let j = 0; j < nodes.length; j++) {
  117. const node = nodes[j];
  118. if (node.nodeType === Node.TEXT_NODE) {
  119. const raw = node.textContent?.trim();
  120. if (!raw || raw.length <= 2) { continue; }
  121. const txt = dic[raw];
  122. if (txt) {
  123. node.textContent = txt;
  124. } else if (OUTPUT) {
  125. console.log(`"${raw}": "",`);
  126. }
  127. }
  128. }
  129. }
  130. }
  131. } else {
  132. if (OUTPUT) { console.warn(`CSS选择器未匹配到任何元素: ${css}`); }
  133. }
  134. }
  135. }
  136.  
  137. {//输入框
  138. const inputs = Locales.INPUT;
  139. if (OUTPUT) { console.log("〖输入框〗"); }
  140. const elements = document.querySelectorAll("input");
  141. for (let i = 0; i < elements.length; i++) {
  142. const element = elements[i];
  143. const raw = element.placeholder;
  144. if (!raw) { continue; }
  145. const txt = inputs[raw];
  146. if (txt) {
  147. element.placeholder = txt;
  148. } else if (OUTPUT) {
  149. console.log(`"${raw}": "",`);
  150. }
  151. }
  152. }
  153.  
  154. {//悬浮提示
  155. const labels = Locales.LABEL;
  156. if (OUTPUT) { console.log("〖提示文本〗"); }
  157. const elements = document.querySelectorAll("*[aria-label]");
  158. for (let i = 0; i < elements.length; i++) {
  159. const element = elements[i];
  160. const raw = element.getAttribute("aria-label");
  161. if (!raw) { continue; }
  162. const txt = labels[raw];
  163. if (txt) {
  164. element.setAttribute("aria-label", txt);
  165. } else if (OUTPUT) {
  166. console.log(`"${raw}": "",`);
  167. }
  168. }
  169. }
  170.  
  171. const { script: { version } } = GM_info;
  172. const { DOC: { "更新时间": update, "贡献名单": contribution } } = Locales;
  173.  
  174. const End = new Date().getTime();
  175.  
  176. // 统计耗时
  177. console.log("执行耗时", `${End - Start} ms`);
  178. console.log("=================================");
  179. console.log(`插件版本: ${version}`);
  180. console.log(`更新时间: ${update}`);
  181. console.log(`贡献名单: ${contribution.join(", ")}`);
  182. console.log("=================================");
  183. console.log("迷茫同学:\n『没有恶意 请问直接用谷歌翻译整个网页不香吗』")
  184.  
  185. // 添加按钮
  186. const headerUl=document.querySelector(".header-menu-container>div>ul:nth-child(1)");
  187. const footerUl=document.querySelector(".footer-container>div>ul:nth-child(1)");
  188. const scriptLink = document.createElement("li");
  189. scriptLink.innerHTML = `<a href="https://blog.chrxw.com" target="_blank">SteamDB 汉化 V${version}</a>`;
  190. headerUl.appendChild(scriptLink);
  191. footerUl.appendChild(scriptLink.cloneNode(true));
  192.  
  193. // 添加样式
  194. GM_addStyle(`
  195. .tabnav-tabs > a {
  196. min-width: 80px;
  197. }
  198. .sdc {
  199. display: flex;
  200. }
  201. .sdc > textarea {
  202. width: 100%;
  203. height: 200px;
  204. min-height: 200px;
  205. resize: vertical;
  206. }
  207. .sdc > div.sdc-links {
  208. width: 150px;
  209. margin: 5px;
  210. }
  211. .sdc > div.sdc-links > a {
  212. width: 100%;
  213. margin-bottom: 10px;
  214. background-color: #213145;
  215. color: white;
  216. font-size: 12px;
  217. border-radius: 0px;
  218. display: inline-block;
  219. height: 30px;
  220. }
  221. .sdc > div.sdc-links > a:last-child {
  222. width: 100%;
  223. margin-top: 30px;
  224. margin-bottom: 0px;
  225. color: #67c1f5;
  226. background-color: #273b4b;
  227. }
  228. `);
  229. })();