前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VS Code 整活:100行代码写一个悬浮翻译插件

VS Code 整活:100行代码写一个悬浮翻译插件

作者头像
前端劝退师
发布2022-04-07 14:01:04
1.7K0
发布2022-04-07 14:01:04
举报
文章被收录于专栏:前端劝退师

前言

要说哪个插件对效率提升最大,可能各有推荐,各有千秋。但我要说对初学者,以及英文有亿点点差的同学来讲:翻译,是日常开发中必不可少的一环。在下找过N个VSCode 翻译插件 发现一个神器:

VSCode 插件:Google Translate Extension

这款插件不像其它要么需访问国外网站,要么强绑定快捷键的憨憨插件,有个最直观的功能:选中悬浮翻译

啊这...也太作弊了吧,编程能力+1s。

因为这两年都在从事VSCode二次/插件 开发,这个功能深得我心,于是想捣腾一下,看看能不能写轮眼学习一番

撒话不说,开干!

1. 代码目录分析

其中代码逻辑都在src目录里。

代码语言:javascript
复制
command.js //全部命令
extension.js //插件入口文件
tranlate.js //翻译工具函数

先从入口文件extension.js出发:

代码语言:javascript
复制
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const command = require('./command')

function activate(context) {
    console.log('Congratulations, your extension "vsc-google-translate" is now active!');

    command.initSetting(context);

    context.subscriptions.push(command.hoverDisposable);
    context.subscriptions.push(command.tranDisposable);
    context.subscriptions.push(command.switchDisposable);
    context.subscriptions.push(command.copyDisposable);
    context.subscriptions.push(command.replaceDisposable);
    context.subscriptions.push(command.canDisposable);
    context.subscriptions.push(command.switchLangDisposable);
    context.subscriptions.push(command.fromLangDisposable);
    context.subscriptions.push(command.settingsDisposable);
}

exports.activate = activate;


function deactivate() {
}

exports.deactivate = deactivate;

可以看到相当整洁,其中我们关注的功能只有hoverDisposabletranDisposable,为了方便阅读,我精简了一遍。从500行减到100行。

2. 源码分析

精简完的入口文件:

代码语言:javascript
复制
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const command = require('./command')

function activate(context) {
    console.log('Congratulations, your extension "vsc-google-translate" is now active!');
    
    command.initSetting(context);

    context.subscriptions.push(command.hoverDisposable);
}

exports.activate = activate;


function deactivate() {
}

exports.deactivate = deactivate;

2.1 初始化配置

代码语言:javascript
复制
// 获取用户状态,防止重复使用
function initSetting(cxt) {
    hoverOpen = cxt.globalState.get('hover') || false;
    langFrom = cxt.globalState.get('fromLang') || 'auto'
    if (!translate.languages.isSupported(langFrom)) langFrom = 'auto';
    cxt.globalState.update('hover', hoverOpen);
}

2.2 编写触发函数

代码语言:javascript
复制
// 向文件类型提供悬停内容的简单方法
let hoverDisposable = vscode.languages.registerHoverProvider({scheme: 'file'}, {
    provideHover: async (document, position, token) => {
        // 获取正在激活的编辑器窗口区域
        let editor = vscode.window.activeTextEditor;
        if (!editor || !hoverOpen) {
            return; // No open text editor
        }

        let length = editor.selections.length;
        for (let i = 0; i < length; i++) {
            let selection = editor.selections[i];
            let line = { 
                begin: Math.min(selection.anchor.line, selection.active.line),
                end: Math.max(selection.anchor.line, selection.active.line)
            }, character = {
                begin: Math.min(selection.anchor.character, selection.active.character),
                end: Math.max(selection.anchor.character, selection.active.character)
            };
            // 这里是检验 从后往前 或 从前往后 选择的内容。
            if (line.begin > position.line || character.begin > position.character) continue;
            if (line.end < position.line || character.end < position.character) continue;
            try {
                // 开始翻译
                let trans = await translate(editor.document.getText(selection), langTo);
                if (!trans) return;
                let word = trans.word  
                // 悬停显示的内容
                let pre = `**[Google Translate](https://translate.google.cn/?sl=auto&tl=${trans.lang.to}&text=${encodeURI(trans.text)})**\n\n`;
                console.log("word", word);
                return new vscode.Hover(pre + word.replace(/\r\n/g, '  \r\n'));
            } catch (error) {
                return new vscode.Hover('**[Error](https://github.com/imlinhanchao/vsc-google-translate/issues)**\n\n' + error.message);
            }
        }

    }
})

其中几个关键点:

  1. vscode.languages.registerHoverProvider({scheme: 'file'},{...}: 向文件类型提供悬停内容的简单方法。
  2. 中间的两端if: 检验 从后往前 或 从前往后 选择的内容是否满足需求。

然后到了悬停调用

代码语言:javascript
复制
await translate(editor.document.getText(selection), langTo);

2.3 触发翻译

再来看tranlate.js,我稍微精简了下:

代码语言:javascript
复制
const vscode = require('vscode');
const translator = require('@imlinhanchao/google-translate-api');

let config = {};


async function translate(text, lang) {
    try{
        let result = await translator(text, {
            from: lang.from == 'auto' ? undefined : lang.from,
            to: lang.to,
        })

        return {
            lang,
            text,
            word: result.text || '',
            candidate: result.candidates
        };
    } catch (err) {
        throw new Error(`Translate failed, Error message: '${err.message}'. Please post an issues for me.`);
    }      
}

function getConfig() {
    let keys = [
        'google-translate.firstLanguage',
        'google-translate.secondLanguage',
    ];
    let values = {};
    keys.forEach(k => values[k] = vscode.workspace.getConfiguration().get(k))
    return values;
}

module.exports = async (word, l, from='auto') => {
    if (word == '') return null;
    config = getConfig();
    let lang = {
        from,
        to: l || config['google-translate.firstLanguage']
    };

    // 解析驼峰函数。
    word = word.replace(/([a-z])([A-Z])/g, "$1 $2")
            .replace(/([_])/g, " ").replace(/=/g, ' = ')
            .replace(/(\b)\.(\b)/g, '$1 \n{>}\n $2 ');

    let tran = await translate(word, lang);
    
    // 若翻译无结果,则调用翻译成第二语言
    if (tran.word.replace(/\s/g, '') == word.replace(/\s/g, '') || !tran.word.trim()) {
        lang.to = config['google-translate.secondLanguage'];
        let tranSecond = await translate(word, lang);
        if (tranSecond.word) tran = tranSecond;
    }
    // 去除多余字符
    tran.word = tran.word.replace(/\n{>}\n/g, '.');
    tran.candidate = tran.candidate.map(c => c.replace(/{([^>]*?)>}/g, '$1\n{>}').replace(/\n{>}\n/g, '.'));
    return tran;
};

module.exports.getConfig = getConfig;
module.exports.languages = translator.languages;
  1. @imlinhanchao/google-translate-api:是作者集成的翻译API。
  2. getConfig:获取当前vscode的首选和次选语言,若无则自动翻译(默认英语-> 汉语)。

整个文件导出一个翻译方法。

中间那段正则,可以解析出驼峰函数

代码语言:javascript
复制
word = word.replace(/([a-z])([A-Z])/g, "$1 $2")
        .replace(/([_])/g, " ").replace(/=/g, ' = ')
        .replace(/(\b)\.(\b)/g, '$1 \n{>}\n $2 ');

2.4 显示悬停

回到hoverDisposable:

代码语言:javascript
复制
let trans = await translate(editor.document.getText(selection), langTo);
if (!trans) return;
let word = trans.word    
let pre = `**[Google Translate](https://translate.google.cn/?sl=auto&tl=${trans.lang.to}&text=${encodeURI(trans.text)})**\n\n`;
return new vscode.Hover(pre + word.replace(/\r\n/g, '  \r\n'));

拿到翻译结果后,触发显示为:

这里一个很有意思的点,给你拼装了一段可打开的Google Translate链接,非常体贴了可以说。

这个插件作为一个vscode插件开发初体验,是不错的。

2.5 额外小发现:google-translate-api

一个用于 Google 翻译的免费且无限制的 API💵

总结

约有一年没写文章了,这段时间都在摸鱼以及健身。都在写vscode二次/插件开发。比较少关注新技术。准备重新出发,整整账号了。

源码:

VSCode 插件:Google Translate Extension

精简后的:https://github.com/roger-hiro/vscode-google-translate

不想拉代码的同学可以试试CS的自定义模板

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端劝退师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1. 代码目录分析
  • 2. 源码分析
    • 2.1 初始化配置
      • 2.2 编写触发函数
        • 2.3 触发翻译
          • 2.4 显示悬停
            • 2.5 额外小发现:google-translate-api
            • 总结
            • 源码:
            相关产品与服务
            机器翻译
            机器翻译(Tencent Machine Translation,TMT)结合了神经机器翻译和统计机器翻译的优点,从大规模双语语料库自动学习翻译知识,实现从源语言文本到目标语言文本的自动翻译,目前可支持十余种语言的互译。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档