translate_display_mode and translate_max_display_length added. see #247
This commit is contained in:
parent
32abc00693
commit
ef7483031d
11 changed files with 270 additions and 53 deletions
|
|
@ -239,6 +239,10 @@
|
|||
"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": ""
|
||||
|
|
@ -1957,18 +1961,6 @@
|
|||
"message": "Auto-summarize messages",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_auto_disabled": {
|
||||
"message": "Disabled",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_auto_manual": {
|
||||
"message": "Show summary button",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_auto_automatic": {
|
||||
"message": "Generate automatically",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_auto_Info": {
|
||||
"message": "Choose whether to automatically generate summaries when viewing messages. Requires an API-based connection (not ChatGPT Web).",
|
||||
"description": ""
|
||||
|
|
@ -1977,14 +1969,6 @@
|
|||
"message": "Display summary in",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_display_mode_inline": {
|
||||
"message": "Message pane (inline)",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_display_mode_webchat": {
|
||||
"message": "Chat window",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_summarize_display_mode_Info": {
|
||||
"message": "Choose where the summary result is displayed. Inline mode shows a summary banner directly in the message pane. Chat window mode opens the AI chat window.",
|
||||
"description": ""
|
||||
|
|
@ -2085,15 +2069,15 @@
|
|||
"message": "Auto-translate messages",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_translate_auto_disabled": {
|
||||
"prefs_OptionText_action_auto_disabled": {
|
||||
"message": "Disabled",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_translate_auto_manual": {
|
||||
"prefs_OptionText_action_auto_manual": {
|
||||
"message": "Manual button only",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_translate_auto_automatic": {
|
||||
"prefs_OptionText_action_auto_automatic": {
|
||||
"message": "Automatic",
|
||||
"description": ""
|
||||
},
|
||||
|
|
@ -2101,6 +2085,38 @@
|
|||
"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": ""
|
||||
},
|
||||
"prefs_OptionText_display_mode_webchat": {
|
||||
"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": ""
|
||||
},
|
||||
"prefs_OptionText_translate_max_display_length_Info": {
|
||||
"message": "Maximum number of characters shown in the inline translation. 0 = no limit. When set, longer text is truncated with a \"See more\" toggle.",
|
||||
"description": ""
|
||||
},
|
||||
"translate_see_more": {
|
||||
"message": "See more",
|
||||
"description": ""
|
||||
},
|
||||
"translate_see_less": {
|
||||
"message": "See less",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_translate_lang": {
|
||||
"message": "Translation target language",
|
||||
"description": ""
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ class MessagesArea extends HTMLElement {
|
|||
}
|
||||
|
||||
// Save as Summary button (only shown for summary webchat sessions)
|
||||
if(promptData.prompt_info?.headerMessageId) {
|
||||
if(promptData.prompt_info?.headerMessageId && promptData.prompt_info?.summaryTabId) {
|
||||
const saveSummaryButton = document.createElement('button');
|
||||
saveSummaryButton.textContent = browser.i18n.getMessage("webchat_save_as_summary");
|
||||
saveSummaryButton.classList.add('action_btn');
|
||||
|
|
@ -481,6 +481,29 @@ 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');
|
||||
|
|
|
|||
|
|
@ -80,11 +80,13 @@ mzta-background.js (checks summarize_auto + summarize_display_mode prefs)
|
|||
|
||||
### Data Flow: Inline Translation on Message Display
|
||||
|
||||
The `translate_auto` preference controls when translation is triggered. Unlike summarize, translation has no `display_mode` option (always inline).
|
||||
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 = 0` (disabled) → do nothing
|
||||
- `translate_auto = 1` (manual button) → show "Get AI Translation" button in message body
|
||||
- `translate_auto = 2` (automatic) → generate translation immediately on message open
|
||||
- `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 target language is determined by `translate_lang` (fallback on `default_chatgpt_lang`).
|
||||
|
||||
|
|
@ -93,14 +95,16 @@ User opens/selects a message in Thunderbird
|
|||
↓
|
||||
mzta-compose-script.js (sends "initTranslation" to background)
|
||||
↓
|
||||
mzta-background.js (checks translate + translate_auto prefs)
|
||||
mzta-background.js (checks translate + translate_auto + translate_display_mode 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)│
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓ (if generating)
|
||||
↓ (if generating inline)
|
||||
taTranslationStore (check cache / set processing)
|
||||
↓ (cache miss)
|
||||
mzta-special-commands (via Web Worker, NOT chatgpt_web)
|
||||
|
|
|
|||
|
|
@ -88,14 +88,16 @@ 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 inline translation in the message body. Unlike summarize, it has no context menu entry and no webchat mode.
|
||||
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.
|
||||
|
||||
**Inline Translation on Message Display** (controlled by `translate_auto` pref):
|
||||
**Inline Translation on Message Display** (controlled by `translate_auto` and `translate_display_mode` prefs):
|
||||
- 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 + "\""`
|
||||
- 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)
|
||||
- Result is rendered as a styled banner (green/teal theme) in the message body via `mzta-compose-script.js`
|
||||
- `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`
|
||||
- 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)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ 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) |
|
||||
| `translate_display_mode` | `'inline'` | Where to display translations: `'inline'` = message pane banner, `'webchat'` = AI chat window. Note: `translate_auto = 2` always uses 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. |
|
||||
|
||||
### Summarize Settings Page (`pages/summarize/`)
|
||||
|
|
@ -132,10 +134,13 @@ 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. **Target language** (`translate_lang`) — text input for the destination language. If empty, falls back to `default_chatgpt_lang`.
|
||||
4. **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`.
|
||||
|
||||
Unlike summarize, translation has no `display_mode` option (always inline) and no max display length setting.
|
||||
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`.
|
||||
|
||||
## Adding a New Preference
|
||||
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,9 @@ switch (message.command) {
|
|||
translationHeader.appendChild(translationMenu);
|
||||
translationContainer.appendChild(translationHeader);
|
||||
|
||||
const translationTextWrapper = document.createElement('div');
|
||||
translationTextWrapper.style.cssText = 'flex-grow: 1;';
|
||||
|
||||
const translationText = document.createElement('div');
|
||||
translationText.style.cssText = 'white-space: pre-wrap; line-height: 1.5;';
|
||||
if (translationData.error) {
|
||||
|
|
@ -1265,7 +1268,60 @@ switch (message.command) {
|
|||
} else {
|
||||
translationText.textContent = translationData.translated_text || '';
|
||||
}
|
||||
translationContainer.appendChild(translationText);
|
||||
translationTextWrapper.appendChild(translationText);
|
||||
|
||||
// Expand/collapse for long translations
|
||||
const maxLenTranslation = translationData.maxDisplayLength || 0;
|
||||
const fullTranslationText = translationData.translated_text || '';
|
||||
if (!translationData.error && maxLenTranslation > 0 && fullTranslationText.length > maxLenTranslation) {
|
||||
translationText.style.overflow = 'hidden';
|
||||
translationText.style.transition = 'max-height 0.2s ease';
|
||||
|
||||
let cutPos = fullTranslationText.lastIndexOf(' ', maxLenTranslation);
|
||||
if (cutPos <= 0) cutPos = maxLenTranslation;
|
||||
const truncatedTranslation = fullTranslationText.substring(0, cutPos) + '\u2026';
|
||||
translationText.textContent = truncatedTranslation;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const collapsedHeight = translationText.scrollHeight;
|
||||
translationText.style.maxHeight = collapsedHeight + 'px';
|
||||
});
|
||||
|
||||
const toggleLinkTranslation = document.createElement('a');
|
||||
toggleLinkTranslation.textContent = browser.i18n.getMessage("translate_see_more") || "See more";
|
||||
toggleLinkTranslation.href = '#';
|
||||
toggleLinkTranslation.style.cssText = 'display: inline-block; margin-top: 4px; font-size: 13px; color: ' +
|
||||
(isDarkTranslation ? '#6db3f2' : '#1a5fa8') + '; cursor: pointer; text-decoration: underline;';
|
||||
|
||||
let expandedTranslation = false;
|
||||
toggleLinkTranslation.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
if (!expandedTranslation) {
|
||||
translationText.textContent = fullTranslationText;
|
||||
const fullHeight = translationText.scrollHeight;
|
||||
translationText.style.maxHeight = fullHeight + 'px';
|
||||
toggleLinkTranslation.textContent = browser.i18n.getMessage("translate_see_less") || "See less";
|
||||
} else {
|
||||
translationText.textContent = truncatedTranslation;
|
||||
const collapsedHeight = translationText.scrollHeight;
|
||||
translationText.textContent = fullTranslationText;
|
||||
translationText.style.maxHeight = translationText.scrollHeight + 'px';
|
||||
requestAnimationFrame(() => {
|
||||
translationText.style.maxHeight = collapsedHeight + 'px';
|
||||
});
|
||||
translationText.addEventListener('transitionend', function handler() {
|
||||
translationText.removeEventListener('transitionend', handler);
|
||||
translationText.textContent = truncatedTranslation;
|
||||
});
|
||||
toggleLinkTranslation.textContent = browser.i18n.getMessage("translate_see_more") || "See more";
|
||||
}
|
||||
expandedTranslation = !expandedTranslation;
|
||||
});
|
||||
|
||||
translationTextWrapper.appendChild(toggleLinkTranslation);
|
||||
}
|
||||
|
||||
translationContainer.appendChild(translationTextWrapper);
|
||||
|
||||
const summaryBannerForTranslation = document.getElementById('mzta-summary-banner') || document.getElementById('mzta-summary-generating');
|
||||
const spamBannerForTranslation = document.getElementById('mzta-spam-report-banner') || document.getElementById('mzta-spam-check-progress');
|
||||
|
|
@ -1368,7 +1424,7 @@ switch (message.command) {
|
|||
const wrapper = document.getElementById('mzta-translation-trigger-wrapper');
|
||||
if (wrapper) wrapper.remove(); else translationTriggerBtn.remove();
|
||||
browser.runtime.sendMessage({
|
||||
command: "triggerTranslationGeneration",
|
||||
command: message.webchat ? "triggerTranslationWebchat" : "triggerTranslationGeneration",
|
||||
headerMessageId: message.headerMessageId
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -334,16 +334,17 @@ 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 });
|
||||
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 });
|
||||
|
||||
if (!prefs.translate) return;
|
||||
|
||||
let message = await browser.messageDisplay.getDisplayedMessage(tabId);
|
||||
if (!message) return;
|
||||
|
||||
// Always show cached translation if available, regardless of translate_auto
|
||||
let cachedTranslation = await translationStore.loadTranslation(message.headerMessageId);
|
||||
if (cachedTranslation && !cachedTranslation.error) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...cachedTranslation } });
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...cachedTranslation, maxDisplayLength: prefs.translate_max_display_length } });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -352,15 +353,21 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// If translate_auto is disabled, don't show button or auto-generate
|
||||
if (prefs.translate_auto === 0) return;
|
||||
|
||||
// Auto mode (translate_auto === 2) always generates inline
|
||||
if (prefs.translate_auto === 2) {
|
||||
_generateTranslationForMessage(message.headerMessageId, tabId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 });
|
||||
}
|
||||
} catch (e) {
|
||||
taLog.error("Error in initTranslation: " + e);
|
||||
}
|
||||
|
|
@ -374,17 +381,59 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|||
}
|
||||
_triggerTranslationGeneration(message);
|
||||
break;
|
||||
case 'triggerTranslationWebchat':
|
||||
async function _triggerTranslationWebchat(message) {
|
||||
let tabId = sender.tab.id;
|
||||
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);
|
||||
}
|
||||
}
|
||||
_refreshTranslation(message);
|
||||
break;
|
||||
case 'removeTranslation':
|
||||
translationStore.removeTranslation(message.headerMessageId);
|
||||
break;
|
||||
case 'chatgpt_saveTranslation':
|
||||
async function _saveTranslationFromWebchat(msg) {
|
||||
try {
|
||||
let translatedText = msg.text.trim();
|
||||
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: translatedText,
|
||||
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});
|
||||
|
|
@ -647,12 +696,13 @@ async function _generateTranslationForMessage(headerMessageId, tabId) {
|
|||
do_debug: prefs_default.do_debug,
|
||||
default_chatgpt_lang: prefs_default.default_chatgpt_lang,
|
||||
translate_lang: prefs_default.translate_lang,
|
||||
translate_max_display_length: prefs_default.translate_max_display_length,
|
||||
...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])
|
||||
});
|
||||
|
||||
let cachedTranslation = await translationStore.loadTranslation(headerMessageId);
|
||||
if (cachedTranslation && !cachedTranslation.error) {
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...cachedTranslation } });
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...cachedTranslation, maxDisplayLength: prefs.translate_max_display_length } });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +754,7 @@ async function _generateTranslationForMessage(headerMessageId, tabId) {
|
|||
headerMessageId: headerMessageId
|
||||
};
|
||||
await translationStore.saveTranslation(translationData, headerMessageId);
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...translationData } });
|
||||
browser.tabs.sendMessage(tabId, { command: "showTranslation", data: { ...translationData, maxDisplayLength: prefs.translate_max_display_length } });
|
||||
taWorkingStatus.stopWorking();
|
||||
|
||||
} catch (error) {
|
||||
|
|
@ -862,6 +912,41 @@ 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 || '';
|
||||
const { promptText, promptInfo } = await taPromptUtils.buildTranslationPrompt(curr_message_full, lang);
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ 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
|
||||
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
|
||||
spamfilter_show_msg_panel: true,
|
||||
...generated_prefs
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@
|
|||
<td>
|
||||
<label>
|
||||
<select id="summarize_auto" name="summarize_auto" class="option-input">
|
||||
<option value="0">__MSG_prefs_OptionText_summarize_auto_disabled__</option>
|
||||
<option value="1">__MSG_prefs_OptionText_summarize_auto_manual__</option>
|
||||
<option value="2">__MSG_prefs_OptionText_summarize_auto_automatic__</option>
|
||||
<option value="0">__MSG_prefs_OptionText_action_auto_disabled__</option>
|
||||
<option value="1">__MSG_prefs_OptionText_action_auto_manual__</option>
|
||||
<option value="2">__MSG_prefs_OptionText_action_auto_automatic__</option>
|
||||
</select>
|
||||
<br>__MSG_prefs_OptionText_summarize_auto_Info__
|
||||
</label>
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
<td>
|
||||
<label>
|
||||
<select id="summarize_display_mode" name="summarize_display_mode" class="option-input">
|
||||
<option value="inline">__MSG_prefs_OptionText_summarize_display_mode_inline__</option>
|
||||
<option value="webchat">__MSG_prefs_OptionText_summarize_display_mode_webchat__</option>
|
||||
<option value="inline">__MSG_prefs_OptionText_display_mode_inline__</option>
|
||||
<option value="webchat">__MSG_prefs_OptionText_display_mode_webchat__</option>
|
||||
</select>
|
||||
<br>__MSG_prefs_OptionText_summarize_display_mode_Info__
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -31,14 +31,35 @@
|
|||
<td>
|
||||
<label>
|
||||
<select id="translate_auto" name="translate_auto" class="option-input">
|
||||
<option value="0">__MSG_prefs_OptionText_translate_auto_disabled__</option>
|
||||
<option value="1">__MSG_prefs_OptionText_translate_auto_manual__</option>
|
||||
<option value="2">__MSG_prefs_OptionText_translate_auto_automatic__</option>
|
||||
<option value="0">__MSG_prefs_OptionText_action_auto_disabled__</option>
|
||||
<option value="1">__MSG_prefs_OptionText_action_auto_manual__</option>
|
||||
<option value="2">__MSG_prefs_OptionText_action_auto_automatic__</option>
|
||||
</select>
|
||||
<br>__MSG_prefs_OptionText_translate_auto_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="translate_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_translate_display_mode__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<select id="translate_display_mode" name="translate_display_mode" class="option-input">
|
||||
<option value="inline">__MSG_prefs_OptionText_display_mode_inline__</option>
|
||||
<option value="webchat">__MSG_prefs_OptionText_display_mode_webchat__</option>
|
||||
</select>
|
||||
<br>__MSG_prefs_OptionText_translate_display_mode_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="translate_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_translate_max_display_length__</span></td>
|
||||
<td>
|
||||
<label>
|
||||
<input type="number" id="translate_max_display_length" name="translate_max_display_length" min="0" class="option-input" />
|
||||
<br>__MSG_prefs_OptionText_translate_max_display_length_Info__
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="translate_tr">
|
||||
<td><span class="opt_title">__MSG_prefs_OptionText_translate_lang__</span></td>
|
||||
<td>
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ 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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue