lingo.dev 0.92.8 → 0.92.9
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 +882 -110
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +865 -93
- package/build/cli.mjs.map +1 -1
- package/package.json +15 -6
package/build/cli.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/cli/index.ts
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
import { InteractiveCommand as InteractiveCommand2 } from "interactive-commander";
|
|
4
|
-
import
|
|
5
|
-
import { vice as
|
|
4
|
+
import figlet3 from "figlet";
|
|
5
|
+
import { vice as vice3 } from "gradient-string";
|
|
6
6
|
|
|
7
7
|
// src/cli/cmd/auth.ts
|
|
8
8
|
import { Command } from "interactive-commander";
|
|
@@ -1250,7 +1250,7 @@ function createTextFileLoader(pathPattern) {
|
|
|
1250
1250
|
const trimmedResult = result.trim();
|
|
1251
1251
|
return trimmedResult;
|
|
1252
1252
|
},
|
|
1253
|
-
async push(locale, data,
|
|
1253
|
+
async push(locale, data, _29, originalLocale) {
|
|
1254
1254
|
const draftPath = pathPattern.replaceAll("[locale]", locale);
|
|
1255
1255
|
const finalPath = path10.resolve(draftPath);
|
|
1256
1256
|
const dirPath = path10.dirname(finalPath);
|
|
@@ -1564,6 +1564,9 @@ function createCsvLoader() {
|
|
|
1564
1564
|
skip_empty_lines: true
|
|
1565
1565
|
});
|
|
1566
1566
|
const columns = input2.length > 0 ? Object.keys(input2[0]) : ["id", locale];
|
|
1567
|
+
if (!columns.includes(locale)) {
|
|
1568
|
+
columns.push(locale);
|
|
1569
|
+
}
|
|
1567
1570
|
const updatedRows = input2.map((row) => ({
|
|
1568
1571
|
...row,
|
|
1569
1572
|
[locale]: data[row.id] || row[locale] || ""
|
|
@@ -1776,7 +1779,7 @@ function createPropertiesLoader() {
|
|
|
1776
1779
|
return result;
|
|
1777
1780
|
},
|
|
1778
1781
|
async push(locale, payload) {
|
|
1779
|
-
const result = Object.entries(payload).filter(([
|
|
1782
|
+
const result = Object.entries(payload).filter(([_29, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
1780
1783
|
return result;
|
|
1781
1784
|
}
|
|
1782
1785
|
});
|
|
@@ -2043,10 +2046,10 @@ function createUnlocalizableLoader(isCacheRestore = false, returnUnlocalizedKeys
|
|
|
2043
2046
|
}
|
|
2044
2047
|
}
|
|
2045
2048
|
return false;
|
|
2046
|
-
}).map(([key,
|
|
2047
|
-
const result = _10.omitBy(input2, (
|
|
2049
|
+
}).map(([key, _29]) => key);
|
|
2050
|
+
const result = _10.omitBy(input2, (_29, key) => passthroughKeys.includes(key));
|
|
2048
2051
|
if (returnUnlocalizedKeys) {
|
|
2049
|
-
result.unlocalizable = _10.omitBy(input2, (
|
|
2052
|
+
result.unlocalizable = _10.omitBy(input2, (_29, key) => !passthroughKeys.includes(key));
|
|
2050
2053
|
}
|
|
2051
2054
|
return result;
|
|
2052
2055
|
},
|
|
@@ -3963,11 +3966,15 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
3963
3966
|
}
|
|
3964
3967
|
|
|
3965
3968
|
// src/cli/cmd/i18n.ts
|
|
3966
|
-
import
|
|
3969
|
+
import chalk2 from "chalk";
|
|
3967
3970
|
import { createTwoFilesPatch } from "diff";
|
|
3968
3971
|
import inquirer2 from "inquirer";
|
|
3969
3972
|
import externalEditor from "external-editor";
|
|
3970
3973
|
|
|
3974
|
+
// src/cli/processor/index.ts
|
|
3975
|
+
import chalk from "chalk";
|
|
3976
|
+
import dedent from "dedent";
|
|
3977
|
+
|
|
3971
3978
|
// src/cli/processor/lingo.ts
|
|
3972
3979
|
import { LingoDotDevEngine } from "@lingo.dev/_sdk";
|
|
3973
3980
|
function createLingoLocalizer(params) {
|
|
@@ -4002,9 +4009,6 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
4002
4009
|
if (!Object.keys(input2.processableData).length) {
|
|
4003
4010
|
return input2.processableData;
|
|
4004
4011
|
}
|
|
4005
|
-
if (!process.env.OPENAI_API_KEY) {
|
|
4006
|
-
throw new Error("OPENAI_API_KEY is not set");
|
|
4007
|
-
}
|
|
4008
4012
|
const response = await generateText({
|
|
4009
4013
|
model,
|
|
4010
4014
|
messages: [
|
|
@@ -4052,9 +4056,21 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
4052
4056
|
|
|
4053
4057
|
// src/cli/processor/index.ts
|
|
4054
4058
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
4059
|
+
|
|
4060
|
+
// src/cli/constants.ts
|
|
4061
|
+
var colors = {
|
|
4062
|
+
orange: "#ff6600",
|
|
4063
|
+
green: "#6ae300",
|
|
4064
|
+
blue: "#0090ff",
|
|
4065
|
+
yellow: "#ffcc00",
|
|
4066
|
+
grey: "#808080",
|
|
4067
|
+
red: "#ff0000"
|
|
4068
|
+
};
|
|
4069
|
+
|
|
4070
|
+
// src/cli/processor/index.ts
|
|
4055
4071
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
4056
4072
|
function createProcessor(provider, params) {
|
|
4057
|
-
if (!provider
|
|
4073
|
+
if (!provider) {
|
|
4058
4074
|
const result = createLingoLocalizer(params);
|
|
4059
4075
|
return result;
|
|
4060
4076
|
} else {
|
|
@@ -4064,10 +4080,30 @@ function createProcessor(provider, params) {
|
|
|
4064
4080
|
}
|
|
4065
4081
|
}
|
|
4066
4082
|
function getPureModelProvider(provider) {
|
|
4083
|
+
const createMissingKeyErrorMessage = (providerId, envVar) => dedent`
|
|
4084
|
+
You're trying to use raw ${chalk.dim(providerId)} API for translation, however, ${chalk.dim(envVar)} environment variable is not set.
|
|
4085
|
+
|
|
4086
|
+
To fix this issue:
|
|
4087
|
+
1. Set ${chalk.dim(envVar)} in your environment variables, or
|
|
4088
|
+
2. Remove the ${chalk.italic("provider")} node from your i18n.json configuration to switch to ${chalk.hex(colors.green)("Lingo.dev")}
|
|
4089
|
+
|
|
4090
|
+
${chalk.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4091
|
+
`;
|
|
4092
|
+
const createUnsupportedProviderErrorMessage = (providerId) => dedent`
|
|
4093
|
+
You're trying to use unsupported provider: ${chalk.dim(providerId)}.
|
|
4094
|
+
|
|
4095
|
+
To fix this issue:
|
|
4096
|
+
1. Switch to one of the supported providers, or
|
|
4097
|
+
2. Remove the ${chalk.italic("provider")} node from your i18n.json configuration to switch to ${chalk.hex(colors.green)("Lingo.dev")}
|
|
4098
|
+
|
|
4099
|
+
${chalk.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4100
|
+
`;
|
|
4067
4101
|
switch (provider?.id) {
|
|
4068
4102
|
case "openai":
|
|
4069
4103
|
if (!process.env.OPENAI_API_KEY) {
|
|
4070
|
-
throw new Error(
|
|
4104
|
+
throw new Error(
|
|
4105
|
+
createMissingKeyErrorMessage("OpenAI", "OPENAI_API_KEY")
|
|
4106
|
+
);
|
|
4071
4107
|
}
|
|
4072
4108
|
return createOpenAI({
|
|
4073
4109
|
apiKey: process.env.OPENAI_API_KEY,
|
|
@@ -4075,13 +4111,15 @@ function getPureModelProvider(provider) {
|
|
|
4075
4111
|
})(provider.model);
|
|
4076
4112
|
case "anthropic":
|
|
4077
4113
|
if (!process.env.ANTHROPIC_API_KEY) {
|
|
4078
|
-
throw new Error(
|
|
4114
|
+
throw new Error(
|
|
4115
|
+
createMissingKeyErrorMessage("Anthropic", "ANTHROPIC_API_KEY")
|
|
4116
|
+
);
|
|
4079
4117
|
}
|
|
4080
4118
|
return createAnthropic({
|
|
4081
4119
|
apiKey: process.env.ANTHROPIC_API_KEY
|
|
4082
4120
|
})(provider.model);
|
|
4083
4121
|
default:
|
|
4084
|
-
throw new Error(
|
|
4122
|
+
throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
|
|
4085
4123
|
}
|
|
4086
4124
|
}
|
|
4087
4125
|
|
|
@@ -4306,7 +4344,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4306
4344
|
validateParams(i18nConfig, flags);
|
|
4307
4345
|
ora.succeed("Localization configuration is valid");
|
|
4308
4346
|
ora.start("Connecting to Lingo.dev Localization Engine...");
|
|
4309
|
-
const isByokMode = i18nConfig?.provider
|
|
4347
|
+
const isByokMode = !!i18nConfig?.provider;
|
|
4310
4348
|
if (isByokMode) {
|
|
4311
4349
|
authId = null;
|
|
4312
4350
|
ora.succeed("Using external provider (BYOK mode)");
|
|
@@ -4589,7 +4627,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4589
4627
|
if (flags.key) {
|
|
4590
4628
|
processableData = _25.pickBy(
|
|
4591
4629
|
processableData,
|
|
4592
|
-
(
|
|
4630
|
+
(_29, key) => key === flags.key
|
|
4593
4631
|
);
|
|
4594
4632
|
}
|
|
4595
4633
|
if (flags.verbose) {
|
|
@@ -4616,15 +4654,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4616
4654
|
targetData
|
|
4617
4655
|
},
|
|
4618
4656
|
(progress, sourceChunk, processedChunk) => {
|
|
4619
|
-
|
|
4620
|
-
if (flags.verbose) {
|
|
4621
|
-
bucketOra.info(progressLog);
|
|
4622
|
-
bucketOra.info(
|
|
4623
|
-
`(${progress}%) Caching chunk ${JSON.stringify(sourceChunk, null, 2)} -> ${JSON.stringify(processedChunk, null, 2)}`
|
|
4624
|
-
);
|
|
4625
|
-
} else {
|
|
4626
|
-
bucketOra.text = progressLog;
|
|
4627
|
-
}
|
|
4657
|
+
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length} entries] (${progress}%) AI localization in progress...`;
|
|
4628
4658
|
}
|
|
4629
4659
|
);
|
|
4630
4660
|
if (flags.verbose) {
|
|
@@ -4778,7 +4808,7 @@ async function reviewChanges(args) {
|
|
|
4778
4808
|
if (currentStr === proposedStr && !args.force) {
|
|
4779
4809
|
console.log(
|
|
4780
4810
|
`
|
|
4781
|
-
${
|
|
4811
|
+
${chalk2.blue(args.pathPattern)} (${chalk2.yellow(args.targetLocale)}): ${chalk2.gray("No changes to review")}`
|
|
4782
4812
|
);
|
|
4783
4813
|
return args.proposedData;
|
|
4784
4814
|
}
|
|
@@ -4792,14 +4822,14 @@ ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targetLocale)}): ${chalk.gr
|
|
|
4792
4822
|
{ context: 3 }
|
|
4793
4823
|
);
|
|
4794
4824
|
const coloredDiff = patch.split("\n").map((line) => {
|
|
4795
|
-
if (line.startsWith("+")) return
|
|
4796
|
-
if (line.startsWith("-")) return
|
|
4797
|
-
if (line.startsWith("@")) return
|
|
4825
|
+
if (line.startsWith("+")) return chalk2.green(line);
|
|
4826
|
+
if (line.startsWith("-")) return chalk2.red(line);
|
|
4827
|
+
if (line.startsWith("@")) return chalk2.cyan(line);
|
|
4798
4828
|
return line;
|
|
4799
4829
|
}).join("\n");
|
|
4800
4830
|
console.log(
|
|
4801
4831
|
`
|
|
4802
|
-
Reviewing changes for ${
|
|
4832
|
+
Reviewing changes for ${chalk2.blue(args.pathPattern)} (${chalk2.yellow(args.targetLocale)}):`
|
|
4803
4833
|
);
|
|
4804
4834
|
console.log(coloredDiff);
|
|
4805
4835
|
const { action } = await inquirer2.prompt([
|
|
@@ -4834,32 +4864,32 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
|
|
|
4834
4864
|
);
|
|
4835
4865
|
for (const key of changes) {
|
|
4836
4866
|
console.log(`
|
|
4837
|
-
Editing value for: ${
|
|
4838
|
-
console.log(
|
|
4867
|
+
Editing value for: ${chalk2.cyan(key)}`);
|
|
4868
|
+
console.log(chalk2.gray("Source text:"), chalk2.blue(args.sourceData[key]));
|
|
4839
4869
|
console.log(
|
|
4840
|
-
|
|
4841
|
-
|
|
4870
|
+
chalk2.gray("Current value:"),
|
|
4871
|
+
chalk2.red(args.currentData[key] || "(empty)")
|
|
4842
4872
|
);
|
|
4843
4873
|
console.log(
|
|
4844
|
-
|
|
4845
|
-
|
|
4874
|
+
chalk2.gray("Suggested value:"),
|
|
4875
|
+
chalk2.green(args.proposedData[key])
|
|
4846
4876
|
);
|
|
4847
4877
|
console.log(
|
|
4848
|
-
|
|
4878
|
+
chalk2.gray(
|
|
4849
4879
|
"\nYour editor will open. Edit the text and save to continue."
|
|
4850
4880
|
)
|
|
4851
4881
|
);
|
|
4852
|
-
console.log(
|
|
4882
|
+
console.log(chalk2.gray("------------"));
|
|
4853
4883
|
try {
|
|
4854
4884
|
const editorContent = [
|
|
4855
4885
|
"# Edit the translation below.",
|
|
4856
4886
|
"# Lines starting with # will be ignored.",
|
|
4857
4887
|
"# Save and exit the editor to continue.",
|
|
4858
4888
|
"#",
|
|
4859
|
-
`# Source text (${
|
|
4889
|
+
`# Source text (${chalk2.blue("English")}):`,
|
|
4860
4890
|
`# ${args.sourceData[key]}`,
|
|
4861
4891
|
"#",
|
|
4862
|
-
`# Current value (${
|
|
4892
|
+
`# Current value (${chalk2.red(args.targetLocale)}):`,
|
|
4863
4893
|
`# ${args.currentData[key] || "(empty)"}`,
|
|
4864
4894
|
"#",
|
|
4865
4895
|
args.proposedData[key]
|
|
@@ -4870,13 +4900,13 @@ Editing value for: ${chalk.cyan(key)}`);
|
|
|
4870
4900
|
customData[key] = customValue;
|
|
4871
4901
|
} else {
|
|
4872
4902
|
console.log(
|
|
4873
|
-
|
|
4903
|
+
chalk2.yellow("Empty value provided, keeping the current value.")
|
|
4874
4904
|
);
|
|
4875
4905
|
customData[key] = args.currentData[key] || args.proposedData[key];
|
|
4876
4906
|
}
|
|
4877
4907
|
} catch (error) {
|
|
4878
4908
|
console.log(
|
|
4879
|
-
|
|
4909
|
+
chalk2.red("Error while editing, keeping the suggested value.")
|
|
4880
4910
|
);
|
|
4881
4911
|
customData[key] = args.proposedData[key];
|
|
4882
4912
|
}
|
|
@@ -5091,7 +5121,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5091
5121
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5092
5122
|
import Z6 from "zod";
|
|
5093
5123
|
import { ReplexicaEngine } from "@lingo.dev/_sdk";
|
|
5094
|
-
var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (
|
|
5124
|
+
var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_29, program) => {
|
|
5095
5125
|
const apiKey = program.args[0];
|
|
5096
5126
|
const settings = getSettings(apiKey);
|
|
5097
5127
|
if (!settings.auth.apiKey) {
|
|
@@ -5858,7 +5888,7 @@ import { bucketTypeSchema as bucketTypeSchema3, localeCodeSchema as localeCodeSc
|
|
|
5858
5888
|
import { Command as Command11 } from "interactive-commander";
|
|
5859
5889
|
import Z11 from "zod";
|
|
5860
5890
|
import Ora8 from "ora";
|
|
5861
|
-
import
|
|
5891
|
+
import chalk3 from "chalk";
|
|
5862
5892
|
import Table from "cli-table3";
|
|
5863
5893
|
var status_default = new Command11().command("status").description("Show the status of the localization process").helpOption("-h, --help", "Show help").option("--locale <locale>", "Locale to process", (val, prev) => prev ? [...prev, val] : [val]).option("--bucket <bucket>", "Bucket to process", (val, prev) => prev ? [...prev, val] : [val]).option(
|
|
5864
5894
|
"--file [files...]",
|
|
@@ -6001,7 +6031,7 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6001
6031
|
languageStats[targetLocale].words += sourceWordCount;
|
|
6002
6032
|
totalWordCount.set(targetLocale, (totalWordCount.get(targetLocale) || 0) + sourceWordCount);
|
|
6003
6033
|
bucketOra.succeed(
|
|
6004
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
6034
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk3.red(`0% complete`)} (0/${sourceKeys.length} keys) - file not found`
|
|
6005
6035
|
);
|
|
6006
6036
|
continue;
|
|
6007
6037
|
}
|
|
@@ -6037,20 +6067,20 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6037
6067
|
const completionPercent = (completeKeys.length / totalKeysInFile * 100).toFixed(1);
|
|
6038
6068
|
if (missingKeys.length === 0 && updatedKeys.length === 0) {
|
|
6039
6069
|
bucketOra.succeed(
|
|
6040
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
6070
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk3.green(`100% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`
|
|
6041
6071
|
);
|
|
6042
6072
|
} else {
|
|
6043
|
-
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ?
|
|
6073
|
+
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ? chalk3.yellow(`${completionPercent}% complete`) : chalk3.red(`${completionPercent}% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`;
|
|
6044
6074
|
bucketOra.succeed(message);
|
|
6045
6075
|
if (flags.verbose) {
|
|
6046
6076
|
if (missingKeys.length > 0) {
|
|
6047
|
-
console.log(` ${
|
|
6077
|
+
console.log(` ${chalk3.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`);
|
|
6048
6078
|
console.log(
|
|
6049
|
-
` ${
|
|
6079
|
+
` ${chalk3.dim(`Example missing: ${missingKeys.slice(0, 2).join(", ")}${missingKeys.length > 2 ? "..." : ""}`)}`
|
|
6050
6080
|
);
|
|
6051
6081
|
}
|
|
6052
6082
|
if (updatedKeys.length > 0) {
|
|
6053
|
-
console.log(` ${
|
|
6083
|
+
console.log(` ${chalk3.yellow(`Updated:`)} ${updatedKeys.length} keys that changed in source`);
|
|
6054
6084
|
}
|
|
6055
6085
|
}
|
|
6056
6086
|
}
|
|
@@ -6065,16 +6095,16 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6065
6095
|
}, 0);
|
|
6066
6096
|
const totalCompletedKeys = totalSourceKeyCount - totalKeysNeedingTranslation / targetLocales.length;
|
|
6067
6097
|
console.log();
|
|
6068
|
-
ora.succeed(
|
|
6069
|
-
console.log(
|
|
6098
|
+
ora.succeed(chalk3.green(`Localization status completed.`));
|
|
6099
|
+
console.log(chalk3.bold.cyan(`
|
|
6070
6100
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`));
|
|
6071
|
-
console.log(
|
|
6072
|
-
console.log(
|
|
6073
|
-
console.log(
|
|
6101
|
+
console.log(chalk3.bold.cyan(`\u2551 LOCALIZATION STATUS REPORT \u2551`));
|
|
6102
|
+
console.log(chalk3.bold.cyan(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`));
|
|
6103
|
+
console.log(chalk3.bold(`
|
|
6074
6104
|
\u{1F4DD} SOURCE CONTENT:`));
|
|
6075
|
-
console.log(`\u2022 Source language: ${
|
|
6076
|
-
console.log(`\u2022 Source keys: ${
|
|
6077
|
-
console.log(
|
|
6105
|
+
console.log(`\u2022 Source language: ${chalk3.green(i18nConfig.locale.source)}`);
|
|
6106
|
+
console.log(`\u2022 Source keys: ${chalk3.yellow(totalSourceKeyCount.toString())} keys across all files`);
|
|
6107
|
+
console.log(chalk3.bold(`
|
|
6078
6108
|
\u{1F310} LANGUAGE BY LANGUAGE BREAKDOWN:`));
|
|
6079
6109
|
const table = new Table({
|
|
6080
6110
|
head: ["Language", "Status", "Complete", "Missing", "Updated", "Total Keys", "Words to Translate"],
|
|
@@ -6096,19 +6126,19 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6096
6126
|
let statusColor;
|
|
6097
6127
|
if (stats.missing === totalSourceKeyCount) {
|
|
6098
6128
|
statusText = "\u{1F534} Not started";
|
|
6099
|
-
statusColor =
|
|
6129
|
+
statusColor = chalk3.red;
|
|
6100
6130
|
} else if (stats.missing === 0 && stats.updated === 0) {
|
|
6101
6131
|
statusText = "\u2705 Complete";
|
|
6102
|
-
statusColor =
|
|
6132
|
+
statusColor = chalk3.green;
|
|
6103
6133
|
} else if (parseFloat(percentComplete) > 80) {
|
|
6104
6134
|
statusText = "\u{1F7E1} Almost done";
|
|
6105
|
-
statusColor =
|
|
6135
|
+
statusColor = chalk3.yellow;
|
|
6106
6136
|
} else if (parseFloat(percentComplete) > 0) {
|
|
6107
6137
|
statusText = "\u{1F7E0} In progress";
|
|
6108
|
-
statusColor =
|
|
6138
|
+
statusColor = chalk3.yellow;
|
|
6109
6139
|
} else {
|
|
6110
6140
|
statusText = "\u{1F534} Not started";
|
|
6111
|
-
statusColor =
|
|
6141
|
+
statusColor = chalk3.red;
|
|
6112
6142
|
}
|
|
6113
6143
|
const words = totalWordCount.get(locale) || 0;
|
|
6114
6144
|
totalWordsToTranslate += words;
|
|
@@ -6116,17 +6146,17 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6116
6146
|
locale,
|
|
6117
6147
|
statusColor(statusText),
|
|
6118
6148
|
`${stats.complete}/${totalSourceKeyCount} (${percentComplete}%)`,
|
|
6119
|
-
stats.missing > 0 ?
|
|
6120
|
-
stats.updated > 0 ?
|
|
6121
|
-
totalNeeded > 0 ?
|
|
6149
|
+
stats.missing > 0 ? chalk3.red(stats.missing.toString()) : "0",
|
|
6150
|
+
stats.updated > 0 ? chalk3.yellow(stats.updated.toString()) : "0",
|
|
6151
|
+
totalNeeded > 0 ? chalk3.magenta(totalNeeded.toString()) : "0",
|
|
6122
6152
|
words > 0 ? `~${words.toLocaleString()}` : "0"
|
|
6123
6153
|
]);
|
|
6124
6154
|
}
|
|
6125
6155
|
console.log(table.toString());
|
|
6126
|
-
console.log(
|
|
6156
|
+
console.log(chalk3.bold(`
|
|
6127
6157
|
\u{1F4CA} USAGE ESTIMATE:`));
|
|
6128
6158
|
console.log(
|
|
6129
|
-
`\u2022 WORDS TO BE CONSUMED: ~${
|
|
6159
|
+
`\u2022 WORDS TO BE CONSUMED: ~${chalk3.yellow.bold(totalWordsToTranslate.toLocaleString())} words across all languages`
|
|
6130
6160
|
);
|
|
6131
6161
|
console.log(` (Words are counted from source language for keys that need translation in target languages)`);
|
|
6132
6162
|
if (targetLocales.length > 1) {
|
|
@@ -6138,11 +6168,11 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6138
6168
|
}
|
|
6139
6169
|
}
|
|
6140
6170
|
if (flags.confirm && Object.keys(fileStats).length > 0) {
|
|
6141
|
-
console.log(
|
|
6171
|
+
console.log(chalk3.bold(`
|
|
6142
6172
|
\u{1F4D1} BREAKDOWN BY FILE:`));
|
|
6143
6173
|
Object.entries(fileStats).sort((a, b) => b[1].wordCount - a[1].wordCount).forEach(([path17, stats]) => {
|
|
6144
6174
|
if (stats.sourceKeys === 0) return;
|
|
6145
|
-
console.log(
|
|
6175
|
+
console.log(chalk3.bold(`
|
|
6146
6176
|
\u2022 ${path17}:`));
|
|
6147
6177
|
console.log(` ${stats.sourceKeys} source keys, ~${stats.wordCount.toLocaleString()} source words`);
|
|
6148
6178
|
const fileTable = new Table({
|
|
@@ -6160,13 +6190,13 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6160
6190
|
const total = stats.sourceKeys;
|
|
6161
6191
|
const completion = (complete / total * 100).toFixed(1);
|
|
6162
6192
|
let status = "\u2705 Complete";
|
|
6163
|
-
let statusColor =
|
|
6193
|
+
let statusColor = chalk3.green;
|
|
6164
6194
|
if (langStats.missing === total) {
|
|
6165
6195
|
status = "\u274C Not started";
|
|
6166
|
-
statusColor =
|
|
6196
|
+
statusColor = chalk3.red;
|
|
6167
6197
|
} else if (langStats.missing > 0 || langStats.updated > 0) {
|
|
6168
6198
|
status = `\u26A0\uFE0F ${completion}% complete`;
|
|
6169
|
-
statusColor =
|
|
6199
|
+
statusColor = chalk3.yellow;
|
|
6170
6200
|
}
|
|
6171
6201
|
let details = "";
|
|
6172
6202
|
if (langStats.missing > 0 || langStats.updated > 0) {
|
|
@@ -6186,16 +6216,16 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6186
6216
|
(locale) => languageStats[locale].missing === 0 && languageStats[locale].updated === 0
|
|
6187
6217
|
);
|
|
6188
6218
|
const missingLanguages = targetLocales.filter((locale) => languageStats[locale].complete === 0);
|
|
6189
|
-
console.log(
|
|
6219
|
+
console.log(chalk3.bold.green(`
|
|
6190
6220
|
\u{1F4A1} OPTIMIZATION TIPS:`));
|
|
6191
6221
|
if (missingLanguages.length > 0) {
|
|
6192
6222
|
console.log(
|
|
6193
|
-
`\u2022 ${
|
|
6223
|
+
`\u2022 ${chalk3.yellow(missingLanguages.join(", "))} ${missingLanguages.length === 1 ? "has" : "have"} no translations yet`
|
|
6194
6224
|
);
|
|
6195
6225
|
}
|
|
6196
6226
|
if (completeLanguages.length > 0) {
|
|
6197
6227
|
console.log(
|
|
6198
|
-
`\u2022 ${
|
|
6228
|
+
`\u2022 ${chalk3.green(completeLanguages.join(", "))} ${completeLanguages.length === 1 ? "is" : "are"} completely translated`
|
|
6199
6229
|
);
|
|
6200
6230
|
}
|
|
6201
6231
|
if (targetLocales.length > 1) {
|
|
@@ -6274,9 +6304,9 @@ function validateParams2(i18nConfig, flags) {
|
|
|
6274
6304
|
import { Command as Command12 } from "interactive-commander";
|
|
6275
6305
|
import * as cp from "node:child_process";
|
|
6276
6306
|
import figlet from "figlet";
|
|
6277
|
-
import
|
|
6307
|
+
import chalk4 from "chalk";
|
|
6278
6308
|
import { vice } from "gradient-string";
|
|
6279
|
-
var
|
|
6309
|
+
var colors2 = {
|
|
6280
6310
|
orange: "#ff6600",
|
|
6281
6311
|
green: "#6ae300",
|
|
6282
6312
|
blue: "#0090ff",
|
|
@@ -6288,7 +6318,7 @@ var may_the_fourth_default = new Command12().command("may-the-fourth").descripti
|
|
|
6288
6318
|
await renderClear();
|
|
6289
6319
|
await renderBanner();
|
|
6290
6320
|
await renderSpacer();
|
|
6291
|
-
console.log(
|
|
6321
|
+
console.log(chalk4.hex(colors2.yellow)("Loading the Star Wars movie..."));
|
|
6292
6322
|
await renderSpacer();
|
|
6293
6323
|
await new Promise((resolve, reject) => {
|
|
6294
6324
|
const ssh = cp.spawn("ssh", ["starwarstel.net"], {
|
|
@@ -6307,10 +6337,10 @@ var may_the_fourth_default = new Command12().command("may-the-fourth").descripti
|
|
|
6307
6337
|
});
|
|
6308
6338
|
await renderSpacer();
|
|
6309
6339
|
console.log(
|
|
6310
|
-
`${
|
|
6340
|
+
`${chalk4.hex(colors2.green)("We hope you enjoyed it! :)")} ${chalk4.hex(colors2.blue)("May the Fourth be with you! \u{1F680}")}`
|
|
6311
6341
|
);
|
|
6312
6342
|
await renderSpacer();
|
|
6313
|
-
console.log(
|
|
6343
|
+
console.log(chalk4.dim(`---`));
|
|
6314
6344
|
await renderSpacer();
|
|
6315
6345
|
await renderHero();
|
|
6316
6346
|
});
|
|
@@ -6333,19 +6363,19 @@ async function renderBanner() {
|
|
|
6333
6363
|
}
|
|
6334
6364
|
async function renderHero() {
|
|
6335
6365
|
console.log(
|
|
6336
|
-
`\u26A1\uFE0F ${
|
|
6366
|
+
`\u26A1\uFE0F ${chalk4.hex(colors2.green)("Lingo.dev")} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
6337
6367
|
);
|
|
6338
6368
|
console.log(" ");
|
|
6339
6369
|
console.log(
|
|
6340
|
-
|
|
6370
|
+
chalk4.hex(colors2.blue)("\u2B50 GitHub Repo: https://lingo.dev/go/gh")
|
|
6341
6371
|
);
|
|
6342
|
-
console.log(
|
|
6372
|
+
console.log(chalk4.hex(colors2.blue)("\u{1F4AC} 24/7 Support: hi@lingo.dev"));
|
|
6343
6373
|
}
|
|
6344
6374
|
|
|
6345
6375
|
// package.json
|
|
6346
6376
|
var package_default = {
|
|
6347
6377
|
name: "lingo.dev",
|
|
6348
|
-
version: "0.92.
|
|
6378
|
+
version: "0.92.9",
|
|
6349
6379
|
description: "Lingo.dev CLI",
|
|
6350
6380
|
private: false,
|
|
6351
6381
|
publishConfig: {
|
|
@@ -6402,22 +6432,24 @@ var package_default = {
|
|
|
6402
6432
|
author: "",
|
|
6403
6433
|
license: "Apache-2.0",
|
|
6404
6434
|
dependencies: {
|
|
6405
|
-
"@ai-sdk/anthropic": "^1.2.
|
|
6406
|
-
"@ai-sdk/openai": "^1.3.
|
|
6435
|
+
"@ai-sdk/anthropic": "^1.2.11",
|
|
6436
|
+
"@ai-sdk/openai": "^1.3.22",
|
|
6407
6437
|
"@babel/generator": "^7.27.1",
|
|
6408
6438
|
"@babel/parser": "^7.27.1",
|
|
6409
6439
|
"@babel/traverse": "^7.27.1",
|
|
6410
6440
|
"@babel/types": "^7.27.1",
|
|
6411
6441
|
"@datocms/cma-client-node": "^4.0.1",
|
|
6412
6442
|
"@gitbeaker/rest": "^39.34.3",
|
|
6443
|
+
"@inkjs/ui": "^2.0.0",
|
|
6413
6444
|
"@inquirer/prompts": "^7.4.1",
|
|
6414
6445
|
"@lingo.dev/_sdk": "workspace:*",
|
|
6415
6446
|
"@lingo.dev/_spec": "workspace:*",
|
|
6416
6447
|
"@modelcontextprotocol/sdk": "^1.5.0",
|
|
6417
6448
|
"@paralleldrive/cuid2": "^2.2.2",
|
|
6418
|
-
ai: "^4.3.
|
|
6449
|
+
ai: "^4.3.15",
|
|
6419
6450
|
bitbucket: "^2.12.0",
|
|
6420
6451
|
chalk: "^5.4.1",
|
|
6452
|
+
"cli-progress": "^3.12.0",
|
|
6421
6453
|
"cli-table3": "^0.6.5",
|
|
6422
6454
|
cors: "^2.8.5",
|
|
6423
6455
|
"csv-parse": "^5.6.0",
|
|
@@ -6435,12 +6467,16 @@ var package_default = {
|
|
|
6435
6467
|
"gradient-string": "^3.0.0",
|
|
6436
6468
|
"gray-matter": "^4.0.3",
|
|
6437
6469
|
ini: "^5.0.0",
|
|
6470
|
+
ink: "^4.2.0",
|
|
6471
|
+
"ink-progress-bar": "^3.0.0",
|
|
6472
|
+
"ink-spinner": "^5.0.0",
|
|
6438
6473
|
inquirer: "^12.6.0",
|
|
6439
6474
|
"interactive-commander": "^0.5.194",
|
|
6440
6475
|
"is-url": "^1.2.4",
|
|
6441
6476
|
jsdom: "^25.0.1",
|
|
6442
6477
|
json5: "^2.2.3",
|
|
6443
6478
|
jsonrepair: "^3.11.2",
|
|
6479
|
+
listr2: "^8.3.2",
|
|
6444
6480
|
lodash: "^4.17.21",
|
|
6445
6481
|
marked: "^15.0.6",
|
|
6446
6482
|
"mdast-util-from-markdown": "^2.0.2",
|
|
@@ -6457,6 +6493,7 @@ var package_default = {
|
|
|
6457
6493
|
plist: "^3.1.0",
|
|
6458
6494
|
"posthog-node": "^4.17.0",
|
|
6459
6495
|
prettier: "^3.4.2",
|
|
6496
|
+
react: "^18.3.1",
|
|
6460
6497
|
"rehype-stringify": "^10.0.1",
|
|
6461
6498
|
"remark-disable-tokenizers": "^1.1.1",
|
|
6462
6499
|
"remark-frontmatter": "^5.0.0",
|
|
@@ -6478,6 +6515,7 @@ var package_default = {
|
|
|
6478
6515
|
},
|
|
6479
6516
|
devDependencies: {
|
|
6480
6517
|
"@types/babel__generator": "^7.27.0",
|
|
6518
|
+
"@types/cli-progress": "^3.11.6",
|
|
6481
6519
|
"@types/cors": "^2.8.17",
|
|
6482
6520
|
"@types/diff": "^7.0.0",
|
|
6483
6521
|
"@types/express": "^5.0.1",
|
|
@@ -6493,6 +6531,7 @@ var package_default = {
|
|
|
6493
6531
|
"@types/node-gettext": "^3.0.6",
|
|
6494
6532
|
"@types/object-hash": "^3.0.6",
|
|
6495
6533
|
"@types/plist": "^3.0.5",
|
|
6534
|
+
"@types/react": "^18.3.20",
|
|
6496
6535
|
"@types/xml2js": "^0.4.14",
|
|
6497
6536
|
tsup: "^8.3.5",
|
|
6498
6537
|
typescript: "^5.8.3",
|
|
@@ -6503,13 +6542,746 @@ var package_default = {
|
|
|
6503
6542
|
}
|
|
6504
6543
|
};
|
|
6505
6544
|
|
|
6545
|
+
// src/cli/cmd/run/index.ts
|
|
6546
|
+
import { Command as Command13 } from "interactive-commander";
|
|
6547
|
+
|
|
6548
|
+
// src/cli/cmd/run/setup.ts
|
|
6549
|
+
import chalk8 from "chalk";
|
|
6550
|
+
import { Listr } from "listr2";
|
|
6551
|
+
|
|
6552
|
+
// src/cli/cmd/run/_const.ts
|
|
6553
|
+
import chalk5 from "chalk";
|
|
6554
|
+
import { ListrDefaultRendererLogLevels } from "listr2";
|
|
6555
|
+
var commonTaskRendererOptions = {
|
|
6556
|
+
color: {
|
|
6557
|
+
[ListrDefaultRendererLogLevels.COMPLETED]: (msg) => msg ? chalk5.hex(colors.green)(msg) : chalk5.hex(colors.green)("")
|
|
6558
|
+
},
|
|
6559
|
+
icon: {
|
|
6560
|
+
[ListrDefaultRendererLogLevels.COMPLETED]: chalk5.hex(colors.green)("\u2713")
|
|
6561
|
+
}
|
|
6562
|
+
};
|
|
6563
|
+
|
|
6564
|
+
// src/cli/localizer/lingodotdev.ts
|
|
6565
|
+
import dedent2 from "dedent";
|
|
6566
|
+
import chalk6 from "chalk";
|
|
6567
|
+
import { LingoDotDevEngine as LingoDotDevEngine2 } from "@lingo.dev/_sdk";
|
|
6568
|
+
function createLingoDotDevLocalizer(explicitApiKey) {
|
|
6569
|
+
const { auth } = getSettings(explicitApiKey);
|
|
6570
|
+
if (!auth) {
|
|
6571
|
+
throw new Error(
|
|
6572
|
+
dedent2`
|
|
6573
|
+
You're trying to use ${chalk6.hex(colors.green)("Lingo.dev")} provider, however, you are not authenticated.
|
|
6574
|
+
|
|
6575
|
+
To fix this issue:
|
|
6576
|
+
1. Run ${chalk6.dim("lingo.dev login")} to authenticate, or
|
|
6577
|
+
2. Use the ${chalk6.dim("--api-key")} flag to provide an API key.
|
|
6578
|
+
3. Set ${chalk6.dim("LINGODOTDEV_API_KEY")} environment variable.
|
|
6579
|
+
`
|
|
6580
|
+
);
|
|
6581
|
+
}
|
|
6582
|
+
const engine = new LingoDotDevEngine2({
|
|
6583
|
+
apiKey: auth.apiKey,
|
|
6584
|
+
apiUrl: auth.apiUrl
|
|
6585
|
+
});
|
|
6586
|
+
return {
|
|
6587
|
+
id: "Lingo.dev",
|
|
6588
|
+
checkAuth: async () => {
|
|
6589
|
+
try {
|
|
6590
|
+
const response = await engine.whoami();
|
|
6591
|
+
return {
|
|
6592
|
+
authenticated: !!response,
|
|
6593
|
+
username: response?.email
|
|
6594
|
+
};
|
|
6595
|
+
} catch {
|
|
6596
|
+
return { authenticated: false };
|
|
6597
|
+
}
|
|
6598
|
+
},
|
|
6599
|
+
localize: async (input2, onProgress) => {
|
|
6600
|
+
if (!Object.keys(input2.processableData).length) {
|
|
6601
|
+
return input2;
|
|
6602
|
+
}
|
|
6603
|
+
const processedData = await engine.localizeObject(
|
|
6604
|
+
input2.processableData,
|
|
6605
|
+
{
|
|
6606
|
+
sourceLocale: input2.sourceLocale,
|
|
6607
|
+
targetLocale: input2.targetLocale,
|
|
6608
|
+
reference: {
|
|
6609
|
+
[input2.sourceLocale]: input2.sourceData,
|
|
6610
|
+
[input2.targetLocale]: input2.targetData
|
|
6611
|
+
}
|
|
6612
|
+
},
|
|
6613
|
+
onProgress
|
|
6614
|
+
);
|
|
6615
|
+
return processedData;
|
|
6616
|
+
}
|
|
6617
|
+
};
|
|
6618
|
+
}
|
|
6619
|
+
|
|
6620
|
+
// src/cli/localizer/explicit.ts
|
|
6621
|
+
import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
6622
|
+
import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
6623
|
+
import chalk7 from "chalk";
|
|
6624
|
+
import dedent3 from "dedent";
|
|
6625
|
+
import { generateText as generateText2 } from "ai";
|
|
6626
|
+
function createExplicitLocalizer(provider) {
|
|
6627
|
+
switch (provider.id) {
|
|
6628
|
+
default:
|
|
6629
|
+
throw new Error(
|
|
6630
|
+
dedent3`
|
|
6631
|
+
You're trying to use unsupported provider: ${chalk7.dim(provider.id)}.
|
|
6632
|
+
|
|
6633
|
+
To fix this issue:
|
|
6634
|
+
1. Switch to one of the supported providers, or
|
|
6635
|
+
2. Remove the ${chalk7.italic("provider")} node from your i18n.json configuration to switch to ${chalk7.hex(colors.green)("Lingo.dev")}
|
|
6636
|
+
|
|
6637
|
+
${chalk7.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
6638
|
+
`
|
|
6639
|
+
);
|
|
6640
|
+
case "openai":
|
|
6641
|
+
return createAiSdkLocalizer({
|
|
6642
|
+
factory: (params) => createOpenAI2(params).languageModel(provider.model),
|
|
6643
|
+
id: provider.id,
|
|
6644
|
+
prompt: provider.prompt,
|
|
6645
|
+
apiKeyName: "OPENAI_API_KEY",
|
|
6646
|
+
baseUrl: provider.baseUrl
|
|
6647
|
+
});
|
|
6648
|
+
case "anthropic":
|
|
6649
|
+
return createAiSdkLocalizer({
|
|
6650
|
+
factory: (params) => createAnthropic2(params).languageModel(provider.model),
|
|
6651
|
+
id: provider.id,
|
|
6652
|
+
prompt: provider.prompt,
|
|
6653
|
+
apiKeyName: "ANTHROPIC_API_KEY",
|
|
6654
|
+
baseUrl: provider.baseUrl
|
|
6655
|
+
});
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
function createAiSdkLocalizer(params) {
|
|
6659
|
+
const apiKey = process.env[params.apiKeyName];
|
|
6660
|
+
if (!apiKey) {
|
|
6661
|
+
throw new Error(
|
|
6662
|
+
dedent3`
|
|
6663
|
+
You're trying to use raw ${chalk7.dim(params.id)} API for translation, however, ${chalk7.dim(params.apiKeyName)} environment variable is not set.
|
|
6664
|
+
|
|
6665
|
+
To fix this issue:
|
|
6666
|
+
1. Set ${chalk7.dim(params.apiKeyName)} in your environment variables, or
|
|
6667
|
+
2. Remove the ${chalk7.italic("provider")} node from your i18n.json configuration to switch to ${chalk7.hex(colors.green)("Lingo.dev")}
|
|
6668
|
+
|
|
6669
|
+
${chalk7.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
6670
|
+
`
|
|
6671
|
+
);
|
|
6672
|
+
}
|
|
6673
|
+
const model = params.factory({
|
|
6674
|
+
apiKey,
|
|
6675
|
+
baseUrl: params.baseUrl
|
|
6676
|
+
});
|
|
6677
|
+
return {
|
|
6678
|
+
id: params.id,
|
|
6679
|
+
checkAuth: async () => {
|
|
6680
|
+
try {
|
|
6681
|
+
await generateText2({
|
|
6682
|
+
model,
|
|
6683
|
+
messages: [
|
|
6684
|
+
{ role: "system", content: "You are an echo server" },
|
|
6685
|
+
{ role: "user", content: "OK" },
|
|
6686
|
+
{ role: "assistant", content: "OK" },
|
|
6687
|
+
{ role: "user", content: "OK" }
|
|
6688
|
+
]
|
|
6689
|
+
});
|
|
6690
|
+
return { authenticated: true, username: "anonymous" };
|
|
6691
|
+
} catch (error) {
|
|
6692
|
+
return { authenticated: false };
|
|
6693
|
+
}
|
|
6694
|
+
},
|
|
6695
|
+
localize: async (input2) => {
|
|
6696
|
+
const systemPrompt = params.prompt.replaceAll("{source}", input2.sourceLocale).replaceAll("{target}", input2.targetLocale);
|
|
6697
|
+
const shots = [
|
|
6698
|
+
[
|
|
6699
|
+
{
|
|
6700
|
+
sourceLocale: "en",
|
|
6701
|
+
targetLocale: "es",
|
|
6702
|
+
data: {
|
|
6703
|
+
message: "Hello, world!"
|
|
6704
|
+
}
|
|
6705
|
+
},
|
|
6706
|
+
{
|
|
6707
|
+
sourceLocale: "en",
|
|
6708
|
+
targetLocale: "es",
|
|
6709
|
+
data: {
|
|
6710
|
+
message: "Hola, mundo!"
|
|
6711
|
+
}
|
|
6712
|
+
}
|
|
6713
|
+
]
|
|
6714
|
+
];
|
|
6715
|
+
const payload = {
|
|
6716
|
+
sourceLocale: input2.sourceLocale,
|
|
6717
|
+
targetLocale: input2.targetLocale,
|
|
6718
|
+
data: input2.processableData
|
|
6719
|
+
};
|
|
6720
|
+
const response = await generateText2({
|
|
6721
|
+
model,
|
|
6722
|
+
messages: [
|
|
6723
|
+
{ role: "system", content: systemPrompt },
|
|
6724
|
+
{ role: "user", content: "OK" },
|
|
6725
|
+
...shots.flatMap(
|
|
6726
|
+
([userShot, assistantShot]) => [
|
|
6727
|
+
{ role: "user", content: JSON.stringify(userShot) },
|
|
6728
|
+
{ role: "assistant", content: JSON.stringify(assistantShot) }
|
|
6729
|
+
]
|
|
6730
|
+
),
|
|
6731
|
+
{ role: "user", content: JSON.stringify(payload) }
|
|
6732
|
+
]
|
|
6733
|
+
});
|
|
6734
|
+
const result = JSON.parse(response.text);
|
|
6735
|
+
return result.data;
|
|
6736
|
+
}
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
|
|
6740
|
+
// src/cli/localizer/index.ts
|
|
6741
|
+
function createLocalizer(provider) {
|
|
6742
|
+
if (!provider) {
|
|
6743
|
+
return createLingoDotDevLocalizer();
|
|
6744
|
+
} else {
|
|
6745
|
+
return createExplicitLocalizer(provider);
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
// src/cli/cmd/run/setup.ts
|
|
6750
|
+
async function setup(input2) {
|
|
6751
|
+
console.log(chalk8.hex(colors.orange)("[Setup]"));
|
|
6752
|
+
return new Listr(
|
|
6753
|
+
[
|
|
6754
|
+
{
|
|
6755
|
+
title: "Setting up the environment",
|
|
6756
|
+
task: async (ctx, task) => {
|
|
6757
|
+
task.title = `Environment setup completed`;
|
|
6758
|
+
}
|
|
6759
|
+
},
|
|
6760
|
+
{
|
|
6761
|
+
title: "Loading i18n configuration",
|
|
6762
|
+
task: async (ctx, task) => {
|
|
6763
|
+
ctx.config = getConfig(true);
|
|
6764
|
+
if (!ctx.config) {
|
|
6765
|
+
throw new Error(
|
|
6766
|
+
"i18n.json not found. Please run `lingo.dev init` to initialize the project."
|
|
6767
|
+
);
|
|
6768
|
+
} else if (!ctx.config.buckets || !Object.keys(ctx.config.buckets).length) {
|
|
6769
|
+
throw new Error(
|
|
6770
|
+
"No buckets found in i18n.json. Please add at least one bucket containing i18n content."
|
|
6771
|
+
);
|
|
6772
|
+
} else if (ctx.flags.locale?.some(
|
|
6773
|
+
(locale) => !ctx.config?.locale.targets.includes(locale)
|
|
6774
|
+
)) {
|
|
6775
|
+
throw new Error(
|
|
6776
|
+
`One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list first and try again.`
|
|
6777
|
+
);
|
|
6778
|
+
} else if (ctx.flags.bucket?.some(
|
|
6779
|
+
(bucket) => !ctx.config?.buckets[bucket]
|
|
6780
|
+
)) {
|
|
6781
|
+
throw new Error(
|
|
6782
|
+
`One or more specified buckets do not exist in i18n.json. Please add them to the list first and try again.`
|
|
6783
|
+
);
|
|
6784
|
+
}
|
|
6785
|
+
task.title = `Loaded i18n configuration`;
|
|
6786
|
+
}
|
|
6787
|
+
},
|
|
6788
|
+
{
|
|
6789
|
+
title: "Selecting localization provider",
|
|
6790
|
+
task: async (ctx, task) => {
|
|
6791
|
+
ctx.localizer = createLocalizer(ctx.config?.provider);
|
|
6792
|
+
if (!ctx.localizer) {
|
|
6793
|
+
throw new Error(
|
|
6794
|
+
"Could not create localization provider. Please check your i18n.json configuration."
|
|
6795
|
+
);
|
|
6796
|
+
}
|
|
6797
|
+
task.title = ctx.localizer.id === "Lingo.dev" ? `Using ${chalk8.hex(colors.green)(ctx.localizer.id)} provider` : `Using raw ${chalk8.hex(colors.yellow)(ctx.localizer.id)} API`;
|
|
6798
|
+
}
|
|
6799
|
+
},
|
|
6800
|
+
{
|
|
6801
|
+
title: "Checking authentication",
|
|
6802
|
+
task: async (ctx, task) => {
|
|
6803
|
+
const authStatus = await ctx.localizer.checkAuth();
|
|
6804
|
+
if (!authStatus.authenticated) {
|
|
6805
|
+
throw new Error(
|
|
6806
|
+
`Failed to authenticate with ${chalk8.hex(colors.yellow)(ctx.localizer.id)} provider. Please check your API key and try again.`
|
|
6807
|
+
);
|
|
6808
|
+
}
|
|
6809
|
+
task.title = `Authenticated as ${chalk8.hex(colors.yellow)(authStatus.username)}`;
|
|
6810
|
+
}
|
|
6811
|
+
},
|
|
6812
|
+
{
|
|
6813
|
+
title: "Initializing localization provider",
|
|
6814
|
+
async task(ctx, task) {
|
|
6815
|
+
const isLingoDotDev = ctx.localizer.id === "Lingo.dev";
|
|
6816
|
+
const subTasks = isLingoDotDev ? [
|
|
6817
|
+
"Brand voice enabled",
|
|
6818
|
+
"Translation memory connected",
|
|
6819
|
+
"Glossary enabled",
|
|
6820
|
+
"Quality assurance enabled"
|
|
6821
|
+
].map((title) => ({ title, task: () => {
|
|
6822
|
+
} })) : [
|
|
6823
|
+
"Skipping brand voice",
|
|
6824
|
+
"Skipping glossary",
|
|
6825
|
+
"Skipping translation memory",
|
|
6826
|
+
"Skipping quality assurance"
|
|
6827
|
+
].map((title) => ({ title, task: () => {
|
|
6828
|
+
}, skip: true }));
|
|
6829
|
+
return task.newListr(subTasks, {
|
|
6830
|
+
concurrent: true,
|
|
6831
|
+
rendererOptions: { collapseSubtasks: false }
|
|
6832
|
+
});
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
],
|
|
6836
|
+
{
|
|
6837
|
+
rendererOptions: commonTaskRendererOptions
|
|
6838
|
+
}
|
|
6839
|
+
).run(input2);
|
|
6840
|
+
}
|
|
6841
|
+
|
|
6842
|
+
// src/cli/cmd/run/plan.ts
|
|
6843
|
+
import chalk9 from "chalk";
|
|
6844
|
+
import { Listr as Listr2 } from "listr2";
|
|
6845
|
+
import { resolveOverriddenLocale as resolveOverriddenLocale7 } from "@lingo.dev/_spec";
|
|
6846
|
+
async function plan(input2) {
|
|
6847
|
+
console.log(chalk9.hex(colors.orange)("[Planning]"));
|
|
6848
|
+
let buckets = getBuckets(input2.config);
|
|
6849
|
+
if (input2.flags.bucket) {
|
|
6850
|
+
buckets = buckets.filter((b) => input2.flags.bucket.includes(b.type));
|
|
6851
|
+
}
|
|
6852
|
+
let locales = input2.config.locale.targets;
|
|
6853
|
+
if (input2.flags.locale) {
|
|
6854
|
+
locales = locales.filter((l) => input2.flags.locale.includes(l));
|
|
6855
|
+
}
|
|
6856
|
+
return new Listr2(
|
|
6857
|
+
[
|
|
6858
|
+
{
|
|
6859
|
+
title: "Locating content buckets",
|
|
6860
|
+
task: async (ctx, task) => {
|
|
6861
|
+
const bucketCount = buckets.length;
|
|
6862
|
+
const bucketFilter = input2.flags.bucket ? ` ${chalk9.dim(`(filtered by: ${chalk9.hex(colors.yellow)(input2.flags.bucket.join(", "))})`)}` : "";
|
|
6863
|
+
task.title = `Found ${chalk9.hex(colors.yellow)(bucketCount.toString())} bucket(s)${bucketFilter}`;
|
|
6864
|
+
}
|
|
6865
|
+
},
|
|
6866
|
+
{
|
|
6867
|
+
title: "Detecting locales",
|
|
6868
|
+
task: async (ctx, task) => {
|
|
6869
|
+
if (!locales.length) {
|
|
6870
|
+
throw new Error(
|
|
6871
|
+
`No target locales found in config. Please add locales to your i18n.json config file.`
|
|
6872
|
+
);
|
|
6873
|
+
}
|
|
6874
|
+
const localeFilter = input2.flags.locale ? ` ${chalk9.dim(`(filtered by: ${chalk9.hex(colors.yellow)(input2.flags.locale.join(", "))})`)}` : "";
|
|
6875
|
+
task.title = `Found ${chalk9.hex(colors.yellow)(locales.length.toString())} target locale(s)${localeFilter}`;
|
|
6876
|
+
}
|
|
6877
|
+
},
|
|
6878
|
+
{
|
|
6879
|
+
title: "Locating localizable files",
|
|
6880
|
+
task: async (ctx, task) => {
|
|
6881
|
+
const patterns = [];
|
|
6882
|
+
for (const bucket of buckets) {
|
|
6883
|
+
for (const bucketPath of bucket.paths) {
|
|
6884
|
+
if (input2.flags.file) {
|
|
6885
|
+
if (!input2.flags.file.some(
|
|
6886
|
+
(f) => bucketPath.pathPattern.includes(f)
|
|
6887
|
+
)) {
|
|
6888
|
+
continue;
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
patterns.push(bucketPath.pathPattern);
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6894
|
+
const fileFilter = input2.flags.file ? ` ${chalk9.dim(`(filtered by: ${chalk9.hex(colors.yellow)(input2.flags.file.join(", "))})`)}` : "";
|
|
6895
|
+
task.title = `Found ${chalk9.hex(colors.yellow)(patterns.length.toString())} path pattern(s)${fileFilter}`;
|
|
6896
|
+
}
|
|
6897
|
+
},
|
|
6898
|
+
{
|
|
6899
|
+
title: "Computing translation tasks",
|
|
6900
|
+
task: async (ctx, task) => {
|
|
6901
|
+
for (const bucket of buckets) {
|
|
6902
|
+
for (const bucketPath of bucket.paths) {
|
|
6903
|
+
if (input2.flags.file) {
|
|
6904
|
+
if (!input2.flags.file.some(
|
|
6905
|
+
(f) => bucketPath.pathPattern.includes(f)
|
|
6906
|
+
)) {
|
|
6907
|
+
continue;
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
const sourceLocale = resolveOverriddenLocale7(
|
|
6911
|
+
ctx.config.locale.source,
|
|
6912
|
+
bucketPath.delimiter
|
|
6913
|
+
);
|
|
6914
|
+
for (const _targetLocale of locales) {
|
|
6915
|
+
const targetLocale = resolveOverriddenLocale7(
|
|
6916
|
+
_targetLocale,
|
|
6917
|
+
bucketPath.delimiter
|
|
6918
|
+
);
|
|
6919
|
+
if (sourceLocale === targetLocale) continue;
|
|
6920
|
+
ctx.tasks.push({
|
|
6921
|
+
sourceLocale,
|
|
6922
|
+
targetLocale,
|
|
6923
|
+
bucketType: bucket.type,
|
|
6924
|
+
bucketPathPattern: bucketPath.pathPattern,
|
|
6925
|
+
injectLocale: bucket.injectLocale || [],
|
|
6926
|
+
lockedKeys: bucket.lockedKeys || [],
|
|
6927
|
+
lockedPatterns: bucket.lockedPatterns || []
|
|
6928
|
+
});
|
|
6929
|
+
}
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6932
|
+
task.title = `Prepared ${chalk9.hex(colors.green)(ctx.tasks.length.toString())} translation task(s)`;
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6935
|
+
],
|
|
6936
|
+
{
|
|
6937
|
+
rendererOptions: commonTaskRendererOptions
|
|
6938
|
+
}
|
|
6939
|
+
).run(input2);
|
|
6940
|
+
}
|
|
6941
|
+
|
|
6942
|
+
// src/cli/cmd/run/execute.ts
|
|
6943
|
+
import chalk10 from "chalk";
|
|
6944
|
+
import { Listr as Listr3 } from "listr2";
|
|
6945
|
+
import pLimit from "p-limit";
|
|
6946
|
+
import _28 from "lodash";
|
|
6947
|
+
var MAX_WORKER_COUNT = 10;
|
|
6948
|
+
async function execute(input2) {
|
|
6949
|
+
const effectiveConcurrency = Math.min(
|
|
6950
|
+
input2.flags.concurrency,
|
|
6951
|
+
input2.tasks.length,
|
|
6952
|
+
MAX_WORKER_COUNT
|
|
6953
|
+
);
|
|
6954
|
+
console.log(chalk10.hex(colors.orange)(`[Localization]`));
|
|
6955
|
+
return new Listr3(
|
|
6956
|
+
[
|
|
6957
|
+
{
|
|
6958
|
+
title: "Initializing localization engine",
|
|
6959
|
+
task: async (ctx, task) => {
|
|
6960
|
+
task.title = `Localization engine ${chalk10.hex(colors.green)("ready")} (${ctx.localizer.id})`;
|
|
6961
|
+
}
|
|
6962
|
+
},
|
|
6963
|
+
{
|
|
6964
|
+
title: `Processing localization tasks ${chalk10.dim(`(tasks: ${input2.tasks.length}, concurrency: ${effectiveConcurrency})`)}`,
|
|
6965
|
+
task: (ctx, task) => {
|
|
6966
|
+
if (input2.tasks.length < 1) {
|
|
6967
|
+
task.title = `Skipping, nothing to localize.`;
|
|
6968
|
+
task.skip();
|
|
6969
|
+
return;
|
|
6970
|
+
}
|
|
6971
|
+
const i18nLimiter = pLimit(effectiveConcurrency);
|
|
6972
|
+
const lockfileLimiter = pLimit(1);
|
|
6973
|
+
const workersCount = effectiveConcurrency;
|
|
6974
|
+
const workerTasks = [];
|
|
6975
|
+
for (let i = 0; i < workersCount; i++) {
|
|
6976
|
+
const assignedTasks = ctx.tasks.filter(
|
|
6977
|
+
(_29, idx) => idx % workersCount === i
|
|
6978
|
+
);
|
|
6979
|
+
workerTasks.push(
|
|
6980
|
+
createWorkerTask({
|
|
6981
|
+
ctx,
|
|
6982
|
+
assignedTasks,
|
|
6983
|
+
lockfileLimiter,
|
|
6984
|
+
i18nLimiter,
|
|
6985
|
+
onDone() {
|
|
6986
|
+
task.title = createExecutionProgressMessage(ctx);
|
|
6987
|
+
}
|
|
6988
|
+
})
|
|
6989
|
+
);
|
|
6990
|
+
}
|
|
6991
|
+
return task.newListr(workerTasks, {
|
|
6992
|
+
concurrent: true,
|
|
6993
|
+
exitOnError: false,
|
|
6994
|
+
rendererOptions: {
|
|
6995
|
+
...commonTaskRendererOptions,
|
|
6996
|
+
collapseSubtasks: true
|
|
6997
|
+
}
|
|
6998
|
+
});
|
|
6999
|
+
}
|
|
7000
|
+
}
|
|
7001
|
+
],
|
|
7002
|
+
{
|
|
7003
|
+
exitOnError: false,
|
|
7004
|
+
rendererOptions: commonTaskRendererOptions
|
|
7005
|
+
}
|
|
7006
|
+
).run(input2);
|
|
7007
|
+
}
|
|
7008
|
+
function createWorkerStatusMessage(args) {
|
|
7009
|
+
const displayPath = args.assignedTask.bucketPathPattern.replace(
|
|
7010
|
+
"[locale]",
|
|
7011
|
+
args.assignedTask.targetLocale
|
|
7012
|
+
);
|
|
7013
|
+
return `[${chalk10.hex(colors.yellow)(`${args.percentage}%`)}] Processing: ${chalk10.dim(
|
|
7014
|
+
displayPath
|
|
7015
|
+
)} (${chalk10.hex(colors.yellow)(args.assignedTask.sourceLocale)} -> ${chalk10.hex(
|
|
7016
|
+
colors.yellow
|
|
7017
|
+
)(args.assignedTask.targetLocale)})`;
|
|
7018
|
+
}
|
|
7019
|
+
function createExecutionProgressMessage(ctx) {
|
|
7020
|
+
const succeededTasksCount = countTasks(
|
|
7021
|
+
ctx,
|
|
7022
|
+
(_t, result) => result.status === "success"
|
|
7023
|
+
);
|
|
7024
|
+
const failedTasksCount = countTasks(
|
|
7025
|
+
ctx,
|
|
7026
|
+
(_t, result) => result.status === "error"
|
|
7027
|
+
);
|
|
7028
|
+
const skippedTasksCount = countTasks(
|
|
7029
|
+
ctx,
|
|
7030
|
+
(_t, result) => result.status === "skipped"
|
|
7031
|
+
);
|
|
7032
|
+
return `Processed ${chalk10.green(succeededTasksCount)}/${ctx.tasks.length}, Failed ${chalk10.red(failedTasksCount)}, Skipped ${chalk10.dim(skippedTasksCount)}`;
|
|
7033
|
+
}
|
|
7034
|
+
function createLoaderForTask(assignedTask) {
|
|
7035
|
+
const bucketLoader = createBucketLoader(
|
|
7036
|
+
assignedTask.bucketType,
|
|
7037
|
+
assignedTask.bucketPathPattern,
|
|
7038
|
+
{
|
|
7039
|
+
defaultLocale: assignedTask.sourceLocale,
|
|
7040
|
+
isCacheRestore: false,
|
|
7041
|
+
injectLocale: assignedTask.injectLocale
|
|
7042
|
+
},
|
|
7043
|
+
assignedTask.lockedKeys,
|
|
7044
|
+
assignedTask.lockedPatterns
|
|
7045
|
+
);
|
|
7046
|
+
bucketLoader.setDefaultLocale(assignedTask.sourceLocale);
|
|
7047
|
+
return bucketLoader;
|
|
7048
|
+
}
|
|
7049
|
+
function createWorkerTask(args) {
|
|
7050
|
+
return {
|
|
7051
|
+
title: "Initializing...",
|
|
7052
|
+
task: async (_subCtx, subTask) => {
|
|
7053
|
+
for (const assignedTask of args.assignedTasks) {
|
|
7054
|
+
subTask.title = createWorkerStatusMessage({
|
|
7055
|
+
assignedTask,
|
|
7056
|
+
percentage: 0
|
|
7057
|
+
});
|
|
7058
|
+
const bucketLoader = createLoaderForTask(assignedTask);
|
|
7059
|
+
const deltaProcessor = createDeltaProcessor(
|
|
7060
|
+
assignedTask.bucketPathPattern
|
|
7061
|
+
);
|
|
7062
|
+
const taskResult = await args.i18nLimiter(async () => {
|
|
7063
|
+
try {
|
|
7064
|
+
const sourceData = await bucketLoader.pull(
|
|
7065
|
+
assignedTask.sourceLocale
|
|
7066
|
+
);
|
|
7067
|
+
const targetData = await bucketLoader.pull(
|
|
7068
|
+
assignedTask.targetLocale
|
|
7069
|
+
);
|
|
7070
|
+
const checksums = await deltaProcessor.loadChecksums();
|
|
7071
|
+
const delta = await deltaProcessor.calculateDelta({
|
|
7072
|
+
sourceData,
|
|
7073
|
+
targetData,
|
|
7074
|
+
checksums
|
|
7075
|
+
});
|
|
7076
|
+
const processableData = _28.chain(sourceData).entries().filter(
|
|
7077
|
+
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!args.ctx.flags.force
|
|
7078
|
+
).fromPairs().value();
|
|
7079
|
+
if (!Object.keys(processableData).length) {
|
|
7080
|
+
return { status: "skipped" };
|
|
7081
|
+
}
|
|
7082
|
+
const processedTargetData = await args.ctx.localizer.localize(
|
|
7083
|
+
{
|
|
7084
|
+
sourceLocale: assignedTask.sourceLocale,
|
|
7085
|
+
targetLocale: assignedTask.targetLocale,
|
|
7086
|
+
sourceData,
|
|
7087
|
+
targetData,
|
|
7088
|
+
processableData
|
|
7089
|
+
},
|
|
7090
|
+
(progress) => {
|
|
7091
|
+
subTask.title = createWorkerStatusMessage({
|
|
7092
|
+
assignedTask,
|
|
7093
|
+
percentage: progress
|
|
7094
|
+
});
|
|
7095
|
+
}
|
|
7096
|
+
);
|
|
7097
|
+
const finalTargetData = _28.merge(
|
|
7098
|
+
{},
|
|
7099
|
+
sourceData,
|
|
7100
|
+
targetData,
|
|
7101
|
+
processedTargetData
|
|
7102
|
+
);
|
|
7103
|
+
await bucketLoader.push(assignedTask.targetLocale, finalTargetData);
|
|
7104
|
+
await args.lockfileLimiter(async () => {
|
|
7105
|
+
const checksums2 = await deltaProcessor.createChecksums(sourceData);
|
|
7106
|
+
await deltaProcessor.saveChecksums(checksums2);
|
|
7107
|
+
});
|
|
7108
|
+
return { status: "success" };
|
|
7109
|
+
} catch (error) {
|
|
7110
|
+
return {
|
|
7111
|
+
status: "error",
|
|
7112
|
+
error
|
|
7113
|
+
};
|
|
7114
|
+
}
|
|
7115
|
+
});
|
|
7116
|
+
args.ctx.results.set(assignedTask, taskResult);
|
|
7117
|
+
}
|
|
7118
|
+
subTask.title = "Done";
|
|
7119
|
+
}
|
|
7120
|
+
};
|
|
7121
|
+
}
|
|
7122
|
+
function countTasks(ctx, predicate) {
|
|
7123
|
+
return Array.from(ctx.results.entries()).filter(
|
|
7124
|
+
([task, result]) => predicate(task, result)
|
|
7125
|
+
).length;
|
|
7126
|
+
}
|
|
7127
|
+
|
|
7128
|
+
// src/cli/cmd/run/_types.ts
|
|
7129
|
+
import {
|
|
7130
|
+
bucketTypeSchema as bucketTypeSchema4,
|
|
7131
|
+
localeCodeSchema as localeCodeSchema3
|
|
7132
|
+
} from "@lingo.dev/_spec";
|
|
7133
|
+
import { z as z2 } from "zod";
|
|
7134
|
+
var flagsSchema2 = z2.object({
|
|
7135
|
+
locale: z2.array(localeCodeSchema3).optional(),
|
|
7136
|
+
bucket: z2.array(bucketTypeSchema4).optional(),
|
|
7137
|
+
key: z2.array(z2.string()).optional(),
|
|
7138
|
+
file: z2.array(z2.string()).optional(),
|
|
7139
|
+
apiKey: z2.string().optional(),
|
|
7140
|
+
force: z2.boolean().optional(),
|
|
7141
|
+
frozen: z2.boolean().optional(),
|
|
7142
|
+
verbose: z2.boolean().optional(),
|
|
7143
|
+
strict: z2.boolean().optional(),
|
|
7144
|
+
interactive: z2.boolean().default(false),
|
|
7145
|
+
concurrency: z2.number().positive().default(10),
|
|
7146
|
+
debug: z2.boolean().default(false)
|
|
7147
|
+
});
|
|
7148
|
+
|
|
7149
|
+
// src/cli/cmd/run/_render.ts
|
|
7150
|
+
import chalk11 from "chalk";
|
|
7151
|
+
import figlet2 from "figlet";
|
|
7152
|
+
import { vice as vice2 } from "gradient-string";
|
|
7153
|
+
import readline2 from "readline";
|
|
7154
|
+
async function renderClear2() {
|
|
7155
|
+
console.log("\x1Bc");
|
|
7156
|
+
}
|
|
7157
|
+
async function renderSpacer2() {
|
|
7158
|
+
console.log(" ");
|
|
7159
|
+
}
|
|
7160
|
+
async function renderBanner2() {
|
|
7161
|
+
console.log(
|
|
7162
|
+
vice2(
|
|
7163
|
+
figlet2.textSync("LINGO.DEV", {
|
|
7164
|
+
font: "ANSI Shadow",
|
|
7165
|
+
horizontalLayout: "default",
|
|
7166
|
+
verticalLayout: "default"
|
|
7167
|
+
})
|
|
7168
|
+
)
|
|
7169
|
+
);
|
|
7170
|
+
}
|
|
7171
|
+
async function renderHero2() {
|
|
7172
|
+
console.log(
|
|
7173
|
+
`\u26A1\uFE0F ${chalk11.hex(colors.green)("Lingo.dev")} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
7174
|
+
);
|
|
7175
|
+
console.log("");
|
|
7176
|
+
const label1 = "\u2B50 GitHub Repo:";
|
|
7177
|
+
const label2 = "\u{1F4DA} Docs:";
|
|
7178
|
+
const label3 = "\u{1F4AC} 24/7 Support:";
|
|
7179
|
+
const maxLabelWidth = 17;
|
|
7180
|
+
console.log(
|
|
7181
|
+
`${chalk11.hex(colors.blue)(label1.padEnd(maxLabelWidth))} ${chalk11.hex(colors.blue)("https://lingo.dev/go/gh")}`
|
|
7182
|
+
);
|
|
7183
|
+
console.log(
|
|
7184
|
+
`${chalk11.hex(colors.blue)(label2.padEnd(maxLabelWidth + 1))} ${chalk11.hex(colors.blue)("https://lingo.dev/go/docs")}`
|
|
7185
|
+
);
|
|
7186
|
+
console.log(
|
|
7187
|
+
`${chalk11.hex(colors.blue)(label3.padEnd(maxLabelWidth + 1))} ${chalk11.hex(colors.blue)("hi@lingo.dev")}`
|
|
7188
|
+
);
|
|
7189
|
+
}
|
|
7190
|
+
async function pauseIfDebug(debug) {
|
|
7191
|
+
if (debug) {
|
|
7192
|
+
await waitForUserPrompt("Press Enter to continue...");
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
async function waitForUserPrompt(message) {
|
|
7196
|
+
const rl = readline2.createInterface({
|
|
7197
|
+
input: process.stdin,
|
|
7198
|
+
output: process.stdout
|
|
7199
|
+
});
|
|
7200
|
+
return new Promise((resolve) => {
|
|
7201
|
+
rl.question(chalk11.dim(`[${message}]
|
|
7202
|
+
`), () => {
|
|
7203
|
+
rl.close();
|
|
7204
|
+
resolve();
|
|
7205
|
+
});
|
|
7206
|
+
});
|
|
7207
|
+
}
|
|
7208
|
+
async function renderSummary(ctx) {
|
|
7209
|
+
console.log(chalk11.hex(colors.green)("[Done]"));
|
|
7210
|
+
const skippedTasksCount = ctx.results.values().filter((r) => r.status === "skipped").toArray().length;
|
|
7211
|
+
console.log(
|
|
7212
|
+
`\u2022 ${chalk11.hex(colors.yellow)(skippedTasksCount)} restored from cache`
|
|
7213
|
+
);
|
|
7214
|
+
const succeededTasksCount = ctx.results.values().filter((r) => r.status === "success").toArray().length;
|
|
7215
|
+
console.log(`\u2022 ${chalk11.hex(colors.yellow)(succeededTasksCount)} processed`);
|
|
7216
|
+
const failedTasksCount = ctx.results.values().filter((r) => r.status === "error").toArray().length;
|
|
7217
|
+
console.log(`\u2022 ${chalk11.hex(colors.yellow)(failedTasksCount)} failed`);
|
|
7218
|
+
}
|
|
7219
|
+
|
|
7220
|
+
// src/cli/cmd/run/index.ts
|
|
7221
|
+
var run_default = new Command13().command("run").description("Run Lingo.dev localization engine").helpOption("-h, --help", "Show help").option(
|
|
7222
|
+
"--locale <locale>",
|
|
7223
|
+
"Locale to process",
|
|
7224
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
7225
|
+
).option(
|
|
7226
|
+
"--bucket <bucket>",
|
|
7227
|
+
"Bucket to process",
|
|
7228
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
7229
|
+
).option(
|
|
7230
|
+
"--file <file>",
|
|
7231
|
+
"File to process. Process only files that include this string in their path. Useful if you have a lot of files and want to focus on a specific one. Specify more files separated by commas or spaces.",
|
|
7232
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
7233
|
+
).option(
|
|
7234
|
+
"--key <key>",
|
|
7235
|
+
"Key to process. Process only a specific translation key, useful for updating a single entry",
|
|
7236
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
7237
|
+
).option(
|
|
7238
|
+
"--force",
|
|
7239
|
+
"Ignore lockfile and process all keys, useful for full re-translation"
|
|
7240
|
+
).option(
|
|
7241
|
+
"--api-key <api-key>",
|
|
7242
|
+
"Explicitly set the API key to use, override the default API key from settings"
|
|
7243
|
+
).option(
|
|
7244
|
+
"--debug",
|
|
7245
|
+
"Pause execution at start for debugging purposes, waits for user confirmation before proceeding"
|
|
7246
|
+
).option(
|
|
7247
|
+
"--concurrency <concurrency>",
|
|
7248
|
+
"Number of concurrent tasks to run",
|
|
7249
|
+
(val) => parseInt(val)
|
|
7250
|
+
).action(async (args) => {
|
|
7251
|
+
try {
|
|
7252
|
+
const ctx = {
|
|
7253
|
+
flags: flagsSchema2.parse(args),
|
|
7254
|
+
config: null,
|
|
7255
|
+
results: /* @__PURE__ */ new Map(),
|
|
7256
|
+
tasks: [],
|
|
7257
|
+
localizer: null
|
|
7258
|
+
};
|
|
7259
|
+
await pauseIfDebug(ctx.flags.debug);
|
|
7260
|
+
await renderClear2();
|
|
7261
|
+
await renderSpacer2();
|
|
7262
|
+
await renderBanner2();
|
|
7263
|
+
await renderHero2();
|
|
7264
|
+
await renderSpacer2();
|
|
7265
|
+
await setup(ctx);
|
|
7266
|
+
await renderSpacer2();
|
|
7267
|
+
await plan(ctx);
|
|
7268
|
+
await renderSpacer2();
|
|
7269
|
+
await execute(ctx);
|
|
7270
|
+
await renderSpacer2();
|
|
7271
|
+
await renderSummary(ctx);
|
|
7272
|
+
await renderSpacer2();
|
|
7273
|
+
} catch (error) {
|
|
7274
|
+
process.exit(1);
|
|
7275
|
+
}
|
|
7276
|
+
});
|
|
7277
|
+
|
|
6506
7278
|
// src/cli/index.ts
|
|
6507
7279
|
dotenv.config();
|
|
6508
7280
|
var cli_default = new InteractiveCommand2().name("lingo.dev").description("Lingo.dev CLI").helpOption("-h, --help", "Show help").addHelpText(
|
|
6509
7281
|
"beforeAll",
|
|
6510
7282
|
`
|
|
6511
|
-
${
|
|
6512
|
-
|
|
7283
|
+
${vice3(
|
|
7284
|
+
figlet3.textSync("LINGO.DEV", {
|
|
6513
7285
|
font: "ANSI Shadow",
|
|
6514
7286
|
horizontalLayout: "default",
|
|
6515
7287
|
verticalLayout: "default"
|
|
@@ -6520,11 +7292,11 @@ ${vice2(
|
|
|
6520
7292
|
|
|
6521
7293
|
Star the the repo :) https://github.com/LingoDotDev/lingo.dev
|
|
6522
7294
|
`
|
|
6523
|
-
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default).addCommand(mcp_default).addCommand(ci_default).addCommand(status_default).addCommand(may_the_fourth_default, { hidden: true }).exitOverride((err) => {
|
|
7295
|
+
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default).addCommand(mcp_default).addCommand(ci_default).addCommand(status_default).addCommand(may_the_fourth_default, { hidden: true }).addCommand(run_default, { hidden: true }).exitOverride((err) => {
|
|
6524
7296
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
6525
7297
|
process.exit(0);
|
|
6526
7298
|
}
|
|
6527
|
-
|
|
7299
|
+
process.exit(1);
|
|
6528
7300
|
});
|
|
6529
7301
|
export {
|
|
6530
7302
|
cli_default as default
|