@lingo.dev/_compiler 0.1.12 → 0.2.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/build/index.cjs +289 -123
- package/build/index.mjs +289 -123
- package/package.json +2 -1
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.2.0",
|
|
8
8
|
description: "Lingo.dev Compiler",
|
|
9
9
|
private: false,
|
|
10
10
|
publishConfig: {
|
|
@@ -40,6 +40,7 @@ var package_default = {
|
|
|
40
40
|
typescript: "^5.4.5"
|
|
41
41
|
},
|
|
42
42
|
dependencies: {
|
|
43
|
+
"@ai-sdk/google": "^1.2.19",
|
|
43
44
|
"@ai-sdk/groq": "^1.2.3",
|
|
44
45
|
"@babel/generator": "^7.26.5",
|
|
45
46
|
"@babel/parser": "^7.26.7",
|
|
@@ -449,6 +450,9 @@ function getJsxScopes(node) {
|
|
|
449
450
|
const result = [];
|
|
450
451
|
_traverse2.default.call(void 0, node, {
|
|
451
452
|
JSXElement(path6) {
|
|
453
|
+
if (getJsxElementName(path6) === "LingoProvider") {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
452
456
|
const hasNonEmptyTextSiblings = path6.getAllPrevSiblings().concat(path6.getAllNextSiblings()).some(
|
|
453
457
|
(sibling) => t7.isJSXText(sibling.node) && _optionalChain([sibling, 'access', _16 => _16.node, 'access', _17 => _17.value, 'optionalAccess', _18 => _18.trim, 'call', _19 => _19()]) !== ""
|
|
454
458
|
);
|
|
@@ -916,6 +920,7 @@ var LCPCache = class {
|
|
|
916
920
|
|
|
917
921
|
// src/lib/lcp/api/index.ts
|
|
918
922
|
var _groq = require('@ai-sdk/groq');
|
|
923
|
+
var _google = require('@ai-sdk/google');
|
|
919
924
|
var _ai = require('ai');
|
|
920
925
|
|
|
921
926
|
|
|
@@ -1147,21 +1152,36 @@ function getRc() {
|
|
|
1147
1152
|
return data;
|
|
1148
1153
|
}
|
|
1149
1154
|
|
|
1150
|
-
// src/utils/
|
|
1155
|
+
// src/utils/llm-api-key.ts
|
|
1151
1156
|
|
|
1152
1157
|
var _dotenv = require('dotenv'); var dotenv = _interopRequireWildcard(_dotenv);
|
|
1158
|
+
function getKeyFromEnv(envVarName) {
|
|
1159
|
+
const ephemeralEnv = {};
|
|
1160
|
+
dotenv.config({ processEnv: ephemeralEnv });
|
|
1161
|
+
return ephemeralEnv[envVarName];
|
|
1162
|
+
}
|
|
1163
|
+
function getKeyFromRc(rcPath) {
|
|
1164
|
+
const rc = getRc();
|
|
1165
|
+
const result = _lodash2.default.get(rc, rcPath);
|
|
1166
|
+
return typeof result === "string" ? result : void 0;
|
|
1167
|
+
}
|
|
1153
1168
|
function getGroqKey() {
|
|
1154
1169
|
return getGroqKeyFromEnv() || getGroqKeyFromRc();
|
|
1155
1170
|
}
|
|
1156
1171
|
function getGroqKeyFromRc() {
|
|
1157
|
-
|
|
1158
|
-
const result = _lodash2.default.get(rc, "llm.groqApiKey");
|
|
1159
|
-
return result;
|
|
1172
|
+
return getKeyFromRc("llm.groqApiKey");
|
|
1160
1173
|
}
|
|
1161
1174
|
function getGroqKeyFromEnv() {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1175
|
+
return getKeyFromEnv("GROQ_API_KEY");
|
|
1176
|
+
}
|
|
1177
|
+
function getGoogleKey() {
|
|
1178
|
+
return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
|
|
1179
|
+
}
|
|
1180
|
+
function getGoogleKeyFromRc() {
|
|
1181
|
+
return getKeyFromRc("llm.googleApiKey");
|
|
1182
|
+
}
|
|
1183
|
+
function getGoogleKeyFromEnv() {
|
|
1184
|
+
return getKeyFromEnv("GOOGLE_API_KEY");
|
|
1165
1185
|
}
|
|
1166
1186
|
|
|
1167
1187
|
// src/lib/lcp/api/index.ts
|
|
@@ -1173,6 +1193,24 @@ function isRunningInCIOrDocker() {
|
|
|
1173
1193
|
return Boolean(process.env.CI) || fs.default.existsSync("/.dockerenv");
|
|
1174
1194
|
}
|
|
1175
1195
|
|
|
1196
|
+
// src/lib/lcp/api/provider-details.ts
|
|
1197
|
+
var providerDetails = {
|
|
1198
|
+
groq: {
|
|
1199
|
+
name: "Groq",
|
|
1200
|
+
apiKeyEnvVar: "GROQ_API_KEY",
|
|
1201
|
+
apiKeyConfigKey: "llm.groqApiKey",
|
|
1202
|
+
getKeyLink: "https://groq.com",
|
|
1203
|
+
docsLink: "https://console.groq.com/docs/errors"
|
|
1204
|
+
},
|
|
1205
|
+
google: {
|
|
1206
|
+
name: "Google",
|
|
1207
|
+
apiKeyEnvVar: "GOOGLE_API_KEY",
|
|
1208
|
+
apiKeyConfigKey: "llm.googleApiKey",
|
|
1209
|
+
getKeyLink: "https://ai.google.dev/",
|
|
1210
|
+
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1176
1214
|
// src/lib/lcp/api/index.ts
|
|
1177
1215
|
var LCPAPI = class {
|
|
1178
1216
|
static async translate(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
@@ -1257,114 +1295,207 @@ var LCPAPI = class {
|
|
|
1257
1295
|
return dictionary;
|
|
1258
1296
|
}
|
|
1259
1297
|
static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1260
|
-
try {
|
|
1261
|
-
return await this._translateChunkGroq(
|
|
1262
|
-
models,
|
|
1263
|
-
sourceDictionary,
|
|
1264
|
-
sourceLocale,
|
|
1265
|
-
targetLocale
|
|
1266
|
-
);
|
|
1267
|
-
} catch (e) {
|
|
1268
|
-
console.error(`\u26A0\uFE0F Translation for ${targetLocale} failed:`, e);
|
|
1269
|
-
return {
|
|
1270
|
-
version: 0.1,
|
|
1271
|
-
locale: targetLocale,
|
|
1272
|
-
files: {}
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
if (isRunningInCIOrDocker()) {
|
|
1276
|
-
const groqFromEnv = getGroqKeyFromEnv();
|
|
1277
|
-
if (!groqFromEnv) {
|
|
1278
|
-
this._failMissingGroqKeyCi();
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
throw new Error(
|
|
1282
|
-
"\u26A0\uFE0F No API key found. Please set GROQ_API_KEY environment variable. If you dont have one go to https://groq.com/"
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
static async _translateChunkGroq(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1286
|
-
const groq = _groq.createGroq.call(void 0, { apiKey: getGroqKey() });
|
|
1287
|
-
console.log(`Created Groq client for ${targetLocale}`);
|
|
1288
1298
|
const { provider, model } = getLocaleModel(
|
|
1289
1299
|
models,
|
|
1290
1300
|
sourceLocale,
|
|
1291
1301
|
targetLocale
|
|
1292
1302
|
);
|
|
1293
|
-
if (!model) {
|
|
1303
|
+
if (!provider || !model) {
|
|
1294
1304
|
throw new Error(
|
|
1295
|
-
`\u26A0\uFE0F Locale ${targetLocale} is not configured. Add model for this locale to your config.`
|
|
1305
|
+
`\u26A0\uFE0F Locale "${targetLocale}" is not configured. Add provider and model for this locale to your config, e.g., "groq:llama3-8b-8192".`
|
|
1296
1306
|
);
|
|
1297
1307
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1308
|
+
try {
|
|
1309
|
+
const aiModel = this._createAiModel(provider, model, targetLocale);
|
|
1310
|
+
console.log(
|
|
1311
|
+
`\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
|
|
1301
1312
|
);
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
);
|
|
1306
|
-
const groqModel = groq(model);
|
|
1307
|
-
console.log(`Created model ${model}`);
|
|
1308
|
-
const response = await _ai.generateText.call(void 0, {
|
|
1309
|
-
model: groqModel,
|
|
1310
|
-
messages: [
|
|
1311
|
-
{
|
|
1312
|
-
role: "system",
|
|
1313
|
-
content: prompt_default({ sourceLocale, targetLocale })
|
|
1314
|
-
},
|
|
1315
|
-
...shots_default.flatMap((shotsTuple) => [
|
|
1313
|
+
const response = await _ai.generateText.call(void 0, {
|
|
1314
|
+
model: aiModel,
|
|
1315
|
+
messages: [
|
|
1316
1316
|
{
|
|
1317
|
-
role: "
|
|
1318
|
-
content:
|
|
1317
|
+
role: "system",
|
|
1318
|
+
content: prompt_default({ sourceLocale, targetLocale })
|
|
1319
1319
|
},
|
|
1320
|
+
...shots_default.flatMap((shotsTuple) => [
|
|
1321
|
+
{
|
|
1322
|
+
role: "user",
|
|
1323
|
+
content: obj2xml(shotsTuple[0])
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
role: "assistant",
|
|
1327
|
+
content: obj2xml(shotsTuple[1])
|
|
1328
|
+
}
|
|
1329
|
+
]),
|
|
1320
1330
|
{
|
|
1321
|
-
role: "
|
|
1322
|
-
content: obj2xml(
|
|
1331
|
+
role: "user",
|
|
1332
|
+
content: obj2xml(sourceDictionary)
|
|
1333
|
+
}
|
|
1334
|
+
]
|
|
1335
|
+
});
|
|
1336
|
+
console.log("Response text received for", targetLocale);
|
|
1337
|
+
let responseText = response.text;
|
|
1338
|
+
responseText = responseText.substring(
|
|
1339
|
+
responseText.indexOf("<"),
|
|
1340
|
+
responseText.lastIndexOf(">") + 1
|
|
1341
|
+
);
|
|
1342
|
+
return xml2obj(responseText);
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
this._failLLMFailureLocal(
|
|
1345
|
+
provider,
|
|
1346
|
+
targetLocale,
|
|
1347
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1348
|
+
);
|
|
1349
|
+
throw error;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Instantiates an AI model based on provider and model ID.
|
|
1354
|
+
* Includes CI/CD API key checks.
|
|
1355
|
+
* @param providerId The ID of the AI provider (e.g., "groq", "google").
|
|
1356
|
+
* @param modelId The ID of the specific model (e.g., "llama3-8b-8192", "gemini-2.0-flash").
|
|
1357
|
+
* @param targetLocale The target locale being translated to (for logging/error messages).
|
|
1358
|
+
* @returns An instantiated AI LanguageModel.
|
|
1359
|
+
* @throws Error if the provider is not supported or API key is missing in CI/CD.
|
|
1360
|
+
*/
|
|
1361
|
+
static _createAiModel(providerId, modelId, targetLocale) {
|
|
1362
|
+
switch (providerId) {
|
|
1363
|
+
case "groq":
|
|
1364
|
+
if (isRunningInCIOrDocker()) {
|
|
1365
|
+
const groqFromEnv = getGroqKeyFromEnv();
|
|
1366
|
+
if (!groqFromEnv) {
|
|
1367
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1323
1368
|
}
|
|
1324
|
-
]),
|
|
1325
|
-
{
|
|
1326
|
-
role: "user",
|
|
1327
|
-
content: obj2xml(sourceDictionary)
|
|
1328
1369
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1370
|
+
const groqKey = getGroqKey();
|
|
1371
|
+
if (!groqKey) {
|
|
1372
|
+
throw new Error(
|
|
1373
|
+
"\u26A0\uFE0F GROQ API key not found. Please set GROQ_API_KEY environment variable or configure it user-wide."
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
console.log(
|
|
1377
|
+
`Creating Groq client for ${targetLocale} using model ${modelId}`
|
|
1378
|
+
);
|
|
1379
|
+
return _groq.createGroq.call(void 0, { apiKey: groqKey })(modelId);
|
|
1380
|
+
case "google":
|
|
1381
|
+
if (isRunningInCIOrDocker()) {
|
|
1382
|
+
const googleFromEnv = getGoogleKeyFromEnv();
|
|
1383
|
+
if (!googleFromEnv) {
|
|
1384
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
const googleKey = getGoogleKey();
|
|
1388
|
+
if (!googleKey) {
|
|
1389
|
+
throw new Error(
|
|
1390
|
+
"\u26A0\uFE0F Google API key not found. Please set GOOGLE_API_KEY environment variable or configure it user-wide."
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
console.log(
|
|
1394
|
+
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
|
|
1395
|
+
);
|
|
1396
|
+
return _google.createGoogleGenerativeAI.call(void 0, { apiKey: googleKey })(modelId);
|
|
1397
|
+
default:
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1338
1402
|
}
|
|
1339
1403
|
/**
|
|
1340
1404
|
* Show an actionable error message and exit the process when the compiler
|
|
1341
|
-
* is running in CI/CD without a
|
|
1405
|
+
* is running in CI/CD without a required LLM API key.
|
|
1342
1406
|
* The message explains why this situation is unusual and how to fix it.
|
|
1407
|
+
* @param providerId The ID of the LLM provider whose key is missing.
|
|
1343
1408
|
*/
|
|
1344
|
-
static
|
|
1409
|
+
static _failMissingLLMKeyCi(providerId) {
|
|
1410
|
+
let details = providerDetails[providerId];
|
|
1411
|
+
if (!details) {
|
|
1412
|
+
console.error(
|
|
1413
|
+
`Internal Error: Missing details for provider "${providerId}" when reporting missing key in CI/CD. You might be using an unsupported provider.`
|
|
1414
|
+
);
|
|
1415
|
+
process.exit(1);
|
|
1416
|
+
}
|
|
1345
1417
|
console.log(
|
|
1346
1418
|
_dedent2.default`
|
|
1347
1419
|
\n
|
|
1348
1420
|
💡 You're using Lingo.dev Localization Compiler, and it detected unlocalized components in your app.
|
|
1349
1421
|
|
|
1350
|
-
The compiler needs a
|
|
1422
|
+
The compiler needs a ${details.name} API key to translate missing strings, but ${details.apiKeyEnvVar} is not set in the environment.
|
|
1351
1423
|
|
|
1352
1424
|
This is unexpected: typically you run a full build locally, commit the generated translation files, and push them to CI/CD.
|
|
1353
1425
|
|
|
1354
1426
|
However, If you want CI/CD to translate the new strings, provide the key with:
|
|
1355
|
-
• Session-wide: export
|
|
1356
|
-
• Project-wide / CI: add
|
|
1427
|
+
• Session-wide: export ${details.apiKeyEnvVar}=<your-api-key>
|
|
1428
|
+
• Project-wide / CI: add ${details.apiKeyEnvVar}=<your-api-key> to your pipeline environment variables
|
|
1357
1429
|
|
|
1358
1430
|
⭐️ Also:
|
|
1359
|
-
1. If you don't yet have a
|
|
1360
|
-
2. If you want to use a different LLM,
|
|
1361
|
-
3. If you
|
|
1431
|
+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
1432
|
+
2. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://docs.lingo.dev/
|
|
1433
|
+
3. If the model you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
1362
1434
|
|
|
1363
1435
|
✨
|
|
1364
1436
|
`
|
|
1365
1437
|
);
|
|
1366
1438
|
process.exit(1);
|
|
1367
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Show an actionable error message and exit the process when an LLM API call
|
|
1442
|
+
* fails during local compilation.
|
|
1443
|
+
* @param providerId The ID of the LLM provider that failed.
|
|
1444
|
+
* @param targetLocale The target locale being translated to.
|
|
1445
|
+
* @param errorMessage The error message received from the API.
|
|
1446
|
+
*/
|
|
1447
|
+
static _failLLMFailureLocal(providerId, targetLocale, errorMessage) {
|
|
1448
|
+
const details = providerDetails[providerId];
|
|
1449
|
+
if (!details) {
|
|
1450
|
+
console.error(
|
|
1451
|
+
`Internal Error: Missing details for provider "${providerId}" when reporting local failure.`
|
|
1452
|
+
);
|
|
1453
|
+
console.error(`Original Error: ${errorMessage}`);
|
|
1454
|
+
process.exit(1);
|
|
1455
|
+
}
|
|
1456
|
+
const isInvalidApiKey = errorMessage.match("Invalid API Key");
|
|
1457
|
+
if (isInvalidApiKey) {
|
|
1458
|
+
console.log(_dedent2.default`
|
|
1459
|
+
\n
|
|
1460
|
+
⚠️ Lingo.dev Compiler requires a valid ${details.name} API key to translate your application.
|
|
1461
|
+
|
|
1462
|
+
It looks like you set ${details.name} API key but it is not valid. Please check your API key and try again.
|
|
1463
|
+
|
|
1464
|
+
Error details from ${details.name} API: ${errorMessage}
|
|
1465
|
+
|
|
1466
|
+
👉 You can set the API key in one of the following ways:
|
|
1467
|
+
1. User-wide: Run npx lingo.dev@latest config set ${details.apiKeyConfigKey} <your-api-key>
|
|
1468
|
+
2. Project-wide: Add ${details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
|
|
1469
|
+
3 Session-wide: Run export ${details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
|
|
1470
|
+
|
|
1471
|
+
⭐️ Also:
|
|
1472
|
+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
1473
|
+
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
1474
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1475
|
+
|
|
1476
|
+
✨
|
|
1477
|
+
`);
|
|
1478
|
+
} else {
|
|
1479
|
+
console.log(
|
|
1480
|
+
_dedent2.default`
|
|
1481
|
+
\n
|
|
1482
|
+
⚠️ Lingo.dev Compiler tried to translate your application to "${targetLocale}" locale via ${details.name} but it failed.
|
|
1483
|
+
|
|
1484
|
+
Error details from ${details.name} API: ${errorMessage}
|
|
1485
|
+
|
|
1486
|
+
This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
|
|
1487
|
+
|
|
1488
|
+
⭐️ Also:
|
|
1489
|
+
1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
|
|
1490
|
+
2. Did you reach any limits of your ${details.name} account?
|
|
1491
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1492
|
+
|
|
1493
|
+
✨
|
|
1494
|
+
`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
process.exit(1);
|
|
1498
|
+
}
|
|
1368
1499
|
};
|
|
1369
1500
|
|
|
1370
1501
|
// src/lib/lcp/server.ts
|
|
@@ -2339,13 +2470,23 @@ var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
|
|
|
2339
2470
|
});
|
|
2340
2471
|
|
|
2341
2472
|
// src/index.ts
|
|
2473
|
+
var keyCheckers = {
|
|
2474
|
+
groq: {
|
|
2475
|
+
checkEnv: getGroqKeyFromEnv,
|
|
2476
|
+
checkRc: getGroqKeyFromRc
|
|
2477
|
+
},
|
|
2478
|
+
google: {
|
|
2479
|
+
checkEnv: getGoogleKeyFromEnv,
|
|
2480
|
+
checkRc: getGoogleKeyFromRc
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2342
2483
|
var unplugin = _unplugin.createUnplugin.call(void 0,
|
|
2343
2484
|
(_params, _meta) => {
|
|
2344
2485
|
console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
|
|
2486
|
+
const params = _lodash2.default.defaults(_params, defaultParams);
|
|
2345
2487
|
if (!isRunningInCIOrDocker()) {
|
|
2346
|
-
|
|
2488
|
+
validateLLMKeyDetails(params.models);
|
|
2347
2489
|
}
|
|
2348
|
-
const params = _lodash2.default.defaults(_params, defaultParams);
|
|
2349
2490
|
const invalidLocales = getInvalidLocales(
|
|
2350
2491
|
params.models,
|
|
2351
2492
|
params.sourceLocale,
|
|
@@ -2360,7 +2501,7 @@ var unplugin = _unplugin.createUnplugin.call(void 0,
|
|
|
2360
2501
|
1. Refer to documentation for help: https://docs.lingo.dev/
|
|
2361
2502
|
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2362
2503
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2363
|
-
|
|
2504
|
+
|
|
2364
2505
|
✨
|
|
2365
2506
|
`);
|
|
2366
2507
|
process.exit(1);
|
|
@@ -2459,56 +2600,81 @@ var src_default = {
|
|
|
2459
2600
|
return config2;
|
|
2460
2601
|
}
|
|
2461
2602
|
};
|
|
2462
|
-
function
|
|
2463
|
-
const
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2603
|
+
function validateLLMKeyDetails(models) {
|
|
2604
|
+
const configuredProviders = _lodash2.default.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
|
|
2605
|
+
(providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
|
|
2606
|
+
).value();
|
|
2607
|
+
if (configuredProviders.length === 0) {
|
|
2608
|
+
return;
|
|
2609
|
+
}
|
|
2610
|
+
const keyStatuses = {};
|
|
2611
|
+
const missingProviders = [];
|
|
2612
|
+
const foundProviders = [];
|
|
2613
|
+
for (const providerId of configuredProviders) {
|
|
2614
|
+
const details = providerDetails[providerId];
|
|
2615
|
+
const checkers = keyCheckers[providerId];
|
|
2616
|
+
if (!details || !checkers) continue;
|
|
2617
|
+
const foundInEnv = checkers.checkEnv() !== void 0;
|
|
2618
|
+
const foundInRc = checkers.checkRc() !== void 0;
|
|
2619
|
+
keyStatuses[providerId] = { foundInEnv, foundInRc, details };
|
|
2620
|
+
if (!foundInEnv && !foundInRc) {
|
|
2621
|
+
missingProviders.push(providerId);
|
|
2622
|
+
} else {
|
|
2623
|
+
foundProviders.push(providerId);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
if (missingProviders.length > 0) {
|
|
2468
2627
|
console.log(_dedent2.default`
|
|
2469
2628
|
\n
|
|
2470
|
-
💡
|
|
2629
|
+
💡 Lingo.dev Localization Compiler is configured to use the following LLM provider(s): ${configuredProviders.join(", ")}.
|
|
2471
2630
|
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2631
|
+
The compiler requires API keys for these providers to work, but the following keys are missing:
|
|
2632
|
+
`);
|
|
2633
|
+
for (const providerId of missingProviders) {
|
|
2634
|
+
const status = keyStatuses[providerId];
|
|
2635
|
+
if (!status) continue;
|
|
2636
|
+
console.log(_dedent2.default`
|
|
2637
|
+
⚠️ ${status.details.name} API key is missing. Set ${status.details.apiKeyEnvVar} environment variable.
|
|
2476
2638
|
|
|
2639
|
+
👉 You can set the API key in one of the following ways:
|
|
2640
|
+
1. User-wide: Run npx lingo.dev@latest config set ${status.details.apiKeyConfigKey || "<config-key-not-available>"} <your-api-key>
|
|
2641
|
+
2. Project-wide: Add ${status.details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
|
|
2642
|
+
3. Session-wide: Run export ${status.details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
|
|
2643
|
+
|
|
2644
|
+
⭐️ If you don't yet have a ${status.details.name} API key, get one for free at ${status.details.getKeyLink}
|
|
2645
|
+
`);
|
|
2646
|
+
}
|
|
2647
|
+
console.log(_dedent2.default`
|
|
2648
|
+
\n
|
|
2477
2649
|
⭐️ Also:
|
|
2478
|
-
1. If you
|
|
2479
|
-
2. If you want to use
|
|
2650
|
+
1. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://docs.lingo.dev/
|
|
2651
|
+
2. If the model/provider you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2480
2652
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2481
2653
|
|
|
2482
2654
|
✨
|
|
2483
2655
|
`);
|
|
2484
2656
|
process.exit(1);
|
|
2485
|
-
} else if (
|
|
2486
|
-
console.log(
|
|
2487
|
-
|
|
2488
|
-
🔑
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
);
|
|
2506
|
-
} else if (!groq.fromEnv && groq.fromRc) {
|
|
2507
|
-
console.log(
|
|
2508
|
-
_dedent2.default`
|
|
2509
|
-
🔑 GROQ API key loaded from your user-wide configuration.
|
|
2510
|
-
`
|
|
2511
|
-
);
|
|
2657
|
+
} else if (foundProviders.length > 0) {
|
|
2658
|
+
console.log(_dedent2.default`
|
|
2659
|
+
\n
|
|
2660
|
+
🔑 LLM API keys detected for configured providers: ${foundProviders.join(", ")}.
|
|
2661
|
+
`);
|
|
2662
|
+
for (const providerId of foundProviders) {
|
|
2663
|
+
const status = keyStatuses[providerId];
|
|
2664
|
+
if (!status) continue;
|
|
2665
|
+
let sourceMessage = "";
|
|
2666
|
+
if (status.foundInEnv && status.foundInRc) {
|
|
2667
|
+
sourceMessage = `from both environment variables (${status.details.apiKeyEnvVar}) and your user-wide configuration. The key from the environment will be used because it has higher priority.`;
|
|
2668
|
+
} else if (status.foundInEnv) {
|
|
2669
|
+
sourceMessage = `from environment variables (${status.details.apiKeyEnvVar}).`;
|
|
2670
|
+
} else if (status.foundInRc) {
|
|
2671
|
+
sourceMessage = `from your user-wide configuration${status.details.apiKeyConfigKey ? ` (${status.details.apiKeyConfigKey})` : ""}.`;
|
|
2672
|
+
}
|
|
2673
|
+
console.log(_dedent2.default`
|
|
2674
|
+
• ${status.details.name} API key loaded ${sourceMessage}
|
|
2675
|
+
`);
|
|
2676
|
+
}
|
|
2677
|
+
console.log("\u2728");
|
|
2512
2678
|
}
|
|
2513
2679
|
}
|
|
2514
2680
|
|
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.2.0",
|
|
8
8
|
description: "Lingo.dev Compiler",
|
|
9
9
|
private: false,
|
|
10
10
|
publishConfig: {
|
|
@@ -40,6 +40,7 @@ var package_default = {
|
|
|
40
40
|
typescript: "^5.4.5"
|
|
41
41
|
},
|
|
42
42
|
dependencies: {
|
|
43
|
+
"@ai-sdk/google": "^1.2.19",
|
|
43
44
|
"@ai-sdk/groq": "^1.2.3",
|
|
44
45
|
"@babel/generator": "^7.26.5",
|
|
45
46
|
"@babel/parser": "^7.26.7",
|
|
@@ -449,6 +450,9 @@ function getJsxScopes(node) {
|
|
|
449
450
|
const result = [];
|
|
450
451
|
traverse4(node, {
|
|
451
452
|
JSXElement(path6) {
|
|
453
|
+
if (getJsxElementName(path6) === "LingoProvider") {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
452
456
|
const hasNonEmptyTextSiblings = path6.getAllPrevSiblings().concat(path6.getAllNextSiblings()).some(
|
|
453
457
|
(sibling) => t7.isJSXText(sibling.node) && sibling.node.value?.trim() !== ""
|
|
454
458
|
);
|
|
@@ -916,6 +920,7 @@ var LCPCache = class {
|
|
|
916
920
|
|
|
917
921
|
// src/lib/lcp/api/index.ts
|
|
918
922
|
import { createGroq } from "@ai-sdk/groq";
|
|
923
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
919
924
|
import { generateText } from "ai";
|
|
920
925
|
import _6 from "lodash";
|
|
921
926
|
|
|
@@ -1147,21 +1152,36 @@ function getRc() {
|
|
|
1147
1152
|
return data;
|
|
1148
1153
|
}
|
|
1149
1154
|
|
|
1150
|
-
// src/utils/
|
|
1155
|
+
// src/utils/llm-api-key.ts
|
|
1151
1156
|
import _5 from "lodash";
|
|
1152
1157
|
import * as dotenv from "dotenv";
|
|
1158
|
+
function getKeyFromEnv(envVarName) {
|
|
1159
|
+
const ephemeralEnv = {};
|
|
1160
|
+
dotenv.config({ processEnv: ephemeralEnv });
|
|
1161
|
+
return ephemeralEnv[envVarName];
|
|
1162
|
+
}
|
|
1163
|
+
function getKeyFromRc(rcPath) {
|
|
1164
|
+
const rc = getRc();
|
|
1165
|
+
const result = _5.get(rc, rcPath);
|
|
1166
|
+
return typeof result === "string" ? result : void 0;
|
|
1167
|
+
}
|
|
1153
1168
|
function getGroqKey() {
|
|
1154
1169
|
return getGroqKeyFromEnv() || getGroqKeyFromRc();
|
|
1155
1170
|
}
|
|
1156
1171
|
function getGroqKeyFromRc() {
|
|
1157
|
-
|
|
1158
|
-
const result = _5.get(rc, "llm.groqApiKey");
|
|
1159
|
-
return result;
|
|
1172
|
+
return getKeyFromRc("llm.groqApiKey");
|
|
1160
1173
|
}
|
|
1161
1174
|
function getGroqKeyFromEnv() {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1175
|
+
return getKeyFromEnv("GROQ_API_KEY");
|
|
1176
|
+
}
|
|
1177
|
+
function getGoogleKey() {
|
|
1178
|
+
return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
|
|
1179
|
+
}
|
|
1180
|
+
function getGoogleKeyFromRc() {
|
|
1181
|
+
return getKeyFromRc("llm.googleApiKey");
|
|
1182
|
+
}
|
|
1183
|
+
function getGoogleKeyFromEnv() {
|
|
1184
|
+
return getKeyFromEnv("GOOGLE_API_KEY");
|
|
1165
1185
|
}
|
|
1166
1186
|
|
|
1167
1187
|
// src/lib/lcp/api/index.ts
|
|
@@ -1173,6 +1193,24 @@ function isRunningInCIOrDocker() {
|
|
|
1173
1193
|
return Boolean(process.env.CI) || fs4.existsSync("/.dockerenv");
|
|
1174
1194
|
}
|
|
1175
1195
|
|
|
1196
|
+
// src/lib/lcp/api/provider-details.ts
|
|
1197
|
+
var providerDetails = {
|
|
1198
|
+
groq: {
|
|
1199
|
+
name: "Groq",
|
|
1200
|
+
apiKeyEnvVar: "GROQ_API_KEY",
|
|
1201
|
+
apiKeyConfigKey: "llm.groqApiKey",
|
|
1202
|
+
getKeyLink: "https://groq.com",
|
|
1203
|
+
docsLink: "https://console.groq.com/docs/errors"
|
|
1204
|
+
},
|
|
1205
|
+
google: {
|
|
1206
|
+
name: "Google",
|
|
1207
|
+
apiKeyEnvVar: "GOOGLE_API_KEY",
|
|
1208
|
+
apiKeyConfigKey: "llm.googleApiKey",
|
|
1209
|
+
getKeyLink: "https://ai.google.dev/",
|
|
1210
|
+
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1176
1214
|
// src/lib/lcp/api/index.ts
|
|
1177
1215
|
var LCPAPI = class {
|
|
1178
1216
|
static async translate(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
@@ -1257,114 +1295,207 @@ var LCPAPI = class {
|
|
|
1257
1295
|
return dictionary;
|
|
1258
1296
|
}
|
|
1259
1297
|
static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1260
|
-
try {
|
|
1261
|
-
return await this._translateChunkGroq(
|
|
1262
|
-
models,
|
|
1263
|
-
sourceDictionary,
|
|
1264
|
-
sourceLocale,
|
|
1265
|
-
targetLocale
|
|
1266
|
-
);
|
|
1267
|
-
} catch (e) {
|
|
1268
|
-
console.error(`\u26A0\uFE0F Translation for ${targetLocale} failed:`, e);
|
|
1269
|
-
return {
|
|
1270
|
-
version: 0.1,
|
|
1271
|
-
locale: targetLocale,
|
|
1272
|
-
files: {}
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
if (isRunningInCIOrDocker()) {
|
|
1276
|
-
const groqFromEnv = getGroqKeyFromEnv();
|
|
1277
|
-
if (!groqFromEnv) {
|
|
1278
|
-
this._failMissingGroqKeyCi();
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
throw new Error(
|
|
1282
|
-
"\u26A0\uFE0F No API key found. Please set GROQ_API_KEY environment variable. If you dont have one go to https://groq.com/"
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
static async _translateChunkGroq(models, sourceDictionary, sourceLocale, targetLocale) {
|
|
1286
|
-
const groq = createGroq({ apiKey: getGroqKey() });
|
|
1287
|
-
console.log(`Created Groq client for ${targetLocale}`);
|
|
1288
1298
|
const { provider, model } = getLocaleModel(
|
|
1289
1299
|
models,
|
|
1290
1300
|
sourceLocale,
|
|
1291
1301
|
targetLocale
|
|
1292
1302
|
);
|
|
1293
|
-
if (!model) {
|
|
1303
|
+
if (!provider || !model) {
|
|
1294
1304
|
throw new Error(
|
|
1295
|
-
`\u26A0\uFE0F Locale ${targetLocale} is not configured. Add model for this locale to your config.`
|
|
1305
|
+
`\u26A0\uFE0F Locale "${targetLocale}" is not configured. Add provider and model for this locale to your config, e.g., "groq:llama3-8b-8192".`
|
|
1296
1306
|
);
|
|
1297
1307
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1308
|
+
try {
|
|
1309
|
+
const aiModel = this._createAiModel(provider, model, targetLocale);
|
|
1310
|
+
console.log(
|
|
1311
|
+
`\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
|
|
1301
1312
|
);
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
);
|
|
1306
|
-
const groqModel = groq(model);
|
|
1307
|
-
console.log(`Created model ${model}`);
|
|
1308
|
-
const response = await generateText({
|
|
1309
|
-
model: groqModel,
|
|
1310
|
-
messages: [
|
|
1311
|
-
{
|
|
1312
|
-
role: "system",
|
|
1313
|
-
content: prompt_default({ sourceLocale, targetLocale })
|
|
1314
|
-
},
|
|
1315
|
-
...shots_default.flatMap((shotsTuple) => [
|
|
1313
|
+
const response = await generateText({
|
|
1314
|
+
model: aiModel,
|
|
1315
|
+
messages: [
|
|
1316
1316
|
{
|
|
1317
|
-
role: "
|
|
1318
|
-
content:
|
|
1317
|
+
role: "system",
|
|
1318
|
+
content: prompt_default({ sourceLocale, targetLocale })
|
|
1319
1319
|
},
|
|
1320
|
+
...shots_default.flatMap((shotsTuple) => [
|
|
1321
|
+
{
|
|
1322
|
+
role: "user",
|
|
1323
|
+
content: obj2xml(shotsTuple[0])
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
role: "assistant",
|
|
1327
|
+
content: obj2xml(shotsTuple[1])
|
|
1328
|
+
}
|
|
1329
|
+
]),
|
|
1320
1330
|
{
|
|
1321
|
-
role: "
|
|
1322
|
-
content: obj2xml(
|
|
1331
|
+
role: "user",
|
|
1332
|
+
content: obj2xml(sourceDictionary)
|
|
1333
|
+
}
|
|
1334
|
+
]
|
|
1335
|
+
});
|
|
1336
|
+
console.log("Response text received for", targetLocale);
|
|
1337
|
+
let responseText = response.text;
|
|
1338
|
+
responseText = responseText.substring(
|
|
1339
|
+
responseText.indexOf("<"),
|
|
1340
|
+
responseText.lastIndexOf(">") + 1
|
|
1341
|
+
);
|
|
1342
|
+
return xml2obj(responseText);
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
this._failLLMFailureLocal(
|
|
1345
|
+
provider,
|
|
1346
|
+
targetLocale,
|
|
1347
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
1348
|
+
);
|
|
1349
|
+
throw error;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Instantiates an AI model based on provider and model ID.
|
|
1354
|
+
* Includes CI/CD API key checks.
|
|
1355
|
+
* @param providerId The ID of the AI provider (e.g., "groq", "google").
|
|
1356
|
+
* @param modelId The ID of the specific model (e.g., "llama3-8b-8192", "gemini-2.0-flash").
|
|
1357
|
+
* @param targetLocale The target locale being translated to (for logging/error messages).
|
|
1358
|
+
* @returns An instantiated AI LanguageModel.
|
|
1359
|
+
* @throws Error if the provider is not supported or API key is missing in CI/CD.
|
|
1360
|
+
*/
|
|
1361
|
+
static _createAiModel(providerId, modelId, targetLocale) {
|
|
1362
|
+
switch (providerId) {
|
|
1363
|
+
case "groq":
|
|
1364
|
+
if (isRunningInCIOrDocker()) {
|
|
1365
|
+
const groqFromEnv = getGroqKeyFromEnv();
|
|
1366
|
+
if (!groqFromEnv) {
|
|
1367
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1323
1368
|
}
|
|
1324
|
-
]),
|
|
1325
|
-
{
|
|
1326
|
-
role: "user",
|
|
1327
|
-
content: obj2xml(sourceDictionary)
|
|
1328
1369
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1370
|
+
const groqKey = getGroqKey();
|
|
1371
|
+
if (!groqKey) {
|
|
1372
|
+
throw new Error(
|
|
1373
|
+
"\u26A0\uFE0F GROQ API key not found. Please set GROQ_API_KEY environment variable or configure it user-wide."
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
console.log(
|
|
1377
|
+
`Creating Groq client for ${targetLocale} using model ${modelId}`
|
|
1378
|
+
);
|
|
1379
|
+
return createGroq({ apiKey: groqKey })(modelId);
|
|
1380
|
+
case "google":
|
|
1381
|
+
if (isRunningInCIOrDocker()) {
|
|
1382
|
+
const googleFromEnv = getGoogleKeyFromEnv();
|
|
1383
|
+
if (!googleFromEnv) {
|
|
1384
|
+
this._failMissingLLMKeyCi(providerId);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
const googleKey = getGoogleKey();
|
|
1388
|
+
if (!googleKey) {
|
|
1389
|
+
throw new Error(
|
|
1390
|
+
"\u26A0\uFE0F Google API key not found. Please set GOOGLE_API_KEY environment variable or configure it user-wide."
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
console.log(
|
|
1394
|
+
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
|
|
1395
|
+
);
|
|
1396
|
+
return createGoogleGenerativeAI({ apiKey: googleKey })(modelId);
|
|
1397
|
+
default:
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1338
1402
|
}
|
|
1339
1403
|
/**
|
|
1340
1404
|
* Show an actionable error message and exit the process when the compiler
|
|
1341
|
-
* is running in CI/CD without a
|
|
1405
|
+
* is running in CI/CD without a required LLM API key.
|
|
1342
1406
|
* The message explains why this situation is unusual and how to fix it.
|
|
1407
|
+
* @param providerId The ID of the LLM provider whose key is missing.
|
|
1343
1408
|
*/
|
|
1344
|
-
static
|
|
1409
|
+
static _failMissingLLMKeyCi(providerId) {
|
|
1410
|
+
let details = providerDetails[providerId];
|
|
1411
|
+
if (!details) {
|
|
1412
|
+
console.error(
|
|
1413
|
+
`Internal Error: Missing details for provider "${providerId}" when reporting missing key in CI/CD. You might be using an unsupported provider.`
|
|
1414
|
+
);
|
|
1415
|
+
process.exit(1);
|
|
1416
|
+
}
|
|
1345
1417
|
console.log(
|
|
1346
1418
|
dedent2`
|
|
1347
1419
|
\n
|
|
1348
1420
|
💡 You're using Lingo.dev Localization Compiler, and it detected unlocalized components in your app.
|
|
1349
1421
|
|
|
1350
|
-
The compiler needs a
|
|
1422
|
+
The compiler needs a ${details.name} API key to translate missing strings, but ${details.apiKeyEnvVar} is not set in the environment.
|
|
1351
1423
|
|
|
1352
1424
|
This is unexpected: typically you run a full build locally, commit the generated translation files, and push them to CI/CD.
|
|
1353
1425
|
|
|
1354
1426
|
However, If you want CI/CD to translate the new strings, provide the key with:
|
|
1355
|
-
• Session-wide: export
|
|
1356
|
-
• Project-wide / CI: add
|
|
1427
|
+
• Session-wide: export ${details.apiKeyEnvVar}=<your-api-key>
|
|
1428
|
+
• Project-wide / CI: add ${details.apiKeyEnvVar}=<your-api-key> to your pipeline environment variables
|
|
1357
1429
|
|
|
1358
1430
|
⭐️ Also:
|
|
1359
|
-
1. If you don't yet have a
|
|
1360
|
-
2. If you want to use a different LLM,
|
|
1361
|
-
3. If you
|
|
1431
|
+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
1432
|
+
2. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://docs.lingo.dev/
|
|
1433
|
+
3. If the model you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
1362
1434
|
|
|
1363
1435
|
✨
|
|
1364
1436
|
`
|
|
1365
1437
|
);
|
|
1366
1438
|
process.exit(1);
|
|
1367
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Show an actionable error message and exit the process when an LLM API call
|
|
1442
|
+
* fails during local compilation.
|
|
1443
|
+
* @param providerId The ID of the LLM provider that failed.
|
|
1444
|
+
* @param targetLocale The target locale being translated to.
|
|
1445
|
+
* @param errorMessage The error message received from the API.
|
|
1446
|
+
*/
|
|
1447
|
+
static _failLLMFailureLocal(providerId, targetLocale, errorMessage) {
|
|
1448
|
+
const details = providerDetails[providerId];
|
|
1449
|
+
if (!details) {
|
|
1450
|
+
console.error(
|
|
1451
|
+
`Internal Error: Missing details for provider "${providerId}" when reporting local failure.`
|
|
1452
|
+
);
|
|
1453
|
+
console.error(`Original Error: ${errorMessage}`);
|
|
1454
|
+
process.exit(1);
|
|
1455
|
+
}
|
|
1456
|
+
const isInvalidApiKey = errorMessage.match("Invalid API Key");
|
|
1457
|
+
if (isInvalidApiKey) {
|
|
1458
|
+
console.log(dedent2`
|
|
1459
|
+
\n
|
|
1460
|
+
⚠️ Lingo.dev Compiler requires a valid ${details.name} API key to translate your application.
|
|
1461
|
+
|
|
1462
|
+
It looks like you set ${details.name} API key but it is not valid. Please check your API key and try again.
|
|
1463
|
+
|
|
1464
|
+
Error details from ${details.name} API: ${errorMessage}
|
|
1465
|
+
|
|
1466
|
+
👉 You can set the API key in one of the following ways:
|
|
1467
|
+
1. User-wide: Run npx lingo.dev@latest config set ${details.apiKeyConfigKey} <your-api-key>
|
|
1468
|
+
2. Project-wide: Add ${details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
|
|
1469
|
+
3 Session-wide: Run export ${details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
|
|
1470
|
+
|
|
1471
|
+
⭐️ Also:
|
|
1472
|
+
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
1473
|
+
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
1474
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1475
|
+
|
|
1476
|
+
✨
|
|
1477
|
+
`);
|
|
1478
|
+
} else {
|
|
1479
|
+
console.log(
|
|
1480
|
+
dedent2`
|
|
1481
|
+
\n
|
|
1482
|
+
⚠️ Lingo.dev Compiler tried to translate your application to "${targetLocale}" locale via ${details.name} but it failed.
|
|
1483
|
+
|
|
1484
|
+
Error details from ${details.name} API: ${errorMessage}
|
|
1485
|
+
|
|
1486
|
+
This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
|
|
1487
|
+
|
|
1488
|
+
⭐️ Also:
|
|
1489
|
+
1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
|
|
1490
|
+
2. Did you reach any limits of your ${details.name} account?
|
|
1491
|
+
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
1492
|
+
|
|
1493
|
+
✨
|
|
1494
|
+
`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
process.exit(1);
|
|
1498
|
+
}
|
|
1368
1499
|
};
|
|
1369
1500
|
|
|
1370
1501
|
// src/lib/lcp/server.ts
|
|
@@ -2339,13 +2470,23 @@ var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
|
|
|
2339
2470
|
});
|
|
2340
2471
|
|
|
2341
2472
|
// src/index.ts
|
|
2473
|
+
var keyCheckers = {
|
|
2474
|
+
groq: {
|
|
2475
|
+
checkEnv: getGroqKeyFromEnv,
|
|
2476
|
+
checkRc: getGroqKeyFromRc
|
|
2477
|
+
},
|
|
2478
|
+
google: {
|
|
2479
|
+
checkEnv: getGoogleKeyFromEnv,
|
|
2480
|
+
checkRc: getGoogleKeyFromRc
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2342
2483
|
var unplugin = createUnplugin(
|
|
2343
2484
|
(_params, _meta) => {
|
|
2344
2485
|
console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
|
|
2486
|
+
const params = _11.defaults(_params, defaultParams);
|
|
2345
2487
|
if (!isRunningInCIOrDocker()) {
|
|
2346
|
-
|
|
2488
|
+
validateLLMKeyDetails(params.models);
|
|
2347
2489
|
}
|
|
2348
|
-
const params = _11.defaults(_params, defaultParams);
|
|
2349
2490
|
const invalidLocales = getInvalidLocales(
|
|
2350
2491
|
params.models,
|
|
2351
2492
|
params.sourceLocale,
|
|
@@ -2360,7 +2501,7 @@ var unplugin = createUnplugin(
|
|
|
2360
2501
|
1. Refer to documentation for help: https://docs.lingo.dev/
|
|
2361
2502
|
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2362
2503
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2363
|
-
|
|
2504
|
+
|
|
2364
2505
|
✨
|
|
2365
2506
|
`);
|
|
2366
2507
|
process.exit(1);
|
|
@@ -2459,56 +2600,81 @@ var src_default = {
|
|
|
2459
2600
|
return config2;
|
|
2460
2601
|
}
|
|
2461
2602
|
};
|
|
2462
|
-
function
|
|
2463
|
-
const
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2603
|
+
function validateLLMKeyDetails(models) {
|
|
2604
|
+
const configuredProviders = _11.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
|
|
2605
|
+
(providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
|
|
2606
|
+
).value();
|
|
2607
|
+
if (configuredProviders.length === 0) {
|
|
2608
|
+
return;
|
|
2609
|
+
}
|
|
2610
|
+
const keyStatuses = {};
|
|
2611
|
+
const missingProviders = [];
|
|
2612
|
+
const foundProviders = [];
|
|
2613
|
+
for (const providerId of configuredProviders) {
|
|
2614
|
+
const details = providerDetails[providerId];
|
|
2615
|
+
const checkers = keyCheckers[providerId];
|
|
2616
|
+
if (!details || !checkers) continue;
|
|
2617
|
+
const foundInEnv = checkers.checkEnv() !== void 0;
|
|
2618
|
+
const foundInRc = checkers.checkRc() !== void 0;
|
|
2619
|
+
keyStatuses[providerId] = { foundInEnv, foundInRc, details };
|
|
2620
|
+
if (!foundInEnv && !foundInRc) {
|
|
2621
|
+
missingProviders.push(providerId);
|
|
2622
|
+
} else {
|
|
2623
|
+
foundProviders.push(providerId);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
if (missingProviders.length > 0) {
|
|
2468
2627
|
console.log(dedent3`
|
|
2469
2628
|
\n
|
|
2470
|
-
💡
|
|
2629
|
+
💡 Lingo.dev Localization Compiler is configured to use the following LLM provider(s): ${configuredProviders.join(", ")}.
|
|
2471
2630
|
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2631
|
+
The compiler requires API keys for these providers to work, but the following keys are missing:
|
|
2632
|
+
`);
|
|
2633
|
+
for (const providerId of missingProviders) {
|
|
2634
|
+
const status = keyStatuses[providerId];
|
|
2635
|
+
if (!status) continue;
|
|
2636
|
+
console.log(dedent3`
|
|
2637
|
+
⚠️ ${status.details.name} API key is missing. Set ${status.details.apiKeyEnvVar} environment variable.
|
|
2476
2638
|
|
|
2639
|
+
👉 You can set the API key in one of the following ways:
|
|
2640
|
+
1. User-wide: Run npx lingo.dev@latest config set ${status.details.apiKeyConfigKey || "<config-key-not-available>"} <your-api-key>
|
|
2641
|
+
2. Project-wide: Add ${status.details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
|
|
2642
|
+
3. Session-wide: Run export ${status.details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
|
|
2643
|
+
|
|
2644
|
+
⭐️ If you don't yet have a ${status.details.name} API key, get one for free at ${status.details.getKeyLink}
|
|
2645
|
+
`);
|
|
2646
|
+
}
|
|
2647
|
+
console.log(dedent3`
|
|
2648
|
+
\n
|
|
2477
2649
|
⭐️ Also:
|
|
2478
|
-
1. If you
|
|
2479
|
-
2. If you want to use
|
|
2650
|
+
1. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://docs.lingo.dev/
|
|
2651
|
+
2. If the model/provider you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2480
2652
|
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2481
2653
|
|
|
2482
2654
|
✨
|
|
2483
2655
|
`);
|
|
2484
2656
|
process.exit(1);
|
|
2485
|
-
} else if (
|
|
2486
|
-
console.log(
|
|
2487
|
-
|
|
2488
|
-
🔑
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
);
|
|
2506
|
-
} else if (!groq.fromEnv && groq.fromRc) {
|
|
2507
|
-
console.log(
|
|
2508
|
-
dedent3`
|
|
2509
|
-
🔑 GROQ API key loaded from your user-wide configuration.
|
|
2510
|
-
`
|
|
2511
|
-
);
|
|
2657
|
+
} else if (foundProviders.length > 0) {
|
|
2658
|
+
console.log(dedent3`
|
|
2659
|
+
\n
|
|
2660
|
+
🔑 LLM API keys detected for configured providers: ${foundProviders.join(", ")}.
|
|
2661
|
+
`);
|
|
2662
|
+
for (const providerId of foundProviders) {
|
|
2663
|
+
const status = keyStatuses[providerId];
|
|
2664
|
+
if (!status) continue;
|
|
2665
|
+
let sourceMessage = "";
|
|
2666
|
+
if (status.foundInEnv && status.foundInRc) {
|
|
2667
|
+
sourceMessage = `from both environment variables (${status.details.apiKeyEnvVar}) and your user-wide configuration. The key from the environment will be used because it has higher priority.`;
|
|
2668
|
+
} else if (status.foundInEnv) {
|
|
2669
|
+
sourceMessage = `from environment variables (${status.details.apiKeyEnvVar}).`;
|
|
2670
|
+
} else if (status.foundInRc) {
|
|
2671
|
+
sourceMessage = `from your user-wide configuration${status.details.apiKeyConfigKey ? ` (${status.details.apiKeyConfigKey})` : ""}.`;
|
|
2672
|
+
}
|
|
2673
|
+
console.log(dedent3`
|
|
2674
|
+
• ${status.details.name} API key loaded ${sourceMessage}
|
|
2675
|
+
`);
|
|
2676
|
+
}
|
|
2677
|
+
console.log("\u2728");
|
|
2512
2678
|
}
|
|
2513
2679
|
}
|
|
2514
2680
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingo.dev/_compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Lingo.dev Compiler",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"typescript": "^5.4.5"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@ai-sdk/google": "^1.2.19",
|
|
32
33
|
"@ai-sdk/groq": "^1.2.3",
|
|
33
34
|
"@babel/generator": "^7.26.5",
|
|
34
35
|
"@babel/parser": "^7.26.7",
|