@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.
Files changed (3) hide show
  1. package/build/index.cjs +289 -123
  2. package/build/index.mjs +289 -123
  3. 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.1.12",
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/groq.ts
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
- const rc = getRc();
1158
- const result = _lodash2.default.get(rc, "llm.groqApiKey");
1159
- return result;
1172
+ return getKeyFromRc("llm.groqApiKey");
1160
1173
  }
1161
1174
  function getGroqKeyFromEnv() {
1162
- const ephemeralEnv = {};
1163
- dotenv.config({ processEnv: ephemeralEnv });
1164
- return ephemeralEnv.GROQ_API_KEY;
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
- if (provider !== "groq") {
1299
- throw new Error(
1300
- `\u26A0\uFE0F Provider ${provider} is not supported. Only "groq" provider is supported at the moment.`
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
- console.log(
1304
- `\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
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: "user",
1318
- content: obj2xml(shotsTuple[0])
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: "assistant",
1322
- content: obj2xml(shotsTuple[1])
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
- console.log("Response", response.text);
1332
- let responseText = response.text;
1333
- responseText = responseText.substring(
1334
- responseText.indexOf("<"),
1335
- responseText.lastIndexOf(">") + 1
1336
- );
1337
- return xml2obj(responseText);
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 GROQ API key.
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 _failMissingGroqKeyCi() {
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 GROQ API key to translate missing strings, but GROQ_API_KEY is not set in the environment.
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 GROQ_API_KEY=<your-api-key>
1356
- • Project-wide / CI: add GROQ_API_KEY=<your-api-key> to your pipeline environment variables
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 GROQ API key, get one for free at https://groq.com
1360
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
1361
- 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
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
- validateGroqKeyDetails();
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 validateGroqKeyDetails() {
2463
- const groq = {
2464
- fromEnv: getGroqKeyFromEnv(),
2465
- fromRc: getGroqKeyFromRc()
2466
- };
2467
- if (!groq.fromEnv && !groq.fromRc) {
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
- 💡 You're using Lingo.dev Localization Compiler in your project, which requires a GROQ API key to work.
2629
+ 💡 Lingo.dev Localization Compiler is configured to use the following LLM provider(s): ${configuredProviders.join(", ")}.
2471
2630
 
2472
- 👉 You can set the API key in one of the following ways:
2473
- 1. User-wide: Run npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2474
- 2. Project-wide: Add GROQ_API_KEY=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
2475
- 3. Session-wide: Run export GROQ_API_KEY=<your-api-key> in your terminal before running the compiler to set the API key for the current session
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 don't yet have a GROQ API key, get one for free at https://groq.com
2479
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
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 (groq.fromEnv && groq.fromRc) {
2486
- console.log(
2487
- _dedent2.default`
2488
- 🔑 GROQ API key detected in both environment variables and your user-wide configuration.
2489
-
2490
- 👉 The compiler will use the key from the environment because it has higher priority.
2491
-
2492
- To update the user-wide key run: npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2493
- To remove it run: npx lingo.dev@latest config unset llm.groqApiKey
2494
- To remove the env variable from the current session run: unset GROQ_API_KEY
2495
- `
2496
- );
2497
- } else if (groq.fromEnv && !groq.fromRc) {
2498
- console.log(
2499
- _dedent2.default`
2500
- 🔑 GROQ API key loaded from environment variables.
2501
-
2502
- You can also save the key user-wide with: npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2503
- • Or remove the env variable from the current session with: unset GROQ_API_KEY
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.1.12",
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/groq.ts
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
- const rc = getRc();
1158
- const result = _5.get(rc, "llm.groqApiKey");
1159
- return result;
1172
+ return getKeyFromRc("llm.groqApiKey");
1160
1173
  }
1161
1174
  function getGroqKeyFromEnv() {
1162
- const ephemeralEnv = {};
1163
- dotenv.config({ processEnv: ephemeralEnv });
1164
- return ephemeralEnv.GROQ_API_KEY;
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
- if (provider !== "groq") {
1299
- throw new Error(
1300
- `\u26A0\uFE0F Provider ${provider} is not supported. Only "groq" provider is supported at the moment.`
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
- console.log(
1304
- `\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
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: "user",
1318
- content: obj2xml(shotsTuple[0])
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: "assistant",
1322
- content: obj2xml(shotsTuple[1])
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
- console.log("Response", response.text);
1332
- let responseText = response.text;
1333
- responseText = responseText.substring(
1334
- responseText.indexOf("<"),
1335
- responseText.lastIndexOf(">") + 1
1336
- );
1337
- return xml2obj(responseText);
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 GROQ API key.
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 _failMissingGroqKeyCi() {
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 GROQ API key to translate missing strings, but GROQ_API_KEY is not set in the environment.
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 GROQ_API_KEY=<your-api-key>
1356
- • Project-wide / CI: add GROQ_API_KEY=<your-api-key> to your pipeline environment variables
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 GROQ API key, get one for free at https://groq.com
1360
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
1361
- 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
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
- validateGroqKeyDetails();
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 validateGroqKeyDetails() {
2463
- const groq = {
2464
- fromEnv: getGroqKeyFromEnv(),
2465
- fromRc: getGroqKeyFromRc()
2466
- };
2467
- if (!groq.fromEnv && !groq.fromRc) {
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
- 💡 You're using Lingo.dev Localization Compiler in your project, which requires a GROQ API key to work.
2629
+ 💡 Lingo.dev Localization Compiler is configured to use the following LLM provider(s): ${configuredProviders.join(", ")}.
2471
2630
 
2472
- 👉 You can set the API key in one of the following ways:
2473
- 1. User-wide: Run npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2474
- 2. Project-wide: Add GROQ_API_KEY=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
2475
- 3. Session-wide: Run export GROQ_API_KEY=<your-api-key> in your terminal before running the compiler to set the API key for the current session
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 don't yet have a GROQ API key, get one for free at https://groq.com
2479
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
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 (groq.fromEnv && groq.fromRc) {
2486
- console.log(
2487
- dedent3`
2488
- 🔑 GROQ API key detected in both environment variables and your user-wide configuration.
2489
-
2490
- 👉 The compiler will use the key from the environment because it has higher priority.
2491
-
2492
- To update the user-wide key run: npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2493
- To remove it run: npx lingo.dev@latest config unset llm.groqApiKey
2494
- To remove the env variable from the current session run: unset GROQ_API_KEY
2495
- `
2496
- );
2497
- } else if (groq.fromEnv && !groq.fromRc) {
2498
- console.log(
2499
- dedent3`
2500
- 🔑 GROQ API key loaded from environment variables.
2501
-
2502
- You can also save the key user-wide with: npx lingo.dev@latest config set llm.groqApiKey <your-api-key>
2503
- • Or remove the env variable from the current session with: unset GROQ_API_KEY
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.1.12",
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",