lingo.dev 0.92.7 → 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 +963 -148
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +972 -157
- 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";
|
|
@@ -850,46 +850,67 @@ import Ora4 from "ora";
|
|
|
850
850
|
import _5 from "lodash";
|
|
851
851
|
import path9 from "path";
|
|
852
852
|
import { glob as glob2 } from "glob";
|
|
853
|
-
import {
|
|
853
|
+
import {
|
|
854
|
+
resolveOverriddenLocale
|
|
855
|
+
} from "@lingo.dev/_spec";
|
|
854
856
|
function getBuckets(i18nConfig) {
|
|
855
|
-
const result = Object.entries(i18nConfig.buckets).map(
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
config
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
857
|
+
const result = Object.entries(i18nConfig.buckets).map(
|
|
858
|
+
([bucketType, bucketEntry]) => {
|
|
859
|
+
const includeItems = bucketEntry.include.map(
|
|
860
|
+
(item) => resolveBucketItem(item)
|
|
861
|
+
);
|
|
862
|
+
const excludeItems = bucketEntry.exclude?.map(
|
|
863
|
+
(item) => resolveBucketItem(item)
|
|
864
|
+
);
|
|
865
|
+
const config = {
|
|
866
|
+
type: bucketType,
|
|
867
|
+
paths: extractPathPatterns(
|
|
868
|
+
i18nConfig.locale.source,
|
|
869
|
+
includeItems,
|
|
870
|
+
excludeItems
|
|
871
|
+
)
|
|
872
|
+
};
|
|
873
|
+
if (bucketEntry.injectLocale) {
|
|
874
|
+
config.injectLocale = bucketEntry.injectLocale;
|
|
875
|
+
}
|
|
876
|
+
if (bucketEntry.lockedKeys) {
|
|
877
|
+
config.lockedKeys = bucketEntry.lockedKeys;
|
|
878
|
+
}
|
|
879
|
+
if (bucketEntry.lockedPatterns) {
|
|
880
|
+
config.lockedPatterns = bucketEntry.lockedPatterns;
|
|
881
|
+
}
|
|
882
|
+
if (bucketEntry.ignoredKeys) {
|
|
883
|
+
config.ignoredKeys = bucketEntry.ignoredKeys;
|
|
884
|
+
}
|
|
885
|
+
return config;
|
|
870
886
|
}
|
|
871
|
-
|
|
872
|
-
});
|
|
887
|
+
);
|
|
873
888
|
return result;
|
|
874
889
|
}
|
|
875
890
|
function extractPathPatterns(sourceLocale, include, exclude) {
|
|
876
891
|
const includedPatterns = include.flatMap(
|
|
877
|
-
(pattern) => expandPlaceholderedGlob(
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
892
|
+
(pattern) => expandPlaceholderedGlob(
|
|
893
|
+
pattern.path,
|
|
894
|
+
resolveOverriddenLocale(sourceLocale, pattern.delimiter)
|
|
895
|
+
).map((pathPattern) => ({
|
|
896
|
+
pathPattern,
|
|
897
|
+
delimiter: pattern.delimiter
|
|
898
|
+
}))
|
|
883
899
|
);
|
|
884
900
|
const excludedPatterns = exclude?.flatMap(
|
|
885
|
-
(pattern) => expandPlaceholderedGlob(
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
901
|
+
(pattern) => expandPlaceholderedGlob(
|
|
902
|
+
pattern.path,
|
|
903
|
+
resolveOverriddenLocale(sourceLocale, pattern.delimiter)
|
|
904
|
+
).map((pathPattern) => ({
|
|
905
|
+
pathPattern,
|
|
906
|
+
delimiter: pattern.delimiter
|
|
907
|
+
}))
|
|
908
|
+
);
|
|
909
|
+
const result = _5.differenceBy(
|
|
910
|
+
includedPatterns,
|
|
911
|
+
excludedPatterns ?? [],
|
|
912
|
+
(item) => item.pathPattern
|
|
891
913
|
);
|
|
892
|
-
const result = _5.differenceBy(includedPatterns, excludedPatterns ?? [], (item) => item.pathPattern);
|
|
893
914
|
return result;
|
|
894
915
|
}
|
|
895
916
|
function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
|
|
@@ -908,12 +929,15 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
|
|
|
908
929
|
});
|
|
909
930
|
}
|
|
910
931
|
const pathPatternChunks = pathPattern.split(path9.sep);
|
|
911
|
-
const localeSegmentIndexes = pathPatternChunks.reduce(
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
932
|
+
const localeSegmentIndexes = pathPatternChunks.reduce(
|
|
933
|
+
(indexes, segment, index) => {
|
|
934
|
+
if (segment.includes("[locale]")) {
|
|
935
|
+
indexes.push(index);
|
|
936
|
+
}
|
|
937
|
+
return indexes;
|
|
938
|
+
},
|
|
939
|
+
[]
|
|
940
|
+
);
|
|
917
941
|
const sourcePathPattern = pathPattern.replaceAll(/\[locale\]/g, sourceLocale);
|
|
918
942
|
const sourcePaths = glob2.sync(sourcePathPattern, { follow: true, withFileTypes: true }).filter((file) => file.isFile() || file.isSymbolicLink()).map((file) => file.fullpath()).map((fullpath) => path9.relative(process.cwd(), fullpath));
|
|
919
943
|
const placeholderedPaths = sourcePaths.map((sourcePath) => {
|
|
@@ -1001,7 +1025,7 @@ import {
|
|
|
1001
1025
|
} from "@lingo.dev/_spec";
|
|
1002
1026
|
import { Command as Command6 } from "interactive-commander";
|
|
1003
1027
|
import Z3 from "zod";
|
|
1004
|
-
import
|
|
1028
|
+
import _25 from "lodash";
|
|
1005
1029
|
import * as path14 from "path";
|
|
1006
1030
|
import Ora5 from "ora";
|
|
1007
1031
|
|
|
@@ -1226,7 +1250,7 @@ function createTextFileLoader(pathPattern) {
|
|
|
1226
1250
|
const trimmedResult = result.trim();
|
|
1227
1251
|
return trimmedResult;
|
|
1228
1252
|
},
|
|
1229
|
-
async push(locale, data,
|
|
1253
|
+
async push(locale, data, _29, originalLocale) {
|
|
1230
1254
|
const draftPath = pathPattern.replaceAll("[locale]", locale);
|
|
1231
1255
|
const finalPath = path10.resolve(draftPath);
|
|
1232
1256
|
const dirPath = path10.dirname(finalPath);
|
|
@@ -1540,6 +1564,9 @@ function createCsvLoader() {
|
|
|
1540
1564
|
skip_empty_lines: true
|
|
1541
1565
|
});
|
|
1542
1566
|
const columns = input2.length > 0 ? Object.keys(input2[0]) : ["id", locale];
|
|
1567
|
+
if (!columns.includes(locale)) {
|
|
1568
|
+
columns.push(locale);
|
|
1569
|
+
}
|
|
1543
1570
|
const updatedRows = input2.map((row) => ({
|
|
1544
1571
|
...row,
|
|
1545
1572
|
[locale]: data[row.id] || row[locale] || ""
|
|
@@ -1752,7 +1779,7 @@ function createPropertiesLoader() {
|
|
|
1752
1779
|
return result;
|
|
1753
1780
|
},
|
|
1754
1781
|
async push(locale, payload) {
|
|
1755
|
-
const result = Object.entries(payload).filter(([
|
|
1782
|
+
const result = Object.entries(payload).filter(([_29, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
1756
1783
|
return result;
|
|
1757
1784
|
}
|
|
1758
1785
|
});
|
|
@@ -2019,10 +2046,10 @@ function createUnlocalizableLoader(isCacheRestore = false, returnUnlocalizedKeys
|
|
|
2019
2046
|
}
|
|
2020
2047
|
}
|
|
2021
2048
|
return false;
|
|
2022
|
-
}).map(([key,
|
|
2023
|
-
const result = _10.omitBy(input2, (
|
|
2049
|
+
}).map(([key, _29]) => key);
|
|
2050
|
+
const result = _10.omitBy(input2, (_29, key) => passthroughKeys.includes(key));
|
|
2024
2051
|
if (returnUnlocalizedKeys) {
|
|
2025
|
-
result.unlocalizable = _10.omitBy(input2, (
|
|
2052
|
+
result.unlocalizable = _10.omitBy(input2, (_29, key) => !passthroughKeys.includes(key));
|
|
2026
2053
|
}
|
|
2027
2054
|
return result;
|
|
2028
2055
|
},
|
|
@@ -3653,8 +3680,23 @@ function createMdxLockedPatternsLoader(defaultPatterns) {
|
|
|
3653
3680
|
});
|
|
3654
3681
|
}
|
|
3655
3682
|
|
|
3683
|
+
// src/cli/loaders/ignored-keys.ts
|
|
3684
|
+
import _23 from "lodash";
|
|
3685
|
+
function createIgnoredKeysLoader(ignoredKeys) {
|
|
3686
|
+
return createLoader({
|
|
3687
|
+
pull: async (locale, data) => {
|
|
3688
|
+
const result = _23.chain(data).omit(ignoredKeys).value();
|
|
3689
|
+
return result;
|
|
3690
|
+
},
|
|
3691
|
+
push: async (locale, data, originalInput, originalLocale, pullInput) => {
|
|
3692
|
+
const result = _23.merge({}, data, _23.pick(pullInput, ignoredKeys));
|
|
3693
|
+
return result;
|
|
3694
|
+
}
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3656
3698
|
// src/cli/loaders/index.ts
|
|
3657
|
-
function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys, lockedPatterns) {
|
|
3699
|
+
function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys, lockedPatterns, ignoredKeys) {
|
|
3658
3700
|
switch (bucketType) {
|
|
3659
3701
|
default:
|
|
3660
3702
|
throw new Error(`Unsupported bucket type: ${bucketType}`);
|
|
@@ -3913,6 +3955,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
3913
3955
|
createTypescriptLoader(),
|
|
3914
3956
|
createFlatLoader(),
|
|
3915
3957
|
createSyncLoader(),
|
|
3958
|
+
createLockedKeysLoader(lockedKeys || [], options.isCacheRestore),
|
|
3959
|
+
createIgnoredKeysLoader(ignoredKeys || []),
|
|
3916
3960
|
createUnlocalizableLoader(
|
|
3917
3961
|
options.isCacheRestore,
|
|
3918
3962
|
options.returnUnlocalizedKeys
|
|
@@ -3922,11 +3966,15 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
3922
3966
|
}
|
|
3923
3967
|
|
|
3924
3968
|
// src/cli/cmd/i18n.ts
|
|
3925
|
-
import
|
|
3969
|
+
import chalk2 from "chalk";
|
|
3926
3970
|
import { createTwoFilesPatch } from "diff";
|
|
3927
3971
|
import inquirer2 from "inquirer";
|
|
3928
3972
|
import externalEditor from "external-editor";
|
|
3929
3973
|
|
|
3974
|
+
// src/cli/processor/index.ts
|
|
3975
|
+
import chalk from "chalk";
|
|
3976
|
+
import dedent from "dedent";
|
|
3977
|
+
|
|
3930
3978
|
// src/cli/processor/lingo.ts
|
|
3931
3979
|
import { LingoDotDevEngine } from "@lingo.dev/_sdk";
|
|
3932
3980
|
function createLingoLocalizer(params) {
|
|
@@ -3961,9 +4009,6 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
3961
4009
|
if (!Object.keys(input2.processableData).length) {
|
|
3962
4010
|
return input2.processableData;
|
|
3963
4011
|
}
|
|
3964
|
-
if (!process.env.OPENAI_API_KEY) {
|
|
3965
|
-
throw new Error("OPENAI_API_KEY is not set");
|
|
3966
|
-
}
|
|
3967
4012
|
const response = await generateText({
|
|
3968
4013
|
model,
|
|
3969
4014
|
messages: [
|
|
@@ -4011,9 +4056,21 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
4011
4056
|
|
|
4012
4057
|
// src/cli/processor/index.ts
|
|
4013
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
|
|
4014
4071
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
4015
4072
|
function createProcessor(provider, params) {
|
|
4016
|
-
if (!provider
|
|
4073
|
+
if (!provider) {
|
|
4017
4074
|
const result = createLingoLocalizer(params);
|
|
4018
4075
|
return result;
|
|
4019
4076
|
} else {
|
|
@@ -4023,10 +4080,30 @@ function createProcessor(provider, params) {
|
|
|
4023
4080
|
}
|
|
4024
4081
|
}
|
|
4025
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
|
+
`;
|
|
4026
4101
|
switch (provider?.id) {
|
|
4027
4102
|
case "openai":
|
|
4028
4103
|
if (!process.env.OPENAI_API_KEY) {
|
|
4029
|
-
throw new Error(
|
|
4104
|
+
throw new Error(
|
|
4105
|
+
createMissingKeyErrorMessage("OpenAI", "OPENAI_API_KEY")
|
|
4106
|
+
);
|
|
4030
4107
|
}
|
|
4031
4108
|
return createOpenAI({
|
|
4032
4109
|
apiKey: process.env.OPENAI_API_KEY,
|
|
@@ -4034,13 +4111,15 @@ function getPureModelProvider(provider) {
|
|
|
4034
4111
|
})(provider.model);
|
|
4035
4112
|
case "anthropic":
|
|
4036
4113
|
if (!process.env.ANTHROPIC_API_KEY) {
|
|
4037
|
-
throw new Error(
|
|
4114
|
+
throw new Error(
|
|
4115
|
+
createMissingKeyErrorMessage("Anthropic", "ANTHROPIC_API_KEY")
|
|
4116
|
+
);
|
|
4038
4117
|
}
|
|
4039
4118
|
return createAnthropic({
|
|
4040
4119
|
apiKey: process.env.ANTHROPIC_API_KEY
|
|
4041
4120
|
})(provider.model);
|
|
4042
4121
|
default:
|
|
4043
|
-
throw new Error(
|
|
4122
|
+
throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
|
|
4044
4123
|
}
|
|
4045
4124
|
}
|
|
4046
4125
|
|
|
@@ -4098,7 +4177,7 @@ async function trackEvent(distinctId, event, properties) {
|
|
|
4098
4177
|
}
|
|
4099
4178
|
|
|
4100
4179
|
// src/cli/utils/delta.ts
|
|
4101
|
-
import
|
|
4180
|
+
import _24 from "lodash";
|
|
4102
4181
|
import z from "zod";
|
|
4103
4182
|
|
|
4104
4183
|
// src/cli/utils/fs.ts
|
|
@@ -4147,9 +4226,9 @@ function createDeltaProcessor(fileKey) {
|
|
|
4147
4226
|
return checkIfFileExists(lockfilePath);
|
|
4148
4227
|
},
|
|
4149
4228
|
async calculateDelta(params) {
|
|
4150
|
-
let added =
|
|
4151
|
-
let removed =
|
|
4152
|
-
const updated =
|
|
4229
|
+
let added = _24.difference(Object.keys(params.sourceData), Object.keys(params.targetData));
|
|
4230
|
+
let removed = _24.difference(Object.keys(params.targetData), Object.keys(params.sourceData));
|
|
4231
|
+
const updated = _24.filter(Object.keys(params.sourceData), (key) => {
|
|
4153
4232
|
return md5(params.sourceData[key]) !== params.checksums[key] && params.checksums[key];
|
|
4154
4233
|
});
|
|
4155
4234
|
const renamed = [];
|
|
@@ -4198,7 +4277,7 @@ function createDeltaProcessor(fileKey) {
|
|
|
4198
4277
|
await this.saveLock(lockfileData);
|
|
4199
4278
|
},
|
|
4200
4279
|
async createChecksums(sourceData) {
|
|
4201
|
-
const checksums =
|
|
4280
|
+
const checksums = _24.mapValues(sourceData, (value) => md5(value));
|
|
4202
4281
|
return checksums;
|
|
4203
4282
|
}
|
|
4204
4283
|
};
|
|
@@ -4265,7 +4344,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4265
4344
|
validateParams(i18nConfig, flags);
|
|
4266
4345
|
ora.succeed("Localization configuration is valid");
|
|
4267
4346
|
ora.start("Connecting to Lingo.dev Localization Engine...");
|
|
4268
|
-
const isByokMode = i18nConfig?.provider
|
|
4347
|
+
const isByokMode = !!i18nConfig?.provider;
|
|
4269
4348
|
if (isByokMode) {
|
|
4270
4349
|
authId = null;
|
|
4271
4350
|
ora.succeed("Using external provider (BYOK mode)");
|
|
@@ -4328,7 +4407,8 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4328
4407
|
injectLocale: bucket.injectLocale
|
|
4329
4408
|
},
|
|
4330
4409
|
bucket.lockedKeys,
|
|
4331
|
-
bucket.lockedPatterns
|
|
4410
|
+
bucket.lockedPatterns,
|
|
4411
|
+
bucket.ignoredKeys
|
|
4332
4412
|
);
|
|
4333
4413
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
4334
4414
|
await bucketLoader.init();
|
|
@@ -4437,7 +4517,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4437
4517
|
const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
|
|
4438
4518
|
const sourceChecksums = await deltaProcessor.createChecksums(sourceData);
|
|
4439
4519
|
const savedChecksums = await deltaProcessor.loadChecksums();
|
|
4440
|
-
const updatedSourceData =
|
|
4520
|
+
const updatedSourceData = _25.pickBy(
|
|
4441
4521
|
sourceData,
|
|
4442
4522
|
(value, key) => sourceChecksums[key] !== savedChecksums[key]
|
|
4443
4523
|
);
|
|
@@ -4451,15 +4531,15 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4451
4531
|
bucketPath.delimiter
|
|
4452
4532
|
);
|
|
4453
4533
|
const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
|
|
4454
|
-
const missingKeys =
|
|
4534
|
+
const missingKeys = _25.difference(
|
|
4455
4535
|
Object.keys(sourceData),
|
|
4456
4536
|
Object.keys(targetData)
|
|
4457
4537
|
);
|
|
4458
|
-
const extraKeys =
|
|
4538
|
+
const extraKeys = _25.difference(
|
|
4459
4539
|
Object.keys(targetData),
|
|
4460
4540
|
Object.keys(sourceData)
|
|
4461
4541
|
);
|
|
4462
|
-
const unlocalizableDataDiff = !
|
|
4542
|
+
const unlocalizableDataDiff = !_25.isEqual(
|
|
4463
4543
|
sourceUnlocalizable,
|
|
4464
4544
|
targetUnlocalizable
|
|
4465
4545
|
);
|
|
@@ -4515,7 +4595,8 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4515
4595
|
injectLocale: bucket.injectLocale
|
|
4516
4596
|
},
|
|
4517
4597
|
bucket.lockedKeys,
|
|
4518
|
-
bucket.lockedPatterns
|
|
4598
|
+
bucket.lockedPatterns,
|
|
4599
|
+
bucket.ignoredKeys
|
|
4519
4600
|
);
|
|
4520
4601
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
4521
4602
|
await bucketLoader.init();
|
|
@@ -4540,13 +4621,13 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4540
4621
|
targetData,
|
|
4541
4622
|
checksums: checksums2
|
|
4542
4623
|
});
|
|
4543
|
-
let processableData =
|
|
4624
|
+
let processableData = _25.chain(sourceData).entries().filter(
|
|
4544
4625
|
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!flags.force
|
|
4545
4626
|
).fromPairs().value();
|
|
4546
4627
|
if (flags.key) {
|
|
4547
|
-
processableData =
|
|
4628
|
+
processableData = _25.pickBy(
|
|
4548
4629
|
processableData,
|
|
4549
|
-
(
|
|
4630
|
+
(_29, key) => key === flags.key
|
|
4550
4631
|
);
|
|
4551
4632
|
}
|
|
4552
4633
|
if (flags.verbose) {
|
|
@@ -4573,21 +4654,13 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4573
4654
|
targetData
|
|
4574
4655
|
},
|
|
4575
4656
|
(progress, sourceChunk, processedChunk) => {
|
|
4576
|
-
|
|
4577
|
-
if (flags.verbose) {
|
|
4578
|
-
bucketOra.info(progressLog);
|
|
4579
|
-
bucketOra.info(
|
|
4580
|
-
`(${progress}%) Caching chunk ${JSON.stringify(sourceChunk, null, 2)} -> ${JSON.stringify(processedChunk, null, 2)}`
|
|
4581
|
-
);
|
|
4582
|
-
} else {
|
|
4583
|
-
bucketOra.text = progressLog;
|
|
4584
|
-
}
|
|
4657
|
+
bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length} entries] (${progress}%) AI localization in progress...`;
|
|
4585
4658
|
}
|
|
4586
4659
|
);
|
|
4587
4660
|
if (flags.verbose) {
|
|
4588
4661
|
bucketOra.info(JSON.stringify(processedTargetData, null, 2));
|
|
4589
4662
|
}
|
|
4590
|
-
let finalTargetData =
|
|
4663
|
+
let finalTargetData = _25.merge(
|
|
4591
4664
|
{},
|
|
4592
4665
|
sourceData,
|
|
4593
4666
|
targetData,
|
|
@@ -4608,7 +4681,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
4608
4681
|
`Applying changes to ${bucketPath} (${targetLocale})`
|
|
4609
4682
|
);
|
|
4610
4683
|
}
|
|
4611
|
-
const finalDiffSize =
|
|
4684
|
+
const finalDiffSize = _25.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
|
|
4612
4685
|
await bucketLoader.push(targetLocale, finalTargetData);
|
|
4613
4686
|
if (finalDiffSize > 0 || flags.force) {
|
|
4614
4687
|
bucketOra.succeed(
|
|
@@ -4735,7 +4808,7 @@ async function reviewChanges(args) {
|
|
|
4735
4808
|
if (currentStr === proposedStr && !args.force) {
|
|
4736
4809
|
console.log(
|
|
4737
4810
|
`
|
|
4738
|
-
${
|
|
4811
|
+
${chalk2.blue(args.pathPattern)} (${chalk2.yellow(args.targetLocale)}): ${chalk2.gray("No changes to review")}`
|
|
4739
4812
|
);
|
|
4740
4813
|
return args.proposedData;
|
|
4741
4814
|
}
|
|
@@ -4749,14 +4822,14 @@ ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targetLocale)}): ${chalk.gr
|
|
|
4749
4822
|
{ context: 3 }
|
|
4750
4823
|
);
|
|
4751
4824
|
const coloredDiff = patch.split("\n").map((line) => {
|
|
4752
|
-
if (line.startsWith("+")) return
|
|
4753
|
-
if (line.startsWith("-")) return
|
|
4754
|
-
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);
|
|
4755
4828
|
return line;
|
|
4756
4829
|
}).join("\n");
|
|
4757
4830
|
console.log(
|
|
4758
4831
|
`
|
|
4759
|
-
Reviewing changes for ${
|
|
4832
|
+
Reviewing changes for ${chalk2.blue(args.pathPattern)} (${chalk2.yellow(args.targetLocale)}):`
|
|
4760
4833
|
);
|
|
4761
4834
|
console.log(coloredDiff);
|
|
4762
4835
|
const { action } = await inquirer2.prompt([
|
|
@@ -4779,7 +4852,7 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
|
|
|
4779
4852
|
return args.currentData;
|
|
4780
4853
|
}
|
|
4781
4854
|
const customData = { ...args.currentData };
|
|
4782
|
-
const changes =
|
|
4855
|
+
const changes = _25.reduce(
|
|
4783
4856
|
args.proposedData,
|
|
4784
4857
|
(result, value, key) => {
|
|
4785
4858
|
if (args.currentData[key] !== value) {
|
|
@@ -4791,32 +4864,32 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
|
|
|
4791
4864
|
);
|
|
4792
4865
|
for (const key of changes) {
|
|
4793
4866
|
console.log(`
|
|
4794
|
-
Editing value for: ${
|
|
4795
|
-
console.log(
|
|
4867
|
+
Editing value for: ${chalk2.cyan(key)}`);
|
|
4868
|
+
console.log(chalk2.gray("Source text:"), chalk2.blue(args.sourceData[key]));
|
|
4796
4869
|
console.log(
|
|
4797
|
-
|
|
4798
|
-
|
|
4870
|
+
chalk2.gray("Current value:"),
|
|
4871
|
+
chalk2.red(args.currentData[key] || "(empty)")
|
|
4799
4872
|
);
|
|
4800
4873
|
console.log(
|
|
4801
|
-
|
|
4802
|
-
|
|
4874
|
+
chalk2.gray("Suggested value:"),
|
|
4875
|
+
chalk2.green(args.proposedData[key])
|
|
4803
4876
|
);
|
|
4804
4877
|
console.log(
|
|
4805
|
-
|
|
4878
|
+
chalk2.gray(
|
|
4806
4879
|
"\nYour editor will open. Edit the text and save to continue."
|
|
4807
4880
|
)
|
|
4808
4881
|
);
|
|
4809
|
-
console.log(
|
|
4882
|
+
console.log(chalk2.gray("------------"));
|
|
4810
4883
|
try {
|
|
4811
4884
|
const editorContent = [
|
|
4812
4885
|
"# Edit the translation below.",
|
|
4813
4886
|
"# Lines starting with # will be ignored.",
|
|
4814
4887
|
"# Save and exit the editor to continue.",
|
|
4815
4888
|
"#",
|
|
4816
|
-
`# Source text (${
|
|
4889
|
+
`# Source text (${chalk2.blue("English")}):`,
|
|
4817
4890
|
`# ${args.sourceData[key]}`,
|
|
4818
4891
|
"#",
|
|
4819
|
-
`# Current value (${
|
|
4892
|
+
`# Current value (${chalk2.red(args.targetLocale)}):`,
|
|
4820
4893
|
`# ${args.currentData[key] || "(empty)"}`,
|
|
4821
4894
|
"#",
|
|
4822
4895
|
args.proposedData[key]
|
|
@@ -4827,13 +4900,13 @@ Editing value for: ${chalk.cyan(key)}`);
|
|
|
4827
4900
|
customData[key] = customValue;
|
|
4828
4901
|
} else {
|
|
4829
4902
|
console.log(
|
|
4830
|
-
|
|
4903
|
+
chalk2.yellow("Empty value provided, keeping the current value.")
|
|
4831
4904
|
);
|
|
4832
4905
|
customData[key] = args.currentData[key] || args.proposedData[key];
|
|
4833
4906
|
}
|
|
4834
4907
|
} catch (error) {
|
|
4835
4908
|
console.log(
|
|
4836
|
-
|
|
4909
|
+
chalk2.red("Error while editing, keeping the suggested value.")
|
|
4837
4910
|
);
|
|
4838
4911
|
customData[key] = args.proposedData[key];
|
|
4839
4912
|
}
|
|
@@ -4852,7 +4925,7 @@ import path15 from "path";
|
|
|
4852
4925
|
import Z4 from "zod";
|
|
4853
4926
|
import YAML5 from "yaml";
|
|
4854
4927
|
import { MD5 as MD52 } from "object-hash";
|
|
4855
|
-
import
|
|
4928
|
+
import _26 from "lodash";
|
|
4856
4929
|
function createLockfileHelper() {
|
|
4857
4930
|
return {
|
|
4858
4931
|
isLockfileExists: () => {
|
|
@@ -4862,23 +4935,23 @@ function createLockfileHelper() {
|
|
|
4862
4935
|
registerSourceData: (pathPattern, sourceData) => {
|
|
4863
4936
|
const lockfile = _loadLockfile();
|
|
4864
4937
|
const sectionKey = MD52(pathPattern);
|
|
4865
|
-
const sectionChecksums =
|
|
4938
|
+
const sectionChecksums = _26.mapValues(sourceData, (value) => MD52(value));
|
|
4866
4939
|
lockfile.checksums[sectionKey] = sectionChecksums;
|
|
4867
4940
|
_saveLockfile(lockfile);
|
|
4868
4941
|
},
|
|
4869
4942
|
registerPartialSourceData: (pathPattern, partialSourceData) => {
|
|
4870
4943
|
const lockfile = _loadLockfile();
|
|
4871
4944
|
const sectionKey = MD52(pathPattern);
|
|
4872
|
-
const sectionChecksums =
|
|
4873
|
-
lockfile.checksums[sectionKey] =
|
|
4945
|
+
const sectionChecksums = _26.mapValues(partialSourceData, (value) => MD52(value));
|
|
4946
|
+
lockfile.checksums[sectionKey] = _26.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
|
|
4874
4947
|
_saveLockfile(lockfile);
|
|
4875
4948
|
},
|
|
4876
4949
|
extractUpdatedData: (pathPattern, sourceData) => {
|
|
4877
4950
|
const lockfile = _loadLockfile();
|
|
4878
4951
|
const sectionKey = MD52(pathPattern);
|
|
4879
|
-
const currentChecksums =
|
|
4952
|
+
const currentChecksums = _26.mapValues(sourceData, (value) => MD52(value));
|
|
4880
4953
|
const savedChecksums = lockfile.checksums[sectionKey] || {};
|
|
4881
|
-
const updatedData =
|
|
4954
|
+
const updatedData = _26.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
|
|
4882
4955
|
return updatedData;
|
|
4883
4956
|
}
|
|
4884
4957
|
};
|
|
@@ -4948,7 +5021,7 @@ var flagsSchema = Z5.object({
|
|
|
4948
5021
|
// src/cli/cmd/cleanup.ts
|
|
4949
5022
|
import { resolveOverriddenLocale as resolveOverriddenLocale5 } from "@lingo.dev/_spec";
|
|
4950
5023
|
import { Command as Command8 } from "interactive-commander";
|
|
4951
|
-
import
|
|
5024
|
+
import _27 from "lodash";
|
|
4952
5025
|
import Ora7 from "ora";
|
|
4953
5026
|
var cleanup_default = new Command8().command("cleanup").description("Remove keys from target files that do not exist in the source file").helpOption("-h, --help", "Show help").option("--locale <locale>", "Specific locale to cleanup").option("--bucket <bucket>", "Specific bucket to cleanup").option("--dry-run", "Show what would be removed without making changes").option(
|
|
4954
5027
|
"--verbose",
|
|
@@ -4984,7 +5057,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
|
|
|
4984
5057
|
try {
|
|
4985
5058
|
const targetData = await bucketLoader.pull(targetLocale);
|
|
4986
5059
|
const targetKeys = Object.keys(targetData);
|
|
4987
|
-
const keysToRemove =
|
|
5060
|
+
const keysToRemove = _27.difference(targetKeys, sourceKeys);
|
|
4988
5061
|
if (keysToRemove.length === 0) {
|
|
4989
5062
|
bucketOra.succeed(`[${targetLocale}] No keys to remove`);
|
|
4990
5063
|
continue;
|
|
@@ -4993,7 +5066,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
|
|
|
4993
5066
|
bucketOra.info(`[${targetLocale}] Keys to remove: ${JSON.stringify(keysToRemove, null, 2)}`);
|
|
4994
5067
|
}
|
|
4995
5068
|
if (!options.dryRun) {
|
|
4996
|
-
const cleanedData =
|
|
5069
|
+
const cleanedData = _27.pick(targetData, sourceKeys);
|
|
4997
5070
|
await bucketLoader.push(targetLocale, cleanedData);
|
|
4998
5071
|
bucketOra.succeed(`[${targetLocale}] Removed ${keysToRemove.length} keys`);
|
|
4999
5072
|
} else {
|
|
@@ -5048,7 +5121,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5048
5121
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5049
5122
|
import Z6 from "zod";
|
|
5050
5123
|
import { ReplexicaEngine } from "@lingo.dev/_sdk";
|
|
5051
|
-
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) => {
|
|
5052
5125
|
const apiKey = program.args[0];
|
|
5053
5126
|
const settings = getSettings(apiKey);
|
|
5054
5127
|
if (!settings.auth.apiKey) {
|
|
@@ -5815,7 +5888,7 @@ import { bucketTypeSchema as bucketTypeSchema3, localeCodeSchema as localeCodeSc
|
|
|
5815
5888
|
import { Command as Command11 } from "interactive-commander";
|
|
5816
5889
|
import Z11 from "zod";
|
|
5817
5890
|
import Ora8 from "ora";
|
|
5818
|
-
import
|
|
5891
|
+
import chalk3 from "chalk";
|
|
5819
5892
|
import Table from "cli-table3";
|
|
5820
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(
|
|
5821
5894
|
"--file [files...]",
|
|
@@ -5958,7 +6031,7 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
5958
6031
|
languageStats[targetLocale].words += sourceWordCount;
|
|
5959
6032
|
totalWordCount.set(targetLocale, (totalWordCount.get(targetLocale) || 0) + sourceWordCount);
|
|
5960
6033
|
bucketOra.succeed(
|
|
5961
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
6034
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk3.red(`0% complete`)} (0/${sourceKeys.length} keys) - file not found`
|
|
5962
6035
|
);
|
|
5963
6036
|
continue;
|
|
5964
6037
|
}
|
|
@@ -5994,20 +6067,20 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
5994
6067
|
const completionPercent = (completeKeys.length / totalKeysInFile * 100).toFixed(1);
|
|
5995
6068
|
if (missingKeys.length === 0 && updatedKeys.length === 0) {
|
|
5996
6069
|
bucketOra.succeed(
|
|
5997
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
6070
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk3.green(`100% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`
|
|
5998
6071
|
);
|
|
5999
6072
|
} else {
|
|
6000
|
-
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)`;
|
|
6001
6074
|
bucketOra.succeed(message);
|
|
6002
6075
|
if (flags.verbose) {
|
|
6003
6076
|
if (missingKeys.length > 0) {
|
|
6004
|
-
console.log(` ${
|
|
6077
|
+
console.log(` ${chalk3.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`);
|
|
6005
6078
|
console.log(
|
|
6006
|
-
` ${
|
|
6079
|
+
` ${chalk3.dim(`Example missing: ${missingKeys.slice(0, 2).join(", ")}${missingKeys.length > 2 ? "..." : ""}`)}`
|
|
6007
6080
|
);
|
|
6008
6081
|
}
|
|
6009
6082
|
if (updatedKeys.length > 0) {
|
|
6010
|
-
console.log(` ${
|
|
6083
|
+
console.log(` ${chalk3.yellow(`Updated:`)} ${updatedKeys.length} keys that changed in source`);
|
|
6011
6084
|
}
|
|
6012
6085
|
}
|
|
6013
6086
|
}
|
|
@@ -6022,16 +6095,16 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6022
6095
|
}, 0);
|
|
6023
6096
|
const totalCompletedKeys = totalSourceKeyCount - totalKeysNeedingTranslation / targetLocales.length;
|
|
6024
6097
|
console.log();
|
|
6025
|
-
ora.succeed(
|
|
6026
|
-
console.log(
|
|
6098
|
+
ora.succeed(chalk3.green(`Localization status completed.`));
|
|
6099
|
+
console.log(chalk3.bold.cyan(`
|
|
6027
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`));
|
|
6028
|
-
console.log(
|
|
6029
|
-
console.log(
|
|
6030
|
-
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(`
|
|
6031
6104
|
\u{1F4DD} SOURCE CONTENT:`));
|
|
6032
|
-
console.log(`\u2022 Source language: ${
|
|
6033
|
-
console.log(`\u2022 Source keys: ${
|
|
6034
|
-
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(`
|
|
6035
6108
|
\u{1F310} LANGUAGE BY LANGUAGE BREAKDOWN:`));
|
|
6036
6109
|
const table = new Table({
|
|
6037
6110
|
head: ["Language", "Status", "Complete", "Missing", "Updated", "Total Keys", "Words to Translate"],
|
|
@@ -6053,19 +6126,19 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6053
6126
|
let statusColor;
|
|
6054
6127
|
if (stats.missing === totalSourceKeyCount) {
|
|
6055
6128
|
statusText = "\u{1F534} Not started";
|
|
6056
|
-
statusColor =
|
|
6129
|
+
statusColor = chalk3.red;
|
|
6057
6130
|
} else if (stats.missing === 0 && stats.updated === 0) {
|
|
6058
6131
|
statusText = "\u2705 Complete";
|
|
6059
|
-
statusColor =
|
|
6132
|
+
statusColor = chalk3.green;
|
|
6060
6133
|
} else if (parseFloat(percentComplete) > 80) {
|
|
6061
6134
|
statusText = "\u{1F7E1} Almost done";
|
|
6062
|
-
statusColor =
|
|
6135
|
+
statusColor = chalk3.yellow;
|
|
6063
6136
|
} else if (parseFloat(percentComplete) > 0) {
|
|
6064
6137
|
statusText = "\u{1F7E0} In progress";
|
|
6065
|
-
statusColor =
|
|
6138
|
+
statusColor = chalk3.yellow;
|
|
6066
6139
|
} else {
|
|
6067
6140
|
statusText = "\u{1F534} Not started";
|
|
6068
|
-
statusColor =
|
|
6141
|
+
statusColor = chalk3.red;
|
|
6069
6142
|
}
|
|
6070
6143
|
const words = totalWordCount.get(locale) || 0;
|
|
6071
6144
|
totalWordsToTranslate += words;
|
|
@@ -6073,17 +6146,17 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6073
6146
|
locale,
|
|
6074
6147
|
statusColor(statusText),
|
|
6075
6148
|
`${stats.complete}/${totalSourceKeyCount} (${percentComplete}%)`,
|
|
6076
|
-
stats.missing > 0 ?
|
|
6077
|
-
stats.updated > 0 ?
|
|
6078
|
-
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",
|
|
6079
6152
|
words > 0 ? `~${words.toLocaleString()}` : "0"
|
|
6080
6153
|
]);
|
|
6081
6154
|
}
|
|
6082
6155
|
console.log(table.toString());
|
|
6083
|
-
console.log(
|
|
6156
|
+
console.log(chalk3.bold(`
|
|
6084
6157
|
\u{1F4CA} USAGE ESTIMATE:`));
|
|
6085
6158
|
console.log(
|
|
6086
|
-
`\u2022 WORDS TO BE CONSUMED: ~${
|
|
6159
|
+
`\u2022 WORDS TO BE CONSUMED: ~${chalk3.yellow.bold(totalWordsToTranslate.toLocaleString())} words across all languages`
|
|
6087
6160
|
);
|
|
6088
6161
|
console.log(` (Words are counted from source language for keys that need translation in target languages)`);
|
|
6089
6162
|
if (targetLocales.length > 1) {
|
|
@@ -6095,11 +6168,11 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6095
6168
|
}
|
|
6096
6169
|
}
|
|
6097
6170
|
if (flags.confirm && Object.keys(fileStats).length > 0) {
|
|
6098
|
-
console.log(
|
|
6171
|
+
console.log(chalk3.bold(`
|
|
6099
6172
|
\u{1F4D1} BREAKDOWN BY FILE:`));
|
|
6100
6173
|
Object.entries(fileStats).sort((a, b) => b[1].wordCount - a[1].wordCount).forEach(([path17, stats]) => {
|
|
6101
6174
|
if (stats.sourceKeys === 0) return;
|
|
6102
|
-
console.log(
|
|
6175
|
+
console.log(chalk3.bold(`
|
|
6103
6176
|
\u2022 ${path17}:`));
|
|
6104
6177
|
console.log(` ${stats.sourceKeys} source keys, ~${stats.wordCount.toLocaleString()} source words`);
|
|
6105
6178
|
const fileTable = new Table({
|
|
@@ -6117,13 +6190,13 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6117
6190
|
const total = stats.sourceKeys;
|
|
6118
6191
|
const completion = (complete / total * 100).toFixed(1);
|
|
6119
6192
|
let status = "\u2705 Complete";
|
|
6120
|
-
let statusColor =
|
|
6193
|
+
let statusColor = chalk3.green;
|
|
6121
6194
|
if (langStats.missing === total) {
|
|
6122
6195
|
status = "\u274C Not started";
|
|
6123
|
-
statusColor =
|
|
6196
|
+
statusColor = chalk3.red;
|
|
6124
6197
|
} else if (langStats.missing > 0 || langStats.updated > 0) {
|
|
6125
6198
|
status = `\u26A0\uFE0F ${completion}% complete`;
|
|
6126
|
-
statusColor =
|
|
6199
|
+
statusColor = chalk3.yellow;
|
|
6127
6200
|
}
|
|
6128
6201
|
let details = "";
|
|
6129
6202
|
if (langStats.missing > 0 || langStats.updated > 0) {
|
|
@@ -6143,16 +6216,16 @@ var status_default = new Command11().command("status").description("Show the sta
|
|
|
6143
6216
|
(locale) => languageStats[locale].missing === 0 && languageStats[locale].updated === 0
|
|
6144
6217
|
);
|
|
6145
6218
|
const missingLanguages = targetLocales.filter((locale) => languageStats[locale].complete === 0);
|
|
6146
|
-
console.log(
|
|
6219
|
+
console.log(chalk3.bold.green(`
|
|
6147
6220
|
\u{1F4A1} OPTIMIZATION TIPS:`));
|
|
6148
6221
|
if (missingLanguages.length > 0) {
|
|
6149
6222
|
console.log(
|
|
6150
|
-
`\u2022 ${
|
|
6223
|
+
`\u2022 ${chalk3.yellow(missingLanguages.join(", "))} ${missingLanguages.length === 1 ? "has" : "have"} no translations yet`
|
|
6151
6224
|
);
|
|
6152
6225
|
}
|
|
6153
6226
|
if (completeLanguages.length > 0) {
|
|
6154
6227
|
console.log(
|
|
6155
|
-
`\u2022 ${
|
|
6228
|
+
`\u2022 ${chalk3.green(completeLanguages.join(", "))} ${completeLanguages.length === 1 ? "is" : "are"} completely translated`
|
|
6156
6229
|
);
|
|
6157
6230
|
}
|
|
6158
6231
|
if (targetLocales.length > 1) {
|
|
@@ -6231,9 +6304,9 @@ function validateParams2(i18nConfig, flags) {
|
|
|
6231
6304
|
import { Command as Command12 } from "interactive-commander";
|
|
6232
6305
|
import * as cp from "node:child_process";
|
|
6233
6306
|
import figlet from "figlet";
|
|
6234
|
-
import
|
|
6307
|
+
import chalk4 from "chalk";
|
|
6235
6308
|
import { vice } from "gradient-string";
|
|
6236
|
-
var
|
|
6309
|
+
var colors2 = {
|
|
6237
6310
|
orange: "#ff6600",
|
|
6238
6311
|
green: "#6ae300",
|
|
6239
6312
|
blue: "#0090ff",
|
|
@@ -6245,7 +6318,7 @@ var may_the_fourth_default = new Command12().command("may-the-fourth").descripti
|
|
|
6245
6318
|
await renderClear();
|
|
6246
6319
|
await renderBanner();
|
|
6247
6320
|
await renderSpacer();
|
|
6248
|
-
console.log(
|
|
6321
|
+
console.log(chalk4.hex(colors2.yellow)("Loading the Star Wars movie..."));
|
|
6249
6322
|
await renderSpacer();
|
|
6250
6323
|
await new Promise((resolve, reject) => {
|
|
6251
6324
|
const ssh = cp.spawn("ssh", ["starwarstel.net"], {
|
|
@@ -6264,10 +6337,10 @@ var may_the_fourth_default = new Command12().command("may-the-fourth").descripti
|
|
|
6264
6337
|
});
|
|
6265
6338
|
await renderSpacer();
|
|
6266
6339
|
console.log(
|
|
6267
|
-
`${
|
|
6340
|
+
`${chalk4.hex(colors2.green)("We hope you enjoyed it! :)")} ${chalk4.hex(colors2.blue)("May the Fourth be with you! \u{1F680}")}`
|
|
6268
6341
|
);
|
|
6269
6342
|
await renderSpacer();
|
|
6270
|
-
console.log(
|
|
6343
|
+
console.log(chalk4.dim(`---`));
|
|
6271
6344
|
await renderSpacer();
|
|
6272
6345
|
await renderHero();
|
|
6273
6346
|
});
|
|
@@ -6290,19 +6363,19 @@ async function renderBanner() {
|
|
|
6290
6363
|
}
|
|
6291
6364
|
async function renderHero() {
|
|
6292
6365
|
console.log(
|
|
6293
|
-
`\u26A1\uFE0F ${
|
|
6366
|
+
`\u26A1\uFE0F ${chalk4.hex(colors2.green)("Lingo.dev")} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
6294
6367
|
);
|
|
6295
6368
|
console.log(" ");
|
|
6296
6369
|
console.log(
|
|
6297
|
-
|
|
6370
|
+
chalk4.hex(colors2.blue)("\u2B50 GitHub Repo: https://lingo.dev/go/gh")
|
|
6298
6371
|
);
|
|
6299
|
-
console.log(
|
|
6372
|
+
console.log(chalk4.hex(colors2.blue)("\u{1F4AC} 24/7 Support: hi@lingo.dev"));
|
|
6300
6373
|
}
|
|
6301
6374
|
|
|
6302
6375
|
// package.json
|
|
6303
6376
|
var package_default = {
|
|
6304
6377
|
name: "lingo.dev",
|
|
6305
|
-
version: "0.92.
|
|
6378
|
+
version: "0.92.9",
|
|
6306
6379
|
description: "Lingo.dev CLI",
|
|
6307
6380
|
private: false,
|
|
6308
6381
|
publishConfig: {
|
|
@@ -6359,22 +6432,24 @@ var package_default = {
|
|
|
6359
6432
|
author: "",
|
|
6360
6433
|
license: "Apache-2.0",
|
|
6361
6434
|
dependencies: {
|
|
6362
|
-
"@ai-sdk/anthropic": "^1.2.
|
|
6363
|
-
"@ai-sdk/openai": "^1.3.
|
|
6435
|
+
"@ai-sdk/anthropic": "^1.2.11",
|
|
6436
|
+
"@ai-sdk/openai": "^1.3.22",
|
|
6364
6437
|
"@babel/generator": "^7.27.1",
|
|
6365
6438
|
"@babel/parser": "^7.27.1",
|
|
6366
6439
|
"@babel/traverse": "^7.27.1",
|
|
6367
6440
|
"@babel/types": "^7.27.1",
|
|
6368
6441
|
"@datocms/cma-client-node": "^4.0.1",
|
|
6369
6442
|
"@gitbeaker/rest": "^39.34.3",
|
|
6443
|
+
"@inkjs/ui": "^2.0.0",
|
|
6370
6444
|
"@inquirer/prompts": "^7.4.1",
|
|
6371
6445
|
"@lingo.dev/_sdk": "workspace:*",
|
|
6372
6446
|
"@lingo.dev/_spec": "workspace:*",
|
|
6373
6447
|
"@modelcontextprotocol/sdk": "^1.5.0",
|
|
6374
6448
|
"@paralleldrive/cuid2": "^2.2.2",
|
|
6375
|
-
ai: "^4.3.
|
|
6449
|
+
ai: "^4.3.15",
|
|
6376
6450
|
bitbucket: "^2.12.0",
|
|
6377
6451
|
chalk: "^5.4.1",
|
|
6452
|
+
"cli-progress": "^3.12.0",
|
|
6378
6453
|
"cli-table3": "^0.6.5",
|
|
6379
6454
|
cors: "^2.8.5",
|
|
6380
6455
|
"csv-parse": "^5.6.0",
|
|
@@ -6392,12 +6467,16 @@ var package_default = {
|
|
|
6392
6467
|
"gradient-string": "^3.0.0",
|
|
6393
6468
|
"gray-matter": "^4.0.3",
|
|
6394
6469
|
ini: "^5.0.0",
|
|
6470
|
+
ink: "^4.2.0",
|
|
6471
|
+
"ink-progress-bar": "^3.0.0",
|
|
6472
|
+
"ink-spinner": "^5.0.0",
|
|
6395
6473
|
inquirer: "^12.6.0",
|
|
6396
6474
|
"interactive-commander": "^0.5.194",
|
|
6397
6475
|
"is-url": "^1.2.4",
|
|
6398
6476
|
jsdom: "^25.0.1",
|
|
6399
6477
|
json5: "^2.2.3",
|
|
6400
6478
|
jsonrepair: "^3.11.2",
|
|
6479
|
+
listr2: "^8.3.2",
|
|
6401
6480
|
lodash: "^4.17.21",
|
|
6402
6481
|
marked: "^15.0.6",
|
|
6403
6482
|
"mdast-util-from-markdown": "^2.0.2",
|
|
@@ -6414,6 +6493,7 @@ var package_default = {
|
|
|
6414
6493
|
plist: "^3.1.0",
|
|
6415
6494
|
"posthog-node": "^4.17.0",
|
|
6416
6495
|
prettier: "^3.4.2",
|
|
6496
|
+
react: "^18.3.1",
|
|
6417
6497
|
"rehype-stringify": "^10.0.1",
|
|
6418
6498
|
"remark-disable-tokenizers": "^1.1.1",
|
|
6419
6499
|
"remark-frontmatter": "^5.0.0",
|
|
@@ -6435,6 +6515,7 @@ var package_default = {
|
|
|
6435
6515
|
},
|
|
6436
6516
|
devDependencies: {
|
|
6437
6517
|
"@types/babel__generator": "^7.27.0",
|
|
6518
|
+
"@types/cli-progress": "^3.11.6",
|
|
6438
6519
|
"@types/cors": "^2.8.17",
|
|
6439
6520
|
"@types/diff": "^7.0.0",
|
|
6440
6521
|
"@types/express": "^5.0.1",
|
|
@@ -6450,6 +6531,7 @@ var package_default = {
|
|
|
6450
6531
|
"@types/node-gettext": "^3.0.6",
|
|
6451
6532
|
"@types/object-hash": "^3.0.6",
|
|
6452
6533
|
"@types/plist": "^3.0.5",
|
|
6534
|
+
"@types/react": "^18.3.20",
|
|
6453
6535
|
"@types/xml2js": "^0.4.14",
|
|
6454
6536
|
tsup: "^8.3.5",
|
|
6455
6537
|
typescript: "^5.8.3",
|
|
@@ -6460,13 +6542,746 @@ var package_default = {
|
|
|
6460
6542
|
}
|
|
6461
6543
|
};
|
|
6462
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
|
+
|
|
6463
7278
|
// src/cli/index.ts
|
|
6464
7279
|
dotenv.config();
|
|
6465
7280
|
var cli_default = new InteractiveCommand2().name("lingo.dev").description("Lingo.dev CLI").helpOption("-h, --help", "Show help").addHelpText(
|
|
6466
7281
|
"beforeAll",
|
|
6467
7282
|
`
|
|
6468
|
-
${
|
|
6469
|
-
|
|
7283
|
+
${vice3(
|
|
7284
|
+
figlet3.textSync("LINGO.DEV", {
|
|
6470
7285
|
font: "ANSI Shadow",
|
|
6471
7286
|
horizontalLayout: "default",
|
|
6472
7287
|
verticalLayout: "default"
|
|
@@ -6477,11 +7292,11 @@ ${vice2(
|
|
|
6477
7292
|
|
|
6478
7293
|
Star the the repo :) https://github.com/LingoDotDev/lingo.dev
|
|
6479
7294
|
`
|
|
6480
|
-
).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) => {
|
|
6481
7296
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
6482
7297
|
process.exit(0);
|
|
6483
7298
|
}
|
|
6484
|
-
|
|
7299
|
+
process.exit(1);
|
|
6485
7300
|
});
|
|
6486
7301
|
export {
|
|
6487
7302
|
cli_default as default
|