Telegram 输入框翻译并发送 (v3.9.1 - Gemini模型中文语优化)

v3.1.2基础: 更换模型为Gemini, 更新翻译提示词以更好地处理缅甸语和格式要求, 区分标准和缩写模式的处理流程。

// ==UserScript==
// @name         Telegram 输入框翻译并发送 (v3.9.1 - Gemini模型中文语优化)
// @namespace    http://tampermonkey.net/
// @version      3.9.1
// @description  v3.1.2基础: 更换模型为Gemini, 更新翻译提示词以更好地处理缅甸语和格式要求, 区分标准和缩写模式的处理流程。
// @author       Your Name / AI Assistant
// @match        https://web.telegram.org/k/*
// @match        https://web.telegram.org/a/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      api.lhfcb.com
// @icon         https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Telegram_logo.svg/48px-Telegram_logo.svg.png
// ==/UserScript==

(function() {
'use strict';

// --- 配置 ---
const SCRIPT_VERSION = '3.2.0'; // << MODIFIED v3.2.0 >> 脚本版本
const OHMYGPT_API_KEY = "sk-1zm9YotucF60cHkzLgf9fDHHU9qAGAqzwGv4N7cLkJVfl0rU"; // 如有不同,请替换为你的 API Key (如果需要,根据新模型调整)
const OHMYGPT_API_ENDPOINT = "https://api.lhfcb.com/v1/chat/completions"; // 保持不变,假设此端点是代理或支持Gemini
const INPUT_TRANSLATE_MODEL = "gemini-2.5-flash-preview-05-20-nothinking"; // << MODIFIED v3.2.0 >> 使用的模型
const MAX_CACHE_SIZE = 100; // 最大缓存条目数
const STORAGE_KEY_AUTOSEND = 'telegramTranslateAutoSendPref'; // 自动发送设置的 localStorage 键名
const STORAGE_KEY_MODE = 'telegramTranslateModePref';     // 翻译模式设置的 localStorage 键名

// --- 翻译模式常量 ---
const MODE_ABBREVIATED = 'abbreviated';
const MODE_STANDARD = 'standard';

// --- << MODIFIED v4.1 >> 翻译提示词 (Parser-Safe Version) ---
// 基础翻译提示词 (用于API调用,缩写模式在此基础上进行脚本后处理)
const TRANSLATION_PROMPT = `
Role: Expert Linguist & Cultural Consultant
Task: Translate the following Chinese text into high-fidelity, natural-sounding American English, adhering to a strict set of principles and rules.

// --- Core Principles for High-Quality Translation ---
// Before executing, internalize these guiding principles for handling Chinese.
1.  Context-First, Anti-Literalism: Chinese is a high-context language. First, understand the complete intent, subtext, and logic of the source text. Your primary goal is to translate this *meaning*, not just the individual words.
2.  Master Sentence Restructuring: Actively transform Chinese sentence structures into idiomatic English.
    *   Topic-Comment -> SVO: Convert phrases like 'zhe jian yifu wo xihuan' (literally "this clothing, I like") into "I like this piece of clothing."
    *   Add Implied Subjects: Chinese often omits subjects. Infer and add them. For example, 'zhi dao le' becomes "I understand" or "Got it."
    *   Bridge Logical Gaps: Chinese uses implicit logic (known as 'yihe'). Add English conjunctions (because, so, while, which) to make the relationship between clauses explicit and clear.
3.  Translate Cultural Nuance, Not Just Words:
    *   Idioms ('chengyu'): Translate the underlying meaning. The idiom 'hua she tian zu' should become "to gild the lily" or "to do something superfluous," not "draw a snake and add feet."
    *   Polite Phrases ('ketaohua'): Translate the social function. 'Xin ku le' is not "you've worked hard"; it's "Thank you for your hard work" or "I appreciate your efforts." 'Mafan ni le' is "Thank you for your help" or "Sorry to bother you."
    *   Formality: Distinguish between the formal 'you' (pinyin: nin) and the casual 'you' (pinyin: ni) by adjusting the English tone (e.g., using "sir/ma'am," more structured sentences vs. a relaxed style).

// --- Strict Execution Rules ---
// After considering the principles above, apply these rules without deviation.
1.  Language Detection: Prioritize translating Chinese text. If mixed with untranslatable content (code, IDs, numbers, proper nouns), translate the Chinese parts and integrate the rest seamlessly into the English sentence.
2.  Formality: Maintain the original text's level of formality or informality as determined by the principles above.
3.  Untranslatable Content: If parts of the input are untranslatable, keep them as they are within the translated sentence structure.
4.  Fully Untranslatable Input: If the entire input is untranslatable (e.g., just numbers, code, already valid English, emojis only), return the original text unmodified.
5.  Punctuation: DO NOT add a period (.) at the end of the translated sentence. However, if the original text ends with a different punctuation mark like a question mark (?) or an exclamation mark (!), you MUST preserve it. Ensure correct spacing.
6.  Output: Return ONLY the final translated text. NO explanations, NO notes, NO apologies, NO introductory phrases like "Here is the translation:". Just the resulting text.

Input Text:
{text_to_translate}
`;



// --- 选择器 (保持不变) ---
const INPUT_SELECTOR = 'div.input-message-input[contenteditable="true"]';
const SEND_BUTTON_SELECTOR = 'button.btn-send';
const INPUT_AREA_CONTAINER_SELECTOR = '.chat-input-main';

// --- UI 元素 ID (保持不变) ---
const STATUS_BAR_ID = 'custom-input-status-bar';
const CONTROLS_CONTAINER_ID = 'custom-input-controls-container';
const AUTO_SEND_TOGGLE_ID = 'custom-auto-send-toggle';
const MODE_SELECTOR_CONTAINER_ID = 'custom-mode-selector';
const MODE_BUTTON_ABBR_ID = 'custom-mode-button-abbr';
const MODE_BUTTON_STD_ID = 'custom-mode-button-std';
const RETRY_BUTTON_ID = 'custom-translate-retry-button';
const RETRY_PROCESSING_BUTTON_ID = 'custom-processing-retry-button';

// --- 语言检测正则 (保持不变) ---
const CHINESE_REGEX = /[\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF]/;
const BURMESE_REGEX = /[\u1000-\u109F]/; // 缅甸语 Unicode 范围

// --- 状态变量 (保持不变) ---
let statusBarElement = null;
let controlsContainerElement = null;
let autoSendToggleElement = null;
let modeSelectorContainerElement = null;
let currentInputApiXhr = null;
let isTranslatingAndSending = false;
let sendButtonClickListenerAttached = false;
let lastOriginalText = null;
const translationCache = new Map();
let justTranslated = false;

// --- 自动发送状态 (保持不变) ---
let autoSendEnabled = true;
const savedAutoSendState = localStorage.getItem(STORAGE_KEY_AUTOSEND);
if (savedAutoSendState !== null) {
    autoSendEnabled = savedAutoSendState === 'true';
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 已加载自动发送偏好: ${autoSendEnabled ? '开启' : '关闭'}`);
} else {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 未找到自动发送偏好,使用默认值: ${autoSendEnabled ? '开启' : '关闭'}`);
}

// --- 翻译模式状态 (保持不变) ---
let currentTranslationMode = MODE_ABBREVIATED; // 默认缩写模式
const savedModeState = localStorage.getItem(STORAGE_KEY_MODE);
if (savedModeState === MODE_STANDARD || savedModeState === MODE_ABBREVIATED) {
    currentTranslationMode = savedModeState;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 已加载翻译模式偏好: ${currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'}`);
} else {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 未找到翻译模式偏好,使用默认值: 缩写`);
}

// --- CSS 样式 (保持不变) ---
GM_addStyle(`
    ${INPUT_AREA_CONTAINER_SELECTOR} { position: relative !important; overflow: visible !important; }
    #${STATUS_BAR_ID} { position: absolute; bottom: 2px; left: 8px; right: 8px; display: none; padding: 4px 8px; font-size: 12px; color: #ccc; background-color: rgba(20, 20, 20, 0.85); backdrop-filter: blur(2px); border-top: 1px solid rgba(255, 255, 255, 0.1); border-radius: 4px; z-index: 149; line-height: 1.3; text-align: left; transition: opacity 0.2s ease-in-out, bottom 0.2s ease-in-out; opacity: 0; pointer-events: none; }
    #${STATUS_BAR_ID}.visible { display: flex; justify-content: space-between; align-items: center; opacity: 1; pointer-events: auto; }
    #${STATUS_BAR_ID} .status-text { flex-grow: 1; margin-right: 8px; }
    #${STATUS_BAR_ID} .status-buttons { display: flex; gap: 5px; flex-shrink: 0; }
    #${STATUS_BAR_ID} .status { font-style: italic; color: #a0a0a0; }
    #${STATUS_BAR_ID} .info { font-style: italic; color: #87cefa; }
    #${STATUS_BAR_ID} .error { font-weight: bold; color: #ff8a8a; }
    #${STATUS_BAR_ID} .success { font-weight: bold; color: #8ade8a; }
    #${RETRY_BUTTON_ID}, #${RETRY_PROCESSING_BUTTON_ID} { padding: 2px 6px; font-size: 11px; font-weight: bold; color: #d0d0d0; background-color: rgba(80, 80, 80, 0.9); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 3px; cursor: pointer; flex-shrink: 0; transition: background-color 0.2s ease, color 0.2s ease; white-space: nowrap; }
    #${RETRY_BUTTON_ID}:hover, #${RETRY_PROCESSING_BUTTON_ID}:hover { background-color: rgba(100, 100, 100, 0.9); color: #fff; }
    #${RETRY_BUTTON_ID}:active, #${RETRY_PROCESSING_BUTTON_ID}:active { background-color: rgba(60, 60, 60, 0.9); }
    #${CONTROLS_CONTAINER_ID} { position: absolute; top: 0; right: 10px; display: flex; align-items: flex-end; gap: 0px; z-index: 151; pointer-events: none; height: 26px; }
    #${MODE_SELECTOR_CONTAINER_ID} { display: flex; margin-right: 5px; pointer-events: auto; border: 1px solid rgba(255, 255, 255, 0.2); border-bottom: none; border-radius: 6px 6px 0 0; overflow: hidden; background-color: rgba(80, 80, 80, 0.9); }
    #${MODE_BUTTON_ABBR_ID}, #${MODE_BUTTON_STD_ID} { padding: 4px 8px; font-size: 12px; font-weight: bold; color: #ccc; background-color: transparent; border: none; cursor: pointer; user-select: none; transition: background-color 0.2s ease, color 0.2s ease; line-height: 16px; height: 24px; box-sizing: border-box; }
    #${MODE_BUTTON_ABBR_ID}.active, #${MODE_BUTTON_STD_ID}.active { background-color: rgba(70, 130, 180, 0.95); color: #fff; }
    #${MODE_BUTTON_ABBR_ID}:hover:not(.active), #${MODE_BUTTON_STD_ID}:hover:not(.active) { background-color: rgba(100, 100, 100, 0.9); }
    #${AUTO_SEND_TOGGLE_ID} { padding: 4px 10px; font-size: 12px; font-weight: bold; background-color: rgba(80, 80, 80, 0.9); color: #ccc; border: 1px solid rgba(255, 255, 255, 0.2); border-bottom: none; border-radius: 6px 6px 0 0; cursor: pointer; user-select: none; transition: background-color 0.2s ease, color 0.2s ease; pointer-events: auto; line-height: 16px; height: 24px; box-sizing: border-box; }
    #${AUTO_SEND_TOGGLE_ID}.autosend-on { background-color: rgba(70, 130, 180, 0.95); color: #fff; }
    #${AUTO_SEND_TOGGLE_ID}:hover { filter: brightness(1.1); }
`);

// --- 辅助函数 (大部分保持不变) ---
function detectLanguage(text) { if (!text) return null; if (BURMESE_REGEX.test(text)) return 'Burmese'; if (CHINESE_REGEX.test(text)) return 'Chinese'; return 'Other'; } // 优先检测缅甸语
function setCursorToEnd(element) { try { const range = document.createRange(); const sel = window.getSelection(); range.selectNodeContents(element); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); element.focus(); } catch (e) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 设置光标时出错:`, e); } }
function ensureControlsExist() {
    const inputMainContainer = document.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
    if (!inputMainContainer) return;
    if (window.getComputedStyle(inputMainContainer).position !== 'relative') { inputMainContainer.style.position = 'relative'; }
    if (!controlsContainerElement || !inputMainContainer.contains(controlsContainerElement)) {
        controlsContainerElement = document.createElement('div');
        controlsContainerElement.id = CONTROLS_CONTAINER_ID;
        inputMainContainer.appendChild(controlsContainerElement);
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 控制按钮容器已创建。`);
    }
    if (!modeSelectorContainerElement || !controlsContainerElement.contains(modeSelectorContainerElement)) {
        modeSelectorContainerElement = document.createElement('div');
        modeSelectorContainerElement.id = MODE_SELECTOR_CONTAINER_ID;
        const abbrButton = document.createElement('button'); abbrButton.id = MODE_BUTTON_ABBR_ID; abbrButton.textContent = '缩写'; abbrButton.type = 'button'; abbrButton.addEventListener('click', () => switchMode(MODE_ABBREVIATED)); modeSelectorContainerElement.appendChild(abbrButton);
        const stdButton = document.createElement('button'); stdButton.id = MODE_BUTTON_STD_ID; stdButton.textContent = '标准'; stdButton.type = 'button'; stdButton.addEventListener('click', () => switchMode(MODE_STANDARD)); modeSelectorContainerElement.appendChild(stdButton);
        controlsContainerElement.insertBefore(modeSelectorContainerElement, controlsContainerElement.firstChild);
        updateModeButtonVisuals();
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 模式选择按钮已创建。`);
    }
    if (!autoSendToggleElement || !controlsContainerElement.contains(autoSendToggleElement)) {
        autoSendToggleElement = document.createElement('button'); autoSendToggleElement.id = AUTO_SEND_TOGGLE_ID; autoSendToggleElement.type = 'button'; autoSendToggleElement.addEventListener('click', toggleAutoSend);
        controlsContainerElement.appendChild(autoSendToggleElement);
        updateAutoSendButtonVisual();
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 自动发送开关按钮已创建。`);
    }
    if (!statusBarElement || !inputMainContainer.contains(statusBarElement)) {
        statusBarElement = document.createElement('div'); statusBarElement.id = STATUS_BAR_ID;
        inputMainContainer.appendChild(statusBarElement);
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 状态栏元素已创建。`);
    }
}
function updateStatusDisplay(content, type = 'status', duration = 0, showRetryButton = false, showRetryProcessingButton = false) {
    ensureControlsExist();
    if (!statusBarElement) { console.error(`[输入翻译 v${SCRIPT_VERSION}] 更新状态时未找到状态栏元素。`); return; }
    let buttonsHtml = '';
    if (showRetryButton && lastOriginalText) { buttonsHtml += `<button id="${RETRY_BUTTON_ID}" type="button">重试原文</button>`; }
    if (showRetryProcessingButton) { buttonsHtml += `<button id="${RETRY_PROCESSING_BUTTON_ID}" type="button">重试处理</button>`; }
    statusBarElement.innerHTML = `<span class="status-text ${type}">${content}</span>${buttonsHtml ? `<div class="status-buttons">${buttonsHtml}</div>` : ''}`;
    statusBarElement.classList.add('visible');
    if (showRetryButton && lastOriginalText) { const retryBtn = statusBarElement.querySelector(`#${RETRY_BUTTON_ID}`); if (retryBtn) retryBtn.addEventListener('click', handleRetryOriginalClick); }
    if (showRetryProcessingButton) { const retryProcBtn = statusBarElement.querySelector(`#${RETRY_PROCESSING_BUTTON_ID}`); if (retryProcBtn) retryProcBtn.addEventListener('click', handleRetryProcessingClick); }
    if (statusBarElement.hideTimeout) clearTimeout(statusBarElement.hideTimeout);
    statusBarElement.hideTimeout = duration > 0 ? setTimeout(hideStatusDisplay, duration) : null;
 }
function hideStatusDisplay() {
    if (statusBarElement) { if (statusBarElement.hideTimeout) clearTimeout(statusBarElement.hideTimeout); statusBarElement.hideTimeout = null; statusBarElement.classList.remove('visible'); setTimeout(() => { if (statusBarElement && !statusBarElement.classList.contains('visible')) { statusBarElement.innerHTML = ''; } }, 250); }
}
// --- << ADDED v3.5 >> 缩写处理函数 (保留Emoji) ---
function performAbbreviationPreservingEmojis(inputElement, textToProcess) {
    // 1. 将表情符号<img>替换为占位符
    const emojiMap = new Map();
    let placeholderIndex = 0;

    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = inputElement.innerHTML;

    // --- FIX v3.5.1 START ---
    // First, find all emoji nodes without modifying the DOM tree during traversal.
    // This prevents the iterator from getting confused when the DOM is changed.
    const emojiNodes = [];
    const walker = document.createTreeWalker(tempDiv, NodeFilter.SHOW_ELEMENT);
    let elementNode;
    while(elementNode = walker.nextNode()) {
        if (elementNode.tagName === 'IMG' && elementNode.classList.contains('emoji')) {
            emojiNodes.push(elementNode);
        }
    }

    // Now, iterate over the collected array of nodes and replace them.
    for (const emojiNode of emojiNodes) {
        const placeholder = `__EMOJI_PLACEHOLDER_${placeholderIndex++}__`;
        emojiMap.set(placeholder, emojiNode.outerHTML);
        const textNode = document.createTextNode(placeholder);
        if (emojiNode.parentNode) {
            emojiNode.parentNode.replaceChild(textNode, emojiNode);
        }
    }
    // --- FIX v3.5.1 END ---

    const textWithPlaceholders = tempDiv.textContent || "";

    // 2. 应用缩写规则
    let abbreviatedText = applyLetterAbbreviations(fixNumberAbbreviations(textWithPlaceholders));

    // 3. 将占位符恢复为表情符号<img>
    // 为避免HTML注入,我们创建一个新div并逐个添加文本和表情节点
    const resultFragment = document.createDocumentFragment();
    let lastIndex = 0;

    const placeholderRegex = /__EMOJI_PLACEHOLDER_\d+__/g;
    let match;
    while ((match = placeholderRegex.exec(abbreviatedText)) !== null) {
        // 添加占位符之前的文本部分
        if (match.index > lastIndex) {
            resultFragment.appendChild(document.createTextNode(abbreviatedText.substring(lastIndex, match.index)));
        }
        // 添加表情符号HTML
        const placeholder = match[0];
        if (emojiMap.has(placeholder)) {
            const emojiHtml = emojiMap.get(placeholder);
            const tempContainer = document.createElement('span');
            tempContainer.innerHTML = emojiHtml;
            resultFragment.appendChild(tempContainer.firstChild);
        }
        lastIndex = match.index + placeholder.length;
    }

    // 添加最后一个占位符之后的剩余文本
    if (lastIndex < abbreviatedText.length) {
        resultFragment.appendChild(document.createTextNode(abbreviatedText.substring(lastIndex)));
    }

    // 4. 更新输入框内容并恢复光标
    inputElement.innerHTML = '';
    inputElement.appendChild(resultFragment);
    setCursorToEnd(inputElement);
    inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
}

// --- << MODIFIED v3.2.0 >> 缩写处理函数 (仅在缩写模式下由脚本调用) ---
function fixNumberAbbreviations(text) {
    if (!text) return text; let originalText = text;
    // 严格应用提示词中提到的规则(示例,保持不变)
    text = text.replace(/\b2\b/gi, "to"); text = text.replace(/\b4\b/gi, "for"); text = text.replace(/\b(be?|b)4\b/gi, "before"); text = text.replace(/\b2day\b/gi, "today"); text = text.replace(/\b2nite\b/gi, "tonight"); text = text.replace(/\b2night\b/gi, "tonight"); text = text.replace(/\b2mrw\b/gi, "tomorrow"); text = text.replace(/\b2moro\b/gi, "tomorrow"); text = text.replace(/\bgr8\b/gi, "great"); text = text.replace(/\bl8r\b/gi, "later"); text = text.replace(/\bw8\b/gi, "wait"); text = text.replace(/\bh8\b/gi, "hate"); text = text.replace(/\bsk8\b/gi, "skate"); text = text.replace(/\bm8\b/gi, "mate");
    if (text !== originalText) { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 应用了数字/组合缩写修正: "${originalText}" -> "${text}"`); } return text;
}
function applyLetterAbbreviations(text) {
    if (!text) return text;
    text = text.replace(/\b[Tt]hank you\b/g, m => m.charAt(0) === 'T' ? 'Thx u' : 'thx u');
    let originalText = text; let modifiedText = text; let initialCapitalizationApplied = false; let changesMade = false;
    // 严格应用提示词中提到的规则 (示例,保持不变)
    const abbrMap = { "you": "u", "your": "ur", "yours": "urs", "yourself": "urself", "are": "r", "thanks": "thx", "thank": "thx", "and": "&", "before": "bfr", "first": "frst", "tomorrow": "tmrw", "next": "nxt" };
    const capitalizeAtStart = ["u", "ur", "urs","r", "thx", "bfr", "frst", "tmrw", "nxt", "urself"];
    // (代码逻辑保持不变, 确保能正确应用缩写)
    let firstWordIndex = -1; let firstWord = ""; let leadingChars = ""; const match = modifiedText.match(/^(\s*[^a-zA-Z\s]*)?([a-zA-Z]+)/);
    if (match) { leadingChars = match[1] || ""; firstWord = match[2]; firstWordIndex = leadingChars.length; const lowerFirstWord = firstWord.toLowerCase();
        if (abbrMap.hasOwnProperty(lowerFirstWord)) { const abbreviation = abbrMap[lowerFirstWord]; let replacementMade = false;
            if (capitalizeAtStart.includes(abbreviation)) { const capitalizedAbbr = abbreviation.charAt(0).toUpperCase() + abbreviation.slice(1); modifiedText = leadingChars + capitalizedAbbr + modifiedText.substring(firstWordIndex + firstWord.length); initialCapitalizationApplied = true; replacementMade = true; }
            else if (abbreviation === '&') { modifiedText = leadingChars + abbreviation + modifiedText.substring(firstWordIndex + firstWord.length); initialCapitalizationApplied = true; replacementMade = true; } // Handle '&' at start
            if (replacementMade) changesMade = true;
        }
    }
    const replaceRemaining = (fullWord, abbr) => { const regexLower = new RegExp(`\\b${fullWord}\\b`, 'g'); const regexUpper = new RegExp(`\\b${fullWord.charAt(0).toUpperCase() + fullWord.slice(1)}\\b`, 'g'); let startIndex = 0; if (initialCapitalizationApplied && firstWord.toLowerCase() === fullWord) { startIndex = firstWordIndex + (abbrMap[fullWord] ? abbrMap[fullWord].length : firstWord.length); } let targetStringPart = modifiedText.substring(startIndex); let prefix = modifiedText.substring(0, startIndex); let replacedPart = targetStringPart; let currentChangesMade = false; const originalLength = replacedPart.length; if (abbr === '&') { replacedPart = replacedPart.replace(/\b[Aa]nd\b/g, '&'); } else { replacedPart = replacedPart.replace(regexLower, abbr); replacedPart = replacedPart.replace(regexUpper, abbr); } if(replacedPart.length !== originalLength || replacedPart !== targetStringPart) currentChangesMade = true; modifiedText = prefix + replacedPart; if (currentChangesMade) changesMade = true; };
    for (const word in abbrMap) { replaceRemaining(word, abbrMap[word]); }
    if (/^\s*&/.test(modifiedText)) {
        modifiedText = modifiedText.replace(/^(\s*)&/, '$1And');
    }
    if (changesMade) { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 应用了字母缩写。\n    输入: "${originalText}"\n    输出: "${modifiedText}"`); } else { console.log(`[输入翻译 v${SCRIPT_VERSION}][缩写后处理] 未应用字母缩写。\n    输入: "${originalText}"`); } return modifiedText;
}
// --- 重试处理函数 (保持不变, 但日志会反映当前模式) ---
function handleRetryOriginalClick(event) {
     event.preventDefault(); event.stopPropagation(); console.log(`[输入翻译 v${SCRIPT_VERSION}] "重试原文"按钮被点击。`); if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 正在处理中,忽略"重试原文"点击。`); return; } if (!lastOriginalText) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 没有存储原文可供重试。`); hideStatusDisplay(); return; } const inputElement = document.querySelector(INPUT_SELECTOR); const sendButton = document.querySelector(SEND_BUTTON_SELECTOR); if (!inputElement || !sendButton) { updateStatusDisplay("重试失败: 界面元素丢失", 'error', 4000, true, true); return; } if (sendButton.disabled) { updateStatusDisplay("重试失败: 发送按钮不可用", 'error', 4000, true, true); return; }
     const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'; // << 获取当前模式文本
     console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在使用 [${currentModeText}] 模式重试原文翻译: "${lastOriginalText}"`);
     translateAndSend(lastOriginalText, inputElement, sendButton, true); // forceApi = true
}
function handleRetryProcessingClick(event) {
    event.preventDefault(); event.stopPropagation(); console.log(`[输入翻译 v${SCRIPT_VERSION}] "重试处理"按钮被点击。`); if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 正在处理中,忽略"重试处理"点击。`); return; } const inputElement = document.querySelector(INPUT_SELECTOR); const sendButton = document.querySelector(SEND_BUTTON_SELECTOR); if (!inputElement || !sendButton) { updateStatusDisplay("重试失败: 界面元素丢失", 'error', 4000, true, true); return; } const currentText = inputElement.textContent?.trim(); if (!currentText) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 输入框为空,无法重试处理。`); hideStatusDisplay(); return; } if (sendButton.disabled) { updateStatusDisplay("重试失败: 发送按钮不可用", 'error', 4000, true, true); return; }
    const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'; // << 获取当前模式文本
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在使用 [${currentModeText}] 模式对当前文本重试处理: "${currentText}"`);
    translateAndSend(currentText, inputElement, sendButton, true); // forceApi = true
}
// --- UI 控制函数 (保持不变) ---
function updateAutoSendButtonVisual() {
    if (!autoSendToggleElement) return; autoSendToggleElement.textContent = autoSendEnabled ? "自动:开" : "自动:关"; autoSendToggleElement.className = autoSendEnabled ? 'autosend-on' : '';
}
function toggleAutoSend() {
    autoSendEnabled = !autoSendEnabled; const statusText = autoSendEnabled ? '开启' : '关闭'; console.log(`[输入翻译 v${SCRIPT_VERSION}] 自动发送切换为: ${statusText}`); updateAutoSendButtonVisual(); updateStatusDisplay(`自动发送已${statusText}`, 'status', 2000); try { localStorage.setItem(STORAGE_KEY_AUTOSEND, autoSendEnabled.toString()); console.log(`[输入翻译 v${SCRIPT_VERSION}] 已将自动发送偏好 (${statusText}) 保存到 localStorage。`); } catch (e) { console.error(`[输入翻译 v${SCRIPT_VERSION}] 保存自动发送偏好到 localStorage 时出错:`, e); updateStatusDisplay("无法保存自动发送设置", 'error', 3000); }
}
function updateModeButtonVisuals() {
    const abbrButton = document.getElementById(MODE_BUTTON_ABBR_ID); const stdButton = document.getElementById(MODE_BUTTON_STD_ID); if (!abbrButton || !stdButton) return; if (currentTranslationMode === MODE_ABBREVIATED) { abbrButton.classList.add('active'); stdButton.classList.remove('active'); } else { abbrButton.classList.remove('active'); stdButton.classList.add('active'); }
}
function switchMode(newMode) {
    if (newMode === currentTranslationMode) return; const oldModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'; currentTranslationMode = newMode; const newModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准'; console.log(`[输入翻译 v${SCRIPT_VERSION}] 翻译模式切换为: ${newModeText}`); updateModeButtonVisuals(); updateStatusDisplay(`模式切换为: ${newModeText}`, 'status', 2000); try { localStorage.setItem(STORAGE_KEY_MODE, currentTranslationMode); console.log(`[输入翻译 v${SCRIPT_VERSION}] 已将翻译模式偏好 (${newModeText}) 保存到 localStorage。`); } catch (e) { console.error(`[输入翻译 v${SCRIPT_VERSION}] 保存翻译模式偏好到 localStorage 时出错:`, e); updateStatusDisplay("无法保存模式设置", 'error', 3000); }
}

// --- << MODIFIED v3.2.0 >> 主要翻译逻辑 (适配新提示词和模式处理) ---
function translateAndSend(textToProcess, inputElement, sendButton, forceApi = false) {
    if (isTranslatingAndSending) { console.warn(`[输入翻译 v${SCRIPT_VERSION}] 已在处理中,忽略新的处理请求。`); return; }
    if (!inputElement || !sendButton) { updateStatusDisplay("错误: 无法找到输入框或发送按钮", 'error', 4000, true, true); return; }
    isTranslatingAndSending = true;
    hideStatusDisplay();
    const detectedLang = detectLanguage(textToProcess);
    const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准';
    // 英文缩写仅模式
    if (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese') {
        // << MODIFIED v3.5 >> 使用新函数处理缩写以保留表情符号
        performAbbreviationPreservingEmojis(inputElement, textToProcess);

        updateStatusDisplay("替换缩写成功", 'success', 2000);
        showInlineStatus(inputElement, '替换缩写成功');
        // 英文缩写模式始终自动发送
        setTimeout(() => {
            justTranslated = true;
            if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                sendButton.click();
            }
            isTranslatingAndSending = false;
            hideStatusDisplay();
        }, 50);
        return;
    }
    if (detectedLang === 'Chinese' || detectedLang === 'Burmese') { lastOriginalText = textToProcess; }

    // --- 缓存检查 ---
    const useCache = !forceApi && (detectedLang === 'Chinese' || detectedLang === 'Burmese');
    // << MODIFIED v3.2.0 >> 缓存键包含模式,因为后处理不同
    const cacheKey = `${currentTranslationMode}::${textToProcess}`;

    if (useCache && translationCache.has(cacheKey)) { // 检查包含模式的缓存键
        const cachedProcessedTranslation = translationCache.get(cacheKey); // 获取已处理过的翻译结果
        console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存命中] 找到原文 "${textToProcess.substring(0,30)}..." 在 [${currentModeText}] 模式下的缓存结果: "${cachedProcessedTranslation}"`);
        updateStatusDisplay(`[${currentModeText}] 已从缓存加载 ✓`, 'info', 3000, false, !autoSendEnabled);

        // 直接使用缓存中已经处理好的文本
        const finalText = cachedProcessedTranslation;

        inputElement.textContent = finalText;
        setCursorToEnd(inputElement);
        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));

        if (autoSendEnabled) {
            const sendDelay = 50;
            console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 自动发送已开启。将在 ${sendDelay}ms 后模拟点击发送。`);
            setTimeout(() => {
                if (!isTranslatingAndSending) {
                    console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][发送超时] 发送已中止 (可能被新操作打断)。`);
                    return;
                }
                if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                     console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 重置状态并尝试发送...`);
                     isTranslatingAndSending = false;
                     justTranslated = false; // 发送后重置
                     sendButton.click();
                     hideStatusDisplay();
                } else {
                     console.error(`[输入翻译 v${SCRIPT_VERSION}][缓存][自动发送] 发送失败,按钮不可用或已消失。`);
                     updateStatusDisplay("发送失败 (按钮不可用?)", 'error', 4000, true, true);
                     isTranslatingAndSending = false;
                }
            }, sendDelay);
        } else {
            console.log(`[输入翻译 v${SCRIPT_VERSION}][缓存] 自动发送已关闭。`);
            updateStatusDisplay(`[${currentModeText}] 处理完成 ✓ (请手动发送)`, 'success', 0, true, true); // 保持状态栏直到用户操作
            isTranslatingAndSending = false;
            justTranslated = true; // 标记为已翻译,等待手动发送
        }
        return; // 缓存命中,结束函数
    }
    // --- 缓存检查结束 ---

    // --- API 调用 ---
    // << MODIFIED v3.2.0 >> 使用统一的基础翻译提示词
    const finalPrompt = TRANSLATION_PROMPT.replace('{text_to_translate}', textToProcess);
    console.log(`[输入翻译 v${SCRIPT_VERSION}] ${forceApi ? '强制 API 调用' : '缓存未命中'}。使用 [${currentModeText}] 模式调用 API (${INPUT_TRANSLATE_MODEL}) 处理: "${textToProcess.substring(0, 30)}..."`);
    updateStatusDisplay(`[${currentModeText}] 翻译处理中...`, 'status');

    // << MODIFIED v3.2.0 >> model 使用新配置
    const requestBody = { model: INPUT_TRANSLATE_MODEL, messages: [{"role": "user", "content": finalPrompt }], temperature: 0.6 }; // Temperature 可以根据模型调整
    if (currentInputApiXhr && typeof currentInputApiXhr.abort === 'function') { currentInputApiXhr.abort(); console.log(`[输入翻译 v${SCRIPT_VERSION}] 中止了之前的 API 请求。`);}

    currentInputApiXhr = GM_xmlhttpRequest({
        method: "POST", url: OHMYGPT_API_ENDPOINT,
        headers: { "Content-Type": "application/json", "Authorization": `Bearer ${OHMYGPT_API_KEY}` },
        data: JSON.stringify(requestBody),
        onload: function(response) {
            currentInputApiXhr = null;
            try {
                if (response.status >= 200 && response.status < 300) {
                    const data = JSON.parse(response.responseText);
                    const rawTranslation = data.choices?.[0]?.message?.content?.trim();
                    if (rawTranslation) {
                        console.log(`[输入翻译 v${SCRIPT_VERSION}][API 成功] 收到原始结果: "${rawTranslation}"`);

                        let finalProcessedText;
                        // << MODIFIED v3.2.0 >> 根据模式进行后处理
                        if (currentTranslationMode === MODE_ABBREVIATED) {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API 后处理] 应用缩写模式处理...`);
                            finalProcessedText = applyLetterAbbreviations(fixNumberAbbreviations(rawTranslation));
                        } else {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API 后处理] 标准模式,直接使用翻译结果。`);
                            finalProcessedText = rawTranslation.trim(); // 提示词已要求不加句号,trim即可
                        }
                        console.log(`[输入翻译 v${SCRIPT_VERSION}][API 处理后] 最终文本: "${finalProcessedText}"`);

                        // << MODIFIED v3.2.0 >> 缓存处理后的结果,使用包含模式的键
                        if (!forceApi && (detectedLang === 'Chinese' || detectedLang === 'Burmese')) {
                             if (translationCache.size >= MAX_CACHE_SIZE) { const oldestKey = translationCache.keys().next().value; translationCache.delete(oldestKey); }
                             translationCache.set(cacheKey, finalProcessedText); // 缓存处理后的结果
                             console.log(`[输入翻译 v${SCRIPT_VERSION}] 已缓存 [${currentModeText}] 模式处理结果: "${textToProcess.substring(0,30)}..." -> "${finalProcessedText}"`);
                        }


                        inputElement.textContent = finalProcessedText;
                        setCursorToEnd(inputElement);
                        inputElement.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));

                        if (autoSendEnabled) {
                            const sendDelay = 150; // API 延迟稍长
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 自动发送已开启。将在 ${sendDelay}ms 后模拟点击发送。`);
                            setTimeout(() => {
                                if (!isTranslatingAndSending) {
                                    console.log(`[输入翻译 v${SCRIPT_VERSION}][API][发送超时] 发送已中止。`);
                                    return;
                                }
                                if (sendButton && sendButton.isConnected && !sendButton.disabled) {
                                    console.log(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 重置状态并尝试发送...`);
                                    isTranslatingAndSending = false;
                                    justTranslated = false; // 发送后重置
                                    sendButton.click();
                                    hideStatusDisplay();
                                } else {
                                    console.error(`[输入翻译 v${SCRIPT_VERSION}][API][自动发送] 发送失败,按钮不可用或已消失。`);
                                    updateStatusDisplay("发送失败 (按钮不可用?)", 'error', 4000, true, true);
                                    isTranslatingAndSending = false;
                                }
                            }, sendDelay);
                        } else {
                            console.log(`[输入翻译 v${SCRIPT_VERSION}][API] 自动发送已关闭。`);
                            updateStatusDisplay(`[${currentModeText}] 处理完成 ✓ (请手动发送)`, 'success', 0, true, true); // 保持状态栏直到用户操作
                            isTranslatingAndSending = false;
                            justTranslated = true; // 标记为已翻译,等待手动发送
                        }
                    } else { throw new Error(`API 返回空内容 (结束原因: ${data.choices?.[0]?.finish_reason || '未知'})`); }
                } else { let errorDetail = `HTTP ${response.status}: ${response.statusText}`; try { const errData = JSON.parse(response.responseText); errorDetail = errData.error?.message || errorDetail; } catch (e) { /* 忽略解析错误 */ } throw new Error(errorDetail); }
            } catch (e) { console.error(`[输入翻译 v${SCRIPT_VERSION}][API 错误] 处理 API 响应时出错:`, e); updateStatusDisplay(`处理失败: ${e.message.substring(0, 60)}`, 'error', 5000, true, true); isTranslatingAndSending = false; }
        },
        onerror: function(response) { currentInputApiXhr = null; console.error(`[输入翻译 v${SCRIPT_VERSION}][网络错误] 请求失败:`, response); updateStatusDisplay(`处理失败: 网络错误 (${response.status || 'N/A'})`, 'error', 5000, true, true); isTranslatingAndSending = false; },
        ontimeout: function() { currentInputApiXhr = null; console.error(`[输入翻译 v${SCRIPT_VERSION}][超时错误] API 请求超时。`); updateStatusDisplay("处理失败: 请求超时", 'error', 5000, true, true); isTranslatingAndSending = false; },
        onabort: function() { currentInputApiXhr = null; console.log(`[输入翻译 v${SCRIPT_VERSION}] API 请求已中止。`); hideStatusDisplay(); isTranslatingAndSending = false; },
        timeout: 45000 // << MODIFIED v3.2.0 >> 稍微增加超时时间以适应潜在较慢的模型
    });
}

// --- 事件监听器 (保持 v3.1.2 修复的手动发送逻辑) ---
function handleInputKeyDown(event) {
    const inputElement = event.target;
    if (!inputElement || !inputElement.matches(INPUT_SELECTOR)) return;

    // 专为手动发送设计:如果刚刚翻译完成(自动发送关闭),第一次回车应该发送消息,而不是触发新的翻译。
    if (event.key === 'Enter' && !event.shiftKey && !event.altKey && !event.ctrlKey && justTranslated) {
        console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 检测到 justTranslated 标志,将直接发送已翻译内容。`);
        event.preventDefault();
        event.stopPropagation();
        const sendButton = document.querySelector(SEND_BUTTON_SELECTOR);
        if (sendButton && !sendButton.disabled) {
            sendButton.click();
        }
        justTranslated = false; // 重置标志
        hideStatusDisplay();
        return;
    }

    // --- 主要回车键逻辑 ---
    if (event.key === 'Enter' && !event.shiftKey && !event.altKey && !event.ctrlKey) {
        // **核心改动:立即阻止默认的回车行为(发送消息或换行)。**
        // 这样,所有的发送逻辑都将由本脚本显式控制。
        event.preventDefault();
        event.stopPropagation();

        // 如果正在翻译或处理中,则忽略本次回车,防止重复触发。
        if (isTranslatingAndSending) {
            console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 正在处理中,已阻止并忽略本次回车。`);
            return;
        }

        const text = inputElement.textContent?.trim() || "";
        const detectedLang = detectLanguage(text);
        const sendButton = document.querySelector(SEND_BUTTON_SELECTOR);

        // 检查发送按钮是否可用
        if (!sendButton || sendButton.disabled) {
            updateStatusDisplay("错误: 发送按钮不可用!", 'error', 5000, true, true);
            console.warn(`[输入翻译 v${SCRIPT_VERSION}][回车] 发送按钮不可用或未找到,操作中止。`);
            return;
        }

        // 判断是否需要翻译或处理
        const needsProcessing = text && (
            (detectedLang === 'Chinese' || detectedLang === 'Burmese') ||
            (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese')
        );

        if (needsProcessing) {
            // 如果文本需要翻译或处理
            const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准';
            console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 检测到 ${detectedLang} 文本。将使用 [${currentModeText}] 模式处理...`);
            translateAndSend(text, inputElement, sendButton); // 调用翻译处理函数
        } else {
            // 如果文本不需要翻译(例如,已经是英文且非缩写模式,或为空)
            console.log(`[输入翻译 v${SCRIPT_VERSION}][回车] 无需翻译的文本 ("${text.substring(0, 30)}...") 或空内容,将直接发送。`);
            hideStatusDisplay(); // 清除可能存在的旧状态
            // 在发送前确保重置 justTranslated 标志
            justTranslated = false;
            sendButton.click(); // 显式点击发送按钮
        }
    }
    // --- 其他按键逻辑 (打断处理) ---
    else if (isTranslatingAndSending && !['Shift', 'Control', 'Alt', 'Meta', 'Enter', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Escape', 'Tab'].includes(event.key)) {
        console.log(`[输入翻译 v${SCRIPT_VERSION}][输入打断] 检测到输入,中止当前处理... (按键: ${event.key})`);
        hideStatusDisplay();
        if (currentInputApiXhr && typeof currentInputApiXhr.abort === 'function') {
            currentInputApiXhr.abort();
        } else {
            isTranslatingAndSending = false;
            console.log(`[输入翻译 v${SCRIPT_VERSION}][输入打断] 已设置 isTranslatingAndSending 为 false。`);
        }
    } else if (!isTranslatingAndSending) {
        // 输入时隐藏非持久性状态
        if (statusBarElement && statusBarElement.classList.contains('visible')) {
            const statusSpan = statusBarElement.querySelector('span.status');
            const errorSpan = statusBarElement.querySelector('span.error');
            const successSpan = statusBarElement.querySelector('span.success');
            const infoSpan = statusBarElement.querySelector('span.info');
            if (statusSpan && !errorSpan && !successSpan && !infoSpan) {
                hideStatusDisplay();
            }
        }
    }
}

function handleSendButtonClick(event) {
    if (justTranslated) {
        console.log(`[输入翻译 v${SCRIPT_VERSION}][发送点击] 检测到 justTranslated 标志,允许默认发送行为。`);
        justTranslated = false;
        hideStatusDisplay();
        return; // 允许默认的点击发送行为
    }
    let sendButton = event.target.closest(SEND_BUTTON_SELECTOR);
    if (!sendButton) {
        const btn = event.target.closest('button');
        if (btn && btn.textContent.trim().toUpperCase() === 'SEND') {
            sendButton = btn;
        }
    }
    if (!sendButton) return;

    // 查找输入元素:优先包含图片的预览容器中的 caption,fallback 到聊天输入框
    let inputElement = null;
    let el = sendButton;
    while (el && el !== document.body) {
        const img = el.querySelector('img');
        const caption = el.querySelector('div[contenteditable="true"]');
        if (img && caption) { inputElement = caption; break; }
        el = el.parentElement;
    }
    if (!inputElement) {
        inputElement = document.querySelector(INPUT_SELECTOR);
    }
    if (!inputElement) return; // 无输入框, 跳过处理
    const text = inputElement.textContent?.trim() || "";
    const detectedLang = detectLanguage(text);

    // 英文缩写模式下直接替换文本,保留默认发送行为
    if (currentTranslationMode === MODE_ABBREVIATED && detectedLang !== 'Chinese' && detectedLang !== 'Burmese' && text) {
        // << MODIFIED v3.5 >> 使用新函数处理缩写以保留表情符号
        performAbbreviationPreservingEmojis(inputElement, text);

        updateStatusDisplay("替换缩写成功", 'success', 2000);
        showInlineStatus(inputElement, '替换缩写成功');
        return; // 保留默认 click 发送
    }
    // 中文或缅甸语时拦截并翻译后发送
    if (text && (detectedLang === 'Chinese' || detectedLang === 'Burmese')) {
        const currentModeText = currentTranslationMode === MODE_ABBREVIATED ? '缩写' : '标准';
        console.log(`[输入翻译 v${SCRIPT_VERSION}][发送点击] 检测到 ${detectedLang} 文本。将使用 [${currentModeText}] 模式处理...`);
        event.preventDefault(); event.stopPropagation();
        if (sendButton.disabled) { updateStatusDisplay("错误: 发送按钮不可用!", 'error', 5000, true, true); return; }
        translateAndSend(text, inputElement, sendButton);
    } else {
        // 其他情况允许默认发送
        if (!isTranslatingAndSending) hideStatusDisplay();
    }
}

// --- 初始化与附加监听器 (保持不变) ---
function initialize() {
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 初始化脚本...`);
    document.body.addEventListener('click', handleSendButtonClick, true);
    const observer = new MutationObserver(mutations => {
        let controlsNeedCheck = false;
        let sendButtonMaybeAppeared = false;
        mutations.forEach(mutation => {
            if (mutation.addedNodes) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType !== 1) return; // 只处理元素节点
                    // 检查容器
                    const containerNode = node.matches(INPUT_AREA_CONTAINER_SELECTOR) ? node : node.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
                    if(containerNode) controlsNeedCheck = true;
                    // 检查输入框
                    const inputElementNode = node.matches(INPUT_SELECTOR) ? node : node.querySelector(INPUT_SELECTOR);
                    if (inputElementNode && !inputElementNode.dataset.customInputTranslateListener) {
                        attachInputListeners(inputElementNode);
                        controlsNeedCheck = true; // 输入框出现也需要检查控件
                    }
                    // 检查发送按钮
                    const sendButtonNode = node.matches(SEND_BUTTON_SELECTOR) ? node : node.querySelector(SEND_BUTTON_SELECTOR);
                    if(sendButtonNode) sendButtonMaybeAppeared = true;
                });
            }
            // 如果容器自身属性变化,也可能需要检查控件
            if (mutation.target && mutation.target.matches && mutation.target.matches(INPUT_AREA_CONTAINER_SELECTOR)) {
                controlsNeedCheck = true;
            }
        });

        if (controlsNeedCheck) {
            // 使用 setTimeout 稍微延迟执行,确保 DOM 结构稳定
            setTimeout(ensureControlsExist, 50);
        }
        if (sendButtonMaybeAppeared || !sendButtonClickListenerAttached) {
             const sendButton = document.querySelector(SEND_BUTTON_SELECTOR);
             if (sendButton && !sendButton.dataset.customSendClickListener) {
                 attachSendButtonListener(sendButton);
             }
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    // 初始检查,以防页面加载时元素已存在
    setTimeout(() => {
        const initialContainer = document.querySelector(INPUT_AREA_CONTAINER_SELECTOR);
        if (initialContainer) { ensureControlsExist(); }
        const initialInputElement = document.querySelector(INPUT_SELECTOR);
        if (initialInputElement && !initialInputElement.dataset.customInputTranslateListener) {
            attachInputListeners(initialInputElement);
        }
        const initialSendButton = document.querySelector(SEND_BUTTON_SELECTOR);
        if(initialSendButton && !initialSendButton.dataset.customSendClickListener) {
            attachSendButtonListener(initialSendButton);
        }
        console.log(`[输入翻译 v${SCRIPT_VERSION}] 初始检查完成,观察者已激活。`);
    }, 1800); // 延迟启动,等待 Telegram Web 加载
}

function attachInputListeners(inputElement) {
     if (inputElement.dataset.customInputTranslateListener) return;
     console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在附加 Keydown 监听器到输入框:`, inputElement);
     inputElement.addEventListener('keydown', handleInputKeyDown, true); // 使用捕获阶段确保优先处理
     inputElement.dataset.customInputTranslateListener = 'true';
     ensureControlsExist(); // 确保控件也存在
}

function attachSendButtonListener(sendButton) {
    if (sendButton.dataset.customSendClickListener) return;
    console.log(`[输入翻译 v${SCRIPT_VERSION}] 正在附加 Click 监听器到发送按钮:`, sendButton);
    sendButton.addEventListener('click', handleSendButtonClick, true); // 使用捕获阶段确保优先处理
    sendButton.dataset.customSendClickListener = 'true';
    sendButtonClickListenerAttached = true; // 标记已附加监听器

    // 添加一个观察器来检测按钮是否从 DOM 中移除(例如切换聊天时)
    const buttonObserver = new MutationObserver(() => {
        if (!sendButton.isConnected) {
            console.log(`[输入翻译 v${SCRIPT_VERSION}] 发送按钮已从 DOM 移除。重置监听器标志。`);
            buttonObserver.disconnect();
            // 清理标志位和属性,以便下次能重新附加
            if (sendButton.dataset.customSendClickListener) {
                 delete sendButton.dataset.customSendClickListener;
            }
            sendButtonClickListenerAttached = false;
        }
    });
    // 观察按钮的父节点,检测子节点变化
    if (sendButton.parentNode) {
        buttonObserver.observe(sendButton.parentNode, { childList: true, subtree: false });
    } else {
         console.warn(`[输入翻译 v${SCRIPT_VERSION}] 未找到发送按钮的父节点用于观察器。`);
    }

}

// --- 启动初始化 (保持不变) ---
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initialize);
} else {
    initialize();
}

function showInlineStatus(el, msg, duration=2000) {
    const parent = el.parentElement;
    if (!parent) return;
    parent.style.position = parent.style.position || 'relative';
    const tip = document.createElement('div');
    tip.textContent = msg;
    tip.style.cssText = 'position:absolute;top:-24px;right:0;padding:4px 8px;background:rgba(0,0,0,0.7);color:#fff;border-radius:4px;font-size:12px;z-index:500;';
    parent.appendChild(tip);
    setTimeout(() => { if (tip && tip.parentElement) tip.parentElement.removeChild(tip); }, duration);
}

})();