SteamDB_CN

SteamDB汉化插件

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