@lingo.dev/_compiler 0.2.4 → 0.3.1
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/build/index.cjs +290 -119
- package/build/index.d.cts +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.mjs +283 -112
- package/package.json +5 -2
package/build/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ var _unplugin = require('unplugin');
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@lingo.dev/_compiler",
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.3.1",
|
|
8
8
|
description: "Lingo.dev Compiler",
|
|
9
9
|
private: false,
|
|
10
10
|
publishConfig: {
|
|
@@ -46,6 +46,8 @@ var package_default = {
|
|
|
46
46
|
"@babel/parser": "^7.26.7",
|
|
47
47
|
"@babel/traverse": "^7.27.4",
|
|
48
48
|
"@babel/types": "^7.26.7",
|
|
49
|
+
"@lingo.dev/_sdk": "workspace:*",
|
|
50
|
+
"@openrouter/ai-sdk-provider": "^0.7.1",
|
|
49
51
|
ai: "^4.2.10",
|
|
50
52
|
dedent: "^1.6.0",
|
|
51
53
|
dotenv: "^16.4.5",
|
|
@@ -53,11 +55,13 @@ var package_default = {
|
|
|
53
55
|
ini: "^5.0.0",
|
|
54
56
|
lodash: "^4.17.21",
|
|
55
57
|
"object-hash": "^3.0.0",
|
|
58
|
+
"ollama-ai-provider": "^1.2.0",
|
|
56
59
|
prettier: "^3.4.2",
|
|
57
60
|
unplugin: "^2.1.2",
|
|
58
61
|
vitest: "^2.1.4",
|
|
59
62
|
zod: "^3.24.1"
|
|
60
|
-
}
|
|
63
|
+
},
|
|
64
|
+
packageManager: "pnpm@9.12.3"
|
|
61
65
|
};
|
|
62
66
|
|
|
63
67
|
// src/index.ts
|
|
@@ -830,10 +834,9 @@ var LCPCache = class {
|
|
|
830
834
|
}
|
|
831
835
|
// merge dictionary with current cache, sort files, entries and locales to minimize diffs
|
|
832
836
|
static _mergeLocaleDictionary(currentCache, dictionary, lcp) {
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
const cachedEntry = _nullishCoalesce(_lodash2.default.get(currentCache, ["files", fileName, "entries", entryName]), () => ( {}));
|
|
837
|
+
const newCache = _lodash2.default.cloneDeep(currentCache);
|
|
838
|
+
for (const [fileName, fileData] of Object.entries(dictionary.files)) {
|
|
839
|
+
for (const [entryName, entryValue] of Object.entries(fileData.entries)) {
|
|
837
840
|
const hash = _lodash2.default.get(lcp, [
|
|
838
841
|
"files",
|
|
839
842
|
fileName,
|
|
@@ -841,19 +844,33 @@ var LCPCache = class {
|
|
|
841
844
|
entryName,
|
|
842
845
|
"hash"
|
|
843
846
|
]);
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
847
|
+
const existingEntry = _lodash2.default.get(newCache, [
|
|
848
|
+
"files",
|
|
849
|
+
fileName,
|
|
850
|
+
"entries",
|
|
851
|
+
entryName
|
|
852
|
+
]) || {
|
|
853
|
+
content: {},
|
|
854
|
+
hash
|
|
855
|
+
};
|
|
856
|
+
const mergedContent = _lodash2.default.call(void 0, {
|
|
857
|
+
...existingEntry.content,
|
|
858
|
+
[dictionary.locale]: entryValue
|
|
848
859
|
}).toPairs().sortBy([0]).fromPairs().value();
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
860
|
+
_lodash2.default.set(newCache, ["files", fileName, "entries", entryName], {
|
|
861
|
+
content: mergedContent,
|
|
862
|
+
hash
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
const sortedFiles = _lodash2.default.call(void 0, newCache.files).toPairs().sortBy([0]).map(([fileName, file]) => {
|
|
867
|
+
const sortedEntries = _lodash2.default.call(void 0, file.entries).toPairs().sortBy([0]).fromPairs().value();
|
|
868
|
+
return [fileName, { entries: sortedEntries }];
|
|
869
|
+
}).fromPairs().value();
|
|
870
|
+
return {
|
|
853
871
|
version: dictionary.version,
|
|
854
|
-
files
|
|
872
|
+
files: sortedFiles
|
|
855
873
|
};
|
|
856
|
-
return newCache;
|
|
857
874
|
}
|
|
858
875
|
// extract dictionary from cache for given locale, validate entry hash from LCP schema
|
|
859
876
|
static _extractLocaleDictionary(cache, locale, lcp) {
|
|
@@ -926,7 +943,10 @@ var LCPCache = class {
|
|
|
926
943
|
// src/lib/lcp/api/index.ts
|
|
927
944
|
var _groq = require('@ai-sdk/groq');
|
|
928
945
|
var _google = require('@ai-sdk/google');
|
|
946
|
+
var _aisdkprovider = require('@openrouter/ai-sdk-provider');
|
|
947
|
+
var _ollamaaiprovider = require('ollama-ai-provider');
|
|
929
948
|
var _ai = require('ai');
|
|
949
|
+
var __sdk = require('@lingo.dev/_sdk');
|
|
930
950
|
|
|
931
951
|
|
|
932
952
|
// src/utils/locales.ts
|
|
@@ -949,7 +969,16 @@ function getLocaleModel(localeModels, sourceLocale, targetLocale) {
|
|
|
949
969
|
];
|
|
950
970
|
const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
|
|
951
971
|
if (modelKey) {
|
|
952
|
-
const
|
|
972
|
+
const value = localeModels[modelKey];
|
|
973
|
+
const firstColonIndex = _optionalChain([value, 'optionalAccess', _29 => _29.indexOf, 'call', _30 => _30(":")]);
|
|
974
|
+
if (value && firstColonIndex !== -1 && firstColonIndex !== void 0) {
|
|
975
|
+
const provider2 = value.substring(0, firstColonIndex);
|
|
976
|
+
const model2 = value.substring(firstColonIndex + 1);
|
|
977
|
+
if (provider2 && model2) {
|
|
978
|
+
return { provider: provider2, model: model2 };
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const [provider, model] = _optionalChain([value, 'optionalAccess', _31 => _31.split, 'call', _32 => _32(":")]) || [];
|
|
953
982
|
if (provider && model) {
|
|
954
983
|
return { provider, model };
|
|
955
984
|
}
|
|
@@ -962,7 +991,7 @@ var prompt_default = (args) => {
|
|
|
962
991
|
return getUserSystemPrompt(args) || getBuiltInSystemPrompt(args);
|
|
963
992
|
};
|
|
964
993
|
function getUserSystemPrompt(args) {
|
|
965
|
-
const userPrompt = _optionalChain([args, 'access',
|
|
994
|
+
const userPrompt = _optionalChain([args, 'access', _33 => _33.prompt, 'optionalAccess', _34 => _34.trim, 'call', _35 => _35(), 'optionalAccess', _36 => _36.replace, 'call', _37 => _37("{SOURCE_LOCALE}", args.sourceLocale), 'optionalAccess', _38 => _38.replace, 'call', _39 => _39("{TARGET_LOCALE}", args.targetLocale)]);
|
|
966
995
|
if (userPrompt) {
|
|
967
996
|
console.log("\u2728 Compiler is using user-defined prompt.");
|
|
968
997
|
return userPrompt;
|
|
@@ -1172,7 +1201,7 @@ function getKeyFromEnv(envVarName) {
|
|
|
1172
1201
|
path.default.resolve(process.cwd(), ".env.development")
|
|
1173
1202
|
]
|
|
1174
1203
|
});
|
|
1175
|
-
return _optionalChain([result, 'optionalAccess',
|
|
1204
|
+
return _optionalChain([result, 'optionalAccess', _40 => _40.parsed, 'optionalAccess', _41 => _41[envVarName]]);
|
|
1176
1205
|
}
|
|
1177
1206
|
function getKeyFromRc(rcPath) {
|
|
1178
1207
|
const rc = getRc();
|
|
@@ -1188,6 +1217,15 @@ function getGroqKeyFromRc() {
|
|
|
1188
1217
|
function getGroqKeyFromEnv() {
|
|
1189
1218
|
return getKeyFromEnv("GROQ_API_KEY");
|
|
1190
1219
|
}
|
|
1220
|
+
function getLingoDotDevKeyFromEnv() {
|
|
1221
|
+
return getKeyFromEnv("LINGODOTDEV_API_KEY");
|
|
1222
|
+
}
|
|
1223
|
+
function getLingoDotDevKeyFromRc() {
|
|
1224
|
+
return getKeyFromRc("auth.apiKey");
|
|
1225
|
+
}
|
|
1226
|
+
function getLingoDotDevKey() {
|
|
1227
|
+
return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
|
|
1228
|
+
}
|
|
1191
1229
|
function getGoogleKey() {
|
|
1192
1230
|
return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
|
|
1193
1231
|
}
|
|
@@ -1197,6 +1235,15 @@ function getGoogleKeyFromRc() {
|
|
|
1197
1235
|
function getGoogleKeyFromEnv() {
|
|
1198
1236
|
return getKeyFromEnv("GOOGLE_API_KEY");
|
|
1199
1237
|
}
|
|
1238
|
+
function getOpenRouterKey() {
|
|
1239
|
+
return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
|
|
1240
|
+
}
|
|
1241
|
+
function getOpenRouterKeyFromRc() {
|
|
1242
|
+
return getKeyFromRc("llm.openrouterApiKey");
|
|
1243
|
+
}
|
|
1244
|
+
function getOpenRouterKeyFromEnv() {
|
|
1245
|
+
return getKeyFromEnv("OPENROUTER_API_KEY");
|
|
1246
|
+
}
|
|
1200
1247
|
|
|
1201
1248
|
// src/lib/lcp/api/index.ts
|
|
1202
1249
|
|
|
@@ -1222,6 +1269,22 @@ var providerDetails = {
|
|
|
1222
1269
|
apiKeyConfigKey: "llm.googleApiKey",
|
|
1223
1270
|
getKeyLink: "https://ai.google.dev/",
|
|
1224
1271
|
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
|
|
1272
|
+
},
|
|
1273
|
+
openrouter: {
|
|
1274
|
+
name: "OpenRouter",
|
|
1275
|
+
apiKeyEnvVar: "OPENROUTER_API_KEY",
|
|
1276
|
+
apiKeyConfigKey: "llm.openrouterApiKey",
|
|
1277
|
+
getKeyLink: "https://openrouter.ai",
|
|
1278
|
+
docsLink: "https://openrouter.ai/docs"
|
|
1279
|
+
},
|
|
1280
|
+
ollama: {
|
|
1281
|
+
name: "Ollama",
|
|
1282
|
+
apiKeyEnvVar: void 0,
|
|
1283
|
+
// Ollama doesn't require an API key
|
|
1284
|
+
apiKeyConfigKey: void 0,
|
|
1285
|
+
// Ollama doesn't require an API key
|
|
1286
|
+
getKeyLink: "https://ollama.com/download",
|
|
1287
|
+
docsLink: "https://github.com/ollama/ollama/tree/main/docs"
|
|
1225
1288
|
}
|
|
1226
1289
|
};
|
|
1227
1290
|
|
|
@@ -1308,59 +1371,118 @@ var LCPAPI = class {
|
|
|
1308
1371
|
};
|
|
1309
1372
|
return dictionary;
|
|
1310
1373
|
}
|
|
1311
|
-
static
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1374
|
+
static _createLingoDotDevEngine() {
|
|
1375
|
+
if (isRunningInCIOrDocker()) {
|
|
1376
|
+
const apiKeyFromEnv = getLingoDotDevKeyFromEnv();
|
|
1377
|
+
if (!apiKeyFromEnv) {
|
|
1378
|
+
this._failMissingLLMKeyCi("lingo.dev");
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const apiKey = getLingoDotDevKey();
|
|
1382
|
+
if (!apiKey) {
|
|
1318
1383
|
throw new Error(
|
|
1319
|
-
|
|
1384
|
+
"\u26A0\uFE0F Lingo.dev API key not found. Please set LINGODOTDEV_API_KEY environment variable or configure it user-wide."
|
|
1320
1385
|
);
|
|
1321
1386
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1387
|
+
console.log(`Creating Lingo.dev client`);
|
|
1388
|
+
return new (0, __sdk.LingoDotDevEngine)({
|
|
1389
|
+
apiKey
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1393
|
+
if (models === "lingo.dev") {
|
|
1394
|
+
try {
|
|
1395
|
+
const lingoDotDevEngine = this._createLingoDotDevEngine();
|
|
1396
|
+
console.log(
|
|
1397
|
+
`\u2728 Using Lingo.dev Engine to localize from "${sourceLocale}" to "${targetLocale}"`
|
|
1398
|
+
);
|
|
1399
|
+
const result = await lingoDotDevEngine.localizeObject(
|
|
1400
|
+
sourceDictionary,
|
|
1330
1401
|
{
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1402
|
+
sourceLocale,
|
|
1403
|
+
targetLocale
|
|
1404
|
+
}
|
|
1405
|
+
);
|
|
1406
|
+
return result;
|
|
1407
|
+
} catch (error) {
|
|
1408
|
+
this._failLLMFailureLocal(
|
|
1409
|
+
"lingo.dev",
|
|
1410
|
+
targetLocale,
|
|
1411
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1412
|
+
);
|
|
1413
|
+
throw error;
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
const { provider, model } = getLocaleModel(
|
|
1417
|
+
models,
|
|
1418
|
+
sourceLocale,
|
|
1419
|
+
targetLocale
|
|
1420
|
+
);
|
|
1421
|
+
if (!provider || !model) {
|
|
1422
|
+
throw new Error(
|
|
1423
|
+
_dedent2.default`
|
|
1424
|
+
🚫 Lingo.dev Localization Engine Not Configured!
|
|
1425
|
+
|
|
1426
|
+
The "models" parameter is missing or incomplete in your Lingo.dev configuration.
|
|
1427
|
+
|
|
1428
|
+
👉 To fix this, set the "models" parameter to either:
|
|
1429
|
+
• "lingo.dev" (for the default engine)
|
|
1430
|
+
• a map of locale-to-model, e.g. { "models": { "en:es": "openai:gpt-3.5-turbo" } }
|
|
1431
|
+
|
|
1432
|
+
Example:
|
|
1433
|
+
{
|
|
1434
|
+
// ...
|
|
1435
|
+
"models": "lingo.dev"
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
For more details, see: https://lingo.dev/compiler
|
|
1439
|
+
To get help, join our Discord: https://lingo.dev/go/discord
|
|
1440
|
+
`
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
try {
|
|
1444
|
+
const aiModel = this._createAiModel(provider, model, targetLocale);
|
|
1445
|
+
console.log(
|
|
1446
|
+
`\u2139\uFE0F Using raw LLM API ("${provider}":"${model}") to translate from "${sourceLocale}" to "${targetLocale}"`
|
|
1447
|
+
);
|
|
1448
|
+
const response = await _ai.generateText.call(void 0, {
|
|
1449
|
+
model: aiModel,
|
|
1450
|
+
messages: [
|
|
1335
1451
|
{
|
|
1336
|
-
role: "
|
|
1337
|
-
content:
|
|
1452
|
+
role: "system",
|
|
1453
|
+
content: prompt_default({ sourceLocale, targetLocale })
|
|
1338
1454
|
},
|
|
1455
|
+
...shots_default.flatMap((shotsTuple) => [
|
|
1456
|
+
{
|
|
1457
|
+
role: "user",
|
|
1458
|
+
content: obj2xml(shotsTuple[0])
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
role: "assistant",
|
|
1462
|
+
content: obj2xml(shotsTuple[1])
|
|
1463
|
+
}
|
|
1464
|
+
]),
|
|
1339
1465
|
{
|
|
1340
|
-
role: "
|
|
1341
|
-
content: obj2xml(
|
|
1466
|
+
role: "user",
|
|
1467
|
+
content: obj2xml(sourceDictionary)
|
|
1342
1468
|
}
|
|
1343
|
-
]
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
targetLocale,
|
|
1361
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1362
|
-
);
|
|
1363
|
-
throw error;
|
|
1469
|
+
]
|
|
1470
|
+
});
|
|
1471
|
+
console.log("Response text received for", targetLocale);
|
|
1472
|
+
let responseText = response.text;
|
|
1473
|
+
responseText = responseText.substring(
|
|
1474
|
+
responseText.indexOf("<"),
|
|
1475
|
+
responseText.lastIndexOf(">") + 1
|
|
1476
|
+
);
|
|
1477
|
+
return xml2obj(responseText);
|
|
1478
|
+
} catch (error) {
|
|
1479
|
+
this._failLLMFailureLocal(
|
|
1480
|
+
provider,
|
|
1481
|
+
targetLocale,
|
|
1482
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1483
|
+
);
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1364
1486
|
}
|
|
1365
1487
|
}
|
|
1366
1488
|
/**
|
|
@@ -1374,7 +1496,7 @@ var LCPAPI = class {
|
|
|
1374
1496
|
*/
|
|
1375
1497
|
static _createAiModel(providerId, modelId, targetLocale) {
|
|
1376
1498
|
switch (providerId) {
|
|
1377
|
-
case "groq":
|
|
1499
|
+
case "groq": {
|
|
1378
1500
|
if (isRunningInCIOrDocker()) {
|
|
1379
1501
|
const groqFromEnv = getGroqKeyFromEnv();
|
|
1380
1502
|
if (!groqFromEnv) {
|
|
@@ -1391,7 +1513,8 @@ var LCPAPI = class {
|
|
|
1391
1513
|
`Creating Groq client for ${targetLocale} using model ${modelId}`
|
|
1392
1514
|
);
|
|
1393
1515
|
return _groq.createGroq.call(void 0, { apiKey: groqKey })(modelId);
|
|
1394
|
-
|
|
1516
|
+
}
|
|
1517
|
+
case "google": {
|
|
1395
1518
|
if (isRunningInCIOrDocker()) {
|
|
1396
1519
|
const googleFromEnv = getGoogleKeyFromEnv();
|
|
1397
1520
|
if (!googleFromEnv) {
|
|
@@ -1408,10 +1531,38 @@ var LCPAPI = class {
|
|
|
1408
1531
|
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
|
|
1409
1532
|
);
|
|
1410
1533
|
return _google.createGoogleGenerativeAI.call(void 0, { apiKey: googleKey })(modelId);
|
|
1411
|
-
|
|
1534
|
+
}
|
|
1535
|
+
case "openrouter": {
|
|
1536
|
+
if (isRunningInCIOrDocker()) {
|
|
1537
|
+
const openRouterFromEnv = getOpenRouterKeyFromEnv();
|
|
1538
|
+
if (!openRouterFromEnv) {
|
|
1539
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
const openRouterKey = getOpenRouterKey();
|
|
1543
|
+
if (!openRouterKey) {
|
|
1544
|
+
throw new Error(
|
|
1545
|
+
"\u26A0\uFE0F OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide."
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
console.log(
|
|
1549
|
+
`Creating OpenRouter client for ${targetLocale} using model ${modelId}`
|
|
1550
|
+
);
|
|
1551
|
+
return _aisdkprovider.createOpenRouter.call(void 0, {
|
|
1552
|
+
apiKey: openRouterKey
|
|
1553
|
+
})(modelId);
|
|
1554
|
+
}
|
|
1555
|
+
case "ollama": {
|
|
1556
|
+
console.log(
|
|
1557
|
+
`Creating Ollama client for ${targetLocale} using model ${modelId} at default Ollama address`
|
|
1558
|
+
);
|
|
1559
|
+
return _ollamaaiprovider.createOllama.call(void 0, )(modelId);
|
|
1560
|
+
}
|
|
1561
|
+
default: {
|
|
1412
1562
|
throw new Error(
|
|
1413
1563
|
`\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
|
|
1414
1564
|
);
|
|
1565
|
+
}
|
|
1415
1566
|
}
|
|
1416
1567
|
}
|
|
1417
1568
|
/**
|
|
@@ -1500,7 +1651,7 @@ var LCPAPI = class {
|
|
|
1500
1651
|
This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
|
|
1501
1652
|
|
|
1502
1653
|
⭐️ Also:
|
|
1503
|
-
1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
|
|
1654
|
+
1. Did you set ${details.apiKeyEnvVar ? `${details.apiKeyEnvVar}` : "the provider API key"} environment variable correctly ${!details.apiKeyEnvVar ? "(if required)" : ""}?
|
|
1504
1655
|
2. Did you reach any limits of your ${details.name} account?
|
|
1505
1656
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1506
1657
|
|
|
@@ -1514,31 +1665,39 @@ var LCPAPI = class {
|
|
|
1514
1665
|
|
|
1515
1666
|
// src/lib/lcp/server.ts
|
|
1516
1667
|
var LCPServer = (_class = class {
|
|
1517
|
-
static __initStatic() {this.
|
|
1668
|
+
static __initStatic() {this.dictionariesCache = null}
|
|
1669
|
+
static __initStatic2() {this.inFlightPromise = null}
|
|
1518
1670
|
static async loadDictionaries(params) {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
setTimeout(resolve3, 500);
|
|
1522
|
-
});
|
|
1671
|
+
if (this.dictionariesCache) {
|
|
1672
|
+
return this.dictionariesCache;
|
|
1523
1673
|
}
|
|
1524
|
-
this.
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1674
|
+
if (this.inFlightPromise) {
|
|
1675
|
+
return this.inFlightPromise;
|
|
1676
|
+
}
|
|
1677
|
+
this.inFlightPromise = (async () => {
|
|
1678
|
+
try {
|
|
1679
|
+
const targetLocales = _lodash2.default.uniq([
|
|
1680
|
+
...params.targetLocales,
|
|
1681
|
+
params.sourceLocale
|
|
1682
|
+
]);
|
|
1683
|
+
const dictionaries = await Promise.all(
|
|
1684
|
+
targetLocales.map(
|
|
1685
|
+
(targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
|
|
1686
|
+
)
|
|
1687
|
+
);
|
|
1688
|
+
const result = _lodash2.default.fromPairs(
|
|
1689
|
+
targetLocales.map((targetLocale, index) => [
|
|
1690
|
+
targetLocale,
|
|
1691
|
+
dictionaries[index]
|
|
1692
|
+
])
|
|
1693
|
+
);
|
|
1694
|
+
this.dictionariesCache = result;
|
|
1695
|
+
return result;
|
|
1696
|
+
} finally {
|
|
1697
|
+
this.inFlightPromise = null;
|
|
1698
|
+
}
|
|
1699
|
+
})();
|
|
1700
|
+
return this.inFlightPromise;
|
|
1542
1701
|
}
|
|
1543
1702
|
static async loadDictionaryForLocale(params) {
|
|
1544
1703
|
const sourceDictionary = this._extractSourceDictionary(
|
|
@@ -1703,14 +1862,14 @@ var LCPServer = (_class = class {
|
|
|
1703
1862
|
const sourceFile = _lodash2.default.get(sourceDictionary.files, fileName);
|
|
1704
1863
|
const targetFile = _lodash2.default.get(targetDictionary.files, fileName);
|
|
1705
1864
|
const entries = removeEmptyEntries ? _lodash2.default.pickBy(
|
|
1706
|
-
_optionalChain([sourceFile, 'optionalAccess',
|
|
1707
|
-
(value) => _optionalChain([String, 'call',
|
|
1708
|
-
) : _optionalChain([sourceFile, 'optionalAccess',
|
|
1865
|
+
_optionalChain([sourceFile, 'optionalAccess', _42 => _42.entries]) || {},
|
|
1866
|
+
(value) => _optionalChain([String, 'call', _43 => _43(value || ""), 'optionalAccess', _44 => _44.trim, 'optionalCall', _45 => _45(), 'optionalAccess', _46 => _46.length]) > 0
|
|
1867
|
+
) : _optionalChain([sourceFile, 'optionalAccess', _47 => _47.entries]) || {};
|
|
1709
1868
|
return [
|
|
1710
1869
|
fileName,
|
|
1711
1870
|
{
|
|
1712
1871
|
...targetFile,
|
|
1713
|
-
entries: _lodash2.default.merge(_optionalChain([targetFile, 'optionalAccess',
|
|
1872
|
+
entries: _lodash2.default.merge({}, _optionalChain([targetFile, 'optionalAccess', _48 => _48.entries]) || {}, entries)
|
|
1714
1873
|
}
|
|
1715
1874
|
];
|
|
1716
1875
|
}).fromPairs().value();
|
|
@@ -1727,7 +1886,7 @@ var LCPServer = (_class = class {
|
|
|
1727
1886
|
0
|
|
1728
1887
|
);
|
|
1729
1888
|
}
|
|
1730
|
-
}, _class.__initStatic(), _class);
|
|
1889
|
+
}, _class.__initStatic(), _class.__initStatic2(), _class);
|
|
1731
1890
|
|
|
1732
1891
|
// src/utils/invokations.ts
|
|
1733
1892
|
|
|
@@ -1916,7 +2075,7 @@ function jsxFragmentMutation(payload) {
|
|
|
1916
2075
|
var jsxHtmlLangMutation = createCodeMutation((payload) => {
|
|
1917
2076
|
_traverse2.default.call(void 0, payload.ast, {
|
|
1918
2077
|
JSXElement: (path7) => {
|
|
1919
|
-
if (_optionalChain([getJsxElementName, 'call',
|
|
2078
|
+
if (_optionalChain([getJsxElementName, 'call', _49 => _49(path7), 'optionalAccess', _50 => _50.toLowerCase, 'call', _51 => _51()]) === "html") {
|
|
1920
2079
|
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
1921
2080
|
const packagePath = mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
|
|
1922
2081
|
const lingoHtmlComponentImport = getOrCreateImport(payload.ast, {
|
|
@@ -2499,6 +2658,10 @@ var keyCheckers = {
|
|
|
2499
2658
|
google: {
|
|
2500
2659
|
checkEnv: getGoogleKeyFromEnv,
|
|
2501
2660
|
checkRc: getGoogleKeyFromRc
|
|
2661
|
+
},
|
|
2662
|
+
"lingo.dev": {
|
|
2663
|
+
checkEnv: getLingoDotDevKeyFromEnv,
|
|
2664
|
+
checkRc: getLingoDotDevKeyFromRc
|
|
2502
2665
|
}
|
|
2503
2666
|
};
|
|
2504
2667
|
var unplugin = _unplugin.createUnplugin.call(void 0,
|
|
@@ -2506,26 +2669,31 @@ var unplugin = _unplugin.createUnplugin.call(void 0,
|
|
|
2506
2669
|
console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
|
|
2507
2670
|
const params = _lodash2.default.defaults(_params, defaultParams);
|
|
2508
2671
|
if (!isRunningInCIOrDocker()) {
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2672
|
+
if (params.models === "lingo.dev") {
|
|
2673
|
+
validateLLMKeyDetails(["lingo.dev"]);
|
|
2674
|
+
} else {
|
|
2675
|
+
const configuredProviders = getConfiguredProviders(params.models);
|
|
2676
|
+
validateLLMKeyDetails(configuredProviders);
|
|
2677
|
+
const invalidLocales = getInvalidLocales(
|
|
2678
|
+
params.models,
|
|
2679
|
+
params.sourceLocale,
|
|
2680
|
+
params.targetLocales
|
|
2681
|
+
);
|
|
2682
|
+
if (invalidLocales.length > 0) {
|
|
2683
|
+
console.log(_dedent2.default`
|
|
2684
|
+
\n
|
|
2685
|
+
⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
|
|
2686
|
+
|
|
2687
|
+
⭐️ Next steps:
|
|
2688
|
+
1. Refer to documentation for help: https://docs.lingo.dev/
|
|
2689
|
+
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2690
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2691
|
+
|
|
2692
|
+
✨
|
|
2693
|
+
`);
|
|
2694
|
+
process.exit(1);
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2529
2697
|
}
|
|
2530
2698
|
LCPCache.ensureDictionaryFile({
|
|
2531
2699
|
sourceRoot: params.sourceRoot,
|
|
@@ -2553,6 +2721,7 @@ var unplugin = _unplugin.createUnplugin.call(void 0,
|
|
|
2553
2721
|
lingoDir: params.lingoDir
|
|
2554
2722
|
});
|
|
2555
2723
|
const dictionary = dictionaries[moduleInfo.params.locale];
|
|
2724
|
+
console.log(JSON.stringify(dictionary, null, 2));
|
|
2556
2725
|
return {
|
|
2557
2726
|
code: `export default ${JSON.stringify(dictionary, null, 2)}`
|
|
2558
2727
|
};
|
|
@@ -2621,10 +2790,12 @@ var src_default = {
|
|
|
2621
2790
|
return config2;
|
|
2622
2791
|
}
|
|
2623
2792
|
};
|
|
2624
|
-
function
|
|
2625
|
-
|
|
2793
|
+
function getConfiguredProviders(models) {
|
|
2794
|
+
return _lodash2.default.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
|
|
2626
2795
|
(providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
|
|
2627
2796
|
).value();
|
|
2797
|
+
}
|
|
2798
|
+
function validateLLMKeyDetails(configuredProviders) {
|
|
2628
2799
|
if (configuredProviders.length === 0) {
|
|
2629
2800
|
return;
|
|
2630
2801
|
}
|
package/build/index.d.cts
CHANGED
package/build/index.d.ts
CHANGED
package/build/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { createUnplugin } from "unplugin";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@lingo.dev/_compiler",
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.3.1",
|
|
8
8
|
description: "Lingo.dev Compiler",
|
|
9
9
|
private: false,
|
|
10
10
|
publishConfig: {
|
|
@@ -46,6 +46,8 @@ var package_default = {
|
|
|
46
46
|
"@babel/parser": "^7.26.7",
|
|
47
47
|
"@babel/traverse": "^7.27.4",
|
|
48
48
|
"@babel/types": "^7.26.7",
|
|
49
|
+
"@lingo.dev/_sdk": "workspace:*",
|
|
50
|
+
"@openrouter/ai-sdk-provider": "^0.7.1",
|
|
49
51
|
ai: "^4.2.10",
|
|
50
52
|
dedent: "^1.6.0",
|
|
51
53
|
dotenv: "^16.4.5",
|
|
@@ -53,11 +55,13 @@ var package_default = {
|
|
|
53
55
|
ini: "^5.0.0",
|
|
54
56
|
lodash: "^4.17.21",
|
|
55
57
|
"object-hash": "^3.0.0",
|
|
58
|
+
"ollama-ai-provider": "^1.2.0",
|
|
56
59
|
prettier: "^3.4.2",
|
|
57
60
|
unplugin: "^2.1.2",
|
|
58
61
|
vitest: "^2.1.4",
|
|
59
62
|
zod: "^3.24.1"
|
|
60
|
-
}
|
|
63
|
+
},
|
|
64
|
+
packageManager: "pnpm@9.12.3"
|
|
61
65
|
};
|
|
62
66
|
|
|
63
67
|
// src/index.ts
|
|
@@ -830,10 +834,9 @@ var LCPCache = class {
|
|
|
830
834
|
}
|
|
831
835
|
// merge dictionary with current cache, sort files, entries and locales to minimize diffs
|
|
832
836
|
static _mergeLocaleDictionary(currentCache, dictionary, lcp) {
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
const cachedEntry = _3.get(currentCache, ["files", fileName, "entries", entryName]) ?? {};
|
|
837
|
+
const newCache = _3.cloneDeep(currentCache);
|
|
838
|
+
for (const [fileName, fileData] of Object.entries(dictionary.files)) {
|
|
839
|
+
for (const [entryName, entryValue] of Object.entries(fileData.entries)) {
|
|
837
840
|
const hash = _3.get(lcp, [
|
|
838
841
|
"files",
|
|
839
842
|
fileName,
|
|
@@ -841,19 +844,33 @@ var LCPCache = class {
|
|
|
841
844
|
entryName,
|
|
842
845
|
"hash"
|
|
843
846
|
]);
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
847
|
+
const existingEntry = _3.get(newCache, [
|
|
848
|
+
"files",
|
|
849
|
+
fileName,
|
|
850
|
+
"entries",
|
|
851
|
+
entryName
|
|
852
|
+
]) || {
|
|
853
|
+
content: {},
|
|
854
|
+
hash
|
|
855
|
+
};
|
|
856
|
+
const mergedContent = _3({
|
|
857
|
+
...existingEntry.content,
|
|
858
|
+
[dictionary.locale]: entryValue
|
|
848
859
|
}).toPairs().sortBy([0]).fromPairs().value();
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
860
|
+
_3.set(newCache, ["files", fileName, "entries", entryName], {
|
|
861
|
+
content: mergedContent,
|
|
862
|
+
hash
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
const sortedFiles = _3(newCache.files).toPairs().sortBy([0]).map(([fileName, file]) => {
|
|
867
|
+
const sortedEntries = _3(file.entries).toPairs().sortBy([0]).fromPairs().value();
|
|
868
|
+
return [fileName, { entries: sortedEntries }];
|
|
869
|
+
}).fromPairs().value();
|
|
870
|
+
return {
|
|
853
871
|
version: dictionary.version,
|
|
854
|
-
files
|
|
872
|
+
files: sortedFiles
|
|
855
873
|
};
|
|
856
|
-
return newCache;
|
|
857
874
|
}
|
|
858
875
|
// extract dictionary from cache for given locale, validate entry hash from LCP schema
|
|
859
876
|
static _extractLocaleDictionary(cache, locale, lcp) {
|
|
@@ -926,7 +943,10 @@ var LCPCache = class {
|
|
|
926
943
|
// src/lib/lcp/api/index.ts
|
|
927
944
|
import { createGroq } from "@ai-sdk/groq";
|
|
928
945
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
946
|
+
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
947
|
+
import { createOllama } from "ollama-ai-provider";
|
|
929
948
|
import { generateText } from "ai";
|
|
949
|
+
import { LingoDotDevEngine } from "@lingo.dev/_sdk";
|
|
930
950
|
import _6 from "lodash";
|
|
931
951
|
|
|
932
952
|
// src/utils/locales.ts
|
|
@@ -949,7 +969,16 @@ function getLocaleModel(localeModels, sourceLocale, targetLocale) {
|
|
|
949
969
|
];
|
|
950
970
|
const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
|
|
951
971
|
if (modelKey) {
|
|
952
|
-
const
|
|
972
|
+
const value = localeModels[modelKey];
|
|
973
|
+
const firstColonIndex = value?.indexOf(":");
|
|
974
|
+
if (value && firstColonIndex !== -1 && firstColonIndex !== void 0) {
|
|
975
|
+
const provider2 = value.substring(0, firstColonIndex);
|
|
976
|
+
const model2 = value.substring(firstColonIndex + 1);
|
|
977
|
+
if (provider2 && model2) {
|
|
978
|
+
return { provider: provider2, model: model2 };
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const [provider, model] = value?.split(":") || [];
|
|
953
982
|
if (provider && model) {
|
|
954
983
|
return { provider, model };
|
|
955
984
|
}
|
|
@@ -1188,6 +1217,15 @@ function getGroqKeyFromRc() {
|
|
|
1188
1217
|
function getGroqKeyFromEnv() {
|
|
1189
1218
|
return getKeyFromEnv("GROQ_API_KEY");
|
|
1190
1219
|
}
|
|
1220
|
+
function getLingoDotDevKeyFromEnv() {
|
|
1221
|
+
return getKeyFromEnv("LINGODOTDEV_API_KEY");
|
|
1222
|
+
}
|
|
1223
|
+
function getLingoDotDevKeyFromRc() {
|
|
1224
|
+
return getKeyFromRc("auth.apiKey");
|
|
1225
|
+
}
|
|
1226
|
+
function getLingoDotDevKey() {
|
|
1227
|
+
return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
|
|
1228
|
+
}
|
|
1191
1229
|
function getGoogleKey() {
|
|
1192
1230
|
return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
|
|
1193
1231
|
}
|
|
@@ -1197,6 +1235,15 @@ function getGoogleKeyFromRc() {
|
|
|
1197
1235
|
function getGoogleKeyFromEnv() {
|
|
1198
1236
|
return getKeyFromEnv("GOOGLE_API_KEY");
|
|
1199
1237
|
}
|
|
1238
|
+
function getOpenRouterKey() {
|
|
1239
|
+
return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
|
|
1240
|
+
}
|
|
1241
|
+
function getOpenRouterKeyFromRc() {
|
|
1242
|
+
return getKeyFromRc("llm.openrouterApiKey");
|
|
1243
|
+
}
|
|
1244
|
+
function getOpenRouterKeyFromEnv() {
|
|
1245
|
+
return getKeyFromEnv("OPENROUTER_API_KEY");
|
|
1246
|
+
}
|
|
1200
1247
|
|
|
1201
1248
|
// src/lib/lcp/api/index.ts
|
|
1202
1249
|
import dedent2 from "dedent";
|
|
@@ -1222,6 +1269,22 @@ var providerDetails = {
|
|
|
1222
1269
|
apiKeyConfigKey: "llm.googleApiKey",
|
|
1223
1270
|
getKeyLink: "https://ai.google.dev/",
|
|
1224
1271
|
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
|
|
1272
|
+
},
|
|
1273
|
+
openrouter: {
|
|
1274
|
+
name: "OpenRouter",
|
|
1275
|
+
apiKeyEnvVar: "OPENROUTER_API_KEY",
|
|
1276
|
+
apiKeyConfigKey: "llm.openrouterApiKey",
|
|
1277
|
+
getKeyLink: "https://openrouter.ai",
|
|
1278
|
+
docsLink: "https://openrouter.ai/docs"
|
|
1279
|
+
},
|
|
1280
|
+
ollama: {
|
|
1281
|
+
name: "Ollama",
|
|
1282
|
+
apiKeyEnvVar: void 0,
|
|
1283
|
+
// Ollama doesn't require an API key
|
|
1284
|
+
apiKeyConfigKey: void 0,
|
|
1285
|
+
// Ollama doesn't require an API key
|
|
1286
|
+
getKeyLink: "https://ollama.com/download",
|
|
1287
|
+
docsLink: "https://github.com/ollama/ollama/tree/main/docs"
|
|
1225
1288
|
}
|
|
1226
1289
|
};
|
|
1227
1290
|
|
|
@@ -1308,59 +1371,118 @@ var LCPAPI = class {
|
|
|
1308
1371
|
};
|
|
1309
1372
|
return dictionary;
|
|
1310
1373
|
}
|
|
1311
|
-
static
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1374
|
+
static _createLingoDotDevEngine() {
|
|
1375
|
+
if (isRunningInCIOrDocker()) {
|
|
1376
|
+
const apiKeyFromEnv = getLingoDotDevKeyFromEnv();
|
|
1377
|
+
if (!apiKeyFromEnv) {
|
|
1378
|
+
this._failMissingLLMKeyCi("lingo.dev");
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const apiKey = getLingoDotDevKey();
|
|
1382
|
+
if (!apiKey) {
|
|
1318
1383
|
throw new Error(
|
|
1319
|
-
|
|
1384
|
+
"\u26A0\uFE0F Lingo.dev API key not found. Please set LINGODOTDEV_API_KEY environment variable or configure it user-wide."
|
|
1320
1385
|
);
|
|
1321
1386
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1387
|
+
console.log(`Creating Lingo.dev client`);
|
|
1388
|
+
return new LingoDotDevEngine({
|
|
1389
|
+
apiKey
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1393
|
+
if (models === "lingo.dev") {
|
|
1394
|
+
try {
|
|
1395
|
+
const lingoDotDevEngine = this._createLingoDotDevEngine();
|
|
1396
|
+
console.log(
|
|
1397
|
+
`\u2728 Using Lingo.dev Engine to localize from "${sourceLocale}" to "${targetLocale}"`
|
|
1398
|
+
);
|
|
1399
|
+
const result = await lingoDotDevEngine.localizeObject(
|
|
1400
|
+
sourceDictionary,
|
|
1330
1401
|
{
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1402
|
+
sourceLocale,
|
|
1403
|
+
targetLocale
|
|
1404
|
+
}
|
|
1405
|
+
);
|
|
1406
|
+
return result;
|
|
1407
|
+
} catch (error) {
|
|
1408
|
+
this._failLLMFailureLocal(
|
|
1409
|
+
"lingo.dev",
|
|
1410
|
+
targetLocale,
|
|
1411
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1412
|
+
);
|
|
1413
|
+
throw error;
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
const { provider, model } = getLocaleModel(
|
|
1417
|
+
models,
|
|
1418
|
+
sourceLocale,
|
|
1419
|
+
targetLocale
|
|
1420
|
+
);
|
|
1421
|
+
if (!provider || !model) {
|
|
1422
|
+
throw new Error(
|
|
1423
|
+
dedent2`
|
|
1424
|
+
🚫 Lingo.dev Localization Engine Not Configured!
|
|
1425
|
+
|
|
1426
|
+
The "models" parameter is missing or incomplete in your Lingo.dev configuration.
|
|
1427
|
+
|
|
1428
|
+
👉 To fix this, set the "models" parameter to either:
|
|
1429
|
+
• "lingo.dev" (for the default engine)
|
|
1430
|
+
• a map of locale-to-model, e.g. { "models": { "en:es": "openai:gpt-3.5-turbo" } }
|
|
1431
|
+
|
|
1432
|
+
Example:
|
|
1433
|
+
{
|
|
1434
|
+
// ...
|
|
1435
|
+
"models": "lingo.dev"
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
For more details, see: https://lingo.dev/compiler
|
|
1439
|
+
To get help, join our Discord: https://lingo.dev/go/discord
|
|
1440
|
+
`
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
try {
|
|
1444
|
+
const aiModel = this._createAiModel(provider, model, targetLocale);
|
|
1445
|
+
console.log(
|
|
1446
|
+
`\u2139\uFE0F Using raw LLM API ("${provider}":"${model}") to translate from "${sourceLocale}" to "${targetLocale}"`
|
|
1447
|
+
);
|
|
1448
|
+
const response = await generateText({
|
|
1449
|
+
model: aiModel,
|
|
1450
|
+
messages: [
|
|
1335
1451
|
{
|
|
1336
|
-
role: "
|
|
1337
|
-
content:
|
|
1452
|
+
role: "system",
|
|
1453
|
+
content: prompt_default({ sourceLocale, targetLocale })
|
|
1338
1454
|
},
|
|
1455
|
+
...shots_default.flatMap((shotsTuple) => [
|
|
1456
|
+
{
|
|
1457
|
+
role: "user",
|
|
1458
|
+
content: obj2xml(shotsTuple[0])
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
role: "assistant",
|
|
1462
|
+
content: obj2xml(shotsTuple[1])
|
|
1463
|
+
}
|
|
1464
|
+
]),
|
|
1339
1465
|
{
|
|
1340
|
-
role: "
|
|
1341
|
-
content: obj2xml(
|
|
1466
|
+
role: "user",
|
|
1467
|
+
content: obj2xml(sourceDictionary)
|
|
1342
1468
|
}
|
|
1343
|
-
]
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
targetLocale,
|
|
1361
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1362
|
-
);
|
|
1363
|
-
throw error;
|
|
1469
|
+
]
|
|
1470
|
+
});
|
|
1471
|
+
console.log("Response text received for", targetLocale);
|
|
1472
|
+
let responseText = response.text;
|
|
1473
|
+
responseText = responseText.substring(
|
|
1474
|
+
responseText.indexOf("<"),
|
|
1475
|
+
responseText.lastIndexOf(">") + 1
|
|
1476
|
+
);
|
|
1477
|
+
return xml2obj(responseText);
|
|
1478
|
+
} catch (error) {
|
|
1479
|
+
this._failLLMFailureLocal(
|
|
1480
|
+
provider,
|
|
1481
|
+
targetLocale,
|
|
1482
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1483
|
+
);
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1364
1486
|
}
|
|
1365
1487
|
}
|
|
1366
1488
|
/**
|
|
@@ -1374,7 +1496,7 @@ var LCPAPI = class {
|
|
|
1374
1496
|
*/
|
|
1375
1497
|
static _createAiModel(providerId, modelId, targetLocale) {
|
|
1376
1498
|
switch (providerId) {
|
|
1377
|
-
case "groq":
|
|
1499
|
+
case "groq": {
|
|
1378
1500
|
if (isRunningInCIOrDocker()) {
|
|
1379
1501
|
const groqFromEnv = getGroqKeyFromEnv();
|
|
1380
1502
|
if (!groqFromEnv) {
|
|
@@ -1391,7 +1513,8 @@ var LCPAPI = class {
|
|
|
1391
1513
|
`Creating Groq client for ${targetLocale} using model ${modelId}`
|
|
1392
1514
|
);
|
|
1393
1515
|
return createGroq({ apiKey: groqKey })(modelId);
|
|
1394
|
-
|
|
1516
|
+
}
|
|
1517
|
+
case "google": {
|
|
1395
1518
|
if (isRunningInCIOrDocker()) {
|
|
1396
1519
|
const googleFromEnv = getGoogleKeyFromEnv();
|
|
1397
1520
|
if (!googleFromEnv) {
|
|
@@ -1408,10 +1531,38 @@ var LCPAPI = class {
|
|
|
1408
1531
|
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
|
|
1409
1532
|
);
|
|
1410
1533
|
return createGoogleGenerativeAI({ apiKey: googleKey })(modelId);
|
|
1411
|
-
|
|
1534
|
+
}
|
|
1535
|
+
case "openrouter": {
|
|
1536
|
+
if (isRunningInCIOrDocker()) {
|
|
1537
|
+
const openRouterFromEnv = getOpenRouterKeyFromEnv();
|
|
1538
|
+
if (!openRouterFromEnv) {
|
|
1539
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
const openRouterKey = getOpenRouterKey();
|
|
1543
|
+
if (!openRouterKey) {
|
|
1544
|
+
throw new Error(
|
|
1545
|
+
"\u26A0\uFE0F OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide."
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
console.log(
|
|
1549
|
+
`Creating OpenRouter client for ${targetLocale} using model ${modelId}`
|
|
1550
|
+
);
|
|
1551
|
+
return createOpenRouter({
|
|
1552
|
+
apiKey: openRouterKey
|
|
1553
|
+
})(modelId);
|
|
1554
|
+
}
|
|
1555
|
+
case "ollama": {
|
|
1556
|
+
console.log(
|
|
1557
|
+
`Creating Ollama client for ${targetLocale} using model ${modelId} at default Ollama address`
|
|
1558
|
+
);
|
|
1559
|
+
return createOllama()(modelId);
|
|
1560
|
+
}
|
|
1561
|
+
default: {
|
|
1412
1562
|
throw new Error(
|
|
1413
1563
|
`\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
|
|
1414
1564
|
);
|
|
1565
|
+
}
|
|
1415
1566
|
}
|
|
1416
1567
|
}
|
|
1417
1568
|
/**
|
|
@@ -1500,7 +1651,7 @@ var LCPAPI = class {
|
|
|
1500
1651
|
This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
|
|
1501
1652
|
|
|
1502
1653
|
⭐️ Also:
|
|
1503
|
-
1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
|
|
1654
|
+
1. Did you set ${details.apiKeyEnvVar ? `${details.apiKeyEnvVar}` : "the provider API key"} environment variable correctly ${!details.apiKeyEnvVar ? "(if required)" : ""}?
|
|
1504
1655
|
2. Did you reach any limits of your ${details.name} account?
|
|
1505
1656
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1506
1657
|
|
|
@@ -1514,31 +1665,39 @@ var LCPAPI = class {
|
|
|
1514
1665
|
|
|
1515
1666
|
// src/lib/lcp/server.ts
|
|
1516
1667
|
var LCPServer = class {
|
|
1517
|
-
static
|
|
1668
|
+
static dictionariesCache = null;
|
|
1669
|
+
static inFlightPromise = null;
|
|
1518
1670
|
static async loadDictionaries(params) {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
setTimeout(resolve3, 500);
|
|
1522
|
-
});
|
|
1671
|
+
if (this.dictionariesCache) {
|
|
1672
|
+
return this.dictionariesCache;
|
|
1523
1673
|
}
|
|
1524
|
-
this.
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1674
|
+
if (this.inFlightPromise) {
|
|
1675
|
+
return this.inFlightPromise;
|
|
1676
|
+
}
|
|
1677
|
+
this.inFlightPromise = (async () => {
|
|
1678
|
+
try {
|
|
1679
|
+
const targetLocales = _7.uniq([
|
|
1680
|
+
...params.targetLocales,
|
|
1681
|
+
params.sourceLocale
|
|
1682
|
+
]);
|
|
1683
|
+
const dictionaries = await Promise.all(
|
|
1684
|
+
targetLocales.map(
|
|
1685
|
+
(targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
|
|
1686
|
+
)
|
|
1687
|
+
);
|
|
1688
|
+
const result = _7.fromPairs(
|
|
1689
|
+
targetLocales.map((targetLocale, index) => [
|
|
1690
|
+
targetLocale,
|
|
1691
|
+
dictionaries[index]
|
|
1692
|
+
])
|
|
1693
|
+
);
|
|
1694
|
+
this.dictionariesCache = result;
|
|
1695
|
+
return result;
|
|
1696
|
+
} finally {
|
|
1697
|
+
this.inFlightPromise = null;
|
|
1698
|
+
}
|
|
1699
|
+
})();
|
|
1700
|
+
return this.inFlightPromise;
|
|
1542
1701
|
}
|
|
1543
1702
|
static async loadDictionaryForLocale(params) {
|
|
1544
1703
|
const sourceDictionary = this._extractSourceDictionary(
|
|
@@ -1710,7 +1869,7 @@ var LCPServer = class {
|
|
|
1710
1869
|
fileName,
|
|
1711
1870
|
{
|
|
1712
1871
|
...targetFile,
|
|
1713
|
-
entries: _7.merge(targetFile?.entries || {}, entries)
|
|
1872
|
+
entries: _7.merge({}, targetFile?.entries || {}, entries)
|
|
1714
1873
|
}
|
|
1715
1874
|
];
|
|
1716
1875
|
}).fromPairs().value();
|
|
@@ -2499,6 +2658,10 @@ var keyCheckers = {
|
|
|
2499
2658
|
google: {
|
|
2500
2659
|
checkEnv: getGoogleKeyFromEnv,
|
|
2501
2660
|
checkRc: getGoogleKeyFromRc
|
|
2661
|
+
},
|
|
2662
|
+
"lingo.dev": {
|
|
2663
|
+
checkEnv: getLingoDotDevKeyFromEnv,
|
|
2664
|
+
checkRc: getLingoDotDevKeyFromRc
|
|
2502
2665
|
}
|
|
2503
2666
|
};
|
|
2504
2667
|
var unplugin = createUnplugin(
|
|
@@ -2506,26 +2669,31 @@ var unplugin = createUnplugin(
|
|
|
2506
2669
|
console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
|
|
2507
2670
|
const params = _11.defaults(_params, defaultParams);
|
|
2508
2671
|
if (!isRunningInCIOrDocker()) {
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2672
|
+
if (params.models === "lingo.dev") {
|
|
2673
|
+
validateLLMKeyDetails(["lingo.dev"]);
|
|
2674
|
+
} else {
|
|
2675
|
+
const configuredProviders = getConfiguredProviders(params.models);
|
|
2676
|
+
validateLLMKeyDetails(configuredProviders);
|
|
2677
|
+
const invalidLocales = getInvalidLocales(
|
|
2678
|
+
params.models,
|
|
2679
|
+
params.sourceLocale,
|
|
2680
|
+
params.targetLocales
|
|
2681
|
+
);
|
|
2682
|
+
if (invalidLocales.length > 0) {
|
|
2683
|
+
console.log(dedent3`
|
|
2684
|
+
\n
|
|
2685
|
+
⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
|
|
2686
|
+
|
|
2687
|
+
⭐️ Next steps:
|
|
2688
|
+
1. Refer to documentation for help: https://docs.lingo.dev/
|
|
2689
|
+
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2690
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2691
|
+
|
|
2692
|
+
✨
|
|
2693
|
+
`);
|
|
2694
|
+
process.exit(1);
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2529
2697
|
}
|
|
2530
2698
|
LCPCache.ensureDictionaryFile({
|
|
2531
2699
|
sourceRoot: params.sourceRoot,
|
|
@@ -2553,6 +2721,7 @@ var unplugin = createUnplugin(
|
|
|
2553
2721
|
lingoDir: params.lingoDir
|
|
2554
2722
|
});
|
|
2555
2723
|
const dictionary = dictionaries[moduleInfo.params.locale];
|
|
2724
|
+
console.log(JSON.stringify(dictionary, null, 2));
|
|
2556
2725
|
return {
|
|
2557
2726
|
code: `export default ${JSON.stringify(dictionary, null, 2)}`
|
|
2558
2727
|
};
|
|
@@ -2621,10 +2790,12 @@ var src_default = {
|
|
|
2621
2790
|
return config2;
|
|
2622
2791
|
}
|
|
2623
2792
|
};
|
|
2624
|
-
function
|
|
2625
|
-
|
|
2793
|
+
function getConfiguredProviders(models) {
|
|
2794
|
+
return _11.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
|
|
2626
2795
|
(providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
|
|
2627
2796
|
).value();
|
|
2797
|
+
}
|
|
2798
|
+
function validateLLMKeyDetails(configuredProviders) {
|
|
2628
2799
|
if (configuredProviders.length === 0) {
|
|
2629
2800
|
return;
|
|
2630
2801
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingo.dev/_compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Lingo.dev Compiler",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@babel/parser": "^7.26.7",
|
|
36
36
|
"@babel/traverse": "^7.27.4",
|
|
37
37
|
"@babel/types": "^7.26.7",
|
|
38
|
+
"@openrouter/ai-sdk-provider": "^0.7.1",
|
|
38
39
|
"ai": "^4.2.10",
|
|
39
40
|
"dedent": "^1.6.0",
|
|
40
41
|
"dotenv": "^16.4.5",
|
|
@@ -42,10 +43,12 @@
|
|
|
42
43
|
"ini": "^5.0.0",
|
|
43
44
|
"lodash": "^4.17.21",
|
|
44
45
|
"object-hash": "^3.0.0",
|
|
46
|
+
"ollama-ai-provider": "^1.2.0",
|
|
45
47
|
"prettier": "^3.4.2",
|
|
46
48
|
"unplugin": "^2.1.2",
|
|
47
49
|
"vitest": "^2.1.4",
|
|
48
|
-
"zod": "^3.24.1"
|
|
50
|
+
"zod": "^3.24.1",
|
|
51
|
+
"@lingo.dev/_sdk": "0.9.1"
|
|
49
52
|
},
|
|
50
53
|
"scripts": {
|
|
51
54
|
"dev": "tsup --watch",
|