lingo.dev 0.97.5 → 0.99.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/cli.cjs CHANGED
@@ -30,7 +30,8 @@ function getSettings(explicitApiKey) {
30
30
  openaiApiKey: env.OPENAI_API_KEY || _optionalChain([systemFile, 'access', _40 => _40.llm, 'optionalAccess', _41 => _41.openaiApiKey]),
31
31
  anthropicApiKey: env.ANTHROPIC_API_KEY || _optionalChain([systemFile, 'access', _42 => _42.llm, 'optionalAccess', _43 => _43.anthropicApiKey]),
32
32
  groqApiKey: env.GROQ_API_KEY || _optionalChain([systemFile, 'access', _44 => _44.llm, 'optionalAccess', _45 => _45.groqApiKey]),
33
- googleApiKey: env.GOOGLE_API_KEY || _optionalChain([systemFile, 'access', _46 => _46.llm, 'optionalAccess', _47 => _47.googleApiKey])
33
+ googleApiKey: env.GOOGLE_API_KEY || _optionalChain([systemFile, 'access', _46 => _46.llm, 'optionalAccess', _47 => _47.googleApiKey]),
34
+ openrouterApiKey: env.OPENROUTER_API_KEY || _optionalChain([systemFile, 'access', _48 => _48.llm, 'optionalAccess', _49 => _49.openrouterApiKey])
34
35
  }
35
36
  };
36
37
  }
@@ -59,7 +60,8 @@ var SettingsSchema = _zod2.default.object({
59
60
  openaiApiKey: _zod2.default.string().optional(),
60
61
  anthropicApiKey: _zod2.default.string().optional(),
61
62
  groqApiKey: _zod2.default.string().optional(),
62
- googleApiKey: _zod2.default.string().optional()
63
+ googleApiKey: _zod2.default.string().optional(),
64
+ openrouterApiKey: _zod2.default.string().optional()
63
65
  })
64
66
  });
65
67
  var SETTINGS_KEYS = flattenZodObject(
@@ -83,7 +85,8 @@ function _loadEnv() {
83
85
  OPENAI_API_KEY: _zod2.default.string().optional(),
84
86
  ANTHROPIC_API_KEY: _zod2.default.string().optional(),
85
87
  GROQ_API_KEY: _zod2.default.string().optional(),
86
- GOOGLE_API_KEY: _zod2.default.string().optional()
88
+ GOOGLE_API_KEY: _zod2.default.string().optional(),
89
+ OPENROUTER_API_KEY: _zod2.default.string().optional()
87
90
  }).passthrough().parse(process.env);
88
91
  }
89
92
  function _loadSystemFile() {
@@ -100,7 +103,8 @@ function _loadSystemFile() {
100
103
  openaiApiKey: _zod2.default.string().optional(),
101
104
  anthropicApiKey: _zod2.default.string().optional(),
102
105
  groqApiKey: _zod2.default.string().optional(),
103
- googleApiKey: _zod2.default.string().optional()
106
+ googleApiKey: _zod2.default.string().optional(),
107
+ openrouterApiKey: _zod2.default.string().optional()
104
108
  }).optional()
105
109
  }).passthrough().parse(data);
106
110
  }
@@ -133,36 +137,42 @@ Please use LINGODOTDEV_API_KEY instead.
133
137
  function _envVarsInfo() {
134
138
  const env = _loadEnv();
135
139
  const systemFile = _loadSystemFile();
136
- if (env.LINGODOTDEV_API_KEY && _optionalChain([systemFile, 'access', _48 => _48.auth, 'optionalAccess', _49 => _49.apiKey])) {
140
+ if (env.LINGODOTDEV_API_KEY && _optionalChain([systemFile, 'access', _50 => _50.auth, 'optionalAccess', _51 => _51.apiKey])) {
137
141
  console.info(
138
142
  "\x1B[36m%s\x1B[0m",
139
143
  `\u2139\uFE0F Using LINGODOTDEV_API_KEY env var instead of credentials from user config`
140
144
  );
141
145
  }
142
- if (env.OPENAI_API_KEY && _optionalChain([systemFile, 'access', _50 => _50.llm, 'optionalAccess', _51 => _51.openaiApiKey])) {
146
+ if (env.OPENAI_API_KEY && _optionalChain([systemFile, 'access', _52 => _52.llm, 'optionalAccess', _53 => _53.openaiApiKey])) {
143
147
  console.info(
144
148
  "\x1B[36m%s\x1B[0m",
145
149
  `\u2139\uFE0F Using OPENAI_API_KEY env var instead of key from user config.`
146
150
  );
147
151
  }
148
- if (env.ANTHROPIC_API_KEY && _optionalChain([systemFile, 'access', _52 => _52.llm, 'optionalAccess', _53 => _53.anthropicApiKey])) {
152
+ if (env.ANTHROPIC_API_KEY && _optionalChain([systemFile, 'access', _54 => _54.llm, 'optionalAccess', _55 => _55.anthropicApiKey])) {
149
153
  console.info(
150
154
  "\x1B[36m%s\x1B[0m",
151
155
  `\u2139\uFE0F Using ANTHROPIC_API_KEY env var instead of key from user config`
152
156
  );
153
157
  }
154
- if (env.GROQ_API_KEY && _optionalChain([systemFile, 'access', _54 => _54.llm, 'optionalAccess', _55 => _55.groqApiKey])) {
158
+ if (env.GROQ_API_KEY && _optionalChain([systemFile, 'access', _56 => _56.llm, 'optionalAccess', _57 => _57.groqApiKey])) {
155
159
  console.info(
156
160
  "\x1B[36m%s\x1B[0m",
157
161
  `\u2139\uFE0F Using GROQ_API_KEY env var instead of key from user config`
158
162
  );
159
163
  }
160
- if (env.GOOGLE_API_KEY && _optionalChain([systemFile, 'access', _56 => _56.llm, 'optionalAccess', _57 => _57.googleApiKey])) {
164
+ if (env.GOOGLE_API_KEY && _optionalChain([systemFile, 'access', _58 => _58.llm, 'optionalAccess', _59 => _59.googleApiKey])) {
161
165
  console.info(
162
166
  "\x1B[36m%s\x1B[0m",
163
167
  `\u2139\uFE0F Using GOOGLE_API_KEY env var instead of key from user config`
164
168
  );
165
169
  }
170
+ if (env.OPENROUTER_API_KEY && _optionalChain([systemFile, 'access', _60 => _60.llm, 'optionalAccess', _61 => _61.openrouterApiKey])) {
171
+ console.info(
172
+ "\x1B[36m%s\x1B[0m",
173
+ `\u2139\uFE0F Using OPENROUTER_API_KEY env var instead of key from user config`
174
+ );
175
+ }
166
176
  if (env.LINGODOTDEV_API_URL) {
167
177
  console.info(
168
178
  "\x1B[36m%s\x1B[0m",
@@ -204,6 +214,26 @@ var CLIError = class extends Error {
204
214
  }
205
215
  };
206
216
 
217
+ // src/cli/utils/cloudflare-status.ts
218
+ async function checkCloudflareStatus() {
219
+ try {
220
+ const response = await fetch("https://www.cloudflarestatus.com/api/v2/status.json", {
221
+ signal: AbortSignal.timeout(5e3)
222
+ });
223
+ if (response.ok) {
224
+ return await response.json();
225
+ }
226
+ } catch (error) {
227
+ }
228
+ return null;
229
+ }
230
+ function formatCloudflareStatusMessage(status) {
231
+ if (status.status.indicator === "none") {
232
+ return "";
233
+ }
234
+ return `Cloudflare is experiencing ${status.status.indicator} issues: ${status.status.description}. This may be affecting the API connection.`;
235
+ }
236
+
207
237
  // src/cli/utils/auth.ts
208
238
  function createAuthenticator(params) {
209
239
  return {
@@ -218,7 +248,7 @@ function createAuthenticator(params) {
218
248
  });
219
249
  if (res.ok) {
220
250
  const payload = await res.json();
221
- if (!_optionalChain([payload, 'optionalAccess', _58 => _58.email])) {
251
+ if (!_optionalChain([payload, 'optionalAccess', _62 => _62.email])) {
222
252
  return null;
223
253
  }
224
254
  return {
@@ -226,8 +256,32 @@ function createAuthenticator(params) {
226
256
  id: payload.id
227
257
  };
228
258
  }
259
+ if (res.status >= 500 && res.status < 600) {
260
+ const originalErrorMessage = `Server error (${res.status}): ${res.statusText}. Please try again later.`;
261
+ const cloudflareStatus = await checkCloudflareStatus();
262
+ if (!cloudflareStatus) {
263
+ throw new CLIError({
264
+ message: originalErrorMessage,
265
+ docUrl: "connectionFailed"
266
+ });
267
+ }
268
+ if (cloudflareStatus.status.indicator !== "none") {
269
+ const cloudflareMessage = formatCloudflareStatusMessage(cloudflareStatus);
270
+ throw new CLIError({
271
+ message: cloudflareMessage,
272
+ docUrl: "connectionFailed"
273
+ });
274
+ }
275
+ throw new CLIError({
276
+ message: originalErrorMessage,
277
+ docUrl: "connectionFailed"
278
+ });
279
+ }
229
280
  return null;
230
281
  } catch (error) {
282
+ if (error instanceof CLIError) {
283
+ throw error;
284
+ }
231
285
  const isNetworkError = error instanceof TypeError && error.message === "fetch failed";
232
286
  if (isNetworkError) {
233
287
  throw new CLIError({
@@ -980,7 +1034,7 @@ var init_default = new (0, _interactivecommander.InteractiveCommand)().command("
980
1034
  });
981
1035
  const auth2 = await newAuthenticator.whoami();
982
1036
  if (auth2) {
983
- _ora2.default.call(void 0, ).succeed(`Authenticated as ${_optionalChain([auth2, 'optionalAccess', _59 => _59.email])}`);
1037
+ _ora2.default.call(void 0, ).succeed(`Authenticated as ${_optionalChain([auth2, 'optionalAccess', _63 => _63.email])}`);
984
1038
  } else {
985
1039
  _ora2.default.call(void 0, ).fail("Authentication failed.");
986
1040
  }
@@ -1065,7 +1119,7 @@ function getBuckets(i18nConfig) {
1065
1119
  const includeItems = bucketEntry.include.map(
1066
1120
  (item) => resolveBucketItem(item)
1067
1121
  );
1068
- const excludeItems = _optionalChain([bucketEntry, 'access', _60 => _60.exclude, 'optionalAccess', _61 => _61.map, 'call', _62 => _62(
1122
+ const excludeItems = _optionalChain([bucketEntry, 'access', _64 => _64.exclude, 'optionalAccess', _65 => _65.map, 'call', _66 => _66(
1069
1123
  (item) => resolveBucketItem(item)
1070
1124
  )]);
1071
1125
  const config = {
@@ -1103,7 +1157,7 @@ function extractPathPatterns(sourceLocale, include, exclude) {
1103
1157
  delimiter: pattern.delimiter
1104
1158
  }))
1105
1159
  );
1106
- const excludedPatterns = _optionalChain([exclude, 'optionalAccess', _63 => _63.flatMap, 'call', _64 => _64(
1160
+ const excludedPatterns = _optionalChain([exclude, 'optionalAccess', _67 => _67.flatMap, 'call', _68 => _68(
1107
1161
  (pattern) => expandPlaceholderedGlob(
1108
1162
  pattern.path,
1109
1163
  __spec.resolveOverriddenLocale.call(void 0, sourceLocale, pattern.delimiter)
@@ -1356,12 +1410,12 @@ function composeLoaders(...loaders) {
1356
1410
  return {
1357
1411
  init: async () => {
1358
1412
  for (const loader of loaders) {
1359
- await _optionalChain([loader, 'access', _65 => _65.init, 'optionalCall', _66 => _66()]);
1413
+ await _optionalChain([loader, 'access', _69 => _69.init, 'optionalCall', _70 => _70()]);
1360
1414
  }
1361
1415
  },
1362
1416
  setDefaultLocale(locale) {
1363
1417
  for (const loader of loaders) {
1364
- _optionalChain([loader, 'access', _67 => _67.setDefaultLocale, 'optionalCall', _68 => _68(locale)]);
1418
+ _optionalChain([loader, 'access', _71 => _71.setDefaultLocale, 'optionalCall', _72 => _72(locale)]);
1365
1419
  }
1366
1420
  return this;
1367
1421
  },
@@ -1394,7 +1448,7 @@ function createLoader(lDefinition) {
1394
1448
  if (state.initCtx) {
1395
1449
  return state.initCtx;
1396
1450
  }
1397
- state.initCtx = await _optionalChain([lDefinition, 'access', _69 => _69.init, 'optionalCall', _70 => _70()]);
1451
+ state.initCtx = await _optionalChain([lDefinition, 'access', _73 => _73.init, 'optionalCall', _74 => _74()]);
1398
1452
  return state.initCtx;
1399
1453
  },
1400
1454
  setDefaultLocale(locale) {
@@ -1499,7 +1553,7 @@ function createNormalizeLoader() {
1499
1553
  return normalized;
1500
1554
  },
1501
1555
  push: async (locale, data, originalInput) => {
1502
- const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _71 => _71.keysMap]), () => ( {}));
1556
+ const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _75 => _75.keysMap]), () => ( {}));
1503
1557
  const input2 = mapDenormalizedKeys(data, keysMap);
1504
1558
  const denormalized = _flat.unflatten.call(void 0, input2, {
1505
1559
  delimiter: "/",
@@ -1602,8 +1656,8 @@ async function getTrailingNewLine(pathPattern, locale, originalLocale) {
1602
1656
  if (!templateData) {
1603
1657
  templateData = await readFileForLocale(pathPattern, originalLocale);
1604
1658
  }
1605
- if (_optionalChain([templateData, 'optionalAccess', _72 => _72.match, 'call', _73 => _73(/[\r\n]$/)])) {
1606
- const ending = _optionalChain([templateData, 'optionalAccess', _74 => _74.includes, 'call', _75 => _75("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _76 => _76.includes, 'call', _77 => _77("\r")]) ? "\r" : "\n";
1659
+ if (_optionalChain([templateData, 'optionalAccess', _76 => _76.match, 'call', _77 => _77(/[\r\n]$/)])) {
1660
+ const ending = _optionalChain([templateData, 'optionalAccess', _78 => _78.includes, 'call', _79 => _79("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _80 => _80.includes, 'call', _81 => _81("\r")]) ? "\r" : "\n";
1607
1661
  return ending;
1608
1662
  }
1609
1663
  return "";
@@ -1867,7 +1921,7 @@ var _sync3 = require('csv-stringify/sync');
1867
1921
 
1868
1922
  function detectKeyColumnName(csvString) {
1869
1923
  const row = _sync.parse.call(void 0, csvString)[0];
1870
- const firstColumn = _optionalChain([row, 'optionalAccess', _78 => _78[0], 'optionalAccess', _79 => _79.trim, 'call', _80 => _80()]);
1924
+ const firstColumn = _optionalChain([row, 'optionalAccess', _82 => _82[0], 'optionalAccess', _83 => _83.trim, 'call', _84 => _84()]);
1871
1925
  return firstColumn || "KEY";
1872
1926
  }
1873
1927
  function createCsvLoader() {
@@ -1965,7 +2019,7 @@ function createHtmlLoader() {
1965
2019
  break;
1966
2020
  }
1967
2021
  const siblings = Array.from(parent.childNodes).filter(
1968
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _81 => _81.textContent, 'optionalAccess', _82 => _82.trim, 'call', _83 => _83()])
2022
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _85 => _85.textContent, 'optionalAccess', _86 => _86.trim, 'call', _87 => _87()])
1969
2023
  );
1970
2024
  const index = siblings.indexOf(current);
1971
2025
  if (index !== -1) {
@@ -2000,11 +2054,11 @@ function createHtmlLoader() {
2000
2054
  result[getPath(element, attr)] = value;
2001
2055
  }
2002
2056
  });
2003
- Array.from(element.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _84 => _84.textContent, 'optionalAccess', _85 => _85.trim, 'call', _86 => _86()])).forEach(processNode);
2057
+ Array.from(element.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _88 => _88.textContent, 'optionalAccess', _89 => _89.trim, 'call', _90 => _90()])).forEach(processNode);
2004
2058
  }
2005
2059
  };
2006
- Array.from(document.head.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _87 => _87.textContent, 'optionalAccess', _88 => _88.trim, 'call', _89 => _89()])).forEach(processNode);
2007
- Array.from(document.body.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _90 => _90.textContent, 'optionalAccess', _91 => _91.trim, 'call', _92 => _92()])).forEach(processNode);
2060
+ Array.from(document.head.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _91 => _91.textContent, 'optionalAccess', _92 => _92.trim, 'call', _93 => _93()])).forEach(processNode);
2061
+ Array.from(document.body.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _94 => _94.textContent, 'optionalAccess', _95 => _95.trim, 'call', _96 => _96()])).forEach(processNode);
2008
2062
  return result;
2009
2063
  },
2010
2064
  async push(locale, data, originalInput) {
@@ -2026,7 +2080,7 @@ function createHtmlLoader() {
2026
2080
  for (let i = 0; i < indices.length; i++) {
2027
2081
  const index = parseInt(indices[i]);
2028
2082
  const siblings = Array.from(parent.childNodes).filter(
2029
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _93 => _93.textContent, 'optionalAccess', _94 => _94.trim, 'call', _95 => _95()])
2083
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _97 => _97.textContent, 'optionalAccess', _98 => _98.trim, 'call', _99 => _99()])
2030
2084
  );
2031
2085
  if (index >= siblings.length) {
2032
2086
  if (i === indices.length - 1) {
@@ -2077,7 +2131,7 @@ function createMarkdownLoader() {
2077
2131
  yaml: yamlEngine
2078
2132
  }
2079
2133
  });
2080
- const sections = content.split(SECTION_REGEX).map((section) => _nullishCoalesce(_optionalChain([section, 'optionalAccess', _96 => _96.trim, 'call', _97 => _97()]), () => ( ""))).filter(Boolean);
2134
+ const sections = content.split(SECTION_REGEX).map((section) => _nullishCoalesce(_optionalChain([section, 'optionalAccess', _100 => _100.trim, 'call', _101 => _101()]), () => ( ""))).filter(Boolean);
2081
2135
  return {
2082
2136
  ...Object.fromEntries(
2083
2137
  sections.map((section, index) => [`${MD_SECTION_PREFIX}${index}`, section]).filter(([, section]) => Boolean(section))
@@ -2089,7 +2143,7 @@ function createMarkdownLoader() {
2089
2143
  const frontmatter = Object.fromEntries(
2090
2144
  Object.entries(data).filter(([key]) => key.startsWith(FM_ATTR_PREFIX)).map(([key, value]) => [key.replace(FM_ATTR_PREFIX, ""), value])
2091
2145
  );
2092
- let content = Object.entries(data).filter(([key]) => key.startsWith(MD_SECTION_PREFIX)).sort(([a], [b]) => Number(a.split("-").pop()) - Number(b.split("-").pop())).map(([, value]) => _nullishCoalesce(_optionalChain([value, 'optionalAccess', _98 => _98.trim, 'call', _99 => _99()]), () => ( ""))).filter(Boolean).join("\n\n");
2146
+ let content = Object.entries(data).filter(([key]) => key.startsWith(MD_SECTION_PREFIX)).sort(([a], [b]) => Number(a.split("-").pop()) - Number(b.split("-").pop())).map(([, value]) => _nullishCoalesce(_optionalChain([value, 'optionalAccess', _102 => _102.trim, 'call', _103 => _103()]), () => ( ""))).filter(Boolean).join("\n\n");
2093
2147
  if (Object.keys(frontmatter).length > 0) {
2094
2148
  content = `
2095
2149
  ${content}`;
@@ -2133,7 +2187,7 @@ function isSkippableLine(line) {
2133
2187
  function parsePropertyLine(line) {
2134
2188
  const [key, ...valueParts] = line.split("=");
2135
2189
  return {
2136
- key: _optionalChain([key, 'optionalAccess', _100 => _100.trim, 'call', _101 => _101()]) || "",
2190
+ key: _optionalChain([key, 'optionalAccess', _104 => _104.trim, 'call', _105 => _105()]) || "",
2137
2191
  value: valueParts.join("=").trim()
2138
2192
  };
2139
2193
  }
@@ -2219,7 +2273,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2219
2273
  if (rootTranslationEntity.shouldTranslate === false) {
2220
2274
  continue;
2221
2275
  }
2222
- const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _102 => _102.localizations, 'optionalAccess', _103 => _103[locale]]);
2276
+ const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _106 => _106.localizations, 'optionalAccess', _107 => _107[locale]]);
2223
2277
  if (langTranslationEntity) {
2224
2278
  if ("stringUnit" in langTranslationEntity) {
2225
2279
  resultData[translationKey] = langTranslationEntity.stringUnit.value;
@@ -2228,7 +2282,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2228
2282
  resultData[translationKey] = {};
2229
2283
  const pluralForms = langTranslationEntity.variations.plural;
2230
2284
  for (const form in pluralForms) {
2231
- if (_optionalChain([pluralForms, 'access', _104 => _104[form], 'optionalAccess', _105 => _105.stringUnit, 'optionalAccess', _106 => _106.value])) {
2285
+ if (_optionalChain([pluralForms, 'access', _108 => _108[form], 'optionalAccess', _109 => _109.stringUnit, 'optionalAccess', _110 => _110.value])) {
2232
2286
  resultData[translationKey][form] = pluralForms[form].stringUnit.value;
2233
2287
  }
2234
2288
  }
@@ -2251,7 +2305,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2251
2305
  const hasDoNotTranslateFlag = originalInput && originalInput.strings && originalInput.strings[key] && originalInput.strings[key].shouldTranslate === false;
2252
2306
  if (typeof value === "string") {
2253
2307
  langDataToMerge.strings[key] = {
2254
- extractionState: _optionalChain([originalInput, 'optionalAccess', _107 => _107.strings, 'optionalAccess', _108 => _108[key], 'optionalAccess', _109 => _109.extractionState]),
2308
+ extractionState: _optionalChain([originalInput, 'optionalAccess', _111 => _111.strings, 'optionalAccess', _112 => _112[key], 'optionalAccess', _113 => _113.extractionState]),
2255
2309
  localizations: {
2256
2310
  [locale]: {
2257
2311
  stringUnit: {
@@ -2434,7 +2488,7 @@ function createPoDataLoader(params) {
2434
2488
  Object.entries(entries).forEach(([msgid, entry]) => {
2435
2489
  if (msgid && entry.msgid) {
2436
2490
  const context = entry.msgctxt || "";
2437
- const fullEntry = _optionalChain([parsedPo, 'access', _110 => _110.translations, 'access', _111 => _111[context], 'optionalAccess', _112 => _112[msgid]]);
2491
+ const fullEntry = _optionalChain([parsedPo, 'access', _114 => _114.translations, 'access', _115 => _115[context], 'optionalAccess', _116 => _116[msgid]]);
2438
2492
  if (fullEntry) {
2439
2493
  result[msgid] = fullEntry;
2440
2494
  }
@@ -2444,8 +2498,8 @@ function createPoDataLoader(params) {
2444
2498
  return result;
2445
2499
  },
2446
2500
  async push(locale, data, originalInput, originalLocale, pullInput) {
2447
- const currentSections = _optionalChain([pullInput, 'optionalAccess', _113 => _113.split, 'call', _114 => _114("\n\n"), 'access', _115 => _115.filter, 'call', _116 => _116(Boolean)]) || [];
2448
- const originalSections = _optionalChain([originalInput, 'optionalAccess', _117 => _117.split, 'call', _118 => _118("\n\n"), 'access', _119 => _119.filter, 'call', _120 => _120(Boolean)]) || [];
2501
+ const currentSections = _optionalChain([pullInput, 'optionalAccess', _117 => _117.split, 'call', _118 => _118("\n\n"), 'access', _119 => _119.filter, 'call', _120 => _120(Boolean)]) || [];
2502
+ const originalSections = _optionalChain([originalInput, 'optionalAccess', _121 => _121.split, 'call', _122 => _122("\n\n"), 'access', _123 => _123.filter, 'call', _124 => _124(Boolean)]) || [];
2449
2503
  const result = originalSections.map((section) => {
2450
2504
  const sectionPo = _gettextparser2.default.po.parse(section);
2451
2505
  if (Object.keys(sectionPo.translations).length === 0) {
@@ -2514,8 +2568,8 @@ function createPoContentLoader() {
2514
2568
  {
2515
2569
  ...entry,
2516
2570
  msgstr: [
2517
- _optionalChain([data, 'access', _121 => _121[entry.msgid], 'optionalAccess', _122 => _122.singular]),
2518
- _optionalChain([data, 'access', _123 => _123[entry.msgid], 'optionalAccess', _124 => _124.plural]) || null
2571
+ _optionalChain([data, 'access', _125 => _125[entry.msgid], 'optionalAccess', _126 => _126.singular]),
2572
+ _optionalChain([data, 'access', _127 => _127[entry.msgid], 'optionalAccess', _128 => _128.plural]) || null
2519
2573
  ].filter(Boolean)
2520
2574
  }
2521
2575
  ]).fromPairs().value();
@@ -2791,7 +2845,7 @@ function createDatoClient(params) {
2791
2845
  only_valid: "true",
2792
2846
  ids: !records.length ? void 0 : records.join(",")
2793
2847
  }
2794
- }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _125 => _125.response, 'optionalAccess', _126 => _126.body, 'optionalAccess', _127 => _127.data, 'optionalAccess', _128 => _128[0]]) || error));
2848
+ }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _129 => _129.response, 'optionalAccess', _130 => _130.body, 'optionalAccess', _131 => _131.data, 'optionalAccess', _132 => _132[0]]) || error));
2795
2849
  },
2796
2850
  findRecordsForModel: async (modelId, records) => {
2797
2851
  try {
@@ -2801,9 +2855,9 @@ function createDatoClient(params) {
2801
2855
  filter: {
2802
2856
  type: modelId,
2803
2857
  only_valid: "true",
2804
- ids: !_optionalChain([records, 'optionalAccess', _129 => _129.length]) ? void 0 : records.join(",")
2858
+ ids: !_optionalChain([records, 'optionalAccess', _133 => _133.length]) ? void 0 : records.join(",")
2805
2859
  }
2806
- }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _130 => _130.response, 'optionalAccess', _131 => _131.body, 'optionalAccess', _132 => _132.data, 'optionalAccess', _133 => _133[0]]) || error));
2860
+ }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _134 => _134.response, 'optionalAccess', _135 => _135.body, 'optionalAccess', _136 => _136.data, 'optionalAccess', _137 => _137[0]]) || error));
2807
2861
  return result;
2808
2862
  } catch (_error) {
2809
2863
  throw new Error(
@@ -2817,9 +2871,9 @@ function createDatoClient(params) {
2817
2871
  },
2818
2872
  updateRecord: async (id, payload) => {
2819
2873
  try {
2820
- await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _134 => _134.response, 'optionalAccess', _135 => _135.body, 'optionalAccess', _136 => _136.data, 'optionalAccess', _137 => _137[0]]) || error));
2874
+ await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _138 => _138.response, 'optionalAccess', _139 => _139.body, 'optionalAccess', _140 => _140.data, 'optionalAccess', _141 => _141[0]]) || error));
2821
2875
  } catch (_error) {
2822
- if (_optionalChain([_error, 'optionalAccess', _138 => _138.attributes, 'optionalAccess', _139 => _139.details, 'optionalAccess', _140 => _140.message])) {
2876
+ if (_optionalChain([_error, 'optionalAccess', _142 => _142.attributes, 'optionalAccess', _143 => _143.details, 'optionalAccess', _144 => _144.message])) {
2823
2877
  throw new Error(
2824
2878
  [
2825
2879
  `${_error.attributes.details.message}`,
@@ -2840,9 +2894,9 @@ function createDatoClient(params) {
2840
2894
  },
2841
2895
  enableFieldLocalization: async (args) => {
2842
2896
  try {
2843
- await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _141 => _141.response, 'optionalAccess', _142 => _142.body, 'optionalAccess', _143 => _143.data, 'optionalAccess', _144 => _144[0]]) || error));
2897
+ await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _145 => _145.response, 'optionalAccess', _146 => _146.body, 'optionalAccess', _147 => _147.data, 'optionalAccess', _148 => _148[0]]) || error));
2844
2898
  } catch (_error) {
2845
- if (_optionalChain([_error, 'optionalAccess', _145 => _145.attributes, 'optionalAccess', _146 => _146.code]) === "NOT_FOUND") {
2899
+ if (_optionalChain([_error, 'optionalAccess', _149 => _149.attributes, 'optionalAccess', _150 => _150.code]) === "NOT_FOUND") {
2846
2900
  throw new Error(
2847
2901
  [
2848
2902
  `Field "${args.fieldId}" not found in model "${args.modelId}".`,
@@ -2850,7 +2904,7 @@ function createDatoClient(params) {
2850
2904
  ].join("\n\n")
2851
2905
  );
2852
2906
  }
2853
- if (_optionalChain([_error, 'optionalAccess', _147 => _147.attributes, 'optionalAccess', _148 => _148.details, 'optionalAccess', _149 => _149.message])) {
2907
+ if (_optionalChain([_error, 'optionalAccess', _151 => _151.attributes, 'optionalAccess', _152 => _152.details, 'optionalAccess', _153 => _153.message])) {
2854
2908
  throw new Error(
2855
2909
  [`${_error.attributes.details.message}`, `Error: ${JSON.stringify(_error, null, 2)}`].join("\n\n")
2856
2910
  );
@@ -2916,7 +2970,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
2916
2970
  }
2917
2971
  }
2918
2972
  const records = await dato.findRecordsForModel(modelId);
2919
- const recordChoices = createRecordChoices(records, _optionalChain([config, 'access', _150 => _150.models, 'access', _151 => _151[modelId], 'optionalAccess', _152 => _152.records]) || [], project);
2973
+ const recordChoices = createRecordChoices(records, _optionalChain([config, 'access', _154 => _154.models, 'access', _155 => _155[modelId], 'optionalAccess', _156 => _156.records]) || [], project);
2920
2974
  const selectedRecords = await promptRecordSelection(modelName, recordChoices);
2921
2975
  result.models[modelId].records = records.filter((record) => selectedRecords.includes(record.id));
2922
2976
  updatedConfig.models[modelId].records = selectedRecords;
@@ -2928,14 +2982,14 @@ function createDatoApiLoader(config, onConfigUpdate) {
2928
2982
  },
2929
2983
  async pull(locale, input2, initCtx) {
2930
2984
  const result = {};
2931
- for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _153 => _153.models]) || {})) {
2932
- let records = _optionalChain([initCtx, 'optionalAccess', _154 => _154.models, 'access', _155 => _155[modelId], 'access', _156 => _156.records]) || [];
2985
+ for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _157 => _157.models]) || {})) {
2986
+ let records = _optionalChain([initCtx, 'optionalAccess', _158 => _158.models, 'access', _159 => _159[modelId], 'access', _160 => _160.records]) || [];
2933
2987
  const recordIds = records.map((record) => record.id);
2934
2988
  records = await dato.findRecords(recordIds);
2935
2989
  console.log(`Fetched ${records.length} records for model ${modelId}`);
2936
2990
  if (records.length > 0) {
2937
2991
  result[modelId] = {
2938
- fields: _optionalChain([initCtx, 'optionalAccess', _157 => _157.models, 'optionalAccess', _158 => _158[modelId], 'optionalAccess', _159 => _159.fields]) || [],
2992
+ fields: _optionalChain([initCtx, 'optionalAccess', _161 => _161.models, 'optionalAccess', _162 => _162[modelId], 'optionalAccess', _163 => _163.fields]) || [],
2939
2993
  records
2940
2994
  };
2941
2995
  }
@@ -2994,7 +3048,7 @@ function createRecordChoices(records, selectedIds = [], project) {
2994
3048
  return records.map((record) => ({
2995
3049
  name: `${record.id} - https://${project.internal_domain}/editor/item_types/${record.item_type.id}/items/${record.id}`,
2996
3050
  value: record.id,
2997
- checked: _optionalChain([selectedIds, 'optionalAccess', _160 => _160.includes, 'call', _161 => _161(record.id)])
3051
+ checked: _optionalChain([selectedIds, 'optionalAccess', _164 => _164.includes, 'call', _165 => _165(record.id)])
2998
3052
  }));
2999
3053
  }
3000
3054
  async function promptRecordSelection(modelName, choices) {
@@ -3264,7 +3318,7 @@ function createVttLoader() {
3264
3318
  if (!input2) {
3265
3319
  return "";
3266
3320
  }
3267
- const vtt = _optionalChain([_nodewebvtt2.default, 'access', _162 => _162.parse, 'call', _163 => _163(input2), 'optionalAccess', _164 => _164.cues]);
3321
+ const vtt = _optionalChain([_nodewebvtt2.default, 'access', _166 => _166.parse, 'call', _167 => _167(input2), 'optionalAccess', _168 => _168.cues]);
3268
3322
  if (Object.keys(vtt).length === 0) {
3269
3323
  return {};
3270
3324
  } else {
@@ -3318,7 +3372,7 @@ function variableExtractLoader(params) {
3318
3372
  for (let i = 0; i < matches.length; i++) {
3319
3373
  const match = matches[i];
3320
3374
  const currentValue = result[key].value;
3321
- const newValue = _optionalChain([currentValue, 'optionalAccess', _165 => _165.replace, 'call', _166 => _166(match, `{variable:${i}}`)]);
3375
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _169 => _169.replace, 'call', _170 => _170(match, `{variable:${i}}`)]);
3322
3376
  result[key].value = newValue;
3323
3377
  result[key].variables[i] = match;
3324
3378
  }
@@ -3332,7 +3386,7 @@ function variableExtractLoader(params) {
3332
3386
  for (let i = 0; i < valueObj.variables.length; i++) {
3333
3387
  const variable = valueObj.variables[i];
3334
3388
  const currentValue = result[key];
3335
- const newValue = _optionalChain([currentValue, 'optionalAccess', _167 => _167.replace, 'call', _168 => _168(`{variable:${i}}`, variable)]);
3389
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _171 => _171.replace, 'call', _172 => _172(`{variable:${i}}`, variable)]);
3336
3390
  result[key] = newValue;
3337
3391
  }
3338
3392
  }
@@ -3515,7 +3569,7 @@ function createVueJsonLoader() {
3515
3569
  return createLoader({
3516
3570
  pull: async (locale, input2, ctx) => {
3517
3571
  const parsed = parseVueFile(input2);
3518
- return _nullishCoalesce(_optionalChain([parsed, 'optionalAccess', _169 => _169.i18n, 'optionalAccess', _170 => _170[locale]]), () => ( {}));
3572
+ return _nullishCoalesce(_optionalChain([parsed, 'optionalAccess', _173 => _173.i18n, 'optionalAccess', _174 => _174[locale]]), () => ( {}));
3519
3573
  },
3520
3574
  push: async (locale, data, originalInput) => {
3521
3575
  const parsed = parseVueFile(_nullishCoalesce(originalInput, () => ( "")));
@@ -3696,7 +3750,7 @@ function updateStringsInObjectExpression(objectExpression, data) {
3696
3750
  objectExpression.properties.forEach((prop) => {
3697
3751
  if (!t.isObjectProperty(prop)) return;
3698
3752
  const key = getPropertyKey(prop);
3699
- const incomingVal = _optionalChain([data, 'optionalAccess', _171 => _171[key]]);
3753
+ const incomingVal = _optionalChain([data, 'optionalAccess', _175 => _175[key]]);
3700
3754
  if (incomingVal === void 0) {
3701
3755
  return;
3702
3756
  }
@@ -3732,7 +3786,7 @@ function updateStringsInArrayExpression(arrayExpression, incoming) {
3732
3786
  let modified = false;
3733
3787
  arrayExpression.elements.forEach((element, index) => {
3734
3788
  if (!element) return;
3735
- const incomingVal = _optionalChain([incoming, 'optionalAccess', _172 => _172[index]]);
3789
+ const incomingVal = _optionalChain([incoming, 'optionalAccess', _176 => _176[index]]);
3736
3790
  if (incomingVal === void 0) return;
3737
3791
  if (t.isStringLiteral(element) && typeof incomingVal === "string") {
3738
3792
  if (element.value !== incomingVal) {
@@ -4008,7 +4062,7 @@ function createMdxSectionsSplit2Loader() {
4008
4062
  const content = _lodash2.default.chain(data.sections).values().join("\n\n").value();
4009
4063
  const result = {
4010
4064
  frontmatter: data.frontmatter,
4011
- codePlaceholders: _optionalChain([pullInput, 'optionalAccess', _173 => _173.codePlaceholders]) || {},
4065
+ codePlaceholders: _optionalChain([pullInput, 'optionalAccess', _177 => _177.codePlaceholders]) || {},
4012
4066
  content
4013
4067
  };
4014
4068
  return result;
@@ -4451,7 +4505,7 @@ function createBasicTranslator(model, systemPrompt) {
4451
4505
  ]
4452
4506
  });
4453
4507
  const result = JSON.parse(response.text);
4454
- return _optionalChain([result, 'optionalAccess', _174 => _174.data]) || {};
4508
+ return _optionalChain([result, 'optionalAccess', _178 => _178.data]) || {};
4455
4509
  }
4456
4510
  }
4457
4511
  function extractPayloadChunks(payload) {
@@ -4493,6 +4547,8 @@ function countWordsInRecord(payload) {
4493
4547
  var _openai = require('@ai-sdk/openai');
4494
4548
  var _anthropic = require('@ai-sdk/anthropic');
4495
4549
  var _google = require('@ai-sdk/google');
4550
+ var _aisdkprovider = require('@openrouter/ai-sdk-provider');
4551
+ var _ollamaaiprovider = require('ollama-ai-provider');
4496
4552
  function createProcessor(provider, params) {
4497
4553
  if (!provider) {
4498
4554
  const result = createLingoLocalizer(params);
@@ -4505,10 +4561,10 @@ function createProcessor(provider, params) {
4505
4561
  }
4506
4562
  function getPureModelProvider(provider) {
4507
4563
  const createMissingKeyErrorMessage = (providerId, envVar) => _dedent2.default`
4508
- You're trying to use raw ${_chalk2.default.dim(providerId)} API for translation, however, ${_chalk2.default.dim(envVar)} environment variable is not set.
4564
+ You're trying to use raw ${_chalk2.default.dim(providerId)} API for translation. ${envVar ? `However, ${_chalk2.default.dim(envVar)} environment variable is not set.` : "However, that provider is unavailable."}
4509
4565
 
4510
4566
  To fix this issue:
4511
- 1. Set ${_chalk2.default.dim(envVar)} in your environment variables, or
4567
+ 1. ${envVar ? `Set ${_chalk2.default.dim(envVar)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
4512
4568
  2. Remove the ${_chalk2.default.italic("provider")} node from your i18n.json configuration to switch to ${_chalk2.default.hex(colors.green)("Lingo.dev")}
4513
4569
 
4514
4570
  ${_chalk2.default.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
@@ -4522,8 +4578,8 @@ function getPureModelProvider(provider) {
4522
4578
 
4523
4579
  ${_chalk2.default.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
4524
4580
  `;
4525
- switch (_optionalChain([provider, 'optionalAccess', _175 => _175.id])) {
4526
- case "openai":
4581
+ switch (_optionalChain([provider, 'optionalAccess', _179 => _179.id])) {
4582
+ case "openai": {
4527
4583
  if (!process.env.OPENAI_API_KEY) {
4528
4584
  throw new Error(
4529
4585
  createMissingKeyErrorMessage("OpenAI", "OPENAI_API_KEY")
@@ -4533,7 +4589,8 @@ function getPureModelProvider(provider) {
4533
4589
  apiKey: process.env.OPENAI_API_KEY,
4534
4590
  baseURL: provider.baseUrl
4535
4591
  })(provider.model);
4536
- case "anthropic":
4592
+ }
4593
+ case "anthropic": {
4537
4594
  if (!process.env.ANTHROPIC_API_KEY) {
4538
4595
  throw new Error(
4539
4596
  createMissingKeyErrorMessage("Anthropic", "ANTHROPIC_API_KEY")
@@ -4542,7 +4599,8 @@ function getPureModelProvider(provider) {
4542
4599
  return _anthropic.createAnthropic.call(void 0, {
4543
4600
  apiKey: process.env.ANTHROPIC_API_KEY
4544
4601
  })(provider.model);
4545
- case "google":
4602
+ }
4603
+ case "google": {
4546
4604
  if (!process.env.GOOGLE_API_KEY) {
4547
4605
  throw new Error(
4548
4606
  createMissingKeyErrorMessage("Google", "GOOGLE_API_KEY")
@@ -4551,8 +4609,24 @@ function getPureModelProvider(provider) {
4551
4609
  return _google.createGoogleGenerativeAI.call(void 0, {
4552
4610
  apiKey: process.env.GOOGLE_API_KEY
4553
4611
  })(provider.model);
4554
- default:
4555
- throw new Error(createUnsupportedProviderErrorMessage(_optionalChain([provider, 'optionalAccess', _176 => _176.id])));
4612
+ }
4613
+ case "openrouter": {
4614
+ if (!process.env.OPENROUTER_API_KEY) {
4615
+ throw new Error(
4616
+ createMissingKeyErrorMessage("OpenRouter", "OPENROUTER_API_KEY")
4617
+ );
4618
+ }
4619
+ return _aisdkprovider.createOpenRouter.call(void 0, {
4620
+ apiKey: process.env.OPENROUTER_API_KEY,
4621
+ baseURL: provider.baseUrl
4622
+ })(provider.model);
4623
+ }
4624
+ case "ollama": {
4625
+ return _ollamaaiprovider.createOllama.call(void 0, )(provider.model);
4626
+ }
4627
+ default: {
4628
+ throw new Error(createUnsupportedProviderErrorMessage(_optionalChain([provider, 'optionalAccess', _180 => _180.id])));
4629
+ }
4556
4630
  }
4557
4631
  }
4558
4632
 
@@ -4776,7 +4850,7 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
4776
4850
  validateParams(i18nConfig, flags);
4777
4851
  ora.succeed("Localization configuration is valid");
4778
4852
  ora.start("Connecting to Lingo.dev Localization Engine...");
4779
- const isByokMode = !!_optionalChain([i18nConfig, 'optionalAccess', _177 => _177.provider]);
4853
+ const isByokMode = !!_optionalChain([i18nConfig, 'optionalAccess', _181 => _181.provider]);
4780
4854
  if (isByokMode) {
4781
4855
  authId = null;
4782
4856
  ora.succeed("Using external provider (BYOK mode)");
@@ -4790,16 +4864,16 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
4790
4864
  flags
4791
4865
  });
4792
4866
  let buckets = getBuckets(i18nConfig);
4793
- if (_optionalChain([flags, 'access', _178 => _178.bucket, 'optionalAccess', _179 => _179.length])) {
4867
+ if (_optionalChain([flags, 'access', _182 => _182.bucket, 'optionalAccess', _183 => _183.length])) {
4794
4868
  buckets = buckets.filter(
4795
4869
  (bucket) => flags.bucket.includes(bucket.type)
4796
4870
  );
4797
4871
  }
4798
4872
  ora.succeed("Buckets retrieved");
4799
- if (_optionalChain([flags, 'access', _180 => _180.file, 'optionalAccess', _181 => _181.length])) {
4873
+ if (_optionalChain([flags, 'access', _184 => _184.file, 'optionalAccess', _185 => _185.length])) {
4800
4874
  buckets = buckets.map((bucket) => {
4801
4875
  const paths = bucket.paths.filter(
4802
- (path16) => flags.file.find((file) => _optionalChain([path16, 'access', _182 => _182.pathPattern, 'optionalAccess', _183 => _183.includes, 'call', _184 => _184(file)]))
4876
+ (path16) => flags.file.find((file) => _optionalChain([path16, 'access', _186 => _186.pathPattern, 'optionalAccess', _187 => _187.includes, 'call', _188 => _188(file)]))
4803
4877
  );
4804
4878
  return { ...bucket, paths };
4805
4879
  }).filter((bucket) => bucket.paths.length > 0);
@@ -4818,7 +4892,7 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
4818
4892
  });
4819
4893
  }
4820
4894
  }
4821
- const targetLocales = _optionalChain([flags, 'access', _185 => _185.locale, 'optionalAccess', _186 => _186.length]) ? flags.locale : i18nConfig.locale.targets;
4895
+ const targetLocales = _optionalChain([flags, 'access', _189 => _189.locale, 'optionalAccess', _190 => _190.length]) ? flags.locale : i18nConfig.locale.targets;
4822
4896
  ora.start("Setting up localization cache...");
4823
4897
  const checkLockfileProcessor = createDeltaProcessor("");
4824
4898
  const lockfileExists = await checkLockfileProcessor.checkIfLockExists();
@@ -5162,12 +5236,12 @@ function validateParams(i18nConfig, flags) {
5162
5236
  message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
5163
5237
  docUrl: "bucketNotFound"
5164
5238
  });
5165
- } else if (_optionalChain([flags, 'access', _187 => _187.locale, 'optionalAccess', _188 => _188.some, 'call', _189 => _189((locale) => !i18nConfig.locale.targets.includes(locale))])) {
5239
+ } else if (_optionalChain([flags, 'access', _191 => _191.locale, 'optionalAccess', _192 => _192.some, 'call', _193 => _193((locale) => !i18nConfig.locale.targets.includes(locale))])) {
5166
5240
  throw new CLIError({
5167
5241
  message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
5168
5242
  docUrl: "localeTargetNotFound"
5169
5243
  });
5170
- } else if (_optionalChain([flags, 'access', _190 => _190.bucket, 'optionalAccess', _191 => _191.some, 'call', _192 => _192(
5244
+ } else if (_optionalChain([flags, 'access', _194 => _194.bucket, 'optionalAccess', _195 => _195.some, 'call', _196 => _196(
5171
5245
  (bucket) => !i18nConfig.buckets[bucket]
5172
5246
  )])) {
5173
5247
  throw new CLIError({
@@ -5617,7 +5691,7 @@ function createLingoDotDevLocalizer(explicitApiKey) {
5617
5691
  const response = await engine.whoami();
5618
5692
  return {
5619
5693
  authenticated: !!response,
5620
- username: _optionalChain([response, 'optionalAccess', _193 => _193.email])
5694
+ username: _optionalChain([response, 'optionalAccess', _197 => _197.email])
5621
5695
  };
5622
5696
  } catch (e2) {
5623
5697
  return { authenticated: false };
@@ -5652,6 +5726,8 @@ function createLingoDotDevLocalizer(explicitApiKey) {
5652
5726
 
5653
5727
 
5654
5728
 
5729
+
5730
+
5655
5731
  function createExplicitLocalizer(provider) {
5656
5732
  switch (provider.id) {
5657
5733
  default:
@@ -5690,27 +5766,42 @@ function createExplicitLocalizer(provider) {
5690
5766
  apiKeyName: "GOOGLE_API_KEY",
5691
5767
  baseUrl: provider.baseUrl
5692
5768
  });
5769
+ case "openrouter":
5770
+ return createAiSdkLocalizer({
5771
+ factory: (params) => _aisdkprovider.createOpenRouter.call(void 0, params).languageModel(provider.model),
5772
+ id: provider.id,
5773
+ prompt: provider.prompt,
5774
+ apiKeyName: "OPENROUTER_API_KEY",
5775
+ baseUrl: provider.baseUrl
5776
+ });
5777
+ case "ollama":
5778
+ return createAiSdkLocalizer({
5779
+ factory: (_params) => _ollamaaiprovider.createOllama.call(void 0, ).languageModel(provider.model),
5780
+ id: provider.id,
5781
+ prompt: provider.prompt,
5782
+ skipAuth: true
5783
+ });
5693
5784
  }
5694
5785
  }
5695
5786
  function createAiSdkLocalizer(params) {
5696
- const apiKey = process.env[params.apiKeyName];
5697
- if (!apiKey) {
5787
+ const skipAuth = params.skipAuth === true;
5788
+ const apiKey = process.env[_nullishCoalesce(_optionalChain([params, 'optionalAccess', _198 => _198.apiKeyName]), () => ( ""))];
5789
+ if (!skipAuth && !apiKey || !params.apiKeyName) {
5698
5790
  throw new Error(
5699
5791
  _dedent2.default`
5700
- You're trying to use raw ${_chalk2.default.dim(params.id)} API for translation, however, ${_chalk2.default.dim(params.apiKeyName)} environment variable is not set.
5792
+ You're trying to use raw ${_chalk2.default.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${_chalk2.default.dim(params.apiKeyName)} environment variable is not set.` : "However, that provider is unavailable."}
5701
5793
 
5702
5794
  To fix this issue:
5703
- 1. Set ${_chalk2.default.dim(params.apiKeyName)} in your environment variables, or
5795
+ 1. ${params.apiKeyName ? `Set ${_chalk2.default.dim(params.apiKeyName)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
5704
5796
  2. Remove the ${_chalk2.default.italic("provider")} node from your i18n.json configuration to switch to ${_chalk2.default.hex(colors.green)("Lingo.dev")}
5705
5797
 
5706
5798
  ${_chalk2.default.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
5707
5799
  `
5708
5800
  );
5709
5801
  }
5710
- const model = params.factory({
5711
- apiKey,
5712
- baseUrl: params.baseUrl
5713
- });
5802
+ const model = params.factory(
5803
+ skipAuth ? {} : { apiKey, baseUrl: params.baseUrl }
5804
+ );
5714
5805
  return {
5715
5806
  id: params.id,
5716
5807
  checkAuth: async () => {
@@ -5811,8 +5902,8 @@ async function setup(input2) {
5811
5902
  throw new Error(
5812
5903
  "No buckets found in i18n.json. Please add at least one bucket containing i18n content."
5813
5904
  );
5814
- } else if (_optionalChain([ctx, 'access', _194 => _194.flags, 'access', _195 => _195.bucket, 'optionalAccess', _196 => _196.some, 'call', _197 => _197(
5815
- (bucket) => !_optionalChain([ctx, 'access', _198 => _198.config, 'optionalAccess', _199 => _199.buckets, 'access', _200 => _200[bucket]])
5905
+ } else if (_optionalChain([ctx, 'access', _199 => _199.flags, 'access', _200 => _200.bucket, 'optionalAccess', _201 => _201.some, 'call', _202 => _202(
5906
+ (bucket) => !_optionalChain([ctx, 'access', _203 => _203.config, 'optionalAccess', _204 => _204.buckets, 'access', _205 => _205[bucket]])
5816
5907
  )])) {
5817
5908
  throw new Error(
5818
5909
  `One or more specified buckets do not exist in i18n.json. Please add them to the list first and try again.`
@@ -5825,7 +5916,7 @@ async function setup(input2) {
5825
5916
  title: "Selecting localization provider",
5826
5917
  task: async (ctx, task) => {
5827
5918
  ctx.localizer = createLocalizer(
5828
- _optionalChain([ctx, 'access', _201 => _201.config, 'optionalAccess', _202 => _202.provider]),
5919
+ _optionalChain([ctx, 'access', _206 => _206.config, 'optionalAccess', _207 => _207.provider]),
5829
5920
  ctx.flags.apiKey
5830
5921
  );
5831
5922
  if (!ctx.localizer) {
@@ -6205,13 +6296,13 @@ var flagsSchema2 = _zod.z.object({
6205
6296
 
6206
6297
  // src/cli/cmd/run/_utils.ts
6207
6298
  async function determineAuthId(ctx) {
6208
- const isByokMode = !!_optionalChain([ctx, 'access', _203 => _203.config, 'optionalAccess', _204 => _204.provider]);
6299
+ const isByokMode = !!_optionalChain([ctx, 'access', _208 => _208.config, 'optionalAccess', _209 => _209.provider]);
6209
6300
  if (isByokMode) {
6210
6301
  return null;
6211
6302
  } else {
6212
6303
  try {
6213
- const authStatus = await _optionalChain([ctx, 'access', _205 => _205.localizer, 'optionalAccess', _206 => _206.checkAuth, 'call', _207 => _207()]);
6214
- return _optionalChain([authStatus, 'optionalAccess', _208 => _208.username]) || null;
6304
+ const authStatus = await _optionalChain([ctx, 'access', _210 => _210.localizer, 'optionalAccess', _211 => _211.checkAuth, 'call', _212 => _212()]);
6305
+ return _optionalChain([authStatus, 'optionalAccess', _213 => _213.username]) || null;
6215
6306
  } catch (e3) {
6216
6307
  return null;
6217
6308
  }
@@ -6359,7 +6450,7 @@ var InBranchFlow = class extends IntegrationFlow {
6359
6450
  _child_process.execSync.call(void 0, `git config --global safe.directory ${process.cwd()}`);
6360
6451
  _child_process.execSync.call(void 0, `git config user.name "${gitConfig.userName}"`);
6361
6452
  _child_process.execSync.call(void 0, `git config user.email "${gitConfig.userEmail}"`);
6362
- _optionalChain([this, 'access', _209 => _209.platformKit, 'optionalAccess', _210 => _210.gitConfig, 'call', _211 => _211()]);
6453
+ _optionalChain([this, 'access', _214 => _214.platformKit, 'optionalAccess', _215 => _215.gitConfig, 'call', _216 => _216()]);
6363
6454
  _child_process.execSync.call(void 0, `git fetch origin ${baseBranchName}`, { stdio: "inherit" });
6364
6455
  _child_process.execSync.call(void 0, `git checkout ${baseBranchName} --`, { stdio: "inherit" });
6365
6456
  if (!processOwnCommits) {
@@ -6391,7 +6482,7 @@ var InBranchFlow = class extends IntegrationFlow {
6391
6482
  // src/cli/cmd/ci/flows/pull-request.ts
6392
6483
  var PullRequestFlow = class extends InBranchFlow {
6393
6484
  async preRun() {
6394
- const canContinue = await _optionalChain([super.preRun.bind(this), 'optionalCall', _212 => _212()]);
6485
+ const canContinue = await _optionalChain([super.preRun.bind(this), 'optionalCall', _217 => _217()]);
6395
6486
  if (!canContinue) {
6396
6487
  return false;
6397
6488
  }
@@ -6646,10 +6737,10 @@ var BitbucketPlatformKit = class extends PlatformKit {
6646
6737
  repo_slug: this.platformConfig.repositoryName,
6647
6738
  state: "OPEN"
6648
6739
  }).then(({ data: { values } }) => {
6649
- return _optionalChain([values, 'optionalAccess', _213 => _213.find, 'call', _214 => _214(
6650
- ({ source, destination }) => _optionalChain([source, 'optionalAccess', _215 => _215.branch, 'optionalAccess', _216 => _216.name]) === branch && _optionalChain([destination, 'optionalAccess', _217 => _217.branch, 'optionalAccess', _218 => _218.name]) === this.platformConfig.baseBranchName
6740
+ return _optionalChain([values, 'optionalAccess', _218 => _218.find, 'call', _219 => _219(
6741
+ ({ source, destination }) => _optionalChain([source, 'optionalAccess', _220 => _220.branch, 'optionalAccess', _221 => _221.name]) === branch && _optionalChain([destination, 'optionalAccess', _222 => _222.branch, 'optionalAccess', _223 => _223.name]) === this.platformConfig.baseBranchName
6651
6742
  )]);
6652
- }).then((pr) => _optionalChain([pr, 'optionalAccess', _219 => _219.id]));
6743
+ }).then((pr) => _optionalChain([pr, 'optionalAccess', _224 => _224.id]));
6653
6744
  }
6654
6745
  async closePullRequest({ pullRequestNumber }) {
6655
6746
  await this.bb.repositories.declinePullRequest({
@@ -6745,7 +6836,7 @@ var GitHubPlatformKit = class extends PlatformKit {
6745
6836
  repo: this.platformConfig.repositoryName,
6746
6837
  base: this.platformConfig.baseBranchName,
6747
6838
  state: "open"
6748
- }).then(({ data }) => data[0]).then((pr) => _optionalChain([pr, 'optionalAccess', _220 => _220.number]));
6839
+ }).then(({ data }) => data[0]).then((pr) => _optionalChain([pr, 'optionalAccess', _225 => _225.number]));
6749
6840
  }
6750
6841
  async closePullRequest({ pullRequestNumber }) {
6751
6842
  await this.octokit.rest.pulls.update({
@@ -6872,7 +6963,7 @@ var GitlabPlatformKit = class extends PlatformKit {
6872
6963
  sourceBranch: branch,
6873
6964
  state: "opened"
6874
6965
  });
6875
- return _optionalChain([mergeRequests, 'access', _221 => _221[0], 'optionalAccess', _222 => _222.iid]);
6966
+ return _optionalChain([mergeRequests, 'access', _226 => _226[0], 'optionalAccess', _227 => _227.iid]);
6876
6967
  }
6877
6968
  async closePullRequest({
6878
6969
  pullRequestNumber
@@ -6962,7 +7053,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
6962
7053
  }
6963
7054
  const env = {
6964
7055
  LINGODOTDEV_API_KEY: settings.auth.apiKey,
6965
- LINGODOTDEV_PULL_REQUEST: _optionalChain([options, 'access', _223 => _223.pullRequest, 'optionalAccess', _224 => _224.toString, 'call', _225 => _225()]) || "false",
7056
+ LINGODOTDEV_PULL_REQUEST: _optionalChain([options, 'access', _228 => _228.pullRequest, 'optionalAccess', _229 => _229.toString, 'call', _230 => _230()]) || "false",
6966
7057
  ...options.commitMessage && {
6967
7058
  LINGODOTDEV_COMMIT_MESSAGE: options.commitMessage
6968
7059
  },
@@ -6982,7 +7073,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
6982
7073
  const { isPullRequestMode } = platformKit.config;
6983
7074
  ora.info(`Pull request mode: ${isPullRequestMode ? "on" : "off"}`);
6984
7075
  const flow = isPullRequestMode ? new PullRequestFlow(ora, platformKit) : new InBranchFlow(ora, platformKit);
6985
- const canRun = await _optionalChain([flow, 'access', _226 => _226.preRun, 'optionalCall', _227 => _227()]);
7076
+ const canRun = await _optionalChain([flow, 'access', _231 => _231.preRun, 'optionalCall', _232 => _232()]);
6986
7077
  if (canRun === false) {
6987
7078
  return;
6988
7079
  }
@@ -6992,7 +7083,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
6992
7083
  if (!hasChanges) {
6993
7084
  return;
6994
7085
  }
6995
- await _optionalChain([flow, 'access', _228 => _228.postRun, 'optionalCall', _229 => _229()]);
7086
+ await _optionalChain([flow, 'access', _233 => _233.postRun, 'optionalCall', _234 => _234()]);
6996
7087
  });
6997
7088
  function parseBooleanArg(val) {
6998
7089
  if (val === true) return true;
@@ -7043,13 +7134,13 @@ var status_default = new (0, _interactivecommander.Command)().command("status").
7043
7134
  flags
7044
7135
  });
7045
7136
  let buckets = getBuckets(i18nConfig);
7046
- if (_optionalChain([flags, 'access', _230 => _230.bucket, 'optionalAccess', _231 => _231.length])) {
7137
+ if (_optionalChain([flags, 'access', _235 => _235.bucket, 'optionalAccess', _236 => _236.length])) {
7047
7138
  buckets = buckets.filter((bucket) => flags.bucket.includes(bucket.type));
7048
7139
  }
7049
7140
  ora.succeed("Buckets retrieved");
7050
- if (_optionalChain([flags, 'access', _232 => _232.file, 'optionalAccess', _233 => _233.length])) {
7141
+ if (_optionalChain([flags, 'access', _237 => _237.file, 'optionalAccess', _238 => _238.length])) {
7051
7142
  buckets = buckets.map((bucket) => {
7052
- const paths = bucket.paths.filter((path16) => flags.file.find((file) => _optionalChain([path16, 'access', _234 => _234.pathPattern, 'optionalAccess', _235 => _235.match, 'call', _236 => _236(file)])));
7143
+ const paths = bucket.paths.filter((path16) => flags.file.find((file) => _optionalChain([path16, 'access', _239 => _239.pathPattern, 'optionalAccess', _240 => _240.match, 'call', _241 => _241(file)])));
7053
7144
  return { ...bucket, paths };
7054
7145
  }).filter((bucket) => bucket.paths.length > 0);
7055
7146
  if (buckets.length === 0) {
@@ -7065,7 +7156,7 @@ var status_default = new (0, _interactivecommander.Command)().command("status").
7065
7156
  });
7066
7157
  }
7067
7158
  }
7068
- const targetLocales = _optionalChain([flags, 'access', _237 => _237.locale, 'optionalAccess', _238 => _238.length]) ? flags.locale : i18nConfig.locale.targets;
7159
+ const targetLocales = _optionalChain([flags, 'access', _242 => _242.locale, 'optionalAccess', _243 => _243.length]) ? flags.locale : i18nConfig.locale.targets;
7069
7160
  let totalSourceKeyCount = 0;
7070
7161
  let uniqueKeysToTranslate = 0;
7071
7162
  let totalExistingTranslations = 0;
@@ -7406,12 +7497,12 @@ function validateParams2(i18nConfig, flags) {
7406
7497
  message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
7407
7498
  docUrl: "bucketNotFound"
7408
7499
  });
7409
- } else if (_optionalChain([flags, 'access', _239 => _239.locale, 'optionalAccess', _240 => _240.some, 'call', _241 => _241((locale) => !i18nConfig.locale.targets.includes(locale))])) {
7500
+ } else if (_optionalChain([flags, 'access', _244 => _244.locale, 'optionalAccess', _245 => _245.some, 'call', _246 => _246((locale) => !i18nConfig.locale.targets.includes(locale))])) {
7410
7501
  throw new CLIError({
7411
7502
  message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
7412
7503
  docUrl: "localeTargetNotFound"
7413
7504
  });
7414
- } else if (_optionalChain([flags, 'access', _242 => _242.bucket, 'optionalAccess', _243 => _243.some, 'call', _244 => _244((bucket) => !i18nConfig.buckets[bucket])])) {
7505
+ } else if (_optionalChain([flags, 'access', _247 => _247.bucket, 'optionalAccess', _248 => _248.some, 'call', _249 => _249((bucket) => !i18nConfig.buckets[bucket])])) {
7415
7506
  throw new CLIError({
7416
7507
  message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
7417
7508
  docUrl: "bucketNotFound"
@@ -7494,7 +7585,7 @@ async function renderHero2() {
7494
7585
  // package.json
7495
7586
  var package_default = {
7496
7587
  name: "lingo.dev",
7497
- version: "0.97.5",
7588
+ version: "0.99.0",
7498
7589
  description: "Lingo.dev CLI",
7499
7590
  private: false,
7500
7591
  publishConfig: {
@@ -7622,6 +7713,7 @@ var package_default = {
7622
7713
  "@lingo.dev/_sdk": "workspace:*",
7623
7714
  "@lingo.dev/_spec": "workspace:*",
7624
7715
  "@modelcontextprotocol/sdk": "^1.5.0",
7716
+ "@openrouter/ai-sdk-provider": "^0.7.1",
7625
7717
  "@paralleldrive/cuid2": "^2.2.2",
7626
7718
  ai: "^4.3.15",
7627
7719
  bitbucket: "^2.12.0",
@@ -7663,6 +7755,7 @@ var package_default = {
7663
7755
  "node-webvtt": "^1.9.4",
7664
7756
  "object-hash": "^3.0.0",
7665
7757
  octokit: "^4.0.2",
7758
+ "ollama-ai-provider": "^1.2.0",
7666
7759
  open: "^10.1.2",
7667
7760
  ora: "^8.1.1",
7668
7761
  "p-limit": "^6.2.0",