poly-lexis 0.8.0 → 0.9.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/dist/index.d.ts CHANGED
@@ -184,6 +184,8 @@ interface TranslationConfig {
184
184
  searchPaths?: string[];
185
185
  /** File extensions to search for key usage (default: ['.ts', '.tsx', '.js', '.jsx', '.vue', '.svelte']) */
186
186
  searchExtensions?: string[];
187
+ /** Words or phrases that should never be translated (e.g. brand names, product names) */
188
+ protectedTerms?: string[];
187
189
  }
188
190
  interface TranslationEntry {
189
191
  namespace: string;
@@ -376,6 +378,8 @@ interface TranslateOptions {
376
378
  apiKey?: string;
377
379
  /** Enable automatic language fallback for unsupported regional variants (default: true) */
378
380
  useFallbackLanguages?: boolean;
381
+ /** Words or phrases that should never be translated (e.g. brand names, product names) */
382
+ protectedTerms?: string[];
379
383
  /** Additional provider-specific options */
380
384
  [key: string]: unknown;
381
385
  }
@@ -464,7 +468,7 @@ declare function resetTranslationProvider(): void;
464
468
  * @param useFallbackLanguages - Enable automatic language fallback (default: true)
465
469
  * @returns Promise resolving to translated text
466
470
  */
467
- declare function translateText(text: string, targetLang: string, sourceLang?: string, apiKey?: string, useFallbackLanguages?: boolean): Promise<string>;
471
+ declare function translateText(text: string, targetLang: string, sourceLang?: string, apiKey?: string, useFallbackLanguages?: boolean, protectedTerms?: string[]): Promise<string>;
468
472
  /**
469
473
  * Translate multiple texts in batch
470
474
  *
package/dist/index.js CHANGED
@@ -834,7 +834,8 @@ var init_types = __esm({
834
834
  provider: "deepl",
835
835
  useFallbackLanguages: true,
836
836
  searchPaths: ["src", "app", "pages", "components"],
837
- searchExtensions: [".ts", ".tsx", ".js", ".jsx", ".vue", ".svelte"]
837
+ searchExtensions: [".ts", ".tsx", ".js", ".jsx", ".vue", ".svelte"],
838
+ protectedTerms: []
838
839
  };
839
840
  DEFAULT_LANGUAGES = ["en", "fr", "it", "pl", "es", "pt", "de", "nl", "sv", "hu", "cs", "ja"];
840
841
  }
@@ -977,10 +978,20 @@ import * as path4 from "path";
977
978
 
978
979
  // src/translations/utils/deepl-translate-provider.ts
979
980
  init_language_fallback();
980
- function preserveVariables(text) {
981
+ function preserveVariables(text, protectedTerms = []) {
981
982
  const variableMap = /* @__PURE__ */ new Map();
982
983
  let placeholderIndex = 0;
983
- const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
984
+ let result = text;
985
+ for (const term of protectedTerms) {
986
+ const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
987
+ result = result.replace(new RegExp(escaped, "g"), () => {
988
+ const placeholder = `XXX_${placeholderIndex}_XXX`;
989
+ variableMap.set(placeholder, term);
990
+ placeholderIndex++;
991
+ return placeholder;
992
+ });
993
+ }
994
+ const textWithPlaceholders = result.replace(/\{\{([^}]+)\}\}/g, (match) => {
984
995
  const placeholder = `XXX_${placeholderIndex}_XXX`;
985
996
  variableMap.set(placeholder, match);
986
997
  placeholderIndex++;
@@ -1012,7 +1023,7 @@ var DeepLTranslateProvider = class {
1012
1023
  return this.isFreeApi ? "https://api-free.deepl.com/v2/translate" : "https://api.deepl.com/v2/translate";
1013
1024
  }
1014
1025
  async translate(options) {
1015
- const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
1026
+ const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true, protectedTerms = [] } = options;
1016
1027
  if (!apiKey) {
1017
1028
  throw new Error(
1018
1029
  "DeepL API key is required. Set DEEPL_API_KEY environment variable or provide apiKey in options."
@@ -1026,7 +1037,7 @@ var DeepLTranslateProvider = class {
1026
1037
  logLanguageFallback(sourceLangResult, "deepl");
1027
1038
  resolvedSourceLang = sourceLangResult.resolvedLanguage;
1028
1039
  }
1029
- const { textWithPlaceholders, variableMap } = preserveVariables(text);
1040
+ const { textWithPlaceholders, variableMap } = preserveVariables(text, protectedTerms);
1030
1041
  const body = {
1031
1042
  text: [textWithPlaceholders],
1032
1043
  target_lang: normalizeLanguageCode(targetLangResult.resolvedLanguage),
@@ -1075,10 +1086,20 @@ var DeepLTranslateProvider = class {
1075
1086
 
1076
1087
  // src/translations/utils/google-translate-provider.ts
1077
1088
  init_language_fallback();
1078
- function preserveVariables2(text) {
1089
+ function preserveVariables2(text, protectedTerms = []) {
1079
1090
  const variableMap = /* @__PURE__ */ new Map();
1080
1091
  let placeholderIndex = 0;
1081
- const textWithPlaceholders = text.replace(/\{\{([^}]+)\}\}/g, (match) => {
1092
+ let result = text;
1093
+ for (const term of protectedTerms) {
1094
+ const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1095
+ result = result.replace(new RegExp(escaped, "g"), () => {
1096
+ const placeholder = `XXX_${placeholderIndex}_XXX`;
1097
+ variableMap.set(placeholder, term);
1098
+ placeholderIndex++;
1099
+ return placeholder;
1100
+ });
1101
+ }
1102
+ const textWithPlaceholders = result.replace(/\{\{([^}]+)\}\}/g, (match) => {
1082
1103
  const placeholder = `XXX_${placeholderIndex}_XXX`;
1083
1104
  variableMap.set(placeholder, match);
1084
1105
  placeholderIndex++;
@@ -1100,7 +1121,7 @@ function restoreVariables2(text, variableMap) {
1100
1121
  }
1101
1122
  var GoogleTranslateProvider = class {
1102
1123
  async translate(options) {
1103
- const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true } = options;
1124
+ const { text, sourceLang, targetLang, apiKey, useFallbackLanguages = true, protectedTerms = [] } = options;
1104
1125
  if (!apiKey) {
1105
1126
  throw new Error(
1106
1127
  "Google Translate API key is required. Set GOOGLE_TRANSLATE_API_KEY environment variable or provide apiKey in options."
@@ -1114,7 +1135,7 @@ var GoogleTranslateProvider = class {
1114
1135
  logLanguageFallback(sourceLangResult, "google");
1115
1136
  resolvedSourceLang = sourceLangResult.resolvedLanguage;
1116
1137
  }
1117
- const { textWithPlaceholders, variableMap } = preserveVariables2(text);
1138
+ const { textWithPlaceholders, variableMap } = preserveVariables2(text, protectedTerms);
1118
1139
  const url = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
1119
1140
  const sourceForGoogle = resolvedSourceLang?.includes("_") ? resolvedSourceLang.split("_")[0] : resolvedSourceLang;
1120
1141
  const targetForGoogle = targetLangResult.resolvedLanguage.includes("_") ? targetLangResult.resolvedLanguage.split("_")[0] : targetLangResult.resolvedLanguage;
@@ -1171,14 +1192,15 @@ function getTranslationProvider() {
1171
1192
  function resetTranslationProvider() {
1172
1193
  customProvider = null;
1173
1194
  }
1174
- async function translateText(text, targetLang, sourceLang = "en", apiKey, useFallbackLanguages = true) {
1195
+ async function translateText(text, targetLang, sourceLang = "en", apiKey, useFallbackLanguages = true, protectedTerms = []) {
1175
1196
  const provider = getTranslationProvider();
1176
1197
  return provider.translate({
1177
1198
  text,
1178
1199
  sourceLang,
1179
1200
  targetLang,
1180
1201
  apiKey,
1181
- useFallbackLanguages
1202
+ useFallbackLanguages,
1203
+ protectedTerms
1182
1204
  });
1183
1205
  }
1184
1206
  async function translateBatch(texts, targetLang, sourceLang = "en", apiKey, delayMs = 100) {
@@ -1212,12 +1234,14 @@ function extractPluralBaseKeys(keys) {
1212
1234
  }
1213
1235
  return Array.from(baseKeys);
1214
1236
  }
1215
- var typeTemplate = (translationKeys, namespaceKeys) => `
1237
+ var typeTemplate = (translationKeys, namespaceKeys, languages) => `
1216
1238
  export const translationKeys = [${translationKeys.map((key) => `"${key}"`).join(", ")}] as const;
1217
1239
  export const namespaceKeys = [${namespaceKeys.map((key) => `"${key}"`).join(", ")}] as const;
1240
+ export const languages = [${languages.map((lang) => `"${lang}"`).join(", ")}] as const;
1218
1241
 
1219
1242
  export type TranslationKey = typeof translationKeys[number];
1220
1243
  export type TranslationNamespace = typeof namespaceKeys[number];
1244
+ export type Language = typeof languages[number];
1221
1245
  `;
1222
1246
  function generateTranslationTypes(projectRoot = process.cwd()) {
1223
1247
  console.log("=====");
@@ -1248,7 +1272,7 @@ function generateTranslationTypes(projectRoot = process.cwd()) {
1248
1272
  if (!fs3.existsSync(outputDir)) {
1249
1273
  fs3.mkdirSync(outputDir, { recursive: true });
1250
1274
  }
1251
- const typeString = typeTemplate(allKeys, namespaces);
1275
+ const typeString = typeTemplate(allKeys, namespaces, config.languages);
1252
1276
  fs3.writeFileSync(outputFilePath, typeString, "utf8");
1253
1277
  console.log(`Generated types with ${allKeys.length} keys and ${namespaces.length} namespaces`);
1254
1278
  console.log(`Output: ${outputFilePath}`);
@@ -1309,7 +1333,14 @@ async function addTranslationKey(projectRoot, options) {
1309
1333
  targetTranslations[namespace] = {};
1310
1334
  }
1311
1335
  if (!targetTranslations[namespace][key] || targetTranslations[namespace][key].trim() === "") {
1312
- const translated = await translateText(value, lang, sourceLang, apiKey, config.useFallbackLanguages ?? true);
1336
+ const translated = await translateText(
1337
+ value,
1338
+ lang,
1339
+ sourceLang,
1340
+ apiKey,
1341
+ config.useFallbackLanguages,
1342
+ config.protectedTerms
1343
+ );
1313
1344
  targetTranslations[namespace][key] = translated;
1314
1345
  const sorted = sortKeys(targetTranslations[namespace]);
1315
1346
  writeTranslation(translationsPath, lang, namespace, sorted);
@@ -1564,7 +1595,8 @@ Processing language: ${language}`);
1564
1595
  language,
1565
1596
  config.sourceLanguage,
1566
1597
  apiKey,
1567
- config.useFallbackLanguages ?? true
1598
+ config.useFallbackLanguages,
1599
+ config.protectedTerms
1568
1600
  );
1569
1601
  console.log(` ${language.toUpperCase()}: "${translated}"`);
1570
1602
  if (!dryRun) {
@@ -1629,7 +1661,8 @@ async function fillNamespace(projectRoot, language, namespace, apiKey) {
1629
1661
  language,
1630
1662
  config.sourceLanguage,
1631
1663
  apiKey,
1632
- config.useFallbackLanguages ?? true
1664
+ config.useFallbackLanguages ?? true,
1665
+ config.protectedTerms ?? []
1633
1666
  );
1634
1667
  targetKeys[key] = translated;
1635
1668
  count++;