Update localization support in myTemplateGenerator extension. Added English and Russian settings for the configuration interface, modified default language to English, and removed unnecessary .vscode directory from .gitignore. Updated @types/vscode dependency version in package files. Added VSCode configuration files for better development experience.

This commit is contained in:
S.Gromov
2025-07-13 18:54:05 +03:00
parent 80350e8f5f
commit b87b04d407
8 changed files with 281 additions and 168 deletions

1
.gitignore vendored
View File

@@ -41,7 +41,6 @@ build/Release
# Dependency directories # Dependency directories
node_modules/ node_modules/
jspm_packages/ jspm_packages/
.vscode/
# Snowpack dependency directory (https://snowpack.dev/) # Snowpack dependency directory (https://snowpack.dev/)
web_modules/ web_modules/

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher", "ms-vscode.extension-test-runner"]
}

21
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,21 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

13
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

40
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,40 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$ts-webpack-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": "build"
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: watch",
"npm: watch-tests"
],
"problemMatcher": []
}
]
}

8
package-lock.json generated
View File

@@ -13,7 +13,7 @@
"devDependencies": { "devDependencies": {
"@types/mocha": "^10.0.10", "@types/mocha": "^10.0.10",
"@types/node": "20.x", "@types/node": "20.x",
"@types/vscode": "^1.102.0", "@types/vscode": "^1.60.0",
"@typescript-eslint/eslint-plugin": "^8.31.1", "@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/parser": "^8.31.1", "@typescript-eslint/parser": "^8.31.1",
"@vscode/test-cli": "^0.0.11", "@vscode/test-cli": "^0.0.11",
@@ -485,9 +485,9 @@
} }
}, },
"node_modules/@types/vscode": { "node_modules/@types/vscode": {
"version": "1.102.0", "version": "1.60.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.102.0.tgz", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.60.0.tgz",
"integrity": "sha512-V9sFXmcXz03FtYTSUsYsu5K0Q9wH9w9V25slddcxrh5JgORD14LpnOA7ov0L9ALi+6HrTjskLJ/tY5zeRF3TFA==", "integrity": "sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },

View File

@@ -3,6 +3,7 @@
"displayName": "myTemplateGenerator", "displayName": "myTemplateGenerator",
"description": "Generate files and folders from customizable templates with variable substitution in VSCode.", "description": "Generate files and folders from customizable templates with variable substitution in VSCode.",
"version": "0.0.1", "version": "0.0.1",
"publisher": "MyTemplateGenerator",
"author": "Sergey Gromov", "author": "Sergey Gromov",
"url": "https://github.com/gormov1122/MyTemplateGenerator", "url": "https://github.com/gormov1122/MyTemplateGenerator",
"engines": { "engines": {
@@ -68,7 +69,7 @@
"devDependencies": { "devDependencies": {
"@types/mocha": "^10.0.10", "@types/mocha": "^10.0.10",
"@types/node": "20.x", "@types/node": "20.x",
"@types/vscode": "^1.102.0", "@types/vscode": "^1.60.0",
"@typescript-eslint/eslint-plugin": "^8.31.1", "@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/parser": "^8.31.1", "@typescript-eslint/parser": "^8.31.1",
"@vscode/test-cli": "^0.0.11", "@vscode/test-cli": "^0.0.11",

View File

@@ -268,6 +268,29 @@ const I18N_DICTIONARIES: Record<string, Record<string, string>> = {
} }
}; };
const SETTINGS_I18N: Record<string, Record<string, string>> = {
ru: {
title: 'Настройки myTemplateGenerator',
templatesPath: 'Путь к шаблонам:',
overwriteFiles: 'Перезаписывать существующие файлы',
inputMode: 'Способ ввода переменных:',
inputModeWebview: 'Webview (форма)',
inputModeInputBox: 'InputBox (по одной)',
language: 'Язык интерфейса:',
save: 'Сохранить'
},
en: {
title: 'myTemplateGenerator Settings',
templatesPath: 'Templates path:',
overwriteFiles: 'Overwrite existing files',
inputMode: 'Variable input method:',
inputModeWebview: 'Webview (form)',
inputModeInputBox: 'InputBox (one by one)',
language: 'Interface language:',
save: 'Save'
}
};
interface MyTemplateGeneratorConfig { interface MyTemplateGeneratorConfig {
templatesPath: string; templatesPath: string;
overwriteFiles: boolean; overwriteFiles: boolean;
@@ -279,7 +302,7 @@ const DEFAULT_CONFIG: MyTemplateGeneratorConfig = {
templatesPath: 'templates', templatesPath: 'templates',
overwriteFiles: false, overwriteFiles: false,
inputMode: 'webview', inputMode: 'webview',
language: 'ru', language: 'en',
}; };
function getConfigPath(): string | undefined { function getConfigPath(): string | undefined {
@@ -313,175 +336,183 @@ function writeConfig(config: MyTemplateGeneratorConfig) {
async function showConfigWebview(context: vscode.ExtensionContext) { async function showConfigWebview(context: vscode.ExtensionContext) {
const config = readConfig(); const config = readConfig();
let language = config.language || 'ru';
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
const panel = vscode.window.createWebviewPanel( const panel = vscode.window.createWebviewPanel(
'mytemplategeneratorConfig', 'mytemplategeneratorConfig',
'Настройки myTemplateGenerator', SETTINGS_I18N[language]?.title || SETTINGS_I18N['ru'].title,
vscode.ViewColumn.Active, vscode.ViewColumn.Active,
{ enableScripts: true } { enableScripts: true }
); );
panel.webview.html = ` function setHtml() {
<!DOCTYPE html> const dict = SETTINGS_I18N[language] || SETTINGS_I18N['ru'];
<html lang="ru"> panel.webview.html = `
<head> <!DOCTYPE html>
<meta charset="UTF-8"> <html lang="${language}">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; style-src 'unsafe-inline';"> <head>
<title>Настройки myTemplateGenerator</title> <meta charset="UTF-8">
<style> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; style-src 'unsafe-inline';">
:root { <title>${dict.title}</title>
--bg: #f7f7fa; <style>
--panel-bg: #fff; :root {
--text: #222; --bg: #f7f7fa;
--label: #555; --panel-bg: #fff;
--input-bg: #f0f0f3; --text: #222;
--input-border: #d0d0d7; --label: #555;
--input-focus: #1976d2; --input-bg: #f0f0f3;
--button-bg: #1976d2; --input-border: #d0d0d7;
--button-text: #fff; --input-focus: #1976d2;
--button-hover: #1565c0; --button-bg: #1976d2;
--border-radius: 8px; --button-text: #fff;
--shadow: 0 2px 12px rgba(0,0,0,0.07); --button-hover: #1565c0;
} --border-radius: 8px;
@media (prefers-color-scheme: dark) { --shadow: 0 2px 12px rgba(0,0,0,0.07);
:root { }
--bg: #181a1b; @media (prefers-color-scheme: dark) {
--panel-bg: #23272e; :root {
--text: #f3f3f3; --bg: #181a1b;
--label: #b0b0b0; --panel-bg: #23272e;
--input-bg: #23272e; --text: #f3f3f3;
--input-border: #33363b; --label: #b0b0b0;
--input-focus: #90caf9; --input-bg: #23272e;
--button-bg: #1976d2; --input-border: #33363b;
--button-text: #fff; --input-focus: #90caf9;
--button-hover: #1565c0; --button-bg: #1976d2;
--border-radius: 8px; --button-text: #fff;
--shadow: 0 2px 12px rgba(0,0,0,0.25); --button-hover: #1565c0;
} --border-radius: 8px;
} --shadow: 0 2px 12px rgba(0,0,0,0.25);
body { }
background: var(--bg); }
color: var(--text); body {
font-family: 'Segoe UI', 'Roboto', Arial, sans-serif; background: var(--bg);
margin: 0; color: var(--text);
min-height: 100vh; font-family: 'Segoe UI', 'Roboto', Arial, sans-serif;
} margin: 0;
.config-container { min-height: 100vh;
max-width: 420px; }
margin: 48px auto; .config-container {
background: var(--panel-bg); max-width: 420px;
border-radius: var(--border-radius); margin: 48px auto;
box-shadow: var(--shadow); background: var(--panel-bg);
padding: 32px 36px 28px 36px; border-radius: var(--border-radius);
display: flex; box-shadow: var(--shadow);
flex-direction: column; padding: 32px 36px 28px 36px;
gap: 18px; display: flex;
} flex-direction: column;
.config-container h2 { gap: 18px;
margin: 0 0 18px 0; }
font-size: 1.5em; .config-container h2 {
font-weight: 600; margin: 0 0 18px 0;
letter-spacing: 0.01em; font-size: 1.5em;
} font-weight: 600;
.form-group { letter-spacing: 0.01em;
display: flex; }
flex-direction: column; .form-group {
gap: 10px; display: flex;
margin-bottom: 10px; flex-direction: column;
} gap: 10px;
label { margin-bottom: 10px;
color: var(--label); }
font-size: 1em; label {
font-weight: 500; color: var(--label);
margin-bottom: 2px; font-size: 1em;
} font-weight: 500;
input[type="text"], select { margin-bottom: 2px;
background: var(--input-bg); }
color: var(--text); input[type="text"], select {
border: 1.5px solid var(--input-border); background: var(--input-bg);
border-radius: var(--border-radius); color: var(--text);
padding: 8px 10px; border: 1.5px solid var(--input-border);
font-size: 1em; border-radius: var(--border-radius);
transition: border 0.2s, box-shadow 0.2s; padding: 8px 10px;
outline: none; font-size: 1em;
} transition: border 0.2s, box-shadow 0.2s;
input[type="text"]:focus, select:focus { outline: none;
border-color: var(--input-focus); }
box-shadow: 0 0 0 2px var(--input-focus)33; input[type="text"]:focus, select:focus {
} border-color: var(--input-focus);
.checkbox-group { box-shadow: 0 0 0 2px var(--input-focus)33;
display: flex; }
align-items: center; .checkbox-group {
gap: 8px; display: flex;
margin-bottom: 10px; align-items: center;
} gap: 8px;
input[type="checkbox"] { margin-bottom: 10px;
accent-color: var(--input-focus); }
width: 18px; input[type="checkbox"] {
height: 18px; accent-color: var(--input-focus);
} width: 18px;
button { height: 18px;
margin-top: 10px; }
background: var(--button-bg); button {
color: var(--button-text); margin-top: 10px;
border: none; background: var(--button-bg);
border-radius: var(--border-radius); color: var(--button-text);
padding: 10px 0; border: none;
font-size: 1.1em; border-radius: var(--border-radius);
font-weight: 600; padding: 10px 0;
cursor: pointer; font-size: 1.1em;
transition: background 0.2s, box-shadow 0.2s; font-weight: 600;
box-shadow: 0 1px 4px rgba(25, 118, 210, 0.08); cursor: pointer;
} transition: background 0.2s, box-shadow 0.2s;
button:hover, button:focus { box-shadow: 0 1px 4px rgba(25, 118, 210, 0.08);
background: var(--button-hover); }
} button:hover, button:focus {
</style> background: var(--button-hover);
<script> }
window.addEventListener('DOMContentLoaded', () => { </style>
const vscode = acquireVsCodeApi(); <script>
document.getElementById('configForm').addEventListener('submit', (e) => { window.addEventListener('DOMContentLoaded', () => {
e.preventDefault(); const vscode = acquireVsCodeApi();
const templatesPath = document.getElementById('templatesPath').value; document.getElementById('configForm').addEventListener('submit', (e) => {
const overwriteFiles = document.getElementById('overwriteFiles').checked; e.preventDefault();
const inputMode = document.getElementById('inputMode').value; const templatesPath = document.getElementById('templatesPath').value;
const language = document.getElementById('language').value; const overwriteFiles = document.getElementById('overwriteFiles').checked;
vscode.postMessage({ type: 'save', data: { templatesPath, overwriteFiles, inputMode, language } }); const inputMode = document.getElementById('inputMode').value;
const language = document.getElementById('language').value;
vscode.postMessage({ type: 'save', data: { templatesPath, overwriteFiles, inputMode, language } });
});
document.getElementById('language').addEventListener('change', (e) => {
vscode.postMessage({ type: 'changeLanguage', language: e.target.value });
});
}); });
}); </script>
</script> </head>
</head> <body>
<body> <div class="config-container">
<div class="config-container"> <h2>${dict.title}</h2>
<h2>Настройки myTemplateGenerator</h2> <form id="configForm">
<form id="configForm"> <div class="form-group">
<div class="form-group"> <label for="templatesPath">${dict.templatesPath}</label>
<label for="templatesPath">Путь к шаблонам:</label> <input type="text" id="templatesPath" value="${config.templatesPath || ''}"/>
<input type="text" id="templatesPath" value="${config.templatesPath}" /> </div>
<div class="checkbox-group">
<input type="checkbox" id="overwriteFiles" ${config.overwriteFiles ? 'checked' : ''}/>
<label for="overwriteFiles">${dict.overwriteFiles}</label>
</div>
<div class="form-group">
<label for="inputMode">${dict.inputMode}</label>
<select id="inputMode">
<option value="webview" ${config.inputMode === 'webview' ? 'selected' : ''}>${dict.inputModeWebview}</option>
<option value="inputBox" ${config.inputMode === 'inputBox' ? 'selected' : ''}>${dict.inputModeInputBox}</option>
</select>
</div>
<div class="form-group">
<label for="language">${dict.language}</label>
<select id="language">
<option value="ru" ${language === 'ru' ? 'selected' : ''}>Русский</option>
<option value="en" ${language === 'en' ? 'selected' : ''}>English</option>
</select>
</div>
<button type="submit" style="padding: 10px 15px">${dict.save}</button>
</form>
</div> </div>
<div class="checkbox-group"> </body>
<input type="checkbox" id="overwriteFiles" ${config.overwriteFiles ? 'checked' : ''}/> </html>
<label for="overwriteFiles">Перезаписывать существующие файлы</label> `;
</div> }
<div class="form-group"> setHtml();
<label for="inputMode">Способ ввода переменных:</label>
<select id="inputMode">
<option value="webview" ${config.inputMode === 'webview' ? 'selected' : ''}>Webview (форма)</option>
<option value="inputBox" ${config.inputMode === 'inputBox' ? 'selected' : ''}>InputBox (по одной)</option>
</select>
</div>
<div class="form-group">
<label for="language">Язык интерфейса:</label>
<select id="language">
<option value="ru" ${config.language === 'ru' ? 'selected' : ''}>Русский</option>
<option value="en" ${config.language === 'en' ? 'selected' : ''}>English</option>
</select>
</div>
<button type="submit">Сохранить</button>
</form>
</div>
</body>
</html>
`;
panel.webview.onDidReceiveMessage( panel.webview.onDidReceiveMessage(
message => { message => {
if (message.type === 'save') { if (message.type === 'save') {
@@ -489,6 +520,9 @@ async function showConfigWebview(context: vscode.ExtensionContext) {
vscode.window.showInformationMessage('Настройки myTemplateGenerator сохранены!'); vscode.window.showInformationMessage('Настройки myTemplateGenerator сохранены!');
panel.dispose(); panel.dispose();
resolve(); resolve();
} else if (message.type === 'changeLanguage') {
language = message.language;
setHtml();
} }
}, },
undefined, undefined,