// ==UserScript== // @name Markdown toolbar for GreasyFork // @name:zh-CN GreasyFork markdown // @name:ar GreasyFork markdown // @name:bg GreasyFork markdown // @name:cs GreasyFork markdown // @name:da GreasyFork markdown // @name:de GreasyFork markdown // @name:el GreasyFork markdown // @name:en GreasyFork markdown // @name:eo GreasyFork markdown // @name:es GreasyFork markdown // @name:fi GreasyFork markdown // @name:fr GreasyFork markdown // @name:he GreasyFork markdown // @name:hr GreasyFork markdown // @name:hu GreasyFork markdown // @name:id GreasyFork markdown // @name:it GreasyFork markdown // @name:ja GreasyFork markdown // @name:ka GreasyFork markdown // @name:ko GreasyFork markdown // @name:nl GreasyFork markdown // @name:nb GreasyFork markdown // @name:pl GreasyFork markdown // @name:pt-BR GreasyFork markdown // @name:ro GreasyFork markdown // @name:ru GreasyFork markdown // @name:sk GreasyFork markdown // @name:sr GreasyFork markdown // @name:sv GreasyFork markdown // @name:th GreasyFork markdown // @name:tr GreasyFork markdown // @name:ug GreasyFork markdown // @name:uk GreasyFork markdown // @name:vi GreasyFork markdown // @name:zh-TW GreasyFork markdown // @name:zh-HK GreasyFork markdown // @name:fr-CA GreasyFork markdown // @description:zh-CN 在论坛默认使用格式为Markdown,添加格式帮助链接及在发布新脚本,回复时间启用快速编辑的工具栏 // @description:ar التنسيق الافتراضي المستخدم في المنتدى هوMarkdown,إضافة رابط تعليمات التنسيق ونشر برنامج نصي جديد,شريط أدوات وقت الرد مع تمكين التحرير السريع // @description:bg Форматът по подразбиране, използван във форума, еMarkdown,Добавете връзка за помощ при форматиране и публикувайте нов скрипт,Лента с инструменти за време за отговор с активирано бързо редактиране // @description:cs Výchozí formát používaný ve fóru jeMarkdown,Přidejte odkaz na nápovědu formátu a publikujte nový skript,Panel nástrojů doby odpovědi s povolenou rychlou úpravou // @description:da Standardformatet brugt i forummet erMarkdown,Tilføj format hjælpelink og udgiv nyt script,Værktøjslinjen Svartid med hurtig redigering aktiveret // @description:de Das im Forum verwendete Standardformat istMarkdown,Fügen Sie einen Link zur Formathilfe hinzu und veröffentlichen Sie ein neues Skript,Symbolleiste „Antwortzeit“ mit aktivierter Schnellbearbeitung // @description:el Η προεπιλεγμένη μορφή που χρησιμοποιείται στο φόρουμ είναιMarkdown,Προσθήκη συνδέσμου βοήθειας μορφής και δημοσίευση νέου σεναρίου,Γραμμή εργαλείων χρόνου απάντησης με ενεργοποιημένη τη γρήγορη επεξεργασία // @description:en The default format used in the forum isMarkdown,Add format help link and publish new script,Reply time toolbar with quick editing enabled // @description:eo La defaŭlta formato uzata en la forumo estasMarkdown,Aldonu formatan helpligon kaj publikigu novan skripton,Ilobreto de responda tempo kun rapida redaktado ebligita // @description:es El formato predeterminado utilizado en el foro esMarkdown,Agregue un enlace de ayuda de formato y publique un nuevo script,Barra de herramientas de tiempo de respuesta con edición rápida habilitada // @description:fi Foorumilla käytetty oletusmuoto onMarkdown,Lisää muodon ohjelinkki ja julkaise uusi skripti,Vastausajan työkalupalkki, jossa pikamuokkaus käytössä // @description:fr Le format par défaut utilisé dans le forum estMarkdown,Ajouter un lien d’aide au format et publier un nouveau script,Barre d’outils de temps de réponse avec édition rapide activée // @description:he פורמט ברירת המחדל בשימוש בפורום הואMarkdown,הוסף קישור עזרה בפורמט ופרסם סקריפט חדש,סרגל הכלים של זמן תשובה עם עריכה מהירה מופעלת // @description:hr Zadani format koji se koristi na forumu jeMarkdown,Dodajte vezu za pomoć u formatu i objavite novu skriptu,Alatna traka vremena odgovora s omogućenim brzim uređivanjem // @description:hu A fórumban használt alapértelmezett formátum aMarkdown,Formátum súgóhivatkozás hozzáadása és új szkript közzététele,Válaszidő eszköztár a gyors szerkesztés engedélyezésével // @description:id Format default yang digunakan dalam forum adalahMarkdown,Tambahkan tautan bantuan format dan publikasikan skrip baru,Bilah alat waktu balasan dengan pengeditan cepat diaktifkan // @description:it Il formato predefinito utilizzato nel forum èMarkdown,Aggiungi il collegamento alla guida sul formato e pubblica un nuovo script,Barra degli strumenti del tempo di risposta con modifica rapida abilitata // @description:ja フォーラムで使用されるデフォルトの形式は次のとおりです。Markdown,フォーマットヘルプリンクを追加し、新しいスクリプトを公開します,クイック編集が有効になった返信時間ツールバー // @description:ka ფორუმში გამოყენებული ნაგულისხმევი ფორმატი არისMarkdown,დაამატეთ ფორმატის დახმარების ბმული და გამოაქვეყნეთ ახალი სკრიპტი,პასუხის დროის ინსტრუმენტთა პანელი ჩართულია სწრაფი რედაქტირებით // @description:ko 포럼에서 사용되는 기본 형식은 다음과 같습니다.Markdown,형식 도움말 링크 추가 및 새 스크립트 게시,빠른 편집이 활성화된 응답 시간 도구 모음 // @description:nl Het standaardformaat dat op het forum wordt gebruikt isMarkdown,Voeg de Help-link voor het formaat toe en publiceer een nieuw script,Werkbalk Antwoordtijd met snelle bewerking ingeschakeld // @description:nb Standardformatet som brukes i forumet erMarkdown,Legg til format hjelpekobling og publiser nytt skript,Verktøylinje for svartid med hurtigredigering aktivert // @description:pl Domyślnym formatem używanym na forum jestMarkdown,Dodaj link pomocy formatu i opublikuj nowy skrypt,Pasek narzędzi czasu odpowiedzi z włączoną szybką edycją // @description:pt-BR O formato padrão usado no fórum éMarkdown,Adicionar link de ajuda de formato e publicar novo script,Barra de ferramentas de tempo de resposta com edição rápida habilitada // @description:ro Formatul implicit folosit în forum esteMarkdown,Adăugați linkul de ajutor pentru format și publicați un nou script,Bara de instrumente pentru timpul de răspuns cu editarea rapidă activată // @description:ru Формат по умолчанию, используемый на форуме:Markdown,Добавьте ссылку на справку по формату и опубликуйте новый скрипт.,Панель инструментов времени ответа с включенным быстрым редактированием // @description:sk Predvolený formát používaný vo fóre jeMarkdown,Pridajte odkaz na pomoc s formátom a publikujte nový skript,Panel s nástrojmi času odpovede s povolenou rýchlou úpravou // @description:sr Подразумевани формат који се користи на форуму јеMarkdown,Додајте везу за помоћ за формат и објавите нову скрипту,Трака са алаткама за време одговора са омогућеним брзим уређивањем // @description:sv Standardformatet som används i forumet ärMarkdown,Lägg till hjälplänk för format och publicera nytt skript,Verktygsfältet Svarstid med snabb redigering aktiverad // @description:th รูปแบบเริ่มต้นที่ใช้ในฟอรั่มคือMarkdown,เพิ่มลิงก์วิธีใช้รูปแบบและเผยแพร่สคริปต์ใหม่,แถบเครื่องมือเวลาตอบกลับพร้อมเปิดใช้งานการแก้ไขด่วน // @description:tr Forumda kullanılan varsayılan format:Markdown,Biçim yardım bağlantısı ekleyin ve yeni komut dosyası yayınlayın,Hızlı düzenlemenin etkin olduğu yanıt süresi araç çubuğu // @description:ug مۇنبەردە ئىشلىتىلگەن سۈكۈتتىكى فورماتىMarkdown,فورمات ياردەم ئۇلانمىسىنى قوشۇڭ ۋە يېڭى قوليازما ئېلان قىلىڭ,تېز تەھرىرلەش ئىقتىدارى بىلەن ۋاقىت قورال ستونىغا جاۋاب قايتۇرۇڭ // @description:uk Стандартний формат, який використовується на форуміMarkdown,Додайте посилання на довідку щодо формату та опублікуйте новий сценарій,Панель інструментів часу відповіді з увімкненим швидким редагуванням // @description:vi Định dạng mặc định được sử dụng trong diễn đàn làMarkdown,Thêm liên kết trợ giúp định dạng và xuất bản tập lệnh mới,Thanh công cụ thời gian trả lời có bật tính năng chỉnh sửa nhanh // @description:zh-TW 在論壇預設使用格式為Markdown,新增格式幫助連結及在發布新腳本,回覆時間啟用快速編輯的工具列 // @description:zh-HK 在論壇預設使用格式為Markdown,新增格式幫助連結及在發布新腳本,回覆時間啟用快速編輯的工具列 // @description:fr-CA Le format par défaut utilisé dans le forum estMarkdown,Ajouter un lien d’aide au format et publier un nouveau script,Barre d’outils de temps de réponse avec édition rapide activée // @namespace https://github.com/ChinaGodMan/UserScripts // @description Select Markdown format by default, add help links, add toolbar formatting buttons for markdown // @author wOxxOm, darkred, 人民的勤务员 // @contributor JixunMoe // @contributor 人民的勤务员 // @license MIT // @grant GM_xmlhttpRequest // @match https://greasyfork.org/*discussions/* // @match https://greasyfork.org/*scripts/*/versions/new* // @match https://greasyfork.org/*scripts/*/feedback* // @match https://greasyfork.org/*script_versions/new* // @match https://greasyfork.org/*/conversations/* // @match https://greasyfork.org/*/users/edit // @match https://greasyfork.org/*/reports/new* // @grant GM_addStyle // @run-at document-start // @version 2025.5.11.1 // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAoCAQAAADgMuRfAAABWklEQVR4Ae3YJQIUYRxA8R8OESs4BXcOsHXqngDnFtglKFjEqVOwjtNxd3f547Duux/2Xhx7Y98ITLbHdZHA6/aYDLM9EAl9YB77RWIP8Vgk9hkhvaKp/yP+R5SyXdRxl1KipqV0ETHGGVHDM8YMLoKZHogKH5jJICPIRIUZg45giyhxCykihsnFd3PD0kQwzkUhXDGOVBEs9+azy0kZwZrPShFRf7MrBxfx0hK1WOLl4CLCReNqX6Z1NrFeM9a3HxFyleSibsQbBY0oeNNJRNiolI1NDvZd09Rjmruis4j3Mj/IvG8SEc4boxZjnBedRZQ+sqZ50NJld0gt9otuIsJJIz97suVrf6NKNopuI8L2z7ZzAxaVUhRdR3Qw3zML/WChZ2kiwkUTwUQXRaqIcNzIzx4RKSPC1s/+ia/8/yP+R/wmP0kOicQeYl76H2cw2X63RAJv2W8ynwCwbA7V/z22eQAAAABJRU5ErkJggg== // @iconbak https://raw.githubusercontent.com/dcurtis/markdown-mark/master/png/66x40-solid.png // @supportURL https://github.com/darkred/Userscripts/issues // @downloadURL https://raw.githubusercontent.com/ChinaGodMan/UserScripts/main/greasyfork-markdown-toolbar/greasyfork-markdown-toolbar.user.js // @updateURL https://raw.githubusercontent.com/ChinaGodMan/UserScripts/main/greasyfork-markdown-toolbar/greasyfork-markdown-toolbar.user.js // ==/UserScript== /** * File: greasyfork-markdown-toolbar.user.js * Project: UserScripts * File Created: 2024/11/24,Sunday 12:38:51 * Author: 人民的勤务员@ChinaGodMan (china.qinwuyuan@gmail.com) * ----- * Last Modified: 2025/06/03,Tuesday 11:12:13 * Modified By: 人民的勤务员@ChinaGodMan (china.qinwuyuan@gmail.com) * ----- * License: MIT License * Copyright © 2024 - 2025 @ChinaGodMan,Inc */ // Example URLS to test: // https://greasyfork.org/en/discussions/new // https://greasyfork.org/en/scripts/422887-markdown-toolbar-for-greasyfork/discussions/78139 // https://greasyfork.org/en/scripts/23493/versions/new // https://greasyfork.org/en/scripts/422445-github-watcher/feedback // https://greasyfork.org/en/users/2160-darkred/conversations/new // https://greasyfork.org/en/users/edit var translate = 'en' var inForum = location.href.indexOf('/discussions') > 0 var inPostNewScriptVer = location.href.indexOf('/versions/new') > 0 var autoJumpEdit = true function contains(selector, text) { var elements = document.querySelectorAll(selector) return Array.from(elements).filter(function (element) { return RegExp(text).test(element.textContent) }) } //DOMContentLoaded有时会和其他脚本冲突导致监听失败 window.addEventListener('load', function (e) { var refElements = document.querySelectorAll(` input[name="authenticity_token"] + .label-note, label[for="script-version-additional-info-0"] + .label-note, label[for="changelog"] + .label-note, label[for="conversation_messages_attributes_0_content"] + .label-note, label[for="user_profile"] + .label-note, form > .label-note `) if (inForum) { refElements.forEach(element => { element.insertAdjacentHTML('beforeend', '
') addFeatures(element) }) } else { // not in Forum // This page has 2 non-code textareas: 'Additional info' and 'Changelog' if (inPostNewScriptVer) { refElements.forEach(element => { addFeatures(element.appendChild(document.createElement('br'))) }) } else { // every other page var nn = document.querySelectorAll('input[value="markdown"]') if (nn.length > 0) { for (var n, i = 0; (i < nn.length) && (n = nn[i]); i++) { if (location.href.indexOf('/script_versions/') !== -1) { n.click() } n.click() // 继续点击 addFeatures(n.parentNode.appendChild(document.createElement('br'))) } } } } }) function addFeatures(n) { if (!n) { return } var form = n.closest('form') if (form.action.indexOf('/edit') < 0 && autoJumpEdit) { n.click() } if (inPostNewScriptVer) { n.parentNode.textAreaNode = n.parentNode.querySelector('textarea.TextBox, textarea.previewable, div.previewable textarea') } else { n.parentNode.textAreaNode = form.querySelector('textarea.TextBox, textarea.previewable, div.previewable textarea') } GM_addStyle(` .mdButton { display: inline-block; cursor: pointer; margin: 0px; font-size: 12px; line-height: 1; font-weight: bold; padding: 4px 6px; background: -moz-linear-gradient(center bottom , #CCC 0%, #FAFAFA 100%) repeat scroll 0% 0% #F8F8F8; border: 1px solid #999; border-radius: 2px; white-space: nowrap; text-shadow: 0px 1px 0px #FFF; box-shadow: 0px 1px 0px #FFF inset, 0px -1px 2px #BBB inset; color: #333; } `) // Add buttons btnMake(n, '' + __('B') + '', __('Bold'), '**') btnMake(n, __('#'), __('Title'), '#', ' ') btnMake(n, '
  • ' + __('-') + '
  • ', __('List'), '- ', ' ') btnMake(n, __('>'), __('blockquote'), '
    ', '
    ') btnMake(n, '' + __('标记') + '', __('高亮显示选中文本'), '', '') btnMake(n, '' + __('I') + '', __('Italic'), '*') btnMake(n, '
    ' + __('居中') + '
    ', __('内容居中显示'), '
    ', '
    ') btnMake(n, '' + __('U') + '', __('Underline'), '', '') btnMake(n, '' + __('S') + '', __('Strikethrough'), '', '') btnMake(n, '<br>', __('Force line break'), '
    ', '', true) btnMake(n, __('---'), __('Horizontal line'), '\n\n---\n\n', '', true) btnMake(n, __('URL'), __('Add URL to selected text'), function (e) { try { edWrapInTag('[', '](' + prompt(__('URL') + ':') + ')', edInit(e.target)) } catch (ex) { } } ) btnMake(n, __('Image (https)'), __('Convert selected https://url to inline image'), '![' + __('image') + '](', ')') // if (inForum) { btnMake(n, __('Table'), __('Insert table template'), __('\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n'), '', true) //} 都添加表格 btnMake(n, __('Code'), __('Apply CODE markdown to selected text'), function (e) { var ed = edInit(e.target) if (ed.sel.indexOf('\n') < 0) { edWrapInTag('`', '`', ed) } else { edWrapInTag( ((ed.sel1 == 0) || (ed.text.charAt(ed.sel1 - 1) == '\n') ? '' : '\n') + '```' + (ed.sel.charAt(0) == '\n' ? '' : '\n'), (ed.sel.substr(-1) == '\n' ? '' : '\n') + '```' + (ed.text.substr(ed.sel2, 1) == '\n' ? '' : '\n'), ed ) } } ) g = btnMake(n, __('谷歌翻译'), __('快速翻译选中的内容'), function (e) { const translatedzh = edInit(e.target) translateText(translatedzh.sel).then(translatedText => { edWrapInTag('', translatedText, translatedzh, true) }).catch(error => { alert(' GoogleTranslate ERROR!!! ') }) } ) document.addEventListener('keydown', function (event) { if (event.ctrlKey && event.key === 'q') { g.click() } }) const WeiWeiimages = [ ['npzhyrb4txdoegwl82bkapekufb5', '维维发问:你有眼界吗?'], ['gkhj9p2qhtm62uza3qveshtooe2u', '维维被你震撼到了!'], ['p0i0f5xubhln1wvph3ip70zhpzqq', '维维发问:什么叫做搬起石头砸自己的脚?'], ['nahzae6vc3d3osq861cbt8uaopkk', '维维断言:这就是个国际笑话'], ['kzpmox79idq4gmsbyoj0yyuhx13v', '维维发问:你怎么敢讲这种话的?'] ] const WeiWeiLoveYou = WeiWei(WeiWeiimages, true) btnMake(n, '维维嘲讽', '来自爱国教授维维的五连问', __('\n\n' + WeiWeiLoveYou + `\n\n `), '', true) function WeiWei(images, WeiWeiSays) { let html = `

    爱国教授维维有话对你说


    ` images.forEach(([imgSrc, rtText]) => { const WeiWeiImg = `https://greasyfork.s3.us-east-2.amazonaws.com/${imgSrc} ` if (WeiWeiSays) { html += ` ${rtText} ` } else { html += `\n` } }) html += `

    ` return html } var allPreviewTabs = contains('.preview-tab', 'Preview') allPreviewTabs.forEach(element => { element.onclick = function (event) { let target = event.target // delegation: where was the click? if (target.tagName !== 'A' && target.tagName !== 'SPAN') { return } form.querySelectorAll('.Button').forEach(element2 => element2.style.display = 'none') } }) var allWriteTabs = contains('.write-tab', 'Write') allWriteTabs.forEach(element => { element.onclick = function (event) { let target = event.target // where was the click? if (target.tagName !== 'A' && target.tagName !== 'SPAN') { return } form.querySelectorAll('.Button').forEach(element2 => element2.style.display = 'inline-block') } }) } function btnMake(afterNode, label, title, tag1_or_cb, tag2, noWrap) { var a = document.createElement('a') a.className = 'mdButton' a.innerHTML = label a.title = title a.addEventListener('click', typeof (tag1_or_cb) === 'function' ? tag1_or_cb : // if noWrap ? function (e) { edInsertText(tag1_or_cb, edInit(e.target)) } : // else if function (e) { edWrapInTag(tag1_or_cb, tag2, edInit(e.target)) } // else ) var nparent inForum ? nparent = afterNode : nparent = afterNode.parentNode a.textAreaNode = nparent.textAreaNode || nparent.parentNode.querySelector('textArea') nparent.appendChild(a) return a } function edInit(btn) { var ed = { node: btn.textAreaNode || btn.parentNode.textAreaNode } ed.sel1 = ed.node.selectionStart ed.sel2 = ed.node.selectionEnd ed.text = ed.node.value ed.sel = ed.text.substring(ed.sel1, ed.sel2) return ed } function edWrapInTag(tag1, tag2, ed, rep = false) { if (rep) { ed.node.value = ed.text.substr(0, ed.sel1) + (tag2 ? tag2 : tag1) + ed.text.substr(ed.sel2) } else { ed.node.value = ed.text.substr(0, ed.sel1) + tag1 + ed.sel + (tag2 ? tag2 : tag1) + ed.text.substr(ed.sel2) } ed.node.setSelectionRange(ed.sel1 + tag1.length, ed.sel1 + tag1.length + ed.sel.length) if (rep) return//不选中,文本太长了,选中干啥, ed.node.focus() } function edInsertText(text, ed) { ed.node.value = ed.text.substr(0, ed.sel2) + text + ed.text.substr(ed.sel2) ed.node.setSelectionRange(ed.sel2 + text.length, ed.sel2 + text.length) ed.node.focus() } var __ = (function (l, langs) { var lang = langs[l] || langs[l.replace(/-.+/, '')] return lang ? function (text) { return lang[text] || text } : function (text) { return text } // No matching language, fallback to english })(location.pathname.match(/^\/(.+?)\//)[1], { 'zh-CN': { 'B': '粗体', 'I': '斜体', 'U': '下划线', 'S': '删除线', 'Bold': '粗体', '-': '列表', '#': '标题', '>': '引用', '---': '分割线', 'Italic': '斜体', 'Underline': '下划线', 'Strikethrough': '删除线', 'Force line break': '强制换行', 'Horizontal line': '水平分割线', 'URL': '链接', 'Title': '正文标题H1', 'List': '无序列表,用作分类下的信息展示', 'Add URL to selected text': '为所选文字添加链接', 'Image (https)': '图片 (https)', 'Convert selected https://url to inline image': '将所选地址转换为行内图片', 'image': '图片描述', // Default image alt value 'Table': '表格', 'blockquote': '引用文本', 'Insert table template': '插入表格模板', 'Code': '代码', 'Apply CODE markdown to selected text': '将选中代码围起来', '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n': '\n| 表头 1 | 表头 2 |\n|-------|-------|\n| 表格 1 | 表格 2 |\n| 表格 3 | 表格 4 |\n' }, 'ru': { 'B': 'Ж', 'I': 'К', 'U': 'Ч', 'S': 'П', 'Bold': 'Жирный', 'Italic': 'Курсив', 'Underline': 'Подчеркнутый', 'Strikethrough': 'Перечеркнутый', 'Force line break': 'Новая строка', 'Horizontal line': 'Горизонтальная линия', 'URL': 'ссылка', 'Title': 'Заголовок', 'List': 'Неупорядоченный список', 'Add URL to selected text': 'Добавить ссылку к выделенному тексту', 'Image (https)': 'Картинка (https)', 'Convert selected https://url to inline image': 'Преобразовать выделенный https:// адрес в картинку', 'image': 'картинка', // Default image alt value 'Table': 'Таблица', 'Insert table template': 'Вставить шаблон таблицы', 'Code': 'Код', 'Apply CODE markdown to selected text': 'Пометить выделенный фрагмент как программный код', '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n': '\n| заголовок1 | заголовок2 |\n|-------|-------|\n| ячейка1 | ячейка2 |\n| ячейка3 | ячейка4 |\n' }, 'fr': { 'B': 'G', 'I': 'I', 'U': 'S', 'S': 'B', 'Bold': 'Gras', 'Italic': 'Italique', 'Underline': 'Souligné', 'Strikethrough': 'Barré', 'Force line break': 'Forcer le saut de ligne', 'Horizontal line': 'Ligne horizontale', 'URL': 'URL', 'Title': 'Titre', 'List': 'Liste non ordonnée', 'Add URL to selected text': 'Ajouter URL au texte sélectionné', 'Image (https)': 'Image (https)', 'Convert selected https://url to inline image': 'Convertir https://url sélectionnés en images', 'image': 'image', // Default image alt value 'Table': 'Tableau', 'Insert table template': 'Insérer un modèle de table', 'Code': 'Code', 'Apply CODE markdown to selected text': 'Appliquer CODE markdown au texte sélectionné', '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n': '\n| En-tête 1 | En-tête 2 |\n|-------|-------|\n| cellule 1 | cellule 2 |\n| cellule 3 | cellule 4 |\n' } }) function translateText(text) { return new Promise((resolve, reject) => { var api = 'https://translate.googleapis.com/translate_a/single' var params = { client: 'gtx', dt: 't', sl: 'auto', tl: translate, q: text } GM_xmlhttpRequest({ method: 'GET', url: api + buildQueryString(params), onload: function (response) { try { var data = JSON.parse(response.responseText.replace('\'', '\u2019')) var translatedText = data[0].reduce((acc, item) => acc + item[0], '') resolve(translatedText) } catch (error) { console.error('翻译失败:', error) reject('翻译失败') } }, onerror: function (response) { console.error('请求翻译失败:', response.statusText) reject('请求翻译失败') } }) }) } function buildQueryString(params) { return '?' + Object.keys(params).map(function (key) { return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) }).join('&') }