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/index.d.ts CHANGED
@@ -199,7 +199,7 @@ interface AddKeyOptions {
199
199
  value: string;
200
200
  /** Auto-translate to all languages */
201
201
  autoTranslate?: boolean;
202
- /** Google Translate API key */
202
+ /** Translation API key (DeepL or Google Translate) */
203
203
  apiKey?: string;
204
204
  }
205
205
  /**
package/dist/index.js CHANGED
@@ -741,7 +741,7 @@ var init_types = __esm({
741
741
  languages: ["en"],
742
742
  sourceLanguage: "en",
743
743
  typesOutputPath: "src/types/i18nTypes.ts",
744
- provider: "google",
744
+ provider: "deepl",
745
745
  useFallbackLanguages: true
746
746
  };
747
747
  DEFAULT_LANGUAGES = ["en", "fr", "it", "pl", "es", "pt", "de", "nl", "sv", "hu", "cs", "ja"];
@@ -881,9 +881,9 @@ var init_init = __esm({
881
881
  });
882
882
 
883
883
  // src/translations/cli/add-key.ts
884
- import * as path3 from "path";
884
+ import * as path4 from "path";
885
885
 
886
- // src/translations/utils/google-translate-provider.ts
886
+ // src/translations/utils/deepl-translate-provider.ts
887
887
  init_language_fallback();
888
888
  function preserveVariables(text) {
889
889
  const variableMap = /* @__PURE__ */ new Map();
@@ -903,6 +903,99 @@ function restoreVariables(text, variableMap) {
903
903
  }
904
904
  return result;
905
905
  }
906
+ function normalizeLanguageCode(langCode) {
907
+ return langCode.replace("_", "-").toUpperCase();
908
+ }
909
+ var DeepLTranslateProvider = class {
910
+ isFreeApi;
911
+ constructor(isFreeApi = false) {
912
+ this.isFreeApi = isFreeApi;
913
+ }
914
+ getApiEndpoint() {
915
+ return this.isFreeApi ? "https://api-free.deepl.com/v2/translate" : "https://api.deepl.com/v2/translate";
916
+ }
917
+ async translate(options) {
918
+ const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
919
+ if (!apiKey) {
920
+ throw new Error(
921
+ "DeepL API key is required. Set DEEPL_API_KEY environment variable or provide apiKey in options."
922
+ );
923
+ }
924
+ const targetLangResult = resolveLanguageWithFallback(targetLang, "deepl", useFallbackLanguages);
925
+ logLanguageFallback(targetLangResult, "deepl");
926
+ let resolvedSourceLang;
927
+ if (sourceLang) {
928
+ const sourceLangResult = resolveLanguageWithFallback(sourceLang, "deepl", useFallbackLanguages);
929
+ logLanguageFallback(sourceLangResult, "deepl");
930
+ resolvedSourceLang = sourceLangResult.resolvedLanguage;
931
+ }
932
+ const { textWithPlaceholders, variableMap } = preserveVariables(text);
933
+ const body = {
934
+ text: [textWithPlaceholders],
935
+ target_lang: normalizeLanguageCode(targetLangResult.resolvedLanguage),
936
+ ...resolvedSourceLang && { source_lang: normalizeLanguageCode(resolvedSourceLang) }
937
+ };
938
+ const response = await fetch(this.getApiEndpoint(), {
939
+ method: "POST",
940
+ headers: {
941
+ Authorization: `DeepL-Auth-Key ${apiKey}`,
942
+ "Content-Type": "application/json"
943
+ },
944
+ body: JSON.stringify(body)
945
+ });
946
+ if (!response.ok) {
947
+ const errorData = await response.json().catch(() => ({}));
948
+ throw new Error(`DeepL API error: ${errorData.message || response.statusText} (${response.status})`);
949
+ }
950
+ const data = await response.json();
951
+ if (!data.translations || data.translations.length === 0) {
952
+ throw new Error("DeepL API returned no translations");
953
+ }
954
+ const translatedText = data.translations[0].text;
955
+ return restoreVariables(translatedText, variableMap);
956
+ }
957
+ async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
958
+ const results = [];
959
+ for (const text of texts) {
960
+ const translated = await this.translate({
961
+ text,
962
+ sourceLang,
963
+ targetLang,
964
+ apiKey
965
+ });
966
+ results.push(translated);
967
+ if (delayMs > 0) {
968
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
969
+ }
970
+ }
971
+ return results;
972
+ }
973
+ async validateConfig() {
974
+ const apiKey = process.env.DEEPL_API_KEY;
975
+ return !!apiKey;
976
+ }
977
+ };
978
+
979
+ // src/translations/utils/google-translate-provider.ts
980
+ init_language_fallback();
981
+ function preserveVariables2(text) {
982
+ const variableMap = /* @__PURE__ */ new Map();
983
+ let placeholderIndex = 0;
984
+ const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
985
+ const placeholder = `XXX_${placeholderIndex}_XXX`;
986
+ variableMap.set(placeholder, match);
987
+ placeholderIndex++;
988
+ return placeholder;
989
+ });
990
+ return { textWithPlaceholders, variableMap };
991
+ }
992
+ function restoreVariables2(text, variableMap) {
993
+ let result = text;
994
+ for (const [placeholder, original] of variableMap) {
995
+ result = result.replace(new RegExp(placeholder, "g"), original);
996
+ }
997
+ return result;
998
+ }
906
999
  var GoogleTranslateProvider = class {
907
1000
  async translate(options) {
908
1001
  const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
@@ -919,7 +1012,7 @@ var GoogleTranslateProvider = class {
919
1012
  logLanguageFallback(sourceLangResult, "google");
920
1013
  resolvedSourceLang = sourceLangResult.resolvedLanguage;
921
1014
  }
922
- const { textWithPlaceholders, variableMap } = preserveVariables(text);
1015
+ const { textWithPlaceholders, variableMap } = preserveVariables2(text);
923
1016
  const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
924
1017
  const sourceForGoogle = resolvedSourceLang?.includes("_") ? resolvedSourceLang.split("_")[0] : resolvedSourceLang;
925
1018
  const targetForGoogle = targetLangResult.resolvedLanguage.includes("_") ? targetLangResult.resolvedLanguage.split("_")[0] : targetLangResult.resolvedLanguage;
@@ -940,7 +1033,7 @@ var GoogleTranslateProvider = class {
940
1033
  throw new Error(`Google Translate API error: ${data.error.message}`);
941
1034
  }
942
1035
  const translatedText = data.data.translations[0].translatedText;
943
- return restoreVariables(translatedText, variableMap);
1036
+ return restoreVariables2(translatedText, variableMap);
944
1037
  }
945
1038
  async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
946
1039
  const results = [];
@@ -993,11 +1086,79 @@ async function translateBatch(texts, targetLang, sourceLang = "en", apiKey, dela
993
1086
 
994
1087
  // src/translations/cli/add-key.ts
995
1088
  init_utils();
1089
+
1090
+ // src/translations/cli/generate-types.ts
1091
+ init_utils();
996
1092
  init_init();
997
- async function addTranslationKey(projectRoot, options) {
1093
+ import { execSync } from "child_process";
1094
+ import * as fs3 from "fs";
1095
+ import * as path3 from "path";
1096
+ var typeTemplate = (translationKeys, namespaceKeys) => `
1097
+ export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
1098
+ export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
1099
+
1100
+ export type TranslationKey = typeof translationKeys[number];
1101
+ export type TranslationNamespace = typeof namespaceKeys[number];
1102
+ `;
1103
+ function generateTranslationTypes(projectRoot = process.cwd()) {
1104
+ console.log("=====");
1105
+ console.time("i18n types generated");
1106
+ console.log("Generating i18n types");
1107
+ console.log("=====");
998
1108
  const config = loadConfig(projectRoot);
999
1109
  const translationsPath = path3.join(projectRoot, config.translationsPath);
1110
+ const sourceLanguage = config.sourceLanguage;
1111
+ const outputFilePath = path3.join(projectRoot, config.typesOutputPath);
1112
+ const dirPath = path3.join(translationsPath, sourceLanguage);
1113
+ if (!fs3.existsSync(dirPath)) {
1114
+ throw new Error(`Source language directory not found: ${dirPath}`);
1115
+ }
1116
+ const namespaces = getNamespaces(translationsPath, sourceLanguage);
1117
+ if (!namespaces.length) {
1118
+ throw new Error(`No translation files found in ${dirPath}`);
1119
+ }
1120
+ const translations = readTranslations(translationsPath, sourceLanguage);
1121
+ let allKeys = [];
1122
+ for (const namespace of namespaces) {
1123
+ const keys = Object.keys(translations[namespace] || {});
1124
+ allKeys = allKeys.concat(keys);
1125
+ }
1126
+ const outputDir = path3.dirname(outputFilePath);
1127
+ if (!fs3.existsSync(outputDir)) {
1128
+ fs3.mkdirSync(outputDir, { recursive: true });
1129
+ }
1130
+ const typeString = typeTemplate(allKeys, namespaces);
1131
+ fs3.writeFileSync(outputFilePath, typeString, "utf8");
1132
+ console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
1133
+ console.log(`Output: ${outputFilePath}`);
1134
+ try {
1135
+ execSync(`pnpm biome format --write ${outputFilePath}`, {
1136
+ stdio: "inherit",
1137
+ cwd: projectRoot
1138
+ });
1139
+ } catch {
1140
+ console.warn("Failed to format with Biome, continuing without formatting...");
1141
+ }
1142
+ console.timeEnd("i18n types generated");
1143
+ console.log("=====");
1144
+ }
1145
+
1146
+ // src/translations/cli/add-key.ts
1147
+ init_init();
1148
+ async function addTranslationKey(projectRoot, options) {
1149
+ const config = loadConfig(projectRoot);
1150
+ const translationsPath = path4.join(projectRoot, config.translationsPath);
1000
1151
  const { namespace, key, value, autoTranslate = false, apiKey } = options;
1152
+ const currentProvider = getTranslationProvider();
1153
+ const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
1154
+ if (isDefaultGoogleProvider) {
1155
+ const provider = config.provider || "deepl";
1156
+ if (provider === "deepl") {
1157
+ setTranslationProvider(new DeepLTranslateProvider());
1158
+ } else {
1159
+ setTranslationProvider(new GoogleTranslateProvider());
1160
+ }
1161
+ }
1001
1162
  console.log("=====");
1002
1163
  console.log("Adding translation key");
1003
1164
  console.log("=====");
@@ -1027,7 +1188,7 @@ async function addTranslationKey(projectRoot, options) {
1027
1188
  targetTranslations[namespace] = {};
1028
1189
  }
1029
1190
  if (!targetTranslations[namespace][key] || targetTranslations[namespace][key].trim() === "") {
1030
- const translated = await translateText(value, lang, sourceLang, apiKey);
1191
+ const translated = await translateText(value, lang, sourceLang, apiKey, config.useFallbackLanguages ?? true);
1031
1192
  targetTranslations[namespace][key] = translated;
1032
1193
  const sorted = sortKeys(targetTranslations[namespace]);
1033
1194
  writeTranslation(translationsPath, lang, namespace, sorted);
@@ -1063,6 +1224,12 @@ async function addTranslationKey(projectRoot, options) {
1063
1224
  console.log("=====");
1064
1225
  console.log("Translation key added successfully!");
1065
1226
  console.log("=====");
1227
+ console.log("\nRegenerating TypeScript types...");
1228
+ try {
1229
+ generateTranslationTypes(projectRoot);
1230
+ } catch (error) {
1231
+ console.error("Failed to generate types:", error instanceof Error ? error.message : "Unknown error");
1232
+ }
1066
1233
  }
1067
1234
  async function addTranslationKeys(projectRoot, entries, autoTranslate = false, apiKey) {
1068
1235
  console.log(`Adding ${entries.length} translation keys...`);
@@ -1078,112 +1245,17 @@ async function addTranslationKeys(projectRoot, entries, autoTranslate = false, a
1078
1245
  }
1079
1246
 
1080
1247
  // src/translations/cli/auto-fill.ts
1081
- import * as path5 from "path";
1082
-
1083
- // src/translations/utils/deepl-translate-provider.ts
1084
- init_language_fallback();
1085
- function preserveVariables2(text) {
1086
- const variableMap = /* @__PURE__ */ new Map();
1087
- let placeholderIndex = 0;
1088
- const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
1089
- const placeholder = `XXX_${placeholderIndex}_XXX`;
1090
- variableMap.set(placeholder, match);
1091
- placeholderIndex++;
1092
- return placeholder;
1093
- });
1094
- return { textWithPlaceholders, variableMap };
1095
- }
1096
- function restoreVariables2(text, variableMap) {
1097
- let result = text;
1098
- for (const [placeholder, original] of variableMap) {
1099
- result = result.replace(new RegExp(placeholder, "g"), original);
1100
- }
1101
- return result;
1102
- }
1103
- function normalizeLanguageCode(langCode) {
1104
- return langCode.replace("_", "-").toUpperCase();
1105
- }
1106
- var DeepLTranslateProvider = class {
1107
- isFreeApi;
1108
- constructor(isFreeApi = false) {
1109
- this.isFreeApi = isFreeApi;
1110
- }
1111
- getApiEndpoint() {
1112
- return this.isFreeApi ? "https://api-free.deepl.com/v2/translate" : "https://api.deepl.com/v2/translate";
1113
- }
1114
- async translate(options) {
1115
- const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
1116
- if (!apiKey) {
1117
- throw new Error(
1118
- "DeepL API key is required. Set DEEPL_API_KEY environment variable or provide apiKey in options."
1119
- );
1120
- }
1121
- const targetLangResult = resolveLanguageWithFallback(targetLang, "deepl", useFallbackLanguages);
1122
- logLanguageFallback(targetLangResult, "deepl");
1123
- let resolvedSourceLang;
1124
- if (sourceLang) {
1125
- const sourceLangResult = resolveLanguageWithFallback(sourceLang, "deepl", useFallbackLanguages);
1126
- logLanguageFallback(sourceLangResult, "deepl");
1127
- resolvedSourceLang = sourceLangResult.resolvedLanguage;
1128
- }
1129
- const { textWithPlaceholders, variableMap } = preserveVariables2(text);
1130
- const body = {
1131
- text: [textWithPlaceholders],
1132
- target_lang: normalizeLanguageCode(targetLangResult.resolvedLanguage),
1133
- ...resolvedSourceLang && { source_lang: normalizeLanguageCode(resolvedSourceLang) }
1134
- };
1135
- const response = await fetch(this.getApiEndpoint(), {
1136
- method: "POST",
1137
- headers: {
1138
- Authorization: `DeepL-Auth-Key ${apiKey}`,
1139
- "Content-Type": "application/json"
1140
- },
1141
- body: JSON.stringify(body)
1142
- });
1143
- if (!response.ok) {
1144
- const errorData = await response.json().catch(() => ({}));
1145
- throw new Error(`DeepL API error: ${errorData.message || response.statusText} (${response.status})`);
1146
- }
1147
- const data = await response.json();
1148
- if (!data.translations || data.translations.length === 0) {
1149
- throw new Error("DeepL API returned no translations");
1150
- }
1151
- const translatedText = data.translations[0].text;
1152
- return restoreVariables2(translatedText, variableMap);
1153
- }
1154
- async translateBatch(texts, sourceLang, targetLang, apiKey, delayMs = 100) {
1155
- const results = [];
1156
- for (const text of texts) {
1157
- const translated = await this.translate({
1158
- text,
1159
- sourceLang,
1160
- targetLang,
1161
- apiKey
1162
- });
1163
- results.push(translated);
1164
- if (delayMs > 0) {
1165
- await new Promise((resolve) => setTimeout(resolve, delayMs));
1166
- }
1167
- }
1168
- return results;
1169
- }
1170
- async validateConfig() {
1171
- const apiKey = process.env.DEEPL_API_KEY;
1172
- return !!apiKey;
1173
- }
1174
- };
1175
-
1176
- // src/translations/cli/auto-fill.ts
1248
+ import * as path6 from "path";
1177
1249
  init_utils();
1178
1250
  init_init();
1179
1251
 
1180
1252
  // src/translations/cli/validate.ts
1181
1253
  init_utils();
1182
1254
  init_init();
1183
- import * as path4 from "path";
1255
+ import * as path5 from "path";
1184
1256
  function validateTranslations(projectRoot = process.cwd()) {
1185
1257
  const config = loadConfig(projectRoot);
1186
- const translationsPath = path4.join(projectRoot, config.translationsPath);
1258
+ const translationsPath = path5.join(projectRoot, config.translationsPath);
1187
1259
  const sourceLanguage = config.sourceLanguage;
1188
1260
  const missing = [];
1189
1261
  const empty = [];
@@ -1266,7 +1338,7 @@ function getMissingForLanguage(projectRoot, language) {
1266
1338
  // src/translations/cli/auto-fill.ts
1267
1339
  async function autoFillTranslations(projectRoot = process.cwd(), options = {}) {
1268
1340
  const config = loadConfig(projectRoot);
1269
- const translationsPath = path5.join(projectRoot, config.translationsPath);
1341
+ const translationsPath = path6.join(projectRoot, config.translationsPath);
1270
1342
  const { apiKey, limit = 1e3, delayMs = 100, dryRun = false } = options;
1271
1343
  const currentProvider = getTranslationProvider();
1272
1344
  const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
@@ -1359,7 +1431,7 @@ Processing language: ${language}`);
1359
1431
  }
1360
1432
  async function fillNamespace(projectRoot, language, namespace, apiKey) {
1361
1433
  const config = loadConfig(projectRoot);
1362
- const translationsPath = path5.join(projectRoot, config.translationsPath);
1434
+ const translationsPath = path6.join(projectRoot, config.translationsPath);
1363
1435
  const currentProvider = getTranslationProvider();
1364
1436
  const isDefaultGoogleProvider = currentProvider.constructor.name === "GoogleTranslateProvider";
1365
1437
  if (isDefaultGoogleProvider) {
@@ -1402,62 +1474,6 @@ async function fillNamespace(projectRoot, language, namespace, apiKey) {
1402
1474
  }
1403
1475
  }
1404
1476
 
1405
- // src/translations/cli/generate-types.ts
1406
- init_utils();
1407
- init_init();
1408
- import { execSync } from "child_process";
1409
- import * as fs3 from "fs";
1410
- import * as path6 from "path";
1411
- var typeTemplate = (translationKeys, namespaceKeys) => `
1412
- export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
1413
- export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
1414
-
1415
- export type TranslationKey = typeof translationKeys[number];
1416
- export type TranslationNamespace = typeof namespaceKeys[number];
1417
- `;
1418
- function generateTranslationTypes(projectRoot = process.cwd()) {
1419
- console.log("=====");
1420
- console.time("i18n types generated");
1421
- console.log("Generating i18n types");
1422
- console.log("=====");
1423
- const config = loadConfig(projectRoot);
1424
- const translationsPath = path6.join(projectRoot, config.translationsPath);
1425
- const sourceLanguage = config.sourceLanguage;
1426
- const outputFilePath = path6.join(projectRoot, config.typesOutputPath);
1427
- const dirPath = path6.join(translationsPath, sourceLanguage);
1428
- if (!fs3.existsSync(dirPath)) {
1429
- throw new Error(`Source language directory not found: ${dirPath}`);
1430
- }
1431
- const namespaces = getNamespaces(translationsPath, sourceLanguage);
1432
- if (!namespaces.length) {
1433
- throw new Error(`No translation files found in ${dirPath}`);
1434
- }
1435
- const translations = readTranslations(translationsPath, sourceLanguage);
1436
- let allKeys = [];
1437
- for (const namespace of namespaces) {
1438
- const keys = Object.keys(translations[namespace] || {});
1439
- allKeys = allKeys.concat(keys);
1440
- }
1441
- const outputDir = path6.dirname(outputFilePath);
1442
- if (!fs3.existsSync(outputDir)) {
1443
- fs3.mkdirSync(outputDir, { recursive: true });
1444
- }
1445
- const typeString = typeTemplate(allKeys, namespaces);
1446
- fs3.writeFileSync(outputFilePath, typeString, "utf8");
1447
- console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
1448
- console.log(`Output: ${outputFilePath}`);
1449
- try {
1450
- execSync(`pnpm biome format --write ${outputFilePath}`, {
1451
- stdio: "inherit",
1452
- cwd: projectRoot
1453
- });
1454
- } catch {
1455
- console.warn("Failed to format with Biome, continuing without formatting...");
1456
- }
1457
- console.timeEnd("i18n types generated");
1458
- console.log("=====");
1459
- }
1460
-
1461
1477
  // src/translations/index.ts
1462
1478
  init_init();
1463
1479