一:安装vscode工程脚手架
因为vscode插件开发的脚手架是基于 Yeoman开发的
- 执行下面命令行进行安装
npm install -g yo generator-code
- 执行
yo code
初始化插件
二:初始化插件配置
- 首先在
package.json
中声明contributes
下的commands
字段,声明插件命令为extension.i18n
"contributes": {
"commands": [
{
"command": "extension.i18n",
"title": "autoi18n"
}
],
}
- 然后在激活插件,在package.json中声明
activationEvents
字段为"onCommand:extension.i18n
"
"activationEvents": [
"onCommand:extension.i18n"
],
- 声明插件的使用方式
声明插件出现的时机,为
resourceScheme =~ /^untitled$|^file$/
时,也就是在编辑文件时
"contributes": {
"menus": {
"editor/title": [
{
"when": "resourceScheme =~ /^untitled$|^file$/",
"command": "extension.i18n",
"group": "navigation"
}
]
}
},
监听插件命令
- 第一步:注册
extension.i18n
事件监听vscode.commands.registerCommand('extension.i18n', () => {})
- 第二步:获取编辑文件的路径
const uri = vscode.window.activeTextEditor?.document.uri.fsPath;
- 第三步:使用nodejs的fs模块读取文件
fs.readFile(uri, (err, res) => {})
- 第四步:引入
babel
文件内容解析为ast - 第五部:使用
'@babel/traverse'
便利时判断ast节点类型 - 第六步:对
ImportDeclaration
做处理自动引入import intl from 'intl'
- 第七步:对
JSXText
和StringLiteral
做处理,使用intl
包裹上对应文案的key
进行对语言的调用
import * as vscode from 'vscode';
const fs = require('fs');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const generate = require('@babel/generator').default;
const types = require('@babel/types').default;
const template = require('@babel/template').default;
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('extension.i18n', () => {
const uri = vscode.window.activeTextEditor?.document.uri.fsPath;
fs.readFile(uri, (_err: any, res: { toString: () => any; }) => {
const code = res.toString();
const ast = parser.parse(code, {
sourceType: 'unambiguous',
plugins: ['jsx', 'typescript']
});
try {
traverse.default(ast, {
Program: {
enter(path, state = {}) {
let imported;
path.traverse({
ImportDeclaration(p) {
const source = p.node.source.value;
if(source === 'intl') {
imported = true;
}
}
});
if (!imported) {
const uid = path.scope.generateUid('intl');
const importAst = template.ast(`import ${uid} from 'intl'`);
path.node.body.unshift(importAst);
}
}
},
JSXText(path) {
if (path.node.type === 'JSXText') {
const value = path.node.value.replace('\n', '').trim();
if (value) {
const replaceExpression = template.ast(`{intl('${value}')}`);
path.replaceWith(replaceExpression);
}
}
},
StringLiteral(path) {
let isI18nDisabled = false;
if(path.node.leadingComments) {
isI18nDisabled = path.node.leadingComments.find(item => item.value.includes('i18n-disable'));
}
if (!isI18nDisabled && path.parentPath.node?.callee?.name !== 'intl' && path.node.value !== 'intl' && path.parentPath.type !== 'ImportDeclaration'){
const replaceExpression = template.ast(`intl('${path.node.value}')`);
path.replaceWith(replaceExpression);
}
},
});
} catch (error) {
console.log(error);
}
const { code: codeAfterAst, map } = generate(ast);
fs.writeFileSync(uri, codeAfterAst, 'utf8');
});
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
export function deactivate() {}
todo
需要引入多语言的json文件,然后根据代码中JSXText节点
和StringLiteral节点
中的value
,根据value找到对应的key,完成多语言的key调用