From 83f856d1ae6ce24b37225a0a83c75a3a3a29eb4a Mon Sep 17 00:00:00 2001 From: mic Date: Wed, 1 Apr 2026 00:34:26 +0200 Subject: [PATCH] trasnlate webchat removed. see #247 --- _locales/en/messages.json | 12 --- api_webchat/messagesArea.js | 23 ------ claude-spec/01-architecture.md | 17 ++-- claude-spec/02-prompts.md | 18 ++--- claude-spec/05-options.md | 11 +-- js/mzta-compose-script.js | 2 +- mzta-background.js | 115 +--------------------------- options/mzta-options-default.js | 1 - pages/translate/mzta-translate.html | 12 --- pages/translate/mzta-translate.js | 21 ----- 10 files changed, 21 insertions(+), 211 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2e9377f2..92e9bad0 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -239,10 +239,6 @@ "message": "Save as Summary", "description": "Button label in the webchat window to save the AI response as a message summary" }, - "webchat_save_as_translation": { - "message": "Save as Translation", - "description": "Button label in the webchat window to save the AI response as a message translation" - }, "chatgpt_textarea_not_found_error": { "message": "It seems that the ChatGPT page is taking too long to load. If it finishes loading, click the button on the right. If the problem persists, please check the service status.", "description": "" @@ -2101,10 +2097,6 @@ "message": "Choose when to translate messages: disabled, only when clicking the button, or automatically when opening a message.", "description": "" }, - "prefs_OptionText_translate_display_mode": { - "message": "Display mode for translations", - "description": "" - }, "prefs_OptionText_display_mode_inline": { "message": "Message pane (inline)", "description": "" @@ -2113,10 +2105,6 @@ "message": "Chat window", "description": "" }, - "prefs_OptionText_translate_display_mode_Info": { - "message": "Choose where to display translations. Note: automatic mode always uses inline display.", - "description": "" - }, "prefs_OptionText_translate_max_display_length": { "message": "Maximum length of displayed translation", "description": "" diff --git a/api_webchat/messagesArea.js b/api_webchat/messagesArea.js index 62fffa42..e2611801 100644 --- a/api_webchat/messagesArea.js +++ b/api_webchat/messagesArea.js @@ -481,29 +481,6 @@ class MessagesArea extends HTMLElement { selectionInfo.style.display = "block"; } - // Save as Translation button (only shown for translation webchat sessions) - if(promptData.prompt_info?.headerMessageId && promptData.prompt_info?.translationTabId) { - const saveTranslationButton = document.createElement('button'); - saveTranslationButton.textContent = browser.i18n.getMessage("webchat_save_as_translation"); - saveTranslationButton.classList.add('action_btn'); - saveTranslationButton.addEventListener('click', async () => { - let finalText = removeAloneBRs(fullTextHTMLAtAssignment); - const selectedHTML = this.getCurrentSelectionHTML(); - if(selectedHTML != "") { - finalText = removeAloneBRs(selectedHTML); - } - await browser.runtime.sendMessage({ - command: "chatgpt_saveTranslation", - text: finalText, - headerMessageId: promptData.prompt_info.headerMessageId, - tabId: promptData.prompt_info.translationTabId || promptData.tabId, - }); - browser.runtime.sendMessage({command: "chatgpt_close", window_id: (await browser.windows.getCurrent()).id}); - }); - actionButtons.appendChild(saveTranslationButton); - selectionInfo.style.display = "block"; - } - // diff viewer button if(promptData.prompt_info?.use_diff_viewer == "1") { const diffvButton = document.createElement('button'); diff --git a/claude-spec/01-architecture.md b/claude-spec/01-architecture.md index 8f5e3e42..636bda65 100644 --- a/claude-spec/01-architecture.md +++ b/claude-spec/01-architecture.md @@ -82,13 +82,8 @@ mzta-background.js (checks summarize_auto + summarize_display_mode prefs) ### Data Flow: Inline Translation on Message Display -The `translate_display_mode` preference (`'inline'` or `'webchat'`) controls where -the translation is displayed. The `translate_auto` preference controls when it is triggered. - -- `translate_auto = 2` (automatic) always generates inline, regardless of `translate_display_mode`. -- `translate_auto = 1` (manual button) respects `translate_display_mode`: - - `'inline'` → button click triggers inline generation - - `'webchat'` → button click opens the AI chat window via `_openTranslationWebchat()` +The `translate_auto` preference controls when translation is triggered. +Translation always renders inline (webchat mode has been removed). The target language is determined by `translate_lang` (fallback on `default_chatgpt_lang`). @@ -97,16 +92,14 @@ User opens/selects a message in Thunderbird ↓ mzta-compose-script.js (sends "initTranslation" to background) ↓ -mzta-background.js (checks translate + translate_auto + translate_display_mode prefs) +mzta-background.js (checks translate + translate_auto prefs) ↓ ┌──────────────────────────────────────────────────────────┐ │ translate_auto = 0 → do nothing │ │ translate_auto = 1 → show "click to translate" button │ - │ display_mode = inline → click triggers inline gen │ - │ display_mode = webchat → click opens chat window │ - │ translate_auto = 2 → generate immediately (always inline)│ + │ translate_auto = 2 → generate immediately │ └──────────────────────────────────────────────────────────┘ - ↓ (if generating inline) + ↓ taTranslationStore (check cache / set processing) ↓ (cache miss) mzta-special-commands (via Web Worker, NOT chatgpt_web) diff --git a/claude-spec/02-prompts.md b/claude-spec/02-prompts.md index c2c3eaae..60b1624f 100644 --- a/claude-spec/02-prompts.md +++ b/claude-spec/02-prompts.md @@ -88,24 +88,24 @@ The summarize feature uses two distinct prompt pathways: ### Translate: Inline-Only Prompt System -The translate feature uses a single special prompt (`prompt_translate_this`) for translating emails. It supports both inline display and webchat mode, but has no context menu entry. +The translate feature uses a single special prompt (`prompt_translate_this`) for translating emails. Translation always renders inline (no webchat mode). -**Inline Translation on Message Display** (controlled by `translate_auto` and `translate_display_mode` prefs): +**Inline Translation on Message Display** (controlled by `translate_auto` pref): - Uses a single special prompt: `prompt_translate_this` -- The prompt text is appended with the target language and the email body: `prompt_text + " " + lang + ". \"" + body_text + "\""` +- The prompt uses placeholders (`{%mail_subject%}`, `{%mail_html_body%}`, `{%thunderai_translate_lang%}`, `{%thunderai_translate_exclude_lang%}`) resolved via the standard placeholder system +- The AI response is a JSON object: `{ "subject": "...", "body": "...", "status": "1"|"-1" }` + - `status = "1"`: translation completed, subject and body are displayed + - `status = "-1"`: translation skipped (excluded/target language), a "skipped" message is shown - Target language is determined by `translate_lang` pref, falling back to `default_chatgpt_lang` - Does **not** support `chatgpt_web` connection type (shows error if configured) -- `translate_display_mode = 'inline'`: result is rendered as a styled banner (green/teal theme) in the message body via `mzta-compose-script.js` -- `translate_display_mode = 'webchat'`: opens AI chat window; webchat shows a "Save as Translation" button to persist the result inline -- `translate_auto = 2` (automatic) always generates inline regardless of `translate_display_mode` +- Result is rendered as a styled banner (green/teal theme) in the message body via `mzta-compose-script.js` - Banner includes refresh (↻) and delete (×) buttons - Cached per-message via `taTranslationStore` / `taStorage` (max 100 entries) - The prompt was originally a regular prompt (`defaultPrompts`) and was moved to `specialPrompts` with `is_special: "1"` and `type: "1"` (reading email only) -**Prompt Building** — `taPromptUtils.buildTranslationPrompt(fullMessage, lang)`: +**Prompt Building** — `taPromptUtils.buildTranslationPrompt(fullMessage)`: - Retrieves the `prompt_translate_this` special prompt text -- Extracts the email body from the full message -- Combines prompt + language + body text +- Resolves placeholders via `placeholdersUtils.getPlaceholdersValues()` + `replacePlaceholders()` - Returns `{ promptText, promptInfo }` ## Prompt Types Reference diff --git a/claude-spec/05-options.md b/claude-spec/05-options.md index 06c0d250..d8d14ef3 100644 --- a/claude-spec/05-options.md +++ b/claude-spec/05-options.md @@ -100,7 +100,6 @@ These are generated programmatically at the bottom of `mzta-options-default.js` | `summarize_max_display_length` | `0` | Maximum characters shown in inline summary before truncation. `0` = no limit (show full text). When set, text is truncated at a word boundary and a "See more"/"See less" toggle link is shown. | | `translate` | `true` | Enable email translation | | `translate_auto` | `0` | Auto-translate mode: `0` = disabled, `1` = manual (show button), `2` = automatic (translate on message open), `3` = generate on email receive (background pre-cache via `onNewMailReceived`, no UI during generation) | -| `translate_display_mode` | `'inline'` | Where to display translations: `'inline'` = message pane banner, `'webchat'` = AI chat window. Note: `translate_auto = 2` and `translate_auto = 3` always use inline regardless of this setting. | | `translate_max_display_length` | `0` | Maximum characters shown in inline translation before truncation. `0` = no limit (show full text). When set, text is truncated at a word boundary and a "See more"/"See less" toggle link is shown. | | `translate_lang` | `''` | Target language for translation. Falls back to `default_chatgpt_lang` if empty. | @@ -134,13 +133,9 @@ The translate settings page provides: - `0` (Disabled) — no inline translations - `1` (Manual) — shows a "Get AI Translation" button in message display - `2` (Automatic) — generates translation immediately when message is opened -3. **Display mode dropdown** (`translate_display_mode`) — controls where translations are shown: - - `'inline'` — translation banner in the message pane (default) - - `'webchat'` — opens the AI chat window with a "Save as Translation" button - - Note: `translate_auto = 2` always generates inline regardless of this setting. -4. **Max display length** (`translate_max_display_length`) — number input, limits inline translation text to N characters. `0` = no limit. When truncated, a "See more"/"See less" toggle link is appended. -5. **Target language** (`translate_lang`) — text input for the destination language. If empty, falls back to `default_chatgpt_lang`. -6. **One editable prompt** — the translation instruction prompt (`prompt_translate_this`) with Save/Reset buttons and placeholder autocomplete. Default text comes from i18n string `prompt_translate_this_full_text`. +3. **Max display length** (`translate_max_display_length`) — number input, limits inline translation text to N characters. `0` = no limit. When truncated, a "See more"/"See less" toggle link is appended. +4. **Target language** (`translate_lang`) — text input for the destination language. If empty, falls back to `default_chatgpt_lang`. +5. **One editable prompt** — the translation instruction prompt (`prompt_translate_this`) with Save/Reset buttons and placeholder autocomplete. Default text comes from i18n string `prompt_translate_this_full_text`. ## Adding a New Preference diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index b60d006b..46e344a4 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -1423,7 +1423,7 @@ switch (message.command) { triggerBtn.onclick = () => { _removeToolbarItem('mzta-toolbar-translation'); browser.runtime.sendMessage({ - command: message.webchat ? "triggerTranslationWebchat" : "triggerTranslationGeneration", + command: "triggerTranslationGeneration", headerMessageId: message.headerMessageId }); }; diff --git a/mzta-background.js b/mzta-background.js index 5e9344b1..7a4b0a27 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -335,7 +335,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { async function _initTranslation() { try { let tabId = sender.tab.id; - let prefs = await browser.storage.sync.get({ translate: prefs_default.translate, translate_auto: prefs_default.translate_auto, translate_display_mode: prefs_default.translate_display_mode, translate_max_display_length: prefs_default.translate_max_display_length }); + let prefs = await browser.storage.sync.get({ translate: prefs_default.translate, translate_auto: prefs_default.translate_auto, translate_max_display_length: prefs_default.translate_max_display_length }); if (!prefs.translate) return; @@ -364,11 +364,7 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { } // Manual button mode (translate_auto === 1) - if (prefs.translate_display_mode === 'inline') { - browser.tabs.sendMessage(tabId, { command: "showTranslationButton", headerMessageId: message.headerMessageId }); - } else { - browser.tabs.sendMessage(tabId, { command: "showTranslationButton", headerMessageId: message.headerMessageId, webchat: true }); - } + browser.tabs.sendMessage(tabId, { command: "showTranslationButton", headerMessageId: message.headerMessageId }); } catch (e) { taLog.error("Error in initTranslation: " + e); } @@ -393,83 +389,17 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { } _triggerTranslationGeneration(message); break; - case 'triggerTranslationWebchat': - async function _triggerTranslationWebchat(message) { - let tabId = sender.tab.id; - let prefs_tw = await browser.storage.sync.get({ - translate_lang: prefs_default.translate_lang, - default_chatgpt_lang: prefs_default.default_chatgpt_lang - }); - const lang_tw = prefs_tw.translate_lang || prefs_tw.default_chatgpt_lang || ''; - if (!lang_tw) { - let tabs = await browser.tabs.query({ active: true, currentWindow: true }); - browser.tabs.sendMessage(tabId, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage('translate_no_language_configured') }); - browser.tabs.sendMessage(tabId, { command: "showTranslationButton", headerMessageId: message.headerMessageId, webchat: true }); - return; - } - await _openTranslationWebchat(message.headerMessageId, tabId); - } - _triggerTranslationWebchat(message); - break; case 'refreshTranslation': async function _refreshTranslation(message) { let tabId = sender.tab.id; await translationStore.removeTranslation(message.headerMessageId); - let prefs_refresh_tr = await browser.storage.sync.get({ translate_display_mode: prefs_default.translate_display_mode }); - if (prefs_refresh_tr.translate_display_mode === 'webchat') { - await _openTranslationWebchat(message.headerMessageId, tabId); - } else { - await _generateTranslationForMessage(message.headerMessageId, tabId); - } + await _generateTranslationForMessage(message.headerMessageId, tabId); } _refreshTranslation(message); break; case 'removeTranslation': translationStore.removeTranslation(message.headerMessageId); break; - case 'chatgpt_saveTranslation': - async function _saveTranslationFromWebchat(msg) { - try { - let rawText = msg.text.trim(); - let translatedBody = ''; - let translatedSubject = ''; - let translationStatus = ''; - try { - const parsed = JSON.parse(rawText); - translatedBody = parsed.body || ''; - translatedSubject = parsed.subject || ''; - translationStatus = String(parsed.status || ''); - } catch (e) { - translatedBody = rawText; - } - let prefs_tr = await browser.storage.sync.get({ - translate_lang: prefs_default.translate_lang, - default_chatgpt_lang: prefs_default.default_chatgpt_lang, - translate_max_display_length: prefs_default.translate_max_display_length - }); - let lang = prefs_tr.translate_lang || prefs_tr.default_chatgpt_lang || ''; - const translationData = { - translated_text: translatedBody, - translated_subject: translatedSubject, - translation_status: translationStatus, - lang: lang, - headerMessageId: msg.headerMessageId - }; - await translationStore.saveTranslation(translationData, msg.headerMessageId); - try { - browser.tabs.sendMessage(msg.tabId, { - command: "showTranslation", - data: { ...translationData, maxDisplayLength: prefs_tr.translate_max_display_length } - }); - } catch (e) { - taLog.error("Error sending showTranslation to tab: " + e); - } - } catch (error) { - console.error("[ThunderAI] Error saving translation from webchat:", error); - } - } - _saveTranslationFromWebchat(message); - break; case 'chatgpt_close': async function _closeChatGptWindow(window_id) { let prefs_close = await browser.storage.sync.get({chatgpt_win_save_position: prefs_default.chatgpt_win_save_position}); @@ -980,45 +910,6 @@ async function _openSummaryWebchat(headerMessageId, tabId) { } } -async function _openTranslationWebchat(headerMessageId, tabId) { - try { - const messageResult = await browser.messages.query({ headerMessageId: headerMessageId }); - if (!messageResult || messageResult.messages.length === 0) { - console.error("[ThunderAI] _openTranslationWebchat: Message not found for headerMessageId:", headerMessageId); - return; - } - - const curr_message = messageResult.messages[0]; - const curr_message_full = await browser.messages.getFull(curr_message.id); - - const prefs = await browser.storage.sync.get({ - ...prefs_default, - translate_lang: prefs_default.translate_lang, - default_chatgpt_lang: prefs_default.default_chatgpt_lang - }); - const connectionType = getConnectionType(prefs, {}, 'translate'); - if (connectionType === 'chatgpt_web') { - const errorMsg = browser.i18n.getMessage('translate_chatgpt_web_not_supported'); - await translationStore.saveError(headerMessageId, errorMsg); - browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { error: true, message: errorMsg } }); - return; - } - - const lang = prefs.translate_lang || prefs.default_chatgpt_lang || ''; - if (!lang) { - taLog.warn("Translation skipped: no language configured (translate_lang and default_chatgpt_lang are both empty)."); - return; - } - const { promptText, promptInfo } = await taPromptUtils.buildTranslationPrompt(curr_message_full); - promptInfo.headerMessageId = headerMessageId; - promptInfo.translationTabId = tabId; - - openChatGPT(promptText, promptInfo.action, tabId, promptInfo.name, promptInfo.need_custom_text, promptInfo); - } catch (error) { - console.error("[ThunderAI] Error opening translation webchat:", error); - } -} - // Listen for messages from ThunderAI-Sparks browser.runtime.onMessageExternal.addListener((message, sender, sendResponse) => { switch (message.action) { diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index c1015507..4ac38c96 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -143,7 +143,6 @@ export const prefs_default = { summarize_max_display_length: 0, // 0 = no limit, otherwise max chars shown inline translate: true, translate_auto: 0, // 0: disabled, 1: manual button, 2: automatic on message open, 3: generate on email receive - translate_display_mode: 'inline', // 'inline' or 'webchat' translate_max_display_length: 0, // 0 = no limit, otherwise max chars shown inline translate_lang: '', // target language, fallback on default_chatgpt_lang translate_exclude_lang: '', // languages to do not translate diff --git a/pages/translate/mzta-translate.html b/pages/translate/mzta-translate.html index dc7a4e9d..b582b36e 100644 --- a/pages/translate/mzta-translate.html +++ b/pages/translate/mzta-translate.html @@ -40,18 +40,6 @@ - - __MSG_prefs_OptionText_translate_display_mode__ - - - - __MSG_prefs_OptionText_translate_max_display_length__ diff --git a/pages/translate/mzta-translate.js b/pages/translate/mzta-translate.js index a4812808..df415879 100644 --- a/pages/translate/mzta-translate.js +++ b/pages/translate/mzta-translate.js @@ -74,8 +74,6 @@ document.addEventListener("DOMContentLoaded", async () => { document.querySelectorAll(".option-input").forEach(element => { element.addEventListener("change", saveOptions); }); - document.getElementById('translate_auto').addEventListener('change', updateDisplayModeConstraint); - let translate_textarea = document.getElementById("translate_prompt_text"); let translate_save_btn = document.getElementById("btn_save_prompt"); let translate_reset_btn = document.getElementById("btn_reset_prompt"); @@ -119,21 +117,6 @@ document.addEventListener("DOMContentLoaded", async () => { // Methods to manage options, derived from: /options/mzta-options.js -function updateDisplayModeConstraint() { - const translate_auto_el = document.getElementById('translate_auto'); - const display_mode_el = document.getElementById('translate_display_mode'); - const autoVal = String(translate_auto_el.value); - if (autoVal === '2' || autoVal === '3') { - display_mode_el.value = 'inline'; - display_mode_el.disabled = true; - browser.storage.sync.set({ translate_display_mode: 'inline' }); - } else if (autoVal === '0') { - display_mode_el.disabled = true; - } else { - display_mode_el.disabled = false; - } -} - function saveOptions(e) { e.preventDefault(); let options = {}; @@ -191,9 +174,6 @@ async function restoreOptions() { if (element.id === 'translate_auto') { default_select_value = prefs_default.translate_auto; } - if (element.id === 'translate_display_mode') { - default_select_value = prefs_default.translate_display_mode; - } const restoreValue = result[element.id] ?? default_select_value; let optionExists = Array.from(element.options).some(opt => opt.value === String(restoreValue)); if (element.tomselect) { @@ -248,5 +228,4 @@ async function restoreOptions() { } setCurrentChoice(getting); - updateDisplayModeConstraint(); }