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/README.md +15 -1
- package/dist/cli/translations.js +51 -19
- package/dist/cli/translations.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +49 -16
- package/dist/index.js.map +1 -1
- package/dist/scripts/verify-translations.js +2 -1
- package/dist/scripts/verify-translations.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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++;
|