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 vscode = require('vscode');
const fs = require('fs');
const path = require('path')
const axios = require('axios');
const crypto = require('crypto');
const YOUDAO_API_URL = 'https://openapi.youdao.com/api';
const targetLanguage = 'zh'; // 目标语言,例如中文
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
// console.log('Congratulations, your extension "gn-i18n-helper" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
const disposable = vscode.commands.registerCommand(
'extension.getSelectedText', // 这个名称必须与package.json中的命令名称一致
async () => {
const editor = vscode.window.activeTextEditor;
if (editor) {
// 选中的文本
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
// 获取当前工作区的文件夹
const workspaceFolders = vscode.workspace.workspaceFolders;
// 获取文件内容
const filePath1 = path.join(workspaceFolders[0].uri.fsPath, 'LANGUAGEI18n/LANGUAGEI18nCommon.md');
const filePath2 = path.join(workspaceFolders[0].uri.fsPath, 'LANGUAGEI18n/LANGUAGEI18nFrontend.md');
const filePath3 = path.join(workspaceFolders[0].uri.fsPath, 'LANGUAGEI18n/LANGUAGEI18nPage.md');
const filePath4 = path.join(workspaceFolders[0].uri.fsPath, 'LANGUAGEI18n/LANGUAGEI18nGeneral.md');
const fileContent1 = fs.readFileSync(filePath1, 'utf8');
const fileContent2 = fs.readFileSync(filePath2, 'utf8');
const fileContent3 = fs.readFileSync(filePath3, 'utf8');
const fileContent4 = fs.readFileSync(filePath4, 'utf8');
let fileContent = fileContent1 + fileContent2 + fileContent3 + fileContent4;
if (editor.document.languageId === 'vue') {
const document = editor.document;
const position = editor.selection.active; // 获取光标位置
const lineText = document.lineAt(position.line).text; // 获取当前行文本
const currentFileContent = document.getText(); // 获取文件内容
// 默认 template,防止出现多个 template 标签
// 使用正则表达式匹配 <javaScript> 和 </javaScript> 之间的内容
let section = 'template';
const javaScriptRegex = /<script>([\s\S]*?)<\/script>/i;
const javaScriptMatch = currentFileContent.match(javaScriptRegex);
if (javaScriptMatch && javaScriptMatch[1]) {
const matchContent = javaScriptMatch[1].trim(); // 提取内容并去除多余空格
if(matchContent.includes(lineText)){
section = 'javaScript';
}
}
// 处理选中的内容,截取需要搜索的文字
let searchText = '';
if(selectedText.includes('=')){
searchText = selectedText.split('=')[1].replace(/"/g, "").trim();
}else{
searchText = selectedText;
}
const searchResult = fileContent.search(new RegExp(searchText, 'g'));
let isMatch = false;
if (searchResult !== -1) {
// 截取文件内容 - 提高搜索效率
// let copyFileContent = fileContent.slice(searchResult - 1000, searchResult + 1000);
const lines = fileContent.split('\n'); // 按行分割文本
const regex = /(\w+)\("([^"]+)", "([^"]+)", "([^"]+)",/;
for (const line of lines) {
const match = line.match(regex);
if (match) {
const docKey = match[2];
const docValue = match[3];
const docText = match[4].replace(/"/g, "");
let newText = '';
if(section == 'template'){
if(selectedText.includes('=')){
// placeholder="验证码" -> :placeholder="$t('common.verifyCode')"
const prop = selectedText.split('=')[0];
newText = `:${prop}="$t('${docKey}.${docValue}')"`
}else{
// 验证码 -> {{$t('common.username')}}
newText = `{{$t('${docKey}.${docValue}')}}`
}
}else if(section == 'javaScript'){
// "验证码" -> this.$t('common.username')
newText = `this.$t('${docKey}.${docValue}')`
}
if(docText == searchText){
isMatch = true;
if (docKey && docValue) {
vscode.window.showInformationMessage(editor.selection, newText);
if(section == 'template'){
editor.edit(editBuilder => {
editBuilder.replace(editor.selection, newText);
});
}else if(section == 'javaScript'){
const start = selection.start;
const end = selection.end;
// 获取当前选中内容的前后字符位置
const newStart = new vscode.Position(start.line, Math.max(start.character - 1, 0));
const newEnd = new vscode.Position(end.line, Math.min(end.character + 1, document.lineAt(end.line).text.length));
// 设置新的选择区域
editor.selection = new vscode.Selection(newStart, newEnd);
editor.edit(editBuilder => {
editBuilder.replace(editor.selection, newText); // 替换选中的内容
});
}
break; // 找到后退出循环
}
}
}
}
// 如果没有找到精准匹配的内容
if(!isMatch){
addWordToFile(searchText, filePath4);
// vscode.window.showInformationMessage(`未找到匹配内容:${searchText}`);
}
} else {
addWordToFile(searchText, filePath4);
}
}
} else {
vscode.window.showInformationMessage('No active editor found.');
}
},
);
context.subscriptions.push(disposable);
}
// 添加词条到文件
async function addWordToFile(searchText, filePath4) {
const translatedText = await translateText(searchText, targetLanguage);
const simplifyText = simplify(translatedText);
const camelCaseText = toCamelCase(simplifyText);
// 向文件中添加翻译后的文本
const generationFilePath = filePath4;
const generationFileContent = fs.readFileSync(generationFilePath, 'utf8');
// GENERAL_UPDATELOG("general", "updateLog", "更新日志", "updateLog", "更新日志"),
const insertText = `GENERAL_${camelCaseText.toUpperCase()}("general", "${camelCaseText}", "${searchText}", "${simplifyText}", "${searchText}"),`;
const newGenerationFileContent = generationFileContent + '\n' + insertText;
fs.writeFileSync(generationFilePath, newGenerationFileContent);
}
async function translateText(text, targetLanguage) {
const appKey = ''; // 替换为您的 App Key
const appSecret = ''; // 替换为您的 App Secret
const salt = Date.now();
const curtime = Math.floor(Date.now() / 1000);
const sign = crypto.createHash('sha256')
.update(appKey + truncate(text) + salt + curtime + appSecret)
.digest('hex');
const response = await axios.get(YOUDAO_API_URL, {
params: {
q: text,
from: 'zh-CHS',
to: targetLanguage,
appKey: appKey,
salt: salt,
sign: sign,
signType: "v3",
curtime: curtime,
},
});
return response.data.translation[0];
}
function truncate(text) {
return text.length > 200 ? text.slice(0, 200) : text;
}
function toCamelCase(str) {
// 将 - 替换为 " "
str = str.replace(/-/g, " ");
return str
.split(/\s+/) // 按空格分割
.map((word, index) => {
if (index === 0) {
return word.toLowerCase(); // 第一个单词小写
}
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); // 其他单词首字母大写
})
.join('');
}
function simplify(text) {
// 示例: 删除多余空格和停用词
const stopWords = ['the', 'is', 'in', 'at', 'and', 'of', 'to', 'a', 'that', 'it', 'on', 'for'];
const words = text.split(' ').filter(word => !stopWords.includes(word.toLowerCase()));
return words.join(' ').trim(); // 返回精简后的文本
}
// This method is called when your extension is deactivated
function deactivate() {
vscode.window.showInformationMessage(`Congratulations, your extension "gn-i18n-helper" is now active!`);
}
module.exports = {
activate,
deactivate
}
javascript
复制代码
{
"name": "gn-i18n-helper",
"displayName": "gn-i18n-helper",
"description": "A VS Code extension to help with i18n.",
"publisher": "guniao",
"version": "2.0.2",
"icon": "resources/i18n.png",
"engines": {
"vscode": "^1.96.0"
},
"categories": [
"Other"
],
"activationEvents": [],
"main": "./extension.js",
"contributes": {
"commands": [
{
"command": "extension.getSelectedText",
"title": "Get Selected Text"
}
],
"keybindings": [
{
"command": "extension.getSelectedText",
"key": "alt+r",
"when": "editorTextFocus"
}
]
},
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint",
"test": "vscode-test"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "20.x",
"@types/vscode": "^1.96.0",
"@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.4.1",
"eslint": "^9.16.0"
},
"dependencies": {
"axios": "^1.7.9"
}
}