├── .gitignore ├── .DS_Store ├── img ├── 1.gif ├── 2.gif ├── 3.gif ├── 4.gif ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── icon.png ├── .DS_Store ├── icon1.psd ├── icon2.psd ├── icon3.psd ├── icon4.psd ├── icon5.psd └── icon6.psd ├── src ├── offline │ ├── 功用库.ts │ ├── 翻译 │ │ ├── 数据类型.ts │ │ ├── 自定义词典.ts │ │ ├── 处理.ts │ │ └── 词典相关常量.ts │ ├── 加载词典.ts │ ├── 整文件翻译.ts │ └── 查词.ts ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts ├── status.ts ├── document.ts ├── browser.ts ├── language.ts ├── util.ts ├── open.ts └── extension.ts ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── .vscodeignore ├── .eslintrc.json ├── tsconfig.json ├── CHANGELOG.md ├── README.CN.md ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/.DS_Store -------------------------------------------------------------------------------- /img/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/1.gif -------------------------------------------------------------------------------- /img/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/2.gif -------------------------------------------------------------------------------- /img/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/3.gif -------------------------------------------------------------------------------- /img/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/4.gif -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/5.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/6.png -------------------------------------------------------------------------------- /img/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/7.png -------------------------------------------------------------------------------- /img/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/8.png -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon.png -------------------------------------------------------------------------------- /img/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/.DS_Store -------------------------------------------------------------------------------- /img/icon1.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon1.psd -------------------------------------------------------------------------------- /img/icon2.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon2.psd -------------------------------------------------------------------------------- /img/icon3.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon3.psd -------------------------------------------------------------------------------- /img/icon4.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon4.psd -------------------------------------------------------------------------------- /img/icon5.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon5.psd -------------------------------------------------------------------------------- /img/icon6.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wscats/search-online/master/img/icon6.psd -------------------------------------------------------------------------------- /src/offline/功用库.ts: -------------------------------------------------------------------------------- 1 | export function 取文件名(文件全路径: string): string { 2 | let 拆分路径 = 文件全路径.split("/"); 3 | return 拆分路径.length > 1 ? 拆分路径[拆分路径.length - 1] : 文件全路径; 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/offline/翻译/数据类型.ts: -------------------------------------------------------------------------------- 1 | export interface 词形变化 { 2 | 类型: string; 3 | 变化: string; 4 | } 5 | 6 | export interface 单词条 { 7 | 词: string; 8 | 释义: string; 9 | 词形: 词形变化[]; 10 | } 11 | 12 | export interface 字段释义 { 13 | 原字段: string; 14 | 释义: string; 15 | 各词: 单词条[]; 16 | } 17 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | .yarnrc 7 | vsc-extension-quickstart.md 8 | **/tsconfig.json 9 | **/.eslintrc.json 10 | **/*.map 11 | **/*.ts 12 | img/*.psd 13 | img/*.gif 14 | img/5.png 15 | img/6.png 16 | img/7.png 17 | 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /src/offline/加载词典.ts: -------------------------------------------------------------------------------- 1 | export const 词典数据 = {}; 2 | export const 词形变化数据 = {}; 3 | 4 | async function 导入数据() { 5 | for (let 文件序号 = 0; 文件序号 < 16; 文件序号++) { 6 | const 词典 = await import('./词典数据/词典' + 文件序号) 7 | let 数据 = 词典.数据 8 | for (let 英文 in 数据) { 9 | // @ts-ignore 10 | 词典数据[英文] = 数据[英文]; 11 | } 12 | } 13 | } 14 | let 词形变化源数据 = require('./词典数据/词形变化').数据 15 | for (let 英文 in 词形变化源数据) { 16 | // @ts-ignore 17 | 词形变化数据[英文] = 词形变化源数据[英文]; 18 | } 19 | 20 | 导入数据() -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /src/offline/翻译/自定义词典.ts: -------------------------------------------------------------------------------- 1 | export const 常用命名 = { 2 | 'text': "文本", 3 | "get": "获取", 4 | "util": "功用", 5 | "hash": "哈希", 6 | "set": "置", 7 | "is": "为", 8 | "exception": "例外", 9 | "key": "键", 10 | "type": "类型", 11 | "name": "名称", 12 | "listener": "监听器", 13 | "class": "类", 14 | "method": "方法", 15 | "time": "时间", 16 | "event": "事件", 17 | "file": "文件", 18 | "new": "新", 19 | "add": "添加", 20 | "stream": "流", 21 | "default": "默认", 22 | "count": "计数", 23 | "focus": "聚焦", 24 | "value": "值", 25 | "input": "输入", 26 | "date": "日期", 27 | "long": "长整型", 28 | "size": "大小", 29 | "thread": "线程", 30 | "path": "路径", 31 | "parameter": "参数", 32 | "remove": "删除" 33 | }; 34 | 35 | export const 常用短语 = { 36 | "get started": "启动" 37 | } 38 | 39 | export const 不翻译 = { 40 | "to": false, 41 | "of": false, 42 | "bean": false 43 | }; 44 | 45 | const API词典 = { 46 | 'print': '打印', 47 | 'append': '添加', 48 | 'sort': '排序', 49 | 'len': '长度', 50 | 'end': '结尾' 51 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | - 2018-06-13 Establish a private code repository and implement a simple compilation extension. 4 | - 2018-11-12 Continuous optimization and improvement, only for internal commercial projects, and plan to open source. 5 | - 2018-12-13 Start writing documents and tutorials, and adjust the code structure. 6 | - 2019-11-03 Automatically evaluate documents and generate download links. 7 | - 2020-10-04 Support switching search engines to search for relevant results. 8 | - 2020-10-08 Add some default search engines, support two switching methods. 9 | - 2020-11-11 Publish to the VS extension plugin market. 10 | - 2020-11-12 Support for adding new search engines, using visual interface and configuration files to add. 11 | - 2020-11-12 Support the use of Google Translate to translate the languages of various countries. 12 | - 2020-11-15 Support stackoverflow site search. 13 | - 2020-11-18 Support wikipedia site search. 14 | - 2020-11-20 Support duckduckgo site search. 15 | - 2020-11-24 Support codepen and codesandbox site search. 16 | - 2020-11-29 Improve Chinese documents and bind more convenient shortcut keys. 17 | - 2020-12-25 Improve the startup speed, add offline dictionary switch. 18 | 19 | # Unreleased 20 | 21 | - Support changing search engine link configuration parameters. 22 | -------------------------------------------------------------------------------- /src/status.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | import * as vscode from 'vscode'; 8 | 9 | export class StatusBarUi { 10 | private static _statusBarItem: vscode.StatusBarItem; 11 | private static get statusBarItem() { 12 | if (!StatusBarUi._statusBarItem) { 13 | StatusBarUi._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 200); 14 | this.statusBarItem.show(); 15 | } 16 | return StatusBarUi._statusBarItem; 17 | } 18 | 19 | static init() { 20 | let config = vscode.workspace.getConfiguration("search-online"); 21 | let engine = config.get("search-engine"); 22 | StatusBarUi.working("Starting..."); 23 | setTimeout(function () { 24 | engine && StatusBarUi.setEngine(engine); 25 | config.set("search-engine", engine); 26 | }, 1000); 27 | } 28 | 29 | static setEngine(engine: string) { 30 | StatusBarUi.statusBarItem.text = `$(eye) Search Engine: ${engine}`; 31 | StatusBarUi.statusBarItem.color = 'inherit'; 32 | StatusBarUi.statusBarItem.command = 'extension.search-engine'; 33 | StatusBarUi.statusBarItem.tooltip = 'Switch Search Engine'; 34 | } 35 | 36 | 37 | static working(workingMsg: string = "Working on it...") { 38 | StatusBarUi.statusBarItem.text = `$(pulse) ${workingMsg}`; 39 | StatusBarUi.statusBarItem.tooltip = 'In case if it takes long time, Show output window and report.'; 40 | StatusBarUi.statusBarItem.command = undefined; 41 | } 42 | 43 | static dispose() { 44 | StatusBarUi.statusBarItem.dispose(); 45 | } 46 | } -------------------------------------------------------------------------------- /src/document.ts: -------------------------------------------------------------------------------- 1 | export const document = { 2 | "ahk": "https://autohotkey.com/docs/commands/${query}.htm", 3 | "controller": "http://api.rubyonrails.org/?q=${query}", 4 | "rb": "http://ruby-doc.com/search.html?q=${query}", 5 | "js": "https://developer.mozilla.org/en-US/search?q=${query}&topic=js", 6 | "html": "https://developer.mozilla.org/en-US/search?q=${query}&topic=html", 7 | "htm": "https://developer.mozilla.org/en-US/search?q=${query}&topic=html", 8 | "coffee": "https://developer.mozilla.org/en-US/search?q=${query}", 9 | "php": "http://php.net/manual-lookup.php?pattern=${query}", 10 | "clj": "http://clojuredocs.org/search?x=0&y=0&q=${query}", 11 | "go": "http://golang.org/search?q=${query}", 12 | "c": "http://www.cplusplus.com/search.do?q=${query}", 13 | "cpp": "http://www.cplusplus.com/search.do?q=${query}", 14 | "smarty": "http://www.smarty.net/${query}", 15 | "cmake": "http://cmake.org/cmake/help/v2.8.8/cmake.html#command:${query}", 16 | "perl": "http://perldoc.perl.org/search.html?q=${query}", 17 | "cs": "http://social.msdn.microsoft.com/Search/?query=${query}", 18 | "lua": "http://pgl.yoyo.org/luai/i/${query}", 19 | "pgsql": "http://www.postgresql.org/search/?u=%%2Fdocs%%2Fcurrent%%2F&q=${query}", 20 | "erl": "http://erldocs.com/R16B03/?search=${query}", 21 | "hs": "http://hayoo.fh-wedel.de/?query=${query}", //haskell 22 | "scala": "https://www.scala-lang.org/api/current/?search=${query}", 23 | "css": "http://devdocs.io/#q=${query}", 24 | "scss": "http://devdocs.io/#q=${query}", 25 | "less": "http://devdocs.io/#q=${query}", 26 | "google": "https://google.com/search?q=${query}", 27 | "py": "http://docs.python.org/3/search.html?q=${query}" 28 | }; -------------------------------------------------------------------------------- /src/offline/整文件翻译.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as 释义处理 from './翻译/处理' 3 | import * as 词典常量 from './翻译/词典相关常量' 4 | import * as 功用库 from './功用库'; 5 | import * as 查词 from './查词'; 6 | 7 | import * as vscode from 'vscode'; 8 | 9 | export default class 整文件翻译 implements vscode.TextDocumentContentProvider { 10 | 11 | static scheme = 'references'; 12 | private 原命名列表: string[] = []; 13 | 14 | dispose() { 15 | } 16 | 17 | provideTextDocumentContent(uri: vscode.Uri): string | Thenable { 18 | // TODO: 如果没有当前活跃编辑器, 返回空 19 | let textEditor = vscode.window.activeTextEditor; 20 | // @ts-ignore 21 | return vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', textEditor.document.uri) 22 | .then( 23 | // @ts-ignore 24 | (symbols: Array) => { 25 | for (var 标识符 of symbols) { 26 | this.原命名列表.push(释义处理.消除英文小括号内容(标识符.name)); 27 | for (var 子标识符 of 标识符.children) { 28 | this.原命名列表.push(释义处理.消除英文小括号内容(子标识符.name)); 29 | } 30 | } 31 | 32 | // 长词先查释义, 以免出现一个命名"xxxxyyyy"先替换了yyyy而xxxx未替换的情况 33 | this.原命名列表.sort(function (a, b) { return b.length - a.length }); 34 | 35 | // @ts-ignore 36 | var 新内容 = textEditor.document.getText(); 37 | for (var 原命名 of this.原命名列表) { 38 | let 中文释义 = 查词.取释义(原命名).释义; 39 | let 翻译 = 释义处理.取字段中所有词(原命名).length > 1 40 | ? 中文释义 41 | : 释义处理.首选(中文释义, 词典常量.词性_计算机); 42 | if (翻译) { 43 | 新内容 = this._replaceAll(新内容, 原命名, 翻译); 44 | } 45 | } 46 | return 新内容; 47 | } 48 | ) 49 | } 50 | 51 | // @ts-ignore 52 | private _replaceAll(str, find, replace) { 53 | return str.replace(new RegExp(find, 'g'), replace); 54 | } 55 | } 56 | 57 | let seq = 0; 58 | 59 | export function encodeLocation(uri: vscode.Uri, pos: vscode.Position): vscode.Uri { 60 | const query = JSON.stringify([uri.toString(), pos.line, pos.character]); 61 | let 文件名 = 功用库.取文件名(uri.path); 62 | return vscode.Uri.parse(`${整文件翻译.scheme}:翻译${文件名}?${query}#${seq++}`); 63 | } 64 | -------------------------------------------------------------------------------- /src/browser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | import { QuickPickItem } from "vscode"; 8 | 9 | interface PickItem extends QuickPickItem { 10 | [propName: string]: any; 11 | } 12 | 13 | const platform = process.platform; 14 | 15 | const chromeItem: PickItem = { 16 | description: "Windows, Mac, Linux", 17 | detail: "A fast, secure, and free web browser built for the modern web", 18 | label: "Google Chrome", 19 | standardName: platform === 'win32' 20 | ? 'chrome' 21 | : ( 22 | platform === 'darwin' 23 | ? 'google chrome' 24 | : 'google-chrome' 25 | ), 26 | acceptName: ['chrome', 'google chrome', 'google-chrome', 'gc', '谷歌浏览器'] 27 | }; 28 | 29 | const chromiumItem: PickItem = { 30 | description: "Mac", 31 | detail: "A fast, secure, and free web browser built for the modern web", 32 | label: "Google Chromium", 33 | standardName: "Chromium", 34 | acceptName: ['chromium'] 35 | }; 36 | const firefoxItem: PickItem = { 37 | description: "Windows, Mac, Linux", 38 | detail: "A fast, smart and personal web browser", 39 | label: "Mozilla Firefox", 40 | standardName: "firefox", 41 | acceptName: ['firefox', 'ff', 'mozilla firefox', '火狐浏览器'] 42 | }; 43 | const firefoxDeveloperItem: PickItem = { 44 | description: "Mac", 45 | detail: "A fast, smart and personal web browser", 46 | label: "Mozilla Firefox Developer Edition", 47 | standardName: "FirefoxDeveloperEdition", 48 | acceptName: ['firefox developer', 'fde', 'firefox developer edition'] 49 | }; 50 | 51 | const ieItem: PickItem = { 52 | description: "Windows", 53 | detail: "A slightly outdated browser", 54 | label: "Microsoft IE", 55 | standardName: "iexplore", 56 | acceptName: ['ie', 'iexplore'] 57 | }; 58 | const edgeItem: PickItem = { 59 | description: "Windows", 60 | detail: "A modern browser aiming to replace ie", 61 | label: "Microsoft Edge", 62 | standardName: "MicrosoftEdge", 63 | acceptName: ['edge', 'msedge', 'microsoftedge'] 64 | }; 65 | 66 | const safariItem: PickItem = { 67 | description: "Mac", 68 | detail: "A fast, efficient browser on Mac", 69 | label: "Apple Safari", 70 | standardName: "safari", 71 | acceptName: ['safari'] 72 | }; 73 | 74 | const operaItem: PickItem = { 75 | description: "Windows, Mac", 76 | detail: 'A fast, secure, easy-to-use browser', 77 | label: 'Opera', 78 | standardName: 'opera', 79 | acceptName: ['opera'] 80 | }; 81 | 82 | const browsers = [chromeItem, firefoxItem, operaItem]; 83 | 84 | if (process.platform === 'win32') { 85 | browsers.push(ieItem); 86 | browsers.push(edgeItem); 87 | } else if (process.platform === 'darwin') { 88 | browsers.push(safariItem); 89 | browsers.push(chromiumItem); 90 | browsers.push(firefoxDeveloperItem); 91 | } 92 | 93 | export const browserConfig = { 94 | browsers: browsers, 95 | app: 'open-in-browser' 96 | }; -------------------------------------------------------------------------------- /src/language.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | interface IlanguageConfig { 8 | [key: string]: string 9 | }; 10 | 11 | export const languageConfig: IlanguageConfig = { 12 | "English/英语": "en", 13 | "Chinese/中文": "zh-CN", 14 | "Japanese/日语": "ja", 15 | "Albanian/阿尔巴尼亚语": "sq", 16 | "Arabic/阿拉伯语": "ar", 17 | "Amharic/阿姆哈拉语": "am", 18 | "Azerbaijani/阿塞拜疆语": "az", 19 | "Irish/爱尔兰语": "ga", 20 | "Estonian/爱沙尼亚语": "et", 21 | "Oriya/奥利亚语": "or", 22 | "Basque/巴斯克语": "eu", 23 | "Belarusian/白俄罗斯语": "be", 24 | "Bulgarian/保加利亚语": "bg", 25 | "Icelandic/冰岛语": "is", 26 | "Polish/波兰语": "pl", 27 | "Bosnian/波斯尼亚语": "bs", 28 | "Persian/波斯语": "fa", 29 | "Boolean (Afrikaans)/布尔语(南非荷兰语)": "af", 30 | "Tatar/鞑靼语": "tt", 31 | "Danish/丹麦语": "da", 32 | "German/德语": "de", 33 | "Russian/俄语": "ru", 34 | "French/法语": "fr", 35 | "Filipino/菲律宾语": "tl", 36 | "Finnish/芬兰语": "fi", 37 | "Frisian/弗里西语": "fy", 38 | "Khmer/高棉语": "km", 39 | "Georgian/格鲁吉亚语": "ka", 40 | "Gujarati/古吉拉特语": "gu", 41 | "Kazakh/哈萨克语": "kk", 42 | "Haiti Creole/海地克里奥尔语": "ht", 43 | "Korean/韩语": "ko", 44 | "Hausa/豪萨语": "ha", 45 | "Dutch/荷兰语": "nl", 46 | "Kyrgyz/吉尔吉斯语": "ky", 47 | "Galician/加利西亚语": "gl", 48 | "Catalan/加泰罗尼亚语": "ca", 49 | "Czech/捷克语": "cs", 50 | "Kannada/卡纳达语": "kn", 51 | "Corsican/科西嘉语": "co", 52 | "Croatian/克罗地亚语": "hr", 53 | "Kurdish/库尔德语": "ku", 54 | "Latin/拉丁语": "la", 55 | "Latvian/拉脱维亚语": "lv", 56 | "Laotian/老挝语": "lo", 57 | "Lithuanian/立陶宛语": "lt", 58 | "Luxembourgish/卢森堡语": "lb", 59 | "Rwandan/卢旺达语": "rw", 60 | "Romanian/罗马尼亚语": "ro", 61 | "Malagasy/马尔加什语": "mg", 62 | "Maltese/马耳他语": "mt", 63 | "Marathi/马拉地语": "mr", 64 | "Malayalam/马拉雅拉姆语": "ml", 65 | "Malay/马来语": "ms", 66 | "Macedonian/马其顿语": "mk", 67 | "Maori/毛利语": "mi", 68 | "Mongolian/蒙古语": "mn", 69 | "Bengali/孟加拉语": "bn", 70 | "Burmese/缅甸语": "my", 71 | "Miao language/苗语": "hmn", 72 | "South African Xhosa/南非科萨语": "xh", 73 | "South African Zulu/南非祖鲁语": "zu", 74 | "Nepalese/尼泊尔语": "ne", 75 | "Norwegian/挪威语": "no", 76 | "Punjabi/旁遮普语": "pa", 77 | "Portuguese/葡萄牙语": "pt", 78 | "Pashto/普什图语": "ps", 79 | "Chichewa/齐切瓦语": "ny", 80 | "Swedish/瑞典语": "sv", 81 | "Samoan/萨摩亚语": "sm", 82 | "Serbian/塞尔维亚语": "sr", 83 | "Sesotho/塞索托语": "st", 84 | "Sinhala/僧伽罗语": "si", 85 | "Esperanto/世界语": "eo", 86 | "Slovak/斯洛伐克语": "sk", 87 | "Slovenian/斯洛文尼亚语": "sl", 88 | "Swahili/斯瓦希里语": "sw", 89 | "Scottish Gaelic/苏格兰盖尔语": "gd", 90 | "Cebuano/宿务语": "ceb", 91 | "Somali/索马里语": "so", 92 | "Tajik/塔吉克语": "tg", 93 | "Telugu/泰卢固语": "te", 94 | "Tamil/泰米尔语": "ta", 95 | "Thai/泰语": "th", 96 | "Turkish/土耳其语": "tr", 97 | "Turkmen/土库曼语": "tk", 98 | "Welsh/威尔士语": "cy", 99 | "Uyghur/维吾尔语": "ug", 100 | "Urdu/乌尔都语": "ur", 101 | "Ukrainian/乌克兰语": "uk", 102 | "Uzbek/乌兹别克语": "uz", 103 | "Spanish/西班牙语": "es", 104 | "Hebrew/希伯来语": "iw", 105 | "Greek/希腊语": "el", 106 | "Hawaiian/夏威夷语": "haw", 107 | "Sin German/信德语": "sd", 108 | "Hungarian/匈牙利语": "hu", 109 | "Shona/修纳语": "sn", 110 | "Armenian/亚美尼亚语": "hy", 111 | "Igbo/伊博语": "ig", 112 | "Italian/意大利语": "it", 113 | "Yiddish/意第绪语": "yi", 114 | "Hindi/印地语": "hi", 115 | "Indonesian Sundanese/印尼巽他语": "su", 116 | "Indonesian/印尼语": "id", 117 | "Javanese/印尼爪哇语": "jw", 118 | "Yoruba/约鲁巴语": "yo", 119 | "Vietnamese/越南语": "vi", 120 | "Chinese (Simplified)/中文(简体)": "zh-CN", 121 | "Chinese (Traditional)/中文(繁体)": "zh-TW", 122 | } -------------------------------------------------------------------------------- /src/offline/查词.ts: -------------------------------------------------------------------------------- 1 | import * as 释义处理 from './翻译/处理' 2 | import * as 自定义词典 from './翻译/自定义词典' 3 | import * as 模型 from './翻译/数据类型' 4 | import * as 词典常量 from './翻译/词典相关常量' 5 | import * as 词典 from './加载词典' 6 | 7 | const 词形_原型变换形式 = "原型变换形式" 8 | const 词形类型 = Object.freeze({ 9 | "p": "过去式", // past tense 10 | "d": "过去分词", 11 | "i": "现在分词", // -ing 12 | "3": "第三人称单数", 13 | "r": "形容词比较级", // -er 14 | "t": "形容词最高级", // -est 15 | "s": "名词复数形式", 16 | "0": "原型", 17 | "1": 词形_原型变换形式 18 | }); 19 | 20 | export function 取释义(选中文本: string): 模型.字段释义 { 21 | let 所有词 = 释义处理.取字段中所有词(选中文本); 22 | let 所有词条 = []; 23 | for (let 单词 of 所有词) { 24 | let 处理后词 = 单词; 25 | 26 | if (处理后词 != 单词.toUpperCase()) { 27 | 处理后词 = 单词.toLowerCase(); 28 | } else { 29 | // 应付全大写词, 多见于常量, 如SHIPMENT 30 | // @ts-ignore 31 | if (!词典.词典数据[处理后词]) { 32 | 处理后词 = 单词.toLowerCase(); 33 | } 34 | } 35 | if (处理后词 in 自定义词典.不翻译) { 36 | // TODO: 使用"单词条"数据结构 37 | 所有词条.push({ 38 | 词: 处理后词, 39 | 释义: 处理后词}); 40 | continue; 41 | } 42 | 43 | // TODO: 重构 44 | // 仅在命名包含多词时取原型 45 | if (所有词.length > 1) { 46 | // @ts-ignore 47 | 处理后词 = 释义处理.取原型(处理后词, 提取词形(词典.词形变化数据[处理后词])); 48 | } 49 | // @ts-ignore 50 | let 所有词形 = 提取词形(词典.词形变化数据[处理后词]); 51 | 52 | // TODO: 使用"单词条"数据结构 53 | 所有词条.push({ 54 | 词: 处理后词, 55 | // @ts-ignore 56 | 释义: 词典.词典数据[处理后词], 57 | 词形: 所有词形 58 | }); 59 | } 60 | let 释义 = 选中文本; 61 | if (所有词条.length > 1) { 62 | let 短语释义 = 按短语查询(所有词条); 63 | if (短语释义) { 64 | 释义 = 短语释义; 65 | } else { 66 | 释义 = 逐词翻译(选中文本, 所有词条, 所有词); 67 | } 68 | } else if (所有词条.length == 1) { 69 | // TODO: 简化词条 (以适应状态栏宽度) 70 | 释义 = 所有词条[0].释义; 71 | } 72 | return { 73 | 原字段: 选中文本, 74 | 释义: 释义, 75 | // @ts-ignore 76 | 各词: 所有词条 77 | }; 78 | } 79 | 80 | // @ts-ignore 81 | function 逐词翻译(选中文本, 所有词条, 所有词): string { 82 | let 释义 = 选中文本; 83 | let 首选释义 = 释义处理.选取释义(所有词条, 所有词); 84 | let 各释义 = [] 85 | for (let 序号 = 0; 序号 < 所有词.length; 序号++) { 86 | let 下一词 = 所有词[序号]; 87 | let 位置 = 释义.indexOf(下一词); 88 | 89 | if (位置 > 0) { 90 | 各释义.push(释义.substring(0, 位置)); 91 | } 92 | // @ts-ignore 93 | 各释义.push(自定义词典.常用命名[所有词条[序号].词] || 首选释义[序号]); 94 | 释义 = 释义.substring(位置 + 下一词.length); 95 | } 96 | if (释义 !== "") { 97 | 各释义.push(释义); 98 | } 99 | if (各释义.length > 1 && 各释义[0].indexOf("...") > 0) { 100 | 释义 = 各释义[0].replace("...", 各释义.splice(1).join("")) 101 | } else { 102 | 释义 = 各释义.join(""); 103 | } 104 | return 释义; 105 | } 106 | 107 | // 词形部分数据格式描述: https://github.com/skywind3000/ECDICT#%E8%AF%8D%E5%BD%A2%E5%8F%98%E5%8C%96 108 | function 提取词形(原字符串: string): 模型.词形变化[] { 109 | // @ts-ignore 110 | let 变化 = []; 111 | if (!原字符串) { 112 | // @ts-ignore 113 | return 变化; 114 | } 115 | let 词形字段 = 原字符串.split("/"); 116 | for (let 某字段 of 词形字段) { 117 | let 分段 = 某字段.split(":"); 118 | 119 | // @ts-ignore 120 | let 类型 = 词形类型[分段[0]]; 121 | let 原型变化形式 = []; 122 | if (类型 == 词形_原型变换形式) { 123 | for (let 变化形式 of 分段[1]) { 124 | // @ts-ignore 125 | 原型变化形式.push(词形类型[变化形式]); 126 | } 127 | } 128 | // 如hyphen(vt): s:hyphens/p:hyphened/i:/3:hyphens/d:, i与d内容缺失, 用空字符串占位 129 | 变化.push({ 130 | 类型: 类型, 131 | 变化: 分段.length == 1 ? "" : (类型 == 词形_原型变换形式 ? 原型变化形式 : 分段[1])} 132 | ); 133 | } 134 | // @ts-ignore 135 | return 变化; 136 | } 137 | 138 | // @ts-ignore 139 | function 按短语查询(所有词条): string { 140 | let 所有词 = []; 141 | for (let 词条 of 所有词条) { 142 | 所有词.push(词条.词); 143 | } 144 | let 短语 = 所有词.join(" "); 145 | // @ts-ignore 146 | return 自定义词典.常用短语[短语] || 释义处理.首选(词典.词典数据[短语], 词典常量.词性_计算机); 147 | } -------------------------------------------------------------------------------- /src/offline/翻译/处理.ts: -------------------------------------------------------------------------------- 1 | import * as 模型 from './数据类型' 2 | import * as 词典常量 from './词典相关常量' 3 | 4 | export function 取按词性释义(中文释义: string): Map { 5 | let 所有释义 = 中文释义.split('\\n'); 6 | let 词性到释义 = new Map(); 7 | for (let i in 所有释义) { 8 | let 除去词性 = 所有释义[i]; 9 | let 首空格位置 = 除去词性.indexOf(' '); 10 | let 当前词性 = 首空格位置 > 0 ? 除去词性.substring(0, 首空格位置) : ''; 11 | if (当前词性 && 词典常量.词性.has(当前词性)) { 12 | 除去词性 = 除去词性.substring(当前词性.length).trim(); 13 | } else { 14 | 当前词性 = ''; 15 | } 16 | 17 | // 按逗号分隔词义 18 | // TODO: 也有分号分隔 19 | let 词义 = 除去词性.split(/[;;,]/); 20 | let 此词性的释义: string[] = [] 21 | for (let 某词义 of 词义) { 22 | 此词性的释义.push(某词义.trim()); 23 | } 24 | 词性到释义.set(当前词性, 此词性的释义); 25 | } 26 | return 词性到释义; 27 | } 28 | 29 | export function 选取释义(所有词条: 模型.单词条[], 所有词: string[]): string[] { 30 | let 所有释义 = []; 31 | 32 | // TODO: 重构 33 | if (所有词条.length == 2) { 34 | let 词1释义 = 所有词条[0].释义; 35 | let 词2释义 = 所有词条[1].释义; 36 | if (词1释义 && 取按词性释义(词1释义).has(词典常量.词性_形容词) 37 | && 词2释义 && 取按词性释义(词2释义).has(词典常量.词性_名词)) { 38 | 所有释义.push(首选(词1释义, 词典常量.词性_形容词)); 39 | 所有释义.push(首选(词2释义, 词典常量.词性_名词)); 40 | return (所有释义); 41 | } 42 | } 43 | 44 | for (let i = 0; i < 所有词条.length; i++) { 45 | let 词条 = 所有词条[i]; 46 | 所有释义.push(词条.释义 ? 首选(词条.释义, 词典常量.词性_计算机) : 所有词[i]); 47 | } 48 | return 所有释义; 49 | } 50 | 51 | export function 首选(中文释义: string, 首选词性: string): string { 52 | if (!中文释义) { 53 | return ""; 54 | } 55 | let 首选词义 = ""; 56 | 57 | // TODO: 减少重复调用 58 | let 词性到释义 = 取按词性释义(中文释义); 59 | if (词性到释义.has(词典常量.词性_计算机)) { 60 | // @ts-ignore 61 | 首选词义 = 词性到释义.get(词典常量.词性_计算机)[0]; 62 | } else if (词性到释义.has(首选词性)) { 63 | // @ts-ignore 64 | 首选词义 = 词性到释义.get(首选词性)[0]; 65 | } else { 66 | // 取第一个词性的第一释义 67 | for (let [k, v] of 词性到释义) { 68 | 首选词义 = v[0]; 69 | break; 70 | } 71 | } 72 | 首选词义 = 消除所有括号内容(首选词义); 73 | return 首选词义; 74 | } 75 | 76 | // @ts-ignore 77 | export function 取原型(词: string, 词形): string { 78 | if (词形) { 79 | let 原词 = 词; 80 | let 为复数形式 = false; 81 | for (let 某词形 of 词形) { 82 | if (某词形.类型 == "原型变换形式" && (某词形.变化.includes("名词复数形式") || 某词形.变化.includes("现在分词"))) { 83 | 为复数形式 = true; 84 | } 85 | if (某词形.类型 == "原型") { 86 | 原词 = 某词形.变化; 87 | } 88 | } 89 | if (为复数形式) { 90 | return 原词; 91 | } 92 | } 93 | return 词; 94 | } 95 | 96 | ///////////////// 原文本处理 97 | 98 | 99 | // 假设每个字段除了词, 其他都是非英文字符. 100 | // 仅翻译无空格的片段 101 | export function 取字段中所有词(字段文本: string): string[] { 102 | // 删去所有前后空格后再提取单词 103 | let 删除前后空格 = 字段文本.trim(); 104 | // 确认无空格 105 | if (!删除前后空格.match(/^[^\s]+$/g)) { 106 | return []; 107 | } 108 | let 单词 = 删除前后空格.match(/[a-zA-Z]+/g); 109 | if (单词) { 110 | // @ts-ignore 111 | let 分词 = []; 112 | for (let 某单词 of 单词) { 113 | // @ts-ignore 114 | 分词 = 分词.concat(拆分骆驼命名(某单词)) 115 | } 116 | return 分词; 117 | } 118 | return []; 119 | } 120 | 121 | function 拆分骆驼命名(命名: string): string[] { 122 | // 参考: https://stackoverflow.com/a/46409373/1536803 123 | // Firefox仍不支持lookbehinds: https://stackoverflow.com/questions/49816707/firefox-invalid-regex-group 124 | // 不知为何结果中有空字符串, 暂时过滤即可 125 | return 命名.split(/([A-Z]+|[A-Z]?[a-z]+)(?=[A-Z]|\b)/).filter(词 => 词); 126 | } 127 | 128 | function 消除所有括号内容(中文释义: string): string { 129 | // 不确定是否存在多个括号的情况: 清理后.replace(/ *([^)]*) */g, ""); // 130 | let 清理后 = 消除括号内容(中文释义, "(", ")"); 131 | 清理后 = 消除英文小括号内容(清理后); 132 | 清理后 = 清理后.replace(/ *\[[^)]*\] */g, ""); 133 | return 清理后.trim(); 134 | } 135 | 136 | export function 消除英文小括号内容(字符串: string): string { 137 | return 字符串.replace(/ *\([^)]*\) */g, ""); 138 | } 139 | 140 | function 消除括号内容(中文释义: string, 开括号: string, 闭括号: string): string { 141 | let 开括号位置 = 中文释义.indexOf(开括号); 142 | let 闭括号位置 = 中文释义.indexOf(闭括号); 143 | if (开括号位置 == -1 || 闭括号位置 == -1) { 144 | return 中文释义; 145 | } 146 | let 括号内容 = 中文释义.substring(开括号位置, 闭括号位置 + 1); 147 | return 中文释义.replace(括号内容, ""); 148 | } -------------------------------------------------------------------------------- /src/offline/翻译/词典相关常量.ts: -------------------------------------------------------------------------------- 1 | export const 词性_计算机 = "[计]"; 2 | export const 词性_名词 = "n."; 3 | export const 词性_形容词 = "a."; 4 | export const 词性_副词 = "adv."; 5 | export const 词性_及物动词 = "vt."; 6 | 7 | export const 词性: Set = new Set([ 8 | "[j]", 9 | "[pl.]", 10 | "[专利]", 11 | "[临床]", 12 | "[主澳大利亚俚语]", 13 | "[主美国口语]", 14 | "[主美国新英格兰和中南部方言]", 15 | "[主美用英语]", 16 | "[主苏格兰英语]", 17 | "[主英国英语]", 18 | "[五金]", 19 | "[交]", 20 | "[交][水产]", 21 | "[人工智能]", 22 | "[人类]", 23 | "[会计]", 24 | "[作物]", 25 | "[俚语]", 26 | "[光]", 27 | "[免疫]", 28 | "[公路]", 29 | "[兽]", 30 | "[内科]", 31 | "[军]", 32 | "[军][化工]", 33 | "[军][核]", 34 | "[军][船]", 35 | "[农学]", 36 | "[农经]", 37 | "[冶]", 38 | "[分化]", 39 | "[制冷]", 40 | "[前缀]", 41 | "[加勒比英语]", 42 | "[加拿大英语]", 43 | "[动]", 44 | "[动][心理]", 45 | "[动力]", 46 | "[劳经]", 47 | "[化]", 48 | "[化学]", 49 | "[化工]", 50 | "[化工][电子]", 51 | "[医]", 52 | "[单复同]", 53 | "[印刷]", 54 | "[印度]", 55 | "[口语]", 56 | "[古生]", 57 | "[古语]", 58 | "[古语、书面语]", 59 | "[史]", 60 | "[园艺]", 61 | "[图情]", 62 | "[土壤]", 63 | "[地]", 64 | "[地物]", 65 | "[地理]", 66 | "[地理][水文]", 67 | "[地质]", 68 | "[地质][冶]", 69 | "[域]", 70 | "[声]", 71 | "[复]", 72 | "[复]n.[用作单]", 73 | "[复]n.[用作单或复]", 74 | "[复]n.[语]", 75 | "[复数]", 76 | "[复数,用作单数或复数]", 77 | "[天]", 78 | "[天物]", 79 | "[妇产]", 80 | "[宗]", 81 | "[家具]", 82 | "[岩]", 83 | "[工经]", 84 | "[希]", 85 | "[废语]", 86 | "[建]", 87 | "[律]", 88 | "[微]", 89 | "[德]", 90 | "[意]", 91 | "[拉]", 92 | "[拉][用于祈使语气]", 93 | "[拉丁语]", 94 | "[数]", 95 | "[数][光]", 96 | "[数][天]", 97 | "[无化]", 98 | "[无脊椎]", 99 | "[日语]", 100 | "[旧语]", 101 | "[昆]", 102 | "[有化]", 103 | "[服装]", 104 | "[木]", 105 | "[机]", 106 | "[材]", 107 | "[林]", 108 | "[树脂]", 109 | "[核]", 110 | "[植]", 111 | "[植保]", 112 | "[植物]", 113 | "[橡胶]", 114 | "[气象]", 115 | "[气象][物]", 116 | "[水产][无脊椎]", 117 | "[水利]", 118 | "[水文][地理]", 119 | "[水运]", 120 | "[水运][船]", 121 | "[油气]", 122 | "[泌尿]", 123 | "[法]", 124 | "[法语]", 125 | "[流]", 126 | "[测]", 127 | "[海洋]", 128 | "[涂料]", 129 | "[澳大利亚俚语]", 130 | "[澳大利亚口语]", 131 | "[激光]", 132 | "[炉窑]", 133 | "[牌]", 134 | "[物]", 135 | "[环境]", 136 | "[玻璃]", 137 | "[瑞士]", 138 | "[生]", 139 | "[生化]", 140 | "[生态]", 141 | "[生物]", 142 | "[生物物理]", 143 | "[生理]", 144 | "[用于祈使语气]", 145 | "[电]", 146 | "[电子]", 147 | "[电影]", 148 | "[电视]", 149 | "[电讯]", 150 | "[畜牧]", 151 | "[病毒]", 152 | "[皮革]", 153 | "[矿业]", 154 | "[矿物]", 155 | "[禽]", 156 | "[税收]", 157 | "[粗俗语]", 158 | "[粮食]", 159 | "[纺]", 160 | "[纺织业]", 161 | "[组织]", 162 | "[细胞]", 163 | "[经]", 164 | "[经管]", 165 | "[统计]", 166 | "[缩]", 167 | "[网络]", 168 | "[罕]", 169 | "[美]", 170 | "[美俗]", 171 | "[美口]", 172 | "[美国、加拿大口语]", 173 | "[美国中南部和南部方言]", 174 | "[美国俚语]", 175 | "[美国口语]", 176 | "[美国方言]", 177 | "[美国英语]", 178 | "[肿瘤]", 179 | "[胚]", 180 | "[能源]", 181 | "[脊椎]", 182 | "[自]", 183 | "[航]", 184 | "[航][安全]", 185 | "[航空]", 186 | "[船]", 187 | "[苏]", 188 | "[苏格兰和英格兰北部英语]", 189 | "[苏格兰英语]", 190 | "[英]", 191 | "[英国俚语]", 192 | "[英国口语]", 193 | "[英国方言]", 194 | "[英国英语]", 195 | "[英方]", 196 | "[药]", 197 | "[西]", 198 | "[解剖]", 199 | 词性_计算机, 200 | "[计][印刷]", 201 | "[计][图情]", 202 | "[计][心理]", 203 | "[计][统计]", 204 | "[计][语]", 205 | "[计][通信]", 206 | "[计划]", 207 | "[计量]", 208 | "[诗]", 209 | "[语]", 210 | "[财政]", 211 | "[贬义]", 212 | "[贸易]", 213 | "[贸易][税收]", 214 | "[车辆]", 215 | "[通信]", 216 | "[遗]", 217 | "[遗][免疫]", 218 | "[邮]", 219 | "[金融]", 220 | "[铁路]", 221 | "[食品]", 222 | "[鱼]", 223 | "[鸟]", 224 | 词性_形容词, 225 | "abbr.", 226 | "adj.", 227 | 词性_副词, 228 | "art.", 229 | "aux.", 230 | "col.", 231 | "comb.", 232 | "conj.", 233 | "exclam.", 234 | "ind.", 235 | "ing.", 236 | "int.", 237 | "interj.", 238 | 词性_名词, 239 | "na.", 240 | "num.", 241 | "pers.", 242 | "ph.", 243 | "phr.", 244 | "pl.", 245 | "pla.", 246 | "pn.", 247 | "pp.", 248 | "pr.", 249 | "pref.", 250 | "prep.", 251 | "pron.", 252 | "quant.", 253 | "st.", 254 | "stuff.", 255 | "suf.", 256 | "suff.", 257 | "un.", 258 | "v.", 259 | "vbl.", 260 | "vi.", 261 | 词性_及物动词 262 | ]) -------------------------------------------------------------------------------- /README.CN.md: -------------------------------------------------------------------------------- 1 | # 特性 2 | 3 | Download 4 | Macketplace 5 | Github Page 6 | Eno Yao 7 | 8 | [English](https://github.com/Wscats/search-online/blob/master/README.md) | [中文](https://gitee.com/wscats/search-online/blob/master/README.CN.md) 9 | 10 | 一款让您在代码中进行搜索或者翻译的 VS Code 插件。 11 | 12 | # 使用 13 | 14 | ## 搜索 15 | 16 | 你可以在编辑器中,选中代码中对应的关键词,然后点击鼠标右键,在出现的菜单面板中选择 `Search Online` 菜单项,插件会自动帮你打开默认浏览器,并搜索对应的关键词和显示搜索结果。 17 | 18 | 你还可以选中对应的关键词后,使用快捷键 `cmd+enter(mac)` / `ctrl+enter(win)` 去打开浏览器进行搜索。 19 | 20 | ![img](./img/2.gif?raw=true) 21 | 22 | ## 翻译 23 | 24 | 你可以在编辑器中,选中代码中对应的关键词,然后点击鼠标右键,在出现的菜单面板中选择 `Traslate Online` 菜单项,插件会自动帮你打开默认浏览器,并进入谷歌翻译搜索,搜索对应的关键词的翻译结果。 25 | 26 | 你还可以选中对应的关键词后,使用快捷键 `cmd+shift+enter(mac) / ctrl+shift+enter(win)` 去打开浏览器进行翻译。 27 | 28 | ![img](./img/1.gif?raw=true) 29 | 30 | 支持离线词典的搜索,只需打开设置 `search-online.show-status-bar` 为 `true` 把开关打开(默认关闭),选中代码中的关键词,翻译结果会出现在底部栏右下角,如果你想查看更详细的翻译结果,可以点击底部栏右下角的中文翻译结果,此时会打开你的默认浏览器进行线上翻译。 31 | 32 | ```json 33 | { 34 | "search-online.show-status-bar": true 35 | } 36 | ``` 37 | 38 | ![img](./img/8.png?raw=true) 39 | 40 | # 切换搜索引擎 41 | 42 | 如果你有需要,你可以切换不同的搜索引擎,只需要点击在编辑器底部栏右侧 `Search Engine`,然后在弹窗选项中选择你需要的搜索引擎即可切换。 43 | 44 | ![img](./img/3.gif?raw=true) 45 | 46 | 你还可以在右键菜单栏中选择 `Search Online By Switch Engine`菜单项,直接切换对应的搜索引擎进行搜索。 47 | 48 | ![img](./img/4.gif?raw=true) 49 | 50 | 如果预设的搜索引擎地址不能满足你的使用,你可以手动更新搜索引擎地址,进入插件的 `Extesion Settings` 里设置即可。 51 | 52 | ![img](./img/5.png?raw=true) 53 | 54 | 默认的各搜索引擎地址格式如下: 55 | 56 | > 注意:使用 `%SELECTION%` 来替换搜索引擎选中的关键词. 57 | 58 | | Engine | Url | 59 | | ------------ | ----------------------------------------------- | 60 | | Google | https://www.google.com/search?q=%SELECTION% | 61 | | Bing | https://www.bing.com/search?q=%SELECTION% | 62 | | Github | https://www.github.com/search?q=%SELECTION% | 63 | | Baidu | https://www.baidu.com/search?q=%SELECTION% | 64 | | Npm | https://www.npmjs.com/search?q=%SELECTION% | 65 | | Yahoo | https://search.yahoo.com/search?p=%SELECTION% | 66 | | Wiki | https://wikipedia.org/wiki/%SELECTION% | 67 | | Duck | https://duckduckgo.com/?q=%SELECTION% | 68 | | Code Pen | https://codepen.io/search/pens?q=%SELECTION% | 69 | | Code Sandbox | https://codesandbox.io/search?query=%SELECTION% | 70 | 71 | 你还可以通过修改 `.vscode/setting.json` 文件,来设置默认搜索引擎,例如修改 `search-online.search-engine` 的配置参数为 `Bing`,即可使用 `Bing` 作为默认搜索引擎来搜索。 72 | 73 | ```json 74 | { 75 | "search-online.search-engine": "Bing" 76 | } 77 | ``` 78 | 79 | 通过更改 `.vscode/setting.json` 文件的 `search-online.add-search-engine` 的配置参数,可以添加额外的搜索引擎。 80 | 81 | ```json 82 | { 83 | "search-online.add-search-engine": [ 84 | { 85 | "name": "Visual Studio Marketplace", 86 | "url": "https://marketplace.visualstudio.com/search?term=%SELECTION%&target=VSCode" 87 | }, 88 | { 89 | "name": "Pypi", 90 | "url": "https://pypi.org/search/?q=%SELECTION%" 91 | } 92 | ] 93 | } 94 | ``` 95 | 96 | 你还可以通过可视化界面来增加搜索引擎,在切换引擎的面板底部点击 `➕ Add Search Engine`,然后会出现两次输入框,分别填入如以下内容,即可增加搜索引擎 ↓ 97 | 98 | > name: Visual Studio Marketplace 99 | 100 | > url: https://marketplace.visualstudio.com/search?term=%SELECTION%&target=VSCode 101 | 102 | ![img](./img/6.png?raw=true) 103 | 104 | # 切换翻译引擎 105 | 106 | 你在设置面板更改需要翻译的语言,默认设置是英文翻译成中文。 107 | 108 | ![img](./img/7.png?raw=true) 109 | 110 | # 鸣谢 111 | 112 |
开发团队 113 | 114 | | [
Eno Yao](https://github.com/Wscats) | [
中文编程](https://github.com/program-in-chinese) | 115 | | - | - | 116 | 117 |
118 | 119 | 如果插件对您有帮助,恳请您在 [**插件商城**](https://marketplace.visualstudio.com/items?itemName=Wscats.search&ssr=false#review-details) 中给我们一个五星好评,您的鼓励是我前进的最大动力! 120 | 121 | 如果您有任何问题和建议,您可以进入该 [**链接**](https://github.com/Wscats/search-online/issues/new) 留言,我会尽快回复您。 122 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | 8 | import * as vscode from 'vscode'; 9 | import * as fs from "fs"; 10 | import * as os from "os"; 11 | import opn from './open'; 12 | import { languageConfig } from "./language"; 13 | import { browserConfig } from './browser'; 14 | 15 | export interface Iengine { name: string, url: string } 16 | 17 | export const getEngines = (): string[] => { 18 | const config = vscode.workspace.getConfiguration("search-online"); 19 | const engineAddedConfig = config.get("add-search-engine"); 20 | const engineAdded = engineAddedConfig?.filter((engineItem: Iengine) => { 21 | if (engineItem?.name && engineItem?.url) { 22 | return engineItem; 23 | } 24 | }).map((engineItem: Iengine) => { 25 | return engineItem.name; 26 | }) 27 | if (engineAdded) { 28 | return ["Google", "Bing", "Baidu", "Npm", "Github", "Stack Overflow", "Google Translate", "Yahoo", "Wiki", "Code Pen", "Code Sandbox", ...engineAdded, "➕ Add Search Engine"]; 29 | } else { 30 | return ["Google", "Bing", "Baidu", "Npm", "Github", "Stack Overflow", "Google Translate", "Yahoo", "Wiki", "Code Pen", "Code Sandbox", "➕ Add Search Engine"]; 31 | } 32 | 33 | }; 34 | 35 | export const setEngines = async () => { 36 | const config = vscode.workspace.getConfiguration("search-online"); 37 | const engineAddedConfig = config.get("add-search-engine"); 38 | const engineName = await vscode.window.showInputBox({ 39 | "prompt": "Set your search engine name -> like: Google" 40 | }); 41 | const engineUrl = await vscode.window.showInputBox({ 42 | "prompt": "Set your search engine address -> like: https://www.google.com/search?q=%SELECTION%" 43 | }); 44 | if (!engineName || !engineUrl) { 45 | return; 46 | } 47 | const newEngine: Iengine = { name: engineName, url: engineUrl }; 48 | const newEngines = engineAddedConfig && [newEngine, ...engineAddedConfig]; 49 | config.update("add-search-engine", newEngines); 50 | return { newEngine, newEngines }; 51 | } 52 | 53 | export const standardizedBrowserName = (name: string = ''): string => { 54 | let _name = name.toLowerCase(); 55 | const browser = browserConfig.browsers.find(item => { 56 | return item.acceptName.indexOf(_name) !== -1; 57 | }); 58 | return browser ? browser.standardName : ''; 59 | }; 60 | 61 | export const defaultBrowser = (): string => { 62 | const config = vscode.workspace.getConfiguration(browserConfig.app); 63 | return config ? config.default : ''; 64 | }; 65 | 66 | export const open = (path: string, browser: string | string[]) => { 67 | opn(path, { app: browser }).catch((err: any) => { 68 | vscode.window.showErrorMessage(`Open browser failed!! Please check if you have installed the browser ${browser} correctly!`); 69 | }); 70 | }; 71 | 72 | export const openBrowser = (path: any): void => { 73 | const browser = standardizedBrowserName(defaultBrowser()); 74 | open(path, browser); 75 | }; 76 | 77 | let isDocker: boolean; 78 | export const docker = () => { 79 | const hasDockerEnv = () => { 80 | try { 81 | fs.statSync('/.dockerenv'); 82 | return true; 83 | } catch (_) { 84 | return false; 85 | } 86 | } 87 | const hasDockerCGroup = () => { 88 | try { 89 | return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker'); 90 | } catch (_) { 91 | return false; 92 | } 93 | } 94 | if (isDocker === undefined) { 95 | isDocker = hasDockerEnv() || hasDockerCGroup(); 96 | } 97 | return isDocker; 98 | }; 99 | 100 | const wsll = () => { 101 | if (process.platform !== 'linux') { 102 | return false; 103 | } 104 | if (os.release().toLowerCase().includes('microsoft')) { 105 | if (docker()) { 106 | return false; 107 | } 108 | return true; 109 | } 110 | try { 111 | return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft') ? 112 | !docker() : false; 113 | } catch (_) { 114 | return false; 115 | } 116 | }; 117 | 118 | export const wsl = process.env.__IS_WSL_TEST__ ? wsll : wsll(); 119 | 120 | export const getSelectedText = () => { 121 | const documentText = vscode.window.activeTextEditor?.document.getText(); 122 | if (!documentText) { 123 | return ""; 124 | } 125 | const activeSelection = vscode.window.activeTextEditor?.selection; 126 | if (activeSelection?.isEmpty) { 127 | return ""; 128 | } 129 | const selectStartOffset = vscode.window.activeTextEditor?.document.offsetAt( 130 | activeSelection?.start as vscode.Position 131 | ); 132 | const selectEndOffset = vscode.window.activeTextEditor?.document.offsetAt( 133 | activeSelection?.end as vscode.Position 134 | ); 135 | 136 | let selectedText = documentText.slice(selectStartOffset, selectEndOffset).trim(); 137 | selectedText = selectedText.replace(/\s\s+/g, " "); 138 | return selectedText; 139 | } 140 | 141 | export const getLanguageCode = (languageKey: string) => { 142 | return languageConfig[languageKey]; 143 | } -------------------------------------------------------------------------------- /src/open.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | import { promisify } from "util"; 8 | import * as path from "path"; 9 | import * as fs from "fs"; 10 | import * as childProcess from "child_process"; 11 | import { docker, wsl } from './util'; 12 | 13 | const pAccess = promisify(fs.access); 14 | const pExecFile = promisify(childProcess.execFile); 15 | 16 | const localXdgOpenPath = path.join(__dirname, 'xdg-open'); 17 | 18 | const wslToWindowsPath = async (path: string) => { 19 | const { stdout } = await pExecFile('wslpath', ['-w', path]); 20 | return stdout.trim(); 21 | }; 22 | 23 | const windowsToWslPath = async (path: string) => { 24 | const { stdout } = await pExecFile('wslpath', [path]); 25 | return stdout.trim(); 26 | }; 27 | 28 | const wslGetWindowsEnvVar = async (envVar: string) => { 29 | const { stdout } = await pExecFile('wslvar', [envVar]); 30 | return stdout.trim(); 31 | }; 32 | 33 | export default async (target: string, options: any) => { 34 | if (typeof target !== 'string') { 35 | throw new TypeError('Expected a `target`'); 36 | } 37 | 38 | options = { 39 | wait: false, 40 | background: false, 41 | allowNonzeroExitCode: false, 42 | ...options 43 | }; 44 | 45 | let command; 46 | let { app } = options; 47 | let appArguments = []; 48 | const cliArguments = []; 49 | const childProcessOptions: any = {}; 50 | 51 | if (Array.isArray(app)) { 52 | appArguments = app.slice(1); 53 | app = app[0]; 54 | } 55 | 56 | if (process.platform === 'darwin') { 57 | command = 'open'; 58 | 59 | if (options.wait) { 60 | cliArguments.push('--wait-apps'); 61 | } 62 | 63 | if (options.background) { 64 | cliArguments.push('--background'); 65 | } 66 | 67 | if (app) { 68 | cliArguments.push('-a', app); 69 | } 70 | } else if (process.platform === 'win32' || (wsl && !docker())) { 71 | const windowsRoot = wsl ? await wslGetWindowsEnvVar('systemroot') : process.env.SYSTEMROOT; 72 | command = String.raw`${windowsRoot}\System32\WindowsPowerShell\v1.0\powershell${wsl ? '.exe' : ''}`; 73 | cliArguments.push( 74 | '-NoProfile', 75 | '-NonInteractive', 76 | '–ExecutionPolicy', 77 | 'Bypass', 78 | '-EncodedCommand' 79 | ); 80 | 81 | if (wsl) { 82 | command = await windowsToWslPath(command); 83 | } else { 84 | childProcessOptions.windowsVerbatimArguments = true; 85 | } 86 | 87 | const encodedArguments = ['Start']; 88 | 89 | if (options.wait) { 90 | encodedArguments.push('-Wait'); 91 | } 92 | 93 | if (app) { 94 | if (wsl && app.startsWith('/mnt/')) { 95 | const windowsPath = await wslToWindowsPath(app); 96 | app = windowsPath; 97 | } 98 | 99 | encodedArguments.push(`"\`"${app}\`""`, '-ArgumentList'); 100 | appArguments.unshift(target); 101 | } else { 102 | encodedArguments.push(`"\`"${target}\`""`); 103 | } 104 | 105 | if (appArguments.length > 0) { 106 | appArguments = appArguments.map(arg => `"\`"${arg}\`""`); 107 | encodedArguments.push(appArguments.join(',')); 108 | } 109 | 110 | target = Buffer.from(encodedArguments.join(' '), 'utf16le').toString('base64'); 111 | } else { 112 | if (app) { 113 | command = app; 114 | } else { 115 | const isBundled = !__dirname || __dirname === '/'; 116 | 117 | let exeLocalXdgOpen = false; 118 | try { 119 | await pAccess(localXdgOpenPath, fs.constants.X_OK); 120 | exeLocalXdgOpen = true; 121 | } catch (_) { } 122 | 123 | const useSystemXdgOpen = (process.versions as any).electron || 124 | process.platform === 'android' || isBundled || !exeLocalXdgOpen; 125 | command = useSystemXdgOpen ? 'xdg-open' : localXdgOpenPath; 126 | } 127 | 128 | if (appArguments.length > 0) { 129 | cliArguments.push(...appArguments); 130 | } 131 | 132 | if (!options.wait) { 133 | childProcessOptions.stdio = 'ignore'; 134 | childProcessOptions.detached = true; 135 | } 136 | } 137 | 138 | cliArguments.push(target); 139 | 140 | if (process.platform === 'darwin' && appArguments.length > 0) { 141 | cliArguments.push('--args', ...appArguments); 142 | } 143 | 144 | const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions); 145 | 146 | if (options.wait) { 147 | return new Promise((resolve, reject) => { 148 | subprocess.once('error', reject); 149 | 150 | subprocess.once('close', (exitCode: number) => { 151 | if (options.allowNonzeroExitCode && exitCode > 0) { 152 | reject(new Error(`Exited with code ${exitCode}`)); 153 | return; 154 | } 155 | 156 | resolve(subprocess); 157 | }); 158 | }); 159 | } 160 | subprocess.unref(); 161 | return subprocess; 162 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Feature 2 | 3 | Download 4 | Macketplace 5 | Github Page 6 | Eno Yao 7 | 8 | [English](https://github.com/Wscats/search-online/blob/master/README.md) | [中文](https://gitee.com/wscats/search-online/blob/master/README.CN.md) 9 | 10 | A simple extension for VSCode to search or translate online easily using different engine. 11 | 12 | # How To Use 13 | 14 | ## Search 15 | 16 | You can select a keyword in the code, right-click to open the drop-down menu, select `Search Online`, it will automatically open the browser for you and search for related content. 17 | 18 | Or select a keyword in the code, use the shortcut key `cmd+enter(mac)` / `ctrl+enter(win)` to open the browser search results. 19 | 20 | 21 | 22 | ![2](https://user-images.githubusercontent.com/17243165/100498121-06e07f80-319b-11eb-90d5-68ab242824f1.gif) 23 | 24 | ## Translate 25 | 26 | You can select a keyword in the code, right-click the drop-down menu and select `Traslate Online`, it will automatically open the browser and use Google Translate to help you translate the content. 27 | 28 | Or select a keyword in the code, use the shortcut key `cmd+shift+enter(mac) / ctrl+shift+enter(win)` to translate the content. 29 | 30 | 31 | 32 | ![1](https://user-images.githubusercontent.com/17243165/100498131-152e9b80-319b-11eb-82d1-4296aaf9f12f.gif) 33 | 34 | Support offline dictionary search, select keywords in the code, the translation results will appear in the lower right corner of the bottom bar, if you want to view more detailed translation results, you can click the chinese translation results in the lower right corner of the bottom bar, and your default browser for online translation. 35 | 36 | ```json 37 | { 38 | "search-online.show-status-bar": true 39 | } 40 | ``` 41 | 42 | ![8](https://user-images.githubusercontent.com/17243165/100809200-92def980-3470-11eb-8daf-f7f950e8d69c.png) 43 | 44 | # Switch Search Engine 45 | 46 | You can switch between different search engines according to your needs, just click `Search Engine` in the bottom bar of vscode, and you can switch search engines. Google search used by the search engine by default. 47 | 48 | 49 | 50 | ![3](https://user-images.githubusercontent.com/17243165/100498140-24154e00-319b-11eb-94f6-a2c14d33863c.gif) 51 | 52 | Or, you can right-click to open the drop-down menu after selecting the keywords, and click `Search Online By Switch Engine`, you can switch the engine to search results. 53 | 54 | 55 | 56 | ![4](https://user-images.githubusercontent.com/17243165/100498152-35f6f100-319b-11eb-8e96-fef096c8c75f.gif) 57 | 58 | If necessary, you can change the request address of the search engine. 59 | 60 | 61 | 5 62 | 63 | The default request address format for each search is as follows. Note that the keywords searched in the link use `%SELECTION%` instead. 64 | 65 | | Engine | Url | 66 | | ------------ | ----------------------------------------------- | 67 | | Google | https://www.google.com/search?q=%SELECTION% | 68 | | Bing | https://www.bing.com/search?q=%SELECTION% | 69 | | Github | https://www.github.com/search?q=%SELECTION% | 70 | | Baidu | https://www.baidu.com/search?q=%SELECTION% | 71 | | Npm | https://www.npmjs.com/search?q=%SELECTION% | 72 | | Yahoo | https://search.yahoo.com/search?p=%SELECTION% | 73 | | Wiki | https://wikipedia.org/wiki/%SELECTION% | 74 | | Duck | https://duckduckgo.com/?q=%SELECTION% | 75 | | Code Pen | https://codepen.io/search/pens?q=%SELECTION% | 76 | | Code Sandbox | https://codesandbox.io/search?query=%SELECTION% | 77 | 78 | Or modify the `.vscode/setting.json` file to change the default search engine. For example, modify to the following configuration, then every time you click on `Search Online`, you will use `Bing` to search for related content. 79 | 80 | ```json 81 | { 82 | "search-online.search-engine": "Bing" 83 | } 84 | ``` 85 | 86 | Or modify the `.vscode/setting.json` file to add a new search engine. For example, by modifying `.vscode/setting.json` below, two new search engines, Visual Studio Marketplace and Pypi, are added. 87 | 88 | ```json 89 | { 90 | "search-online.add-search-engine": [ 91 | { 92 | "name": "Visual Studio Marketplace", 93 | "url": "https://marketplace.visualstudio.com/search?term=%SELECTION%&target=VSCode" 94 | }, 95 | { 96 | "name": "Pypi", 97 | "url": "https://pypi.org/search/?q=%SELECTION%" 98 | } 99 | ] 100 | } 101 | ``` 102 | 103 | You can also use the add search engine option to manually add a search engine, you need to provide the name and search address, for example↓. 104 | 105 | > name: Visual Studio Marketplace 106 | 107 | > url: https://marketplace.visualstudio.com/search?term=%SELECTION%&target=VSCode 108 | 109 | 110 | 6 111 | 112 | # Switch Language Engine 113 | 114 | You can change the translation language configuration item of the extension to help you translate different texts. 115 | 116 | 117 | 7 118 | 119 | # Thanks 120 | 121 |
Development Team 122 | 123 | | [
Eno Yao](https://github.com/Wscats) | [
中文编程](https://github.com/program-in-chinese) | 124 | | - | - | 125 | 126 |
127 | 128 | If the extension can help you, please enter the [Rating & Review](https://marketplace.visualstudio.com/items?itemName=Wscats.search&ssr=false#review-details) link to give me a five-star praise. 129 | 130 | If you have any questions or suggestions during use, please leave a message in the [issue](https://github.com/Wscats/search-online/issues/new). 131 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 1998 - 2020 Tencent. All Rights Reserved. 3 | * 4 | * @author enoyao 5 | */ 6 | 7 | import * as vscode from "vscode"; 8 | import { StatusBarUi } from './status'; 9 | import { openBrowser, getSelectedText, getEngines, Iengine, setEngines, getLanguageCode } from './util'; 10 | import { workspace, languages, window, commands, ExtensionContext, Disposable, StatusBarAlignment } from 'vscode'; 11 | import 内容提供器, { encodeLocation } from './offline/整文件翻译'; 12 | import * as 模型 from './offline/翻译/数据类型' 13 | import * as 查词 from './offline/查词'; 14 | 15 | interface SearchType { 16 | searchType: string; 17 | }; 18 | 19 | export function activate(context: vscode.ExtensionContext) { 20 | const searchOnline = vscode.commands.registerTextEditorCommand("extension.search-online", () => { search({ searchType: "default" }) }); 21 | const switchSearchOnline = vscode.commands.registerTextEditorCommand("extension.search-switch", () => { search({ searchType: "switch" }) }); 22 | const searchTranslate = vscode.commands.registerTextEditorCommand("extension.search-translate", () => { search({ searchType: "translate" }) }); 23 | const searchEngine = vscode.commands.registerCommand("extension.search-engine", engine); 24 | 25 | const 提供器 = new 内容提供器(); 26 | 27 | const 提供器注册 = Disposable.from( 28 | workspace.registerTextDocumentContentProvider(内容提供器.scheme, 提供器) 29 | ); 30 | 31 | const 命令注册 = commands.registerTextEditorCommand('editor.批量翻译标识符', 编辑器 => { 32 | const uri = encodeLocation(编辑器.document.uri, 编辑器.selection.active); 33 | // @ts-ignore 34 | return workspace.openTextDocument(uri).then(代码文件 => window.showTextDocument(代码文件, 编辑器.viewColumn + 1)); 35 | }); 36 | 37 | const 状态框 = window.createStatusBarItem(StatusBarAlignment.Right, 100); 38 | 状态框.command = 'extension.翻译选中文本'; 39 | context.subscriptions.push( 40 | 提供器, 41 | 命令注册, 42 | 提供器注册, 43 | 状态框 44 | ); 45 | 46 | context.subscriptions.push(window.onDidChangeActiveTextEditor(e => 更新状态栏(状态框))); 47 | context.subscriptions.push(window.onDidChangeTextEditorSelection(e => 更新状态栏(状态框))); 48 | context.subscriptions.push(window.onDidChangeTextEditorViewColumn(e => 更新状态栏(状态框))); 49 | context.subscriptions.push(workspace.onDidOpenTextDocument(e => 更新状态栏(状态框))); 50 | context.subscriptions.push(workspace.onDidCloseTextDocument(e => 更新状态栏(状态框))); 51 | 52 | context.subscriptions.push(commands.registerCommand('extension.翻译选中文本', async () => { 53 | // TODO: 避免重复查询(状态框查询一次即可?) 54 | let 文本 = 取选中文本(); 55 | if (文本) { 56 | // const translateEngines = await vscode.window.showQuickPick(["Google Translate", "Baidu Translate"]); 57 | search({ searchType: "translate" }); 58 | let 显示 = 显示字段信息(查询词条(文本)); 59 | window.showInformationMessage(显示词条(显示, 1000)); 60 | } 61 | })); 62 | 63 | 更新状态栏(状态框); 64 | 65 | context.subscriptions.push(searchEngine); 66 | context.subscriptions.push(switchSearchOnline); 67 | context.subscriptions.push(searchOnline); 68 | context.subscriptions.push(searchTranslate); 69 | StatusBarUi.init(); 70 | } 71 | 72 | export function deactivate() { StatusBarUi.dispose() }; 73 | 74 | async function engine() { 75 | const engine = await vscode.window.showQuickPick(getEngines()); 76 | if (engine === "➕ Add Search Engine") { 77 | setEngines(); 78 | } else { 79 | const config = vscode.workspace.getConfiguration("search-online"); 80 | config.update("search-engine", engine); 81 | engine && StatusBarUi.setEngine(engine); 82 | } 83 | } 84 | 85 | async function search({ searchType }: SearchType) { 86 | const selectedText = getSelectedText(); 87 | if (!selectedText) { 88 | return; 89 | } 90 | const urlQuery = encodeURI(selectedText); 91 | const config = vscode.workspace.getConfiguration("search-online"); 92 | let engine: string | undefined; 93 | let engineAddedConfig: Iengine[] | undefined; 94 | let traslateIutput: string | undefined; 95 | let traslateOutput: string | undefined; 96 | let traslateIntputCode: string = "en"; 97 | let traslateOutputCode: string = "zh-CN"; 98 | switch (searchType) { 99 | case "switch": 100 | engine = await vscode.window.showQuickPick(getEngines()); 101 | if (engine === "➕ Add Search Engine") { 102 | const newEngineConfig = await setEngines(); 103 | engine = newEngineConfig?.newEngine.name; 104 | engineAddedConfig = newEngineConfig?.newEngines; 105 | } 106 | if (!engine) { 107 | return; 108 | } 109 | break; 110 | case "translate": 111 | engine = 'Google Translate'; 112 | traslateIutput = config.get("Google Translate Input Language"); 113 | traslateOutput = config.get("Google Translate Output Language"); 114 | traslateIntputCode = traslateIutput ? getLanguageCode(traslateIutput) : "en"; 115 | traslateOutputCode = traslateOutput ? getLanguageCode(traslateOutput) : "zh-CN"; 116 | break; 117 | default: 118 | engine = config.get("search-engine"); 119 | break; 120 | }; 121 | if (!engineAddedConfig) { 122 | engineAddedConfig = config.get("add-search-engine"); 123 | } 124 | const engineAddedFilter = engineAddedConfig?.filter((engineItem: Iengine) => { 125 | if (engineItem.name === engine) { 126 | return engineItem; 127 | } 128 | }) 129 | if (engineAddedFilter && engineAddedFilter?.length > 0) { 130 | const uriTemplate = engineAddedFilter[0].url; 131 | const url = uriTemplate?.replace("%SELECTION%", urlQuery).replace("%INPUT_LANGUAGE%", traslateIntputCode).replace("%OUTPUT_LANGUAGE%", traslateOutputCode); 132 | openBrowser(url); 133 | } else { 134 | const uriTemplate: string | undefined = engine && config.get(engine); 135 | const url = uriTemplate?.replace("%SELECTION%", urlQuery).replace("%INPUT_LANGUAGE%", traslateIntputCode).replace("%OUTPUT_LANGUAGE%", traslateOutputCode); 136 | url && openBrowser(url); 137 | } 138 | } 139 | 140 | // @ts-ignore 141 | function 更新状态栏(状态框) { 142 | // 是否显示右下角的提示条,默认不显示 143 | const config = vscode.workspace.getConfiguration("search-online"); 144 | const isShowStatusBar = config.get("show-status-bar"); 145 | if (!isShowStatusBar) { 146 | 状态框.hide(); 147 | return; 148 | } 149 | 150 | let 文本 = 取选中文本(); 151 | if (文本) { 152 | 状态框.text = "$(megaphone) " + 显示词条(显示简要信息(查询词条(文本)), 30); 153 | 状态框.show(); 154 | } else { 155 | 状态框.hide(); 156 | } 157 | } 158 | 159 | // @ts-ignore 160 | function 取选中文本(): string { 161 | const 当前编辑器 = window.activeTextEditor; 162 | if (当前编辑器) { 163 | const 选中部分 = 当前编辑器.selection; 164 | return 当前编辑器.document.getText(选中部分); 165 | } 166 | } 167 | 168 | function 查询词条(英文: string): 模型.字段释义 { 169 | return 查词.取释义(英文); 170 | } 171 | 172 | function 显示词条(显示: any, 最大长度: number): string { 173 | return 显示.length > 最大长度 ? 显示.substring(0, 最大长度 - 1) + "..." : 显示; 174 | } 175 | 176 | function 显示简要信息(查字段结果: 模型.字段释义): string { 177 | if (!查字段结果.释义) { 178 | return "查无结果: " + 查字段结果.原字段; 179 | } 180 | if (查字段结果.各词.length == 1) { 181 | return 取单词条信息(查字段结果.各词[0], false); 182 | } else { 183 | return 查字段结果.释义; 184 | } 185 | } 186 | 187 | function 显示字段信息(查字段结果: 模型.字段释义): string { 188 | // 长度必大于0 189 | if (查字段结果.各词.length == 1) { 190 | return 取单词条信息(查字段结果.各词[0], true); 191 | } else { 192 | let 翻译 = ""; 193 | for (let 单词结果 of 查字段结果.各词) { 194 | 翻译 += 取单词条信息(单词结果, true, false); 195 | } 196 | return 翻译; 197 | } 198 | } 199 | 200 | function 取单词条信息(查词结果: 模型.单词条, 显示原词: boolean = false, 显示词形: boolean = true): string { 201 | let 显示 = 显示原词 ? "【" + 查词结果.词 + "】" : ""; 202 | let 释义 = 查词结果.释义; 203 | if (释义) { 204 | 显示 += " " + 释义.split('\\n').join(" "); 205 | } 206 | 207 | let 词形 = 查词结果.词形; 208 | if (显示词形 && 词形.length > 0) { 209 | let 词形显示 = ""; 210 | for (let 某词形 of 词形) { 211 | 词形显示 += 某词形.类型 + ": " + 某词形.变化 + "; "; 212 | } 213 | 显示 += " " + 词形显示; 214 | } 215 | return 显示; 216 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "search", 3 | "displayName": "Search/Translate Hero - Google/Translate/Bing/Baidu/Wiki/Yahoo/Github/Npm Engine", 4 | "description": "🔍Support search online or translate online/offline.", 5 | "version": "1.0.37", 6 | "engines": { 7 | "vscode": "^1.51.0" 8 | }, 9 | "publisher": "Wscats", 10 | "categories": [ 11 | "Other", 12 | "Programming Languages", 13 | "Formatters" 14 | ], 15 | "author": { 16 | "name": "Eno Yao", 17 | "url": "https://github.com/Wscats/search-online" 18 | }, 19 | "galleryBanner": { 20 | "color": "#232323", 21 | "theme": "dark" 22 | }, 23 | "icon": "img/icon.png", 24 | "homepage": "https://github.com/Wscats/search-online", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/Wscats/search-online" 28 | }, 29 | "keywords": [ 30 | "search", 31 | "google", 32 | "translate", 33 | "google translate", 34 | "stackoverflow", 35 | "duckduckgo", 36 | "baidu", 37 | "vscode", 38 | "codepen", 39 | "codesandbox", 40 | "bing", 41 | "github", 42 | "npm", 43 | "pypi", 44 | "yahoo", 45 | "wiki", 46 | "engine", 47 | "dictionary", 48 | "Chinese", 49 | "English", 50 | "搜索", 51 | "翻译", 52 | "offline", 53 | "online" 54 | ], 55 | "activationEvents": [ 56 | "onStartupFinished", 57 | "onCommand:extension.search-online", 58 | "onCommand:extension.search-engine", 59 | "onCommand:extension.search-switch", 60 | "onCommand:extension.search-translate" 61 | ], 62 | "main": "./out/extension.js", 63 | "contributes": { 64 | "menus": { 65 | "editor/context": [ 66 | { 67 | "when": "editorHasSelection", 68 | "command": "extension.search-online", 69 | "group": "navigation" 70 | }, 71 | { 72 | "when": "editorHasSelection", 73 | "command": "extension.search-translate", 74 | "group": "navigation" 75 | }, 76 | { 77 | "when": "editorHasSelection", 78 | "command": "extension.search-switch", 79 | "group": "navigation" 80 | } 81 | ] 82 | }, 83 | "keybindings": [ 84 | { 85 | "when": "editorHasSelection", 86 | "command": "extension.search-online", 87 | "key": "ctrl+enter cmd+enter", 88 | "mac": "cmd+enter", 89 | "win": "ctrl+enter" 90 | }, 91 | { 92 | "when": "editorHasSelection", 93 | "command": "extension.search-translate", 94 | "key": "ctrl+shift+enter cmd+shift+enter", 95 | "mac": "cmd+shift+enter", 96 | "win": "ctrl+shift+enter" 97 | } 98 | ], 99 | "commands": [ 100 | { 101 | "command": "extension.search-online", 102 | "title": "Search Online" 103 | }, 104 | { 105 | "command": "extension.search-translate", 106 | "title": "Translate Online" 107 | }, 108 | { 109 | "command": "extension.search-switch", 110 | "title": "Search Online By Switch Engine" 111 | } 112 | ], 113 | "configuration": { 114 | "title": "Search Online Config", 115 | "type": "object", 116 | "properties": { 117 | "search-online.show-status-bar": { 118 | "type": "boolean", 119 | "default": false, 120 | "description": "Show/Hide Status Bar" 121 | }, 122 | "search-online.search-engine": { 123 | "type": "string", 124 | "enum": [ 125 | "Google", 126 | "Bing", 127 | "Baidu", 128 | "Npm", 129 | "Github", 130 | "Google Translate" 131 | ], 132 | "default": "Google", 133 | "description": "Search Engine" 134 | }, 135 | "search-online.Google": { 136 | "type": "string", 137 | "default": "https://www.google.com/search?q=%SELECTION%", 138 | "description": "Google Search Engine" 139 | }, 140 | "search-online.Bing": { 141 | "type": "string", 142 | "default": "https://www.bing.com/search?q=%SELECTION%", 143 | "description": "Bing Search Engine" 144 | }, 145 | "search-online.Baidu": { 146 | "type": "string", 147 | "default": "https://www.baidu.com/s?wd=%SELECTION%", 148 | "description": "Baidu Search Engine" 149 | }, 150 | "search-online.Npm": { 151 | "type": "string", 152 | "default": "https://www.npmjs.com/search?q=%SELECTION%", 153 | "description": "Npm Search Engine" 154 | }, 155 | "search-online.Github": { 156 | "type": "string", 157 | "default": "https://github.com/search?q=%SELECTION%", 158 | "description": "Github Search Engine" 159 | }, 160 | "search-online.Stack Overflow": { 161 | "type": "string", 162 | "default": "https://stackoverflow.com/search?q=%SELECTION%", 163 | "description": "Stack Overflow Engine" 164 | }, 165 | "search-online.Google Translate": { 166 | "type": "string", 167 | "default": "https://translate.google.cn/?sl=%INPUT_LANGUAGE%&tl=%OUTPUT_LANGUAGE%&text=%SELECTION%&op=translate", 168 | "description": "Google Translate Engine" 169 | }, 170 | "search-online.Yahoo": { 171 | "type": "string", 172 | "default": "https://search.yahoo.com/search?p=%SELECTION%", 173 | "description": "Yahoo Engine" 174 | }, 175 | "search-online.Wiki": { 176 | "type": "string", 177 | "default": "https://wikipedia.org/wiki/%SELECTION%", 178 | "description": "Wiki Engine" 179 | }, 180 | "search-online.Code Pen": { 181 | "type": "string", 182 | "default": "https://codepen.io/search/pens?q=%SELECTION%", 183 | "description": "Code Pen Engine" 184 | }, 185 | "search-online.Code Sandbox": { 186 | "type": "string", 187 | "default": "https://codesandbox.io/search?query=%SELECTION%", 188 | "description": "Code Sandbox Engine" 189 | }, 190 | "search-online.Google Translate Input Language": { 191 | "type": "string", 192 | "enum": [ 193 | "English/英语", 194 | "Chinese/中文", 195 | "Japanese/日语", 196 | "Albanian/阿尔巴尼亚语", 197 | "Arabic/阿拉伯语", 198 | "Amharic/阿姆哈拉语", 199 | "Azerbaijani/阿塞拜疆语", 200 | "Irish/爱尔兰语", 201 | "Estonian/爱沙尼亚语", 202 | "Oriya/奥利亚语", 203 | "Basque/巴斯克语", 204 | "Belarusian/白俄罗斯语", 205 | "Bulgarian/保加利亚语", 206 | "Icelandic/冰岛语", 207 | "Polish/波兰语", 208 | "Bosnian/波斯尼亚语", 209 | "Persian/波斯语", 210 | "Boolean (Afrikaans)/布尔语(南非荷兰语)", 211 | "Tatar/鞑靼语", 212 | "Danish/丹麦语", 213 | "German/德语", 214 | "Russian/俄语", 215 | "French/法语", 216 | "Filipino/菲律宾语", 217 | "Finnish/芬兰语", 218 | "Frisian/弗里西语", 219 | "Khmer/高棉语", 220 | "Georgian/格鲁吉亚语", 221 | "Gujarati/古吉拉特语", 222 | "Kazakh/哈萨克语", 223 | "Haiti Creole/海地克里奥尔语", 224 | "Korean/韩语", 225 | "Hausa/豪萨语", 226 | "Dutch/荷兰语", 227 | "Kyrgyz/吉尔吉斯语", 228 | "Galician/加利西亚语", 229 | "Catalan/加泰罗尼亚语", 230 | "Czech/捷克语", 231 | "Kannada/卡纳达语", 232 | "Corsican/科西嘉语", 233 | "Croatian/克罗地亚语", 234 | "Kurdish/库尔德语", 235 | "Latin/拉丁语", 236 | "Latvian/拉脱维亚语", 237 | "Laotian/老挝语", 238 | "Lithuanian/立陶宛语", 239 | "Luxembourgish/卢森堡语", 240 | "Rwandan/卢旺达语", 241 | "Romanian/罗马尼亚语", 242 | "Malagasy/马尔加什语", 243 | "Maltese/马耳他语", 244 | "Marathi/马拉地语", 245 | "Malayalam/马拉雅拉姆语", 246 | "Malay/马来语", 247 | "Macedonian/马其顿语", 248 | "Maori/毛利语", 249 | "Mongolian/蒙古语", 250 | "Bengali/孟加拉语", 251 | "Burmese/缅甸语", 252 | "Miao language/苗语", 253 | "South African Xhosa/南非科萨语", 254 | "South African Zulu/南非祖鲁语", 255 | "Nepalese/尼泊尔语", 256 | "Norwegian/挪威语", 257 | "Punjabi/旁遮普语", 258 | "Portuguese/葡萄牙语", 259 | "Pashto/普什图语", 260 | "Chichewa/齐切瓦语", 261 | "Swedish/瑞典语", 262 | "Samoan/萨摩亚语", 263 | "Serbian/塞尔维亚语", 264 | "Sesotho/塞索托语", 265 | "Sinhala/僧伽罗语", 266 | "Esperanto/世界语", 267 | "Slovak/斯洛伐克语", 268 | "Slovenian/斯洛文尼亚语", 269 | "Swahili/斯瓦希里语", 270 | "Scottish Gaelic/苏格兰盖尔语", 271 | "Cebuano/宿务语", 272 | "Somali/索马里语", 273 | "Tajik/塔吉克语", 274 | "Telugu/泰卢固语", 275 | "Tamil/泰米尔语", 276 | "Thai/泰语", 277 | "Turkish/土耳其语", 278 | "Turkmen/土库曼语", 279 | "Welsh/威尔士语", 280 | "Uyghur/维吾尔语", 281 | "Urdu/乌尔都语", 282 | "Ukrainian/乌克兰语", 283 | "Uzbek/乌兹别克语", 284 | "Spanish/西班牙语", 285 | "Hebrew/希伯来语", 286 | "Greek/希腊语", 287 | "Hawaiian/夏威夷语", 288 | "Sin German/信德语", 289 | "Hungarian/匈牙利语", 290 | "Shona/修纳语", 291 | "Armenian/亚美尼亚语", 292 | "Igbo/伊博语", 293 | "Italian/意大利语", 294 | "Yiddish/意第绪语", 295 | "Hindi/印地语", 296 | "Indonesian Sundanese/印尼巽他语", 297 | "Indonesian/印尼语", 298 | "Javanese/印尼爪哇语", 299 | "Yoruba/约鲁巴语", 300 | "Vietnamese/越南语", 301 | "Chinese/中文", 302 | "Chinese (Simplified)/中文(简体)" 303 | ], 304 | "default": "English/英语", 305 | "description": "Language to be translated" 306 | }, 307 | "search-online.Google Translate Output Language": { 308 | "type": "string", 309 | "enum": [ 310 | "English/英语", 311 | "Chinese/中文", 312 | "Japanese/日语", 313 | "Albanian/阿尔巴尼亚语", 314 | "Arabic/阿拉伯语", 315 | "Amharic/阿姆哈拉语", 316 | "Azerbaijani/阿塞拜疆语", 317 | "Irish/爱尔兰语", 318 | "Estonian/爱沙尼亚语", 319 | "Oriya/奥利亚语", 320 | "Basque/巴斯克语", 321 | "Belarusian/白俄罗斯语", 322 | "Bulgarian/保加利亚语", 323 | "Icelandic/冰岛语", 324 | "Polish/波兰语", 325 | "Bosnian/波斯尼亚语", 326 | "Persian/波斯语", 327 | "Boolean (Afrikaans)/布尔语(南非荷兰语)", 328 | "Tatar/鞑靼语", 329 | "Danish/丹麦语", 330 | "German/德语", 331 | "Russian/俄语", 332 | "French/法语", 333 | "Filipino/菲律宾语", 334 | "Finnish/芬兰语", 335 | "Frisian/弗里西语", 336 | "Khmer/高棉语", 337 | "Georgian/格鲁吉亚语", 338 | "Gujarati/古吉拉特语", 339 | "Kazakh/哈萨克语", 340 | "Haiti Creole/海地克里奥尔语", 341 | "Korean/韩语", 342 | "Hausa/豪萨语", 343 | "Dutch/荷兰语", 344 | "Kyrgyz/吉尔吉斯语", 345 | "Galician/加利西亚语", 346 | "Catalan/加泰罗尼亚语", 347 | "Czech/捷克语", 348 | "Kannada/卡纳达语", 349 | "Corsican/科西嘉语", 350 | "Croatian/克罗地亚语", 351 | "Kurdish/库尔德语", 352 | "Latin/拉丁语", 353 | "Latvian/拉脱维亚语", 354 | "Laotian/老挝语", 355 | "Lithuanian/立陶宛语", 356 | "Luxembourgish/卢森堡语", 357 | "Rwandan/卢旺达语", 358 | "Romanian/罗马尼亚语", 359 | "Malagasy/马尔加什语", 360 | "Maltese/马耳他语", 361 | "Marathi/马拉地语", 362 | "Malayalam/马拉雅拉姆语", 363 | "Malay/马来语", 364 | "Macedonian/马其顿语", 365 | "Maori/毛利语", 366 | "Mongolian/蒙古语", 367 | "Bengali/孟加拉语", 368 | "Burmese/缅甸语", 369 | "Miao language/苗语", 370 | "South African Xhosa/南非科萨语", 371 | "South African Zulu/南非祖鲁语", 372 | "Nepalese/尼泊尔语", 373 | "Norwegian/挪威语", 374 | "Punjabi/旁遮普语", 375 | "Portuguese/葡萄牙语", 376 | "Pashto/普什图语", 377 | "Chichewa/齐切瓦语", 378 | "Swedish/瑞典语", 379 | "Samoan/萨摩亚语", 380 | "Serbian/塞尔维亚语", 381 | "Sesotho/塞索托语", 382 | "Sinhala/僧伽罗语", 383 | "Esperanto/世界语", 384 | "Slovak/斯洛伐克语", 385 | "Slovenian/斯洛文尼亚语", 386 | "Swahili/斯瓦希里语", 387 | "Scottish Gaelic/苏格兰盖尔语", 388 | "Cebuano/宿务语", 389 | "Somali/索马里语", 390 | "Tajik/塔吉克语", 391 | "Telugu/泰卢固语", 392 | "Tamil/泰米尔语", 393 | "Thai/泰语", 394 | "Turkish/土耳其语", 395 | "Turkmen/土库曼语", 396 | "Welsh/威尔士语", 397 | "Uyghur/维吾尔语", 398 | "Urdu/乌尔都语", 399 | "Ukrainian/乌克兰语", 400 | "Uzbek/乌兹别克语", 401 | "Spanish/西班牙语", 402 | "Hebrew/希伯来语", 403 | "Greek/希腊语", 404 | "Hawaiian/夏威夷语", 405 | "Sin German/信德语", 406 | "Hungarian/匈牙利语", 407 | "Shona/修纳语", 408 | "Armenian/亚美尼亚语", 409 | "Igbo/伊博语", 410 | "Italian/意大利语", 411 | "Yiddish/意第绪语", 412 | "Hindi/印地语", 413 | "Indonesian Sundanese/印尼巽他语", 414 | "Indonesian/印尼语", 415 | "Javanese/印尼爪哇语", 416 | "Yoruba/约鲁巴语", 417 | "Vietnamese/越南语", 418 | "Chinese (Simplified)/中文(简体)", 419 | "Chinese (Traditional)/中文(繁体)" 420 | ], 421 | "default": "Chinese/中文", 422 | "description": "Translated language" 423 | }, 424 | "search-online.add-search-engine": { 425 | "type": "array", 426 | "default": [ 427 | { 428 | "name": "Duck", 429 | "url": "https://duckduckgo.com/?q=%SELECTION%" 430 | } 431 | ], 432 | "description": "Add Search Engine" 433 | } 434 | } 435 | } 436 | }, 437 | "scripts": { 438 | "build": "vsce package", 439 | "vscode:prepublish": "npm run compile", 440 | "compile": "tsc -p ./", 441 | "lint": "eslint src --ext ts", 442 | "watch": "tsc -watch -p ./", 443 | "pretest": "npm run compile && npm run lint", 444 | "test": "node ./out/test/runTest.js" 445 | }, 446 | "devDependencies": { 447 | "@types/vscode": "^1.51.0", 448 | "@types/glob": "^7.1.3", 449 | "@types/mocha": "^8.0.0", 450 | "@types/node": "^12.11.7", 451 | "eslint": "^7.9.0", 452 | "@typescript-eslint/eslint-plugin": "^4.1.1", 453 | "@typescript-eslint/parser": "^4.1.1", 454 | "glob": "^7.1.6", 455 | "mocha": "^8.1.3", 456 | "typescript": "^4.0.2", 457 | "vscode-test": "^1.4.0" 458 | } 459 | } --------------------------------------------------------------------------------