addonova 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -48
- package/bin/addonova.js +4 -0
- package/bin/index.js +1 -60
- package/package.json +20 -29
- package/src/build/browser.js +143 -0
- package/{workspace/tasks → src/build}/build.js +16 -2
- package/src/build/bundle-html.js +120 -0
- package/{workspace/tasks → src/build}/cli.js +4 -2
- package/src/cli/help.js +16 -0
- package/src/cli/index.js +58 -0
- package/src/commands/init.js +14 -18
- package/src/commands/tool.js +32 -0
- package/src/index.js +0 -1
- package/src/tools/tools-server.js +287 -0
- package/src/tools/tools.html +388 -0
- package/templates/extension/config/firefox.js +30 -0
- package/templates/extension/config/thunderbird.js +30 -0
- package/templates/extension/package.json.tpl +36 -0
- package/{template → templates/extension}/platform/naver/platform.js +0 -15
- package/src/commands/update.js +0 -67
- package/template/config/firefox.js +0 -29
- package/template/config/thunderbird.js +0 -29
- package/template/package.json.tpl +0 -54
- package/workspace/tasks/bundle-html.js +0 -91
- package/workspace/tools/json2i18n.js +0 -37
- package/workspace/tools/translate.js +0 -299
- /package/{workspace/tasks → src/build}/bundle-css.js +0 -0
- /package/{workspace/tasks → src/build}/bundle-js.js +0 -0
- /package/{workspace/tasks → src/build}/bundle-locales.js +0 -0
- /package/{workspace/tasks → src/build}/bundle-manifest.js +0 -0
- /package/{workspace/tasks → src/build}/copy.js +0 -0
- /package/{workspace/tasks → src/build}/folder.js +0 -0
- /package/{workspace/tasks → src/build}/paths.js +0 -0
- /package/{workspace/tasks → src/build}/task.js +0 -0
- /package/{workspace/tasks → src/build}/utils.js +0 -0
- /package/{workspace/tasks → src/build}/watch.js +0 -0
- /package/{workspace/tasks → src/build}/zip.js +0 -0
- /package/{template → templates/extension}/config/chrome.js +0 -0
- /package/{template → templates/extension}/config/edge.js +0 -0
- /package/{template → templates/extension}/config/naver.js +0 -0
- /package/{template → templates/extension}/config/opera.js +0 -0
- /package/{template → templates/extension}/platform/chrome/platform.js +0 -0
- /package/{template → templates/extension}/platform/edge/platform.js +0 -0
- /package/{template → templates/extension}/platform/opera/platform.js +0 -0
- /package/{template → templates/extension}/src/_locales/en.i18n +0 -0
- /package/{template → templates/extension}/src/assets/icons/128.png +0 -0
- /package/{template → templates/extension}/src/assets/icons/32.png +0 -0
- /package/{template → templates/extension}/src/assets/icons/48.png +0 -0
- /package/{template → templates/extension}/src/assets/icons/64.png +0 -0
- /package/{template → templates/extension}/src/css/popup.css +0 -0
- /package/{template → templates/extension}/src/html/popup.html +0 -0
- /package/{template → templates/extension}/src/js/background.js +0 -0
- /package/{template → templates/extension}/src/js/lib/browser.js +0 -0
- /package/{template → templates/extension}/src/js/lib/common.js +0 -0
- /package/{template → templates/extension}/src/js/lib/config.js +0 -0
- /package/{template → templates/extension}/src/js/lib/runtime.js +0 -0
- /package/{template → templates/extension}/src/js/popup.js +0 -0
- /package/{template → templates/extension}/src/manifest/manifest-firefox.json +0 -0
- /package/{template → templates/extension}/src/manifest/manifest.json +0 -0
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "{{name}}",
|
|
3
|
-
"version": "{{version}}",
|
|
4
|
-
"description": "{{description}}",
|
|
5
|
-
"json.schemaValidation": "off",
|
|
6
|
-
"license": "GPLv3",
|
|
7
|
-
"author": "Addonova",
|
|
8
|
-
"type": "module",
|
|
9
|
-
"engines": {
|
|
10
|
-
"node": ">=22",
|
|
11
|
-
"npm": ">=11"
|
|
12
|
-
},
|
|
13
|
-
"scripts": {
|
|
14
|
-
"release": "addonova-release",
|
|
15
|
-
"release:chrome": "addonova-release:chrome",
|
|
16
|
-
"release:edge": "addonova-release:edge",
|
|
17
|
-
"release:opera": "addonova-release:opera",
|
|
18
|
-
"release:firefox": "addonova-release:firefox",
|
|
19
|
-
"release:thunderbird": "addonova-release:thunderbird",
|
|
20
|
-
"release:naver": "addonova-release:naver",
|
|
21
|
-
|
|
22
|
-
"debug": "addonova-debug",
|
|
23
|
-
"debug:chrome": "addonova-debug:chrome",
|
|
24
|
-
"debug:edge": "addonova-debug:edge",
|
|
25
|
-
"debug:opera": "addonova-debug:opera",
|
|
26
|
-
"debug:firefox": "addonova-debug:firefox",
|
|
27
|
-
"debug:thunderbird": "addonova-debug:thunderbird",
|
|
28
|
-
"debug:naver": "addonova-debug:naver",
|
|
29
|
-
|
|
30
|
-
"watch": "addonova-watch",
|
|
31
|
-
"zip": "addonova zip",
|
|
32
|
-
|
|
33
|
-
"addonova-release": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --all --release",
|
|
34
|
-
"addonova-release:chrome": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --chrome --release",
|
|
35
|
-
"addonova-release:edge": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --edge --release",
|
|
36
|
-
"addonova-release:opera": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --opera --release",
|
|
37
|
-
"addonova-release:firefox": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --firefox --release",
|
|
38
|
-
"addonova-release:thunderbird": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --thunderbird --release",
|
|
39
|
-
"addonova-release:naver": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --naver --release",
|
|
40
|
-
|
|
41
|
-
"addonova-debug": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --all --debug",
|
|
42
|
-
"addonova-debug:chrome": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --chrome --debug",
|
|
43
|
-
"addonova-debug:edge": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --edge --debug",
|
|
44
|
-
"addonova-debug:opera": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --opera --debug",
|
|
45
|
-
"addonova-debug:firefox": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --firefox --debug",
|
|
46
|
-
"addonova-debug:thunderbird": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --thunderbird --debug",
|
|
47
|
-
"addonova-debug:naver": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --naver --debug",
|
|
48
|
-
|
|
49
|
-
"addonova-watch": "node --max-old-space-size=3072 node_modules/addonova/workspace/tasks/cli.js build --all --debug --watch"
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"addonova": "^1.0.0"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { build } from 'esbuild';
|
|
3
|
-
import { htmlPlugin } from '@craftamap/esbuild-plugin-html';
|
|
4
|
-
import {getDestDir} from './paths.js';
|
|
5
|
-
import {readFile, writeFile, getConfig, getAllFiles, log, fileExistsInConfig} from './utils.js';
|
|
6
|
-
import {createTask} from './task.js';
|
|
7
|
-
|
|
8
|
-
const srcHTMLDir = 'src/html';
|
|
9
|
-
|
|
10
|
-
async function removeTopSourceComment(filePath) {
|
|
11
|
-
const code = await readFile(filePath, 'utf8');
|
|
12
|
-
const newCode = code.replace(/^\s*<!--[\s\S]*?-->\s*/, '');
|
|
13
|
-
await writeFile(filePath, newCode);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function esbuildHTML(config, isDebug, platform){
|
|
17
|
-
let buildResult, outputs;
|
|
18
|
-
const dir = getDestDir({isDebug, platform});
|
|
19
|
-
for (const [dest, src] of Object.entries(config.entry)) {
|
|
20
|
-
buildResult = await build({
|
|
21
|
-
entryPoints: src,
|
|
22
|
-
outdir: path.join(dir, dest),
|
|
23
|
-
plugins: [htmlPlugin()],
|
|
24
|
-
loader: {
|
|
25
|
-
'.html': 'file' // 🔥 Important
|
|
26
|
-
},
|
|
27
|
-
entryNames: config.filename,
|
|
28
|
-
assetNames: config.filename,
|
|
29
|
-
chunkNames: config.filename,
|
|
30
|
-
metafile: true,
|
|
31
|
-
write: true
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
if (!isDebug) {
|
|
35
|
-
outputs = Object.keys(buildResult.metafile.outputs);
|
|
36
|
-
for (const file of outputs) {
|
|
37
|
-
if (file.endsWith('.html')) {
|
|
38
|
-
removeTopSourceComment(file);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function createBundleHTMLTask(srcHTMLDir){
|
|
47
|
-
let currentWatchFiles;
|
|
48
|
-
const bundleHTML = async ({platforms, isDebug, logInfo, logWarn}) => {
|
|
49
|
-
for(const platform of platforms){
|
|
50
|
-
const config = (await getConfig(platform));
|
|
51
|
-
if(config.html){
|
|
52
|
-
await esbuildHTML(config.html, isDebug, platform);
|
|
53
|
-
if (logInfo) log.ok(`Bundling HTML for ${platform}...`);
|
|
54
|
-
} else{
|
|
55
|
-
if(logWarn) log.warn(`No HTML config found for ${platform}, skipping HTML bundling.`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const onChange = async (changedFiles, watcher, platforms, isDebug) => {
|
|
61
|
-
for(const platform of platforms){
|
|
62
|
-
const config = (await getConfig(platform));
|
|
63
|
-
|
|
64
|
-
if (!config.html) continue;
|
|
65
|
-
const exists = await fileExistsInConfig(
|
|
66
|
-
config.html.entry,
|
|
67
|
-
changedFiles[0]
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
if (exists){
|
|
71
|
-
const newConfig = {
|
|
72
|
-
html: {
|
|
73
|
-
entry: exists,
|
|
74
|
-
filename: config.html.filename
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
await esbuildHTML(newConfig.html, isDebug, platform);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return createTask(
|
|
82
|
-
'bundle HTML',
|
|
83
|
-
bundleHTML,
|
|
84
|
-
).addWatcher(
|
|
85
|
-
async () => {
|
|
86
|
-
currentWatchFiles = await getAllFiles(srcHTMLDir);
|
|
87
|
-
return currentWatchFiles;
|
|
88
|
-
}, onChange);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export default createBundleHTMLTask(srcHTMLDir);
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, readdirSync, existsSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
-
import { join, dirname } from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = dirname(__filename);
|
|
7
|
-
|
|
8
|
-
const localesDir = join(__dirname, "../", "_locales");
|
|
9
|
-
const outputDir = join(__dirname, "../", "output", "_locales");
|
|
10
|
-
|
|
11
|
-
mkdirSync(outputDir, { recursive: true });
|
|
12
|
-
|
|
13
|
-
console.log("Output directory ready.");
|
|
14
|
-
|
|
15
|
-
const languages = readdirSync(localesDir);
|
|
16
|
-
|
|
17
|
-
languages.forEach((lang) => {
|
|
18
|
-
const messagesPath = join(localesDir, lang, "messages.json");
|
|
19
|
-
|
|
20
|
-
if (!existsSync(messagesPath)) return;
|
|
21
|
-
|
|
22
|
-
const input = JSON.parse(readFileSync(messagesPath, "utf8"));
|
|
23
|
-
|
|
24
|
-
let output = "";
|
|
25
|
-
|
|
26
|
-
for (const key in input) {
|
|
27
|
-
output += `@${key}\n`;
|
|
28
|
-
output += `${input[key].message}\n\n`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const outputPath = join(outputDir, `${lang}.i18n`);
|
|
32
|
-
writeFileSync(outputPath, output);
|
|
33
|
-
|
|
34
|
-
console.log(`${lang}.i18n created`);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
console.log("All conversions completed.");
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import * as readline from 'node:readline/promises';
|
|
3
|
-
import { stdin as input, stdout as output } from 'node:process';
|
|
4
|
-
import {readFile, writeFile, httpsRequest, timeout} from '../tasks/utils.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const LOCALES_ROOT = 'src/_locales';
|
|
8
|
-
|
|
9
|
-
function toMessageId(message) {
|
|
10
|
-
if (typeof message !== 'string') return '';
|
|
11
|
-
|
|
12
|
-
return message
|
|
13
|
-
.trim()
|
|
14
|
-
.split(/\s+/) // split by any whitespace
|
|
15
|
-
.slice(0, 3) // only first 3 words
|
|
16
|
-
.map(word =>
|
|
17
|
-
word
|
|
18
|
-
.replace(/[^\w]/g, '') // remove special characters
|
|
19
|
-
.toLowerCase()
|
|
20
|
-
)
|
|
21
|
-
.filter(Boolean) // remove empty results
|
|
22
|
-
.join('_');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function getSupportedLocales() {
|
|
26
|
-
const fileList = await fs.readdir(LOCALES_ROOT);
|
|
27
|
-
|
|
28
|
-
const locales = [];
|
|
29
|
-
|
|
30
|
-
for (const file of fileList) {
|
|
31
|
-
if (file.endsWith('.i18n')) {
|
|
32
|
-
const locale = file.substring(0, file.lastIndexOf('.i18n'));
|
|
33
|
-
locales.push(locale);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return locales;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function stringifyLocale(messages) {
|
|
41
|
-
const lines = [];
|
|
42
|
-
messages.forEach((message, id) => {
|
|
43
|
-
lines.push(`@${id}`);
|
|
44
|
-
const hasDoubleNewLines = /\n\n/.test(message);
|
|
45
|
-
message.split('\n')
|
|
46
|
-
.filter((line) => line.trim())
|
|
47
|
-
.forEach((line, index, filtered) => {
|
|
48
|
-
lines.push(line);
|
|
49
|
-
if (hasDoubleNewLines && index < filtered.length - 1) {
|
|
50
|
-
lines.push('');
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
lines.push('');
|
|
54
|
-
});
|
|
55
|
-
return lines.join('\n');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function parseLocale(content) {
|
|
59
|
-
const messages = new Map();
|
|
60
|
-
const lines = content.split('\n');
|
|
61
|
-
let id = '';
|
|
62
|
-
for (let i = 0; i < lines.length; i++) {
|
|
63
|
-
const line = lines[i];
|
|
64
|
-
if (line.startsWith('@')) {
|
|
65
|
-
id = line.substring(1);
|
|
66
|
-
} else if (line.startsWith('#')) {
|
|
67
|
-
// Ignore
|
|
68
|
-
} else if (messages.has(id)) {
|
|
69
|
-
const message = messages.get(id);
|
|
70
|
-
messages.set(id, `${message}\n${line}`);
|
|
71
|
-
} else {
|
|
72
|
-
messages.set(id, line);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
messages.forEach((value, id) => {
|
|
76
|
-
messages.set(id, value.trim());
|
|
77
|
-
});
|
|
78
|
-
return messages;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async function translate(text, lang) {
|
|
82
|
-
const url = new URL('https://translate.googleapis.com/translate_a/single');
|
|
83
|
-
url.search = (new URLSearchParams({
|
|
84
|
-
client: 'gtx',
|
|
85
|
-
sl: 'en-US',
|
|
86
|
-
tl: lang,
|
|
87
|
-
dt: 't',
|
|
88
|
-
dj: '1',
|
|
89
|
-
q: text,
|
|
90
|
-
})).toString();
|
|
91
|
-
const response = await httpsRequest(url.toString());
|
|
92
|
-
const translation = JSON.parse(response.text());
|
|
93
|
-
return translation.sentences.map((s) => s.trans).join('\n').replaceAll(/\n+/g, '\n');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async function deleteMessage(messageId, targetLocale = null) {
|
|
97
|
-
const supportedLocales = await getSupportedLocales();
|
|
98
|
-
|
|
99
|
-
if (!messageId || !messageId.trim()) {
|
|
100
|
-
console.log('⚠ Message key cannot be empty.');
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const id = messageId.trim();
|
|
105
|
-
let foundAnywhere = false;
|
|
106
|
-
|
|
107
|
-
// 🎯 Decide scope
|
|
108
|
-
const localesToProcess = targetLocale
|
|
109
|
-
? [targetLocale]
|
|
110
|
-
: supportedLocales;
|
|
111
|
-
|
|
112
|
-
for (const locale of localesToProcess) {
|
|
113
|
-
const locFile = `${LOCALES_ROOT}/${locale}.i18n`;
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const locContent = await readFile(locFile);
|
|
117
|
-
const locMessages = parseLocale(locContent);
|
|
118
|
-
|
|
119
|
-
if (!locMessages.has(id)) {
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
locMessages.delete(id);
|
|
124
|
-
|
|
125
|
-
const output = stringifyLocale(locMessages);
|
|
126
|
-
await writeFile(locFile, output);
|
|
127
|
-
|
|
128
|
-
console.log(`✔ Removed from ${locale}.i18n`);
|
|
129
|
-
foundAnywhere = true;
|
|
130
|
-
|
|
131
|
-
} catch (err) {
|
|
132
|
-
console.log(`⚠ Failed to process ${locale}: ${err.message}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// 🧾 Final status
|
|
137
|
-
if (!foundAnywhere) {
|
|
138
|
-
console.log(
|
|
139
|
-
targetLocale
|
|
140
|
-
? `⚠ Message key not found in ${targetLocale}.`
|
|
141
|
-
: '⚠ Message key not found in any locale.'
|
|
142
|
-
);
|
|
143
|
-
} else {
|
|
144
|
-
console.log('🗑 Deletion completed.');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
async function translateEnMessage(message, customId) {
|
|
150
|
-
console.log(`Translating message: ${message}`);
|
|
151
|
-
|
|
152
|
-
const supportedLocales = await getSupportedLocales();
|
|
153
|
-
const messageId = customId && customId.trim()
|
|
154
|
-
? customId.trim()
|
|
155
|
-
: toMessageId(message);
|
|
156
|
-
|
|
157
|
-
// 1️⃣ Update English first
|
|
158
|
-
const enFile = `${LOCALES_ROOT}/en.i18n`;
|
|
159
|
-
const enContent = await readFile(enFile);
|
|
160
|
-
const enMessages = parseLocale(enContent);
|
|
161
|
-
|
|
162
|
-
if (!enMessages.has(messageId)) {
|
|
163
|
-
enMessages.set(messageId, message);
|
|
164
|
-
const output = stringifyLocale(enMessages);
|
|
165
|
-
await writeFile(enFile, output);
|
|
166
|
-
console.log(`en: ${message}`);
|
|
167
|
-
} else {
|
|
168
|
-
console.log('Message already exists in en.i18n');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// 2️⃣ Translate other locales
|
|
172
|
-
for (const locale of supportedLocales) {
|
|
173
|
-
if (locale === 'en') continue;
|
|
174
|
-
|
|
175
|
-
await timeout(1000);
|
|
176
|
-
|
|
177
|
-
const locFile = `${LOCALES_ROOT}/${locale}.i18n`;
|
|
178
|
-
const locContent = await readFile(locFile);
|
|
179
|
-
const locMessages = parseLocale(locContent);
|
|
180
|
-
|
|
181
|
-
if (locMessages.has(messageId)) {
|
|
182
|
-
console.log(`Already exists in: ${locFile}`);
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const translatedDefault = await translate(message, locale);
|
|
187
|
-
|
|
188
|
-
console.log(`✅ Output: ${locale}: ${translatedDefault}`);
|
|
189
|
-
|
|
190
|
-
locMessages.set(messageId, translatedDefault);
|
|
191
|
-
|
|
192
|
-
const outputs = stringifyLocale(locMessages);
|
|
193
|
-
await writeFile(locFile, outputs);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function main() {
|
|
198
|
-
const rl = readline.createInterface({ input, output });
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
while (true) {
|
|
202
|
-
console.log('\n=== Message Manager ===');
|
|
203
|
-
console.log('[1] Add new message');
|
|
204
|
-
console.log('[2] Delete message');
|
|
205
|
-
console.log('[0] Exit');
|
|
206
|
-
|
|
207
|
-
const choice = (await rl.question('Select option: '))
|
|
208
|
-
.trim()
|
|
209
|
-
.toLowerCase();
|
|
210
|
-
|
|
211
|
-
switch (choice) {
|
|
212
|
-
case '1': {
|
|
213
|
-
const newMessage = (await rl.question('Enter new message: '))
|
|
214
|
-
.trim();
|
|
215
|
-
|
|
216
|
-
if (!newMessage) {
|
|
217
|
-
console.log('⚠ Message cannot be empty.');
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const newMessageId = (await rl.question(
|
|
222
|
-
'Enter new message key (leave empty for auto-generation): '
|
|
223
|
-
)).trim();
|
|
224
|
-
|
|
225
|
-
await translateEnMessage(
|
|
226
|
-
newMessage,
|
|
227
|
-
newMessageId || undefined
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
console.log('✔ Message processed successfully.');
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
case '2': {
|
|
235
|
-
const messageId = (await rl.question(
|
|
236
|
-
'Enter message key to delete: '
|
|
237
|
-
)).trim();
|
|
238
|
-
|
|
239
|
-
if (!messageId) {
|
|
240
|
-
console.log('⚠ Message key cannot be empty.');
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// 🌍 Ask scope
|
|
245
|
-
const scope = (await rl.question(
|
|
246
|
-
'Delete from (a)ll locales or specific locale? (a/s): '
|
|
247
|
-
)).trim().toLowerCase();
|
|
248
|
-
|
|
249
|
-
let targetLocale = null;
|
|
250
|
-
|
|
251
|
-
if (scope === 's') {
|
|
252
|
-
targetLocale = (await rl.question(
|
|
253
|
-
'Enter locale (e.g., en, fa, ru): '
|
|
254
|
-
)).trim();
|
|
255
|
-
|
|
256
|
-
if (!targetLocale) {
|
|
257
|
-
console.log('⚠ Locale cannot be empty.');
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// ✅ Confirmation
|
|
263
|
-
const confirm = (await rl.question(
|
|
264
|
-
targetLocale
|
|
265
|
-
? `Are you sure you want to delete "${messageId}" from "${targetLocale}"? (y/n): `
|
|
266
|
-
: `Are you sure you want to delete "${messageId}" from ALL locales? (y/n): `
|
|
267
|
-
)).trim().toLowerCase();
|
|
268
|
-
|
|
269
|
-
if (confirm !== 'y') {
|
|
270
|
-
console.log('Deletion cancelled.');
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// 🔥 Delete logic
|
|
275
|
-
if (targetLocale) {
|
|
276
|
-
await deleteMessage(messageId, targetLocale);
|
|
277
|
-
} else {
|
|
278
|
-
await deleteMessage(messageId);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
console.log('Deleted ✅');
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
case '0':
|
|
286
|
-
case 'exit': {
|
|
287
|
-
console.log('Exiting...');
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
default: {
|
|
292
|
-
console.log('Invalid selection. Please try again.');
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
} finally {
|
|
297
|
-
rl.close();
|
|
298
|
-
}
|
|
299
|
-
}main();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|