poly-lexis 0.1.0
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 +280 -0
- package/dist/cli/translations.d.ts +2 -0
- package/dist/cli/translations.js +1364 -0
- package/dist/cli/translations.js.map +1 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +1016 -0
- package/dist/index.js.map +1 -0
- package/dist/translations/core/translations-config.schema.json +94 -0
- package/package.json +65 -0
|
@@ -0,0 +1,1364 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
10
|
+
var __esm = (fn, res) => function __init() {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
};
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// node_modules/tsup/assets/esm_shims.js
|
|
19
|
+
import path from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
var init_esm_shims = __esm({
|
|
22
|
+
"node_modules/tsup/assets/esm_shims.js"() {
|
|
23
|
+
"use strict";
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// src/translations/utils/utils.ts
|
|
28
|
+
import * as fs from "fs";
|
|
29
|
+
import * as path2 from "path";
|
|
30
|
+
function readTranslations(translationsPath, language) {
|
|
31
|
+
const langPath = path2.join(translationsPath, language);
|
|
32
|
+
if (!fs.existsSync(langPath)) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
|
|
36
|
+
const translations = {};
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
const namespace = path2.basename(file, ".json");
|
|
39
|
+
const filePath = path2.join(langPath, file);
|
|
40
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
41
|
+
translations[namespace] = JSON.parse(content);
|
|
42
|
+
}
|
|
43
|
+
return translations;
|
|
44
|
+
}
|
|
45
|
+
function writeTranslation(translationsPath, language, namespace, translations) {
|
|
46
|
+
const langPath = path2.join(translationsPath, language);
|
|
47
|
+
if (!fs.existsSync(langPath)) {
|
|
48
|
+
fs.mkdirSync(langPath, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
const filePath = path2.join(langPath, `${namespace}.json`);
|
|
51
|
+
fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + "\n", "utf-8");
|
|
52
|
+
}
|
|
53
|
+
function getAvailableLanguages(translationsPath) {
|
|
54
|
+
if (!fs.existsSync(translationsPath)) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
58
|
+
}
|
|
59
|
+
function getNamespaces(translationsPath, language) {
|
|
60
|
+
const langPath = path2.join(translationsPath, language);
|
|
61
|
+
if (!fs.existsSync(langPath)) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path2.basename(f, ".json"));
|
|
65
|
+
}
|
|
66
|
+
function sortKeys(obj) {
|
|
67
|
+
const sorted = {};
|
|
68
|
+
const keys = Object.keys(obj).sort();
|
|
69
|
+
for (const key of keys) {
|
|
70
|
+
sorted[key] = obj[key];
|
|
71
|
+
}
|
|
72
|
+
return sorted;
|
|
73
|
+
}
|
|
74
|
+
function ensureTranslationsStructure(translationsPath, languages) {
|
|
75
|
+
if (!fs.existsSync(translationsPath)) {
|
|
76
|
+
fs.mkdirSync(translationsPath, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
for (const lang of languages) {
|
|
79
|
+
const langPath = path2.join(translationsPath, lang);
|
|
80
|
+
if (!fs.existsSync(langPath)) {
|
|
81
|
+
fs.mkdirSync(langPath, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
var init_utils = __esm({
|
|
86
|
+
"src/translations/utils/utils.ts"() {
|
|
87
|
+
"use strict";
|
|
88
|
+
init_esm_shims();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// src/translations/core/schema.ts
|
|
93
|
+
function isValidLanguage(lang) {
|
|
94
|
+
return SUPPORTED_LANGUAGES.includes(lang);
|
|
95
|
+
}
|
|
96
|
+
function validateLanguages(languages) {
|
|
97
|
+
const invalid = languages.filter((lang) => !isValidLanguage(lang));
|
|
98
|
+
return {
|
|
99
|
+
valid: invalid.length === 0,
|
|
100
|
+
invalid
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
var SUPPORTED_LANGUAGES;
|
|
104
|
+
var init_schema = __esm({
|
|
105
|
+
"src/translations/core/schema.ts"() {
|
|
106
|
+
"use strict";
|
|
107
|
+
init_esm_shims();
|
|
108
|
+
SUPPORTED_LANGUAGES = [
|
|
109
|
+
"en",
|
|
110
|
+
// English
|
|
111
|
+
"fr",
|
|
112
|
+
// French
|
|
113
|
+
"it",
|
|
114
|
+
// Italian
|
|
115
|
+
"pl",
|
|
116
|
+
// Polish
|
|
117
|
+
"es",
|
|
118
|
+
// Spanish
|
|
119
|
+
"pt",
|
|
120
|
+
// Portuguese
|
|
121
|
+
"de",
|
|
122
|
+
// German
|
|
123
|
+
"de_at",
|
|
124
|
+
// German (Austria)
|
|
125
|
+
"nl",
|
|
126
|
+
// Dutch
|
|
127
|
+
"sv",
|
|
128
|
+
// Swedish
|
|
129
|
+
"hu",
|
|
130
|
+
// Hungarian
|
|
131
|
+
"cs",
|
|
132
|
+
// Czech
|
|
133
|
+
"ja",
|
|
134
|
+
// Japanese
|
|
135
|
+
"zh_hk",
|
|
136
|
+
// Chinese (Hong Kong)
|
|
137
|
+
"zh_cn",
|
|
138
|
+
// Chinese (Simplified)
|
|
139
|
+
"ko",
|
|
140
|
+
// Korean
|
|
141
|
+
"ru",
|
|
142
|
+
// Russian
|
|
143
|
+
"ar",
|
|
144
|
+
// Arabic
|
|
145
|
+
"he",
|
|
146
|
+
// Hebrew
|
|
147
|
+
"tr",
|
|
148
|
+
// Turkish
|
|
149
|
+
"da",
|
|
150
|
+
// Danish
|
|
151
|
+
"fi",
|
|
152
|
+
// Finnish
|
|
153
|
+
"no",
|
|
154
|
+
// Norwegian
|
|
155
|
+
"pt_br"
|
|
156
|
+
// Portuguese (Brazil)
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/translations/core/types.ts
|
|
162
|
+
var DEFAULT_CONFIG, DEFAULT_LANGUAGES;
|
|
163
|
+
var init_types = __esm({
|
|
164
|
+
"src/translations/core/types.ts"() {
|
|
165
|
+
"use strict";
|
|
166
|
+
init_esm_shims();
|
|
167
|
+
DEFAULT_CONFIG = {
|
|
168
|
+
translationsPath: "public/static/locales",
|
|
169
|
+
languages: ["en"],
|
|
170
|
+
sourceLanguage: "en",
|
|
171
|
+
typesOutputPath: "src/types/i18nTypes.ts"
|
|
172
|
+
};
|
|
173
|
+
DEFAULT_LANGUAGES = [
|
|
174
|
+
"en",
|
|
175
|
+
"fr",
|
|
176
|
+
"it",
|
|
177
|
+
"pl",
|
|
178
|
+
"es",
|
|
179
|
+
"pt",
|
|
180
|
+
"de",
|
|
181
|
+
"de_at",
|
|
182
|
+
"nl",
|
|
183
|
+
"sv",
|
|
184
|
+
"hu",
|
|
185
|
+
"cs",
|
|
186
|
+
"ja",
|
|
187
|
+
"zh_hk"
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// src/translations/cli/init.ts
|
|
193
|
+
var init_exports = {};
|
|
194
|
+
__export(init_exports, {
|
|
195
|
+
detectExistingTranslations: () => detectExistingTranslations,
|
|
196
|
+
initTranslations: () => initTranslations,
|
|
197
|
+
loadConfig: () => loadConfig
|
|
198
|
+
});
|
|
199
|
+
import * as fs2 from "fs";
|
|
200
|
+
import * as path3 from "path";
|
|
201
|
+
function detectExistingTranslations(projectRoot) {
|
|
202
|
+
const possiblePaths = ["public/static/locales", "public/locales", "src/locales", "locales", "i18n", "translations"];
|
|
203
|
+
for (const possiblePath of possiblePaths) {
|
|
204
|
+
const fullPath = path3.join(projectRoot, possiblePath);
|
|
205
|
+
if (fs2.existsSync(fullPath)) {
|
|
206
|
+
const languages = getAvailableLanguages(fullPath);
|
|
207
|
+
if (languages.length > 0) {
|
|
208
|
+
return { path: possiblePath, languages };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { path: null, languages: [] };
|
|
213
|
+
}
|
|
214
|
+
function initTranslations(projectRoot, config = {}) {
|
|
215
|
+
console.log("=====");
|
|
216
|
+
console.log("Initializing translation structure");
|
|
217
|
+
console.log("=====");
|
|
218
|
+
const existing = detectExistingTranslations(projectRoot);
|
|
219
|
+
let finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
220
|
+
if (existing.path && existing.languages.length > 0) {
|
|
221
|
+
console.log(`\u2713 Detected existing translations at: ${existing.path}`);
|
|
222
|
+
console.log(`\u2713 Found languages: ${existing.languages.join(", ")}`);
|
|
223
|
+
const validation2 = validateLanguages(existing.languages);
|
|
224
|
+
if (!validation2.valid) {
|
|
225
|
+
console.log(`\u26A0\uFE0F Warning: Invalid language codes found: ${validation2.invalid.join(", ")}`);
|
|
226
|
+
console.log("These languages will be skipped.");
|
|
227
|
+
}
|
|
228
|
+
const validLanguages = existing.languages.filter((lang) => !validation2.invalid.includes(lang));
|
|
229
|
+
finalConfig = {
|
|
230
|
+
...finalConfig,
|
|
231
|
+
translationsPath: existing.path,
|
|
232
|
+
languages: validLanguages.length > 0 ? validLanguages : finalConfig.languages
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const translationsPath = path3.join(projectRoot, finalConfig.translationsPath);
|
|
236
|
+
const languages = finalConfig.languages.length > 0 ? finalConfig.languages : [...DEFAULT_LANGUAGES];
|
|
237
|
+
console.log(`Project root: ${projectRoot}`);
|
|
238
|
+
console.log(`Translations path: ${translationsPath}`);
|
|
239
|
+
console.log(`Languages: ${languages.join(", ")}`);
|
|
240
|
+
console.log("=====");
|
|
241
|
+
const validation = validateLanguages(languages);
|
|
242
|
+
if (!validation.valid) {
|
|
243
|
+
throw new Error(`Invalid language codes: ${validation.invalid.join(", ")}`);
|
|
244
|
+
}
|
|
245
|
+
ensureTranslationsStructure(translationsPath, languages);
|
|
246
|
+
const sourceLanguage = finalConfig.sourceLanguage;
|
|
247
|
+
const sourcePath = path3.join(translationsPath, sourceLanguage);
|
|
248
|
+
const commonPath = path3.join(sourcePath, "common.json");
|
|
249
|
+
if (!fs2.existsSync(commonPath)) {
|
|
250
|
+
const sampleTranslations = {
|
|
251
|
+
LOADING: "Loading",
|
|
252
|
+
SAVE: "Save",
|
|
253
|
+
CANCEL: "Cancel",
|
|
254
|
+
SUBMIT: "Submit",
|
|
255
|
+
ERROR: "Error",
|
|
256
|
+
SUCCESS: "Success"
|
|
257
|
+
};
|
|
258
|
+
fs2.writeFileSync(commonPath, JSON.stringify(sampleTranslations, null, 2) + "\n", "utf-8");
|
|
259
|
+
console.log(`Created sample file: ${commonPath}`);
|
|
260
|
+
}
|
|
261
|
+
for (const lang of languages) {
|
|
262
|
+
if (lang === sourceLanguage) continue;
|
|
263
|
+
const langCommonPath = path3.join(translationsPath, lang, "common.json");
|
|
264
|
+
if (!fs2.existsSync(langCommonPath)) {
|
|
265
|
+
fs2.writeFileSync(langCommonPath, "{}\n", "utf-8");
|
|
266
|
+
console.log(`Created empty file: ${langCommonPath}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const configPath = path3.join(projectRoot, ".translationsrc.json");
|
|
270
|
+
if (!fs2.existsSync(configPath)) {
|
|
271
|
+
const configContent = {
|
|
272
|
+
$schema: "./node_modules/@repo/env-scripts/dist/translations/core/translations-config.schema.json",
|
|
273
|
+
translationsPath: finalConfig.translationsPath,
|
|
274
|
+
languages,
|
|
275
|
+
sourceLanguage,
|
|
276
|
+
typesOutputPath: finalConfig.typesOutputPath
|
|
277
|
+
};
|
|
278
|
+
fs2.writeFileSync(configPath, JSON.stringify(configContent, null, 2) + "\n", "utf-8");
|
|
279
|
+
console.log(`Created config file: ${configPath}`);
|
|
280
|
+
}
|
|
281
|
+
console.log("=====");
|
|
282
|
+
console.log("Translation structure initialized successfully!");
|
|
283
|
+
console.log("=====");
|
|
284
|
+
}
|
|
285
|
+
function loadConfig(projectRoot) {
|
|
286
|
+
const configPath = path3.join(projectRoot, ".translationsrc.json");
|
|
287
|
+
if (!fs2.existsSync(configPath)) {
|
|
288
|
+
const existing = detectExistingTranslations(projectRoot);
|
|
289
|
+
if (existing.path && existing.languages.length > 0) {
|
|
290
|
+
console.log(`\u2139\uFE0F No config found, but detected translations at ${existing.path}`);
|
|
291
|
+
return {
|
|
292
|
+
...DEFAULT_CONFIG,
|
|
293
|
+
translationsPath: existing.path,
|
|
294
|
+
languages: existing.languages
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
return DEFAULT_CONFIG;
|
|
298
|
+
}
|
|
299
|
+
const configContent = fs2.readFileSync(configPath, "utf-8");
|
|
300
|
+
const config = JSON.parse(configContent);
|
|
301
|
+
if (config.languages) {
|
|
302
|
+
const validation = validateLanguages(config.languages);
|
|
303
|
+
if (!validation.valid) {
|
|
304
|
+
console.warn(`\u26A0\uFE0F Warning: Invalid language codes in config: ${validation.invalid.join(", ")}`);
|
|
305
|
+
console.warn("Please update .translationsrc.json with valid language codes.");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return { ...DEFAULT_CONFIG, ...config };
|
|
309
|
+
}
|
|
310
|
+
var init_init = __esm({
|
|
311
|
+
"src/translations/cli/init.ts"() {
|
|
312
|
+
"use strict";
|
|
313
|
+
init_esm_shims();
|
|
314
|
+
init_schema();
|
|
315
|
+
init_types();
|
|
316
|
+
init_utils();
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// src/translations/cli/generate-types.ts
|
|
321
|
+
var generate_types_exports = {};
|
|
322
|
+
__export(generate_types_exports, {
|
|
323
|
+
generateTranslationTypes: () => generateTranslationTypes
|
|
324
|
+
});
|
|
325
|
+
import { execSync } from "child_process";
|
|
326
|
+
import * as fs3 from "fs";
|
|
327
|
+
import * as path8 from "path";
|
|
328
|
+
function generateTranslationTypes(projectRoot = process.cwd()) {
|
|
329
|
+
console.log("=====");
|
|
330
|
+
console.time("i18n types generated");
|
|
331
|
+
console.log("Generating i18n types");
|
|
332
|
+
console.log("=====");
|
|
333
|
+
const config = loadConfig(projectRoot);
|
|
334
|
+
const translationsPath = path8.join(projectRoot, config.translationsPath);
|
|
335
|
+
const sourceLanguage = config.sourceLanguage;
|
|
336
|
+
const outputFilePath = path8.join(projectRoot, config.typesOutputPath);
|
|
337
|
+
const dirPath = path8.join(translationsPath, sourceLanguage);
|
|
338
|
+
if (!fs3.existsSync(dirPath)) {
|
|
339
|
+
throw new Error(`Source language directory not found: ${dirPath}`);
|
|
340
|
+
}
|
|
341
|
+
const namespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
342
|
+
if (namespaces.length === 0) {
|
|
343
|
+
throw new Error(`No translation files found in ${dirPath}`);
|
|
344
|
+
}
|
|
345
|
+
const translations = readTranslations(translationsPath, sourceLanguage);
|
|
346
|
+
let allKeys = [];
|
|
347
|
+
for (const namespace of namespaces) {
|
|
348
|
+
const keys = Object.keys(translations[namespace] || {});
|
|
349
|
+
allKeys = allKeys.concat(keys);
|
|
350
|
+
}
|
|
351
|
+
const outputDir = path8.dirname(outputFilePath);
|
|
352
|
+
if (!fs3.existsSync(outputDir)) {
|
|
353
|
+
fs3.mkdirSync(outputDir, { recursive: true });
|
|
354
|
+
}
|
|
355
|
+
const typeString = typeTemplate(allKeys, namespaces);
|
|
356
|
+
fs3.writeFileSync(outputFilePath, typeString, "utf8");
|
|
357
|
+
console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
|
|
358
|
+
console.log(`Output: ${outputFilePath}`);
|
|
359
|
+
try {
|
|
360
|
+
execSync(`pnpm biome format --write ${outputFilePath}`, { stdio: "inherit", cwd: projectRoot });
|
|
361
|
+
} catch {
|
|
362
|
+
console.warn("Failed to format with Biome, continuing without formatting...");
|
|
363
|
+
}
|
|
364
|
+
console.timeEnd("i18n types generated");
|
|
365
|
+
console.log("=====");
|
|
366
|
+
}
|
|
367
|
+
var typeTemplate;
|
|
368
|
+
var init_generate_types = __esm({
|
|
369
|
+
"src/translations/cli/generate-types.ts"() {
|
|
370
|
+
"use strict";
|
|
371
|
+
init_esm_shims();
|
|
372
|
+
init_utils();
|
|
373
|
+
init_init();
|
|
374
|
+
typeTemplate = (translationKeys, namespaceKeys) => `
|
|
375
|
+
export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
|
|
376
|
+
export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
|
|
377
|
+
|
|
378
|
+
export type TranslationKey = typeof translationKeys[number];
|
|
379
|
+
export type TranslationNamespace = typeof namespaceKeys[number];
|
|
380
|
+
`;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// src/cli/translations.ts
|
|
385
|
+
init_esm_shims();
|
|
386
|
+
import "dotenv/config";
|
|
387
|
+
import { confirm as confirm2, input as input2, select } from "@inquirer/prompts";
|
|
388
|
+
import * as fs5 from "fs";
|
|
389
|
+
import * as path10 from "path";
|
|
390
|
+
import { parseArgs } from "util";
|
|
391
|
+
|
|
392
|
+
// src/translations/cli/add-key.ts
|
|
393
|
+
init_esm_shims();
|
|
394
|
+
import * as path4 from "path";
|
|
395
|
+
|
|
396
|
+
// src/translations/utils/translator.ts
|
|
397
|
+
init_esm_shims();
|
|
398
|
+
async function translateText(text, targetLang, sourceLang = "en", apiKey) {
|
|
399
|
+
if (!apiKey) {
|
|
400
|
+
throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable.");
|
|
401
|
+
}
|
|
402
|
+
const variableMap = /* @__PURE__ */ new Map();
|
|
403
|
+
let placeholderIndex = 0;
|
|
404
|
+
const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
|
|
405
|
+
const placeholder = `__PLACEHOLDER_${placeholderIndex}__`;
|
|
406
|
+
variableMap.set(placeholder, match);
|
|
407
|
+
placeholderIndex++;
|
|
408
|
+
return placeholder;
|
|
409
|
+
});
|
|
410
|
+
const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
|
|
411
|
+
const response = await fetch(url, {
|
|
412
|
+
method: "POST",
|
|
413
|
+
headers: {
|
|
414
|
+
"Content-Type": "application/json"
|
|
415
|
+
},
|
|
416
|
+
body: JSON.stringify({
|
|
417
|
+
q: textWithPlaceholders,
|
|
418
|
+
source: sourceLang,
|
|
419
|
+
target: targetLang.split("_")[0],
|
|
420
|
+
// Convert 'pt_BR' to 'pt'
|
|
421
|
+
format: "text"
|
|
422
|
+
})
|
|
423
|
+
});
|
|
424
|
+
const data = await response.json();
|
|
425
|
+
if (data.error) {
|
|
426
|
+
throw new Error(`Google Translate API error: ${data.error.message}`);
|
|
427
|
+
}
|
|
428
|
+
let translatedText = data.data.translations[0].translatedText;
|
|
429
|
+
for (const [placeholder, original] of variableMap) {
|
|
430
|
+
translatedText = translatedText.replace(new RegExp(placeholder, "g"), original);
|
|
431
|
+
}
|
|
432
|
+
return translatedText;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/translations/cli/add-key.ts
|
|
436
|
+
init_utils();
|
|
437
|
+
init_init();
|
|
438
|
+
async function addTranslationKey(projectRoot, options) {
|
|
439
|
+
const config = loadConfig(projectRoot);
|
|
440
|
+
const translationsPath = path4.join(projectRoot, config.translationsPath);
|
|
441
|
+
const { namespace, key, value, autoTranslate = false, apiKey } = options;
|
|
442
|
+
console.log("=====");
|
|
443
|
+
console.log("Adding translation key");
|
|
444
|
+
console.log("=====");
|
|
445
|
+
console.log(`Namespace: ${namespace}`);
|
|
446
|
+
console.log(`Key: ${key}`);
|
|
447
|
+
console.log(`Value (${config.sourceLanguage}): ${value}`);
|
|
448
|
+
console.log("=====");
|
|
449
|
+
const sourceLang = config.sourceLanguage;
|
|
450
|
+
const sourceTranslations = readTranslations(translationsPath, sourceLang);
|
|
451
|
+
if (!sourceTranslations[namespace]) {
|
|
452
|
+
sourceTranslations[namespace] = {};
|
|
453
|
+
}
|
|
454
|
+
if (sourceTranslations[namespace][key]) {
|
|
455
|
+
console.log(`\u26A0 Warning: Key "${key}" already exists in ${namespace}. Updating value.`);
|
|
456
|
+
}
|
|
457
|
+
sourceTranslations[namespace][key] = value;
|
|
458
|
+
const sortedSource = sortKeys(sourceTranslations[namespace]);
|
|
459
|
+
writeTranslation(translationsPath, sourceLang, namespace, sortedSource);
|
|
460
|
+
console.log(`\u2713 Added to ${sourceLang}/${namespace}.json`);
|
|
461
|
+
const otherLanguages = config.languages.filter((lang) => lang !== sourceLang);
|
|
462
|
+
if (autoTranslate && apiKey) {
|
|
463
|
+
console.log("\nAuto-translating to other languages...");
|
|
464
|
+
for (const lang of otherLanguages) {
|
|
465
|
+
try {
|
|
466
|
+
const targetTranslations = readTranslations(translationsPath, lang);
|
|
467
|
+
if (!targetTranslations[namespace]) {
|
|
468
|
+
targetTranslations[namespace] = {};
|
|
469
|
+
}
|
|
470
|
+
if (!targetTranslations[namespace][key] || targetTranslations[namespace][key].trim() === "") {
|
|
471
|
+
const translated = await translateText(value, lang, sourceLang, apiKey);
|
|
472
|
+
targetTranslations[namespace][key] = translated;
|
|
473
|
+
const sorted = sortKeys(targetTranslations[namespace]);
|
|
474
|
+
writeTranslation(translationsPath, lang, namespace, sorted);
|
|
475
|
+
console.log(` \u2713 ${lang}: "${translated}"`);
|
|
476
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
477
|
+
} else {
|
|
478
|
+
console.log(` - ${lang}: Already exists, skipping`);
|
|
479
|
+
}
|
|
480
|
+
} catch (error) {
|
|
481
|
+
console.error(` \u2717 ${lang}: Translation failed - ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
} else {
|
|
485
|
+
console.log("\nAdding empty values to other languages...");
|
|
486
|
+
for (const lang of otherLanguages) {
|
|
487
|
+
const targetTranslations = readTranslations(translationsPath, lang);
|
|
488
|
+
if (!targetTranslations[namespace]) {
|
|
489
|
+
targetTranslations[namespace] = {};
|
|
490
|
+
}
|
|
491
|
+
if (!targetTranslations[namespace][key]) {
|
|
492
|
+
targetTranslations[namespace][key] = "";
|
|
493
|
+
const sorted = sortKeys(targetTranslations[namespace]);
|
|
494
|
+
writeTranslation(translationsPath, lang, namespace, sorted);
|
|
495
|
+
console.log(` \u2713 ${lang}/${namespace}.json`);
|
|
496
|
+
} else {
|
|
497
|
+
console.log(` - ${lang}/${namespace}.json: Already exists`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (!autoTranslate) {
|
|
501
|
+
console.log("\n\u2139 Use --auto-translate flag to automatically translate to all languages");
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
console.log("=====");
|
|
505
|
+
console.log("Translation key added successfully!");
|
|
506
|
+
console.log("=====");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/cli/translations.ts
|
|
510
|
+
init_init();
|
|
511
|
+
|
|
512
|
+
// src/translations/cli/init-interactive.ts
|
|
513
|
+
init_esm_shims();
|
|
514
|
+
init_schema();
|
|
515
|
+
init_types();
|
|
516
|
+
init_init();
|
|
517
|
+
import * as path5 from "path";
|
|
518
|
+
import { checkbox, confirm, input } from "@inquirer/prompts";
|
|
519
|
+
async function initTranslationsInteractive(projectRoot = process.cwd()) {
|
|
520
|
+
console.log("\n\u{1F30D} Translation System Setup\n");
|
|
521
|
+
const configPath = path5.join(projectRoot, ".translationsrc.json");
|
|
522
|
+
const alreadyExists = __require("fs").existsSync(configPath);
|
|
523
|
+
if (alreadyExists) {
|
|
524
|
+
console.log("\u26A0\uFE0F Configuration file already exists at .translationsrc.json\n");
|
|
525
|
+
const shouldOverwrite = await confirm({
|
|
526
|
+
message: "Would you like to reconfigure?",
|
|
527
|
+
default: false
|
|
528
|
+
});
|
|
529
|
+
if (!shouldOverwrite) {
|
|
530
|
+
console.log("\u2713 Keeping existing configuration");
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const { detectExistingTranslations: detectExistingTranslations2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
535
|
+
const existing = detectExistingTranslations2(projectRoot);
|
|
536
|
+
let translationsPath;
|
|
537
|
+
let languages;
|
|
538
|
+
if (existing.path) {
|
|
539
|
+
console.log(`\u2713 Found existing translations at: ${existing.path}`);
|
|
540
|
+
const useExisting = await confirm({
|
|
541
|
+
message: "Use this location?",
|
|
542
|
+
default: true
|
|
543
|
+
});
|
|
544
|
+
if (useExisting) {
|
|
545
|
+
translationsPath = existing.path;
|
|
546
|
+
} else {
|
|
547
|
+
translationsPath = await input({
|
|
548
|
+
message: "Enter translations directory path:",
|
|
549
|
+
default: DEFAULT_CONFIG.translationsPath,
|
|
550
|
+
validate: (value) => {
|
|
551
|
+
if (!value.trim()) return "Path is required";
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
translationsPath = await input({
|
|
558
|
+
message: "Where should translations be stored?",
|
|
559
|
+
default: DEFAULT_CONFIG.translationsPath,
|
|
560
|
+
validate: (value) => {
|
|
561
|
+
if (!value.trim()) return "Path is required";
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (existing.languages.length > 0) {
|
|
567
|
+
console.log(`\u2713 Found existing languages: ${existing.languages.join(", ")}`);
|
|
568
|
+
const useExistingLangs = await confirm({
|
|
569
|
+
message: "Use these languages?",
|
|
570
|
+
default: true
|
|
571
|
+
});
|
|
572
|
+
if (useExistingLangs) {
|
|
573
|
+
languages = existing.languages;
|
|
574
|
+
} else {
|
|
575
|
+
languages = await selectLanguages();
|
|
576
|
+
}
|
|
577
|
+
} else {
|
|
578
|
+
languages = await selectLanguages();
|
|
579
|
+
}
|
|
580
|
+
const sourceLanguage = await input({
|
|
581
|
+
message: "What is your source language?",
|
|
582
|
+
default: "en",
|
|
583
|
+
validate: (value) => {
|
|
584
|
+
if (!SUPPORTED_LANGUAGES.includes(value)) {
|
|
585
|
+
return `Invalid language code. Must be one of: ${SUPPORTED_LANGUAGES.join(", ")}`;
|
|
586
|
+
}
|
|
587
|
+
if (!languages.includes(value)) {
|
|
588
|
+
return "Source language must be in the list of supported languages";
|
|
589
|
+
}
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
const typesOutputPath = await input({
|
|
594
|
+
message: "Where should TypeScript types be generated?",
|
|
595
|
+
default: DEFAULT_CONFIG.typesOutputPath
|
|
596
|
+
});
|
|
597
|
+
console.log("\n\u{1F4CB} Configuration Summary:");
|
|
598
|
+
console.log(` Translations: ${translationsPath}`);
|
|
599
|
+
console.log(` Languages: ${languages.join(", ")}`);
|
|
600
|
+
console.log(` Source: ${sourceLanguage}`);
|
|
601
|
+
console.log(` Types: ${typesOutputPath}`);
|
|
602
|
+
const confirmInit = await confirm({
|
|
603
|
+
message: "\nProceed with initialization?",
|
|
604
|
+
default: true
|
|
605
|
+
});
|
|
606
|
+
if (!confirmInit) {
|
|
607
|
+
console.log("\u274C Cancelled");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const config = {
|
|
611
|
+
translationsPath,
|
|
612
|
+
languages,
|
|
613
|
+
sourceLanguage,
|
|
614
|
+
typesOutputPath
|
|
615
|
+
};
|
|
616
|
+
console.log();
|
|
617
|
+
initTranslations(projectRoot, config);
|
|
618
|
+
console.log("\n\u{1F4DD} Configuration saved to: .translationsrc.json");
|
|
619
|
+
console.log("\n\u{1F4A1} Next steps:");
|
|
620
|
+
console.log(' 1. Run "translations add" to add your first translation key');
|
|
621
|
+
console.log(' 2. Run "translations" to validate and generate types');
|
|
622
|
+
console.log(" 3. Check the .translationsrc.json file for your configuration\n");
|
|
623
|
+
}
|
|
624
|
+
async function selectLanguages() {
|
|
625
|
+
const languageChoices = SUPPORTED_LANGUAGES.map((lang) => ({
|
|
626
|
+
name: `${lang} - ${getLanguageName(lang)}`,
|
|
627
|
+
value: lang,
|
|
628
|
+
checked: lang === "en"
|
|
629
|
+
// English selected by default
|
|
630
|
+
}));
|
|
631
|
+
const selected = await checkbox({
|
|
632
|
+
message: "Select languages to support (space to select, enter to confirm):",
|
|
633
|
+
choices: languageChoices,
|
|
634
|
+
required: true,
|
|
635
|
+
pageSize: 15,
|
|
636
|
+
loop: false
|
|
637
|
+
});
|
|
638
|
+
return selected;
|
|
639
|
+
}
|
|
640
|
+
function getLanguageName(code) {
|
|
641
|
+
const names = {
|
|
642
|
+
en: "English",
|
|
643
|
+
fr: "French",
|
|
644
|
+
it: "Italian",
|
|
645
|
+
pl: "Polish",
|
|
646
|
+
es: "Spanish",
|
|
647
|
+
pt: "Portuguese",
|
|
648
|
+
de: "German",
|
|
649
|
+
de_at: "German (Austria)",
|
|
650
|
+
nl: "Dutch",
|
|
651
|
+
sv: "Swedish",
|
|
652
|
+
hu: "Hungarian",
|
|
653
|
+
cs: "Czech",
|
|
654
|
+
ja: "Japanese",
|
|
655
|
+
zh_hk: "Chinese (Hong Kong)",
|
|
656
|
+
zh_cn: "Chinese (Simplified)",
|
|
657
|
+
ko: "Korean",
|
|
658
|
+
ru: "Russian",
|
|
659
|
+
ar: "Arabic",
|
|
660
|
+
he: "Hebrew",
|
|
661
|
+
tr: "Turkish",
|
|
662
|
+
da: "Danish",
|
|
663
|
+
fi: "Finnish",
|
|
664
|
+
no: "Norwegian",
|
|
665
|
+
pt_br: "Portuguese (Brazil)"
|
|
666
|
+
};
|
|
667
|
+
return names[code] || code;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/translations/cli/manage.ts
|
|
671
|
+
init_esm_shims();
|
|
672
|
+
import * as fs4 from "fs";
|
|
673
|
+
import * as path9 from "path";
|
|
674
|
+
|
|
675
|
+
// src/translations/cli/auto-fill.ts
|
|
676
|
+
init_esm_shims();
|
|
677
|
+
import * as path7 from "path";
|
|
678
|
+
init_utils();
|
|
679
|
+
init_init();
|
|
680
|
+
|
|
681
|
+
// src/translations/cli/validate.ts
|
|
682
|
+
init_esm_shims();
|
|
683
|
+
init_utils();
|
|
684
|
+
init_init();
|
|
685
|
+
import * as path6 from "path";
|
|
686
|
+
function validateTranslations(projectRoot = process.cwd()) {
|
|
687
|
+
const config = loadConfig(projectRoot);
|
|
688
|
+
const translationsPath = path6.join(projectRoot, config.translationsPath);
|
|
689
|
+
const sourceLanguage = config.sourceLanguage;
|
|
690
|
+
const missing = [];
|
|
691
|
+
const empty = [];
|
|
692
|
+
const sourceTranslations = readTranslations(translationsPath, sourceLanguage);
|
|
693
|
+
const sourceNamespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
694
|
+
const languages = getAvailableLanguages(translationsPath).filter((lang) => lang !== sourceLanguage);
|
|
695
|
+
console.log("=====");
|
|
696
|
+
console.log("Validating translations");
|
|
697
|
+
console.log("=====");
|
|
698
|
+
console.log(`Source language: ${sourceLanguage}`);
|
|
699
|
+
console.log(`Target languages: ${languages.join(", ")}`);
|
|
700
|
+
console.log(`Namespaces: ${sourceNamespaces.join(", ")}`);
|
|
701
|
+
console.log("=====");
|
|
702
|
+
for (const language of languages) {
|
|
703
|
+
const targetTranslations = readTranslations(translationsPath, language);
|
|
704
|
+
for (const namespace of sourceNamespaces) {
|
|
705
|
+
const sourceKeys = sourceTranslations[namespace] || {};
|
|
706
|
+
const targetKeys = targetTranslations[namespace] || {};
|
|
707
|
+
for (const [key, sourceValue] of Object.entries(sourceKeys)) {
|
|
708
|
+
const targetValue = targetKeys[key];
|
|
709
|
+
if (targetValue === void 0) {
|
|
710
|
+
missing.push({
|
|
711
|
+
namespace,
|
|
712
|
+
key,
|
|
713
|
+
language,
|
|
714
|
+
sourceValue
|
|
715
|
+
});
|
|
716
|
+
} else if (typeof targetValue === "string" && targetValue.trim() === "") {
|
|
717
|
+
empty.push({
|
|
718
|
+
namespace,
|
|
719
|
+
key,
|
|
720
|
+
language,
|
|
721
|
+
sourceValue
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const valid = missing.length === 0 && empty.length === 0;
|
|
728
|
+
if (valid) {
|
|
729
|
+
console.log("\u2713 All translations are valid!");
|
|
730
|
+
} else {
|
|
731
|
+
if (missing.length > 0) {
|
|
732
|
+
console.log(`
|
|
733
|
+
\u26A0 Found ${missing.length} missing translations:`);
|
|
734
|
+
for (const item of missing.slice(0, 10)) {
|
|
735
|
+
console.log(` ${item.language}/${item.namespace}.json -> ${item.key}`);
|
|
736
|
+
}
|
|
737
|
+
if (missing.length > 10) {
|
|
738
|
+
console.log(` ... and ${missing.length - 10} more`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (empty.length > 0) {
|
|
742
|
+
console.log(`
|
|
743
|
+
\u26A0 Found ${empty.length} empty translations:`);
|
|
744
|
+
for (const item of empty.slice(0, 10)) {
|
|
745
|
+
console.log(` ${item.language}/${item.namespace}.json -> ${item.key}`);
|
|
746
|
+
}
|
|
747
|
+
if (empty.length > 10) {
|
|
748
|
+
console.log(` ... and ${empty.length - 10} more`);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
console.log("=====");
|
|
753
|
+
return { valid, missing, empty };
|
|
754
|
+
}
|
|
755
|
+
function getMissingForLanguage(projectRoot, language) {
|
|
756
|
+
const result = validateTranslations(projectRoot);
|
|
757
|
+
const items = [
|
|
758
|
+
...result.missing.filter((m) => m.language === language).map((m) => ({ ...m, type: "missing" })),
|
|
759
|
+
...result.empty.filter((e) => e.language === language).map((e) => ({ ...e, type: "empty" }))
|
|
760
|
+
];
|
|
761
|
+
return items;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// src/translations/cli/auto-fill.ts
|
|
765
|
+
async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
|
|
766
|
+
const config = loadConfig(projectRoot);
|
|
767
|
+
const translationsPath = path7.join(projectRoot, config.translationsPath);
|
|
768
|
+
const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
|
|
769
|
+
if (!apiKey) {
|
|
770
|
+
throw new Error("Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY or pass --api-key");
|
|
771
|
+
}
|
|
772
|
+
const languagesToProcess = options.language ? [options.language] : config.languages.filter((lang) => lang !== config.sourceLanguage);
|
|
773
|
+
console.log("=====");
|
|
774
|
+
console.log("Auto-filling translations");
|
|
775
|
+
console.log("=====");
|
|
776
|
+
console.log(`Languages: ${languagesToProcess.join(", ")}`);
|
|
777
|
+
console.log(`Limit: ${limit}`);
|
|
778
|
+
console.log(`Dry run: ${dryRun}`);
|
|
779
|
+
console.log("=====");
|
|
780
|
+
let totalProcessed = 0;
|
|
781
|
+
let totalTranslated = 0;
|
|
782
|
+
for (const language of languagesToProcess) {
|
|
783
|
+
if (totalProcessed >= limit) {
|
|
784
|
+
console.log(`
|
|
785
|
+
Reached limit of ${limit} translations`);
|
|
786
|
+
break;
|
|
787
|
+
}
|
|
788
|
+
console.log(`
|
|
789
|
+
Processing language: ${language}`);
|
|
790
|
+
const missing = getMissingForLanguage(projectRoot, language);
|
|
791
|
+
if (missing.length === 0) {
|
|
792
|
+
console.log(" No missing or empty translations");
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
console.log(` Found ${missing.length} translations to fill`);
|
|
796
|
+
const remainingLimit = limit - totalProcessed;
|
|
797
|
+
const itemsToProcess = missing.slice(0, remainingLimit);
|
|
798
|
+
for (const item of itemsToProcess) {
|
|
799
|
+
totalProcessed++;
|
|
800
|
+
try {
|
|
801
|
+
console.log(` [${totalProcessed}/${limit}] Translating ${item.namespace}.${item.key}`);
|
|
802
|
+
console.log(` EN: "${item.sourceValue}"`);
|
|
803
|
+
const translated = await translateText(item.sourceValue, language, config.sourceLanguage, apiKey);
|
|
804
|
+
console.log(` ${language.toUpperCase()}: "${translated}"`);
|
|
805
|
+
if (!dryRun) {
|
|
806
|
+
const translations = readTranslations(translationsPath, language);
|
|
807
|
+
if (!translations[item.namespace]) {
|
|
808
|
+
translations[item.namespace] = {};
|
|
809
|
+
}
|
|
810
|
+
translations[item.namespace][item.key] = translated;
|
|
811
|
+
const sorted = sortKeys(translations[item.namespace]);
|
|
812
|
+
writeTranslation(translationsPath, language, item.namespace, sorted);
|
|
813
|
+
console.log(" \u2713 Saved");
|
|
814
|
+
} else {
|
|
815
|
+
console.log(" \u2713 Dry run - not saved");
|
|
816
|
+
}
|
|
817
|
+
totalTranslated++;
|
|
818
|
+
if (delayMs > 0 && totalProcessed < limit) {
|
|
819
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
820
|
+
}
|
|
821
|
+
} catch (error) {
|
|
822
|
+
console.error(` \u2717 Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
console.log("\n=====");
|
|
827
|
+
console.log(`Total processed: ${totalProcessed}`);
|
|
828
|
+
console.log(`Total translated: ${totalTranslated}`);
|
|
829
|
+
if (dryRun) {
|
|
830
|
+
console.log("\u26A0 Dry run - no changes were saved");
|
|
831
|
+
}
|
|
832
|
+
console.log("=====");
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// src/translations/cli/manage.ts
|
|
836
|
+
init_generate_types();
|
|
837
|
+
init_init();
|
|
838
|
+
async function manageTranslations(projectRoot = process.cwd(), options = {}) {
|
|
839
|
+
const { autoFill = false, apiKey, limit = 1e3, language, skipTypes = false, dryRun = false } = options;
|
|
840
|
+
console.log("=====");
|
|
841
|
+
console.log("Translation Management");
|
|
842
|
+
console.log("=====");
|
|
843
|
+
const configPath = path9.join(projectRoot, ".translationsrc.json");
|
|
844
|
+
const isInitialized = fs4.existsSync(configPath);
|
|
845
|
+
if (!isInitialized) {
|
|
846
|
+
console.log("\u{1F4C1} No translation configuration found. Initializing...\n");
|
|
847
|
+
initTranslations(projectRoot);
|
|
848
|
+
console.log("\n\u2705 Initialization complete!\n");
|
|
849
|
+
} else {
|
|
850
|
+
console.log("\u2713 Translation structure initialized\n");
|
|
851
|
+
}
|
|
852
|
+
const config = loadConfig(projectRoot);
|
|
853
|
+
const translationsPath = path9.join(projectRoot, config.translationsPath);
|
|
854
|
+
const sourceLangPath = path9.join(translationsPath, config.sourceLanguage);
|
|
855
|
+
if (!fs4.existsSync(sourceLangPath)) {
|
|
856
|
+
console.log(`\u26A0\uFE0F Source language directory not found: ${sourceLangPath}`);
|
|
857
|
+
console.log("Please add translation files to the source language directory.\n");
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
console.log("\u{1F50D} Validating translations...\n");
|
|
861
|
+
const validationResult = validateTranslations(projectRoot);
|
|
862
|
+
if (validationResult.valid) {
|
|
863
|
+
console.log("\n\u2705 All translations are complete!\n");
|
|
864
|
+
} else {
|
|
865
|
+
const totalMissing = validationResult.missing.length + validationResult.empty.length;
|
|
866
|
+
if (autoFill) {
|
|
867
|
+
if (!apiKey) {
|
|
868
|
+
console.log("\n\u26A0\uFE0F Auto-fill requested but no API key provided.");
|
|
869
|
+
console.log("Set GOOGLE_TRANSLATE_API_KEY or pass --api-key to enable auto-fill.\n");
|
|
870
|
+
} else {
|
|
871
|
+
console.log(`
|
|
872
|
+
\u{1F916} Auto-filling ${totalMissing} missing translations...
|
|
873
|
+
`);
|
|
874
|
+
await autoFillTranslations(projectRoot, {
|
|
875
|
+
apiKey,
|
|
876
|
+
limit,
|
|
877
|
+
language,
|
|
878
|
+
dryRun,
|
|
879
|
+
delayMs: 100
|
|
880
|
+
});
|
|
881
|
+
if (!dryRun) {
|
|
882
|
+
console.log("\n\u{1F50D} Re-validating after auto-fill...\n");
|
|
883
|
+
const revalidation = validateTranslations(projectRoot);
|
|
884
|
+
if (revalidation.valid) {
|
|
885
|
+
console.log("\n\u2705 All translations are now complete!\n");
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
} else {
|
|
890
|
+
console.log(`
|
|
891
|
+
\u{1F4A1} Tip: Run with --auto-fill to automatically translate missing keys.
|
|
892
|
+
`);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (!skipTypes && !dryRun) {
|
|
896
|
+
console.log("\u{1F4DD} Generating TypeScript types...\n");
|
|
897
|
+
generateTranslationTypes(projectRoot);
|
|
898
|
+
console.log("\n\u2705 Types generated!\n");
|
|
899
|
+
} else if (skipTypes) {
|
|
900
|
+
console.log("\u23ED\uFE0F Skipping type generation (--skip-types)\n");
|
|
901
|
+
} else if (dryRun) {
|
|
902
|
+
console.log("\u23ED\uFE0F Skipping type generation (--dry-run)\n");
|
|
903
|
+
}
|
|
904
|
+
console.log("=====");
|
|
905
|
+
console.log("Summary");
|
|
906
|
+
console.log("=====");
|
|
907
|
+
console.log(`Configuration: ${configPath}`);
|
|
908
|
+
console.log(`Translations: ${translationsPath}`);
|
|
909
|
+
console.log(`Languages: ${config.languages.join(", ")}`);
|
|
910
|
+
console.log(`Source language: ${config.sourceLanguage}`);
|
|
911
|
+
if (!validationResult.valid && !autoFill) {
|
|
912
|
+
console.log(`
|
|
913
|
+
\u26A0\uFE0F ${validationResult.missing.length} missing translations`);
|
|
914
|
+
console.log(`\u26A0\uFE0F ${validationResult.empty.length} empty translations`);
|
|
915
|
+
console.log("\nNext steps:");
|
|
916
|
+
console.log(" 1. Add missing translations manually, or");
|
|
917
|
+
console.log(" 2. Run with --auto-fill to translate automatically");
|
|
918
|
+
} else if (validationResult.valid) {
|
|
919
|
+
console.log("\n\u2705 All systems ready!");
|
|
920
|
+
}
|
|
921
|
+
console.log("=====\n");
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// src/cli/translations.ts
|
|
925
|
+
init_utils();
|
|
926
|
+
var { values, positionals } = parseArgs({
|
|
927
|
+
options: {
|
|
928
|
+
"auto-fill": {
|
|
929
|
+
type: "boolean",
|
|
930
|
+
short: "a",
|
|
931
|
+
default: false
|
|
932
|
+
},
|
|
933
|
+
"api-key": {
|
|
934
|
+
type: "string"
|
|
935
|
+
},
|
|
936
|
+
limit: {
|
|
937
|
+
type: "string",
|
|
938
|
+
default: "1000"
|
|
939
|
+
},
|
|
940
|
+
language: {
|
|
941
|
+
type: "string",
|
|
942
|
+
short: "l"
|
|
943
|
+
},
|
|
944
|
+
"skip-types": {
|
|
945
|
+
type: "boolean",
|
|
946
|
+
default: false
|
|
947
|
+
},
|
|
948
|
+
"dry-run": {
|
|
949
|
+
type: "boolean",
|
|
950
|
+
short: "d",
|
|
951
|
+
default: false
|
|
952
|
+
},
|
|
953
|
+
namespace: {
|
|
954
|
+
type: "string",
|
|
955
|
+
short: "n"
|
|
956
|
+
},
|
|
957
|
+
key: {
|
|
958
|
+
type: "string",
|
|
959
|
+
short: "k"
|
|
960
|
+
},
|
|
961
|
+
value: {
|
|
962
|
+
type: "string",
|
|
963
|
+
short: "v"
|
|
964
|
+
},
|
|
965
|
+
help: {
|
|
966
|
+
type: "boolean",
|
|
967
|
+
short: "h"
|
|
968
|
+
}
|
|
969
|
+
},
|
|
970
|
+
allowPositionals: true
|
|
971
|
+
});
|
|
972
|
+
if (values.help) {
|
|
973
|
+
console.log(`
|
|
974
|
+
Usage: translations [command] [options]
|
|
975
|
+
|
|
976
|
+
Smart translation management - automatically handles initialization, validation,
|
|
977
|
+
auto-filling, and type generation based on your project's current state.
|
|
978
|
+
|
|
979
|
+
Commands:
|
|
980
|
+
(none) Smart mode - validates, fills, and generates types
|
|
981
|
+
add Add a new translation key
|
|
982
|
+
|
|
983
|
+
Options (Smart Mode):
|
|
984
|
+
-a, --auto-fill Auto-fill missing translations with Google Translate
|
|
985
|
+
--api-key <key> Google Translate API key (or set GOOGLE_TRANSLATE_API_KEY)
|
|
986
|
+
-l, --language <lang> Process only this language
|
|
987
|
+
--limit <number> Max translations to process (default: 1000)
|
|
988
|
+
--skip-types Skip TypeScript type generation
|
|
989
|
+
-d, --dry-run Preview changes without saving
|
|
990
|
+
-h, --help Show this help
|
|
991
|
+
|
|
992
|
+
Options (Add Mode):
|
|
993
|
+
-n, --namespace <name> Namespace for the translation
|
|
994
|
+
-k, --key <key> Translation key
|
|
995
|
+
-v, --value <value> Translation value in source language
|
|
996
|
+
-a, --auto-fill Auto-translate to all languages
|
|
997
|
+
|
|
998
|
+
(no options) Interactive mode - prompts for all inputs
|
|
999
|
+
|
|
1000
|
+
Examples:
|
|
1001
|
+
# Smart mode - check and validate translations
|
|
1002
|
+
translations
|
|
1003
|
+
|
|
1004
|
+
# Smart mode - validate and auto-fill missing translations
|
|
1005
|
+
export GOOGLE_TRANSLATE_API_KEY=your_key
|
|
1006
|
+
translations --auto-fill
|
|
1007
|
+
|
|
1008
|
+
# Smart mode - auto-fill only French translations
|
|
1009
|
+
translations --auto-fill --language fr
|
|
1010
|
+
|
|
1011
|
+
# Preview what would be translated (dry-run)
|
|
1012
|
+
translations --auto-fill --dry-run
|
|
1013
|
+
|
|
1014
|
+
# Add a new translation key (interactive mode)
|
|
1015
|
+
translations add
|
|
1016
|
+
|
|
1017
|
+
# Add with flags (non-interactive)
|
|
1018
|
+
translations add --namespace common --key HELLO --value "Hello"
|
|
1019
|
+
|
|
1020
|
+
# Add with auto-translation
|
|
1021
|
+
translations add -n common -k WELCOME -v "Welcome" --auto-fill
|
|
1022
|
+
|
|
1023
|
+
What happens in smart mode:
|
|
1024
|
+
1. Checks if translations are initialized (creates .translationsrc.json if needed)
|
|
1025
|
+
2. Validates all translations against source language
|
|
1026
|
+
3. Auto-fills missing translations if --auto-fill is provided
|
|
1027
|
+
4. Generates TypeScript types (unless --skip-types)
|
|
1028
|
+
5. Shows summary and next steps
|
|
1029
|
+
`);
|
|
1030
|
+
process.exit(0);
|
|
1031
|
+
}
|
|
1032
|
+
var command = positionals[0];
|
|
1033
|
+
if (command === "add") {
|
|
1034
|
+
if (!values.namespace && !values.key && !values.value) {
|
|
1035
|
+
(async () => {
|
|
1036
|
+
try {
|
|
1037
|
+
console.log("\n\u2728 Add a new translation key\n");
|
|
1038
|
+
const configPath = path10.join(process.cwd(), ".translationsrc.json");
|
|
1039
|
+
const isInitialized = fs5.existsSync(configPath);
|
|
1040
|
+
if (!isInitialized) {
|
|
1041
|
+
console.log("\u26A0\uFE0F Translation structure not initialized.");
|
|
1042
|
+
const shouldInit = await confirm2({
|
|
1043
|
+
message: "Would you like to initialize it now?",
|
|
1044
|
+
default: true
|
|
1045
|
+
});
|
|
1046
|
+
if (shouldInit) {
|
|
1047
|
+
await initTranslationsInteractive(process.cwd());
|
|
1048
|
+
console.log();
|
|
1049
|
+
} else {
|
|
1050
|
+
console.log("\u274C Cannot add translations without initialization.");
|
|
1051
|
+
process.exit(1);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const config = loadConfig(process.cwd());
|
|
1055
|
+
const translationsPath = path10.join(process.cwd(), config.translationsPath);
|
|
1056
|
+
const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
|
|
1057
|
+
let namespace;
|
|
1058
|
+
if (existingNamespaces.length > 0) {
|
|
1059
|
+
const namespaceChoice = await select({
|
|
1060
|
+
message: "Select namespace:",
|
|
1061
|
+
choices: [
|
|
1062
|
+
...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
|
|
1063
|
+
{ name: "\u2795 Create new namespace", value: "__new__" }
|
|
1064
|
+
]
|
|
1065
|
+
});
|
|
1066
|
+
if (namespaceChoice === "__new__") {
|
|
1067
|
+
namespace = await input2({
|
|
1068
|
+
message: "Enter new namespace name:",
|
|
1069
|
+
validate: (value2) => {
|
|
1070
|
+
if (!value2.trim()) return "Namespace is required";
|
|
1071
|
+
if (!/^[a-z0-9-]+$/.test(value2)) {
|
|
1072
|
+
return "Namespace must contain only lowercase letters, numbers, and hyphens";
|
|
1073
|
+
}
|
|
1074
|
+
return true;
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
} else {
|
|
1078
|
+
namespace = namespaceChoice;
|
|
1079
|
+
}
|
|
1080
|
+
} else {
|
|
1081
|
+
namespace = await input2({
|
|
1082
|
+
message: "Enter namespace name (e.g., common, members):",
|
|
1083
|
+
default: "common",
|
|
1084
|
+
validate: (value2) => {
|
|
1085
|
+
if (!value2.trim()) return "Namespace is required";
|
|
1086
|
+
if (!/^[a-z0-9-]+$/.test(value2)) {
|
|
1087
|
+
return "Namespace must contain only lowercase letters, numbers, and hyphens";
|
|
1088
|
+
}
|
|
1089
|
+
return true;
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
const key = await input2({
|
|
1094
|
+
message: "Enter translation key (UPPERCASE_SNAKE_CASE):",
|
|
1095
|
+
validate: (value2) => {
|
|
1096
|
+
if (!value2.trim()) return "Key is required";
|
|
1097
|
+
if (!/^[A-Z0-9_]+$/.test(value2)) {
|
|
1098
|
+
return "Key should use UPPERCASE_SNAKE_CASE (e.g., SAVE_CHANGES)";
|
|
1099
|
+
}
|
|
1100
|
+
return true;
|
|
1101
|
+
},
|
|
1102
|
+
transformer: (value2) => value2.toUpperCase()
|
|
1103
|
+
});
|
|
1104
|
+
const value = await input2({
|
|
1105
|
+
message: `Enter ${config.sourceLanguage.toUpperCase()} translation:`,
|
|
1106
|
+
validate: (value2) => {
|
|
1107
|
+
if (!value2.trim()) return "Translation value is required";
|
|
1108
|
+
return true;
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
const autoTranslate = await confirm2({
|
|
1112
|
+
message: `Auto-translate to ${config.languages.length - 1} other languages?`,
|
|
1113
|
+
default: true
|
|
1114
|
+
});
|
|
1115
|
+
let apiKey;
|
|
1116
|
+
if (autoTranslate) {
|
|
1117
|
+
apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
|
|
1118
|
+
if (!apiKey) {
|
|
1119
|
+
console.log("\n\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
|
|
1120
|
+
console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
console.log();
|
|
1124
|
+
await addTranslationKey(process.cwd(), {
|
|
1125
|
+
namespace,
|
|
1126
|
+
key: key.toUpperCase(),
|
|
1127
|
+
value,
|
|
1128
|
+
autoTranslate: autoTranslate && !!apiKey,
|
|
1129
|
+
apiKey
|
|
1130
|
+
});
|
|
1131
|
+
console.log('\n\u{1F4A1} Run "translations" to validate and generate types');
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
if (error.message === "User force closed the prompt") {
|
|
1134
|
+
console.log("\n\u274C Cancelled");
|
|
1135
|
+
process.exit(0);
|
|
1136
|
+
}
|
|
1137
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1138
|
+
process.exit(1);
|
|
1139
|
+
}
|
|
1140
|
+
})();
|
|
1141
|
+
} else {
|
|
1142
|
+
if (!values.namespace || !values.key || !values.value) {
|
|
1143
|
+
console.error("Error: --namespace, --key, and --value are required for add command");
|
|
1144
|
+
console.log("Use --help for usage information");
|
|
1145
|
+
process.exit(1);
|
|
1146
|
+
}
|
|
1147
|
+
const apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
|
|
1148
|
+
if (values["auto-fill"] && !apiKey) {
|
|
1149
|
+
console.error(
|
|
1150
|
+
"Error: --api-key or GOOGLE_TRANSLATE_API_KEY environment variable is required for auto-translation"
|
|
1151
|
+
);
|
|
1152
|
+
process.exit(1);
|
|
1153
|
+
}
|
|
1154
|
+
addTranslationKey(process.cwd(), {
|
|
1155
|
+
namespace: values.namespace,
|
|
1156
|
+
key: values.key,
|
|
1157
|
+
value: values.value,
|
|
1158
|
+
autoTranslate: values["auto-fill"],
|
|
1159
|
+
apiKey
|
|
1160
|
+
}).then(() => {
|
|
1161
|
+
console.log('\n\u{1F4A1} Run "translations" to validate and generate types');
|
|
1162
|
+
}).catch((error) => {
|
|
1163
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1164
|
+
process.exit(1);
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
} else if (command) {
|
|
1168
|
+
console.error(`Unknown command: ${command}`);
|
|
1169
|
+
console.log("Use --help for usage information");
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
} else {
|
|
1172
|
+
const hasFlags = values["auto-fill"] || values.language || values["skip-types"] || values["dry-run"];
|
|
1173
|
+
if (hasFlags) {
|
|
1174
|
+
const apiKey = values["api-key"] || process.env.GOOGLE_TRANSLATE_API_KEY;
|
|
1175
|
+
const limit = Number.parseInt(values.limit || "1000", 10);
|
|
1176
|
+
manageTranslations(process.cwd(), {
|
|
1177
|
+
autoFill: values["auto-fill"],
|
|
1178
|
+
apiKey,
|
|
1179
|
+
limit,
|
|
1180
|
+
language: values.language,
|
|
1181
|
+
skipTypes: values["skip-types"],
|
|
1182
|
+
dryRun: values["dry-run"]
|
|
1183
|
+
}).catch((error) => {
|
|
1184
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1185
|
+
process.exit(1);
|
|
1186
|
+
});
|
|
1187
|
+
} else {
|
|
1188
|
+
(async () => {
|
|
1189
|
+
try {
|
|
1190
|
+
const configPath = path10.join(process.cwd(), ".translationsrc.json");
|
|
1191
|
+
const isInitialized = fs5.existsSync(configPath);
|
|
1192
|
+
console.log("\n\u{1F30D} Translation Management\n");
|
|
1193
|
+
const action = await select({
|
|
1194
|
+
message: "What would you like to do?",
|
|
1195
|
+
choices: [
|
|
1196
|
+
{
|
|
1197
|
+
name: "\u2728 Add a new translation key",
|
|
1198
|
+
value: "add",
|
|
1199
|
+
description: "Add a translation key to all languages"
|
|
1200
|
+
},
|
|
1201
|
+
{
|
|
1202
|
+
name: "\u{1F50D} Validate translations",
|
|
1203
|
+
value: "validate",
|
|
1204
|
+
description: "Check for missing or empty translations"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
name: "\u{1F916} Auto-fill missing translations",
|
|
1208
|
+
value: "autofill",
|
|
1209
|
+
description: "Automatically translate missing keys with Google Translate"
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
name: "\u{1F4DD} Generate TypeScript types",
|
|
1213
|
+
value: "types",
|
|
1214
|
+
description: "Generate types from translation files"
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
name: "\u2699\uFE0F Initialize/reconfigure",
|
|
1218
|
+
value: "init",
|
|
1219
|
+
description: "Set up or change translation configuration"
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
name: "\u{1F4CA} Full check (validate + types)",
|
|
1223
|
+
value: "full",
|
|
1224
|
+
description: "Validate translations and generate types"
|
|
1225
|
+
}
|
|
1226
|
+
]
|
|
1227
|
+
});
|
|
1228
|
+
console.log();
|
|
1229
|
+
if (action === "add") {
|
|
1230
|
+
if (!isInitialized) {
|
|
1231
|
+
console.log("\u26A0\uFE0F Translation structure not initialized.");
|
|
1232
|
+
const shouldInit = await confirm2({
|
|
1233
|
+
message: "Would you like to initialize it now?",
|
|
1234
|
+
default: true
|
|
1235
|
+
});
|
|
1236
|
+
if (shouldInit) {
|
|
1237
|
+
await initTranslationsInteractive(process.cwd());
|
|
1238
|
+
console.log();
|
|
1239
|
+
} else {
|
|
1240
|
+
console.log("\u274C Cannot add translations without initialization.");
|
|
1241
|
+
process.exit(1);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
const config = loadConfig(process.cwd());
|
|
1245
|
+
const translationsPath = path10.join(process.cwd(), config.translationsPath);
|
|
1246
|
+
const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
|
|
1247
|
+
let namespace;
|
|
1248
|
+
if (existingNamespaces.length > 0) {
|
|
1249
|
+
const namespaceChoice = await select({
|
|
1250
|
+
message: "Select namespace:",
|
|
1251
|
+
choices: [
|
|
1252
|
+
...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
|
|
1253
|
+
{ name: "\u2795 Create new namespace", value: "__new__" }
|
|
1254
|
+
]
|
|
1255
|
+
});
|
|
1256
|
+
if (namespaceChoice === "__new__") {
|
|
1257
|
+
namespace = await input2({
|
|
1258
|
+
message: "Enter new namespace name:",
|
|
1259
|
+
validate: (value2) => {
|
|
1260
|
+
if (!value2.trim()) return "Namespace is required";
|
|
1261
|
+
if (!/^[a-z0-9-]+$/.test(value2)) {
|
|
1262
|
+
return "Namespace must contain only lowercase letters, numbers, and hyphens";
|
|
1263
|
+
}
|
|
1264
|
+
return true;
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
} else {
|
|
1268
|
+
namespace = namespaceChoice;
|
|
1269
|
+
}
|
|
1270
|
+
} else {
|
|
1271
|
+
namespace = await input2({
|
|
1272
|
+
message: "Enter namespace name (e.g., common, members):",
|
|
1273
|
+
default: "common",
|
|
1274
|
+
validate: (value2) => {
|
|
1275
|
+
if (!value2.trim()) return "Namespace is required";
|
|
1276
|
+
if (!/^[a-z0-9-]+$/.test(value2)) {
|
|
1277
|
+
return "Namespace must contain only lowercase letters, numbers, and hyphens";
|
|
1278
|
+
}
|
|
1279
|
+
return true;
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
const key = await input2({
|
|
1284
|
+
message: "Enter translation key (UPPERCASE_SNAKE_CASE):",
|
|
1285
|
+
validate: (value2) => {
|
|
1286
|
+
if (!value2.trim()) return "Key is required";
|
|
1287
|
+
if (!/^[A-Z0-9_]+$/.test(value2)) {
|
|
1288
|
+
return "Key should use UPPERCASE_SNAKE_CASE (e.g., SAVE_CHANGES)";
|
|
1289
|
+
}
|
|
1290
|
+
return true;
|
|
1291
|
+
},
|
|
1292
|
+
transformer: (value2) => value2.toUpperCase()
|
|
1293
|
+
});
|
|
1294
|
+
const value = await input2({
|
|
1295
|
+
message: `Enter ${config.sourceLanguage.toUpperCase()} translation:`,
|
|
1296
|
+
validate: (value2) => {
|
|
1297
|
+
if (!value2.trim()) return "Translation value is required";
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1300
|
+
});
|
|
1301
|
+
const autoTranslate = await confirm2({
|
|
1302
|
+
message: `Auto-translate to ${config.languages.length - 1} other languages?`,
|
|
1303
|
+
default: true
|
|
1304
|
+
});
|
|
1305
|
+
let apiKey;
|
|
1306
|
+
if (autoTranslate) {
|
|
1307
|
+
apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
|
|
1308
|
+
if (!apiKey) {
|
|
1309
|
+
console.log("\n\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
|
|
1310
|
+
console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
console.log();
|
|
1314
|
+
await addTranslationKey(process.cwd(), {
|
|
1315
|
+
namespace,
|
|
1316
|
+
key: key.toUpperCase(),
|
|
1317
|
+
value,
|
|
1318
|
+
autoTranslate: autoTranslate && !!apiKey,
|
|
1319
|
+
apiKey
|
|
1320
|
+
});
|
|
1321
|
+
console.log('\n\u{1F4A1} Run "translations" again to validate and generate types');
|
|
1322
|
+
} else if (action === "init") {
|
|
1323
|
+
await initTranslationsInteractive(process.cwd());
|
|
1324
|
+
} else if (action === "validate") {
|
|
1325
|
+
await manageTranslations(process.cwd(), {
|
|
1326
|
+
skipTypes: true
|
|
1327
|
+
});
|
|
1328
|
+
} else if (action === "autofill") {
|
|
1329
|
+
const apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
|
|
1330
|
+
if (!apiKey) {
|
|
1331
|
+
console.log("\u26A0\uFE0F GOOGLE_TRANSLATE_API_KEY environment variable not found.");
|
|
1332
|
+
console.log("Please set it to enable auto-translation.\n");
|
|
1333
|
+
process.exit(1);
|
|
1334
|
+
}
|
|
1335
|
+
const shouldContinue = await confirm2({
|
|
1336
|
+
message: "This will auto-translate all missing keys. Continue?",
|
|
1337
|
+
default: true
|
|
1338
|
+
});
|
|
1339
|
+
if (shouldContinue) {
|
|
1340
|
+
await manageTranslations(process.cwd(), {
|
|
1341
|
+
autoFill: true,
|
|
1342
|
+
apiKey
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
} else if (action === "types") {
|
|
1346
|
+
console.log("\u{1F4DD} Generating TypeScript types...\n");
|
|
1347
|
+
const { generateTranslationTypes: generateTranslationTypes2 } = await Promise.resolve().then(() => (init_generate_types(), generate_types_exports));
|
|
1348
|
+
generateTranslationTypes2(process.cwd());
|
|
1349
|
+
console.log("\n\u2705 Types generated!\n");
|
|
1350
|
+
} else if (action === "full") {
|
|
1351
|
+
await manageTranslations(process.cwd());
|
|
1352
|
+
}
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
if (error.message === "User force closed the prompt") {
|
|
1355
|
+
console.log("\n\u274C Cancelled");
|
|
1356
|
+
process.exit(0);
|
|
1357
|
+
}
|
|
1358
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
1359
|
+
process.exit(1);
|
|
1360
|
+
}
|
|
1361
|
+
})();
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
//# sourceMappingURL=translations.js.map
|