poly-lexis 0.4.1 → 0.4.3
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/dist/cli/translations.js +136 -123
- package/dist/cli/translations.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +179 -163
- package/dist/index.js.map +1 -1
- package/dist/scripts/verify-translations.js +1 -1
- package/dist/scripts/verify-translations.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/translations.js
CHANGED
|
@@ -649,7 +649,7 @@ var init_types = __esm({
|
|
|
649
649
|
languages: ["en"],
|
|
650
650
|
sourceLanguage: "en",
|
|
651
651
|
typesOutputPath: "src/types/i18nTypes.ts",
|
|
652
|
-
provider: "
|
|
652
|
+
provider: "deepl",
|
|
653
653
|
useFallbackLanguages: true
|
|
654
654
|
};
|
|
655
655
|
DEFAULT_LANGUAGES = ["en", "fr", "it", "pl", "es", "pt", "de", "nl", "sv", "hu", "cs", "ja"];
|
|
@@ -795,19 +795,19 @@ __export(generate_types_exports, {
|
|
|
795
795
|
generateTranslationTypes: () => generateTranslationTypes
|
|
796
796
|
});
|
|
797
797
|
import { execSync } from "child_process";
|
|
798
|
-
import * as
|
|
799
|
-
import * as
|
|
798
|
+
import * as fs3 from "fs";
|
|
799
|
+
import * as path4 from "path";
|
|
800
800
|
function generateTranslationTypes(projectRoot = process.cwd()) {
|
|
801
801
|
console.log("=====");
|
|
802
802
|
console.time("i18n types generated");
|
|
803
803
|
console.log("Generating i18n types");
|
|
804
804
|
console.log("=====");
|
|
805
805
|
const config = loadConfig(projectRoot);
|
|
806
|
-
const translationsPath =
|
|
806
|
+
const translationsPath = path4.join(projectRoot, config.translationsPath);
|
|
807
807
|
const sourceLanguage = config.sourceLanguage;
|
|
808
|
-
const outputFilePath =
|
|
809
|
-
const dirPath =
|
|
810
|
-
if (!
|
|
808
|
+
const outputFilePath = path4.join(projectRoot, config.typesOutputPath);
|
|
809
|
+
const dirPath = path4.join(translationsPath, sourceLanguage);
|
|
810
|
+
if (!fs3.existsSync(dirPath)) {
|
|
811
811
|
throw new Error(`Source language directory not found: ${dirPath}`);
|
|
812
812
|
}
|
|
813
813
|
const namespaces = getNamespaces(translationsPath, sourceLanguage);
|
|
@@ -820,12 +820,12 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
|
|
|
820
820
|
const keys = Object.keys(translations[namespace] || {});
|
|
821
821
|
allKeys = allKeys.concat(keys);
|
|
822
822
|
}
|
|
823
|
-
const outputDir =
|
|
824
|
-
if (!
|
|
825
|
-
|
|
823
|
+
const outputDir = path4.dirname(outputFilePath);
|
|
824
|
+
if (!fs3.existsSync(outputDir)) {
|
|
825
|
+
fs3.mkdirSync(outputDir, { recursive: true });
|
|
826
826
|
}
|
|
827
827
|
const typeString = typeTemplate(allKeys, namespaces);
|
|
828
|
-
|
|
828
|
+
fs3.writeFileSync(outputFilePath, typeString, "utf8");
|
|
829
829
|
console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
|
|
830
830
|
console.log(`Output: ${outputFilePath}`);
|
|
831
831
|
try {
|
|
@@ -866,15 +866,106 @@ import { confirm as confirm2, input as input2, select as select2 } from "@inquir
|
|
|
866
866
|
|
|
867
867
|
// src/translations/cli/add-key.ts
|
|
868
868
|
init_esm_shims();
|
|
869
|
-
import * as
|
|
869
|
+
import * as path5 from "path";
|
|
870
870
|
|
|
871
|
-
// src/translations/utils/
|
|
871
|
+
// src/translations/utils/deepl-translate-provider.ts
|
|
872
872
|
init_esm_shims();
|
|
873
|
+
init_language_fallback();
|
|
874
|
+
function preserveVariables(text) {
|
|
875
|
+
const variableMap = /* @__PURE__ */ new Map();
|
|
876
|
+
let placeholderIndex = 0;
|
|
877
|
+
const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
|
|
878
|
+
const placeholder = `XXX_${placeholderIndex}_XXX`;
|
|
879
|
+
variableMap.set(placeholder, match);
|
|
880
|
+
placeholderIndex++;
|
|
881
|
+
return placeholder;
|
|
882
|
+
});
|
|
883
|
+
return { textWithPlaceholders, variableMap };
|
|
884
|
+
}
|
|
885
|
+
function restoreVariables(text, variableMap) {
|
|
886
|
+
let result = text;
|
|
887
|
+
for (const [placeholder, original] of variableMap) {
|
|
888
|
+
result = result.replace(new RegExp(placeholder, "g"), original);
|
|
889
|
+
}
|
|
890
|
+
return result;
|
|
891
|
+
}
|
|
892
|
+
function normalizeLanguageCode(langCode) {
|
|
893
|
+
return langCode.replace("_", "-").toUpperCase();
|
|
894
|
+
}
|
|
895
|
+
var DeepLTranslateProvider = class {
|
|
896
|
+
isFreeApi;
|
|
897
|
+
constructor(isFreeApi = false) {
|
|
898
|
+
this.isFreeApi = isFreeApi;
|
|
899
|
+
}
|
|
900
|
+
getApiEndpoint() {
|
|
901
|
+
return this.isFreeApi ? "https://api-free.deepl.com/v2/translate" : "https://api.deepl.com/v2/translate";
|
|
902
|
+
}
|
|
903
|
+
async translate(options) {
|
|
904
|
+
const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
|
|
905
|
+
if (!apiKey) {
|
|
906
|
+
throw new Error(
|
|
907
|
+
"DeepL API key is required. Set DEEPL_API_KEY environment variable or provide apiKey in options."
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
const targetLangResult = resolveLanguageWithFallback(targetLang, "deepl", useFallbackLanguages);
|
|
911
|
+
logLanguageFallback(targetLangResult, "deepl");
|
|
912
|
+
let resolvedSourceLang;
|
|
913
|
+
if (sourceLang) {
|
|
914
|
+
const sourceLangResult = resolveLanguageWithFallback(sourceLang, "deepl", useFallbackLanguages);
|
|
915
|
+
logLanguageFallback(sourceLangResult, "deepl");
|
|
916
|
+
resolvedSourceLang = sourceLangResult.resolvedLanguage;
|
|
917
|
+
}
|
|
918
|
+
const { textWithPlaceholders, variableMap } = preserveVariables(text);
|
|
919
|
+
const body = {
|
|
920
|
+
text: [textWithPlaceholders],
|
|
921
|
+
target_lang: normalizeLanguageCode(targetLangResult.resolvedLanguage),
|
|
922
|
+
...resolvedSourceLang && { source_lang: normalizeLanguageCode(resolvedSourceLang) }
|
|
923
|
+
};
|
|
924
|
+
const response = await fetch(this.getApiEndpoint(), {
|
|
925
|
+
method: "POST",
|
|
926
|
+
headers: {
|
|
927
|
+
Authorization: `DeepL-Auth-Key ${apiKey}`,
|
|
928
|
+
"Content-Type": "application/json"
|
|
929
|
+
},
|
|
930
|
+
body: JSON.stringify(body)
|
|
931
|
+
});
|
|
932
|
+
if (!response.ok) {
|
|
933
|
+
const errorData = await response.json().catch(() => ({}));
|
|
934
|
+
throw new Error(`DeepL API error: ${errorData.message || response.statusText} (${response.status})`);
|
|
935
|
+
}
|
|
936
|
+
const data = await response.json();
|
|
937
|
+
if (!data.translations || data.translations.length === 0) {
|
|
938
|
+
throw new Error("DeepL API returned no translations");
|
|
939
|
+
}
|
|
940
|
+
const translatedText = data.translations[0].text;
|
|
941
|
+
return restoreVariables(translatedText, variableMap);
|
|
942
|
+
}
|
|
943
|
+
async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
|
|
944
|
+
const results = [];
|
|
945
|
+
for (const text of texts) {
|
|
946
|
+
const translated = await this.translate({
|
|
947
|
+
text,
|
|
948
|
+
sourceLang,
|
|
949
|
+
targetLang,
|
|
950
|
+
apiKey
|
|
951
|
+
});
|
|
952
|
+
results.push(translated);
|
|
953
|
+
if (delayMs > 0) {
|
|
954
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return results;
|
|
958
|
+
}
|
|
959
|
+
async validateConfig() {
|
|
960
|
+
const apiKey = process.env.DEEPL_API_KEY;
|
|
961
|
+
return !!apiKey;
|
|
962
|
+
}
|
|
963
|
+
};
|
|
873
964
|
|
|
874
965
|
// src/translations/utils/google-translate-provider.ts
|
|
875
966
|
init_esm_shims();
|
|
876
967
|
init_language_fallback();
|
|
877
|
-
function
|
|
968
|
+
function preserveVariables2(text) {
|
|
878
969
|
const variableMap = /* @__PURE__ */ new Map();
|
|
879
970
|
let placeholderIndex = 0;
|
|
880
971
|
const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
|
|
@@ -885,7 +976,7 @@ function preserveVariables(text) {
|
|
|
885
976
|
});
|
|
886
977
|
return { textWithPlaceholders, variableMap };
|
|
887
978
|
}
|
|
888
|
-
function
|
|
979
|
+
function restoreVariables2(text, variableMap) {
|
|
889
980
|
let result = text;
|
|
890
981
|
for (const [placeholder, original] of variableMap) {
|
|
891
982
|
result = result.replace(new RegExp(placeholder, "g"), original);
|
|
@@ -908,7 +999,7 @@ var GoogleTranslateProvider = class {
|
|
|
908
999
|
logLanguageFallback(sourceLangResult, "google");
|
|
909
1000
|
resolvedSourceLang = sourceLangResult.resolvedLanguage;
|
|
910
1001
|
}
|
|
911
|
-
const { textWithPlaceholders, variableMap } =
|
|
1002
|
+
const { textWithPlaceholders, variableMap } = preserveVariables2(text);
|
|
912
1003
|
const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
|
|
913
1004
|
const sourceForGoogle = resolvedSourceLang?.includes("_") ? resolvedSourceLang.split("_")[0] : resolvedSourceLang;
|
|
914
1005
|
const targetForGoogle = targetLangResult.resolvedLanguage.includes("_") ? targetLangResult.resolvedLanguage.split("_")[0] : targetLangResult.resolvedLanguage;
|
|
@@ -929,7 +1020,7 @@ var GoogleTranslateProvider = class {
|
|
|
929
1020
|
throw new Error(`Google Translate API error: ${data.error.message}`);
|
|
930
1021
|
}
|
|
931
1022
|
const translatedText = data.data.translations[0].translatedText;
|
|
932
|
-
return
|
|
1023
|
+
return restoreVariables2(translatedText, variableMap);
|
|
933
1024
|
}
|
|
934
1025
|
async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
|
|
935
1026
|
const results = [];
|
|
@@ -954,6 +1045,7 @@ var GoogleTranslateProvider = class {
|
|
|
954
1045
|
};
|
|
955
1046
|
|
|
956
1047
|
// src/translations/utils/translator.ts
|
|
1048
|
+
init_esm_shims();
|
|
957
1049
|
var defaultProvider = new GoogleTranslateProvider();
|
|
958
1050
|
var customProvider = null;
|
|
959
1051
|
function setTranslationProvider(provider) {
|
|
@@ -975,11 +1067,22 @@ async function translateText(text, targetLang, sourceLang = "en", apiKey, useFal
|
|
|
975
1067
|
|
|
976
1068
|
// src/translations/cli/add-key.ts
|
|
977
1069
|
init_utils();
|
|
1070
|
+
init_generate_types();
|
|
978
1071
|
init_init();
|
|
979
1072
|
async function addTranslationKey(projectRoot, options) {
|
|
980
1073
|
const config = loadConfig(projectRoot);
|
|
981
|
-
const translationsPath =
|
|
1074
|
+
const translationsPath = path5.join(projectRoot, config.translationsPath);
|
|
982
1075
|
const { namespace, key, value, autoTranslate = false, apiKey } = options;
|
|
1076
|
+
const currentProvider = getTranslationProvider();
|
|
1077
|
+
const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
|
|
1078
|
+
if (isDefaultGoogleProvider) {
|
|
1079
|
+
const provider = config.provider || "deepl";
|
|
1080
|
+
if (provider === "deepl") {
|
|
1081
|
+
setTranslationProvider(new DeepLTranslateProvider());
|
|
1082
|
+
} else {
|
|
1083
|
+
setTranslationProvider(new GoogleTranslateProvider());
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
983
1086
|
console.log("=====");
|
|
984
1087
|
console.log("Adding translation key");
|
|
985
1088
|
console.log("=====");
|
|
@@ -1009,7 +1112,7 @@ async function addTranslationKey(projectRoot, options) {
|
|
|
1009
1112
|
targetTranslations[namespace] = {};
|
|
1010
1113
|
}
|
|
1011
1114
|
if (!targetTranslations[namespace][key] || targetTranslations[namespace][key].trim() === "") {
|
|
1012
|
-
const translated = await translateText(value, lang, sourceLang, apiKey);
|
|
1115
|
+
const translated = await translateText(value, lang, sourceLang, apiKey, config.useFallbackLanguages ?? true);
|
|
1013
1116
|
targetTranslations[namespace][key] = translated;
|
|
1014
1117
|
const sorted = sortKeys(targetTranslations[namespace]);
|
|
1015
1118
|
writeTranslation(translationsPath, lang, namespace, sorted);
|
|
@@ -1045,6 +1148,12 @@ async function addTranslationKey(projectRoot, options) {
|
|
|
1045
1148
|
console.log("=====");
|
|
1046
1149
|
console.log("Translation key added successfully!");
|
|
1047
1150
|
console.log("=====");
|
|
1151
|
+
console.log("\nRegenerating TypeScript types...");
|
|
1152
|
+
try {
|
|
1153
|
+
generateTranslationTypes(projectRoot);
|
|
1154
|
+
} catch (error) {
|
|
1155
|
+
console.error("Failed to generate types:", error instanceof Error ? error.message : "Unknown error");
|
|
1156
|
+
}
|
|
1048
1157
|
}
|
|
1049
1158
|
|
|
1050
1159
|
// src/cli/translations.ts
|
|
@@ -1055,13 +1164,13 @@ init_esm_shims();
|
|
|
1055
1164
|
init_schema();
|
|
1056
1165
|
init_types();
|
|
1057
1166
|
init_init();
|
|
1058
|
-
import * as
|
|
1059
|
-
import * as
|
|
1167
|
+
import * as fs4 from "fs";
|
|
1168
|
+
import * as path6 from "path";
|
|
1060
1169
|
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
1061
1170
|
async function initTranslationsInteractive(projectRoot = process.cwd()) {
|
|
1062
1171
|
console.log("\n\u{1F30D} Translation System Setup\n");
|
|
1063
|
-
const configPath =
|
|
1064
|
-
const alreadyExists =
|
|
1172
|
+
const configPath = path6.join(projectRoot, ".translationsrc.json");
|
|
1173
|
+
const alreadyExists = fs4.existsSync(configPath);
|
|
1065
1174
|
if (alreadyExists) {
|
|
1066
1175
|
console.log("\u26A0\uFE0F Configuration file already exists at .translationsrc.json\n");
|
|
1067
1176
|
const shouldOverwrite = await confirm({
|
|
@@ -1235,103 +1344,7 @@ import * as path9 from "path";
|
|
|
1235
1344
|
|
|
1236
1345
|
// src/translations/cli/auto-fill.ts
|
|
1237
1346
|
init_esm_shims();
|
|
1238
|
-
import * as
|
|
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
|
|
1347
|
+
import * as path8 from "path";
|
|
1335
1348
|
init_utils();
|
|
1336
1349
|
init_init();
|
|
1337
1350
|
|
|
@@ -1339,10 +1352,10 @@ init_init();
|
|
|
1339
1352
|
init_esm_shims();
|
|
1340
1353
|
init_utils();
|
|
1341
1354
|
init_init();
|
|
1342
|
-
import * as
|
|
1355
|
+
import * as path7 from "path";
|
|
1343
1356
|
function validateTranslations(projectRoot = process.cwd()) {
|
|
1344
1357
|
const config = loadConfig(projectRoot);
|
|
1345
|
-
const translationsPath =
|
|
1358
|
+
const translationsPath = path7.join(projectRoot, config.translationsPath);
|
|
1346
1359
|
const sourceLanguage = config.sourceLanguage;
|
|
1347
1360
|
const missing = [];
|
|
1348
1361
|
const empty = [];
|
|
@@ -1425,7 +1438,7 @@ function getMissingForLanguage(projectRoot, language) {
|
|
|
1425
1438
|
// src/translations/cli/auto-fill.ts
|
|
1426
1439
|
async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
|
|
1427
1440
|
const config = loadConfig(projectRoot);
|
|
1428
|
-
const translationsPath =
|
|
1441
|
+
const translationsPath = path8.join(projectRoot, config.translationsPath);
|
|
1429
1442
|
const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
|
|
1430
1443
|
const currentProvider = getTranslationProvider();
|
|
1431
1444
|
const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
|