poly-lexis 0.3.2 → 0.4.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 +87 -17
- package/dist/cli/translations.js +527 -125
- package/dist/cli/translations.js.map +1 -1
- package/dist/index.d.ts +189 -113
- package/dist/index.js +531 -123
- package/dist/index.js.map +1 -1
- package/dist/scripts/generate-schema.js +5 -0
- package/dist/scripts/generate-schema.js.map +1 -1
- package/dist/scripts/verify-translations.js +73 -4
- package/dist/scripts/verify-translations.js.map +1 -1
- package/dist/translations/core/translations-config.schema.json +5 -0
- package/package.json +1 -1
package/dist/cli/translations.js
CHANGED
|
@@ -18,72 +18,6 @@ var init_esm_shims = __esm({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
// src/translations/utils/utils.ts
|
|
22
|
-
import * as fs from "fs";
|
|
23
|
-
import * as path2 from "path";
|
|
24
|
-
function readTranslations(translationsPath, language) {
|
|
25
|
-
const langPath = path2.join(translationsPath, language);
|
|
26
|
-
if (!fs.existsSync(langPath)) {
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
|
|
30
|
-
const translations = {};
|
|
31
|
-
for (const file of files) {
|
|
32
|
-
const namespace = path2.basename(file, ".json");
|
|
33
|
-
const filePath = path2.join(langPath, file);
|
|
34
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
35
|
-
translations[namespace] = JSON.parse(content);
|
|
36
|
-
}
|
|
37
|
-
return translations;
|
|
38
|
-
}
|
|
39
|
-
function writeTranslation(translationsPath, language, namespace, translations) {
|
|
40
|
-
const langPath = path2.join(translationsPath, language);
|
|
41
|
-
if (!fs.existsSync(langPath)) {
|
|
42
|
-
fs.mkdirSync(langPath, { recursive: true });
|
|
43
|
-
}
|
|
44
|
-
const filePath = path2.join(langPath, `${namespace}.json`);
|
|
45
|
-
fs.writeFileSync(filePath, `${JSON.stringify(translations, null, 2)}
|
|
46
|
-
`, "utf-8");
|
|
47
|
-
}
|
|
48
|
-
function getAvailableLanguages(translationsPath) {
|
|
49
|
-
if (!fs.existsSync(translationsPath)) {
|
|
50
|
-
return [];
|
|
51
|
-
}
|
|
52
|
-
return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
53
|
-
}
|
|
54
|
-
function getNamespaces(translationsPath, language) {
|
|
55
|
-
const langPath = path2.join(translationsPath, language);
|
|
56
|
-
if (!fs.existsSync(langPath)) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path2.basename(f, ".json"));
|
|
60
|
-
}
|
|
61
|
-
function sortKeys(obj) {
|
|
62
|
-
const sorted = {};
|
|
63
|
-
const keys = Object.keys(obj).sort();
|
|
64
|
-
for (const key of keys) {
|
|
65
|
-
sorted[key] = obj[key];
|
|
66
|
-
}
|
|
67
|
-
return sorted;
|
|
68
|
-
}
|
|
69
|
-
function ensureTranslationsStructure(translationsPath, languages) {
|
|
70
|
-
if (!fs.existsSync(translationsPath)) {
|
|
71
|
-
fs.mkdirSync(translationsPath, { recursive: true });
|
|
72
|
-
}
|
|
73
|
-
for (const lang of languages) {
|
|
74
|
-
const langPath = path2.join(translationsPath, lang);
|
|
75
|
-
if (!fs.existsSync(langPath)) {
|
|
76
|
-
fs.mkdirSync(langPath, { recursive: true });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
var init_utils = __esm({
|
|
81
|
-
"src/translations/utils/utils.ts"() {
|
|
82
|
-
"use strict";
|
|
83
|
-
init_esm_shims();
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
21
|
// src/translations/core/schema.ts
|
|
88
22
|
function isValidLanguage(lang) {
|
|
89
23
|
return SUPPORTED_LANGUAGES.includes(lang);
|
|
@@ -91,7 +25,7 @@ function isValidLanguage(lang) {
|
|
|
91
25
|
function validateLanguages(languages) {
|
|
92
26
|
const invalid = languages.filter((lang) => !isValidLanguage(lang));
|
|
93
27
|
return {
|
|
94
|
-
valid: invalid.length
|
|
28
|
+
valid: !invalid.length,
|
|
95
29
|
invalid
|
|
96
30
|
};
|
|
97
31
|
}
|
|
@@ -100,6 +34,7 @@ var init_schema = __esm({
|
|
|
100
34
|
"src/translations/core/schema.ts"() {
|
|
101
35
|
"use strict";
|
|
102
36
|
init_esm_shims();
|
|
37
|
+
init_language_fallback();
|
|
103
38
|
DEEPL_LANGUAGES = [
|
|
104
39
|
"ar",
|
|
105
40
|
// Arabic
|
|
@@ -412,6 +347,297 @@ var init_schema = __esm({
|
|
|
412
347
|
}
|
|
413
348
|
});
|
|
414
349
|
|
|
350
|
+
// src/translations/utils/language-fallback.ts
|
|
351
|
+
function resolveLanguageWithFallback(language, provider, enableFallback = true) {
|
|
352
|
+
const normalizedLanguage = language.toLowerCase();
|
|
353
|
+
const supportedLanguages = getSupportedLanguagesForProvider(provider);
|
|
354
|
+
if (isLanguageSupported(normalizedLanguage, supportedLanguages)) {
|
|
355
|
+
return {
|
|
356
|
+
resolvedLanguage: normalizedLanguage,
|
|
357
|
+
usedFallback: false,
|
|
358
|
+
originalLanguage: language
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
if (!enableFallback) {
|
|
362
|
+
return {
|
|
363
|
+
resolvedLanguage: normalizedLanguage,
|
|
364
|
+
usedFallback: false,
|
|
365
|
+
originalLanguage: language
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
const fallbackChain = LANGUAGE_FALLBACK_MAP[normalizedLanguage] || [];
|
|
369
|
+
for (const fallbackLang of fallbackChain) {
|
|
370
|
+
if (isLanguageSupported(fallbackLang, supportedLanguages)) {
|
|
371
|
+
return {
|
|
372
|
+
resolvedLanguage: fallbackLang,
|
|
373
|
+
usedFallback: true,
|
|
374
|
+
originalLanguage: language,
|
|
375
|
+
fallbackChain: [normalizedLanguage, ...fallbackChain]
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const baseLang = normalizedLanguage.split("_")[0];
|
|
380
|
+
if (baseLang !== normalizedLanguage && isLanguageSupported(baseLang, supportedLanguages)) {
|
|
381
|
+
return {
|
|
382
|
+
resolvedLanguage: baseLang,
|
|
383
|
+
usedFallback: true,
|
|
384
|
+
originalLanguage: language,
|
|
385
|
+
fallbackChain: [normalizedLanguage, baseLang]
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
resolvedLanguage: normalizedLanguage,
|
|
390
|
+
usedFallback: false,
|
|
391
|
+
originalLanguage: language
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function getSupportedLanguagesForProvider(provider) {
|
|
395
|
+
switch (provider) {
|
|
396
|
+
case "deepl":
|
|
397
|
+
return DEEPL_LANGUAGES;
|
|
398
|
+
case "google":
|
|
399
|
+
return GOOGLE_LANGUAGES;
|
|
400
|
+
default:
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
function isLanguageSupported(language, supportedLanguages) {
|
|
405
|
+
return supportedLanguages.includes(language);
|
|
406
|
+
}
|
|
407
|
+
function logLanguageFallback(result, provider) {
|
|
408
|
+
if (result.usedFallback) {
|
|
409
|
+
console.warn(
|
|
410
|
+
`\u26A0\uFE0F Language fallback: '${result.originalLanguage}' is not supported by ${provider}, using '${result.resolvedLanguage}' instead`
|
|
411
|
+
);
|
|
412
|
+
if (result.fallbackChain && result.fallbackChain.length > 2) {
|
|
413
|
+
console.warn(` Fallback chain: ${result.fallbackChain.join(" \u2192 ")}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
var LANGUAGE_FALLBACK_MAP;
|
|
418
|
+
var init_language_fallback = __esm({
|
|
419
|
+
"src/translations/utils/language-fallback.ts"() {
|
|
420
|
+
"use strict";
|
|
421
|
+
init_esm_shims();
|
|
422
|
+
init_schema();
|
|
423
|
+
LANGUAGE_FALLBACK_MAP = {
|
|
424
|
+
// German variants
|
|
425
|
+
de_at: ["de"],
|
|
426
|
+
// Austrian German -> German
|
|
427
|
+
de_ch: ["de"],
|
|
428
|
+
// Swiss German -> German
|
|
429
|
+
de_de: ["de"],
|
|
430
|
+
// Standard German -> German
|
|
431
|
+
// English variants
|
|
432
|
+
en_gb: ["en"],
|
|
433
|
+
// British English -> English
|
|
434
|
+
en_us: ["en"],
|
|
435
|
+
// American English -> English
|
|
436
|
+
en_au: ["en"],
|
|
437
|
+
// Australian English -> English
|
|
438
|
+
en_ca: ["en"],
|
|
439
|
+
// Canadian English -> English
|
|
440
|
+
en_nz: ["en"],
|
|
441
|
+
// New Zealand English -> English
|
|
442
|
+
// Chinese variants (Hong Kong, Taiwan -> Traditional)
|
|
443
|
+
zh_hk: ["zh_hant", "zh"],
|
|
444
|
+
// Hong Kong Chinese -> Traditional Chinese -> Chinese
|
|
445
|
+
zh_tw: ["zh_hant", "zh"],
|
|
446
|
+
// Taiwan Chinese -> Traditional Chinese -> Chinese
|
|
447
|
+
zh_mo: ["zh_hant", "zh"],
|
|
448
|
+
// Macau Chinese -> Traditional Chinese -> Chinese
|
|
449
|
+
// Chinese variants (Mainland, Singapore -> Simplified)
|
|
450
|
+
zh_cn: ["zh_hans", "zh"],
|
|
451
|
+
// Mainland Chinese -> Simplified Chinese -> Chinese
|
|
452
|
+
zh_sg: ["zh_hans", "zh"],
|
|
453
|
+
// Singapore Chinese -> Simplified Chinese -> Chinese
|
|
454
|
+
// Portuguese variants
|
|
455
|
+
pt_pt: ["pt"],
|
|
456
|
+
// European Portuguese -> Portuguese
|
|
457
|
+
pt_ao: ["pt"],
|
|
458
|
+
// Angolan Portuguese -> Portuguese
|
|
459
|
+
pt_mz: ["pt"],
|
|
460
|
+
// Mozambican Portuguese -> Portuguese
|
|
461
|
+
// Spanish variants (Latin America)
|
|
462
|
+
es_mx: ["es_419", "es"],
|
|
463
|
+
// Mexican Spanish -> Latin American Spanish -> Spanish
|
|
464
|
+
es_ar: ["es_419", "es"],
|
|
465
|
+
// Argentine Spanish -> Latin American Spanish -> Spanish
|
|
466
|
+
es_co: ["es_419", "es"],
|
|
467
|
+
// Colombian Spanish -> Latin American Spanish -> Spanish
|
|
468
|
+
es_cl: ["es_419", "es"],
|
|
469
|
+
// Chilean Spanish -> Latin American Spanish -> Spanish
|
|
470
|
+
es_pe: ["es_419", "es"],
|
|
471
|
+
// Peruvian Spanish -> Latin American Spanish -> Spanish
|
|
472
|
+
es_ve: ["es_419", "es"],
|
|
473
|
+
// Venezuelan Spanish -> Latin American Spanish -> Spanish
|
|
474
|
+
es_ec: ["es_419", "es"],
|
|
475
|
+
// Ecuadorian Spanish -> Latin American Spanish -> Spanish
|
|
476
|
+
es_gt: ["es_419", "es"],
|
|
477
|
+
// Guatemalan Spanish -> Latin American Spanish -> Spanish
|
|
478
|
+
es_cu: ["es_419", "es"],
|
|
479
|
+
// Cuban Spanish -> Latin American Spanish -> Spanish
|
|
480
|
+
es_do: ["es_419", "es"],
|
|
481
|
+
// Dominican Spanish -> Latin American Spanish -> Spanish
|
|
482
|
+
es_hn: ["es_419", "es"],
|
|
483
|
+
// Honduran Spanish -> Latin American Spanish -> Spanish
|
|
484
|
+
es_ni: ["es_419", "es"],
|
|
485
|
+
// Nicaraguan Spanish -> Latin American Spanish -> Spanish
|
|
486
|
+
es_sv: ["es_419", "es"],
|
|
487
|
+
// Salvadoran Spanish -> Latin American Spanish -> Spanish
|
|
488
|
+
es_cr: ["es_419", "es"],
|
|
489
|
+
// Costa Rican Spanish -> Latin American Spanish -> Spanish
|
|
490
|
+
es_pa: ["es_419", "es"],
|
|
491
|
+
// Panamanian Spanish -> Latin American Spanish -> Spanish
|
|
492
|
+
es_uy: ["es_419", "es"],
|
|
493
|
+
// Uruguayan Spanish -> Latin American Spanish -> Spanish
|
|
494
|
+
es_py: ["es_419", "es"],
|
|
495
|
+
// Paraguayan Spanish -> Latin American Spanish -> Spanish
|
|
496
|
+
es_bo: ["es_419", "es"],
|
|
497
|
+
// Bolivian Spanish -> Latin American Spanish -> Spanish
|
|
498
|
+
// Spanish (European)
|
|
499
|
+
es_es: ["es"],
|
|
500
|
+
// European Spanish -> Spanish
|
|
501
|
+
// French variants
|
|
502
|
+
fr_ca: ["fr"],
|
|
503
|
+
// Canadian French -> French
|
|
504
|
+
fr_ch: ["fr"],
|
|
505
|
+
// Swiss French -> French
|
|
506
|
+
fr_be: ["fr"],
|
|
507
|
+
// Belgian French -> French
|
|
508
|
+
fr_fr: ["fr"],
|
|
509
|
+
// Standard French -> French
|
|
510
|
+
// Norwegian variants
|
|
511
|
+
no: ["nb"],
|
|
512
|
+
// Norwegian -> Norwegian Bokmål
|
|
513
|
+
nn: ["nb"],
|
|
514
|
+
// Norwegian Nynorsk -> Norwegian Bokmål
|
|
515
|
+
// Other regional variants
|
|
516
|
+
it_ch: ["it"],
|
|
517
|
+
// Swiss Italian -> Italian
|
|
518
|
+
nl_be: ["nl"],
|
|
519
|
+
// Belgian Dutch (Flemish) -> Dutch
|
|
520
|
+
sv_fi: ["sv"],
|
|
521
|
+
// Finland Swedish -> Swedish
|
|
522
|
+
ar_ae: ["ar"],
|
|
523
|
+
// UAE Arabic -> Arabic
|
|
524
|
+
ar_sa: ["ar"],
|
|
525
|
+
// Saudi Arabic -> Arabic
|
|
526
|
+
ar_eg: ["ar"]
|
|
527
|
+
// Egyptian Arabic -> Arabic
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// src/translations/utils/utils.ts
|
|
533
|
+
import * as fs from "fs";
|
|
534
|
+
import * as path2 from "path";
|
|
535
|
+
function readTranslations(translationsPath, language) {
|
|
536
|
+
const langPath = path2.join(translationsPath, language);
|
|
537
|
+
if (!fs.existsSync(langPath)) {
|
|
538
|
+
return {};
|
|
539
|
+
}
|
|
540
|
+
const files = fs.readdirSync(langPath).filter((f) => f.endsWith(".json"));
|
|
541
|
+
const translations = {};
|
|
542
|
+
for (const file of files) {
|
|
543
|
+
const namespace = path2.basename(file, ".json");
|
|
544
|
+
const filePath = path2.join(langPath, file);
|
|
545
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
546
|
+
translations[namespace] = JSON.parse(content);
|
|
547
|
+
}
|
|
548
|
+
return translations;
|
|
549
|
+
}
|
|
550
|
+
function writeTranslation(translationsPath, language, namespace, translations) {
|
|
551
|
+
const langPath = path2.join(translationsPath, language);
|
|
552
|
+
if (!fs.existsSync(langPath)) {
|
|
553
|
+
fs.mkdirSync(langPath, { recursive: true });
|
|
554
|
+
}
|
|
555
|
+
const filePath = path2.join(langPath, `${namespace}.json`);
|
|
556
|
+
fs.writeFileSync(filePath, `${JSON.stringify(translations, null, 2)}
|
|
557
|
+
`, "utf-8");
|
|
558
|
+
}
|
|
559
|
+
function getAvailableLanguages(translationsPath) {
|
|
560
|
+
if (!fs.existsSync(translationsPath)) {
|
|
561
|
+
return [];
|
|
562
|
+
}
|
|
563
|
+
return fs.readdirSync(translationsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
564
|
+
}
|
|
565
|
+
function getNamespaces(translationsPath, language) {
|
|
566
|
+
const langPath = path2.join(translationsPath, language);
|
|
567
|
+
if (!fs.existsSync(langPath)) {
|
|
568
|
+
return [];
|
|
569
|
+
}
|
|
570
|
+
return fs.readdirSync(langPath).filter((f) => f.endsWith(".json")).map((f) => path2.basename(f, ".json"));
|
|
571
|
+
}
|
|
572
|
+
function sortKeys(obj) {
|
|
573
|
+
const sorted = {};
|
|
574
|
+
const keys = Object.keys(obj).sort();
|
|
575
|
+
for (const key of keys) {
|
|
576
|
+
sorted[key] = obj[key];
|
|
577
|
+
}
|
|
578
|
+
return sorted;
|
|
579
|
+
}
|
|
580
|
+
function ensureTranslationsStructure(translationsPath, languages) {
|
|
581
|
+
if (!fs.existsSync(translationsPath)) {
|
|
582
|
+
fs.mkdirSync(translationsPath, { recursive: true });
|
|
583
|
+
}
|
|
584
|
+
for (const lang of languages) {
|
|
585
|
+
const langPath = path2.join(translationsPath, lang);
|
|
586
|
+
if (!fs.existsSync(langPath)) {
|
|
587
|
+
fs.mkdirSync(langPath, { recursive: true });
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function createEmptyTranslationStructure(sourceFile) {
|
|
592
|
+
const result = {};
|
|
593
|
+
for (const key of Object.keys(sourceFile)) {
|
|
594
|
+
result[key] = "";
|
|
595
|
+
}
|
|
596
|
+
return result;
|
|
597
|
+
}
|
|
598
|
+
function syncTranslationStructure(translationsPath, languages, sourceLanguage) {
|
|
599
|
+
const result = {
|
|
600
|
+
createdFolders: [],
|
|
601
|
+
createdFiles: [],
|
|
602
|
+
skippedFiles: []
|
|
603
|
+
};
|
|
604
|
+
ensureTranslationsStructure(translationsPath, languages);
|
|
605
|
+
const sourceNamespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
606
|
+
if (!sourceNamespaces.length) {
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
const sourceTranslations = readTranslations(translationsPath, sourceLanguage);
|
|
610
|
+
const targetLanguages = languages.filter((lang) => lang !== sourceLanguage);
|
|
611
|
+
for (const language of targetLanguages) {
|
|
612
|
+
for (const namespace of sourceNamespaces) {
|
|
613
|
+
const filePath = path2.join(translationsPath, language, `${namespace}.json`);
|
|
614
|
+
if (fs.existsSync(filePath)) {
|
|
615
|
+
result.skippedFiles.push({
|
|
616
|
+
language,
|
|
617
|
+
namespace,
|
|
618
|
+
reason: "already exists"
|
|
619
|
+
});
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const sourceFile = sourceTranslations[namespace] || {};
|
|
623
|
+
const emptyStructure = createEmptyTranslationStructure(sourceFile);
|
|
624
|
+
writeTranslation(translationsPath, language, namespace, emptyStructure);
|
|
625
|
+
result.createdFiles.push({
|
|
626
|
+
language,
|
|
627
|
+
namespace,
|
|
628
|
+
path: filePath
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
var init_utils = __esm({
|
|
635
|
+
"src/translations/utils/utils.ts"() {
|
|
636
|
+
"use strict";
|
|
637
|
+
init_esm_shims();
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
|
|
415
641
|
// src/translations/core/types.ts
|
|
416
642
|
var DEFAULT_CONFIG, DEFAULT_LANGUAGES;
|
|
417
643
|
var init_types = __esm({
|
|
@@ -422,24 +648,11 @@ var init_types = __esm({
|
|
|
422
648
|
translationsPath: "public/static/locales",
|
|
423
649
|
languages: ["en"],
|
|
424
650
|
sourceLanguage: "en",
|
|
425
|
-
typesOutputPath: "src/types/i18nTypes.ts"
|
|
651
|
+
typesOutputPath: "src/types/i18nTypes.ts",
|
|
652
|
+
provider: "google",
|
|
653
|
+
useFallbackLanguages: true
|
|
426
654
|
};
|
|
427
|
-
DEFAULT_LANGUAGES = [
|
|
428
|
-
"en",
|
|
429
|
-
"fr",
|
|
430
|
-
"it",
|
|
431
|
-
"pl",
|
|
432
|
-
"es",
|
|
433
|
-
"pt",
|
|
434
|
-
"de",
|
|
435
|
-
"de_at",
|
|
436
|
-
"nl",
|
|
437
|
-
"sv",
|
|
438
|
-
"hu",
|
|
439
|
-
"cs",
|
|
440
|
-
"ja",
|
|
441
|
-
"zh_hk"
|
|
442
|
-
];
|
|
655
|
+
DEFAULT_LANGUAGES = ["en", "fr", "it", "pl", "es", "pt", "de", "nl", "sv", "hu", "cs", "ja"];
|
|
443
656
|
}
|
|
444
657
|
});
|
|
445
658
|
|
|
@@ -513,12 +726,14 @@ function initTranslations(projectRoot, config = {}) {
|
|
|
513
726
|
`, "utf-8");
|
|
514
727
|
console.log(`Created sample file: ${commonPath}`);
|
|
515
728
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
729
|
+
console.log("\nSynchronizing translation structure...");
|
|
730
|
+
const syncResult = syncTranslationStructure(translationsPath, languages, sourceLanguage);
|
|
731
|
+
if (syncResult.createdFiles.length > 0) {
|
|
732
|
+
console.log(`Created ${syncResult.createdFiles.length} namespace files in target languages`);
|
|
733
|
+
const languageGroups = new Set(syncResult.createdFiles.map((f) => f.language));
|
|
734
|
+
for (const lang of languageGroups) {
|
|
735
|
+
const langFiles = syncResult.createdFiles.filter((f) => f.language === lang);
|
|
736
|
+
console.log(` ${lang}: ${langFiles.map((f) => f.namespace).join(", ")}`);
|
|
522
737
|
}
|
|
523
738
|
}
|
|
524
739
|
const configPath = path3.join(projectRoot, ".translationsrc.json");
|
|
@@ -528,7 +743,8 @@ function initTranslations(projectRoot, config = {}) {
|
|
|
528
743
|
translationsPath: finalConfig.translationsPath,
|
|
529
744
|
languages,
|
|
530
745
|
sourceLanguage,
|
|
531
|
-
typesOutputPath: finalConfig.typesOutputPath
|
|
746
|
+
typesOutputPath: finalConfig.typesOutputPath,
|
|
747
|
+
provider: finalConfig.provider
|
|
532
748
|
};
|
|
533
749
|
fs2.writeFileSync(configPath, `${JSON.stringify(configContent, null, 2)}
|
|
534
750
|
`, "utf-8");
|
|
@@ -595,7 +811,7 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
|
|
|
595
811
|
throw new Error(`Source language directory not found: ${dirPath}`);
|
|
596
812
|
}
|
|
597
813
|
const namespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
598
|
-
if (namespaces.length
|
|
814
|
+
if (!namespaces.length) {
|
|
599
815
|
throw new Error(`No translation files found in ${dirPath}`);
|
|
600
816
|
}
|
|
601
817
|
const translations = readTranslations(translationsPath, sourceLanguage);
|
|
@@ -646,7 +862,7 @@ import "dotenv/config";
|
|
|
646
862
|
import * as fs6 from "fs";
|
|
647
863
|
import * as path10 from "path";
|
|
648
864
|
import { parseArgs } from "util";
|
|
649
|
-
import { confirm as confirm2, input as input2, select } from "@inquirer/prompts";
|
|
865
|
+
import { confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
|
|
650
866
|
|
|
651
867
|
// src/translations/cli/add-key.ts
|
|
652
868
|
init_esm_shims();
|
|
@@ -657,6 +873,7 @@ init_esm_shims();
|
|
|
657
873
|
|
|
658
874
|
// src/translations/utils/google-translate-provider.ts
|
|
659
875
|
init_esm_shims();
|
|
876
|
+
init_language_fallback();
|
|
660
877
|
function preserveVariables(text) {
|
|
661
878
|
const variableMap = /* @__PURE__ */ new Map();
|
|
662
879
|
let placeholderIndex = 0;
|
|
@@ -677,14 +894,24 @@ function restoreVariables(text, variableMap) {
|
|
|
677
894
|
}
|
|
678
895
|
var GoogleTranslateProvider = class {
|
|
679
896
|
async translate(options) {
|
|
680
|
-
const { text, sourceLang, targetLang, apiKey } = options;
|
|
897
|
+
const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
|
|
681
898
|
if (!apiKey) {
|
|
682
899
|
throw new Error(
|
|
683
900
|
"Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable or provide apiKey in options."
|
|
684
901
|
);
|
|
685
902
|
}
|
|
903
|
+
const targetLangResult = resolveLanguageWithFallback(targetLang, "google", useFallbackLanguages);
|
|
904
|
+
logLanguageFallback(targetLangResult, "google");
|
|
905
|
+
let resolvedSourceLang;
|
|
906
|
+
if (sourceLang) {
|
|
907
|
+
const sourceLangResult = resolveLanguageWithFallback(sourceLang, "google", useFallbackLanguages);
|
|
908
|
+
logLanguageFallback(sourceLangResult, "google");
|
|
909
|
+
resolvedSourceLang = sourceLangResult.resolvedLanguage;
|
|
910
|
+
}
|
|
686
911
|
const { textWithPlaceholders, variableMap } = preserveVariables(text);
|
|
687
912
|
const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
|
|
913
|
+
const sourceForGoogle = resolvedSourceLang?.includes("_") ? resolvedSourceLang.split("_")[0] : resolvedSourceLang;
|
|
914
|
+
const targetForGoogle = targetLangResult.resolvedLanguage.includes("_") ? targetLangResult.resolvedLanguage.split("_")[0] : targetLangResult.resolvedLanguage;
|
|
688
915
|
const response = await fetch(url, {
|
|
689
916
|
method: "POST",
|
|
690
917
|
headers: {
|
|
@@ -692,9 +919,8 @@ var GoogleTranslateProvider = class {
|
|
|
692
919
|
},
|
|
693
920
|
body: JSON.stringify({
|
|
694
921
|
q: textWithPlaceholders,
|
|
695
|
-
source:
|
|
696
|
-
target:
|
|
697
|
-
// Convert 'pt_BR' to 'pt'
|
|
922
|
+
source: sourceForGoogle,
|
|
923
|
+
target: targetForGoogle,
|
|
698
924
|
format: "text"
|
|
699
925
|
})
|
|
700
926
|
});
|
|
@@ -730,16 +956,20 @@ var GoogleTranslateProvider = class {
|
|
|
730
956
|
// src/translations/utils/translator.ts
|
|
731
957
|
var defaultProvider = new GoogleTranslateProvider();
|
|
732
958
|
var customProvider = null;
|
|
959
|
+
function setTranslationProvider(provider) {
|
|
960
|
+
customProvider = provider;
|
|
961
|
+
}
|
|
733
962
|
function getTranslationProvider() {
|
|
734
963
|
return customProvider || defaultProvider;
|
|
735
964
|
}
|
|
736
|
-
async function translateText(text, targetLang, sourceLang = "en", apiKey) {
|
|
965
|
+
async function translateText(text, targetLang, sourceLang = "en", apiKey, useFallbackLanguages = true) {
|
|
737
966
|
const provider = getTranslationProvider();
|
|
738
967
|
return provider.translate({
|
|
739
968
|
text,
|
|
740
969
|
sourceLang,
|
|
741
970
|
targetLang,
|
|
742
|
-
apiKey
|
|
971
|
+
apiKey,
|
|
972
|
+
useFallbackLanguages
|
|
743
973
|
});
|
|
744
974
|
}
|
|
745
975
|
|
|
@@ -827,7 +1057,7 @@ init_types();
|
|
|
827
1057
|
init_init();
|
|
828
1058
|
import * as fs3 from "fs";
|
|
829
1059
|
import * as path5 from "path";
|
|
830
|
-
import { checkbox, confirm, input } from "@inquirer/prompts";
|
|
1060
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
831
1061
|
async function initTranslationsInteractive(projectRoot = process.cwd()) {
|
|
832
1062
|
console.log("\n\u{1F30D} Translation System Setup\n");
|
|
833
1063
|
const configPath = path5.join(projectRoot, ".translationsrc.json");
|
|
@@ -906,11 +1136,28 @@ async function initTranslationsInteractive(projectRoot = process.cwd()) {
|
|
|
906
1136
|
message: "Where should TypeScript types be generated?",
|
|
907
1137
|
default: DEFAULT_CONFIG.typesOutputPath
|
|
908
1138
|
});
|
|
1139
|
+
const provider = await select({
|
|
1140
|
+
message: "Which translation provider would you like to use?",
|
|
1141
|
+
choices: [
|
|
1142
|
+
{
|
|
1143
|
+
name: "DeepL (recommended)",
|
|
1144
|
+
value: "deepl",
|
|
1145
|
+
description: "High-quality translations, requires DEEPL_API_KEY"
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
name: "Google Translate",
|
|
1149
|
+
value: "google",
|
|
1150
|
+
description: "Google Cloud Translation API, requires GOOGLE_TRANSLATE_API_KEY"
|
|
1151
|
+
}
|
|
1152
|
+
],
|
|
1153
|
+
default: "deepl"
|
|
1154
|
+
});
|
|
909
1155
|
console.log("\n\u{1F4CB} Configuration Summary:");
|
|
910
1156
|
console.log(` Translations: ${translationsPath}`);
|
|
911
1157
|
console.log(` Languages: ${languages.join(", ")}`);
|
|
912
1158
|
console.log(` Source: ${sourceLanguage}`);
|
|
913
1159
|
console.log(` Types: ${typesOutputPath}`);
|
|
1160
|
+
console.log(` Provider: ${provider}`);
|
|
914
1161
|
const confirmInit = await confirm({
|
|
915
1162
|
message: "\nProceed with initialization?",
|
|
916
1163
|
default: true
|
|
@@ -923,7 +1170,8 @@ async function initTranslationsInteractive(projectRoot = process.cwd()) {
|
|
|
923
1170
|
translationsPath,
|
|
924
1171
|
languages,
|
|
925
1172
|
sourceLanguage,
|
|
926
|
-
typesOutputPath
|
|
1173
|
+
typesOutputPath,
|
|
1174
|
+
provider
|
|
927
1175
|
};
|
|
928
1176
|
console.log();
|
|
929
1177
|
initTranslations(projectRoot, config);
|
|
@@ -981,12 +1229,109 @@ function getLanguageName(code) {
|
|
|
981
1229
|
|
|
982
1230
|
// src/translations/cli/manage.ts
|
|
983
1231
|
init_esm_shims();
|
|
1232
|
+
init_utils();
|
|
984
1233
|
import * as fs5 from "fs";
|
|
985
1234
|
import * as path9 from "path";
|
|
986
1235
|
|
|
987
1236
|
// src/translations/cli/auto-fill.ts
|
|
988
1237
|
init_esm_shims();
|
|
989
1238
|
import * as path7 from "path";
|
|
1239
|
+
|
|
1240
|
+
// src/translations/utils/deepl-translate-provider.ts
|
|
1241
|
+
init_esm_shims();
|
|
1242
|
+
init_language_fallback();
|
|
1243
|
+
function preserveVariables2(text) {
|
|
1244
|
+
const variableMap = /* @__PURE__ */ new Map();
|
|
1245
|
+
let placeholderIndex = 0;
|
|
1246
|
+
const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
|
|
1247
|
+
const placeholder = `XXX_${placeholderIndex}_XXX`;
|
|
1248
|
+
variableMap.set(placeholder, match);
|
|
1249
|
+
placeholderIndex++;
|
|
1250
|
+
return placeholder;
|
|
1251
|
+
});
|
|
1252
|
+
return { textWithPlaceholders, variableMap };
|
|
1253
|
+
}
|
|
1254
|
+
function restoreVariables2(text, variableMap) {
|
|
1255
|
+
let result = text;
|
|
1256
|
+
for (const [placeholder, original] of variableMap) {
|
|
1257
|
+
result = result.replace(new RegExp(placeholder, "g"), original);
|
|
1258
|
+
}
|
|
1259
|
+
return result;
|
|
1260
|
+
}
|
|
1261
|
+
function normalizeLanguageCode(langCode) {
|
|
1262
|
+
return langCode.replace("_", "-").toUpperCase();
|
|
1263
|
+
}
|
|
1264
|
+
var DeepLTranslateProvider = class {
|
|
1265
|
+
isFreeApi;
|
|
1266
|
+
constructor(isFreeApi = false) {
|
|
1267
|
+
this.isFreeApi = isFreeApi;
|
|
1268
|
+
}
|
|
1269
|
+
getApiEndpoint() {
|
|
1270
|
+
return this.isFreeApi ? "https://api-free.deepl.com/v2/translate" : "https://api.deepl.com/v2/translate";
|
|
1271
|
+
}
|
|
1272
|
+
async translate(options) {
|
|
1273
|
+
const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
|
|
1274
|
+
if (!apiKey) {
|
|
1275
|
+
throw new Error(
|
|
1276
|
+
"DeepL API key is required. Set DEEPL_API_KEY environment variable or provide apiKey in options."
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
const targetLangResult = resolveLanguageWithFallback(targetLang, "deepl", useFallbackLanguages);
|
|
1280
|
+
logLanguageFallback(targetLangResult, "deepl");
|
|
1281
|
+
let resolvedSourceLang;
|
|
1282
|
+
if (sourceLang) {
|
|
1283
|
+
const sourceLangResult = resolveLanguageWithFallback(sourceLang, "deepl", useFallbackLanguages);
|
|
1284
|
+
logLanguageFallback(sourceLangResult, "deepl");
|
|
1285
|
+
resolvedSourceLang = sourceLangResult.resolvedLanguage;
|
|
1286
|
+
}
|
|
1287
|
+
const { textWithPlaceholders, variableMap } = preserveVariables2(text);
|
|
1288
|
+
const body = {
|
|
1289
|
+
text: [textWithPlaceholders],
|
|
1290
|
+
target_lang: normalizeLanguageCode(targetLangResult.resolvedLanguage),
|
|
1291
|
+
...resolvedSourceLang && { source_lang: normalizeLanguageCode(resolvedSourceLang) }
|
|
1292
|
+
};
|
|
1293
|
+
const response = await fetch(this.getApiEndpoint(), {
|
|
1294
|
+
method: "POST",
|
|
1295
|
+
headers: {
|
|
1296
|
+
Authorization: `DeepL-Auth-Key ${apiKey}`,
|
|
1297
|
+
"Content-Type": "application/json"
|
|
1298
|
+
},
|
|
1299
|
+
body: JSON.stringify(body)
|
|
1300
|
+
});
|
|
1301
|
+
if (!response.ok) {
|
|
1302
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1303
|
+
throw new Error(`DeepL API error: ${errorData.message || response.statusText} (${response.status})`);
|
|
1304
|
+
}
|
|
1305
|
+
const data = await response.json();
|
|
1306
|
+
if (!data.translations || data.translations.length === 0) {
|
|
1307
|
+
throw new Error("DeepL API returned no translations");
|
|
1308
|
+
}
|
|
1309
|
+
const translatedText = data.translations[0].text;
|
|
1310
|
+
return restoreVariables2(translatedText, variableMap);
|
|
1311
|
+
}
|
|
1312
|
+
async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
|
|
1313
|
+
const results = [];
|
|
1314
|
+
for (const text of texts) {
|
|
1315
|
+
const translated = await this.translate({
|
|
1316
|
+
text,
|
|
1317
|
+
sourceLang,
|
|
1318
|
+
targetLang,
|
|
1319
|
+
apiKey
|
|
1320
|
+
});
|
|
1321
|
+
results.push(translated);
|
|
1322
|
+
if (delayMs > 0) {
|
|
1323
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return results;
|
|
1327
|
+
}
|
|
1328
|
+
async validateConfig() {
|
|
1329
|
+
const apiKey = process.env.DEEPL_API_KEY;
|
|
1330
|
+
return !!apiKey;
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1334
|
+
// src/translations/cli/auto-fill.ts
|
|
990
1335
|
init_utils();
|
|
991
1336
|
init_init();
|
|
992
1337
|
|
|
@@ -1003,7 +1348,11 @@ function validateTranslations(projectRoot = process.cwd()) {
|
|
|
1003
1348
|
const empty = [];
|
|
1004
1349
|
const sourceTranslations = readTranslations(translationsPath, sourceLanguage);
|
|
1005
1350
|
const sourceNamespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
1006
|
-
const languages =
|
|
1351
|
+
const languages = config.languages.filter((lang) => lang !== sourceLanguage);
|
|
1352
|
+
const syncResult = syncTranslationStructure(translationsPath, config.languages, sourceLanguage);
|
|
1353
|
+
if (syncResult.createdFiles.length > 0) {
|
|
1354
|
+
console.log(`Created ${syncResult.createdFiles.length} missing namespace files during sync`);
|
|
1355
|
+
}
|
|
1007
1356
|
console.log("=====");
|
|
1008
1357
|
console.log("Validating translations");
|
|
1009
1358
|
console.log("=====");
|
|
@@ -1036,7 +1385,7 @@ function validateTranslations(projectRoot = process.cwd()) {
|
|
|
1036
1385
|
}
|
|
1037
1386
|
}
|
|
1038
1387
|
}
|
|
1039
|
-
const valid = missing.length
|
|
1388
|
+
const valid = !missing.length && !empty.length;
|
|
1040
1389
|
if (valid) {
|
|
1041
1390
|
console.log("\u2713 All translations are valid!");
|
|
1042
1391
|
} else {
|
|
@@ -1078,10 +1427,28 @@ async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
|
|
|
1078
1427
|
const config = loadConfig(projectRoot);
|
|
1079
1428
|
const translationsPath = path7.join(projectRoot, config.translationsPath);
|
|
1080
1429
|
const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
|
|
1430
|
+
const currentProvider = getTranslationProvider();
|
|
1431
|
+
const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
|
|
1432
|
+
if (isDefaultGoogleProvider) {
|
|
1433
|
+
const provider = config.provider || "deepl";
|
|
1434
|
+
if (provider === "deepl") {
|
|
1435
|
+
setTranslationProvider(new DeepLTranslateProvider());
|
|
1436
|
+
} else {
|
|
1437
|
+
setTranslationProvider(new GoogleTranslateProvider());
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1081
1440
|
if (!apiKey) {
|
|
1082
|
-
|
|
1441
|
+
const provider = config.provider || "deepl";
|
|
1442
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
1443
|
+
throw new Error(`Translation API key is required. Set ${envVarName} or pass --api-key`);
|
|
1083
1444
|
}
|
|
1084
1445
|
const languagesToProcess = options.language ? [options.language] : config.languages.filter((lang) => lang !== config.sourceLanguage);
|
|
1446
|
+
console.log("\u{1F504} Synchronizing translation structure...");
|
|
1447
|
+
const syncResult = syncTranslationStructure(translationsPath, config.languages, config.sourceLanguage);
|
|
1448
|
+
if (syncResult.createdFiles.length > 0) {
|
|
1449
|
+
console.log(`Created ${syncResult.createdFiles.length} namespace files
|
|
1450
|
+
`);
|
|
1451
|
+
}
|
|
1085
1452
|
console.log("=====");
|
|
1086
1453
|
console.log("Auto-filling translations");
|
|
1087
1454
|
console.log("=====");
|
|
@@ -1100,7 +1467,7 @@ Reached limit of ${limit} translations`);
|
|
|
1100
1467
|
console.log(`
|
|
1101
1468
|
Processing language: ${language}`);
|
|
1102
1469
|
const missing = getMissingForLanguage(projectRoot, language);
|
|
1103
|
-
if (missing.length
|
|
1470
|
+
if (!missing.length) {
|
|
1104
1471
|
console.log(" No missing or empty translations");
|
|
1105
1472
|
continue;
|
|
1106
1473
|
}
|
|
@@ -1112,7 +1479,13 @@ Processing language: ${language}`);
|
|
|
1112
1479
|
try {
|
|
1113
1480
|
console.log(` [${totalProcessed}/${limit}] Translating ${item.namespace}.${item.key}`);
|
|
1114
1481
|
console.log(` EN: "${item.sourceValue}"`);
|
|
1115
|
-
const translated = await translateText(
|
|
1482
|
+
const translated = await translateText(
|
|
1483
|
+
item.sourceValue,
|
|
1484
|
+
language,
|
|
1485
|
+
config.sourceLanguage,
|
|
1486
|
+
apiKey,
|
|
1487
|
+
config.useFallbackLanguages ?? true
|
|
1488
|
+
);
|
|
1116
1489
|
console.log(` ${language.toUpperCase()}: "${translated}"`);
|
|
1117
1490
|
if (!dryRun) {
|
|
1118
1491
|
const translations = readTranslations(translationsPath, language);
|
|
@@ -1169,6 +1542,14 @@ async function manageTranslations(projectRoot = process.cwd(), options = {}) {
|
|
|
1169
1542
|
console.log("Please add translation files to the source language directory.\n");
|
|
1170
1543
|
return false;
|
|
1171
1544
|
}
|
|
1545
|
+
console.log("\u{1F504} Synchronizing translation structure...\n");
|
|
1546
|
+
const syncResult = syncTranslationStructure(translationsPath, config.languages, config.sourceLanguage);
|
|
1547
|
+
if (syncResult.createdFiles.length > 0) {
|
|
1548
|
+
console.log(`\u2713 Created ${syncResult.createdFiles.length} namespace files
|
|
1549
|
+
`);
|
|
1550
|
+
} else {
|
|
1551
|
+
console.log("\u2713 Translation structure is already synchronized\n");
|
|
1552
|
+
}
|
|
1172
1553
|
console.log("\u{1F50D} Validating translations...\n");
|
|
1173
1554
|
const validationResult = validateTranslations(projectRoot);
|
|
1174
1555
|
if (validationResult.valid) {
|
|
@@ -1177,8 +1558,11 @@ async function manageTranslations(projectRoot = process.cwd(), options = {}) {
|
|
|
1177
1558
|
const totalMissing = validationResult.missing.length + validationResult.empty.length;
|
|
1178
1559
|
if (autoFill) {
|
|
1179
1560
|
if (!apiKey) {
|
|
1561
|
+
const provider = config.provider || "deepl";
|
|
1562
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
1180
1563
|
console.log("\n\u26A0\uFE0F Auto-fill requested but no API key provided.");
|
|
1181
|
-
console.log(
|
|
1564
|
+
console.log(`Set ${envVarName} or pass --api-key to enable auto-fill.
|
|
1565
|
+
`);
|
|
1182
1566
|
} else {
|
|
1183
1567
|
console.log(`
|
|
1184
1568
|
\u{1F916} Auto-filling ${totalMissing} missing translations...
|
|
@@ -1298,8 +1682,8 @@ Commands:
|
|
|
1298
1682
|
add Add a new translation key
|
|
1299
1683
|
|
|
1300
1684
|
Options (Smart Mode):
|
|
1301
|
-
-a, --auto-fill Auto-fill missing translations with Google Translate
|
|
1302
|
-
--api-key <key>
|
|
1685
|
+
-a, --auto-fill Auto-fill missing translations with DeepL or Google Translate
|
|
1686
|
+
--api-key <key> Translation API key (or set DEEPL_API_KEY/GOOGLE_TRANSLATE_API_KEY)
|
|
1303
1687
|
-l, --language <lang> Process only this language
|
|
1304
1688
|
--limit <number> Max translations to process (default: 1000)
|
|
1305
1689
|
--skip-types Skip TypeScript type generation
|
|
@@ -1318,7 +1702,11 @@ Examples:
|
|
|
1318
1702
|
# Smart mode - check and validate translations
|
|
1319
1703
|
translations
|
|
1320
1704
|
|
|
1321
|
-
# Smart mode - validate and auto-fill missing translations
|
|
1705
|
+
# Smart mode - validate and auto-fill missing translations (DeepL)
|
|
1706
|
+
export DEEPL_API_KEY=your_key
|
|
1707
|
+
translations --auto-fill
|
|
1708
|
+
|
|
1709
|
+
# Smart mode - validate and auto-fill missing translations (Google)
|
|
1322
1710
|
export GOOGLE_TRANSLATE_API_KEY=your_key
|
|
1323
1711
|
translations --auto-fill
|
|
1324
1712
|
|
|
@@ -1373,7 +1761,7 @@ if (command === "add") {
|
|
|
1373
1761
|
const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
|
|
1374
1762
|
let namespace;
|
|
1375
1763
|
if (existingNamespaces.length > 0) {
|
|
1376
|
-
const namespaceChoice = await
|
|
1764
|
+
const namespaceChoice = await select2({
|
|
1377
1765
|
message: "Select namespace:",
|
|
1378
1766
|
choices: [
|
|
1379
1767
|
...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
|
|
@@ -1431,9 +1819,12 @@ if (command === "add") {
|
|
|
1431
1819
|
});
|
|
1432
1820
|
let apiKey;
|
|
1433
1821
|
if (autoTranslate) {
|
|
1434
|
-
|
|
1822
|
+
const provider = config.provider || "deepl";
|
|
1823
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
1824
|
+
apiKey = values["api-key"] || process.env[envVarName];
|
|
1435
1825
|
if (!apiKey) {
|
|
1436
|
-
console.log(
|
|
1826
|
+
console.log(`
|
|
1827
|
+
\u26A0\uFE0F ${envVarName} environment variable not found.`);
|
|
1437
1828
|
console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
|
|
1438
1829
|
}
|
|
1439
1830
|
}
|
|
@@ -1461,11 +1852,12 @@ if (command === "add") {
|
|
|
1461
1852
|
console.log("Use --help for usage information");
|
|
1462
1853
|
process.exit(1);
|
|
1463
1854
|
}
|
|
1464
|
-
const
|
|
1855
|
+
const config = loadConfig(process.cwd());
|
|
1856
|
+
const provider = config.provider || "deepl";
|
|
1857
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
1858
|
+
const apiKey = values["api-key"] || process.env[envVarName];
|
|
1465
1859
|
if (values["auto-fill"] && !apiKey) {
|
|
1466
|
-
console.error(
|
|
1467
|
-
"Error: --api-key or GOOGLE_TRANSLATE_API_KEY environment variable is required for auto-translation"
|
|
1468
|
-
);
|
|
1860
|
+
console.error(`Error: --api-key or ${envVarName} environment variable is required for auto-translation`);
|
|
1469
1861
|
process.exit(1);
|
|
1470
1862
|
}
|
|
1471
1863
|
addTranslationKey(process.cwd(), {
|
|
@@ -1488,7 +1880,11 @@ if (command === "add") {
|
|
|
1488
1880
|
} else {
|
|
1489
1881
|
const hasFlags = values["auto-fill"] || values.language || values["skip-types"] || values["dry-run"];
|
|
1490
1882
|
if (hasFlags) {
|
|
1491
|
-
const
|
|
1883
|
+
const configPath = path10.join(process.cwd(), ".translationsrc.json");
|
|
1884
|
+
const config = fs6.existsSync(configPath) ? loadConfig(process.cwd()) : { provider: "deepl" };
|
|
1885
|
+
const provider = config.provider || "deepl";
|
|
1886
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
1887
|
+
const apiKey = values["api-key"] || process.env[envVarName];
|
|
1492
1888
|
const limit = Number.parseInt(values.limit || "1000", 10);
|
|
1493
1889
|
manageTranslations(process.cwd(), {
|
|
1494
1890
|
autoFill: values["auto-fill"],
|
|
@@ -1511,7 +1907,7 @@ if (command === "add") {
|
|
|
1511
1907
|
const configPath = path10.join(process.cwd(), ".translationsrc.json");
|
|
1512
1908
|
const isInitialized = fs6.existsSync(configPath);
|
|
1513
1909
|
console.log("\n\u{1F30D} Translation Management\n");
|
|
1514
|
-
const action = await
|
|
1910
|
+
const action = await select2({
|
|
1515
1911
|
message: "What would you like to do?",
|
|
1516
1912
|
choices: [
|
|
1517
1913
|
{
|
|
@@ -1527,7 +1923,7 @@ if (command === "add") {
|
|
|
1527
1923
|
{
|
|
1528
1924
|
name: "\u{1F916} Auto-fill missing translations",
|
|
1529
1925
|
value: "autofill",
|
|
1530
|
-
description: "Automatically translate missing keys with Google Translate"
|
|
1926
|
+
description: "Automatically translate missing keys with DeepL or Google Translate"
|
|
1531
1927
|
},
|
|
1532
1928
|
{
|
|
1533
1929
|
name: "\u{1F4DD} Generate TypeScript types",
|
|
@@ -1567,7 +1963,7 @@ if (command === "add") {
|
|
|
1567
1963
|
const existingNamespaces = getNamespaces(translationsPath, config.sourceLanguage);
|
|
1568
1964
|
let namespace;
|
|
1569
1965
|
if (existingNamespaces.length > 0) {
|
|
1570
|
-
const namespaceChoice = await
|
|
1966
|
+
const namespaceChoice = await select2({
|
|
1571
1967
|
message: "Select namespace:",
|
|
1572
1968
|
choices: [
|
|
1573
1969
|
...existingNamespaces.map((ns) => ({ name: ns, value: ns })),
|
|
@@ -1625,9 +2021,12 @@ if (command === "add") {
|
|
|
1625
2021
|
});
|
|
1626
2022
|
let apiKey;
|
|
1627
2023
|
if (autoTranslate) {
|
|
1628
|
-
|
|
2024
|
+
const provider = config.provider || "deepl";
|
|
2025
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
2026
|
+
apiKey = process.env[envVarName];
|
|
1629
2027
|
if (!apiKey) {
|
|
1630
|
-
console.log(
|
|
2028
|
+
console.log(`
|
|
2029
|
+
\u26A0\uFE0F ${envVarName} environment variable not found.`);
|
|
1631
2030
|
console.log("Skipping auto-translation. Set this variable to enable auto-translation.\n");
|
|
1632
2031
|
}
|
|
1633
2032
|
}
|
|
@@ -1647,9 +2046,12 @@ if (command === "add") {
|
|
|
1647
2046
|
skipTypes: true
|
|
1648
2047
|
});
|
|
1649
2048
|
} else if (action === "autofill") {
|
|
1650
|
-
const
|
|
2049
|
+
const config = loadConfig(process.cwd());
|
|
2050
|
+
const provider = config.provider || "deepl";
|
|
2051
|
+
const envVarName = provider === "google" ? "GOOGLE_TRANSLATE_API_KEY" : "DEEPL_API_KEY";
|
|
2052
|
+
const apiKey = process.env[envVarName];
|
|
1651
2053
|
if (!apiKey) {
|
|
1652
|
-
console.log(
|
|
2054
|
+
console.log(`\u26A0\uFE0F ${envVarName} environment variable not found.`);
|
|
1653
2055
|
console.log("Please set it to enable auto-translation.\n");
|
|
1654
2056
|
process.exit(1);
|
|
1655
2057
|
}
|