@lingo.dev/_compiler 0.2.4 → 0.3.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 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.2.4",
7
+ version: "0.3.0",
8
8
  description: "Lingo.dev Compiler",
9
9
  private: false,
10
10
  publishConfig: {
@@ -46,6 +46,8 @@ var package_default = {
46
46
  "@babel/parser": "^7.26.7",
47
47
  "@babel/traverse": "^7.27.4",
48
48
  "@babel/types": "^7.26.7",
49
+ "@lingo.dev/_sdk": "workspace:*",
50
+ "@openrouter/ai-sdk-provider": "^0.7.1",
49
51
  ai: "^4.2.10",
50
52
  dedent: "^1.6.0",
51
53
  dotenv: "^16.4.5",
@@ -53,11 +55,13 @@ var package_default = {
53
55
  ini: "^5.0.0",
54
56
  lodash: "^4.17.21",
55
57
  "object-hash": "^3.0.0",
58
+ "ollama-ai-provider": "^1.2.0",
56
59
  prettier: "^3.4.2",
57
60
  unplugin: "^2.1.2",
58
61
  vitest: "^2.1.4",
59
62
  zod: "^3.24.1"
60
- }
63
+ },
64
+ packageManager: "pnpm@9.12.3"
61
65
  };
62
66
 
63
67
  // src/index.ts
@@ -926,7 +930,10 @@ var LCPCache = class {
926
930
  // src/lib/lcp/api/index.ts
927
931
  var _groq = require('@ai-sdk/groq');
928
932
  var _google = require('@ai-sdk/google');
933
+ var _aisdkprovider = require('@openrouter/ai-sdk-provider');
934
+ var _ollamaaiprovider = require('ollama-ai-provider');
929
935
  var _ai = require('ai');
936
+ var __sdk = require('@lingo.dev/_sdk');
930
937
 
931
938
 
932
939
  // src/utils/locales.ts
@@ -949,7 +956,16 @@ function getLocaleModel(localeModels, sourceLocale, targetLocale) {
949
956
  ];
950
957
  const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
951
958
  if (modelKey) {
952
- const [provider, model] = _optionalChain([localeModels, 'access', _29 => _29[modelKey], 'optionalAccess', _30 => _30.split, 'call', _31 => _31(":")]);
959
+ const value = localeModels[modelKey];
960
+ const firstColonIndex = _optionalChain([value, 'optionalAccess', _29 => _29.indexOf, 'call', _30 => _30(":")]);
961
+ if (value && firstColonIndex !== -1 && firstColonIndex !== void 0) {
962
+ const provider2 = value.substring(0, firstColonIndex);
963
+ const model2 = value.substring(firstColonIndex + 1);
964
+ if (provider2 && model2) {
965
+ return { provider: provider2, model: model2 };
966
+ }
967
+ }
968
+ const [provider, model] = _optionalChain([value, 'optionalAccess', _31 => _31.split, 'call', _32 => _32(":")]) || [];
953
969
  if (provider && model) {
954
970
  return { provider, model };
955
971
  }
@@ -962,7 +978,7 @@ var prompt_default = (args) => {
962
978
  return getUserSystemPrompt(args) || getBuiltInSystemPrompt(args);
963
979
  };
964
980
  function getUserSystemPrompt(args) {
965
- const userPrompt = _optionalChain([args, 'access', _32 => _32.prompt, 'optionalAccess', _33 => _33.trim, 'call', _34 => _34(), 'optionalAccess', _35 => _35.replace, 'call', _36 => _36("{SOURCE_LOCALE}", args.sourceLocale), 'optionalAccess', _37 => _37.replace, 'call', _38 => _38("{TARGET_LOCALE}", args.targetLocale)]);
981
+ const userPrompt = _optionalChain([args, 'access', _33 => _33.prompt, 'optionalAccess', _34 => _34.trim, 'call', _35 => _35(), 'optionalAccess', _36 => _36.replace, 'call', _37 => _37("{SOURCE_LOCALE}", args.sourceLocale), 'optionalAccess', _38 => _38.replace, 'call', _39 => _39("{TARGET_LOCALE}", args.targetLocale)]);
966
982
  if (userPrompt) {
967
983
  console.log("\u2728 Compiler is using user-defined prompt.");
968
984
  return userPrompt;
@@ -1172,7 +1188,7 @@ function getKeyFromEnv(envVarName) {
1172
1188
  path.default.resolve(process.cwd(), ".env.development")
1173
1189
  ]
1174
1190
  });
1175
- return _optionalChain([result, 'optionalAccess', _39 => _39.parsed, 'optionalAccess', _40 => _40[envVarName]]);
1191
+ return _optionalChain([result, 'optionalAccess', _40 => _40.parsed, 'optionalAccess', _41 => _41[envVarName]]);
1176
1192
  }
1177
1193
  function getKeyFromRc(rcPath) {
1178
1194
  const rc = getRc();
@@ -1188,6 +1204,15 @@ function getGroqKeyFromRc() {
1188
1204
  function getGroqKeyFromEnv() {
1189
1205
  return getKeyFromEnv("GROQ_API_KEY");
1190
1206
  }
1207
+ function getLingoDotDevKeyFromEnv() {
1208
+ return getKeyFromEnv("LINGODOTDEV_API_KEY");
1209
+ }
1210
+ function getLingoDotDevKeyFromRc() {
1211
+ return getKeyFromRc("auth.apiKey");
1212
+ }
1213
+ function getLingoDotDevKey() {
1214
+ return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
1215
+ }
1191
1216
  function getGoogleKey() {
1192
1217
  return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
1193
1218
  }
@@ -1197,6 +1222,15 @@ function getGoogleKeyFromRc() {
1197
1222
  function getGoogleKeyFromEnv() {
1198
1223
  return getKeyFromEnv("GOOGLE_API_KEY");
1199
1224
  }
1225
+ function getOpenRouterKey() {
1226
+ return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
1227
+ }
1228
+ function getOpenRouterKeyFromRc() {
1229
+ return getKeyFromRc("llm.openrouterApiKey");
1230
+ }
1231
+ function getOpenRouterKeyFromEnv() {
1232
+ return getKeyFromEnv("OPENROUTER_API_KEY");
1233
+ }
1200
1234
 
1201
1235
  // src/lib/lcp/api/index.ts
1202
1236
 
@@ -1222,6 +1256,22 @@ var providerDetails = {
1222
1256
  apiKeyConfigKey: "llm.googleApiKey",
1223
1257
  getKeyLink: "https://ai.google.dev/",
1224
1258
  docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
1259
+ },
1260
+ openrouter: {
1261
+ name: "OpenRouter",
1262
+ apiKeyEnvVar: "OPENROUTER_API_KEY",
1263
+ apiKeyConfigKey: "llm.openrouterApiKey",
1264
+ getKeyLink: "https://openrouter.ai",
1265
+ docsLink: "https://openrouter.ai/docs"
1266
+ },
1267
+ ollama: {
1268
+ name: "Ollama",
1269
+ apiKeyEnvVar: void 0,
1270
+ // Ollama doesn't require an API key
1271
+ apiKeyConfigKey: void 0,
1272
+ // Ollama doesn't require an API key
1273
+ getKeyLink: "https://ollama.com/download",
1274
+ docsLink: "https://github.com/ollama/ollama/tree/main/docs"
1225
1275
  }
1226
1276
  };
1227
1277
 
@@ -1308,59 +1358,118 @@ var LCPAPI = class {
1308
1358
  };
1309
1359
  return dictionary;
1310
1360
  }
1311
- static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
1312
- const { provider, model } = getLocaleModel(
1313
- models,
1314
- sourceLocale,
1315
- targetLocale
1316
- );
1317
- if (!provider || !model) {
1361
+ static _createLingoDotDevEngine() {
1362
+ if (isRunningInCIOrDocker()) {
1363
+ const apiKeyFromEnv = getLingoDotDevKeyFromEnv();
1364
+ if (!apiKeyFromEnv) {
1365
+ this._failMissingLLMKeyCi("lingo.dev");
1366
+ }
1367
+ }
1368
+ const apiKey = getLingoDotDevKey();
1369
+ if (!apiKey) {
1318
1370
  throw new Error(
1319
- `\u26A0\uFE0F Locale "${targetLocale}" is not configured. Add provider and model for this locale to your config, e.g., "groq:llama3-8b-8192".`
1371
+ "\u26A0\uFE0F Lingo.dev API key not found. Please set LINGODOTDEV_API_KEY environment variable or configure it user-wide."
1320
1372
  );
1321
1373
  }
1322
- try {
1323
- const aiModel = this._createAiModel(provider, model, targetLocale);
1324
- console.log(
1325
- `\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
1326
- );
1327
- const response = await _ai.generateText.call(void 0, {
1328
- model: aiModel,
1329
- messages: [
1374
+ console.log(`Creating Lingo.dev client`);
1375
+ return new (0, __sdk.LingoDotDevEngine)({
1376
+ apiKey
1377
+ });
1378
+ }
1379
+ static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
1380
+ if (models === "lingo.dev") {
1381
+ try {
1382
+ const lingoDotDevEngine = this._createLingoDotDevEngine();
1383
+ console.log(
1384
+ `\u2728 Using Lingo.dev Engine to localize from "${sourceLocale}" to "${targetLocale}"`
1385
+ );
1386
+ const result = await lingoDotDevEngine.localizeObject(
1387
+ sourceDictionary,
1330
1388
  {
1331
- role: "system",
1332
- content: prompt_default({ sourceLocale, targetLocale })
1333
- },
1334
- ...shots_default.flatMap((shotsTuple) => [
1389
+ sourceLocale,
1390
+ targetLocale
1391
+ }
1392
+ );
1393
+ return result;
1394
+ } catch (error) {
1395
+ this._failLLMFailureLocal(
1396
+ "lingo.dev",
1397
+ targetLocale,
1398
+ error instanceof Error ? error.message : "Unknown error"
1399
+ );
1400
+ throw error;
1401
+ }
1402
+ } else {
1403
+ const { provider, model } = getLocaleModel(
1404
+ models,
1405
+ sourceLocale,
1406
+ targetLocale
1407
+ );
1408
+ if (!provider || !model) {
1409
+ throw new Error(
1410
+ _dedent2.default`
1411
+ 🚫 Lingo.dev Localization Engine Not Configured!
1412
+
1413
+ The "models" parameter is missing or incomplete in your Lingo.dev configuration.
1414
+
1415
+ 👉 To fix this, set the "models" parameter to either:
1416
+ • "lingo.dev" (for the default engine)
1417
+ • a map of locale-to-model, e.g. { "models": { "en:es": "openai:gpt-3.5-turbo" } }
1418
+
1419
+ Example:
1420
+ {
1421
+ // ...
1422
+ "models": "lingo.dev"
1423
+ }
1424
+
1425
+ For more details, see: https://lingo.dev/compiler
1426
+ To get help, join our Discord: https://lingo.dev/go/discord
1427
+ `
1428
+ );
1429
+ }
1430
+ try {
1431
+ const aiModel = this._createAiModel(provider, model, targetLocale);
1432
+ console.log(
1433
+ `\u2139\uFE0F Using raw LLM API ("${provider}":"${model}") to translate from "${sourceLocale}" to "${targetLocale}"`
1434
+ );
1435
+ const response = await _ai.generateText.call(void 0, {
1436
+ model: aiModel,
1437
+ messages: [
1335
1438
  {
1336
- role: "user",
1337
- content: obj2xml(shotsTuple[0])
1439
+ role: "system",
1440
+ content: prompt_default({ sourceLocale, targetLocale })
1338
1441
  },
1442
+ ...shots_default.flatMap((shotsTuple) => [
1443
+ {
1444
+ role: "user",
1445
+ content: obj2xml(shotsTuple[0])
1446
+ },
1447
+ {
1448
+ role: "assistant",
1449
+ content: obj2xml(shotsTuple[1])
1450
+ }
1451
+ ]),
1339
1452
  {
1340
- role: "assistant",
1341
- content: obj2xml(shotsTuple[1])
1453
+ role: "user",
1454
+ content: obj2xml(sourceDictionary)
1342
1455
  }
1343
- ]),
1344
- {
1345
- role: "user",
1346
- content: obj2xml(sourceDictionary)
1347
- }
1348
- ]
1349
- });
1350
- console.log("Response text received for", targetLocale);
1351
- let responseText = response.text;
1352
- responseText = responseText.substring(
1353
- responseText.indexOf("<"),
1354
- responseText.lastIndexOf(">") + 1
1355
- );
1356
- return xml2obj(responseText);
1357
- } catch (error) {
1358
- this._failLLMFailureLocal(
1359
- provider,
1360
- targetLocale,
1361
- error instanceof Error ? error.message : "Unknown error"
1362
- );
1363
- throw error;
1456
+ ]
1457
+ });
1458
+ console.log("Response text received for", targetLocale);
1459
+ let responseText = response.text;
1460
+ responseText = responseText.substring(
1461
+ responseText.indexOf("<"),
1462
+ responseText.lastIndexOf(">") + 1
1463
+ );
1464
+ return xml2obj(responseText);
1465
+ } catch (error) {
1466
+ this._failLLMFailureLocal(
1467
+ provider,
1468
+ targetLocale,
1469
+ error instanceof Error ? error.message : "Unknown error"
1470
+ );
1471
+ throw error;
1472
+ }
1364
1473
  }
1365
1474
  }
1366
1475
  /**
@@ -1374,7 +1483,7 @@ var LCPAPI = class {
1374
1483
  */
1375
1484
  static _createAiModel(providerId, modelId, targetLocale) {
1376
1485
  switch (providerId) {
1377
- case "groq":
1486
+ case "groq": {
1378
1487
  if (isRunningInCIOrDocker()) {
1379
1488
  const groqFromEnv = getGroqKeyFromEnv();
1380
1489
  if (!groqFromEnv) {
@@ -1391,7 +1500,8 @@ var LCPAPI = class {
1391
1500
  `Creating Groq client for ${targetLocale} using model ${modelId}`
1392
1501
  );
1393
1502
  return _groq.createGroq.call(void 0, { apiKey: groqKey })(modelId);
1394
- case "google":
1503
+ }
1504
+ case "google": {
1395
1505
  if (isRunningInCIOrDocker()) {
1396
1506
  const googleFromEnv = getGoogleKeyFromEnv();
1397
1507
  if (!googleFromEnv) {
@@ -1408,10 +1518,38 @@ var LCPAPI = class {
1408
1518
  `Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
1409
1519
  );
1410
1520
  return _google.createGoogleGenerativeAI.call(void 0, { apiKey: googleKey })(modelId);
1411
- default:
1521
+ }
1522
+ case "openrouter": {
1523
+ if (isRunningInCIOrDocker()) {
1524
+ const openRouterFromEnv = getOpenRouterKeyFromEnv();
1525
+ if (!openRouterFromEnv) {
1526
+ this._failMissingLLMKeyCi(providerId);
1527
+ }
1528
+ }
1529
+ const openRouterKey = getOpenRouterKey();
1530
+ if (!openRouterKey) {
1531
+ throw new Error(
1532
+ "\u26A0\uFE0F OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide."
1533
+ );
1534
+ }
1535
+ console.log(
1536
+ `Creating OpenRouter client for ${targetLocale} using model ${modelId}`
1537
+ );
1538
+ return _aisdkprovider.createOpenRouter.call(void 0, {
1539
+ apiKey: openRouterKey
1540
+ })(modelId);
1541
+ }
1542
+ case "ollama": {
1543
+ console.log(
1544
+ `Creating Ollama client for ${targetLocale} using model ${modelId} at default Ollama address`
1545
+ );
1546
+ return _ollamaaiprovider.createOllama.call(void 0, )(modelId);
1547
+ }
1548
+ default: {
1412
1549
  throw new Error(
1413
1550
  `\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
1414
1551
  );
1552
+ }
1415
1553
  }
1416
1554
  }
1417
1555
  /**
@@ -1500,7 +1638,7 @@ var LCPAPI = class {
1500
1638
  This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
1501
1639
 
1502
1640
  ⭐️ Also:
1503
- 1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
1641
+ 1. Did you set ${details.apiKeyEnvVar ? `${details.apiKeyEnvVar}` : "the provider API key"} environment variable correctly ${!details.apiKeyEnvVar ? "(if required)" : ""}?
1504
1642
  2. Did you reach any limits of your ${details.name} account?
1505
1643
  3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
1506
1644
 
@@ -1514,31 +1652,39 @@ var LCPAPI = class {
1514
1652
 
1515
1653
  // src/lib/lcp/server.ts
1516
1654
  var LCPServer = (_class = class {
1517
- static __initStatic() {this.isLoading = false}
1655
+ static __initStatic() {this.dictionariesCache = null}
1656
+ static __initStatic2() {this.inFlightPromise = null}
1518
1657
  static async loadDictionaries(params) {
1519
- while (this.isLoading) {
1520
- await new Promise(function(resolve3) {
1521
- setTimeout(resolve3, 500);
1522
- });
1658
+ if (this.dictionariesCache) {
1659
+ return this.dictionariesCache;
1523
1660
  }
1524
- this.isLoading = true;
1525
- const targetLocales = _lodash2.default.uniq([
1526
- ...params.targetLocales,
1527
- params.sourceLocale
1528
- ]);
1529
- const dictionaries = await Promise.all(
1530
- targetLocales.map(
1531
- (targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
1532
- )
1533
- );
1534
- const result = _lodash2.default.fromPairs(
1535
- targetLocales.map((targetLocale, index) => [
1536
- targetLocale,
1537
- dictionaries[index]
1538
- ])
1539
- );
1540
- this.isLoading = false;
1541
- return result;
1661
+ if (this.inFlightPromise) {
1662
+ return this.inFlightPromise;
1663
+ }
1664
+ this.inFlightPromise = (async () => {
1665
+ try {
1666
+ const targetLocales = _lodash2.default.uniq([
1667
+ ...params.targetLocales,
1668
+ params.sourceLocale
1669
+ ]);
1670
+ const dictionaries = await Promise.all(
1671
+ targetLocales.map(
1672
+ (targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
1673
+ )
1674
+ );
1675
+ const result = _lodash2.default.fromPairs(
1676
+ targetLocales.map((targetLocale, index) => [
1677
+ targetLocale,
1678
+ dictionaries[index]
1679
+ ])
1680
+ );
1681
+ this.dictionariesCache = result;
1682
+ return result;
1683
+ } finally {
1684
+ this.inFlightPromise = null;
1685
+ }
1686
+ })();
1687
+ return this.inFlightPromise;
1542
1688
  }
1543
1689
  static async loadDictionaryForLocale(params) {
1544
1690
  const sourceDictionary = this._extractSourceDictionary(
@@ -1703,14 +1849,14 @@ var LCPServer = (_class = class {
1703
1849
  const sourceFile = _lodash2.default.get(sourceDictionary.files, fileName);
1704
1850
  const targetFile = _lodash2.default.get(targetDictionary.files, fileName);
1705
1851
  const entries = removeEmptyEntries ? _lodash2.default.pickBy(
1706
- _optionalChain([sourceFile, 'optionalAccess', _41 => _41.entries]) || {},
1707
- (value) => _optionalChain([String, 'call', _42 => _42(value || ""), 'optionalAccess', _43 => _43.trim, 'optionalCall', _44 => _44(), 'optionalAccess', _45 => _45.length]) > 0
1708
- ) : _optionalChain([sourceFile, 'optionalAccess', _46 => _46.entries]) || {};
1852
+ _optionalChain([sourceFile, 'optionalAccess', _42 => _42.entries]) || {},
1853
+ (value) => _optionalChain([String, 'call', _43 => _43(value || ""), 'optionalAccess', _44 => _44.trim, 'optionalCall', _45 => _45(), 'optionalAccess', _46 => _46.length]) > 0
1854
+ ) : _optionalChain([sourceFile, 'optionalAccess', _47 => _47.entries]) || {};
1709
1855
  return [
1710
1856
  fileName,
1711
1857
  {
1712
1858
  ...targetFile,
1713
- entries: _lodash2.default.merge(_optionalChain([targetFile, 'optionalAccess', _47 => _47.entries]) || {}, entries)
1859
+ entries: _lodash2.default.merge({}, _optionalChain([targetFile, 'optionalAccess', _48 => _48.entries]) || {}, entries)
1714
1860
  }
1715
1861
  ];
1716
1862
  }).fromPairs().value();
@@ -1727,7 +1873,7 @@ var LCPServer = (_class = class {
1727
1873
  0
1728
1874
  );
1729
1875
  }
1730
- }, _class.__initStatic(), _class);
1876
+ }, _class.__initStatic(), _class.__initStatic2(), _class);
1731
1877
 
1732
1878
  // src/utils/invokations.ts
1733
1879
 
@@ -1916,7 +2062,7 @@ function jsxFragmentMutation(payload) {
1916
2062
  var jsxHtmlLangMutation = createCodeMutation((payload) => {
1917
2063
  _traverse2.default.call(void 0, payload.ast, {
1918
2064
  JSXElement: (path7) => {
1919
- if (_optionalChain([getJsxElementName, 'call', _48 => _48(path7), 'optionalAccess', _49 => _49.toLowerCase, 'call', _50 => _50()]) === "html") {
2065
+ if (_optionalChain([getJsxElementName, 'call', _49 => _49(path7), 'optionalAccess', _50 => _50.toLowerCase, 'call', _51 => _51()]) === "html") {
1920
2066
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
1921
2067
  const packagePath = mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
1922
2068
  const lingoHtmlComponentImport = getOrCreateImport(payload.ast, {
@@ -2499,6 +2645,10 @@ var keyCheckers = {
2499
2645
  google: {
2500
2646
  checkEnv: getGoogleKeyFromEnv,
2501
2647
  checkRc: getGoogleKeyFromRc
2648
+ },
2649
+ "lingo.dev": {
2650
+ checkEnv: getLingoDotDevKeyFromEnv,
2651
+ checkRc: getLingoDotDevKeyFromRc
2502
2652
  }
2503
2653
  };
2504
2654
  var unplugin = _unplugin.createUnplugin.call(void 0,
@@ -2506,26 +2656,31 @@ var unplugin = _unplugin.createUnplugin.call(void 0,
2506
2656
  console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
2507
2657
  const params = _lodash2.default.defaults(_params, defaultParams);
2508
2658
  if (!isRunningInCIOrDocker()) {
2509
- validateLLMKeyDetails(params.models);
2510
- }
2511
- const invalidLocales = getInvalidLocales(
2512
- params.models,
2513
- params.sourceLocale,
2514
- params.targetLocales
2515
- );
2516
- if (invalidLocales.length > 0) {
2517
- console.log(_dedent2.default`
2518
- \n
2519
- ⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
2520
-
2521
- ⭐️ Next steps:
2522
- 1. Refer to documentation for help: https://docs.lingo.dev/
2523
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
2524
- 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
2525
-
2526
-
2527
- `);
2528
- process.exit(1);
2659
+ if (params.models === "lingo.dev") {
2660
+ validateLLMKeyDetails(["lingo.dev"]);
2661
+ } else {
2662
+ const configuredProviders = getConfiguredProviders(params.models);
2663
+ validateLLMKeyDetails(configuredProviders);
2664
+ const invalidLocales = getInvalidLocales(
2665
+ params.models,
2666
+ params.sourceLocale,
2667
+ params.targetLocales
2668
+ );
2669
+ if (invalidLocales.length > 0) {
2670
+ console.log(_dedent2.default`
2671
+ \n
2672
+ ⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
2673
+
2674
+ ⭐️ Next steps:
2675
+ 1. Refer to documentation for help: https://docs.lingo.dev/
2676
+ 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
2677
+ 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
2678
+
2679
+
2680
+ `);
2681
+ process.exit(1);
2682
+ }
2683
+ }
2529
2684
  }
2530
2685
  LCPCache.ensureDictionaryFile({
2531
2686
  sourceRoot: params.sourceRoot,
@@ -2553,6 +2708,7 @@ var unplugin = _unplugin.createUnplugin.call(void 0,
2553
2708
  lingoDir: params.lingoDir
2554
2709
  });
2555
2710
  const dictionary = dictionaries[moduleInfo.params.locale];
2711
+ console.log(JSON.stringify(dictionary, null, 2));
2556
2712
  return {
2557
2713
  code: `export default ${JSON.stringify(dictionary, null, 2)}`
2558
2714
  };
@@ -2621,10 +2777,12 @@ var src_default = {
2621
2777
  return config2;
2622
2778
  }
2623
2779
  };
2624
- function validateLLMKeyDetails(models) {
2625
- const configuredProviders = _lodash2.default.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
2780
+ function getConfiguredProviders(models) {
2781
+ return _lodash2.default.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
2626
2782
  (providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
2627
2783
  ).value();
2784
+ }
2785
+ function validateLLMKeyDetails(configuredProviders) {
2628
2786
  if (configuredProviders.length === 0) {
2629
2787
  return;
2630
2788
  }
package/build/index.d.cts CHANGED
@@ -8,7 +8,7 @@ type CompilerParams = {
8
8
  rsc: boolean;
9
9
  useDirective: boolean;
10
10
  debug: boolean;
11
- models: Record<string, string>;
11
+ models: "lingo.dev" | Record<string, string>;
12
12
  };
13
13
  declare const defaultParams: CompilerParams;
14
14
 
package/build/index.d.ts CHANGED
@@ -8,7 +8,7 @@ type CompilerParams = {
8
8
  rsc: boolean;
9
9
  useDirective: boolean;
10
10
  debug: boolean;
11
- models: Record<string, string>;
11
+ models: "lingo.dev" | Record<string, string>;
12
12
  };
13
13
  declare const defaultParams: CompilerParams;
14
14
 
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.2.4",
7
+ version: "0.3.0",
8
8
  description: "Lingo.dev Compiler",
9
9
  private: false,
10
10
  publishConfig: {
@@ -46,6 +46,8 @@ var package_default = {
46
46
  "@babel/parser": "^7.26.7",
47
47
  "@babel/traverse": "^7.27.4",
48
48
  "@babel/types": "^7.26.7",
49
+ "@lingo.dev/_sdk": "workspace:*",
50
+ "@openrouter/ai-sdk-provider": "^0.7.1",
49
51
  ai: "^4.2.10",
50
52
  dedent: "^1.6.0",
51
53
  dotenv: "^16.4.5",
@@ -53,11 +55,13 @@ var package_default = {
53
55
  ini: "^5.0.0",
54
56
  lodash: "^4.17.21",
55
57
  "object-hash": "^3.0.0",
58
+ "ollama-ai-provider": "^1.2.0",
56
59
  prettier: "^3.4.2",
57
60
  unplugin: "^2.1.2",
58
61
  vitest: "^2.1.4",
59
62
  zod: "^3.24.1"
60
- }
63
+ },
64
+ packageManager: "pnpm@9.12.3"
61
65
  };
62
66
 
63
67
  // src/index.ts
@@ -926,7 +930,10 @@ var LCPCache = class {
926
930
  // src/lib/lcp/api/index.ts
927
931
  import { createGroq } from "@ai-sdk/groq";
928
932
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
933
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
934
+ import { createOllama } from "ollama-ai-provider";
929
935
  import { generateText } from "ai";
936
+ import { LingoDotDevEngine } from "@lingo.dev/_sdk";
930
937
  import _6 from "lodash";
931
938
 
932
939
  // src/utils/locales.ts
@@ -949,7 +956,16 @@ function getLocaleModel(localeModels, sourceLocale, targetLocale) {
949
956
  ];
950
957
  const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
951
958
  if (modelKey) {
952
- const [provider, model] = localeModels[modelKey]?.split(":");
959
+ const value = localeModels[modelKey];
960
+ const firstColonIndex = value?.indexOf(":");
961
+ if (value && firstColonIndex !== -1 && firstColonIndex !== void 0) {
962
+ const provider2 = value.substring(0, firstColonIndex);
963
+ const model2 = value.substring(firstColonIndex + 1);
964
+ if (provider2 && model2) {
965
+ return { provider: provider2, model: model2 };
966
+ }
967
+ }
968
+ const [provider, model] = value?.split(":") || [];
953
969
  if (provider && model) {
954
970
  return { provider, model };
955
971
  }
@@ -1188,6 +1204,15 @@ function getGroqKeyFromRc() {
1188
1204
  function getGroqKeyFromEnv() {
1189
1205
  return getKeyFromEnv("GROQ_API_KEY");
1190
1206
  }
1207
+ function getLingoDotDevKeyFromEnv() {
1208
+ return getKeyFromEnv("LINGODOTDEV_API_KEY");
1209
+ }
1210
+ function getLingoDotDevKeyFromRc() {
1211
+ return getKeyFromRc("auth.apiKey");
1212
+ }
1213
+ function getLingoDotDevKey() {
1214
+ return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
1215
+ }
1191
1216
  function getGoogleKey() {
1192
1217
  return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
1193
1218
  }
@@ -1197,6 +1222,15 @@ function getGoogleKeyFromRc() {
1197
1222
  function getGoogleKeyFromEnv() {
1198
1223
  return getKeyFromEnv("GOOGLE_API_KEY");
1199
1224
  }
1225
+ function getOpenRouterKey() {
1226
+ return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
1227
+ }
1228
+ function getOpenRouterKeyFromRc() {
1229
+ return getKeyFromRc("llm.openrouterApiKey");
1230
+ }
1231
+ function getOpenRouterKeyFromEnv() {
1232
+ return getKeyFromEnv("OPENROUTER_API_KEY");
1233
+ }
1200
1234
 
1201
1235
  // src/lib/lcp/api/index.ts
1202
1236
  import dedent2 from "dedent";
@@ -1222,6 +1256,22 @@ var providerDetails = {
1222
1256
  apiKeyConfigKey: "llm.googleApiKey",
1223
1257
  getKeyLink: "https://ai.google.dev/",
1224
1258
  docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
1259
+ },
1260
+ openrouter: {
1261
+ name: "OpenRouter",
1262
+ apiKeyEnvVar: "OPENROUTER_API_KEY",
1263
+ apiKeyConfigKey: "llm.openrouterApiKey",
1264
+ getKeyLink: "https://openrouter.ai",
1265
+ docsLink: "https://openrouter.ai/docs"
1266
+ },
1267
+ ollama: {
1268
+ name: "Ollama",
1269
+ apiKeyEnvVar: void 0,
1270
+ // Ollama doesn't require an API key
1271
+ apiKeyConfigKey: void 0,
1272
+ // Ollama doesn't require an API key
1273
+ getKeyLink: "https://ollama.com/download",
1274
+ docsLink: "https://github.com/ollama/ollama/tree/main/docs"
1225
1275
  }
1226
1276
  };
1227
1277
 
@@ -1308,59 +1358,118 @@ var LCPAPI = class {
1308
1358
  };
1309
1359
  return dictionary;
1310
1360
  }
1311
- static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
1312
- const { provider, model } = getLocaleModel(
1313
- models,
1314
- sourceLocale,
1315
- targetLocale
1316
- );
1317
- if (!provider || !model) {
1361
+ static _createLingoDotDevEngine() {
1362
+ if (isRunningInCIOrDocker()) {
1363
+ const apiKeyFromEnv = getLingoDotDevKeyFromEnv();
1364
+ if (!apiKeyFromEnv) {
1365
+ this._failMissingLLMKeyCi("lingo.dev");
1366
+ }
1367
+ }
1368
+ const apiKey = getLingoDotDevKey();
1369
+ if (!apiKey) {
1318
1370
  throw new Error(
1319
- `\u26A0\uFE0F Locale "${targetLocale}" is not configured. Add provider and model for this locale to your config, e.g., "groq:llama3-8b-8192".`
1371
+ "\u26A0\uFE0F Lingo.dev API key not found. Please set LINGODOTDEV_API_KEY environment variable or configure it user-wide."
1320
1372
  );
1321
1373
  }
1322
- try {
1323
- const aiModel = this._createAiModel(provider, model, targetLocale);
1324
- console.log(
1325
- `\u2728 Using model "${model}" from "${provider}" to translate from "${sourceLocale}" to "${targetLocale}"`
1326
- );
1327
- const response = await generateText({
1328
- model: aiModel,
1329
- messages: [
1374
+ console.log(`Creating Lingo.dev client`);
1375
+ return new LingoDotDevEngine({
1376
+ apiKey
1377
+ });
1378
+ }
1379
+ static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale) {
1380
+ if (models === "lingo.dev") {
1381
+ try {
1382
+ const lingoDotDevEngine = this._createLingoDotDevEngine();
1383
+ console.log(
1384
+ `\u2728 Using Lingo.dev Engine to localize from "${sourceLocale}" to "${targetLocale}"`
1385
+ );
1386
+ const result = await lingoDotDevEngine.localizeObject(
1387
+ sourceDictionary,
1330
1388
  {
1331
- role: "system",
1332
- content: prompt_default({ sourceLocale, targetLocale })
1333
- },
1334
- ...shots_default.flatMap((shotsTuple) => [
1389
+ sourceLocale,
1390
+ targetLocale
1391
+ }
1392
+ );
1393
+ return result;
1394
+ } catch (error) {
1395
+ this._failLLMFailureLocal(
1396
+ "lingo.dev",
1397
+ targetLocale,
1398
+ error instanceof Error ? error.message : "Unknown error"
1399
+ );
1400
+ throw error;
1401
+ }
1402
+ } else {
1403
+ const { provider, model } = getLocaleModel(
1404
+ models,
1405
+ sourceLocale,
1406
+ targetLocale
1407
+ );
1408
+ if (!provider || !model) {
1409
+ throw new Error(
1410
+ dedent2`
1411
+ 🚫 Lingo.dev Localization Engine Not Configured!
1412
+
1413
+ The "models" parameter is missing or incomplete in your Lingo.dev configuration.
1414
+
1415
+ 👉 To fix this, set the "models" parameter to either:
1416
+ • "lingo.dev" (for the default engine)
1417
+ • a map of locale-to-model, e.g. { "models": { "en:es": "openai:gpt-3.5-turbo" } }
1418
+
1419
+ Example:
1420
+ {
1421
+ // ...
1422
+ "models": "lingo.dev"
1423
+ }
1424
+
1425
+ For more details, see: https://lingo.dev/compiler
1426
+ To get help, join our Discord: https://lingo.dev/go/discord
1427
+ `
1428
+ );
1429
+ }
1430
+ try {
1431
+ const aiModel = this._createAiModel(provider, model, targetLocale);
1432
+ console.log(
1433
+ `\u2139\uFE0F Using raw LLM API ("${provider}":"${model}") to translate from "${sourceLocale}" to "${targetLocale}"`
1434
+ );
1435
+ const response = await generateText({
1436
+ model: aiModel,
1437
+ messages: [
1335
1438
  {
1336
- role: "user",
1337
- content: obj2xml(shotsTuple[0])
1439
+ role: "system",
1440
+ content: prompt_default({ sourceLocale, targetLocale })
1338
1441
  },
1442
+ ...shots_default.flatMap((shotsTuple) => [
1443
+ {
1444
+ role: "user",
1445
+ content: obj2xml(shotsTuple[0])
1446
+ },
1447
+ {
1448
+ role: "assistant",
1449
+ content: obj2xml(shotsTuple[1])
1450
+ }
1451
+ ]),
1339
1452
  {
1340
- role: "assistant",
1341
- content: obj2xml(shotsTuple[1])
1453
+ role: "user",
1454
+ content: obj2xml(sourceDictionary)
1342
1455
  }
1343
- ]),
1344
- {
1345
- role: "user",
1346
- content: obj2xml(sourceDictionary)
1347
- }
1348
- ]
1349
- });
1350
- console.log("Response text received for", targetLocale);
1351
- let responseText = response.text;
1352
- responseText = responseText.substring(
1353
- responseText.indexOf("<"),
1354
- responseText.lastIndexOf(">") + 1
1355
- );
1356
- return xml2obj(responseText);
1357
- } catch (error) {
1358
- this._failLLMFailureLocal(
1359
- provider,
1360
- targetLocale,
1361
- error instanceof Error ? error.message : "Unknown error"
1362
- );
1363
- throw error;
1456
+ ]
1457
+ });
1458
+ console.log("Response text received for", targetLocale);
1459
+ let responseText = response.text;
1460
+ responseText = responseText.substring(
1461
+ responseText.indexOf("<"),
1462
+ responseText.lastIndexOf(">") + 1
1463
+ );
1464
+ return xml2obj(responseText);
1465
+ } catch (error) {
1466
+ this._failLLMFailureLocal(
1467
+ provider,
1468
+ targetLocale,
1469
+ error instanceof Error ? error.message : "Unknown error"
1470
+ );
1471
+ throw error;
1472
+ }
1364
1473
  }
1365
1474
  }
1366
1475
  /**
@@ -1374,7 +1483,7 @@ var LCPAPI = class {
1374
1483
  */
1375
1484
  static _createAiModel(providerId, modelId, targetLocale) {
1376
1485
  switch (providerId) {
1377
- case "groq":
1486
+ case "groq": {
1378
1487
  if (isRunningInCIOrDocker()) {
1379
1488
  const groqFromEnv = getGroqKeyFromEnv();
1380
1489
  if (!groqFromEnv) {
@@ -1391,7 +1500,8 @@ var LCPAPI = class {
1391
1500
  `Creating Groq client for ${targetLocale} using model ${modelId}`
1392
1501
  );
1393
1502
  return createGroq({ apiKey: groqKey })(modelId);
1394
- case "google":
1503
+ }
1504
+ case "google": {
1395
1505
  if (isRunningInCIOrDocker()) {
1396
1506
  const googleFromEnv = getGoogleKeyFromEnv();
1397
1507
  if (!googleFromEnv) {
@@ -1408,10 +1518,38 @@ var LCPAPI = class {
1408
1518
  `Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
1409
1519
  );
1410
1520
  return createGoogleGenerativeAI({ apiKey: googleKey })(modelId);
1411
- default:
1521
+ }
1522
+ case "openrouter": {
1523
+ if (isRunningInCIOrDocker()) {
1524
+ const openRouterFromEnv = getOpenRouterKeyFromEnv();
1525
+ if (!openRouterFromEnv) {
1526
+ this._failMissingLLMKeyCi(providerId);
1527
+ }
1528
+ }
1529
+ const openRouterKey = getOpenRouterKey();
1530
+ if (!openRouterKey) {
1531
+ throw new Error(
1532
+ "\u26A0\uFE0F OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide."
1533
+ );
1534
+ }
1535
+ console.log(
1536
+ `Creating OpenRouter client for ${targetLocale} using model ${modelId}`
1537
+ );
1538
+ return createOpenRouter({
1539
+ apiKey: openRouterKey
1540
+ })(modelId);
1541
+ }
1542
+ case "ollama": {
1543
+ console.log(
1544
+ `Creating Ollama client for ${targetLocale} using model ${modelId} at default Ollama address`
1545
+ );
1546
+ return createOllama()(modelId);
1547
+ }
1548
+ default: {
1412
1549
  throw new Error(
1413
1550
  `\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq" and "google" providers are supported at the moment.`
1414
1551
  );
1552
+ }
1415
1553
  }
1416
1554
  }
1417
1555
  /**
@@ -1500,7 +1638,7 @@ var LCPAPI = class {
1500
1638
  This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
1501
1639
 
1502
1640
  ⭐️ Also:
1503
- 1. Did you set ${details.apiKeyEnvVar} environment variable correctly?
1641
+ 1. Did you set ${details.apiKeyEnvVar ? `${details.apiKeyEnvVar}` : "the provider API key"} environment variable correctly ${!details.apiKeyEnvVar ? "(if required)" : ""}?
1504
1642
  2. Did you reach any limits of your ${details.name} account?
1505
1643
  3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
1506
1644
 
@@ -1514,31 +1652,39 @@ var LCPAPI = class {
1514
1652
 
1515
1653
  // src/lib/lcp/server.ts
1516
1654
  var LCPServer = class {
1517
- static isLoading = false;
1655
+ static dictionariesCache = null;
1656
+ static inFlightPromise = null;
1518
1657
  static async loadDictionaries(params) {
1519
- while (this.isLoading) {
1520
- await new Promise(function(resolve3) {
1521
- setTimeout(resolve3, 500);
1522
- });
1658
+ if (this.dictionariesCache) {
1659
+ return this.dictionariesCache;
1523
1660
  }
1524
- this.isLoading = true;
1525
- const targetLocales = _7.uniq([
1526
- ...params.targetLocales,
1527
- params.sourceLocale
1528
- ]);
1529
- const dictionaries = await Promise.all(
1530
- targetLocales.map(
1531
- (targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
1532
- )
1533
- );
1534
- const result = _7.fromPairs(
1535
- targetLocales.map((targetLocale, index) => [
1536
- targetLocale,
1537
- dictionaries[index]
1538
- ])
1539
- );
1540
- this.isLoading = false;
1541
- return result;
1661
+ if (this.inFlightPromise) {
1662
+ return this.inFlightPromise;
1663
+ }
1664
+ this.inFlightPromise = (async () => {
1665
+ try {
1666
+ const targetLocales = _7.uniq([
1667
+ ...params.targetLocales,
1668
+ params.sourceLocale
1669
+ ]);
1670
+ const dictionaries = await Promise.all(
1671
+ targetLocales.map(
1672
+ (targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
1673
+ )
1674
+ );
1675
+ const result = _7.fromPairs(
1676
+ targetLocales.map((targetLocale, index) => [
1677
+ targetLocale,
1678
+ dictionaries[index]
1679
+ ])
1680
+ );
1681
+ this.dictionariesCache = result;
1682
+ return result;
1683
+ } finally {
1684
+ this.inFlightPromise = null;
1685
+ }
1686
+ })();
1687
+ return this.inFlightPromise;
1542
1688
  }
1543
1689
  static async loadDictionaryForLocale(params) {
1544
1690
  const sourceDictionary = this._extractSourceDictionary(
@@ -1710,7 +1856,7 @@ var LCPServer = class {
1710
1856
  fileName,
1711
1857
  {
1712
1858
  ...targetFile,
1713
- entries: _7.merge(targetFile?.entries || {}, entries)
1859
+ entries: _7.merge({}, targetFile?.entries || {}, entries)
1714
1860
  }
1715
1861
  ];
1716
1862
  }).fromPairs().value();
@@ -2499,6 +2645,10 @@ var keyCheckers = {
2499
2645
  google: {
2500
2646
  checkEnv: getGoogleKeyFromEnv,
2501
2647
  checkRc: getGoogleKeyFromRc
2648
+ },
2649
+ "lingo.dev": {
2650
+ checkEnv: getLingoDotDevKeyFromEnv,
2651
+ checkRc: getLingoDotDevKeyFromRc
2502
2652
  }
2503
2653
  };
2504
2654
  var unplugin = createUnplugin(
@@ -2506,26 +2656,31 @@ var unplugin = createUnplugin(
2506
2656
  console.log("\u2139\uFE0F Starting Lingo.dev compiler...");
2507
2657
  const params = _11.defaults(_params, defaultParams);
2508
2658
  if (!isRunningInCIOrDocker()) {
2509
- validateLLMKeyDetails(params.models);
2510
- }
2511
- const invalidLocales = getInvalidLocales(
2512
- params.models,
2513
- params.sourceLocale,
2514
- params.targetLocales
2515
- );
2516
- if (invalidLocales.length > 0) {
2517
- console.log(dedent3`
2518
- \n
2519
- ⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
2520
-
2521
- ⭐️ Next steps:
2522
- 1. Refer to documentation for help: https://docs.lingo.dev/
2523
- 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
2524
- 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
2525
-
2526
-
2527
- `);
2528
- process.exit(1);
2659
+ if (params.models === "lingo.dev") {
2660
+ validateLLMKeyDetails(["lingo.dev"]);
2661
+ } else {
2662
+ const configuredProviders = getConfiguredProviders(params.models);
2663
+ validateLLMKeyDetails(configuredProviders);
2664
+ const invalidLocales = getInvalidLocales(
2665
+ params.models,
2666
+ params.sourceLocale,
2667
+ params.targetLocales
2668
+ );
2669
+ if (invalidLocales.length > 0) {
2670
+ console.log(dedent3`
2671
+ \n
2672
+ ⚠️ Lingo.dev Localization Compiler requires LLM model setup for the following locales: ${invalidLocales.join(", ")}.
2673
+
2674
+ ⭐️ Next steps:
2675
+ 1. Refer to documentation for help: https://docs.lingo.dev/
2676
+ 2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
2677
+ 3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
2678
+
2679
+
2680
+ `);
2681
+ process.exit(1);
2682
+ }
2683
+ }
2529
2684
  }
2530
2685
  LCPCache.ensureDictionaryFile({
2531
2686
  sourceRoot: params.sourceRoot,
@@ -2553,6 +2708,7 @@ var unplugin = createUnplugin(
2553
2708
  lingoDir: params.lingoDir
2554
2709
  });
2555
2710
  const dictionary = dictionaries[moduleInfo.params.locale];
2711
+ console.log(JSON.stringify(dictionary, null, 2));
2556
2712
  return {
2557
2713
  code: `export default ${JSON.stringify(dictionary, null, 2)}`
2558
2714
  };
@@ -2621,10 +2777,12 @@ var src_default = {
2621
2777
  return config2;
2622
2778
  }
2623
2779
  };
2624
- function validateLLMKeyDetails(models) {
2625
- const configuredProviders = _11.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
2780
+ function getConfiguredProviders(models) {
2781
+ return _11.chain(Object.values(models)).map((modelString) => modelString.split(":")[0]).filter(Boolean).uniq().filter(
2626
2782
  (providerId) => providerDetails.hasOwnProperty(providerId) && keyCheckers.hasOwnProperty(providerId)
2627
2783
  ).value();
2784
+ }
2785
+ function validateLLMKeyDetails(configuredProviders) {
2628
2786
  if (configuredProviders.length === 0) {
2629
2787
  return;
2630
2788
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingo.dev/_compiler",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Lingo.dev Compiler",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -35,6 +35,7 @@
35
35
  "@babel/parser": "^7.26.7",
36
36
  "@babel/traverse": "^7.27.4",
37
37
  "@babel/types": "^7.26.7",
38
+ "@openrouter/ai-sdk-provider": "^0.7.1",
38
39
  "ai": "^4.2.10",
39
40
  "dedent": "^1.6.0",
40
41
  "dotenv": "^16.4.5",
@@ -42,10 +43,12 @@
42
43
  "ini": "^5.0.0",
43
44
  "lodash": "^4.17.21",
44
45
  "object-hash": "^3.0.0",
46
+ "ollama-ai-provider": "^1.2.0",
45
47
  "prettier": "^3.4.2",
46
48
  "unplugin": "^2.1.2",
47
49
  "vitest": "^2.1.4",
48
- "zod": "^3.24.1"
50
+ "zod": "^3.24.1",
51
+ "@lingo.dev/_sdk": "0.9.1"
49
52
  },
50
53
  "scripts": {
51
54
  "dev": "tsup --watch",