<style> :root { --trans-primary: #49b1f5; --trans-glass-bg: rgba(255, 255, 255, 0.7); --trans-glass-border: 1px solid rgba(255, 255, 255, 0.6); --trans-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15); --trans-text: #333; --trans-radius: 12px; }
[data-theme="dark"] { --trans-glass-bg: rgba(30, 30, 30, 0.6); --trans-glass-border: 1px solid rgba(255, 255, 255, 0.1); --trans-text: #e0e0e0; --trans-primary: #52a7e0; }
.trans-container { max-width: 1000px; margin: 2rem auto; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
.trans-header { display: flex; justify-content: center; align-items: center; gap: 15px; margin-bottom: 20px; padding: 15px; background: var(--trans-glass-bg); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border-radius: var(--trans-radius); border: var(--trans-glass-border); box-shadow: var(--trans-shadow); }
.trans-select { padding: 8px 16px; border-radius: 8px; border: 1px solid rgba(128, 128, 128, 0.3); background: rgba(255, 255, 255, 0.5); color: var(--trans-text); font-size: 15px; outline: none; cursor: pointer; transition: all 0.3s; } [data-theme="dark"] .trans-select { background: rgba(0, 0, 0, 0.3); } [data-theme="dark"] .trans-select option { background: #333; }
.trans-swap-btn { width: 36px; height: 36px; border-radius: 50%; border: 1px solid rgba(128, 128, 128, 0.2); background: rgba(255, 255, 255, 0.5); color: var(--trans-primary); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s; font-size: 18px; } [data-theme="dark"] .trans-swap-btn { background: rgba(255, 255, 255, 0.1); } .trans-swap-btn:hover { transform: rotate(180deg); background: var(--trans-primary); color: white; }
.trans-body { display: flex; gap: 20px; min-height: 350px; }
.trans-box { flex: 1; display: flex; flex-direction: column; background: var(--trans-glass-bg); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border-radius: var(--trans-radius); border: var(--trans-glass-border); box-shadow: var(--trans-shadow); position: relative; transition: transform 0.2s; } .trans-box:focus-within { border-color: var(--trans-primary); }
.trans-textarea { flex: 1; width: 100%; padding: 20px; border: none; background: transparent; resize: none; outline: none; font-size: 16px; line-height: 1.6; color: var(--trans-text); }
.trans-tools { padding: 10px 15px; display: flex; justify-content: space-between; align-items: center; border-top: 1px solid rgba(128, 128, 128, 0.1); }
.trans-btn-icon { display: flex; align-items: center; gap: 5px; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 13px; color: #888; transition: all 0.2s; background: transparent; border: none; }
.trans-btn-icon:hover { background: rgba(128, 128, 128, 0.1); color: var(--trans-primary); }
.trans-btn-icon.copied { background: #67c23a; color: white; }
.trans-action { margin-top: 25px; text-align: center; }
.trans-btn-main { background: var(--trans-primary); color: white; border: none; padding: 12px 60px; border-radius: 30px; font-size: 18px; font-weight: 600; cursor: pointer; box-shadow: 0 4px 15px rgba(73, 177, 245, 0.4); transition: all 0.3s; }
.trans-btn-main:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(73, 177, 245, 0.6); }
.trans-btn-main:disabled { background: #ccc; cursor: not-allowed; transform: none; box-shadow: none; }
@media (max-width: 768px) { .trans-body { flex-direction: column; } .trans-box { min-height: 200px; } } </style>
<div id="mtran-app" class="trans-container"> <div class="trans-header"> <select id="srcLang" class="trans-select"> <option value="en">英语 (English)</option> <option value="zh">中文 (Chinese)</option> <option value="ja">日语 (Japanese)</option> <option value="ko">韩语 (Korean)</option> <option value="fr">法语 (French)</option> <option value="de">德语 (German)</option> <option value="ru">俄语 (Russian)</option> </select> <button id="swapBtn" class="trans-swap-btn" title="交换语言">⇄</button>
<select id="tgtLang" class="trans-select"> <option value="zh" selected>中文 (Chinese)</option> <option value="en">英语 (English)</option> <option value="ja">日语 (Japanese)</option> <option value="ko">韩语 (Korean)</option> <option value="fr">法语 (French)</option> <option value="de">德语 (German)</option> <option value="ru">俄语 (Russian)</option> </select> </div>
<div class="trans-body"> <div class="trans-box"> <textarea id="inputTxt" class="trans-textarea" placeholder="在此输入内容..."></textarea> <div class="trans-tools"> <span style="font-size: 12px; color: #999;" id="charCount">0 字符</span> <button class="trans-btn-icon" id="clearBtn" title="清空内容"> 🗑️ 清空 </button> </div> </div>
<div class="trans-box"> <textarea id="outputTxt" class="trans-textarea" readonly placeholder="翻译结果显示在这里..."></textarea> <div class="trans-tools"> <span style="font-size: 12px; color: #999;">MTranServer</span> <button class="trans-btn-icon" id="copyBtn" title="复制结果"> 📋 复制 </button> </div> </div> </div>
<div class="trans-action"> <button id="transBtn" class="trans-btn-main">开始翻译</button> </div> </div>
<script>
function initMTran() { const app = document.getElementById('mtran-app'); if (!app) return;
if (app.getAttribute('data-loaded') === 'true') return; app.setAttribute('data-loaded', 'true');
const srcLang = document.getElementById('srcLang'); const tgtLang = document.getElementById('tgtLang'); const inputTxt = document.getElementById('inputTxt'); const outputTxt = document.getElementById('outputTxt'); const transBtn = document.getElementById('transBtn'); const swapBtn = document.getElementById('swapBtn'); const charCount = document.getElementById('charCount'); const clearBtn = document.getElementById('clearBtn'); const copyBtn = document.getElementById('copyBtn');
if(swapBtn) { swapBtn.onclick = () => { const tempLang = srcLang.value; srcLang.value = tgtLang.value; tgtLang.value = tempLang; const tempText = inputTxt.value; inputTxt.value = outputTxt.value; outputTxt.value = tempText; charCount.textContent = `${inputTxt.value.length} 字符`; }; }
if(inputTxt) { inputTxt.oninput = () => { charCount.textContent = `${inputTxt.value.length} 字符`; }; }
if(clearBtn) { clearBtn.onclick = () => { inputTxt.value = ''; outputTxt.value = ''; charCount.textContent = '0 字符'; inputTxt.focus(); }; }
if(copyBtn) { copyBtn.onclick = function() { const text = outputTxt.value; if (!text) return; const btn = this; navigator.clipboard.writeText(text).then(() => { btn.classList.add('copied'); btn.innerHTML = '✅ 已复制'; setTimeout(() => { btn.classList.remove('copied'); btn.innerHTML = '📋 复制'; }, 2000); }).catch(err => { alert('复制失败,请手动复制'); }); }; }
if(transBtn) { transBtn.onclick = async () => { const text = inputTxt.value.trim(); if (!text) { alert('请输入要翻译的内容'); return; }
transBtn.disabled = true; transBtn.textContent = '翻译中...'; inputTxt.disabled = true; outputTxt.value = '正在思考...';
try { const response = await fetch('/api/translate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ q: text, source: srcLang.value, target: tgtLang.value, format: 'text' }) });
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`); const resData = await response.json(); if (resData.data && resData.data.translations) { outputTxt.value = resData.data.translations[0].translatedText; } else { outputTxt.value = '错误: 未能获取翻译结果'; } } catch (error) { console.error(error); outputTxt.value = '连接超时或服务未启动。\n请检查服务器状态。'; } finally { transBtn.disabled = false; transBtn.textContent = '开始翻译'; inputTxt.disabled = false; } }; } }
if (document.readyState === 'complete' || document.readyState === 'interactive') { initMTran(); }
document.addEventListener('DOMContentLoaded', initMTran);
document.addEventListener('pjax:complete', initMTran); </script>
|