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.mjs CHANGED
@@ -30,7 +30,8 @@ function getSettings(explicitApiKey) {
30
30
  openaiApiKey: env.OPENAI_API_KEY || systemFile.llm?.openaiApiKey,
31
31
  anthropicApiKey: env.ANTHROPIC_API_KEY || systemFile.llm?.anthropicApiKey,
32
32
  groqApiKey: env.GROQ_API_KEY || systemFile.llm?.groqApiKey,
33
- googleApiKey: env.GOOGLE_API_KEY || systemFile.llm?.googleApiKey
33
+ googleApiKey: env.GOOGLE_API_KEY || systemFile.llm?.googleApiKey,
34
+ openrouterApiKey: env.OPENROUTER_API_KEY || systemFile.llm?.openrouterApiKey
34
35
  }
35
36
  };
36
37
  }
@@ -59,7 +60,8 @@ var SettingsSchema = Z.object({
59
60
  openaiApiKey: Z.string().optional(),
60
61
  anthropicApiKey: Z.string().optional(),
61
62
  groqApiKey: Z.string().optional(),
62
- googleApiKey: Z.string().optional()
63
+ googleApiKey: Z.string().optional(),
64
+ openrouterApiKey: Z.string().optional()
63
65
  })
64
66
  });
65
67
  var SETTINGS_KEYS = flattenZodObject(
@@ -83,7 +85,8 @@ function _loadEnv() {
83
85
  OPENAI_API_KEY: Z.string().optional(),
84
86
  ANTHROPIC_API_KEY: Z.string().optional(),
85
87
  GROQ_API_KEY: Z.string().optional(),
86
- GOOGLE_API_KEY: Z.string().optional()
88
+ GOOGLE_API_KEY: Z.string().optional(),
89
+ OPENROUTER_API_KEY: Z.string().optional()
87
90
  }).passthrough().parse(process.env);
88
91
  }
89
92
  function _loadSystemFile() {
@@ -100,7 +103,8 @@ function _loadSystemFile() {
100
103
  openaiApiKey: Z.string().optional(),
101
104
  anthropicApiKey: Z.string().optional(),
102
105
  groqApiKey: Z.string().optional(),
103
- googleApiKey: Z.string().optional()
106
+ googleApiKey: Z.string().optional(),
107
+ openrouterApiKey: Z.string().optional()
104
108
  }).optional()
105
109
  }).passthrough().parse(data);
106
110
  }
@@ -163,6 +167,12 @@ function _envVarsInfo() {
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 && systemFile.llm?.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 {
@@ -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({
@@ -4493,6 +4547,8 @@ function countWordsInRecord(payload) {
4493
4547
  import { createOpenAI } from "@ai-sdk/openai";
4494
4548
  import { createAnthropic } from "@ai-sdk/anthropic";
4495
4549
  import { createGoogleGenerativeAI } from "@ai-sdk/google";
4550
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
4551
+ import { createOllama } from "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) => dedent4`
4508
- You're trying to use raw ${chalk5.dim(providerId)} API for translation, however, ${chalk5.dim(envVar)} environment variable is not set.
4564
+ You're trying to use raw ${chalk5.dim(providerId)} API for translation. ${envVar ? `However, ${chalk5.dim(envVar)} environment variable is not set.` : "However, that provider is unavailable."}
4509
4565
 
4510
4566
  To fix this issue:
4511
- 1. Set ${chalk5.dim(envVar)} in your environment variables, or
4567
+ 1. ${envVar ? `Set ${chalk5.dim(envVar)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
4512
4568
  2. Remove the ${chalk5.italic("provider")} node from your i18n.json configuration to switch to ${chalk5.hex(colors.green)("Lingo.dev")}
4513
4569
 
4514
4570
  ${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
@@ -4523,7 +4579,7 @@ function getPureModelProvider(provider) {
4523
4579
  ${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
4524
4580
  `;
4525
4581
  switch (provider?.id) {
4526
- case "openai":
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 createAnthropic({
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 createGoogleGenerativeAI({
4552
4610
  apiKey: process.env.GOOGLE_API_KEY
4553
4611
  })(provider.model);
4554
- default:
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 createOpenRouter({
4620
+ apiKey: process.env.OPENROUTER_API_KEY,
4621
+ baseURL: provider.baseUrl
4622
+ })(provider.model);
4623
+ }
4624
+ case "ollama": {
4625
+ return createOllama()(provider.model);
4626
+ }
4627
+ default: {
4555
4628
  throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
4629
+ }
4556
4630
  }
4557
4631
  }
4558
4632
 
@@ -5648,10 +5722,12 @@ function createLingoDotDevLocalizer(explicitApiKey) {
5648
5722
  import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
5649
5723
  import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
5650
5724
  import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
5725
+ import { createOpenRouter as createOpenRouter2 } from "@openrouter/ai-sdk-provider";
5651
5726
  import chalk9 from "chalk";
5652
5727
  import dedent6 from "dedent";
5653
5728
  import { generateText as generateText2 } from "ai";
5654
5729
  import { jsonrepair as jsonrepair3 } from "jsonrepair";
5730
+ import { createOllama as createOllama2 } from "ollama-ai-provider";
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) => createOpenRouter2(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) => createOllama2().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[params?.apiKeyName ?? ""];
5789
+ if (!skipAuth && !apiKey || !params.apiKeyName) {
5698
5790
  throw new Error(
5699
5791
  dedent6`
5700
- You're trying to use raw ${chalk9.dim(params.id)} API for translation, however, ${chalk9.dim(params.apiKeyName)} environment variable is not set.
5792
+ You're trying to use raw ${chalk9.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${chalk9.dim(params.apiKeyName)} environment variable is not set.` : "However, that provider is unavailable."}
5701
5793
 
5702
5794
  To fix this issue:
5703
- 1. Set ${chalk9.dim(params.apiKeyName)} in your environment variables, or
5795
+ 1. ${params.apiKeyName ? `Set ${chalk9.dim(params.apiKeyName)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
5704
5796
  2. Remove the ${chalk9.italic("provider")} node from your i18n.json configuration to switch to ${chalk9.hex(colors.green)("Lingo.dev")}
5705
5797
 
5706
5798
  ${chalk9.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 () => {
@@ -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",