lingo.dev 0.100.1 → 0.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/build/cli.cjs +1245 -440
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +1210 -405
- package/build/cli.mjs.map +1 -1
- package/package.json +7 -4
package/build/cli.mjs
CHANGED
|
@@ -31,7 +31,8 @@ function getSettings(explicitApiKey) {
|
|
|
31
31
|
anthropicApiKey: env.ANTHROPIC_API_KEY || systemFile.llm?.anthropicApiKey,
|
|
32
32
|
groqApiKey: env.GROQ_API_KEY || systemFile.llm?.groqApiKey,
|
|
33
33
|
googleApiKey: env.GOOGLE_API_KEY || systemFile.llm?.googleApiKey,
|
|
34
|
-
openrouterApiKey: env.OPENROUTER_API_KEY || systemFile.llm?.openrouterApiKey
|
|
34
|
+
openrouterApiKey: env.OPENROUTER_API_KEY || systemFile.llm?.openrouterApiKey,
|
|
35
|
+
mistralApiKey: env.MISTRAL_API_KEY || systemFile.llm?.mistralApiKey
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
38
|
}
|
|
@@ -61,7 +62,8 @@ var SettingsSchema = Z.object({
|
|
|
61
62
|
anthropicApiKey: Z.string().optional(),
|
|
62
63
|
groqApiKey: Z.string().optional(),
|
|
63
64
|
googleApiKey: Z.string().optional(),
|
|
64
|
-
openrouterApiKey: Z.string().optional()
|
|
65
|
+
openrouterApiKey: Z.string().optional(),
|
|
66
|
+
mistralApiKey: Z.string().optional()
|
|
65
67
|
})
|
|
66
68
|
});
|
|
67
69
|
var SETTINGS_KEYS = flattenZodObject(
|
|
@@ -86,7 +88,8 @@ function _loadEnv() {
|
|
|
86
88
|
ANTHROPIC_API_KEY: Z.string().optional(),
|
|
87
89
|
GROQ_API_KEY: Z.string().optional(),
|
|
88
90
|
GOOGLE_API_KEY: Z.string().optional(),
|
|
89
|
-
OPENROUTER_API_KEY: Z.string().optional()
|
|
91
|
+
OPENROUTER_API_KEY: Z.string().optional(),
|
|
92
|
+
MISTRAL_API_KEY: Z.string().optional()
|
|
90
93
|
}).passthrough().parse(process.env);
|
|
91
94
|
}
|
|
92
95
|
function _loadSystemFile() {
|
|
@@ -104,7 +107,8 @@ function _loadSystemFile() {
|
|
|
104
107
|
anthropicApiKey: Z.string().optional(),
|
|
105
108
|
groqApiKey: Z.string().optional(),
|
|
106
109
|
googleApiKey: Z.string().optional(),
|
|
107
|
-
openrouterApiKey: Z.string().optional()
|
|
110
|
+
openrouterApiKey: Z.string().optional(),
|
|
111
|
+
mistralApiKey: Z.string().optional()
|
|
108
112
|
}).optional()
|
|
109
113
|
}).passthrough().parse(data);
|
|
110
114
|
}
|
|
@@ -173,6 +177,12 @@ function _envVarsInfo() {
|
|
|
173
177
|
`\u2139\uFE0F Using OPENROUTER_API_KEY env var instead of key from user config`
|
|
174
178
|
);
|
|
175
179
|
}
|
|
180
|
+
if (env.MISTRAL_API_KEY && systemFile.llm?.mistralApiKey) {
|
|
181
|
+
console.info(
|
|
182
|
+
"\x1B[36m%s\x1B[0m",
|
|
183
|
+
`\u2139\uFE0F Using MISTRAL_API_KEY env var instead of key from user config`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
176
186
|
if (env.LINGODOTDEV_API_URL) {
|
|
177
187
|
console.info(
|
|
178
188
|
"\x1B[36m%s\x1B[0m",
|
|
@@ -217,9 +227,12 @@ var CLIError = class extends Error {
|
|
|
217
227
|
// src/cli/utils/cloudflare-status.ts
|
|
218
228
|
async function checkCloudflareStatus() {
|
|
219
229
|
try {
|
|
220
|
-
const response = await fetch(
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
const response = await fetch(
|
|
231
|
+
"https://www.cloudflarestatus.com/api/v2/status.json",
|
|
232
|
+
{
|
|
233
|
+
signal: AbortSignal.timeout(5e3)
|
|
234
|
+
}
|
|
235
|
+
);
|
|
223
236
|
if (response.ok) {
|
|
224
237
|
return await response.json();
|
|
225
238
|
}
|
|
@@ -378,7 +391,9 @@ async function renderBanner() {
|
|
|
378
391
|
}
|
|
379
392
|
async function renderHero() {
|
|
380
393
|
console.log(
|
|
381
|
-
`\u26A1\uFE0F ${chalk.hex(colors.green)(
|
|
394
|
+
`\u26A1\uFE0F ${chalk.hex(colors.green)(
|
|
395
|
+
"Lingo.dev"
|
|
396
|
+
)} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
382
397
|
);
|
|
383
398
|
console.log("");
|
|
384
399
|
const label1 = "\u2B50 GitHub Repo:";
|
|
@@ -386,13 +401,19 @@ async function renderHero() {
|
|
|
386
401
|
const label3 = "\u{1F4AC} 24/7 Support:";
|
|
387
402
|
const maxLabelWidth = 17;
|
|
388
403
|
console.log(
|
|
389
|
-
`${chalk.hex(colors.blue)(label1.padEnd(maxLabelWidth))} ${chalk.hex(
|
|
404
|
+
`${chalk.hex(colors.blue)(label1.padEnd(maxLabelWidth))} ${chalk.hex(
|
|
405
|
+
colors.blue
|
|
406
|
+
)("https://lingo.dev/go/gh")}`
|
|
390
407
|
);
|
|
391
408
|
console.log(
|
|
392
|
-
`${chalk.hex(colors.blue)(label2.padEnd(maxLabelWidth + 1))} ${chalk.hex(
|
|
409
|
+
`${chalk.hex(colors.blue)(label2.padEnd(maxLabelWidth + 1))} ${chalk.hex(
|
|
410
|
+
colors.blue
|
|
411
|
+
)("https://lingo.dev/go/docs")}`
|
|
393
412
|
);
|
|
394
413
|
console.log(
|
|
395
|
-
`${chalk.hex(colors.blue)(label3.padEnd(maxLabelWidth + 1))} ${chalk.hex(
|
|
414
|
+
`${chalk.hex(colors.blue)(label3.padEnd(maxLabelWidth + 1))} ${chalk.hex(
|
|
415
|
+
colors.blue
|
|
416
|
+
)("hi@lingo.dev")}`
|
|
396
417
|
);
|
|
397
418
|
}
|
|
398
419
|
async function waitForUserPrompt(message) {
|
|
@@ -541,7 +562,11 @@ function _getConfigFilePath() {
|
|
|
541
562
|
}
|
|
542
563
|
|
|
543
564
|
// src/cli/cmd/init.ts
|
|
544
|
-
import {
|
|
565
|
+
import {
|
|
566
|
+
defaultConfig,
|
|
567
|
+
resolveLocaleCode as resolveLocaleCode2,
|
|
568
|
+
bucketTypes
|
|
569
|
+
} from "@lingo.dev/_spec";
|
|
545
570
|
import fs6 from "fs";
|
|
546
571
|
import path7 from "path";
|
|
547
572
|
import _3 from "lodash";
|
|
@@ -583,13 +608,17 @@ function findLocaleFilesWithExtension(ext2) {
|
|
|
583
608
|
ignore: ["node_modules/**", "package*.json", "i18n.json", "lingo.json"]
|
|
584
609
|
});
|
|
585
610
|
const localeFilePattern = new RegExp(`/([a-z]{2}(-[A-Z]{2})?)${ext2}$`);
|
|
586
|
-
const localeDirectoryPattern = new RegExp(
|
|
611
|
+
const localeDirectoryPattern = new RegExp(
|
|
612
|
+
`/([a-z]{2}(-[A-Z]{2})?)/[^/]+${ext2}$`
|
|
613
|
+
);
|
|
587
614
|
const potentialLocaleFiles = files.filter(
|
|
588
615
|
(file) => localeFilePattern.test(file) || localeDirectoryPattern.test(file)
|
|
589
616
|
);
|
|
590
617
|
const potantialLocaleFilesAndPatterns = potentialLocaleFiles.map((file) => {
|
|
591
618
|
const matchPotentialLocales = Array.from(
|
|
592
|
-
file.matchAll(
|
|
619
|
+
file.matchAll(
|
|
620
|
+
new RegExp(`/([a-z]{2}(-[A-Z]{2})?|[^/]+)(?=/|${ext2})`, "g")
|
|
621
|
+
)
|
|
593
622
|
);
|
|
594
623
|
const potantialLocales = matchPotentialLocales.map((match2) => match2[1]);
|
|
595
624
|
return { file, potantialLocales };
|
|
@@ -603,10 +632,12 @@ function findLocaleFilesWithExtension(ext2) {
|
|
|
603
632
|
}
|
|
604
633
|
return { file, locale: null };
|
|
605
634
|
}).filter(({ locale }) => locale !== null);
|
|
606
|
-
const localeFilesAndPatterns = potantialLocaleFilesAndPatterns.map(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
635
|
+
const localeFilesAndPatterns = potantialLocaleFilesAndPatterns.map(
|
|
636
|
+
({ file, locale }) => {
|
|
637
|
+
const pattern = file.replaceAll(new RegExp(`/${locale}${ext2}`, "g"), `/[locale]${ext2}`).replaceAll(new RegExp(`/${locale}/`, "g"), `/[locale]/`).replaceAll(new RegExp(`/${locale}/`, "g"), `/[locale]/`);
|
|
638
|
+
return { pattern, file };
|
|
639
|
+
}
|
|
640
|
+
);
|
|
610
641
|
const grouppedFilesAndPatterns = _2.groupBy(localeFilesAndPatterns, "pattern");
|
|
611
642
|
const patterns = Object.keys(grouppedFilesAndPatterns);
|
|
612
643
|
const defaultPatterns = [`i18n/[locale]${ext2}`];
|
|
@@ -764,7 +795,9 @@ async function initCICD(spinner) {
|
|
|
764
795
|
message: "Would you like to use Lingo.dev in your CI/CD?"
|
|
765
796
|
});
|
|
766
797
|
if (!init) {
|
|
767
|
-
spinner.warn(
|
|
798
|
+
spinner.warn(
|
|
799
|
+
"CI/CD not initialized. To set it up later, see docs: https://lingo.dev/ci"
|
|
800
|
+
);
|
|
768
801
|
return;
|
|
769
802
|
}
|
|
770
803
|
const selectedPlatforms = await checkbox({
|
|
@@ -895,7 +928,9 @@ var throwHelpError = (option, value) => {
|
|
|
895
928
|
Do you need support for ${value} ${option}? Type "help" and we will.`
|
|
896
929
|
);
|
|
897
930
|
};
|
|
898
|
-
var init_default = new InteractiveCommand().command("init").description("Initialize Lingo.dev project").helpOption("-h, --help", "Show help").addOption(
|
|
931
|
+
var init_default = new InteractiveCommand().command("init").description("Initialize Lingo.dev project").helpOption("-h, --help", "Show help").addOption(
|
|
932
|
+
new InteractiveOption("-f --force", "Overwrite existing config").prompt(void 0).default(false)
|
|
933
|
+
).addOption(
|
|
899
934
|
new InteractiveOption("-s --source <locale>", "Source locale").argParser((value) => {
|
|
900
935
|
try {
|
|
901
936
|
resolveLocaleCode2(value);
|
|
@@ -924,7 +959,10 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
924
959
|
return value;
|
|
925
960
|
}).default("json")
|
|
926
961
|
).addOption(
|
|
927
|
-
new InteractiveOption(
|
|
962
|
+
new InteractiveOption(
|
|
963
|
+
"-p, --paths [path...]",
|
|
964
|
+
"List of paths for the bucket"
|
|
965
|
+
).argParser((value) => {
|
|
928
966
|
if (!value || value.length === 0) return [];
|
|
929
967
|
const values = value.includes(",") ? value.split(",") : value.split(" ");
|
|
930
968
|
for (const p of values) {
|
|
@@ -985,7 +1023,9 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
985
1023
|
}
|
|
986
1024
|
if (selectedPatterns.length === 0) {
|
|
987
1025
|
const useDefault = await confirm2({
|
|
988
|
-
message: `Use (and create) default path ${defaultPatterns.join(
|
|
1026
|
+
message: `Use (and create) default path ${defaultPatterns.join(
|
|
1027
|
+
", "
|
|
1028
|
+
)}?`
|
|
989
1029
|
});
|
|
990
1030
|
if (useDefault) {
|
|
991
1031
|
ensurePatterns(defaultPatterns, options.source);
|
|
@@ -1009,7 +1049,9 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
1009
1049
|
spinner.succeed("Lingo.dev project initialized");
|
|
1010
1050
|
if (isInteractive) {
|
|
1011
1051
|
await initCICD(spinner);
|
|
1012
|
-
const openDocs = await confirm2({
|
|
1052
|
+
const openDocs = await confirm2({
|
|
1053
|
+
message: "Would you like to see our docs?"
|
|
1054
|
+
});
|
|
1013
1055
|
if (openDocs) {
|
|
1014
1056
|
openUrl("/go/docs");
|
|
1015
1057
|
}
|
|
@@ -1040,7 +1082,9 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
1040
1082
|
}
|
|
1041
1083
|
}
|
|
1042
1084
|
} else {
|
|
1043
|
-
Ora4().warn(
|
|
1085
|
+
Ora4().warn(
|
|
1086
|
+
"You are not logged in. Run `npx lingo.dev@latest auth --login` to login."
|
|
1087
|
+
);
|
|
1044
1088
|
}
|
|
1045
1089
|
} else {
|
|
1046
1090
|
Ora4().succeed(`Authenticated as ${auth.email}`);
|
|
@@ -1229,7 +1273,13 @@ function resolveBucketItem(bucketItem) {
|
|
|
1229
1273
|
|
|
1230
1274
|
// src/cli/cmd/show/files.ts
|
|
1231
1275
|
import { resolveOverriddenLocale as resolveOverriddenLocale2 } from "@lingo.dev/_spec";
|
|
1232
|
-
var files_default = new Command6().command("files").description("Print out the list of files managed by Lingo.dev").option(
|
|
1276
|
+
var files_default = new Command6().command("files").description("Print out the list of files managed by Lingo.dev").option(
|
|
1277
|
+
"--source",
|
|
1278
|
+
"Only show source files, files containing the original translations"
|
|
1279
|
+
).option(
|
|
1280
|
+
"--target",
|
|
1281
|
+
"Only show target files, files containing translated content"
|
|
1282
|
+
).helpOption("-h, --help", "Show help").action(async (type) => {
|
|
1233
1283
|
const ora = Ora6();
|
|
1234
1284
|
try {
|
|
1235
1285
|
try {
|
|
@@ -1243,12 +1293,26 @@ var files_default = new Command6().command("files").description("Print out the l
|
|
|
1243
1293
|
const buckets = getBuckets(i18nConfig);
|
|
1244
1294
|
for (const bucket of buckets) {
|
|
1245
1295
|
for (const bucketConfig of bucket.paths) {
|
|
1246
|
-
const sourceLocale = resolveOverriddenLocale2(
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1296
|
+
const sourceLocale = resolveOverriddenLocale2(
|
|
1297
|
+
i18nConfig.locale.source,
|
|
1298
|
+
bucketConfig.delimiter
|
|
1299
|
+
);
|
|
1300
|
+
const sourcePath = bucketConfig.pathPattern.replace(
|
|
1301
|
+
/\[locale\]/g,
|
|
1302
|
+
sourceLocale
|
|
1303
|
+
);
|
|
1304
|
+
const targetPaths = i18nConfig.locale.targets.map(
|
|
1305
|
+
(_targetLocale) => {
|
|
1306
|
+
const targetLocale = resolveOverriddenLocale2(
|
|
1307
|
+
_targetLocale,
|
|
1308
|
+
bucketConfig.delimiter
|
|
1309
|
+
);
|
|
1310
|
+
return bucketConfig.pathPattern.replace(
|
|
1311
|
+
/\[locale\]/g,
|
|
1312
|
+
targetLocale
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
);
|
|
1252
1316
|
const result = [];
|
|
1253
1317
|
if (!type.source && !type.target) {
|
|
1254
1318
|
result.push(sourcePath, ...targetPaths);
|
|
@@ -1328,7 +1392,9 @@ Available keys:
|
|
|
1328
1392
|
console.error(
|
|
1329
1393
|
dedent2`
|
|
1330
1394
|
${chalk3.red("\u2716")} Unknown configuration key: ${chalk3.bold(key)}
|
|
1331
|
-
Run ${chalk3.dim(
|
|
1395
|
+
Run ${chalk3.dim(
|
|
1396
|
+
"lingo.dev config unset --help"
|
|
1397
|
+
)} to see available keys.
|
|
1332
1398
|
`
|
|
1333
1399
|
);
|
|
1334
1400
|
process.exitCode = 1;
|
|
@@ -1402,7 +1468,7 @@ import {
|
|
|
1402
1468
|
} from "@lingo.dev/_spec";
|
|
1403
1469
|
import { Command as Command12 } from "interactive-commander";
|
|
1404
1470
|
import Z3 from "zod";
|
|
1405
|
-
import
|
|
1471
|
+
import _30 from "lodash";
|
|
1406
1472
|
import Ora7 from "ora";
|
|
1407
1473
|
|
|
1408
1474
|
// src/cli/loaders/_utils.ts
|
|
@@ -1627,13 +1693,17 @@ function createTextFileLoader(pathPattern) {
|
|
|
1627
1693
|
const trimmedResult = result.trim();
|
|
1628
1694
|
return trimmedResult;
|
|
1629
1695
|
},
|
|
1630
|
-
async push(locale, data,
|
|
1696
|
+
async push(locale, data, _34, originalLocale) {
|
|
1631
1697
|
const draftPath = pathPattern.replaceAll("[locale]", locale);
|
|
1632
1698
|
const finalPath = path10.resolve(draftPath);
|
|
1633
1699
|
const dirPath = path10.dirname(finalPath);
|
|
1634
1700
|
await fs8.mkdir(dirPath, { recursive: true });
|
|
1635
1701
|
const trimmedPayload = data.trim();
|
|
1636
|
-
const trailingNewLine = await getTrailingNewLine(
|
|
1702
|
+
const trailingNewLine = await getTrailingNewLine(
|
|
1703
|
+
pathPattern,
|
|
1704
|
+
locale,
|
|
1705
|
+
originalLocale
|
|
1706
|
+
);
|
|
1637
1707
|
let finalPayload = trimmedPayload + trailingNewLine;
|
|
1638
1708
|
await fs8.writeFile(finalPath, finalPayload, {
|
|
1639
1709
|
encoding: "utf-8",
|
|
@@ -1727,15 +1797,22 @@ import _10 from "lodash";
|
|
|
1727
1797
|
function createFlutterLoader() {
|
|
1728
1798
|
return createLoader({
|
|
1729
1799
|
async pull(locale, input2) {
|
|
1730
|
-
const result = _10.pickBy(input2, (value, key) => !key
|
|
1800
|
+
const result = _10.pickBy(input2, (value, key) => !_isMetadataKey(key));
|
|
1731
1801
|
return result;
|
|
1732
1802
|
},
|
|
1733
1803
|
async push(locale, data, originalInput) {
|
|
1734
|
-
const
|
|
1804
|
+
const metadata = _10.pickBy(
|
|
1805
|
+
originalInput,
|
|
1806
|
+
(value, key) => _isMetadataKey(key)
|
|
1807
|
+
);
|
|
1808
|
+
const result = _10.merge({}, metadata, { "@@locale": locale }, data);
|
|
1735
1809
|
return result;
|
|
1736
1810
|
}
|
|
1737
1811
|
});
|
|
1738
1812
|
}
|
|
1813
|
+
function _isMetadataKey(key) {
|
|
1814
|
+
return key.startsWith("@");
|
|
1815
|
+
}
|
|
1739
1816
|
|
|
1740
1817
|
// src/cli/loaders/android.ts
|
|
1741
1818
|
import { parseStringPromise, Builder } from "xml2js";
|
|
@@ -1930,7 +2007,9 @@ function createCsvLoader() {
|
|
|
1930
2007
|
function _createCsvLoader() {
|
|
1931
2008
|
return createLoader({
|
|
1932
2009
|
async pull(locale, input2) {
|
|
1933
|
-
const keyColumnName = detectKeyColumnName(
|
|
2010
|
+
const keyColumnName = detectKeyColumnName(
|
|
2011
|
+
input2.split("\n").find((l) => l.length)
|
|
2012
|
+
);
|
|
1934
2013
|
const inputParsed = parse(input2, {
|
|
1935
2014
|
columns: true,
|
|
1936
2015
|
skip_empty_lines: true,
|
|
@@ -1958,7 +2037,9 @@ function _createCsvLoader() {
|
|
|
1958
2037
|
...row,
|
|
1959
2038
|
[locale]: items[row[keyColumnName]] || row[locale] || ""
|
|
1960
2039
|
}));
|
|
1961
|
-
const existingKeys = new Set(
|
|
2040
|
+
const existingKeys = new Set(
|
|
2041
|
+
inputParsed.map((row) => row[keyColumnName])
|
|
2042
|
+
);
|
|
1962
2043
|
Object.entries(items).forEach(([key, value]) => {
|
|
1963
2044
|
if (!existingKeys.has(key)) {
|
|
1964
2045
|
const newRow = {
|
|
@@ -2054,15 +2135,23 @@ function createHtmlLoader() {
|
|
|
2054
2135
|
result[getPath(element, attr)] = value;
|
|
2055
2136
|
}
|
|
2056
2137
|
});
|
|
2057
|
-
Array.from(element.childNodes).filter(
|
|
2138
|
+
Array.from(element.childNodes).filter(
|
|
2139
|
+
(n) => n.nodeType === 1 || n.nodeType === 3 && n.textContent?.trim()
|
|
2140
|
+
).forEach(processNode);
|
|
2058
2141
|
}
|
|
2059
2142
|
};
|
|
2060
|
-
Array.from(document.head.childNodes).filter(
|
|
2061
|
-
|
|
2143
|
+
Array.from(document.head.childNodes).filter(
|
|
2144
|
+
(n) => n.nodeType === 1 || n.nodeType === 3 && n.textContent?.trim()
|
|
2145
|
+
).forEach(processNode);
|
|
2146
|
+
Array.from(document.body.childNodes).filter(
|
|
2147
|
+
(n) => n.nodeType === 1 || n.nodeType === 3 && n.textContent?.trim()
|
|
2148
|
+
).forEach(processNode);
|
|
2062
2149
|
return result;
|
|
2063
2150
|
},
|
|
2064
2151
|
async push(locale, data, originalInput) {
|
|
2065
|
-
const dom = new JSDOM(
|
|
2152
|
+
const dom = new JSDOM(
|
|
2153
|
+
originalInput ?? "<!DOCTYPE html><html><head></head><body></body></html>"
|
|
2154
|
+
);
|
|
2066
2155
|
const document = dom.window.document;
|
|
2067
2156
|
const htmlElement = document.documentElement;
|
|
2068
2157
|
htmlElement.setAttribute("lang", locale);
|
|
@@ -2136,14 +2225,21 @@ function createMarkdownLoader() {
|
|
|
2136
2225
|
...Object.fromEntries(
|
|
2137
2226
|
sections.map((section, index) => [`${MD_SECTION_PREFIX}${index}`, section]).filter(([, section]) => Boolean(section))
|
|
2138
2227
|
),
|
|
2139
|
-
...Object.fromEntries(
|
|
2228
|
+
...Object.fromEntries(
|
|
2229
|
+
Object.entries(frontmatter).map(([key, value]) => [
|
|
2230
|
+
`${FM_ATTR_PREFIX}${key}`,
|
|
2231
|
+
value
|
|
2232
|
+
])
|
|
2233
|
+
)
|
|
2140
2234
|
};
|
|
2141
2235
|
},
|
|
2142
2236
|
async push(locale, data) {
|
|
2143
2237
|
const frontmatter = Object.fromEntries(
|
|
2144
2238
|
Object.entries(data).filter(([key]) => key.startsWith(FM_ATTR_PREFIX)).map(([key, value]) => [key.replace(FM_ATTR_PREFIX, ""), value])
|
|
2145
2239
|
);
|
|
2146
|
-
let content = Object.entries(data).filter(([key]) => key.startsWith(MD_SECTION_PREFIX)).sort(
|
|
2240
|
+
let content = Object.entries(data).filter(([key]) => key.startsWith(MD_SECTION_PREFIX)).sort(
|
|
2241
|
+
([a], [b]) => Number(a.split("-").pop()) - Number(b.split("-").pop())
|
|
2242
|
+
).map(([, value]) => value?.trim() ?? "").filter(Boolean).join("\n\n");
|
|
2147
2243
|
if (Object.keys(frontmatter).length > 0) {
|
|
2148
2244
|
content = `
|
|
2149
2245
|
${content}`;
|
|
@@ -2176,7 +2272,7 @@ function createPropertiesLoader() {
|
|
|
2176
2272
|
return result;
|
|
2177
2273
|
},
|
|
2178
2274
|
async push(locale, payload) {
|
|
2179
|
-
const result = Object.entries(payload).filter(([
|
|
2275
|
+
const result = Object.entries(payload).filter(([_34, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
2180
2276
|
return result;
|
|
2181
2277
|
}
|
|
2182
2278
|
});
|
|
@@ -2268,7 +2364,9 @@ function createXcodeXcstringsLoader(defaultLocale) {
|
|
|
2268
2364
|
async pull(locale, input2, initCtx) {
|
|
2269
2365
|
const resultData = {};
|
|
2270
2366
|
const isSourceLanguage = locale === defaultLocale;
|
|
2271
|
-
for (const [translationKey, _translationEntity] of Object.entries(
|
|
2367
|
+
for (const [translationKey, _translationEntity] of Object.entries(
|
|
2368
|
+
input2.strings
|
|
2369
|
+
)) {
|
|
2272
2370
|
const rootTranslationEntity = _translationEntity;
|
|
2273
2371
|
if (rootTranslationEntity.shouldTranslate === false) {
|
|
2274
2372
|
continue;
|
|
@@ -2297,7 +2395,10 @@ function createXcodeXcstringsLoader(defaultLocale) {
|
|
|
2297
2395
|
async push(locale, payload, originalInput) {
|
|
2298
2396
|
const langDataToMerge = {};
|
|
2299
2397
|
langDataToMerge.strings = {};
|
|
2300
|
-
const input2 = _12.cloneDeep(originalInput) || {
|
|
2398
|
+
const input2 = _12.cloneDeep(originalInput) || {
|
|
2399
|
+
sourceLanguage: locale,
|
|
2400
|
+
strings: {}
|
|
2401
|
+
};
|
|
2301
2402
|
for (const [key, value] of Object.entries(payload)) {
|
|
2302
2403
|
if (value === null || value === void 0) {
|
|
2303
2404
|
continue;
|
|
@@ -2343,11 +2444,22 @@ function createXcodeXcstringsLoader(defaultLocale) {
|
|
|
2343
2444
|
}
|
|
2344
2445
|
}
|
|
2345
2446
|
}
|
|
2346
|
-
const
|
|
2447
|
+
const originalInputWithoutLocale = originalInput ? _removeLocale(originalInput, locale) : {};
|
|
2448
|
+
const result = _12.merge({}, originalInputWithoutLocale, langDataToMerge);
|
|
2347
2449
|
return result;
|
|
2348
2450
|
}
|
|
2349
2451
|
});
|
|
2350
2452
|
}
|
|
2453
|
+
function _removeLocale(input2, locale) {
|
|
2454
|
+
const { sourceLanguage, strings } = input2;
|
|
2455
|
+
const newStrings = _12.cloneDeep(strings);
|
|
2456
|
+
for (const [key, value] of Object.entries(newStrings)) {
|
|
2457
|
+
if (value.localizations?.[locale]) {
|
|
2458
|
+
delete value.localizations[locale];
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
return { sourceLanguage, strings: newStrings };
|
|
2462
|
+
}
|
|
2351
2463
|
|
|
2352
2464
|
// src/cli/loaders/prettier.ts
|
|
2353
2465
|
import path11 from "path";
|
|
@@ -2425,36 +2537,29 @@ async function formatDataWithPrettier(data, filePath, options) {
|
|
|
2425
2537
|
import _13 from "lodash";
|
|
2426
2538
|
import _isUrl from "is-url";
|
|
2427
2539
|
import { isValid, parseISO } from "date-fns";
|
|
2428
|
-
function createUnlocalizableLoader(
|
|
2429
|
-
const rules = {
|
|
2430
|
-
isEmpty: (v) => _13.isEmpty(v),
|
|
2431
|
-
isNumber: (v) => typeof v === "number" || /^[0-9]+$/.test(v),
|
|
2432
|
-
isBoolean: (v) => _13.isBoolean(v),
|
|
2433
|
-
isIsoDate: (v) => _13.isString(v) && _isIsoDate(v),
|
|
2434
|
-
isSystemId: (v) => _13.isString(v) && _isSystemId(v),
|
|
2435
|
-
isUrl: (v) => _13.isString(v) && _isUrl(v)
|
|
2436
|
-
};
|
|
2540
|
+
function createUnlocalizableLoader(returnUnlocalizedKeys = false) {
|
|
2437
2541
|
return createLoader({
|
|
2438
2542
|
async pull(locale, input2) {
|
|
2439
|
-
const
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
}
|
|
2445
|
-
return false;
|
|
2446
|
-
}).map(([key, _33]) => key);
|
|
2447
|
-
const result = _13.omitBy(input2, (_33, key) => passthroughKeys.includes(key));
|
|
2543
|
+
const unlocalizableKeys = _getUnlocalizableKeys(input2);
|
|
2544
|
+
const result = _13.omitBy(
|
|
2545
|
+
input2,
|
|
2546
|
+
(_34, key) => unlocalizableKeys.includes(key)
|
|
2547
|
+
);
|
|
2448
2548
|
if (returnUnlocalizedKeys) {
|
|
2449
|
-
result.unlocalizable = _13.omitBy(
|
|
2549
|
+
result.unlocalizable = _13.omitBy(
|
|
2550
|
+
input2,
|
|
2551
|
+
(_34, key) => !unlocalizableKeys.includes(key)
|
|
2552
|
+
);
|
|
2450
2553
|
}
|
|
2451
2554
|
return result;
|
|
2452
2555
|
},
|
|
2453
2556
|
async push(locale, data, originalInput) {
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2557
|
+
const unlocalizableKeys = _getUnlocalizableKeys(originalInput);
|
|
2558
|
+
const result = _13.merge(
|
|
2559
|
+
{},
|
|
2560
|
+
data,
|
|
2561
|
+
_13.omitBy(originalInput, (_34, key) => !unlocalizableKeys.includes(key))
|
|
2562
|
+
);
|
|
2458
2563
|
return result;
|
|
2459
2564
|
}
|
|
2460
2565
|
});
|
|
@@ -2465,6 +2570,27 @@ function _isSystemId(v) {
|
|
|
2465
2570
|
function _isIsoDate(v) {
|
|
2466
2571
|
return isValid(parseISO(v));
|
|
2467
2572
|
}
|
|
2573
|
+
function _getUnlocalizableKeys(input2) {
|
|
2574
|
+
const rules = {
|
|
2575
|
+
isEmpty: (v) => _13.isEmpty(v),
|
|
2576
|
+
isNumber: (v) => typeof v === "number" || /^[0-9]+$/.test(v),
|
|
2577
|
+
isBoolean: (v) => _13.isBoolean(v),
|
|
2578
|
+
isIsoDate: (v) => _13.isString(v) && _isIsoDate(v),
|
|
2579
|
+
isSystemId: (v) => _13.isString(v) && _isSystemId(v),
|
|
2580
|
+
isUrl: (v) => _13.isString(v) && _isUrl(v)
|
|
2581
|
+
};
|
|
2582
|
+
if (!input2) {
|
|
2583
|
+
return [];
|
|
2584
|
+
}
|
|
2585
|
+
return Object.entries(input2).filter(([key, value]) => {
|
|
2586
|
+
for (const [ruleName, rule] of Object.entries(rules)) {
|
|
2587
|
+
if (rule(value)) {
|
|
2588
|
+
return true;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
return false;
|
|
2592
|
+
}).map(([key, _34]) => key);
|
|
2593
|
+
}
|
|
2468
2594
|
|
|
2469
2595
|
// src/cli/loaders/po/index.ts
|
|
2470
2596
|
import _14 from "lodash";
|
|
@@ -2736,16 +2862,24 @@ function createDatoFilterLoader() {
|
|
|
2736
2862
|
for (const [modelId, modelInfo] of _15.entries(result)) {
|
|
2737
2863
|
for (const record of modelInfo.records) {
|
|
2738
2864
|
for (const [fieldId, fieldValue] of _15.entries(record)) {
|
|
2739
|
-
const fieldInfo = modelInfo.fields.find(
|
|
2865
|
+
const fieldInfo = modelInfo.fields.find(
|
|
2866
|
+
(field) => field.api_key === fieldId
|
|
2867
|
+
);
|
|
2740
2868
|
if (fieldInfo) {
|
|
2741
2869
|
const sourceFieldValue = _15.get(fieldValue, [originalLocale]);
|
|
2742
|
-
const targetFieldValue = _15.get(data, [
|
|
2870
|
+
const targetFieldValue = _15.get(data, [
|
|
2871
|
+
modelId,
|
|
2872
|
+
record.id,
|
|
2873
|
+
fieldId
|
|
2874
|
+
]);
|
|
2743
2875
|
if (targetFieldValue) {
|
|
2744
2876
|
_15.set(record, [fieldId, locale], targetFieldValue);
|
|
2745
2877
|
} else {
|
|
2746
2878
|
_15.set(record, [fieldId, locale], sourceFieldValue);
|
|
2747
2879
|
}
|
|
2748
|
-
_15.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _15.isEmpty(_15.get(fieldValue, [loc]))).forEach(
|
|
2880
|
+
_15.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _15.isEmpty(_15.get(fieldValue, [loc]))).forEach(
|
|
2881
|
+
(loc) => _15.set(record, [fieldId, loc], sourceFieldValue)
|
|
2882
|
+
).value();
|
|
2749
2883
|
}
|
|
2750
2884
|
}
|
|
2751
2885
|
}
|
|
@@ -2763,7 +2897,9 @@ import _16 from "lodash";
|
|
|
2763
2897
|
import { buildClient } from "@datocms/cma-client-node";
|
|
2764
2898
|
function createDatoClient(params) {
|
|
2765
2899
|
if (!params.apiKey) {
|
|
2766
|
-
throw new Error(
|
|
2900
|
+
throw new Error(
|
|
2901
|
+
"Missing required environment variable: DATO_API_TOKEN. Please set this variable and try again."
|
|
2902
|
+
);
|
|
2767
2903
|
}
|
|
2768
2904
|
const dato = buildClient({
|
|
2769
2905
|
apiToken: params.apiKey,
|
|
@@ -2810,11 +2946,16 @@ function createDatoClient(params) {
|
|
|
2810
2946
|
findModels: async () => {
|
|
2811
2947
|
try {
|
|
2812
2948
|
const models = await dato.itemTypes.list();
|
|
2813
|
-
const modelsWithoutBlocks = models.filter(
|
|
2949
|
+
const modelsWithoutBlocks = models.filter(
|
|
2950
|
+
(model) => !model.modular_block
|
|
2951
|
+
);
|
|
2814
2952
|
return modelsWithoutBlocks;
|
|
2815
2953
|
} catch (_error) {
|
|
2816
2954
|
throw new Error(
|
|
2817
|
-
[
|
|
2955
|
+
[
|
|
2956
|
+
`Failed to find models in DatoCMS.`,
|
|
2957
|
+
`Error: ${JSON.stringify(_error, null, 2)}`
|
|
2958
|
+
].join("\n\n")
|
|
2818
2959
|
);
|
|
2819
2960
|
}
|
|
2820
2961
|
},
|
|
@@ -2845,7 +2986,9 @@ function createDatoClient(params) {
|
|
|
2845
2986
|
only_valid: "true",
|
|
2846
2987
|
ids: !records.length ? void 0 : records.join(",")
|
|
2847
2988
|
}
|
|
2848
|
-
}).catch(
|
|
2989
|
+
}).catch(
|
|
2990
|
+
(error) => Promise.reject(error?.response?.body?.data?.[0] || error)
|
|
2991
|
+
);
|
|
2849
2992
|
},
|
|
2850
2993
|
findRecordsForModel: async (modelId, records) => {
|
|
2851
2994
|
try {
|
|
@@ -2857,7 +3000,9 @@ function createDatoClient(params) {
|
|
|
2857
3000
|
only_valid: "true",
|
|
2858
3001
|
ids: !records?.length ? void 0 : records.join(",")
|
|
2859
3002
|
}
|
|
2860
|
-
}).catch(
|
|
3003
|
+
}).catch(
|
|
3004
|
+
(error) => Promise.reject(error?.response?.body?.data?.[0] || error)
|
|
3005
|
+
);
|
|
2861
3006
|
return result;
|
|
2862
3007
|
} catch (_error) {
|
|
2863
3008
|
throw new Error(
|
|
@@ -2871,7 +3016,9 @@ function createDatoClient(params) {
|
|
|
2871
3016
|
},
|
|
2872
3017
|
updateRecord: async (id, payload) => {
|
|
2873
3018
|
try {
|
|
2874
|
-
await dato.items.update(id, payload).catch(
|
|
3019
|
+
await dato.items.update(id, payload).catch(
|
|
3020
|
+
(error) => Promise.reject(error?.response?.body?.data?.[0] || error)
|
|
3021
|
+
);
|
|
2875
3022
|
} catch (_error) {
|
|
2876
3023
|
if (_error?.attributes?.details?.message) {
|
|
2877
3024
|
throw new Error(
|
|
@@ -2894,7 +3041,9 @@ function createDatoClient(params) {
|
|
|
2894
3041
|
},
|
|
2895
3042
|
enableFieldLocalization: async (args) => {
|
|
2896
3043
|
try {
|
|
2897
|
-
await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch(
|
|
3044
|
+
await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch(
|
|
3045
|
+
(error) => Promise.reject(error?.response?.body?.data?.[0] || error)
|
|
3046
|
+
);
|
|
2898
3047
|
} catch (_error) {
|
|
2899
3048
|
if (_error?.attributes?.code === "NOT_FOUND") {
|
|
2900
3049
|
throw new Error(
|
|
@@ -2906,7 +3055,10 @@ function createDatoClient(params) {
|
|
|
2906
3055
|
}
|
|
2907
3056
|
if (_error?.attributes?.details?.message) {
|
|
2908
3057
|
throw new Error(
|
|
2909
|
-
[
|
|
3058
|
+
[
|
|
3059
|
+
`${_error.attributes.details.message}`,
|
|
3060
|
+
`Error: ${JSON.stringify(_error, null, 2)}`
|
|
3061
|
+
].join("\n\n")
|
|
2910
3062
|
);
|
|
2911
3063
|
}
|
|
2912
3064
|
throw new Error(
|
|
@@ -2958,9 +3110,16 @@ function createDatoApiLoader(config, onConfigUpdate) {
|
|
|
2958
3110
|
result.models[modelId] = { fields: [], records: [] };
|
|
2959
3111
|
const fieldInfos = await getFieldDetails(dato, fields);
|
|
2960
3112
|
const fieldChoices = createFieldChoices(fieldInfos);
|
|
2961
|
-
const selectedFields = await promptFieldSelection(
|
|
3113
|
+
const selectedFields = await promptFieldSelection(
|
|
3114
|
+
modelName,
|
|
3115
|
+
fieldChoices
|
|
3116
|
+
);
|
|
2962
3117
|
for (const fieldInfo of fieldInfos) {
|
|
2963
|
-
const isLocalized = await updateFieldLocalization(
|
|
3118
|
+
const isLocalized = await updateFieldLocalization(
|
|
3119
|
+
dato,
|
|
3120
|
+
fieldInfo,
|
|
3121
|
+
selectedFields.includes(fieldInfo.id)
|
|
3122
|
+
);
|
|
2964
3123
|
if (isLocalized) {
|
|
2965
3124
|
result.models[modelId].fields.push(fieldInfo);
|
|
2966
3125
|
updatedConfig.models[modelId].fields = _17.uniq([
|
|
@@ -2970,9 +3129,18 @@ function createDatoApiLoader(config, onConfigUpdate) {
|
|
|
2970
3129
|
}
|
|
2971
3130
|
}
|
|
2972
3131
|
const records = await dato.findRecordsForModel(modelId);
|
|
2973
|
-
const recordChoices = createRecordChoices(
|
|
2974
|
-
|
|
2975
|
-
|
|
3132
|
+
const recordChoices = createRecordChoices(
|
|
3133
|
+
records,
|
|
3134
|
+
config.models[modelId]?.records || [],
|
|
3135
|
+
project
|
|
3136
|
+
);
|
|
3137
|
+
const selectedRecords = await promptRecordSelection(
|
|
3138
|
+
modelName,
|
|
3139
|
+
recordChoices
|
|
3140
|
+
);
|
|
3141
|
+
result.models[modelId].records = records.filter(
|
|
3142
|
+
(record) => selectedRecords.includes(record.id)
|
|
3143
|
+
);
|
|
2976
3144
|
updatedConfig.models[modelId].records = selectedRecords;
|
|
2977
3145
|
}
|
|
2978
3146
|
}
|
|
@@ -3000,7 +3168,9 @@ function createDatoApiLoader(config, onConfigUpdate) {
|
|
|
3000
3168
|
for (const modelId of _17.keys(data)) {
|
|
3001
3169
|
for (let i = 0; i < data[modelId].records.length; i++) {
|
|
3002
3170
|
const record = data[modelId].records[i];
|
|
3003
|
-
console.log(
|
|
3171
|
+
console.log(
|
|
3172
|
+
`Updating record ${i + 1}/${data[modelId].records.length} for model ${modelId}...`
|
|
3173
|
+
);
|
|
3004
3174
|
await dato.updateRecord(record.id, record);
|
|
3005
3175
|
}
|
|
3006
3176
|
}
|
|
@@ -3039,7 +3209,9 @@ async function promptFieldSelection(modelName, choices) {
|
|
|
3039
3209
|
}
|
|
3040
3210
|
async function updateFieldLocalization(dato, fieldInfo, shouldBeLocalized) {
|
|
3041
3211
|
if (shouldBeLocalized !== fieldInfo.localized) {
|
|
3042
|
-
console.log(
|
|
3212
|
+
console.log(
|
|
3213
|
+
`${shouldBeLocalized ? "Enabling" : "Disabling"} localization for ${fieldInfo.label}...`
|
|
3214
|
+
);
|
|
3043
3215
|
await dato.updateField(fieldInfo.id, { localized: shouldBeLocalized });
|
|
3044
3216
|
}
|
|
3045
3217
|
return shouldBeLocalized;
|
|
@@ -3112,9 +3284,21 @@ function createDatoExtractLoader() {
|
|
|
3112
3284
|
for (const [virtualRecordId, record] of _18.entries(modelInfo)) {
|
|
3113
3285
|
for (const [fieldName, fieldValue] of _18.entries(record)) {
|
|
3114
3286
|
const [, recordId] = virtualRecordId.split("_");
|
|
3115
|
-
const originalFieldValue = _18.get(originalInput, [
|
|
3116
|
-
|
|
3117
|
-
|
|
3287
|
+
const originalFieldValue = _18.get(originalInput, [
|
|
3288
|
+
modelId,
|
|
3289
|
+
recordId,
|
|
3290
|
+
fieldName
|
|
3291
|
+
]);
|
|
3292
|
+
const rawValue = createRawDatoValue(
|
|
3293
|
+
fieldValue,
|
|
3294
|
+
originalFieldValue,
|
|
3295
|
+
true
|
|
3296
|
+
);
|
|
3297
|
+
_18.set(
|
|
3298
|
+
result,
|
|
3299
|
+
[modelId, recordId, fieldName],
|
|
3300
|
+
rawValue || originalFieldValue
|
|
3301
|
+
);
|
|
3118
3302
|
}
|
|
3119
3303
|
}
|
|
3120
3304
|
}
|
|
@@ -3184,7 +3368,11 @@ function createRawDatoValue(parsedDatoValue, originalRawDatoValue, isClean = fal
|
|
|
3184
3368
|
case "single_block":
|
|
3185
3369
|
return deserializeBlock(parsedDatoValue, originalRawDatoValue, isClean);
|
|
3186
3370
|
case "rich_text":
|
|
3187
|
-
return deserializeBlockList(
|
|
3371
|
+
return deserializeBlockList(
|
|
3372
|
+
parsedDatoValue,
|
|
3373
|
+
originalRawDatoValue,
|
|
3374
|
+
isClean
|
|
3375
|
+
);
|
|
3188
3376
|
case "json":
|
|
3189
3377
|
return JSON.stringify(parsedDatoValue, null, 2);
|
|
3190
3378
|
case "video":
|
|
@@ -3201,7 +3389,11 @@ function serializeStructuredText(rawStructuredText) {
|
|
|
3201
3389
|
return serializeStructuredTextNode(rawStructuredText);
|
|
3202
3390
|
function serializeStructuredTextNode(node, path17 = [], acc = {}) {
|
|
3203
3391
|
if ("document" in node) {
|
|
3204
|
-
return serializeStructuredTextNode(
|
|
3392
|
+
return serializeStructuredTextNode(
|
|
3393
|
+
node.document,
|
|
3394
|
+
[...path17, "document"],
|
|
3395
|
+
acc
|
|
3396
|
+
);
|
|
3205
3397
|
}
|
|
3206
3398
|
if (!_18.isNil(node.value)) {
|
|
3207
3399
|
acc[[...path17, "value"].join(".")] = node.value;
|
|
@@ -3210,7 +3402,11 @@ function serializeStructuredText(rawStructuredText) {
|
|
|
3210
3402
|
}
|
|
3211
3403
|
if (node.children) {
|
|
3212
3404
|
for (let i = 0; i < node.children.length; i++) {
|
|
3213
|
-
serializeStructuredTextNode(
|
|
3405
|
+
serializeStructuredTextNode(
|
|
3406
|
+
node.children[i],
|
|
3407
|
+
[...path17, i.toString()],
|
|
3408
|
+
acc
|
|
3409
|
+
);
|
|
3214
3410
|
}
|
|
3215
3411
|
}
|
|
3216
3412
|
return acc;
|
|
@@ -3253,7 +3449,11 @@ function deserializeVideo(parsedVideo, originalRawVideo) {
|
|
|
3253
3449
|
function deserializeBlock(payload, rawNode, isClean = false) {
|
|
3254
3450
|
const result = _18.cloneDeep(rawNode);
|
|
3255
3451
|
for (const [attributeName, attributeValue] of _18.entries(rawNode.attributes)) {
|
|
3256
|
-
const rawValue = createRawDatoValue(
|
|
3452
|
+
const rawValue = createRawDatoValue(
|
|
3453
|
+
payload[attributeName],
|
|
3454
|
+
attributeValue,
|
|
3455
|
+
isClean
|
|
3456
|
+
);
|
|
3257
3457
|
_18.set(result, ["attributes", attributeName], rawValue);
|
|
3258
3458
|
}
|
|
3259
3459
|
if (isClean) {
|
|
@@ -3265,13 +3465,19 @@ function deserializeSeo(parsedSeo, originalRawSeo) {
|
|
|
3265
3465
|
return _18.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
|
|
3266
3466
|
}
|
|
3267
3467
|
function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = false) {
|
|
3268
|
-
return _18.chain(parsedBlockList).map(
|
|
3468
|
+
return _18.chain(parsedBlockList).map(
|
|
3469
|
+
(block, i) => deserializeBlock(block, originalRawBlockList[i], isClean)
|
|
3470
|
+
).value();
|
|
3269
3471
|
}
|
|
3270
3472
|
function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
|
|
3271
3473
|
const result = _18.cloneDeep(originalRawStructuredText);
|
|
3272
3474
|
for (const [path17, value] of _18.entries(parsedStructuredText)) {
|
|
3273
3475
|
const realPath = _18.chain(path17.split(".")).flatMap((s) => !_18.isNaN(_18.toNumber(s)) ? ["children", s] : s).value();
|
|
3274
|
-
const deserializedValue = createRawDatoValue(
|
|
3476
|
+
const deserializedValue = createRawDatoValue(
|
|
3477
|
+
value,
|
|
3478
|
+
_18.get(originalRawStructuredText, realPath),
|
|
3479
|
+
true
|
|
3480
|
+
);
|
|
3275
3481
|
_18.set(result, realPath, deserializedValue);
|
|
3276
3482
|
}
|
|
3277
3483
|
return result;
|
|
@@ -3284,13 +3490,21 @@ function _isJson(rawDatoValue) {
|
|
|
3284
3490
|
}
|
|
3285
3491
|
}
|
|
3286
3492
|
function _isFile(rawDatoValue) {
|
|
3287
|
-
return _18.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every(
|
|
3288
|
-
}
|
|
3289
|
-
function _isVideo(rawDatoValue) {
|
|
3290
|
-
return _18.isObject(rawDatoValue) && ["url", "title", "width", "height", "provider", "provider_uid", "thumbnail_url"].every(
|
|
3493
|
+
return _18.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every(
|
|
3291
3494
|
(key) => _18.has(rawDatoValue, key)
|
|
3292
3495
|
);
|
|
3293
3496
|
}
|
|
3497
|
+
function _isVideo(rawDatoValue) {
|
|
3498
|
+
return _18.isObject(rawDatoValue) && [
|
|
3499
|
+
"url",
|
|
3500
|
+
"title",
|
|
3501
|
+
"width",
|
|
3502
|
+
"height",
|
|
3503
|
+
"provider",
|
|
3504
|
+
"provider_uid",
|
|
3505
|
+
"thumbnail_url"
|
|
3506
|
+
].every((key) => _18.has(rawDatoValue, key));
|
|
3507
|
+
}
|
|
3294
3508
|
|
|
3295
3509
|
// src/cli/loaders/dato/index.ts
|
|
3296
3510
|
function createDatoLoader(configFilePath) {
|
|
@@ -3300,13 +3514,20 @@ function createDatoLoader(configFilePath) {
|
|
|
3300
3514
|
return composeLoaders(
|
|
3301
3515
|
createDatoApiLoader(
|
|
3302
3516
|
datoConfig,
|
|
3303
|
-
(updatedConfig) => fs9.writeFileSync(
|
|
3517
|
+
(updatedConfig) => fs9.writeFileSync(
|
|
3518
|
+
configFilePath,
|
|
3519
|
+
JSON5.stringify(updatedConfig, null, 2)
|
|
3520
|
+
)
|
|
3304
3521
|
),
|
|
3305
3522
|
createDatoFilterLoader(),
|
|
3306
3523
|
createDatoExtractLoader()
|
|
3307
3524
|
);
|
|
3308
3525
|
} catch (error) {
|
|
3309
|
-
throw new Error(
|
|
3526
|
+
throw new Error(
|
|
3527
|
+
[`Failed to parse DatoCMS config file.`, `Error: ${error.message}`].join(
|
|
3528
|
+
"\n\n"
|
|
3529
|
+
)
|
|
3530
|
+
);
|
|
3310
3531
|
}
|
|
3311
3532
|
}
|
|
3312
3533
|
|
|
@@ -3455,7 +3676,9 @@ function formatPlutilStyle(jsonData, existingJson) {
|
|
|
3455
3676
|
}
|
|
3456
3677
|
if (Array.isArray(data)) {
|
|
3457
3678
|
if (data.length === 0) return "[]";
|
|
3458
|
-
const items2 = data.map(
|
|
3679
|
+
const items2 = data.map(
|
|
3680
|
+
(item) => `${nextIndent}${format(item, level + 1)}`
|
|
3681
|
+
);
|
|
3459
3682
|
return `[
|
|
3460
3683
|
${items2.join(",\n")}
|
|
3461
3684
|
${currentIndent}]`;
|
|
@@ -3475,7 +3698,10 @@ ${currentIndent}}`;
|
|
|
3475
3698
|
});
|
|
3476
3699
|
const items = sortedKeys.map((key) => {
|
|
3477
3700
|
const value = data[key];
|
|
3478
|
-
return `${nextIndent}${JSON.stringify(key)} : ${format(
|
|
3701
|
+
return `${nextIndent}${JSON.stringify(key)} : ${format(
|
|
3702
|
+
value,
|
|
3703
|
+
level + 1
|
|
3704
|
+
)}`;
|
|
3479
3705
|
});
|
|
3480
3706
|
return `{
|
|
3481
3707
|
${items.join(",\n")}
|
|
@@ -3548,11 +3774,23 @@ function toPhpArray(data, shortSyntax = true, indentLevel = 1) {
|
|
|
3548
3774
|
const arrayEnd = shortSyntax ? "]" : ")";
|
|
3549
3775
|
if (Array.isArray(data)) {
|
|
3550
3776
|
return `${arrayStart}
|
|
3551
|
-
${data.map(
|
|
3777
|
+
${data.map(
|
|
3778
|
+
(value) => `${indent(indentLevel)}${toPhpArray(
|
|
3779
|
+
value,
|
|
3780
|
+
shortSyntax,
|
|
3781
|
+
indentLevel + 1
|
|
3782
|
+
)}`
|
|
3783
|
+
).join(",\n")}
|
|
3552
3784
|
${indent(indentLevel - 1)}${arrayEnd}`;
|
|
3553
3785
|
}
|
|
3554
3786
|
const output = `${arrayStart}
|
|
3555
|
-
${Object.entries(data).map(
|
|
3787
|
+
${Object.entries(data).map(
|
|
3788
|
+
([key, value]) => `${indent(indentLevel)}'${key}' => ${toPhpArray(
|
|
3789
|
+
value,
|
|
3790
|
+
shortSyntax,
|
|
3791
|
+
indentLevel + 1
|
|
3792
|
+
)}`
|
|
3793
|
+
).join(",\n")}
|
|
3556
3794
|
${indent(indentLevel - 1)}${arrayEnd}`;
|
|
3557
3795
|
return output;
|
|
3558
3796
|
}
|
|
@@ -3578,7 +3816,11 @@ function createVueJsonLoader() {
|
|
|
3578
3816
|
}
|
|
3579
3817
|
parsed.i18n[locale] = data;
|
|
3580
3818
|
return `${parsed.before}<i18n>
|
|
3581
|
-
${JSON.stringify(
|
|
3819
|
+
${JSON.stringify(
|
|
3820
|
+
parsed.i18n,
|
|
3821
|
+
null,
|
|
3822
|
+
2
|
|
3823
|
+
)}
|
|
3582
3824
|
</i18n>${parsed.after}`;
|
|
3583
3825
|
}
|
|
3584
3826
|
});
|
|
@@ -3844,42 +4086,48 @@ function createInjectLocaleLoader(injectLocaleKeys) {
|
|
|
3844
4086
|
if (!injectLocaleKeys) {
|
|
3845
4087
|
return data;
|
|
3846
4088
|
}
|
|
3847
|
-
const omitKeys =
|
|
3848
|
-
return _22.get(data, key) === locale;
|
|
3849
|
-
});
|
|
4089
|
+
const omitKeys = _getKeysWithLocales(data, injectLocaleKeys, locale);
|
|
3850
4090
|
const result = _22.omit(data, omitKeys);
|
|
3851
4091
|
return result;
|
|
3852
4092
|
},
|
|
3853
4093
|
async push(locale, data, originalInput, originalLocale) {
|
|
3854
|
-
if (!injectLocaleKeys) {
|
|
4094
|
+
if (!injectLocaleKeys || !originalInput) {
|
|
3855
4095
|
return data;
|
|
3856
4096
|
}
|
|
3857
|
-
const
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
4097
|
+
const localeKeys = _getKeysWithLocales(
|
|
4098
|
+
originalInput,
|
|
4099
|
+
injectLocaleKeys,
|
|
4100
|
+
originalLocale
|
|
4101
|
+
);
|
|
4102
|
+
localeKeys.forEach((key) => {
|
|
4103
|
+
_22.set(data, key, locale);
|
|
3862
4104
|
});
|
|
3863
|
-
return
|
|
4105
|
+
return data;
|
|
3864
4106
|
}
|
|
3865
4107
|
});
|
|
3866
4108
|
}
|
|
4109
|
+
function _getKeysWithLocales(data, injectLocaleKeys, locale) {
|
|
4110
|
+
return injectLocaleKeys.filter((key) => {
|
|
4111
|
+
return _22.get(data, key) === locale;
|
|
4112
|
+
});
|
|
4113
|
+
}
|
|
3867
4114
|
|
|
3868
4115
|
// src/cli/loaders/locked-keys.ts
|
|
3869
4116
|
import _23 from "lodash";
|
|
3870
|
-
function createLockedKeysLoader(lockedKeys
|
|
4117
|
+
function createLockedKeysLoader(lockedKeys) {
|
|
3871
4118
|
return createLoader({
|
|
3872
|
-
pull: async (locale, data) =>
|
|
4119
|
+
pull: async (locale, data) => {
|
|
4120
|
+
return _23.pickBy(data, (value, key) => !_isLockedKey(key, lockedKeys));
|
|
4121
|
+
},
|
|
3873
4122
|
push: async (locale, data, originalInput) => {
|
|
3874
|
-
const lockedSubObject = _23.chain(originalInput).pickBy((value, key) =>
|
|
3875
|
-
|
|
3876
|
-
return _23.merge({}, data, lockedSubObject);
|
|
3877
|
-
} else {
|
|
3878
|
-
return _23.merge({}, originalInput, data, lockedSubObject);
|
|
3879
|
-
}
|
|
4123
|
+
const lockedSubObject = _23.chain(originalInput).pickBy((value, key) => _isLockedKey(key, lockedKeys)).value();
|
|
4124
|
+
return _23.merge({}, data, lockedSubObject);
|
|
3880
4125
|
}
|
|
3881
4126
|
});
|
|
3882
4127
|
}
|
|
4128
|
+
function _isLockedKey(key, lockedKeys) {
|
|
4129
|
+
return lockedKeys.some((lockedKey) => key.startsWith(lockedKey));
|
|
4130
|
+
}
|
|
3883
4131
|
|
|
3884
4132
|
// src/cli/loaders/mdx2/frontmatter-split.ts
|
|
3885
4133
|
import matter2 from "gray-matter";
|
|
@@ -4109,9 +4357,14 @@ function createMdxLockedPatternsLoader(defaultPatterns) {
|
|
|
4109
4357
|
if (!pullInput) {
|
|
4110
4358
|
return data;
|
|
4111
4359
|
}
|
|
4112
|
-
const { lockedPlaceholders } = extractLockedPatterns(
|
|
4360
|
+
const { lockedPlaceholders } = extractLockedPatterns(
|
|
4361
|
+
pullInput,
|
|
4362
|
+
patterns
|
|
4363
|
+
);
|
|
4113
4364
|
let result = data;
|
|
4114
|
-
for (const [placeholder, original] of Object.entries(
|
|
4365
|
+
for (const [placeholder, original] of Object.entries(
|
|
4366
|
+
lockedPlaceholders
|
|
4367
|
+
)) {
|
|
4115
4368
|
result = result.replaceAll(placeholder, original);
|
|
4116
4369
|
}
|
|
4117
4370
|
return result;
|
|
@@ -4205,7 +4458,10 @@ function parseEjsForTranslation(input2) {
|
|
|
4205
4458
|
if (trimmedContent) {
|
|
4206
4459
|
const key = `text_${counter++}`;
|
|
4207
4460
|
translatable[key] = trimmedContent;
|
|
4208
|
-
template += textPart.content.replace(
|
|
4461
|
+
template += textPart.content.replace(
|
|
4462
|
+
trimmedContent,
|
|
4463
|
+
`__LINGO_PLACEHOLDER_${key}__`
|
|
4464
|
+
);
|
|
4209
4465
|
} else {
|
|
4210
4466
|
template += textPart.content;
|
|
4211
4467
|
}
|
|
@@ -4235,7 +4491,9 @@ function createEjsLoader() {
|
|
|
4235
4491
|
const parseResult = parseEjsForTranslation(input2);
|
|
4236
4492
|
return parseResult.translatable;
|
|
4237
4493
|
} catch (error) {
|
|
4238
|
-
console.warn(
|
|
4494
|
+
console.warn(
|
|
4495
|
+
"Warning: Could not parse EJS template, treating as plain text"
|
|
4496
|
+
);
|
|
4239
4497
|
return { content: input2.trim() };
|
|
4240
4498
|
}
|
|
4241
4499
|
},
|
|
@@ -4246,15 +4504,51 @@ function createEjsLoader() {
|
|
|
4246
4504
|
try {
|
|
4247
4505
|
const parseResult = parseEjsForTranslation(originalInput);
|
|
4248
4506
|
const mergedTranslatable = { ...parseResult.translatable, ...data };
|
|
4249
|
-
return reconstructEjsWithTranslation(
|
|
4507
|
+
return reconstructEjsWithTranslation(
|
|
4508
|
+
parseResult.content,
|
|
4509
|
+
mergedTranslatable
|
|
4510
|
+
);
|
|
4250
4511
|
} catch (error) {
|
|
4251
|
-
console.warn(
|
|
4512
|
+
console.warn(
|
|
4513
|
+
"Warning: Could not reconstruct EJS template, returning translated data"
|
|
4514
|
+
);
|
|
4252
4515
|
return Object.values(data).join("\n");
|
|
4253
4516
|
}
|
|
4254
4517
|
}
|
|
4255
4518
|
});
|
|
4256
4519
|
}
|
|
4257
4520
|
|
|
4521
|
+
// src/cli/loaders/ensure-key-order.ts
|
|
4522
|
+
import _27 from "lodash";
|
|
4523
|
+
function createEnsureKeyOrderLoader() {
|
|
4524
|
+
return createLoader({
|
|
4525
|
+
pull: async (_locale, input2) => {
|
|
4526
|
+
return input2;
|
|
4527
|
+
},
|
|
4528
|
+
push: async (_locale, data, originalInput) => {
|
|
4529
|
+
if (!originalInput || !data) {
|
|
4530
|
+
return data;
|
|
4531
|
+
}
|
|
4532
|
+
return reorderKeys(data, originalInput);
|
|
4533
|
+
}
|
|
4534
|
+
});
|
|
4535
|
+
}
|
|
4536
|
+
function reorderKeys(data, originalInput) {
|
|
4537
|
+
if (!_27.isObject(data) || _27.isArray(data) || _27.isDate(data)) {
|
|
4538
|
+
return data;
|
|
4539
|
+
}
|
|
4540
|
+
const orderedData = {};
|
|
4541
|
+
const originalKeys = Object.keys(originalInput);
|
|
4542
|
+
const dataKeys = new Set(Object.keys(data));
|
|
4543
|
+
for (const key of originalKeys) {
|
|
4544
|
+
if (dataKeys.has(key)) {
|
|
4545
|
+
orderedData[key] = reorderKeys(data[key], originalInput[key]);
|
|
4546
|
+
dataKeys.delete(key);
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
return orderedData;
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4258
4552
|
// src/cli/loaders/index.ts
|
|
4259
4553
|
function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys, lockedPatterns, ignoredKeys) {
|
|
4260
4554
|
switch (bucketType) {
|
|
@@ -4264,23 +4558,19 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4264
4558
|
return composeLoaders(
|
|
4265
4559
|
createTextFileLoader(bucketPathPattern),
|
|
4266
4560
|
createAndroidLoader(),
|
|
4561
|
+
createEnsureKeyOrderLoader(),
|
|
4267
4562
|
createFlatLoader(),
|
|
4268
4563
|
createSyncLoader(),
|
|
4269
|
-
createUnlocalizableLoader(
|
|
4270
|
-
options.isCacheRestore,
|
|
4271
|
-
options.returnUnlocalizedKeys
|
|
4272
|
-
)
|
|
4564
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4273
4565
|
);
|
|
4274
4566
|
case "csv":
|
|
4275
4567
|
return composeLoaders(
|
|
4276
4568
|
createTextFileLoader(bucketPathPattern),
|
|
4277
4569
|
createCsvLoader(),
|
|
4570
|
+
createEnsureKeyOrderLoader(),
|
|
4278
4571
|
createFlatLoader(),
|
|
4279
4572
|
createSyncLoader(),
|
|
4280
|
-
createUnlocalizableLoader(
|
|
4281
|
-
options.isCacheRestore,
|
|
4282
|
-
options.returnUnlocalizedKeys
|
|
4283
|
-
)
|
|
4573
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4284
4574
|
);
|
|
4285
4575
|
case "html":
|
|
4286
4576
|
return composeLoaders(
|
|
@@ -4288,34 +4578,26 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4288
4578
|
createPrettierLoader({ parser: "html", bucketPathPattern }),
|
|
4289
4579
|
createHtmlLoader(),
|
|
4290
4580
|
createSyncLoader(),
|
|
4291
|
-
createUnlocalizableLoader(
|
|
4292
|
-
options.isCacheRestore,
|
|
4293
|
-
options.returnUnlocalizedKeys
|
|
4294
|
-
)
|
|
4581
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4295
4582
|
);
|
|
4296
4583
|
case "ejs":
|
|
4297
4584
|
return composeLoaders(
|
|
4298
4585
|
createTextFileLoader(bucketPathPattern),
|
|
4299
4586
|
createEjsLoader(),
|
|
4300
4587
|
createSyncLoader(),
|
|
4301
|
-
createUnlocalizableLoader(
|
|
4302
|
-
options.isCacheRestore,
|
|
4303
|
-
options.returnUnlocalizedKeys
|
|
4304
|
-
)
|
|
4588
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4305
4589
|
);
|
|
4306
4590
|
case "json":
|
|
4307
4591
|
return composeLoaders(
|
|
4308
4592
|
createTextFileLoader(bucketPathPattern),
|
|
4309
4593
|
createPrettierLoader({ parser: "json", bucketPathPattern }),
|
|
4310
4594
|
createJsonLoader(),
|
|
4595
|
+
createEnsureKeyOrderLoader(),
|
|
4311
4596
|
createInjectLocaleLoader(options.injectLocale),
|
|
4312
4597
|
createFlatLoader(),
|
|
4313
|
-
createLockedKeysLoader(lockedKeys || []
|
|
4598
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4314
4599
|
createSyncLoader(),
|
|
4315
|
-
createUnlocalizableLoader(
|
|
4316
|
-
options.isCacheRestore,
|
|
4317
|
-
options.returnUnlocalizedKeys
|
|
4318
|
-
)
|
|
4600
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4319
4601
|
);
|
|
4320
4602
|
case "markdown":
|
|
4321
4603
|
return composeLoaders(
|
|
@@ -4323,10 +4605,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4323
4605
|
createPrettierLoader({ parser: "markdown", bucketPathPattern }),
|
|
4324
4606
|
createMarkdownLoader(),
|
|
4325
4607
|
createSyncLoader(),
|
|
4326
|
-
createUnlocalizableLoader(
|
|
4327
|
-
options.isCacheRestore,
|
|
4328
|
-
options.returnUnlocalizedKeys
|
|
4329
|
-
)
|
|
4608
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4330
4609
|
);
|
|
4331
4610
|
case "mdx":
|
|
4332
4611
|
return composeLoaders(
|
|
@@ -4341,55 +4620,43 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4341
4620
|
createMdxSectionsSplit2Loader(),
|
|
4342
4621
|
createLocalizableMdxDocumentLoader(),
|
|
4343
4622
|
createFlatLoader(),
|
|
4344
|
-
|
|
4623
|
+
createEnsureKeyOrderLoader(),
|
|
4624
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4345
4625
|
createSyncLoader(),
|
|
4346
|
-
createUnlocalizableLoader(
|
|
4347
|
-
options.isCacheRestore,
|
|
4348
|
-
options.returnUnlocalizedKeys
|
|
4349
|
-
)
|
|
4626
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4350
4627
|
);
|
|
4351
4628
|
case "po":
|
|
4352
4629
|
return composeLoaders(
|
|
4353
4630
|
createTextFileLoader(bucketPathPattern),
|
|
4354
4631
|
createPoLoader(),
|
|
4355
4632
|
createFlatLoader(),
|
|
4633
|
+
createEnsureKeyOrderLoader(),
|
|
4356
4634
|
createSyncLoader(),
|
|
4357
4635
|
createVariableLoader({ type: "python" }),
|
|
4358
|
-
createUnlocalizableLoader(
|
|
4359
|
-
options.isCacheRestore,
|
|
4360
|
-
options.returnUnlocalizedKeys
|
|
4361
|
-
)
|
|
4636
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4362
4637
|
);
|
|
4363
4638
|
case "properties":
|
|
4364
4639
|
return composeLoaders(
|
|
4365
4640
|
createTextFileLoader(bucketPathPattern),
|
|
4366
4641
|
createPropertiesLoader(),
|
|
4367
4642
|
createSyncLoader(),
|
|
4368
|
-
createUnlocalizableLoader(
|
|
4369
|
-
options.isCacheRestore,
|
|
4370
|
-
options.returnUnlocalizedKeys
|
|
4371
|
-
)
|
|
4643
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4372
4644
|
);
|
|
4373
4645
|
case "xcode-strings":
|
|
4374
4646
|
return composeLoaders(
|
|
4375
4647
|
createTextFileLoader(bucketPathPattern),
|
|
4376
4648
|
createXcodeStringsLoader(),
|
|
4377
4649
|
createSyncLoader(),
|
|
4378
|
-
createUnlocalizableLoader(
|
|
4379
|
-
options.isCacheRestore,
|
|
4380
|
-
options.returnUnlocalizedKeys
|
|
4381
|
-
)
|
|
4650
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4382
4651
|
);
|
|
4383
4652
|
case "xcode-stringsdict":
|
|
4384
4653
|
return composeLoaders(
|
|
4385
4654
|
createTextFileLoader(bucketPathPattern),
|
|
4386
4655
|
createXcodeStringsdictLoader(),
|
|
4387
4656
|
createFlatLoader(),
|
|
4657
|
+
createEnsureKeyOrderLoader(),
|
|
4388
4658
|
createSyncLoader(),
|
|
4389
|
-
createUnlocalizableLoader(
|
|
4390
|
-
options.isCacheRestore,
|
|
4391
|
-
options.returnUnlocalizedKeys
|
|
4392
|
-
)
|
|
4659
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4393
4660
|
);
|
|
4394
4661
|
case "xcode-xcstrings":
|
|
4395
4662
|
return composeLoaders(
|
|
@@ -4398,12 +4665,10 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4398
4665
|
createJsonLoader(),
|
|
4399
4666
|
createXcodeXcstringsLoader(options.defaultLocale),
|
|
4400
4667
|
createFlatLoader(),
|
|
4668
|
+
createEnsureKeyOrderLoader(),
|
|
4401
4669
|
createSyncLoader(),
|
|
4402
4670
|
createVariableLoader({ type: "ieee" }),
|
|
4403
|
-
createUnlocalizableLoader(
|
|
4404
|
-
options.isCacheRestore,
|
|
4405
|
-
options.returnUnlocalizedKeys
|
|
4406
|
-
)
|
|
4671
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4407
4672
|
);
|
|
4408
4673
|
case "yaml":
|
|
4409
4674
|
return composeLoaders(
|
|
@@ -4411,12 +4676,10 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4411
4676
|
createPrettierLoader({ parser: "yaml", bucketPathPattern }),
|
|
4412
4677
|
createYamlLoader(),
|
|
4413
4678
|
createFlatLoader(),
|
|
4414
|
-
|
|
4679
|
+
createEnsureKeyOrderLoader(),
|
|
4680
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4415
4681
|
createSyncLoader(),
|
|
4416
|
-
createUnlocalizableLoader(
|
|
4417
|
-
options.isCacheRestore,
|
|
4418
|
-
options.returnUnlocalizedKeys
|
|
4419
|
-
)
|
|
4682
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4420
4683
|
);
|
|
4421
4684
|
case "yaml-root-key":
|
|
4422
4685
|
return composeLoaders(
|
|
@@ -4425,76 +4688,60 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4425
4688
|
createYamlLoader(),
|
|
4426
4689
|
createRootKeyLoader(true),
|
|
4427
4690
|
createFlatLoader(),
|
|
4691
|
+
createEnsureKeyOrderLoader(),
|
|
4428
4692
|
createSyncLoader(),
|
|
4429
|
-
createUnlocalizableLoader(
|
|
4430
|
-
options.isCacheRestore,
|
|
4431
|
-
options.returnUnlocalizedKeys
|
|
4432
|
-
)
|
|
4693
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4433
4694
|
);
|
|
4434
4695
|
case "flutter":
|
|
4435
4696
|
return composeLoaders(
|
|
4436
4697
|
createTextFileLoader(bucketPathPattern),
|
|
4437
4698
|
createPrettierLoader({ parser: "json", bucketPathPattern }),
|
|
4438
4699
|
createJsonLoader(),
|
|
4700
|
+
createEnsureKeyOrderLoader(),
|
|
4439
4701
|
createFlutterLoader(),
|
|
4440
4702
|
createFlatLoader(),
|
|
4441
4703
|
createSyncLoader(),
|
|
4442
|
-
createUnlocalizableLoader(
|
|
4443
|
-
options.isCacheRestore,
|
|
4444
|
-
options.returnUnlocalizedKeys
|
|
4445
|
-
)
|
|
4704
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4446
4705
|
);
|
|
4447
4706
|
case "xliff":
|
|
4448
4707
|
return composeLoaders(
|
|
4449
4708
|
createTextFileLoader(bucketPathPattern),
|
|
4450
4709
|
createXliffLoader(),
|
|
4451
4710
|
createFlatLoader(),
|
|
4711
|
+
createEnsureKeyOrderLoader(),
|
|
4452
4712
|
createSyncLoader(),
|
|
4453
|
-
createUnlocalizableLoader(
|
|
4454
|
-
options.isCacheRestore,
|
|
4455
|
-
options.returnUnlocalizedKeys
|
|
4456
|
-
)
|
|
4713
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4457
4714
|
);
|
|
4458
4715
|
case "xml":
|
|
4459
4716
|
return composeLoaders(
|
|
4460
4717
|
createTextFileLoader(bucketPathPattern),
|
|
4461
4718
|
createXmlLoader(),
|
|
4462
4719
|
createFlatLoader(),
|
|
4720
|
+
createEnsureKeyOrderLoader(),
|
|
4463
4721
|
createSyncLoader(),
|
|
4464
|
-
createUnlocalizableLoader(
|
|
4465
|
-
options.isCacheRestore,
|
|
4466
|
-
options.returnUnlocalizedKeys
|
|
4467
|
-
)
|
|
4722
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4468
4723
|
);
|
|
4469
4724
|
case "srt":
|
|
4470
4725
|
return composeLoaders(
|
|
4471
4726
|
createTextFileLoader(bucketPathPattern),
|
|
4472
4727
|
createSrtLoader(),
|
|
4473
4728
|
createSyncLoader(),
|
|
4474
|
-
createUnlocalizableLoader(
|
|
4475
|
-
options.isCacheRestore,
|
|
4476
|
-
options.returnUnlocalizedKeys
|
|
4477
|
-
)
|
|
4729
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4478
4730
|
);
|
|
4479
4731
|
case "dato":
|
|
4480
4732
|
return composeLoaders(
|
|
4481
4733
|
createDatoLoader(bucketPathPattern),
|
|
4482
4734
|
createSyncLoader(),
|
|
4483
4735
|
createFlatLoader(),
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
options.returnUnlocalizedKeys
|
|
4487
|
-
)
|
|
4736
|
+
createEnsureKeyOrderLoader(),
|
|
4737
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4488
4738
|
);
|
|
4489
4739
|
case "vtt":
|
|
4490
4740
|
return composeLoaders(
|
|
4491
4741
|
createTextFileLoader(bucketPathPattern),
|
|
4492
4742
|
createVttLoader(),
|
|
4493
4743
|
createSyncLoader(),
|
|
4494
|
-
createUnlocalizableLoader(
|
|
4495
|
-
options.isCacheRestore,
|
|
4496
|
-
options.returnUnlocalizedKeys
|
|
4497
|
-
)
|
|
4744
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4498
4745
|
);
|
|
4499
4746
|
case "php":
|
|
4500
4747
|
return composeLoaders(
|
|
@@ -4502,10 +4749,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4502
4749
|
createPhpLoader(),
|
|
4503
4750
|
createSyncLoader(),
|
|
4504
4751
|
createFlatLoader(),
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
options.returnUnlocalizedKeys
|
|
4508
|
-
)
|
|
4752
|
+
createEnsureKeyOrderLoader(),
|
|
4753
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4509
4754
|
);
|
|
4510
4755
|
case "vue-json":
|
|
4511
4756
|
return composeLoaders(
|
|
@@ -4513,10 +4758,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4513
4758
|
createVueJsonLoader(),
|
|
4514
4759
|
createSyncLoader(),
|
|
4515
4760
|
createFlatLoader(),
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
options.returnUnlocalizedKeys
|
|
4519
|
-
)
|
|
4761
|
+
createEnsureKeyOrderLoader(),
|
|
4762
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4520
4763
|
);
|
|
4521
4764
|
case "typescript":
|
|
4522
4765
|
return composeLoaders(
|
|
@@ -4524,13 +4767,11 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4524
4767
|
createPrettierLoader({ parser: "typescript", bucketPathPattern }),
|
|
4525
4768
|
createTypescriptLoader(),
|
|
4526
4769
|
createFlatLoader(),
|
|
4770
|
+
createEnsureKeyOrderLoader(),
|
|
4527
4771
|
createSyncLoader(),
|
|
4528
|
-
createLockedKeysLoader(lockedKeys || []
|
|
4772
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4529
4773
|
createIgnoredKeysLoader(ignoredKeys || []),
|
|
4530
|
-
createUnlocalizableLoader(
|
|
4531
|
-
options.isCacheRestore,
|
|
4532
|
-
options.returnUnlocalizedKeys
|
|
4533
|
-
)
|
|
4774
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4534
4775
|
);
|
|
4535
4776
|
}
|
|
4536
4777
|
}
|
|
@@ -4574,7 +4815,7 @@ function createLingoLocalizer(params) {
|
|
|
4574
4815
|
|
|
4575
4816
|
// src/cli/processor/basic.ts
|
|
4576
4817
|
import { generateText } from "ai";
|
|
4577
|
-
import
|
|
4818
|
+
import _28 from "lodash";
|
|
4578
4819
|
function createBasicTranslator(model, systemPrompt) {
|
|
4579
4820
|
return async (input2, onProgress) => {
|
|
4580
4821
|
const chunks = extractPayloadChunks(input2.processableData);
|
|
@@ -4588,7 +4829,7 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
4588
4829
|
subResults.push(result2);
|
|
4589
4830
|
onProgress(i / chunks.length * 100, chunk, result2);
|
|
4590
4831
|
}
|
|
4591
|
-
const result =
|
|
4832
|
+
const result = _28.merge({}, ...subResults);
|
|
4592
4833
|
return result;
|
|
4593
4834
|
};
|
|
4594
4835
|
async function doJob(input2) {
|
|
@@ -4679,6 +4920,7 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|
|
4679
4920
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
4680
4921
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
4681
4922
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
4923
|
+
import { createMistral } from "@ai-sdk/mistral";
|
|
4682
4924
|
import { createOllama } from "ollama-ai-provider";
|
|
4683
4925
|
function createProcessor(provider, params) {
|
|
4684
4926
|
if (!provider) {
|
|
@@ -4696,7 +4938,11 @@ function getPureModelProvider(provider) {
|
|
|
4696
4938
|
|
|
4697
4939
|
To fix this issue:
|
|
4698
4940
|
1. ${envVar ? `Set ${chalk5.dim(envVar)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
|
|
4699
|
-
2. Remove the ${chalk5.italic(
|
|
4941
|
+
2. Remove the ${chalk5.italic(
|
|
4942
|
+
"provider"
|
|
4943
|
+
)} node from your i18n.json configuration to switch to ${chalk5.hex(
|
|
4944
|
+
colors.green
|
|
4945
|
+
)("Lingo.dev")}
|
|
4700
4946
|
|
|
4701
4947
|
${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4702
4948
|
`;
|
|
@@ -4705,7 +4951,11 @@ function getPureModelProvider(provider) {
|
|
|
4705
4951
|
|
|
4706
4952
|
To fix this issue:
|
|
4707
4953
|
1. Switch to one of the supported providers, or
|
|
4708
|
-
2. Remove the ${chalk5.italic(
|
|
4954
|
+
2. Remove the ${chalk5.italic(
|
|
4955
|
+
"provider"
|
|
4956
|
+
)} node from your i18n.json configuration to switch to ${chalk5.hex(
|
|
4957
|
+
colors.green
|
|
4958
|
+
)("Lingo.dev")}
|
|
4709
4959
|
|
|
4710
4960
|
${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4711
4961
|
`;
|
|
@@ -4755,6 +5005,17 @@ function getPureModelProvider(provider) {
|
|
|
4755
5005
|
case "ollama": {
|
|
4756
5006
|
return createOllama()(provider.model);
|
|
4757
5007
|
}
|
|
5008
|
+
case "mistral": {
|
|
5009
|
+
if (!process.env.MISTRAL_API_KEY) {
|
|
5010
|
+
throw new Error(
|
|
5011
|
+
createMissingKeyErrorMessage("Mistral", "MISTRAL_API_KEY")
|
|
5012
|
+
);
|
|
5013
|
+
}
|
|
5014
|
+
return createMistral({
|
|
5015
|
+
apiKey: process.env.MISTRAL_API_KEY,
|
|
5016
|
+
baseURL: provider.baseUrl
|
|
5017
|
+
})(provider.model);
|
|
5018
|
+
}
|
|
4758
5019
|
default: {
|
|
4759
5020
|
throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
|
|
4760
5021
|
}
|
|
@@ -4815,7 +5076,7 @@ async function trackEvent(distinctId, event, properties) {
|
|
|
4815
5076
|
}
|
|
4816
5077
|
|
|
4817
5078
|
// src/cli/utils/delta.ts
|
|
4818
|
-
import
|
|
5079
|
+
import _29 from "lodash";
|
|
4819
5080
|
import z from "zod";
|
|
4820
5081
|
|
|
4821
5082
|
// src/cli/utils/fs.ts
|
|
@@ -4864,11 +5125,17 @@ function createDeltaProcessor(fileKey) {
|
|
|
4864
5125
|
return checkIfFileExists(lockfilePath);
|
|
4865
5126
|
},
|
|
4866
5127
|
async calculateDelta(params) {
|
|
4867
|
-
let added =
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
5128
|
+
let added = _29.difference(
|
|
5129
|
+
Object.keys(params.sourceData),
|
|
5130
|
+
Object.keys(params.targetData)
|
|
5131
|
+
);
|
|
5132
|
+
let removed = _29.difference(
|
|
5133
|
+
Object.keys(params.targetData),
|
|
5134
|
+
Object.keys(params.sourceData)
|
|
5135
|
+
);
|
|
5136
|
+
const updated = Object.keys(params.sourceData).filter(
|
|
5137
|
+
(key) => md5(params.sourceData[key]) !== params.checksums[key] && params.checksums[key]
|
|
5138
|
+
);
|
|
4872
5139
|
const renamed = [];
|
|
4873
5140
|
for (const addedKey of added) {
|
|
4874
5141
|
const addedHash = md5(params.sourceData[addedKey]);
|
|
@@ -4879,9 +5146,18 @@ function createDeltaProcessor(fileKey) {
|
|
|
4879
5146
|
}
|
|
4880
5147
|
}
|
|
4881
5148
|
}
|
|
4882
|
-
added = added.filter(
|
|
4883
|
-
|
|
4884
|
-
|
|
5149
|
+
added = added.filter(
|
|
5150
|
+
(key) => !renamed.some(([oldKey, newKey]) => newKey === key)
|
|
5151
|
+
);
|
|
5152
|
+
removed = removed.filter(
|
|
5153
|
+
(key) => !renamed.some(([oldKey, newKey]) => oldKey === key)
|
|
5154
|
+
);
|
|
5155
|
+
const hasChanges = [
|
|
5156
|
+
added.length > 0,
|
|
5157
|
+
removed.length > 0,
|
|
5158
|
+
updated.length > 0,
|
|
5159
|
+
renamed.length > 0
|
|
5160
|
+
].some((v) => v);
|
|
4885
5161
|
return {
|
|
4886
5162
|
added,
|
|
4887
5163
|
removed,
|
|
@@ -4915,7 +5191,7 @@ function createDeltaProcessor(fileKey) {
|
|
|
4915
5191
|
await this.saveLock(lockfileData);
|
|
4916
5192
|
},
|
|
4917
5193
|
async createChecksums(sourceData) {
|
|
4918
|
-
const checksums =
|
|
5194
|
+
const checksums = _29.mapValues(sourceData, (value) => md5(value));
|
|
4919
5195
|
return checksums;
|
|
4920
5196
|
}
|
|
4921
5197
|
};
|
|
@@ -5039,7 +5315,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5039
5315
|
bucket.type,
|
|
5040
5316
|
bucketPath.pathPattern,
|
|
5041
5317
|
{
|
|
5042
|
-
isCacheRestore: false,
|
|
5043
5318
|
defaultLocale: sourceLocale,
|
|
5044
5319
|
injectLocale: bucket.injectLocale
|
|
5045
5320
|
},
|
|
@@ -5074,7 +5349,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5074
5349
|
bucket.type,
|
|
5075
5350
|
bucketPath.pathPattern,
|
|
5076
5351
|
{
|
|
5077
|
-
isCacheRestore: false,
|
|
5078
5352
|
defaultLocale: sourceLocale,
|
|
5079
5353
|
returnUnlocalizedKeys: true,
|
|
5080
5354
|
injectLocale: bucket.injectLocale
|
|
@@ -5087,7 +5361,7 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5087
5361
|
const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
|
|
5088
5362
|
const sourceChecksums = await deltaProcessor.createChecksums(sourceData);
|
|
5089
5363
|
const savedChecksums = await deltaProcessor.loadChecksums();
|
|
5090
|
-
const updatedSourceData =
|
|
5364
|
+
const updatedSourceData = _30.pickBy(
|
|
5091
5365
|
sourceData,
|
|
5092
5366
|
(value, key) => sourceChecksums[key] !== savedChecksums[key]
|
|
5093
5367
|
);
|
|
@@ -5101,15 +5375,15 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5101
5375
|
bucketPath.delimiter
|
|
5102
5376
|
);
|
|
5103
5377
|
const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
|
|
5104
|
-
const missingKeys =
|
|
5378
|
+
const missingKeys = _30.difference(
|
|
5105
5379
|
Object.keys(sourceData),
|
|
5106
5380
|
Object.keys(targetData)
|
|
5107
5381
|
);
|
|
5108
|
-
const extraKeys =
|
|
5382
|
+
const extraKeys = _30.difference(
|
|
5109
5383
|
Object.keys(targetData),
|
|
5110
5384
|
Object.keys(sourceData)
|
|
5111
5385
|
);
|
|
5112
|
-
const unlocalizableDataDiff = !
|
|
5386
|
+
const unlocalizableDataDiff = !_30.isEqual(
|
|
5113
5387
|
sourceUnlocalizable,
|
|
5114
5388
|
targetUnlocalizable
|
|
5115
5389
|
);
|
|
@@ -5160,7 +5434,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5160
5434
|
bucket.type,
|
|
5161
5435
|
bucketPath.pathPattern,
|
|
5162
5436
|
{
|
|
5163
|
-
isCacheRestore: false,
|
|
5164
5437
|
defaultLocale: sourceLocale,
|
|
5165
5438
|
injectLocale: bucket.injectLocale
|
|
5166
5439
|
},
|
|
@@ -5191,13 +5464,13 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5191
5464
|
targetData,
|
|
5192
5465
|
checksums: checksums2
|
|
5193
5466
|
});
|
|
5194
|
-
let processableData =
|
|
5467
|
+
let processableData = _30.chain(sourceData).entries().filter(
|
|
5195
5468
|
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!flags.force
|
|
5196
5469
|
).fromPairs().value();
|
|
5197
5470
|
if (flags.key) {
|
|
5198
|
-
processableData =
|
|
5471
|
+
processableData = _30.pickBy(
|
|
5199
5472
|
processableData,
|
|
5200
|
-
(
|
|
5473
|
+
(_34, key) => key === flags.key
|
|
5201
5474
|
);
|
|
5202
5475
|
}
|
|
5203
5476
|
if (flags.verbose) {
|
|
@@ -5230,13 +5503,13 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5230
5503
|
if (flags.verbose) {
|
|
5231
5504
|
bucketOra.info(JSON.stringify(processedTargetData, null, 2));
|
|
5232
5505
|
}
|
|
5233
|
-
let finalTargetData =
|
|
5506
|
+
let finalTargetData = _30.merge(
|
|
5234
5507
|
{},
|
|
5235
5508
|
sourceData,
|
|
5236
5509
|
targetData,
|
|
5237
5510
|
processedTargetData
|
|
5238
5511
|
);
|
|
5239
|
-
finalTargetData =
|
|
5512
|
+
finalTargetData = _30.chain(finalTargetData).entries().map(([key, value]) => {
|
|
5240
5513
|
const renaming = delta.renamed.find(
|
|
5241
5514
|
([oldKey, newKey]) => oldKey === key
|
|
5242
5515
|
);
|
|
@@ -5260,7 +5533,7 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5260
5533
|
`Applying changes to ${bucketPath} (${targetLocale})`
|
|
5261
5534
|
);
|
|
5262
5535
|
}
|
|
5263
|
-
const finalDiffSize =
|
|
5536
|
+
const finalDiffSize = _30.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
|
|
5264
5537
|
await bucketLoader.push(targetLocale, finalTargetData);
|
|
5265
5538
|
if (finalDiffSize > 0 || flags.force) {
|
|
5266
5539
|
bucketOra.succeed(
|
|
@@ -5387,7 +5660,9 @@ async function reviewChanges(args) {
|
|
|
5387
5660
|
if (currentStr === proposedStr && !args.force) {
|
|
5388
5661
|
console.log(
|
|
5389
5662
|
`
|
|
5390
|
-
${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5663
|
+
${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5664
|
+
args.targetLocale
|
|
5665
|
+
)}): ${chalk6.gray("No changes to review")}`
|
|
5391
5666
|
);
|
|
5392
5667
|
return args.proposedData;
|
|
5393
5668
|
}
|
|
@@ -5408,7 +5683,9 @@ ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(args.targetLocale)}): ${chalk6
|
|
|
5408
5683
|
}).join("\n");
|
|
5409
5684
|
console.log(
|
|
5410
5685
|
`
|
|
5411
|
-
Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5686
|
+
Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5687
|
+
args.targetLocale
|
|
5688
|
+
)}):`
|
|
5412
5689
|
);
|
|
5413
5690
|
console.log(coloredDiff);
|
|
5414
5691
|
const { action } = await inquirer2.prompt([
|
|
@@ -5431,7 +5708,7 @@ Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(args.tar
|
|
|
5431
5708
|
return args.currentData;
|
|
5432
5709
|
}
|
|
5433
5710
|
const customData = { ...args.currentData };
|
|
5434
|
-
const changes =
|
|
5711
|
+
const changes = _30.reduce(
|
|
5435
5712
|
args.proposedData,
|
|
5436
5713
|
(result, value, key) => {
|
|
5437
5714
|
if (args.currentData[key] !== value) {
|
|
@@ -5504,7 +5781,7 @@ import path14 from "path";
|
|
|
5504
5781
|
import Z4 from "zod";
|
|
5505
5782
|
import YAML5 from "yaml";
|
|
5506
5783
|
import { MD5 as MD52 } from "object-hash";
|
|
5507
|
-
import
|
|
5784
|
+
import _31 from "lodash";
|
|
5508
5785
|
function createLockfileHelper() {
|
|
5509
5786
|
return {
|
|
5510
5787
|
isLockfileExists: () => {
|
|
@@ -5514,23 +5791,33 @@ function createLockfileHelper() {
|
|
|
5514
5791
|
registerSourceData: (pathPattern, sourceData) => {
|
|
5515
5792
|
const lockfile = _loadLockfile();
|
|
5516
5793
|
const sectionKey = MD52(pathPattern);
|
|
5517
|
-
const sectionChecksums =
|
|
5794
|
+
const sectionChecksums = _31.mapValues(sourceData, (value) => MD52(value));
|
|
5518
5795
|
lockfile.checksums[sectionKey] = sectionChecksums;
|
|
5519
5796
|
_saveLockfile(lockfile);
|
|
5520
5797
|
},
|
|
5521
5798
|
registerPartialSourceData: (pathPattern, partialSourceData) => {
|
|
5522
5799
|
const lockfile = _loadLockfile();
|
|
5523
5800
|
const sectionKey = MD52(pathPattern);
|
|
5524
|
-
const sectionChecksums =
|
|
5525
|
-
|
|
5801
|
+
const sectionChecksums = _31.mapValues(
|
|
5802
|
+
partialSourceData,
|
|
5803
|
+
(value) => MD52(value)
|
|
5804
|
+
);
|
|
5805
|
+
lockfile.checksums[sectionKey] = _31.merge(
|
|
5806
|
+
{},
|
|
5807
|
+
lockfile.checksums[sectionKey] ?? {},
|
|
5808
|
+
sectionChecksums
|
|
5809
|
+
);
|
|
5526
5810
|
_saveLockfile(lockfile);
|
|
5527
5811
|
},
|
|
5528
5812
|
extractUpdatedData: (pathPattern, sourceData) => {
|
|
5529
5813
|
const lockfile = _loadLockfile();
|
|
5530
5814
|
const sectionKey = MD52(pathPattern);
|
|
5531
|
-
const currentChecksums =
|
|
5815
|
+
const currentChecksums = _31.mapValues(sourceData, (value) => MD52(value));
|
|
5532
5816
|
const savedChecksums = lockfile.checksums[sectionKey] || {};
|
|
5533
|
-
const updatedData =
|
|
5817
|
+
const updatedData = _31.pickBy(
|
|
5818
|
+
sourceData,
|
|
5819
|
+
(value, key) => savedChecksums[key] !== currentChecksums[key]
|
|
5820
|
+
);
|
|
5534
5821
|
return updatedData;
|
|
5535
5822
|
}
|
|
5536
5823
|
};
|
|
@@ -5574,20 +5861,31 @@ var lockfile_default = new Command13().command("lockfile").description("Create a
|
|
|
5574
5861
|
const ora = Ora8();
|
|
5575
5862
|
const lockfileHelper = createLockfileHelper();
|
|
5576
5863
|
if (lockfileHelper.isLockfileExists() && !flags.force) {
|
|
5577
|
-
ora.warn(
|
|
5864
|
+
ora.warn(
|
|
5865
|
+
`Lockfile won't be created because it already exists. Use --force to overwrite.`
|
|
5866
|
+
);
|
|
5578
5867
|
} else {
|
|
5579
5868
|
const i18nConfig = getConfig();
|
|
5580
5869
|
const buckets = getBuckets(i18nConfig);
|
|
5581
5870
|
for (const bucket of buckets) {
|
|
5582
5871
|
for (const bucketConfig of bucket.paths) {
|
|
5583
|
-
const sourceLocale = resolveOverriddenLocale4(
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5872
|
+
const sourceLocale = resolveOverriddenLocale4(
|
|
5873
|
+
i18nConfig.locale.source,
|
|
5874
|
+
bucketConfig.delimiter
|
|
5875
|
+
);
|
|
5876
|
+
const bucketLoader = createBucketLoader(
|
|
5877
|
+
bucket.type,
|
|
5878
|
+
bucketConfig.pathPattern,
|
|
5879
|
+
{
|
|
5880
|
+
defaultLocale: sourceLocale
|
|
5881
|
+
}
|
|
5882
|
+
);
|
|
5588
5883
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
5589
5884
|
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
5590
|
-
lockfileHelper.registerSourceData(
|
|
5885
|
+
lockfileHelper.registerSourceData(
|
|
5886
|
+
bucketConfig.pathPattern,
|
|
5887
|
+
sourceData
|
|
5888
|
+
);
|
|
5591
5889
|
}
|
|
5592
5890
|
}
|
|
5593
5891
|
ora.succeed("Lockfile created");
|
|
@@ -5600,9 +5898,11 @@ var flagsSchema = Z5.object({
|
|
|
5600
5898
|
// src/cli/cmd/cleanup.ts
|
|
5601
5899
|
import { resolveOverriddenLocale as resolveOverriddenLocale5 } from "@lingo.dev/_spec";
|
|
5602
5900
|
import { Command as Command14 } from "interactive-commander";
|
|
5603
|
-
import
|
|
5901
|
+
import _32 from "lodash";
|
|
5604
5902
|
import Ora9 from "ora";
|
|
5605
|
-
var cleanup_default = new Command14().command("cleanup").description(
|
|
5903
|
+
var cleanup_default = new Command14().command("cleanup").description(
|
|
5904
|
+
"Remove keys from target files that do not exist in the source file"
|
|
5905
|
+
).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(
|
|
5606
5906
|
"--verbose",
|
|
5607
5907
|
"Show detailed output including:\n - List of keys that would be removed.\n - Processing steps."
|
|
5608
5908
|
).action(async function(options) {
|
|
@@ -5615,44 +5915,69 @@ var cleanup_default = new Command14().command("cleanup").description("Remove key
|
|
|
5615
5915
|
ora.succeed("Configuration loaded");
|
|
5616
5916
|
let buckets = getBuckets(i18nConfig);
|
|
5617
5917
|
if (options.bucket) {
|
|
5618
|
-
buckets = buckets.filter(
|
|
5918
|
+
buckets = buckets.filter(
|
|
5919
|
+
(bucket) => bucket.type === options.bucket
|
|
5920
|
+
);
|
|
5619
5921
|
}
|
|
5620
5922
|
const targetLocales = options.locale ? [options.locale] : i18nConfig.locale.targets;
|
|
5621
5923
|
for (const bucket of buckets) {
|
|
5622
5924
|
console.log();
|
|
5623
5925
|
ora.info(`Processing bucket: ${bucket.type}`);
|
|
5624
5926
|
for (const bucketConfig of bucket.paths) {
|
|
5625
|
-
const sourceLocale = resolveOverriddenLocale5(
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5927
|
+
const sourceLocale = resolveOverriddenLocale5(
|
|
5928
|
+
i18nConfig.locale.source,
|
|
5929
|
+
bucketConfig.delimiter
|
|
5930
|
+
);
|
|
5931
|
+
const bucketOra = Ora9({ indent: 2 }).info(
|
|
5932
|
+
`Processing path: ${bucketConfig.pathPattern}`
|
|
5933
|
+
);
|
|
5934
|
+
const bucketLoader = createBucketLoader(
|
|
5935
|
+
bucket.type,
|
|
5936
|
+
bucketConfig.pathPattern,
|
|
5937
|
+
{
|
|
5938
|
+
defaultLocale: sourceLocale
|
|
5939
|
+
}
|
|
5940
|
+
);
|
|
5631
5941
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
5632
5942
|
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
5633
5943
|
const sourceKeys = Object.keys(sourceData);
|
|
5634
5944
|
for (const _targetLocale of targetLocales) {
|
|
5635
|
-
const targetLocale = resolveOverriddenLocale5(
|
|
5945
|
+
const targetLocale = resolveOverriddenLocale5(
|
|
5946
|
+
_targetLocale,
|
|
5947
|
+
bucketConfig.delimiter
|
|
5948
|
+
);
|
|
5636
5949
|
try {
|
|
5637
5950
|
const targetData = await bucketLoader.pull(targetLocale);
|
|
5638
5951
|
const targetKeys = Object.keys(targetData);
|
|
5639
|
-
const keysToRemove =
|
|
5952
|
+
const keysToRemove = _32.difference(targetKeys, sourceKeys);
|
|
5640
5953
|
if (keysToRemove.length === 0) {
|
|
5641
5954
|
bucketOra.succeed(`[${targetLocale}] No keys to remove`);
|
|
5642
5955
|
continue;
|
|
5643
5956
|
}
|
|
5644
5957
|
if (options.verbose) {
|
|
5645
|
-
bucketOra.info(
|
|
5958
|
+
bucketOra.info(
|
|
5959
|
+
`[${targetLocale}] Keys to remove: ${JSON.stringify(
|
|
5960
|
+
keysToRemove,
|
|
5961
|
+
null,
|
|
5962
|
+
2
|
|
5963
|
+
)}`
|
|
5964
|
+
);
|
|
5646
5965
|
}
|
|
5647
5966
|
if (!options.dryRun) {
|
|
5648
|
-
const cleanedData =
|
|
5967
|
+
const cleanedData = _32.pick(targetData, sourceKeys);
|
|
5649
5968
|
await bucketLoader.push(targetLocale, cleanedData);
|
|
5650
|
-
bucketOra.succeed(
|
|
5969
|
+
bucketOra.succeed(
|
|
5970
|
+
`[${targetLocale}] Removed ${keysToRemove.length} keys`
|
|
5971
|
+
);
|
|
5651
5972
|
} else {
|
|
5652
|
-
bucketOra.succeed(
|
|
5973
|
+
bucketOra.succeed(
|
|
5974
|
+
`[${targetLocale}] Would remove ${keysToRemove.length} keys (dry run)`
|
|
5975
|
+
);
|
|
5653
5976
|
}
|
|
5654
5977
|
} catch (error) {
|
|
5655
|
-
bucketOra.fail(
|
|
5978
|
+
bucketOra.fail(
|
|
5979
|
+
`[${targetLocale}] Failed to cleanup: ${error.message}`
|
|
5980
|
+
);
|
|
5656
5981
|
results.push({
|
|
5657
5982
|
step: `Cleanup ${bucket.type}/${bucketConfig} for ${targetLocale}`,
|
|
5658
5983
|
status: "Failed",
|
|
@@ -5700,7 +6025,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5700
6025
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5701
6026
|
import Z6 from "zod";
|
|
5702
6027
|
import { ReplexicaEngine } from "@lingo.dev/_sdk";
|
|
5703
|
-
var mcp_default = new Command15().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (
|
|
6028
|
+
var mcp_default = new Command15().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_34, program) => {
|
|
5704
6029
|
const apiKey = program.args[0];
|
|
5705
6030
|
const settings = getSettings(apiKey);
|
|
5706
6031
|
if (!settings.auth.apiKey) {
|
|
@@ -5802,7 +6127,9 @@ function createLingoDotDevLocalizer(explicitApiKey) {
|
|
|
5802
6127
|
if (!auth) {
|
|
5803
6128
|
throw new Error(
|
|
5804
6129
|
dedent5`
|
|
5805
|
-
You're trying to use ${chalk8.hex(colors.green)(
|
|
6130
|
+
You're trying to use ${chalk8.hex(colors.green)(
|
|
6131
|
+
"Lingo.dev"
|
|
6132
|
+
)} provider, however, you are not authenticated.
|
|
5806
6133
|
|
|
5807
6134
|
To fix this issue:
|
|
5808
6135
|
1. Run ${chalk8.dim("lingo.dev login")} to authenticate, or
|
|
@@ -5854,6 +6181,7 @@ import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
|
5854
6181
|
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
5855
6182
|
import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
5856
6183
|
import { createOpenRouter as createOpenRouter2 } from "@openrouter/ai-sdk-provider";
|
|
6184
|
+
import { createMistral as createMistral2 } from "@ai-sdk/mistral";
|
|
5857
6185
|
import chalk9 from "chalk";
|
|
5858
6186
|
import dedent6 from "dedent";
|
|
5859
6187
|
import { generateText as generateText2 } from "ai";
|
|
@@ -5868,7 +6196,11 @@ function createExplicitLocalizer(provider) {
|
|
|
5868
6196
|
|
|
5869
6197
|
To fix this issue:
|
|
5870
6198
|
1. Switch to one of the supported providers, or
|
|
5871
|
-
2. Remove the ${chalk9.italic(
|
|
6199
|
+
2. Remove the ${chalk9.italic(
|
|
6200
|
+
"provider"
|
|
6201
|
+
)} node from your i18n.json configuration to switch to ${chalk9.hex(
|
|
6202
|
+
colors.green
|
|
6203
|
+
)("Lingo.dev")}
|
|
5872
6204
|
|
|
5873
6205
|
${chalk9.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
5874
6206
|
`
|
|
@@ -5912,6 +6244,14 @@ function createExplicitLocalizer(provider) {
|
|
|
5912
6244
|
prompt: provider.prompt,
|
|
5913
6245
|
skipAuth: true
|
|
5914
6246
|
});
|
|
6247
|
+
case "mistral":
|
|
6248
|
+
return createAiSdkLocalizer({
|
|
6249
|
+
factory: (params) => createMistral2(params).languageModel(provider.model),
|
|
6250
|
+
id: provider.id,
|
|
6251
|
+
prompt: provider.prompt,
|
|
6252
|
+
apiKeyName: "MISTRAL_API_KEY",
|
|
6253
|
+
baseUrl: provider.baseUrl
|
|
6254
|
+
});
|
|
5915
6255
|
}
|
|
5916
6256
|
}
|
|
5917
6257
|
function createAiSdkLocalizer(params) {
|
|
@@ -5920,11 +6260,19 @@ function createAiSdkLocalizer(params) {
|
|
|
5920
6260
|
if (!skipAuth && !apiKey || !params.apiKeyName) {
|
|
5921
6261
|
throw new Error(
|
|
5922
6262
|
dedent6`
|
|
5923
|
-
You're trying to use raw ${chalk9.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${chalk9.dim(
|
|
6263
|
+
You're trying to use raw ${chalk9.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${chalk9.dim(
|
|
6264
|
+
params.apiKeyName
|
|
6265
|
+
)} environment variable is not set.` : "However, that provider is unavailable."}
|
|
5924
6266
|
|
|
5925
6267
|
To fix this issue:
|
|
5926
|
-
1. ${params.apiKeyName ? `Set ${chalk9.dim(
|
|
5927
|
-
|
|
6268
|
+
1. ${params.apiKeyName ? `Set ${chalk9.dim(
|
|
6269
|
+
params.apiKeyName
|
|
6270
|
+
)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
|
|
6271
|
+
2. Remove the ${chalk9.italic(
|
|
6272
|
+
"provider"
|
|
6273
|
+
)} node from your i18n.json configuration to switch to ${chalk9.hex(
|
|
6274
|
+
colors.green
|
|
6275
|
+
)("Lingo.dev")}
|
|
5928
6276
|
|
|
5929
6277
|
${chalk9.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
5930
6278
|
`
|
|
@@ -6064,10 +6412,14 @@ async function setup(input2) {
|
|
|
6064
6412
|
const authStatus = await ctx.localizer.checkAuth();
|
|
6065
6413
|
if (!authStatus.authenticated) {
|
|
6066
6414
|
throw new Error(
|
|
6067
|
-
`Failed to authenticate with ${chalk10.hex(colors.yellow)(
|
|
6415
|
+
`Failed to authenticate with ${chalk10.hex(colors.yellow)(
|
|
6416
|
+
ctx.localizer.id
|
|
6417
|
+
)} provider. Please check your API key and try again.`
|
|
6068
6418
|
);
|
|
6069
6419
|
}
|
|
6070
|
-
task.title = `Authenticated as ${chalk10.hex(colors.yellow)(
|
|
6420
|
+
task.title = `Authenticated as ${chalk10.hex(colors.yellow)(
|
|
6421
|
+
authStatus.username
|
|
6422
|
+
)}`;
|
|
6071
6423
|
}
|
|
6072
6424
|
},
|
|
6073
6425
|
{
|
|
@@ -6128,14 +6480,22 @@ async function plan(input2) {
|
|
|
6128
6480
|
title: "Locating content buckets",
|
|
6129
6481
|
task: async (ctx, task) => {
|
|
6130
6482
|
const bucketCount = buckets.length;
|
|
6131
|
-
const bucketFilter = input2.flags.bucket ? ` ${chalk11.dim(
|
|
6132
|
-
|
|
6483
|
+
const bucketFilter = input2.flags.bucket ? ` ${chalk11.dim(
|
|
6484
|
+
`(filtered by: ${chalk11.hex(colors.yellow)(
|
|
6485
|
+
input2.flags.bucket.join(", ")
|
|
6486
|
+
)})`
|
|
6487
|
+
)}` : "";
|
|
6488
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6489
|
+
bucketCount.toString()
|
|
6490
|
+
)} bucket(s)${bucketFilter}`;
|
|
6133
6491
|
}
|
|
6134
6492
|
},
|
|
6135
6493
|
{
|
|
6136
6494
|
title: "Detecting locales",
|
|
6137
6495
|
task: async (ctx, task) => {
|
|
6138
|
-
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6496
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6497
|
+
_targetLocales.length.toString()
|
|
6498
|
+
)} target locale(s)`;
|
|
6139
6499
|
}
|
|
6140
6500
|
},
|
|
6141
6501
|
{
|
|
@@ -6154,8 +6514,14 @@ async function plan(input2) {
|
|
|
6154
6514
|
patterns.push(bucketPath.pathPattern);
|
|
6155
6515
|
}
|
|
6156
6516
|
}
|
|
6157
|
-
const fileFilter = input2.flags.file ? ` ${chalk11.dim(
|
|
6158
|
-
|
|
6517
|
+
const fileFilter = input2.flags.file ? ` ${chalk11.dim(
|
|
6518
|
+
`(filtered by: ${chalk11.hex(colors.yellow)(
|
|
6519
|
+
input2.flags.file.join(", ")
|
|
6520
|
+
)})`
|
|
6521
|
+
)}` : "";
|
|
6522
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6523
|
+
patterns.length.toString()
|
|
6524
|
+
)} path pattern(s)${fileFilter}`;
|
|
6159
6525
|
}
|
|
6160
6526
|
},
|
|
6161
6527
|
{
|
|
@@ -6193,7 +6559,9 @@ async function plan(input2) {
|
|
|
6193
6559
|
}
|
|
6194
6560
|
}
|
|
6195
6561
|
}
|
|
6196
|
-
task.title = `Prepared ${chalk11.hex(colors.green)(
|
|
6562
|
+
task.title = `Prepared ${chalk11.hex(colors.green)(
|
|
6563
|
+
ctx.tasks.length.toString()
|
|
6564
|
+
)} translation task(s)`;
|
|
6197
6565
|
}
|
|
6198
6566
|
}
|
|
6199
6567
|
],
|
|
@@ -6207,7 +6575,7 @@ async function plan(input2) {
|
|
|
6207
6575
|
import chalk12 from "chalk";
|
|
6208
6576
|
import { Listr as Listr3 } from "listr2";
|
|
6209
6577
|
import pLimit from "p-limit";
|
|
6210
|
-
import
|
|
6578
|
+
import _33 from "lodash";
|
|
6211
6579
|
|
|
6212
6580
|
// ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
6213
6581
|
var balanced = (a, b, str) => {
|
|
@@ -6898,7 +7266,7 @@ var AST = class _AST {
|
|
|
6898
7266
|
if (!this.type) {
|
|
6899
7267
|
const noEmpty = this.isStart() && this.isEnd();
|
|
6900
7268
|
const src = this.#parts.map((p) => {
|
|
6901
|
-
const [re,
|
|
7269
|
+
const [re, _34, hasMagic, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
|
|
6902
7270
|
this.#hasMagic = this.#hasMagic || hasMagic;
|
|
6903
7271
|
this.#uflag = this.#uflag || uflag;
|
|
6904
7272
|
return re;
|
|
@@ -6971,7 +7339,7 @@ var AST = class _AST {
|
|
|
6971
7339
|
if (typeof p === "string") {
|
|
6972
7340
|
throw new Error("string type in extglob ast??");
|
|
6973
7341
|
}
|
|
6974
|
-
const [re,
|
|
7342
|
+
const [re, _34, _hasMagic, uflag] = p.toRegExpSource(dot);
|
|
6975
7343
|
this.#uflag = this.#uflag || uflag;
|
|
6976
7344
|
return re;
|
|
6977
7345
|
}).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
|
|
@@ -7216,7 +7584,7 @@ var Minimatch = class {
|
|
|
7216
7584
|
}
|
|
7217
7585
|
return false;
|
|
7218
7586
|
}
|
|
7219
|
-
debug(...
|
|
7587
|
+
debug(..._34) {
|
|
7220
7588
|
}
|
|
7221
7589
|
make() {
|
|
7222
7590
|
const pattern = this.pattern;
|
|
@@ -7238,7 +7606,7 @@ var Minimatch = class {
|
|
|
7238
7606
|
const rawGlobParts = this.globSet.map((s) => this.slashSplit(s));
|
|
7239
7607
|
this.globParts = this.preprocess(rawGlobParts);
|
|
7240
7608
|
this.debug(this.pattern, this.globParts);
|
|
7241
|
-
let set = this.globParts.map((s,
|
|
7609
|
+
let set = this.globParts.map((s, _34, __) => {
|
|
7242
7610
|
if (this.isWindows && this.windowsNoMagicRoot) {
|
|
7243
7611
|
const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]);
|
|
7244
7612
|
const isDrive = /^[a-z]:/i.test(s[0]);
|
|
@@ -7761,11 +8129,15 @@ async function execute(input2) {
|
|
|
7761
8129
|
{
|
|
7762
8130
|
title: "Initializing localization engine",
|
|
7763
8131
|
task: async (ctx, task) => {
|
|
7764
|
-
task.title = `Localization engine ${chalk12.hex(colors.green)(
|
|
8132
|
+
task.title = `Localization engine ${chalk12.hex(colors.green)(
|
|
8133
|
+
"ready"
|
|
8134
|
+
)} (${ctx.localizer.id})`;
|
|
7765
8135
|
}
|
|
7766
8136
|
},
|
|
7767
8137
|
{
|
|
7768
|
-
title: `Processing localization tasks ${chalk12.dim(
|
|
8138
|
+
title: `Processing localization tasks ${chalk12.dim(
|
|
8139
|
+
`(tasks: ${input2.tasks.length}, concurrency: ${effectiveConcurrency})`
|
|
8140
|
+
)}`,
|
|
7769
8141
|
task: (ctx, task) => {
|
|
7770
8142
|
if (input2.tasks.length < 1) {
|
|
7771
8143
|
task.title = `Skipping, nothing to localize.`;
|
|
@@ -7778,7 +8150,7 @@ async function execute(input2) {
|
|
|
7778
8150
|
const workerTasks = [];
|
|
7779
8151
|
for (let i = 0; i < workersCount; i++) {
|
|
7780
8152
|
const assignedTasks = ctx.tasks.filter(
|
|
7781
|
-
(
|
|
8153
|
+
(_34, idx) => idx % workersCount === i
|
|
7782
8154
|
);
|
|
7783
8155
|
workerTasks.push(
|
|
7784
8156
|
createWorkerTask({
|
|
@@ -7814,11 +8186,11 @@ function createWorkerStatusMessage(args) {
|
|
|
7814
8186
|
"[locale]",
|
|
7815
8187
|
args.assignedTask.targetLocale
|
|
7816
8188
|
);
|
|
7817
|
-
return `[${chalk12.hex(colors.yellow)(
|
|
7818
|
-
|
|
7819
|
-
)}
|
|
7820
|
-
|
|
7821
|
-
)(args.assignedTask.targetLocale)})`;
|
|
8189
|
+
return `[${chalk12.hex(colors.yellow)(
|
|
8190
|
+
`${args.percentage}%`
|
|
8191
|
+
)}] Processing: ${chalk12.dim(displayPath)} (${chalk12.hex(colors.yellow)(
|
|
8192
|
+
args.assignedTask.sourceLocale
|
|
8193
|
+
)} -> ${chalk12.hex(colors.yellow)(args.assignedTask.targetLocale)})`;
|
|
7822
8194
|
}
|
|
7823
8195
|
function createExecutionProgressMessage(ctx) {
|
|
7824
8196
|
const succeededTasksCount = countTasks(
|
|
@@ -7833,7 +8205,9 @@ function createExecutionProgressMessage(ctx) {
|
|
|
7833
8205
|
ctx,
|
|
7834
8206
|
(_t, result) => result.status === "skipped"
|
|
7835
8207
|
);
|
|
7836
|
-
return `Processed ${chalk12.green(succeededTasksCount)}/${ctx.tasks.length}, Failed ${chalk12.red(failedTasksCount)}, Skipped ${chalk12.dim(
|
|
8208
|
+
return `Processed ${chalk12.green(succeededTasksCount)}/${ctx.tasks.length}, Failed ${chalk12.red(failedTasksCount)}, Skipped ${chalk12.dim(
|
|
8209
|
+
skippedTasksCount
|
|
8210
|
+
)}`;
|
|
7837
8211
|
}
|
|
7838
8212
|
function createLoaderForTask(assignedTask) {
|
|
7839
8213
|
const bucketLoader = createBucketLoader(
|
|
@@ -7841,7 +8215,6 @@ function createLoaderForTask(assignedTask) {
|
|
|
7841
8215
|
assignedTask.bucketPathPattern,
|
|
7842
8216
|
{
|
|
7843
8217
|
defaultLocale: assignedTask.sourceLocale,
|
|
7844
|
-
isCacheRestore: false,
|
|
7845
8218
|
injectLocale: assignedTask.injectLocale
|
|
7846
8219
|
},
|
|
7847
8220
|
assignedTask.lockedKeys,
|
|
@@ -7877,7 +8250,7 @@ function createWorkerTask(args) {
|
|
|
7877
8250
|
targetData,
|
|
7878
8251
|
checksums
|
|
7879
8252
|
});
|
|
7880
|
-
const processableData =
|
|
8253
|
+
const processableData = _33.chain(sourceData).entries().filter(
|
|
7881
8254
|
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!args.ctx.flags.force
|
|
7882
8255
|
).filter(
|
|
7883
8256
|
([key]) => !assignedTask.onlyKeys.length || assignedTask.onlyKeys?.some(
|
|
@@ -7895,33 +8268,47 @@ function createWorkerTask(args) {
|
|
|
7895
8268
|
targetData,
|
|
7896
8269
|
processableData
|
|
7897
8270
|
},
|
|
7898
|
-
(progress) => {
|
|
8271
|
+
async (progress, _sourceChunk, processedChunk) => {
|
|
8272
|
+
await args.ioLimiter(async () => {
|
|
8273
|
+
await bucketLoader.pull(assignedTask.sourceLocale);
|
|
8274
|
+
const latestTargetData = await bucketLoader.pull(
|
|
8275
|
+
assignedTask.targetLocale
|
|
8276
|
+
);
|
|
8277
|
+
const _partialData = _33.merge(
|
|
8278
|
+
{},
|
|
8279
|
+
latestTargetData,
|
|
8280
|
+
processedChunk
|
|
8281
|
+
);
|
|
8282
|
+
const finalChunkTargetData = processRenamedKeys(
|
|
8283
|
+
delta,
|
|
8284
|
+
_partialData
|
|
8285
|
+
);
|
|
8286
|
+
await bucketLoader.push(
|
|
8287
|
+
assignedTask.targetLocale,
|
|
8288
|
+
finalChunkTargetData
|
|
8289
|
+
);
|
|
8290
|
+
});
|
|
7899
8291
|
subTask.title = createWorkerStatusMessage({
|
|
7900
8292
|
assignedTask,
|
|
7901
8293
|
percentage: progress
|
|
7902
8294
|
});
|
|
7903
8295
|
}
|
|
7904
8296
|
);
|
|
7905
|
-
|
|
8297
|
+
const finalTargetData = _33.merge(
|
|
7906
8298
|
{},
|
|
7907
8299
|
sourceData,
|
|
7908
8300
|
targetData,
|
|
7909
8301
|
processedTargetData
|
|
7910
8302
|
);
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
if (!renaming) {
|
|
7916
|
-
return [key, value];
|
|
7917
|
-
}
|
|
7918
|
-
return [renaming[1], value];
|
|
7919
|
-
}).fromPairs().value();
|
|
8303
|
+
const finalRenamedTargetData = processRenamedKeys(
|
|
8304
|
+
delta,
|
|
8305
|
+
finalTargetData
|
|
8306
|
+
);
|
|
7920
8307
|
await args.ioLimiter(async () => {
|
|
7921
8308
|
await bucketLoader.pull(assignedTask.sourceLocale);
|
|
7922
8309
|
await bucketLoader.push(
|
|
7923
8310
|
assignedTask.targetLocale,
|
|
7924
|
-
|
|
8311
|
+
finalRenamedTargetData
|
|
7925
8312
|
);
|
|
7926
8313
|
const checksums2 = await deltaProcessor.createChecksums(sourceData);
|
|
7927
8314
|
await deltaProcessor.saveChecksums(checksums2);
|
|
@@ -7945,6 +8332,144 @@ function countTasks(ctx, predicate) {
|
|
|
7945
8332
|
([task, result]) => predicate(task, result)
|
|
7946
8333
|
).length;
|
|
7947
8334
|
}
|
|
8335
|
+
function processRenamedKeys(delta, targetData) {
|
|
8336
|
+
return _33.chain(targetData).entries().map(([key, value]) => {
|
|
8337
|
+
const renaming = delta.renamed.find(([oldKey]) => oldKey === key);
|
|
8338
|
+
if (!renaming) {
|
|
8339
|
+
return [key, value];
|
|
8340
|
+
}
|
|
8341
|
+
return [renaming[1], value];
|
|
8342
|
+
}).fromPairs().value();
|
|
8343
|
+
}
|
|
8344
|
+
|
|
8345
|
+
// src/cli/cmd/run/watch.ts
|
|
8346
|
+
import * as chokidar from "chokidar";
|
|
8347
|
+
import chalk13 from "chalk";
|
|
8348
|
+
async function watch2(ctx) {
|
|
8349
|
+
const debounceDelay = ctx.flags.debounce || 5e3;
|
|
8350
|
+
console.log(chalk13.hex(colors.orange)("[Watch Mode]"));
|
|
8351
|
+
console.log(
|
|
8352
|
+
`\u{1F440} Watching for changes... (Press ${chalk13.yellow("Ctrl+C")} to stop)`
|
|
8353
|
+
);
|
|
8354
|
+
console.log(chalk13.dim(` Debounce delay: ${debounceDelay}ms`));
|
|
8355
|
+
console.log("");
|
|
8356
|
+
const state = {
|
|
8357
|
+
isRunning: false,
|
|
8358
|
+
pendingChanges: /* @__PURE__ */ new Set()
|
|
8359
|
+
};
|
|
8360
|
+
const watchPatterns = await getWatchPatterns(ctx);
|
|
8361
|
+
if (watchPatterns.length === 0) {
|
|
8362
|
+
console.log(chalk13.yellow("\u26A0\uFE0F No source files found to watch"));
|
|
8363
|
+
return;
|
|
8364
|
+
}
|
|
8365
|
+
console.log(chalk13.dim(`Watching ${watchPatterns.length} file pattern(s):`));
|
|
8366
|
+
watchPatterns.forEach((pattern) => {
|
|
8367
|
+
console.log(chalk13.dim(` \u2022 ${pattern}`));
|
|
8368
|
+
});
|
|
8369
|
+
console.log("");
|
|
8370
|
+
const watcher = chokidar.watch(watchPatterns, {
|
|
8371
|
+
ignoreInitial: true,
|
|
8372
|
+
persistent: true,
|
|
8373
|
+
awaitWriteFinish: {
|
|
8374
|
+
stabilityThreshold: 500,
|
|
8375
|
+
pollInterval: 100
|
|
8376
|
+
}
|
|
8377
|
+
});
|
|
8378
|
+
watcher.on("change", (path17) => {
|
|
8379
|
+
handleFileChange(path17, state, ctx);
|
|
8380
|
+
});
|
|
8381
|
+
watcher.on("add", (path17) => {
|
|
8382
|
+
handleFileChange(path17, state, ctx);
|
|
8383
|
+
});
|
|
8384
|
+
watcher.on("unlink", (path17) => {
|
|
8385
|
+
handleFileChange(path17, state, ctx);
|
|
8386
|
+
});
|
|
8387
|
+
watcher.on("error", (error) => {
|
|
8388
|
+
console.error(
|
|
8389
|
+
chalk13.red(
|
|
8390
|
+
`Watch error: ${error instanceof Error ? error.message : String(error)}`
|
|
8391
|
+
)
|
|
8392
|
+
);
|
|
8393
|
+
});
|
|
8394
|
+
process.on("SIGINT", () => {
|
|
8395
|
+
console.log(chalk13.yellow("\n\n\u{1F6D1} Stopping watch mode..."));
|
|
8396
|
+
watcher.close();
|
|
8397
|
+
process.exit(0);
|
|
8398
|
+
});
|
|
8399
|
+
await new Promise(() => {
|
|
8400
|
+
});
|
|
8401
|
+
}
|
|
8402
|
+
async function getWatchPatterns(ctx) {
|
|
8403
|
+
if (!ctx.config) return [];
|
|
8404
|
+
const buckets = getBuckets(ctx.config);
|
|
8405
|
+
const patterns = [];
|
|
8406
|
+
for (const bucket of buckets) {
|
|
8407
|
+
if (ctx.flags.bucket && !ctx.flags.bucket.includes(bucket.type)) {
|
|
8408
|
+
continue;
|
|
8409
|
+
}
|
|
8410
|
+
for (const bucketPath of bucket.paths) {
|
|
8411
|
+
if (ctx.flags.file) {
|
|
8412
|
+
if (!ctx.flags.file.some((f) => bucketPath.pathPattern.includes(f))) {
|
|
8413
|
+
continue;
|
|
8414
|
+
}
|
|
8415
|
+
}
|
|
8416
|
+
const sourceLocale = ctx.flags.sourceLocale || ctx.config.locale.source;
|
|
8417
|
+
const sourcePattern = bucketPath.pathPattern.replace(
|
|
8418
|
+
"[locale]",
|
|
8419
|
+
sourceLocale
|
|
8420
|
+
);
|
|
8421
|
+
patterns.push(sourcePattern);
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
return patterns;
|
|
8425
|
+
}
|
|
8426
|
+
function handleFileChange(filePath, state, ctx) {
|
|
8427
|
+
const debounceDelay = ctx.flags.debounce || 5e3;
|
|
8428
|
+
state.pendingChanges.add(filePath);
|
|
8429
|
+
console.log(chalk13.dim(`\u{1F4DD} File changed: ${filePath}`));
|
|
8430
|
+
if (state.debounceTimer) {
|
|
8431
|
+
clearTimeout(state.debounceTimer);
|
|
8432
|
+
}
|
|
8433
|
+
state.debounceTimer = setTimeout(async () => {
|
|
8434
|
+
if (state.isRunning) {
|
|
8435
|
+
console.log(
|
|
8436
|
+
chalk13.yellow("\u23F3 Translation already in progress, skipping...")
|
|
8437
|
+
);
|
|
8438
|
+
return;
|
|
8439
|
+
}
|
|
8440
|
+
await triggerRetranslation(state, ctx);
|
|
8441
|
+
}, debounceDelay);
|
|
8442
|
+
}
|
|
8443
|
+
async function triggerRetranslation(state, ctx) {
|
|
8444
|
+
if (state.isRunning) return;
|
|
8445
|
+
state.isRunning = true;
|
|
8446
|
+
try {
|
|
8447
|
+
const changedFiles = Array.from(state.pendingChanges);
|
|
8448
|
+
state.pendingChanges.clear();
|
|
8449
|
+
console.log(chalk13.hex(colors.green)("\n\u{1F504} Triggering retranslation..."));
|
|
8450
|
+
console.log(chalk13.dim(`Changed files: ${changedFiles.join(", ")}`));
|
|
8451
|
+
console.log("");
|
|
8452
|
+
const runCtx = {
|
|
8453
|
+
...ctx,
|
|
8454
|
+
tasks: [],
|
|
8455
|
+
results: /* @__PURE__ */ new Map()
|
|
8456
|
+
};
|
|
8457
|
+
await plan(runCtx);
|
|
8458
|
+
if (runCtx.tasks.length === 0) {
|
|
8459
|
+
console.log(chalk13.dim("\u2728 No translation tasks needed"));
|
|
8460
|
+
} else {
|
|
8461
|
+
await execute(runCtx);
|
|
8462
|
+
await renderSummary(runCtx.results);
|
|
8463
|
+
}
|
|
8464
|
+
console.log(chalk13.hex(colors.green)("\u2705 Retranslation completed"));
|
|
8465
|
+
console.log(chalk13.dim("\u{1F440} Continuing to watch for changes...\n"));
|
|
8466
|
+
} catch (error) {
|
|
8467
|
+
console.error(chalk13.red(`\u274C Retranslation failed: ${error.message}`));
|
|
8468
|
+
console.log(chalk13.dim("\u{1F440} Continuing to watch for changes...\n"));
|
|
8469
|
+
} finally {
|
|
8470
|
+
state.isRunning = false;
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
7948
8473
|
|
|
7949
8474
|
// src/cli/cmd/run/_types.ts
|
|
7950
8475
|
import {
|
|
@@ -7964,7 +8489,10 @@ var flagsSchema2 = z2.object({
|
|
|
7964
8489
|
concurrency: z2.number().positive().default(10),
|
|
7965
8490
|
debug: z2.boolean().default(false),
|
|
7966
8491
|
sourceLocale: z2.string().optional(),
|
|
7967
|
-
targetLocale: z2.array(z2.string()).optional()
|
|
8492
|
+
targetLocale: z2.array(z2.string()).optional(),
|
|
8493
|
+
watch: z2.boolean().default(false),
|
|
8494
|
+
debounce: z2.number().positive().default(5e3)
|
|
8495
|
+
// 5 seconds default
|
|
7968
8496
|
});
|
|
7969
8497
|
|
|
7970
8498
|
// src/cli/cmd/run/_utils.ts
|
|
@@ -8015,6 +8543,13 @@ var run_default = new Command16().command("run").description("Run Lingo.dev loca
|
|
|
8015
8543
|
"--concurrency <concurrency>",
|
|
8016
8544
|
"Number of concurrent tasks to run",
|
|
8017
8545
|
(val) => parseInt(val)
|
|
8546
|
+
).option(
|
|
8547
|
+
"--watch",
|
|
8548
|
+
"Watch source files for changes and automatically retranslate"
|
|
8549
|
+
).option(
|
|
8550
|
+
"--debounce <milliseconds>",
|
|
8551
|
+
"Debounce delay in milliseconds for watch mode (default: 5000ms)",
|
|
8552
|
+
(val) => parseInt(val)
|
|
8018
8553
|
).action(async (args) => {
|
|
8019
8554
|
let authId = null;
|
|
8020
8555
|
try {
|
|
@@ -8044,6 +8579,9 @@ var run_default = new Command16().command("run").description("Run Lingo.dev loca
|
|
|
8044
8579
|
await renderSpacer();
|
|
8045
8580
|
await renderSummary(ctx.results);
|
|
8046
8581
|
await renderSpacer();
|
|
8582
|
+
if (ctx.flags.watch) {
|
|
8583
|
+
await watch2(ctx);
|
|
8584
|
+
}
|
|
8047
8585
|
trackEvent(authId, "cmd.run.success", {
|
|
8048
8586
|
config: ctx.config,
|
|
8049
8587
|
flags: ctx.flags
|
|
@@ -8075,7 +8613,9 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
8075
8613
|
execSync(`git add .`, { stdio: "inherit" });
|
|
8076
8614
|
execSync(`git status --porcelain`, { stdio: "inherit" });
|
|
8077
8615
|
execSync(
|
|
8078
|
-
`git commit -m ${escapeShellArg(
|
|
8616
|
+
`git commit -m ${escapeShellArg(
|
|
8617
|
+
this.platformKit.config.commitMessage
|
|
8618
|
+
)} --no-verify`,
|
|
8079
8619
|
{
|
|
8080
8620
|
stdio: "inherit"
|
|
8081
8621
|
}
|
|
@@ -8198,7 +8738,9 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
8198
8738
|
this.ora.start("Checking if PR already exists");
|
|
8199
8739
|
const pullRequestNumber = await this.ensureFreshPr(this.i18nBranchName);
|
|
8200
8740
|
this.ora.succeed(
|
|
8201
|
-
`Pull request ready: ${this.platformKit.buildPullRequestUrl(
|
|
8741
|
+
`Pull request ready: ${this.platformKit.buildPullRequestUrl(
|
|
8742
|
+
pullRequestNumber
|
|
8743
|
+
)}`
|
|
8202
8744
|
);
|
|
8203
8745
|
}
|
|
8204
8746
|
calculatePrBranchName() {
|
|
@@ -8368,11 +8910,17 @@ var PlatformKit = class {
|
|
|
8368
8910
|
get config() {
|
|
8369
8911
|
const env = Z7.object({
|
|
8370
8912
|
LINGODOTDEV_API_KEY: Z7.string(),
|
|
8371
|
-
LINGODOTDEV_PULL_REQUEST: Z7.preprocess(
|
|
8913
|
+
LINGODOTDEV_PULL_REQUEST: Z7.preprocess(
|
|
8914
|
+
(val) => val === "true" || val === true,
|
|
8915
|
+
Z7.boolean()
|
|
8916
|
+
),
|
|
8372
8917
|
LINGODOTDEV_COMMIT_MESSAGE: Z7.string().optional(),
|
|
8373
8918
|
LINGODOTDEV_PULL_REQUEST_TITLE: Z7.string().optional(),
|
|
8374
8919
|
LINGODOTDEV_WORKING_DIRECTORY: Z7.string().optional(),
|
|
8375
|
-
LINGODOTDEV_PROCESS_OWN_COMMITS: Z7.preprocess(
|
|
8920
|
+
LINGODOTDEV_PROCESS_OWN_COMMITS: Z7.preprocess(
|
|
8921
|
+
(val) => val === "true" || val === true,
|
|
8922
|
+
Z7.boolean()
|
|
8923
|
+
).optional()
|
|
8376
8924
|
}).parse(process.env);
|
|
8377
8925
|
return {
|
|
8378
8926
|
replexicaApiKey: env.LINGODOTDEV_API_KEY,
|
|
@@ -8767,16 +9315,34 @@ function parseBooleanArg(val) {
|
|
|
8767
9315
|
}
|
|
8768
9316
|
|
|
8769
9317
|
// src/cli/cmd/status.ts
|
|
8770
|
-
import {
|
|
9318
|
+
import {
|
|
9319
|
+
bucketTypeSchema as bucketTypeSchema4,
|
|
9320
|
+
localeCodeSchema as localeCodeSchema3,
|
|
9321
|
+
resolveOverriddenLocale as resolveOverriddenLocale7
|
|
9322
|
+
} from "@lingo.dev/_spec";
|
|
8771
9323
|
import { Command as Command18 } from "interactive-commander";
|
|
8772
9324
|
import Z11 from "zod";
|
|
8773
9325
|
import Ora10 from "ora";
|
|
8774
|
-
import
|
|
9326
|
+
import chalk14 from "chalk";
|
|
8775
9327
|
import Table from "cli-table3";
|
|
8776
|
-
var status_default = new Command18().command("status").description("Show the status of the localization process").helpOption("-h, --help", "Show help").option(
|
|
9328
|
+
var status_default = new Command18().command("status").description("Show the status of the localization process").helpOption("-h, --help", "Show help").option(
|
|
9329
|
+
"--locale <locale>",
|
|
9330
|
+
"Locale to process",
|
|
9331
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
9332
|
+
).option(
|
|
9333
|
+
"--bucket <bucket>",
|
|
9334
|
+
"Bucket to process",
|
|
9335
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
9336
|
+
).option(
|
|
8777
9337
|
"--file [files...]",
|
|
8778
9338
|
"File to process. Process only a specific path, may contain asterisk * to match multiple files."
|
|
8779
|
-
).option(
|
|
9339
|
+
).option(
|
|
9340
|
+
"--force",
|
|
9341
|
+
"Ignore lockfile and process all keys, useful for estimating full re-translation"
|
|
9342
|
+
).option("--verbose", "Show detailed output including key-level word counts").option(
|
|
9343
|
+
"--api-key <api-key>",
|
|
9344
|
+
"Explicitly set the API key to use, override the default API key from settings"
|
|
9345
|
+
).action(async function(options) {
|
|
8780
9346
|
const ora = Ora10();
|
|
8781
9347
|
const flags = parseFlags2(options);
|
|
8782
9348
|
let authId = null;
|
|
@@ -8808,16 +9374,22 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8808
9374
|
});
|
|
8809
9375
|
let buckets = getBuckets(i18nConfig);
|
|
8810
9376
|
if (flags.bucket?.length) {
|
|
8811
|
-
buckets = buckets.filter(
|
|
9377
|
+
buckets = buckets.filter(
|
|
9378
|
+
(bucket) => flags.bucket.includes(bucket.type)
|
|
9379
|
+
);
|
|
8812
9380
|
}
|
|
8813
9381
|
ora.succeed("Buckets retrieved");
|
|
8814
9382
|
if (flags.file?.length) {
|
|
8815
9383
|
buckets = buckets.map((bucket) => {
|
|
8816
|
-
const paths = bucket.paths.filter(
|
|
9384
|
+
const paths = bucket.paths.filter(
|
|
9385
|
+
(path17) => flags.file.find((file) => path17.pathPattern?.match(file))
|
|
9386
|
+
);
|
|
8817
9387
|
return { ...bucket, paths };
|
|
8818
9388
|
}).filter((bucket) => bucket.paths.length > 0);
|
|
8819
9389
|
if (buckets.length === 0) {
|
|
8820
|
-
ora.fail(
|
|
9390
|
+
ora.fail(
|
|
9391
|
+
"No buckets found. All buckets were filtered out by --file option."
|
|
9392
|
+
);
|
|
8821
9393
|
process.exit(1);
|
|
8822
9394
|
} else {
|
|
8823
9395
|
ora.info(`\x1B[36mProcessing only filtered buckets:\x1B[0m`);
|
|
@@ -8850,13 +9422,17 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8850
9422
|
console.log();
|
|
8851
9423
|
ora.info(`Analyzing bucket: ${bucket.type}`);
|
|
8852
9424
|
for (const bucketPath of bucket.paths) {
|
|
8853
|
-
const bucketOra = Ora10({ indent: 2 }).info(
|
|
8854
|
-
|
|
9425
|
+
const bucketOra = Ora10({ indent: 2 }).info(
|
|
9426
|
+
`Analyzing path: ${bucketPath.pathPattern}`
|
|
9427
|
+
);
|
|
9428
|
+
const sourceLocale = resolveOverriddenLocale7(
|
|
9429
|
+
i18nConfig.locale.source,
|
|
9430
|
+
bucketPath.delimiter
|
|
9431
|
+
);
|
|
8855
9432
|
const bucketLoader = createBucketLoader(
|
|
8856
9433
|
bucket.type,
|
|
8857
9434
|
bucketPath.pathPattern,
|
|
8858
9435
|
{
|
|
8859
|
-
isCacheRestore: false,
|
|
8860
9436
|
defaultLocale: sourceLocale,
|
|
8861
9437
|
injectLocale: bucket.injectLocale
|
|
8862
9438
|
},
|
|
@@ -8895,8 +9471,13 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8895
9471
|
}
|
|
8896
9472
|
fileStats[filePath].wordCount = sourceWordCount;
|
|
8897
9473
|
for (const _targetLocale of targetLocales) {
|
|
8898
|
-
const targetLocale = resolveOverriddenLocale7(
|
|
8899
|
-
|
|
9474
|
+
const targetLocale = resolveOverriddenLocale7(
|
|
9475
|
+
_targetLocale,
|
|
9476
|
+
bucketPath.delimiter
|
|
9477
|
+
);
|
|
9478
|
+
bucketOra.start(
|
|
9479
|
+
`[${sourceLocale} -> ${targetLocale}] Analyzing translation status...`
|
|
9480
|
+
);
|
|
8900
9481
|
let targetData = {};
|
|
8901
9482
|
let fileExists = true;
|
|
8902
9483
|
try {
|
|
@@ -8912,13 +9493,20 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8912
9493
|
fileStats[filePath].languageStats[_targetLocale].words = sourceWordCount;
|
|
8913
9494
|
languageStats[_targetLocale].missing += sourceKeys.length;
|
|
8914
9495
|
languageStats[_targetLocale].words += sourceWordCount;
|
|
8915
|
-
totalWordCount.set(
|
|
9496
|
+
totalWordCount.set(
|
|
9497
|
+
_targetLocale,
|
|
9498
|
+
(totalWordCount.get(_targetLocale) || 0) + sourceWordCount
|
|
9499
|
+
);
|
|
8916
9500
|
bucketOra.succeed(
|
|
8917
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
9501
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk14.red(
|
|
9502
|
+
`0% complete`
|
|
9503
|
+
)} (0/${sourceKeys.length} keys) - file not found`
|
|
8918
9504
|
);
|
|
8919
9505
|
continue;
|
|
8920
9506
|
}
|
|
8921
|
-
const deltaProcessor = createDeltaProcessor(
|
|
9507
|
+
const deltaProcessor = createDeltaProcessor(
|
|
9508
|
+
bucketPath.pathPattern
|
|
9509
|
+
);
|
|
8922
9510
|
const checksums = await deltaProcessor.loadChecksums();
|
|
8923
9511
|
const delta = await deltaProcessor.calculateDelta({
|
|
8924
9512
|
sourceData,
|
|
@@ -8927,7 +9515,9 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8927
9515
|
});
|
|
8928
9516
|
const missingKeys = delta.added;
|
|
8929
9517
|
const updatedKeys = delta.updated;
|
|
8930
|
-
const completeKeys = sourceKeys.filter(
|
|
9518
|
+
const completeKeys = sourceKeys.filter(
|
|
9519
|
+
(key) => !missingKeys.includes(key) && !updatedKeys.includes(key)
|
|
9520
|
+
);
|
|
8931
9521
|
let wordsToTranslate = 0;
|
|
8932
9522
|
const keysToProcess = flags.force ? sourceKeys : [...missingKeys, ...updatedKeys];
|
|
8933
9523
|
for (const key of keysToProcess) {
|
|
@@ -8945,25 +9535,39 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8945
9535
|
languageStats[_targetLocale].updated += updatedKeys.length;
|
|
8946
9536
|
languageStats[_targetLocale].complete += completeKeys.length;
|
|
8947
9537
|
languageStats[_targetLocale].words += wordsToTranslate;
|
|
8948
|
-
totalWordCount.set(
|
|
9538
|
+
totalWordCount.set(
|
|
9539
|
+
_targetLocale,
|
|
9540
|
+
(totalWordCount.get(_targetLocale) || 0) + wordsToTranslate
|
|
9541
|
+
);
|
|
8949
9542
|
const totalKeysInFile = sourceKeys.length;
|
|
8950
9543
|
const completionPercent = (completeKeys.length / totalKeysInFile * 100).toFixed(1);
|
|
8951
9544
|
if (missingKeys.length === 0 && updatedKeys.length === 0) {
|
|
8952
9545
|
bucketOra.succeed(
|
|
8953
|
-
`[${sourceLocale} -> ${targetLocale}] ${
|
|
9546
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk14.green(
|
|
9547
|
+
`100% complete`
|
|
9548
|
+
)} (${completeKeys.length}/${totalKeysInFile} keys)`
|
|
8954
9549
|
);
|
|
8955
9550
|
} else {
|
|
8956
|
-
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ?
|
|
9551
|
+
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ? chalk14.yellow(`${completionPercent}% complete`) : chalk14.red(`${completionPercent}% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`;
|
|
8957
9552
|
bucketOra.succeed(message);
|
|
8958
9553
|
if (flags.verbose) {
|
|
8959
9554
|
if (missingKeys.length > 0) {
|
|
8960
|
-
console.log(` ${chalk13.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`);
|
|
8961
9555
|
console.log(
|
|
8962
|
-
` ${
|
|
9556
|
+
` ${chalk14.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`
|
|
9557
|
+
);
|
|
9558
|
+
console.log(
|
|
9559
|
+
` ${chalk14.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`
|
|
9560
|
+
);
|
|
9561
|
+
console.log(
|
|
9562
|
+
` ${chalk14.dim(
|
|
9563
|
+
`Example missing: ${missingKeys.slice(0, 2).join(", ")}${missingKeys.length > 2 ? "..." : ""}`
|
|
9564
|
+
)}`
|
|
8963
9565
|
);
|
|
8964
9566
|
}
|
|
8965
9567
|
if (updatedKeys.length > 0) {
|
|
8966
|
-
console.log(
|
|
9568
|
+
console.log(
|
|
9569
|
+
` ${chalk14.yellow(`Updated:`)} ${updatedKeys.length} keys that changed in source`
|
|
9570
|
+
);
|
|
8967
9571
|
}
|
|
8968
9572
|
}
|
|
8969
9573
|
}
|
|
@@ -8973,24 +9577,41 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8973
9577
|
ora.fail(`Failed to analyze bucket ${bucket.type}: ${error.message}`);
|
|
8974
9578
|
}
|
|
8975
9579
|
}
|
|
8976
|
-
const totalKeysNeedingTranslation = Object.values(languageStats).reduce(
|
|
8977
|
-
|
|
8978
|
-
|
|
9580
|
+
const totalKeysNeedingTranslation = Object.values(languageStats).reduce(
|
|
9581
|
+
(sum, stats) => {
|
|
9582
|
+
return sum + stats.missing + stats.updated;
|
|
9583
|
+
},
|
|
9584
|
+
0
|
|
9585
|
+
);
|
|
8979
9586
|
const totalCompletedKeys = totalSourceKeyCount - totalKeysNeedingTranslation / targetLocales.length;
|
|
8980
9587
|
console.log();
|
|
8981
|
-
ora.succeed(
|
|
8982
|
-
console.log(
|
|
9588
|
+
ora.succeed(chalk14.green(`Localization status completed.`));
|
|
9589
|
+
console.log(chalk14.bold.cyan(`
|
|
8983
9590
|
\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`));
|
|
8984
|
-
console.log(
|
|
8985
|
-
console.log(
|
|
8986
|
-
console.log(
|
|
9591
|
+
console.log(chalk14.bold.cyan(`\u2551 LOCALIZATION STATUS REPORT \u2551`));
|
|
9592
|
+
console.log(chalk14.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`));
|
|
9593
|
+
console.log(chalk14.bold(`
|
|
8987
9594
|
\u{1F4DD} SOURCE CONTENT:`));
|
|
8988
|
-
console.log(
|
|
8989
|
-
|
|
8990
|
-
|
|
9595
|
+
console.log(
|
|
9596
|
+
`\u2022 Source language: ${chalk14.green(i18nConfig.locale.source)}`
|
|
9597
|
+
);
|
|
9598
|
+
console.log(
|
|
9599
|
+
`\u2022 Source keys: ${chalk14.yellow(
|
|
9600
|
+
totalSourceKeyCount.toString()
|
|
9601
|
+
)} keys across all files`
|
|
9602
|
+
);
|
|
9603
|
+
console.log(chalk14.bold(`
|
|
8991
9604
|
\u{1F310} LANGUAGE BY LANGUAGE BREAKDOWN:`));
|
|
8992
9605
|
const table = new Table({
|
|
8993
|
-
head: [
|
|
9606
|
+
head: [
|
|
9607
|
+
"Language",
|
|
9608
|
+
"Status",
|
|
9609
|
+
"Complete",
|
|
9610
|
+
"Missing",
|
|
9611
|
+
"Updated",
|
|
9612
|
+
"Total Keys",
|
|
9613
|
+
"Words to Translate"
|
|
9614
|
+
],
|
|
8994
9615
|
style: {
|
|
8995
9616
|
head: ["white"],
|
|
8996
9617
|
// White color for headers
|
|
@@ -9009,19 +9630,19 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9009
9630
|
let statusColor;
|
|
9010
9631
|
if (stats.missing === totalSourceKeyCount) {
|
|
9011
9632
|
statusText = "\u{1F534} Not started";
|
|
9012
|
-
statusColor =
|
|
9633
|
+
statusColor = chalk14.red;
|
|
9013
9634
|
} else if (stats.missing === 0 && stats.updated === 0) {
|
|
9014
9635
|
statusText = "\u2705 Complete";
|
|
9015
|
-
statusColor =
|
|
9636
|
+
statusColor = chalk14.green;
|
|
9016
9637
|
} else if (parseFloat(percentComplete) > 80) {
|
|
9017
9638
|
statusText = "\u{1F7E1} Almost done";
|
|
9018
|
-
statusColor =
|
|
9639
|
+
statusColor = chalk14.yellow;
|
|
9019
9640
|
} else if (parseFloat(percentComplete) > 0) {
|
|
9020
9641
|
statusText = "\u{1F7E0} In progress";
|
|
9021
|
-
statusColor =
|
|
9642
|
+
statusColor = chalk14.yellow;
|
|
9022
9643
|
} else {
|
|
9023
9644
|
statusText = "\u{1F534} Not started";
|
|
9024
|
-
statusColor =
|
|
9645
|
+
statusColor = chalk14.red;
|
|
9025
9646
|
}
|
|
9026
9647
|
const words = totalWordCount.get(locale) || 0;
|
|
9027
9648
|
totalWordsToTranslate += words;
|
|
@@ -9029,35 +9650,43 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9029
9650
|
locale,
|
|
9030
9651
|
statusColor(statusText),
|
|
9031
9652
|
`${stats.complete}/${totalSourceKeyCount} (${percentComplete}%)`,
|
|
9032
|
-
stats.missing > 0 ?
|
|
9033
|
-
stats.updated > 0 ?
|
|
9034
|
-
totalNeeded > 0 ?
|
|
9653
|
+
stats.missing > 0 ? chalk14.red(stats.missing.toString()) : "0",
|
|
9654
|
+
stats.updated > 0 ? chalk14.yellow(stats.updated.toString()) : "0",
|
|
9655
|
+
totalNeeded > 0 ? chalk14.magenta(totalNeeded.toString()) : "0",
|
|
9035
9656
|
words > 0 ? `~${words.toLocaleString()}` : "0"
|
|
9036
9657
|
]);
|
|
9037
9658
|
}
|
|
9038
9659
|
console.log(table.toString());
|
|
9039
|
-
console.log(
|
|
9660
|
+
console.log(chalk14.bold(`
|
|
9040
9661
|
\u{1F4CA} USAGE ESTIMATE:`));
|
|
9041
9662
|
console.log(
|
|
9042
|
-
`\u2022 WORDS TO BE CONSUMED: ~${
|
|
9663
|
+
`\u2022 WORDS TO BE CONSUMED: ~${chalk14.yellow.bold(
|
|
9664
|
+
totalWordsToTranslate.toLocaleString()
|
|
9665
|
+
)} words across all languages`
|
|
9666
|
+
);
|
|
9667
|
+
console.log(
|
|
9668
|
+
` (Words are counted from source language for keys that need translation in target languages)`
|
|
9043
9669
|
);
|
|
9044
|
-
console.log(` (Words are counted from source language for keys that need translation in target languages)`);
|
|
9045
9670
|
if (targetLocales.length > 1) {
|
|
9046
9671
|
console.log(`\u2022 Per-language breakdown:`);
|
|
9047
9672
|
for (const locale of targetLocales) {
|
|
9048
9673
|
const words = totalWordCount.get(locale) || 0;
|
|
9049
9674
|
const percent = (words / totalWordsToTranslate * 100).toFixed(1);
|
|
9050
|
-
console.log(
|
|
9675
|
+
console.log(
|
|
9676
|
+
` - ${locale}: ~${words.toLocaleString()} words (${percent}% of total)`
|
|
9677
|
+
);
|
|
9051
9678
|
}
|
|
9052
9679
|
}
|
|
9053
9680
|
if (flags.confirm && Object.keys(fileStats).length > 0) {
|
|
9054
|
-
console.log(
|
|
9681
|
+
console.log(chalk14.bold(`
|
|
9055
9682
|
\u{1F4D1} BREAKDOWN BY FILE:`));
|
|
9056
9683
|
Object.entries(fileStats).sort((a, b) => b[1].wordCount - a[1].wordCount).forEach(([path17, stats]) => {
|
|
9057
9684
|
if (stats.sourceKeys === 0) return;
|
|
9058
|
-
console.log(
|
|
9685
|
+
console.log(chalk14.bold(`
|
|
9059
9686
|
\u2022 ${path17}:`));
|
|
9060
|
-
console.log(
|
|
9687
|
+
console.log(
|
|
9688
|
+
` ${stats.sourceKeys} source keys, ~${stats.wordCount.toLocaleString()} source words`
|
|
9689
|
+
);
|
|
9061
9690
|
const fileTable = new Table({
|
|
9062
9691
|
head: ["Language", "Status", "Details"],
|
|
9063
9692
|
style: {
|
|
@@ -9073,19 +9702,21 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9073
9702
|
const total = stats.sourceKeys;
|
|
9074
9703
|
const completion = (complete / total * 100).toFixed(1);
|
|
9075
9704
|
let status = "\u2705 Complete";
|
|
9076
|
-
let statusColor =
|
|
9705
|
+
let statusColor = chalk14.green;
|
|
9077
9706
|
if (langStats.missing === total) {
|
|
9078
9707
|
status = "\u274C Not started";
|
|
9079
|
-
statusColor =
|
|
9708
|
+
statusColor = chalk14.red;
|
|
9080
9709
|
} else if (langStats.missing > 0 || langStats.updated > 0) {
|
|
9081
9710
|
status = `\u26A0\uFE0F ${completion}% complete`;
|
|
9082
|
-
statusColor =
|
|
9711
|
+
statusColor = chalk14.yellow;
|
|
9083
9712
|
}
|
|
9084
9713
|
let details = "";
|
|
9085
9714
|
if (langStats.missing > 0 || langStats.updated > 0) {
|
|
9086
9715
|
const parts = [];
|
|
9087
|
-
if (langStats.missing > 0)
|
|
9088
|
-
|
|
9716
|
+
if (langStats.missing > 0)
|
|
9717
|
+
parts.push(`${langStats.missing} missing`);
|
|
9718
|
+
if (langStats.updated > 0)
|
|
9719
|
+
parts.push(`${langStats.updated} changed`);
|
|
9089
9720
|
details = `${parts.join(", ")}, ~${langStats.words} words`;
|
|
9090
9721
|
} else {
|
|
9091
9722
|
details = "All keys translated";
|
|
@@ -9098,22 +9729,26 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9098
9729
|
const completeLanguages = targetLocales.filter(
|
|
9099
9730
|
(locale) => languageStats[locale].missing === 0 && languageStats[locale].updated === 0
|
|
9100
9731
|
);
|
|
9101
|
-
const missingLanguages = targetLocales.filter(
|
|
9102
|
-
|
|
9732
|
+
const missingLanguages = targetLocales.filter(
|
|
9733
|
+
(locale) => languageStats[locale].complete === 0
|
|
9734
|
+
);
|
|
9735
|
+
console.log(chalk14.bold.green(`
|
|
9103
9736
|
\u{1F4A1} OPTIMIZATION TIPS:`));
|
|
9104
9737
|
if (missingLanguages.length > 0) {
|
|
9105
9738
|
console.log(
|
|
9106
|
-
`\u2022 ${
|
|
9739
|
+
`\u2022 ${chalk14.yellow(missingLanguages.join(", "))} ${missingLanguages.length === 1 ? "has" : "have"} no translations yet`
|
|
9107
9740
|
);
|
|
9108
9741
|
}
|
|
9109
9742
|
if (completeLanguages.length > 0) {
|
|
9110
9743
|
console.log(
|
|
9111
|
-
`\u2022 ${
|
|
9744
|
+
`\u2022 ${chalk14.green(completeLanguages.join(", "))} ${completeLanguages.length === 1 ? "is" : "are"} completely translated`
|
|
9112
9745
|
);
|
|
9113
9746
|
}
|
|
9114
9747
|
if (targetLocales.length > 1) {
|
|
9115
9748
|
console.log(`\u2022 Translating one language at a time reduces complexity`);
|
|
9116
|
-
console.log(
|
|
9749
|
+
console.log(
|
|
9750
|
+
`\u2022 Try 'lingo.dev@latest i18n --locale ${targetLocales[0]}' to process just one language`
|
|
9751
|
+
);
|
|
9117
9752
|
}
|
|
9118
9753
|
trackEvent(authId || "status", "cmd.status.success", {
|
|
9119
9754
|
i18nConfig,
|
|
@@ -9175,7 +9810,9 @@ function validateParams2(i18nConfig, flags) {
|
|
|
9175
9810
|
message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
|
|
9176
9811
|
docUrl: "localeTargetNotFound"
|
|
9177
9812
|
});
|
|
9178
|
-
} else if (flags.bucket?.some(
|
|
9813
|
+
} else if (flags.bucket?.some(
|
|
9814
|
+
(bucket) => !i18nConfig.buckets[bucket]
|
|
9815
|
+
)) {
|
|
9179
9816
|
throw new CLIError({
|
|
9180
9817
|
message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
|
|
9181
9818
|
docUrl: "bucketNotFound"
|
|
@@ -9187,7 +9824,7 @@ function validateParams2(i18nConfig, flags) {
|
|
|
9187
9824
|
import { Command as Command19 } from "interactive-commander";
|
|
9188
9825
|
import * as cp from "node:child_process";
|
|
9189
9826
|
import figlet2 from "figlet";
|
|
9190
|
-
import
|
|
9827
|
+
import chalk15 from "chalk";
|
|
9191
9828
|
import { vice as vice2 } from "gradient-string";
|
|
9192
9829
|
var colors2 = {
|
|
9193
9830
|
orange: "#ff6600",
|
|
@@ -9201,7 +9838,7 @@ var may_the_fourth_default = new Command19().command("may-the-fourth").descripti
|
|
|
9201
9838
|
await renderClear2();
|
|
9202
9839
|
await renderBanner2();
|
|
9203
9840
|
await renderSpacer2();
|
|
9204
|
-
console.log(
|
|
9841
|
+
console.log(chalk15.hex(colors2.yellow)("Loading the Star Wars movie..."));
|
|
9205
9842
|
await renderSpacer2();
|
|
9206
9843
|
await new Promise((resolve, reject) => {
|
|
9207
9844
|
const ssh = cp.spawn("ssh", ["starwarstel.net"], {
|
|
@@ -9220,10 +9857,12 @@ var may_the_fourth_default = new Command19().command("may-the-fourth").descripti
|
|
|
9220
9857
|
});
|
|
9221
9858
|
await renderSpacer2();
|
|
9222
9859
|
console.log(
|
|
9223
|
-
`${
|
|
9860
|
+
`${chalk15.hex(colors2.green)("We hope you enjoyed it! :)")} ${chalk15.hex(
|
|
9861
|
+
colors2.blue
|
|
9862
|
+
)("May the Fourth be with you! \u{1F680}")}`
|
|
9224
9863
|
);
|
|
9225
9864
|
await renderSpacer2();
|
|
9226
|
-
console.log(
|
|
9865
|
+
console.log(chalk15.dim(`---`));
|
|
9227
9866
|
await renderSpacer2();
|
|
9228
9867
|
await renderHero2();
|
|
9229
9868
|
});
|
|
@@ -9246,19 +9885,21 @@ async function renderBanner2() {
|
|
|
9246
9885
|
}
|
|
9247
9886
|
async function renderHero2() {
|
|
9248
9887
|
console.log(
|
|
9249
|
-
`\u26A1\uFE0F ${
|
|
9888
|
+
`\u26A1\uFE0F ${chalk15.hex(colors2.green)(
|
|
9889
|
+
"Lingo.dev"
|
|
9890
|
+
)} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
9250
9891
|
);
|
|
9251
9892
|
console.log(" ");
|
|
9252
9893
|
console.log(
|
|
9253
|
-
|
|
9894
|
+
chalk15.hex(colors2.blue)("\u2B50 GitHub Repo: https://lingo.dev/go/gh")
|
|
9254
9895
|
);
|
|
9255
|
-
console.log(
|
|
9896
|
+
console.log(chalk15.hex(colors2.blue)("\u{1F4AC} 24/7 Support: hi@lingo.dev"));
|
|
9256
9897
|
}
|
|
9257
9898
|
|
|
9258
9899
|
// package.json
|
|
9259
9900
|
var package_default = {
|
|
9260
9901
|
name: "lingo.dev",
|
|
9261
|
-
version: "0.
|
|
9902
|
+
version: "0.102.0",
|
|
9262
9903
|
description: "Lingo.dev CLI",
|
|
9263
9904
|
private: false,
|
|
9264
9905
|
publishConfig: {
|
|
@@ -9372,6 +10013,7 @@ var package_default = {
|
|
|
9372
10013
|
dependencies: {
|
|
9373
10014
|
"@ai-sdk/anthropic": "^1.2.11",
|
|
9374
10015
|
"@ai-sdk/google": "^1.2.19",
|
|
10016
|
+
"@ai-sdk/mistral": "^1.2.8",
|
|
9375
10017
|
"@ai-sdk/openai": "^1.3.22",
|
|
9376
10018
|
"@babel/generator": "^7.27.1",
|
|
9377
10019
|
"@babel/parser": "^7.27.1",
|
|
@@ -9392,6 +10034,7 @@ var package_default = {
|
|
|
9392
10034
|
ai: "^4.3.15",
|
|
9393
10035
|
bitbucket: "^2.12.0",
|
|
9394
10036
|
chalk: "^5.4.1",
|
|
10037
|
+
chokidar: "^4.0.3",
|
|
9395
10038
|
"cli-progress": "^3.12.0",
|
|
9396
10039
|
"cli-table3": "^0.6.5",
|
|
9397
10040
|
cors: "^2.8.5",
|
|
@@ -9460,6 +10103,7 @@ var package_default = {
|
|
|
9460
10103
|
},
|
|
9461
10104
|
devDependencies: {
|
|
9462
10105
|
"@types/babel__generator": "^7.27.0",
|
|
10106
|
+
"@types/chokidar": "^2.1.7",
|
|
9463
10107
|
"@types/cli-progress": "^3.11.6",
|
|
9464
10108
|
"@types/cors": "^2.8.17",
|
|
9465
10109
|
"@types/diff": "^7.0.0",
|
|
@@ -9488,6 +10132,167 @@ var package_default = {
|
|
|
9488
10132
|
packageManager: "pnpm@9.12.3"
|
|
9489
10133
|
};
|
|
9490
10134
|
|
|
10135
|
+
// src/cli/cmd/purge.ts
|
|
10136
|
+
import { Command as Command20 } from "interactive-commander";
|
|
10137
|
+
import Ora11 from "ora";
|
|
10138
|
+
import { resolveOverriddenLocale as resolveOverriddenLocale8 } from "@lingo.dev/_spec";
|
|
10139
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
10140
|
+
var purge_default = new Command20().command("purge").description(
|
|
10141
|
+
"Remove translations for given --bucket, --file, --key, --locale"
|
|
10142
|
+
).helpOption("-h, --help", "Show help").option(
|
|
10143
|
+
"--bucket <bucket>",
|
|
10144
|
+
"Bucket to process",
|
|
10145
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
10146
|
+
).option(
|
|
10147
|
+
"--file [files...]",
|
|
10148
|
+
"File(s) to process. Only process files that match the given glob pattern(s)."
|
|
10149
|
+
).option(
|
|
10150
|
+
"--key <key>",
|
|
10151
|
+
"Key to remove. Remove all translation keys matching the given glob pattern."
|
|
10152
|
+
).option(
|
|
10153
|
+
"--locale <locale>",
|
|
10154
|
+
"Locale to process",
|
|
10155
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
10156
|
+
).option(
|
|
10157
|
+
"--yes-really",
|
|
10158
|
+
"Skip interactive confirmation and delete without asking."
|
|
10159
|
+
).action(async function(options) {
|
|
10160
|
+
const ora = Ora11();
|
|
10161
|
+
try {
|
|
10162
|
+
ora.start("Loading configuration...");
|
|
10163
|
+
const i18nConfig = getConfig();
|
|
10164
|
+
if (!i18nConfig) {
|
|
10165
|
+
throw new Error("i18n.json not found. Please run `lingo.dev init`.");
|
|
10166
|
+
}
|
|
10167
|
+
ora.succeed("Configuration loaded");
|
|
10168
|
+
let buckets = getBuckets(i18nConfig);
|
|
10169
|
+
if (options.bucket && options.bucket.length) {
|
|
10170
|
+
buckets = buckets.filter(
|
|
10171
|
+
(bucket) => options.bucket.includes(bucket.type)
|
|
10172
|
+
);
|
|
10173
|
+
}
|
|
10174
|
+
if (options.file && options.file.length) {
|
|
10175
|
+
buckets = buckets.map((bucket) => {
|
|
10176
|
+
const paths = bucket.paths.filter(
|
|
10177
|
+
(bucketPath) => options.file?.some((f) => bucketPath.pathPattern.includes(f))
|
|
10178
|
+
);
|
|
10179
|
+
return { ...bucket, paths };
|
|
10180
|
+
}).filter((bucket) => bucket.paths.length > 0);
|
|
10181
|
+
if (buckets.length === 0) {
|
|
10182
|
+
ora.fail("All files were filtered out by --file option.");
|
|
10183
|
+
process.exit(1);
|
|
10184
|
+
}
|
|
10185
|
+
}
|
|
10186
|
+
const sourceLocale = i18nConfig.locale.source;
|
|
10187
|
+
const targetLocales = options.locale && options.locale.length ? options.locale : i18nConfig.locale.targets;
|
|
10188
|
+
let removedAny = false;
|
|
10189
|
+
for (const bucket of buckets) {
|
|
10190
|
+
console.log();
|
|
10191
|
+
ora.info(`Processing bucket: ${bucket.type}`);
|
|
10192
|
+
for (const bucketPath of bucket.paths) {
|
|
10193
|
+
for (const _targetLocale of targetLocales) {
|
|
10194
|
+
const targetLocale = resolveOverriddenLocale8(
|
|
10195
|
+
_targetLocale,
|
|
10196
|
+
bucketPath.delimiter
|
|
10197
|
+
);
|
|
10198
|
+
const bucketOra = Ora11({ indent: 2 }).start(
|
|
10199
|
+
`Processing path: ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10200
|
+
);
|
|
10201
|
+
try {
|
|
10202
|
+
const bucketLoader = createBucketLoader(
|
|
10203
|
+
bucket.type,
|
|
10204
|
+
bucketPath.pathPattern,
|
|
10205
|
+
{
|
|
10206
|
+
defaultLocale: sourceLocale,
|
|
10207
|
+
injectLocale: bucket.injectLocale
|
|
10208
|
+
},
|
|
10209
|
+
bucket.lockedKeys,
|
|
10210
|
+
bucket.lockedPatterns,
|
|
10211
|
+
bucket.ignoredKeys
|
|
10212
|
+
);
|
|
10213
|
+
await bucketLoader.init();
|
|
10214
|
+
bucketLoader.setDefaultLocale(sourceLocale);
|
|
10215
|
+
await bucketLoader.pull(sourceLocale);
|
|
10216
|
+
let targetData = await bucketLoader.pull(targetLocale);
|
|
10217
|
+
if (!targetData || Object.keys(targetData).length === 0) {
|
|
10218
|
+
bucketOra.info(
|
|
10219
|
+
`No translations found for ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10220
|
+
);
|
|
10221
|
+
continue;
|
|
10222
|
+
}
|
|
10223
|
+
let newData = { ...targetData };
|
|
10224
|
+
let keysToRemove = [];
|
|
10225
|
+
if (options.key) {
|
|
10226
|
+
keysToRemove = Object.keys(newData).filter(
|
|
10227
|
+
(k) => minimatch(k, options.key)
|
|
10228
|
+
);
|
|
10229
|
+
} else {
|
|
10230
|
+
keysToRemove = Object.keys(newData);
|
|
10231
|
+
}
|
|
10232
|
+
if (keysToRemove.length > 0) {
|
|
10233
|
+
if (options.key) {
|
|
10234
|
+
bucketOra.info(
|
|
10235
|
+
`About to delete ${keysToRemove.length} key(s) matching '${options.key}' from ${bucketPath.pathPattern} [${targetLocale}]:
|
|
10236
|
+
${keysToRemove.slice(0, 10).join(", ")}${keysToRemove.length > 10 ? ", ..." : ""}`
|
|
10237
|
+
);
|
|
10238
|
+
} else {
|
|
10239
|
+
bucketOra.info(
|
|
10240
|
+
`About to delete all (${keysToRemove.length}) keys from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10241
|
+
);
|
|
10242
|
+
}
|
|
10243
|
+
if (!options.yesReally) {
|
|
10244
|
+
bucketOra.warn(
|
|
10245
|
+
"This is a destructive operation. If you are sure, type 'y' to continue. (Use --yes-really to skip this check.)"
|
|
10246
|
+
);
|
|
10247
|
+
const confirmed = await confirm3({
|
|
10248
|
+
message: `Delete these keys from ${bucketPath.pathPattern} [${targetLocale}]?`,
|
|
10249
|
+
default: false
|
|
10250
|
+
});
|
|
10251
|
+
if (!confirmed) {
|
|
10252
|
+
bucketOra.info("Skipped by user.");
|
|
10253
|
+
continue;
|
|
10254
|
+
}
|
|
10255
|
+
}
|
|
10256
|
+
for (const key of keysToRemove) {
|
|
10257
|
+
delete newData[key];
|
|
10258
|
+
}
|
|
10259
|
+
removedAny = true;
|
|
10260
|
+
await bucketLoader.push(targetLocale, newData);
|
|
10261
|
+
if (options.key) {
|
|
10262
|
+
bucketOra.succeed(
|
|
10263
|
+
`Removed ${keysToRemove.length} key(s) matching '${options.key}' from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10264
|
+
);
|
|
10265
|
+
} else {
|
|
10266
|
+
bucketOra.succeed(
|
|
10267
|
+
`Removed all keys (${keysToRemove.length}) from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10268
|
+
);
|
|
10269
|
+
}
|
|
10270
|
+
} else if (options.key) {
|
|
10271
|
+
bucketOra.info(
|
|
10272
|
+
`No keys matching '${options.key}' found in ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10273
|
+
);
|
|
10274
|
+
} else {
|
|
10275
|
+
bucketOra.info("No keys to remove.");
|
|
10276
|
+
}
|
|
10277
|
+
} catch (error) {
|
|
10278
|
+
const err = error;
|
|
10279
|
+
bucketOra.fail(`Failed: ${err.message}`);
|
|
10280
|
+
}
|
|
10281
|
+
}
|
|
10282
|
+
}
|
|
10283
|
+
}
|
|
10284
|
+
if (!removedAny) {
|
|
10285
|
+
ora.info("No keys were removed.");
|
|
10286
|
+
} else {
|
|
10287
|
+
ora.succeed("Purge completed.");
|
|
10288
|
+
}
|
|
10289
|
+
} catch (error) {
|
|
10290
|
+
const err = error;
|
|
10291
|
+
ora.fail(err.message);
|
|
10292
|
+
process.exit(1);
|
|
10293
|
+
}
|
|
10294
|
+
});
|
|
10295
|
+
|
|
9491
10296
|
// src/cli/index.ts
|
|
9492
10297
|
dotenv.config();
|
|
9493
10298
|
var cli_default = new InteractiveCommand2().name("lingo.dev").description("Lingo.dev CLI").helpOption("-h, --help", "Show help").addHelpText(
|
|
@@ -9505,7 +10310,7 @@ ${vice3(
|
|
|
9505
10310
|
|
|
9506
10311
|
Star the the repo :) https://github.com/LingoDotDev/lingo.dev
|
|
9507
10312
|
`
|
|
9508
|
-
).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(login_default).addCommand(logout_default).addCommand(show_default).addCommand(config_default2).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
|
|
10313
|
+
).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(login_default).addCommand(logout_default).addCommand(show_default).addCommand(config_default2).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).addCommand(purge_default).exitOverride((err) => {
|
|
9509
10314
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
9510
10315
|
process.exit(0);
|
|
9511
10316
|
}
|