V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  miraku  ›  全部回复第 1 页 / 共 2 页
回复总数  39
1  2  
3 天前
回复了 zeyangstudies 创建的主题 分享发现 不用赴港申请 Wise 香港账户
ajU0MDU0NDUyN0BnbWFpbC5jb20=
PRO-XHZHQRFUAM7NYP7WOXASDPIMFCCAB-9N 已用
坏了, 没护照
11 天前
回复了 6581 创建的主题 互联网 有问题问医生
#4 道理我都懂,痔疮吃维生素 B 能不能展开讲讲,他 @RonLuo 有一个朋友爱听
17 天前
回复了 poic 创建的主题 问与答 心盲症能通过后天锻炼看到图像吗?
@wangyaominde #113 我发现我想的那个目标会不清楚(五角星的图 4), 或者要像上面说的三角形要一笔一笔画, 但是附带的目标感觉很清楚, 例如想象家里白色的路由器, 那旁边的黑色路由器和蓝色小盒子感觉很清楚, 但是白色的那个就会很模糊 https://i.imgur.com/krir4IG.png , 想象黑色路由器和蓝色小盒子, 白色路由器又会变清楚, 黑色路由器和蓝色小盒子就变模糊了
17 天前
回复了 poic 创建的主题 问与答 心盲症能通过后天锻炼看到图像吗?
为什么我想象个三角形还得在想象里一笔一笔的画, 不能直接想出来...
18 天前
回复了 Rust2015 创建的主题 Google Google AI 搜索,怎么不见了:
好像现在不用邀请码了?
25 天前
回复了 mobinf 创建的主题 推广 [送会员] 播面 App--面试版小宇宙终于上线啦~
1. 安卓 app 怎么样了
2. 能不能增加 ai 相关的
3. 网页播放声音有点小(手机, 地铁上听不清)
26 天前
回复了 jimyan 创建的主题 新手求助 v2ex 如何修改用户名?
是不是没有 50 银币就没这个按钮
bWlyYWt5dXhf
@Cavalon #2 没错, 3 年零 2 个月的时候我电池寄了
33 天前
回复了 ganguanglong 创建的主题 远程工作 [兼职远程] 招兼职远程开发工程师
38 天前
回复了 JuicyJ 创建的主题 汽车 淘宝上号称原厂的汽车零配件靠谱吗
其实我是秦始皇----只能说有, 但很多都不是
@cat9life #5 好奇大家都用的什么啊
@BeforeTooLate #10 支付成功的页面下就有个地方点进去解约的, 这东西也不能说恶心吧, 只能说不细心
@Lowlife #1 是的, 我十几个闹钟也能不准
https://i.imgur.com/nfyrjhn.png
整页翻译有点慢
```javascript
// ==UserScript==
// @name 网页翻译 + 划词翻译气泡( Translator API )
// @namespace http://tampermonkey.net/
// @version 0.3
// @description 使用浏览器内置 Translator API 翻译网页或选中文本,并缓存语言设置(默认 英→中)
// @author mirakyux
// @match *://*/*
// @grant none
// @run-at document_idle
// ==/UserScript==

(async function() {
'use strict';

// ======== 配置与缓存 ========
const cacheKey = 'translator_langs';
const saved = JSON.parse(localStorage.getItem(cacheKey) || '{}');
let sourceLang = saved.sourceLang || 'en';
let targetLang = saved.targetLang || 'zh';

function saveLang() {
localStorage.setItem(cacheKey, JSON.stringify({ sourceLang, targetLang }));
}

// ======== 样式 ========
function style(el, css) {
Object.assign(el.style, css);
}

// ======== 悬浮按钮(整页) ========
const pageBtn = document.createElement('button');
pageBtn.textContent = '🌐 翻译网页';
style(pageBtn, {
position: 'fixed',
bottom: '20px',
right: '20px',
zIndex: 9999,
padding: '10px 16px',
backgroundColor: '#007bff',
color: '#fff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
fontSize: '14px',
opacity: '0.85',
transition: 'opacity 0.3s'
});
pageBtn.onmouseenter = () => (pageBtn.style.opacity = '1');
pageBtn.onmouseleave = () => (pageBtn.style.opacity = '0.85');
document.body.appendChild(pageBtn);

// ======== 检测 Translator API ========
async function isTranslatorAvailable() {
if (!('Translator' in self)) {
console.error('❌ 当前浏览器不支持 Translator API 。请启用 chrome://flags/#translation-api');
return false;
}
try {
const avail = await self.Translator.availability({
sourceLanguage: sourceLang,
targetLanguage: targetLang
});
if (avail === 'unavailable') {
console.error(`❌ 不支持语言对 ${sourceLang} → ${targetLang}`);
return false;
}
console.log(`✅ Translator API 可用 (${avail})`);
return true;
} catch (err) {
console.error('❌ Translator API 检测失败:', err);
return false;
}
}

async function createTranslator() {
return await self.Translator.create({
sourceLanguage: sourceLang,
targetLanguage: targetLang
});
}

// ======== 整页翻译逻辑 ========
async function translatePage() {
const available = await isTranslatorAvailable();
if (!available) {
alert('当前浏览器不支持内置翻译 API ,请查看控制台提示。');
return;
}
pageBtn.disabled = true;
pageBtn.textContent = '翻译中…';
const translator = await createTranslator();

const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
acceptNode: (node) => {
if (!node.nodeValue.trim()) return NodeFilter.FILTER_REJECT;
if (node.parentElement && ['SCRIPT', 'STYLE', 'NOSCRIPT'].includes(node.parentElement.tagName))
return NodeFilter.FILTER_REJECT;
return NodeFilter.FILTER_ACCEPT;
}
});

const textNodes = [];
while (walker.nextNode()) textNodes.push(walker.currentNode);

for (const node of textNodes) {
const text = node.nodeValue.trim();
if (!text || text.length > 2000) continue;
try {
const translated = await translator.translate(text);
node.nodeValue = translated;
} catch (err) {
console.warn('跳过节点:', err);
}
}

pageBtn.textContent = '✅ 已翻译';
setTimeout(() => {
pageBtn.textContent = '🌐 翻译网页';
pageBtn.disabled = false;
}, 3000);
}

pageBtn.addEventListener('click', translatePage);

// ======== 划词翻译气泡 ========
const bubble = document.createElement('div');
style(bubble, {
position: 'absolute',
background: '#007bff',
color: '#fff',
padding: '6px 10px',
borderRadius: '6px',
fontSize: '13px',
cursor: 'pointer',
display: 'none',
zIndex: 99999,
userSelect: 'none',
whiteSpace: 'nowrap',
boxShadow: '0 2px 6px rgba(0,0,0,0.3)'
});
bubble.textContent = '翻译';
document.body.appendChild(bubble);

let currentSelection = '';
document.addEventListener('selectionchange', () => {
const sel = window.getSelection();
const text = sel.toString().trim();
if (text.length > 0) {
const range = sel.getRangeAt(0);
const rect = range.getBoundingClientRect();
bubble.style.left = `${rect.right + window.scrollX + 10}px`;
bubble.style.top = `${rect.top + window.scrollY - 10}px`;
bubble.style.display = 'block';
currentSelection = text;
} else {
bubble.style.display = 'none';
}
});

bubble.addEventListener('click', async () => {
if (!currentSelection) return;
const available = await isTranslatorAvailable();
if (!available) return alert('当前浏览器不支持 Translator API');
const translator = await createTranslator();
bubble.textContent = '翻译中…';
try {
const translated = await translator.translate(currentSelection);
alert(` [${sourceLang} → ${targetLang}] \n\n${translated}`);
} catch (e) {
alert('翻译失败:' + e.message);
} finally {
bubble.textContent = '翻译';
bubble.style.display = 'none';
}
});

// ======== 设置按钮 ========
const configBtn = document.createElement('button');
configBtn.textContent = '⚙️ 设置';
style(configBtn, {
position: 'fixed',
bottom: '60px',
right: '20px',
zIndex: 9999,
padding: '8px 12px',
backgroundColor: '#28a745',
color: '#fff',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontSize: '13px',
opacity: '0.85'
});
configBtn.onmouseenter = () => (configBtn.style.opacity = '1');
configBtn.onmouseleave = () => (configBtn.style.opacity = '0.85');
document.body.appendChild(configBtn);

configBtn.addEventListener('click', async () => {
const src = prompt('源语言(如 en, zh, ja ):', sourceLang);
const tgt = prompt('目标语言(如 zh, en, ko ):', targetLang);
if (src && tgt) {
sourceLang = src;
targetLang = tgt;
saveLang();
alert(`语言设置已保存:${sourceLang} → ${targetLang}`);
}
});
})();

```
1  2  
关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   5824 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 33ms · UTC 06:15 · PVG 14:15 · LAX 22:15 · JFK 01:15
♥ Do have faith in what you're doing.