lingo.dev 0.100.1 → 0.101.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 +1102 -439
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +1037 -374
- package/build/cli.mjs.map +1 -1
- package/package.json +5 -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,53 @@ 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
|
+
if (data[key]) {
|
|
4546
|
+
orderedData[key] = reorderKeys(data[key], originalInput[key]);
|
|
4547
|
+
}
|
|
4548
|
+
dataKeys.delete(key);
|
|
4549
|
+
}
|
|
4550
|
+
}
|
|
4551
|
+
return orderedData;
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4258
4554
|
// src/cli/loaders/index.ts
|
|
4259
4555
|
function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys, lockedPatterns, ignoredKeys) {
|
|
4260
4556
|
switch (bucketType) {
|
|
@@ -4264,23 +4560,19 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4264
4560
|
return composeLoaders(
|
|
4265
4561
|
createTextFileLoader(bucketPathPattern),
|
|
4266
4562
|
createAndroidLoader(),
|
|
4563
|
+
createEnsureKeyOrderLoader(),
|
|
4267
4564
|
createFlatLoader(),
|
|
4268
4565
|
createSyncLoader(),
|
|
4269
|
-
createUnlocalizableLoader(
|
|
4270
|
-
options.isCacheRestore,
|
|
4271
|
-
options.returnUnlocalizedKeys
|
|
4272
|
-
)
|
|
4566
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4273
4567
|
);
|
|
4274
4568
|
case "csv":
|
|
4275
4569
|
return composeLoaders(
|
|
4276
4570
|
createTextFileLoader(bucketPathPattern),
|
|
4277
4571
|
createCsvLoader(),
|
|
4572
|
+
createEnsureKeyOrderLoader(),
|
|
4278
4573
|
createFlatLoader(),
|
|
4279
4574
|
createSyncLoader(),
|
|
4280
|
-
createUnlocalizableLoader(
|
|
4281
|
-
options.isCacheRestore,
|
|
4282
|
-
options.returnUnlocalizedKeys
|
|
4283
|
-
)
|
|
4575
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4284
4576
|
);
|
|
4285
4577
|
case "html":
|
|
4286
4578
|
return composeLoaders(
|
|
@@ -4288,34 +4580,26 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4288
4580
|
createPrettierLoader({ parser: "html", bucketPathPattern }),
|
|
4289
4581
|
createHtmlLoader(),
|
|
4290
4582
|
createSyncLoader(),
|
|
4291
|
-
createUnlocalizableLoader(
|
|
4292
|
-
options.isCacheRestore,
|
|
4293
|
-
options.returnUnlocalizedKeys
|
|
4294
|
-
)
|
|
4583
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4295
4584
|
);
|
|
4296
4585
|
case "ejs":
|
|
4297
4586
|
return composeLoaders(
|
|
4298
4587
|
createTextFileLoader(bucketPathPattern),
|
|
4299
4588
|
createEjsLoader(),
|
|
4300
4589
|
createSyncLoader(),
|
|
4301
|
-
createUnlocalizableLoader(
|
|
4302
|
-
options.isCacheRestore,
|
|
4303
|
-
options.returnUnlocalizedKeys
|
|
4304
|
-
)
|
|
4590
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4305
4591
|
);
|
|
4306
4592
|
case "json":
|
|
4307
4593
|
return composeLoaders(
|
|
4308
4594
|
createTextFileLoader(bucketPathPattern),
|
|
4309
4595
|
createPrettierLoader({ parser: "json", bucketPathPattern }),
|
|
4310
4596
|
createJsonLoader(),
|
|
4597
|
+
createEnsureKeyOrderLoader(),
|
|
4311
4598
|
createInjectLocaleLoader(options.injectLocale),
|
|
4312
4599
|
createFlatLoader(),
|
|
4313
|
-
createLockedKeysLoader(lockedKeys || []
|
|
4600
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4314
4601
|
createSyncLoader(),
|
|
4315
|
-
createUnlocalizableLoader(
|
|
4316
|
-
options.isCacheRestore,
|
|
4317
|
-
options.returnUnlocalizedKeys
|
|
4318
|
-
)
|
|
4602
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4319
4603
|
);
|
|
4320
4604
|
case "markdown":
|
|
4321
4605
|
return composeLoaders(
|
|
@@ -4323,10 +4607,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4323
4607
|
createPrettierLoader({ parser: "markdown", bucketPathPattern }),
|
|
4324
4608
|
createMarkdownLoader(),
|
|
4325
4609
|
createSyncLoader(),
|
|
4326
|
-
createUnlocalizableLoader(
|
|
4327
|
-
options.isCacheRestore,
|
|
4328
|
-
options.returnUnlocalizedKeys
|
|
4329
|
-
)
|
|
4610
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4330
4611
|
);
|
|
4331
4612
|
case "mdx":
|
|
4332
4613
|
return composeLoaders(
|
|
@@ -4341,55 +4622,43 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4341
4622
|
createMdxSectionsSplit2Loader(),
|
|
4342
4623
|
createLocalizableMdxDocumentLoader(),
|
|
4343
4624
|
createFlatLoader(),
|
|
4344
|
-
|
|
4625
|
+
createEnsureKeyOrderLoader(),
|
|
4626
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4345
4627
|
createSyncLoader(),
|
|
4346
|
-
createUnlocalizableLoader(
|
|
4347
|
-
options.isCacheRestore,
|
|
4348
|
-
options.returnUnlocalizedKeys
|
|
4349
|
-
)
|
|
4628
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4350
4629
|
);
|
|
4351
4630
|
case "po":
|
|
4352
4631
|
return composeLoaders(
|
|
4353
4632
|
createTextFileLoader(bucketPathPattern),
|
|
4354
4633
|
createPoLoader(),
|
|
4355
4634
|
createFlatLoader(),
|
|
4635
|
+
createEnsureKeyOrderLoader(),
|
|
4356
4636
|
createSyncLoader(),
|
|
4357
4637
|
createVariableLoader({ type: "python" }),
|
|
4358
|
-
createUnlocalizableLoader(
|
|
4359
|
-
options.isCacheRestore,
|
|
4360
|
-
options.returnUnlocalizedKeys
|
|
4361
|
-
)
|
|
4638
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4362
4639
|
);
|
|
4363
4640
|
case "properties":
|
|
4364
4641
|
return composeLoaders(
|
|
4365
4642
|
createTextFileLoader(bucketPathPattern),
|
|
4366
4643
|
createPropertiesLoader(),
|
|
4367
4644
|
createSyncLoader(),
|
|
4368
|
-
createUnlocalizableLoader(
|
|
4369
|
-
options.isCacheRestore,
|
|
4370
|
-
options.returnUnlocalizedKeys
|
|
4371
|
-
)
|
|
4645
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4372
4646
|
);
|
|
4373
4647
|
case "xcode-strings":
|
|
4374
4648
|
return composeLoaders(
|
|
4375
4649
|
createTextFileLoader(bucketPathPattern),
|
|
4376
4650
|
createXcodeStringsLoader(),
|
|
4377
4651
|
createSyncLoader(),
|
|
4378
|
-
createUnlocalizableLoader(
|
|
4379
|
-
options.isCacheRestore,
|
|
4380
|
-
options.returnUnlocalizedKeys
|
|
4381
|
-
)
|
|
4652
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4382
4653
|
);
|
|
4383
4654
|
case "xcode-stringsdict":
|
|
4384
4655
|
return composeLoaders(
|
|
4385
4656
|
createTextFileLoader(bucketPathPattern),
|
|
4386
4657
|
createXcodeStringsdictLoader(),
|
|
4387
4658
|
createFlatLoader(),
|
|
4659
|
+
createEnsureKeyOrderLoader(),
|
|
4388
4660
|
createSyncLoader(),
|
|
4389
|
-
createUnlocalizableLoader(
|
|
4390
|
-
options.isCacheRestore,
|
|
4391
|
-
options.returnUnlocalizedKeys
|
|
4392
|
-
)
|
|
4661
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4393
4662
|
);
|
|
4394
4663
|
case "xcode-xcstrings":
|
|
4395
4664
|
return composeLoaders(
|
|
@@ -4398,12 +4667,10 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4398
4667
|
createJsonLoader(),
|
|
4399
4668
|
createXcodeXcstringsLoader(options.defaultLocale),
|
|
4400
4669
|
createFlatLoader(),
|
|
4670
|
+
createEnsureKeyOrderLoader(),
|
|
4401
4671
|
createSyncLoader(),
|
|
4402
4672
|
createVariableLoader({ type: "ieee" }),
|
|
4403
|
-
createUnlocalizableLoader(
|
|
4404
|
-
options.isCacheRestore,
|
|
4405
|
-
options.returnUnlocalizedKeys
|
|
4406
|
-
)
|
|
4673
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4407
4674
|
);
|
|
4408
4675
|
case "yaml":
|
|
4409
4676
|
return composeLoaders(
|
|
@@ -4411,12 +4678,10 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4411
4678
|
createPrettierLoader({ parser: "yaml", bucketPathPattern }),
|
|
4412
4679
|
createYamlLoader(),
|
|
4413
4680
|
createFlatLoader(),
|
|
4414
|
-
|
|
4681
|
+
createEnsureKeyOrderLoader(),
|
|
4682
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4415
4683
|
createSyncLoader(),
|
|
4416
|
-
createUnlocalizableLoader(
|
|
4417
|
-
options.isCacheRestore,
|
|
4418
|
-
options.returnUnlocalizedKeys
|
|
4419
|
-
)
|
|
4684
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4420
4685
|
);
|
|
4421
4686
|
case "yaml-root-key":
|
|
4422
4687
|
return composeLoaders(
|
|
@@ -4425,76 +4690,60 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4425
4690
|
createYamlLoader(),
|
|
4426
4691
|
createRootKeyLoader(true),
|
|
4427
4692
|
createFlatLoader(),
|
|
4693
|
+
createEnsureKeyOrderLoader(),
|
|
4428
4694
|
createSyncLoader(),
|
|
4429
|
-
createUnlocalizableLoader(
|
|
4430
|
-
options.isCacheRestore,
|
|
4431
|
-
options.returnUnlocalizedKeys
|
|
4432
|
-
)
|
|
4695
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4433
4696
|
);
|
|
4434
4697
|
case "flutter":
|
|
4435
4698
|
return composeLoaders(
|
|
4436
4699
|
createTextFileLoader(bucketPathPattern),
|
|
4437
4700
|
createPrettierLoader({ parser: "json", bucketPathPattern }),
|
|
4438
4701
|
createJsonLoader(),
|
|
4702
|
+
createEnsureKeyOrderLoader(),
|
|
4439
4703
|
createFlutterLoader(),
|
|
4440
4704
|
createFlatLoader(),
|
|
4441
4705
|
createSyncLoader(),
|
|
4442
|
-
createUnlocalizableLoader(
|
|
4443
|
-
options.isCacheRestore,
|
|
4444
|
-
options.returnUnlocalizedKeys
|
|
4445
|
-
)
|
|
4706
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4446
4707
|
);
|
|
4447
4708
|
case "xliff":
|
|
4448
4709
|
return composeLoaders(
|
|
4449
4710
|
createTextFileLoader(bucketPathPattern),
|
|
4450
4711
|
createXliffLoader(),
|
|
4451
4712
|
createFlatLoader(),
|
|
4713
|
+
createEnsureKeyOrderLoader(),
|
|
4452
4714
|
createSyncLoader(),
|
|
4453
|
-
createUnlocalizableLoader(
|
|
4454
|
-
options.isCacheRestore,
|
|
4455
|
-
options.returnUnlocalizedKeys
|
|
4456
|
-
)
|
|
4715
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4457
4716
|
);
|
|
4458
4717
|
case "xml":
|
|
4459
4718
|
return composeLoaders(
|
|
4460
4719
|
createTextFileLoader(bucketPathPattern),
|
|
4461
4720
|
createXmlLoader(),
|
|
4462
4721
|
createFlatLoader(),
|
|
4722
|
+
createEnsureKeyOrderLoader(),
|
|
4463
4723
|
createSyncLoader(),
|
|
4464
|
-
createUnlocalizableLoader(
|
|
4465
|
-
options.isCacheRestore,
|
|
4466
|
-
options.returnUnlocalizedKeys
|
|
4467
|
-
)
|
|
4724
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4468
4725
|
);
|
|
4469
4726
|
case "srt":
|
|
4470
4727
|
return composeLoaders(
|
|
4471
4728
|
createTextFileLoader(bucketPathPattern),
|
|
4472
4729
|
createSrtLoader(),
|
|
4473
4730
|
createSyncLoader(),
|
|
4474
|
-
createUnlocalizableLoader(
|
|
4475
|
-
options.isCacheRestore,
|
|
4476
|
-
options.returnUnlocalizedKeys
|
|
4477
|
-
)
|
|
4731
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4478
4732
|
);
|
|
4479
4733
|
case "dato":
|
|
4480
4734
|
return composeLoaders(
|
|
4481
4735
|
createDatoLoader(bucketPathPattern),
|
|
4482
4736
|
createSyncLoader(),
|
|
4483
4737
|
createFlatLoader(),
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
options.returnUnlocalizedKeys
|
|
4487
|
-
)
|
|
4738
|
+
createEnsureKeyOrderLoader(),
|
|
4739
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4488
4740
|
);
|
|
4489
4741
|
case "vtt":
|
|
4490
4742
|
return composeLoaders(
|
|
4491
4743
|
createTextFileLoader(bucketPathPattern),
|
|
4492
4744
|
createVttLoader(),
|
|
4493
4745
|
createSyncLoader(),
|
|
4494
|
-
createUnlocalizableLoader(
|
|
4495
|
-
options.isCacheRestore,
|
|
4496
|
-
options.returnUnlocalizedKeys
|
|
4497
|
-
)
|
|
4746
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4498
4747
|
);
|
|
4499
4748
|
case "php":
|
|
4500
4749
|
return composeLoaders(
|
|
@@ -4502,10 +4751,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4502
4751
|
createPhpLoader(),
|
|
4503
4752
|
createSyncLoader(),
|
|
4504
4753
|
createFlatLoader(),
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
options.returnUnlocalizedKeys
|
|
4508
|
-
)
|
|
4754
|
+
createEnsureKeyOrderLoader(),
|
|
4755
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4509
4756
|
);
|
|
4510
4757
|
case "vue-json":
|
|
4511
4758
|
return composeLoaders(
|
|
@@ -4513,10 +4760,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4513
4760
|
createVueJsonLoader(),
|
|
4514
4761
|
createSyncLoader(),
|
|
4515
4762
|
createFlatLoader(),
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
options.returnUnlocalizedKeys
|
|
4519
|
-
)
|
|
4763
|
+
createEnsureKeyOrderLoader(),
|
|
4764
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4520
4765
|
);
|
|
4521
4766
|
case "typescript":
|
|
4522
4767
|
return composeLoaders(
|
|
@@ -4524,13 +4769,11 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
4524
4769
|
createPrettierLoader({ parser: "typescript", bucketPathPattern }),
|
|
4525
4770
|
createTypescriptLoader(),
|
|
4526
4771
|
createFlatLoader(),
|
|
4772
|
+
createEnsureKeyOrderLoader(),
|
|
4527
4773
|
createSyncLoader(),
|
|
4528
|
-
createLockedKeysLoader(lockedKeys || []
|
|
4774
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
4529
4775
|
createIgnoredKeysLoader(ignoredKeys || []),
|
|
4530
|
-
createUnlocalizableLoader(
|
|
4531
|
-
options.isCacheRestore,
|
|
4532
|
-
options.returnUnlocalizedKeys
|
|
4533
|
-
)
|
|
4776
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
4534
4777
|
);
|
|
4535
4778
|
}
|
|
4536
4779
|
}
|
|
@@ -4574,7 +4817,7 @@ function createLingoLocalizer(params) {
|
|
|
4574
4817
|
|
|
4575
4818
|
// src/cli/processor/basic.ts
|
|
4576
4819
|
import { generateText } from "ai";
|
|
4577
|
-
import
|
|
4820
|
+
import _28 from "lodash";
|
|
4578
4821
|
function createBasicTranslator(model, systemPrompt) {
|
|
4579
4822
|
return async (input2, onProgress) => {
|
|
4580
4823
|
const chunks = extractPayloadChunks(input2.processableData);
|
|
@@ -4588,7 +4831,7 @@ function createBasicTranslator(model, systemPrompt) {
|
|
|
4588
4831
|
subResults.push(result2);
|
|
4589
4832
|
onProgress(i / chunks.length * 100, chunk, result2);
|
|
4590
4833
|
}
|
|
4591
|
-
const result =
|
|
4834
|
+
const result = _28.merge({}, ...subResults);
|
|
4592
4835
|
return result;
|
|
4593
4836
|
};
|
|
4594
4837
|
async function doJob(input2) {
|
|
@@ -4679,6 +4922,7 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|
|
4679
4922
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
4680
4923
|
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
4681
4924
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
4925
|
+
import { createMistral } from "@ai-sdk/mistral";
|
|
4682
4926
|
import { createOllama } from "ollama-ai-provider";
|
|
4683
4927
|
function createProcessor(provider, params) {
|
|
4684
4928
|
if (!provider) {
|
|
@@ -4696,7 +4940,11 @@ function getPureModelProvider(provider) {
|
|
|
4696
4940
|
|
|
4697
4941
|
To fix this issue:
|
|
4698
4942
|
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(
|
|
4943
|
+
2. Remove the ${chalk5.italic(
|
|
4944
|
+
"provider"
|
|
4945
|
+
)} node from your i18n.json configuration to switch to ${chalk5.hex(
|
|
4946
|
+
colors.green
|
|
4947
|
+
)("Lingo.dev")}
|
|
4700
4948
|
|
|
4701
4949
|
${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4702
4950
|
`;
|
|
@@ -4705,7 +4953,11 @@ function getPureModelProvider(provider) {
|
|
|
4705
4953
|
|
|
4706
4954
|
To fix this issue:
|
|
4707
4955
|
1. Switch to one of the supported providers, or
|
|
4708
|
-
2. Remove the ${chalk5.italic(
|
|
4956
|
+
2. Remove the ${chalk5.italic(
|
|
4957
|
+
"provider"
|
|
4958
|
+
)} node from your i18n.json configuration to switch to ${chalk5.hex(
|
|
4959
|
+
colors.green
|
|
4960
|
+
)("Lingo.dev")}
|
|
4709
4961
|
|
|
4710
4962
|
${chalk5.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
4711
4963
|
`;
|
|
@@ -4755,6 +5007,17 @@ function getPureModelProvider(provider) {
|
|
|
4755
5007
|
case "ollama": {
|
|
4756
5008
|
return createOllama()(provider.model);
|
|
4757
5009
|
}
|
|
5010
|
+
case "mistral": {
|
|
5011
|
+
if (!process.env.MISTRAL_API_KEY) {
|
|
5012
|
+
throw new Error(
|
|
5013
|
+
createMissingKeyErrorMessage("Mistral", "MISTRAL_API_KEY")
|
|
5014
|
+
);
|
|
5015
|
+
}
|
|
5016
|
+
return createMistral({
|
|
5017
|
+
apiKey: process.env.MISTRAL_API_KEY,
|
|
5018
|
+
baseURL: provider.baseUrl
|
|
5019
|
+
})(provider.model);
|
|
5020
|
+
}
|
|
4758
5021
|
default: {
|
|
4759
5022
|
throw new Error(createUnsupportedProviderErrorMessage(provider?.id));
|
|
4760
5023
|
}
|
|
@@ -4815,7 +5078,7 @@ async function trackEvent(distinctId, event, properties) {
|
|
|
4815
5078
|
}
|
|
4816
5079
|
|
|
4817
5080
|
// src/cli/utils/delta.ts
|
|
4818
|
-
import
|
|
5081
|
+
import _29 from "lodash";
|
|
4819
5082
|
import z from "zod";
|
|
4820
5083
|
|
|
4821
5084
|
// src/cli/utils/fs.ts
|
|
@@ -4864,11 +5127,17 @@ function createDeltaProcessor(fileKey) {
|
|
|
4864
5127
|
return checkIfFileExists(lockfilePath);
|
|
4865
5128
|
},
|
|
4866
5129
|
async calculateDelta(params) {
|
|
4867
|
-
let added =
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
5130
|
+
let added = _29.difference(
|
|
5131
|
+
Object.keys(params.sourceData),
|
|
5132
|
+
Object.keys(params.targetData)
|
|
5133
|
+
);
|
|
5134
|
+
let removed = _29.difference(
|
|
5135
|
+
Object.keys(params.targetData),
|
|
5136
|
+
Object.keys(params.sourceData)
|
|
5137
|
+
);
|
|
5138
|
+
const updated = Object.keys(params.sourceData).filter(
|
|
5139
|
+
(key) => md5(params.sourceData[key]) !== params.checksums[key] && params.checksums[key]
|
|
5140
|
+
);
|
|
4872
5141
|
const renamed = [];
|
|
4873
5142
|
for (const addedKey of added) {
|
|
4874
5143
|
const addedHash = md5(params.sourceData[addedKey]);
|
|
@@ -4879,9 +5148,18 @@ function createDeltaProcessor(fileKey) {
|
|
|
4879
5148
|
}
|
|
4880
5149
|
}
|
|
4881
5150
|
}
|
|
4882
|
-
added = added.filter(
|
|
4883
|
-
|
|
4884
|
-
|
|
5151
|
+
added = added.filter(
|
|
5152
|
+
(key) => !renamed.some(([oldKey, newKey]) => newKey === key)
|
|
5153
|
+
);
|
|
5154
|
+
removed = removed.filter(
|
|
5155
|
+
(key) => !renamed.some(([oldKey, newKey]) => oldKey === key)
|
|
5156
|
+
);
|
|
5157
|
+
const hasChanges = [
|
|
5158
|
+
added.length > 0,
|
|
5159
|
+
removed.length > 0,
|
|
5160
|
+
updated.length > 0,
|
|
5161
|
+
renamed.length > 0
|
|
5162
|
+
].some((v) => v);
|
|
4885
5163
|
return {
|
|
4886
5164
|
added,
|
|
4887
5165
|
removed,
|
|
@@ -4915,7 +5193,7 @@ function createDeltaProcessor(fileKey) {
|
|
|
4915
5193
|
await this.saveLock(lockfileData);
|
|
4916
5194
|
},
|
|
4917
5195
|
async createChecksums(sourceData) {
|
|
4918
|
-
const checksums =
|
|
5196
|
+
const checksums = _29.mapValues(sourceData, (value) => md5(value));
|
|
4919
5197
|
return checksums;
|
|
4920
5198
|
}
|
|
4921
5199
|
};
|
|
@@ -5039,7 +5317,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5039
5317
|
bucket.type,
|
|
5040
5318
|
bucketPath.pathPattern,
|
|
5041
5319
|
{
|
|
5042
|
-
isCacheRestore: false,
|
|
5043
5320
|
defaultLocale: sourceLocale,
|
|
5044
5321
|
injectLocale: bucket.injectLocale
|
|
5045
5322
|
},
|
|
@@ -5074,7 +5351,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5074
5351
|
bucket.type,
|
|
5075
5352
|
bucketPath.pathPattern,
|
|
5076
5353
|
{
|
|
5077
|
-
isCacheRestore: false,
|
|
5078
5354
|
defaultLocale: sourceLocale,
|
|
5079
5355
|
returnUnlocalizedKeys: true,
|
|
5080
5356
|
injectLocale: bucket.injectLocale
|
|
@@ -5087,7 +5363,7 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5087
5363
|
const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
|
|
5088
5364
|
const sourceChecksums = await deltaProcessor.createChecksums(sourceData);
|
|
5089
5365
|
const savedChecksums = await deltaProcessor.loadChecksums();
|
|
5090
|
-
const updatedSourceData =
|
|
5366
|
+
const updatedSourceData = _30.pickBy(
|
|
5091
5367
|
sourceData,
|
|
5092
5368
|
(value, key) => sourceChecksums[key] !== savedChecksums[key]
|
|
5093
5369
|
);
|
|
@@ -5101,15 +5377,15 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5101
5377
|
bucketPath.delimiter
|
|
5102
5378
|
);
|
|
5103
5379
|
const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
|
|
5104
|
-
const missingKeys =
|
|
5380
|
+
const missingKeys = _30.difference(
|
|
5105
5381
|
Object.keys(sourceData),
|
|
5106
5382
|
Object.keys(targetData)
|
|
5107
5383
|
);
|
|
5108
|
-
const extraKeys =
|
|
5384
|
+
const extraKeys = _30.difference(
|
|
5109
5385
|
Object.keys(targetData),
|
|
5110
5386
|
Object.keys(sourceData)
|
|
5111
5387
|
);
|
|
5112
|
-
const unlocalizableDataDiff = !
|
|
5388
|
+
const unlocalizableDataDiff = !_30.isEqual(
|
|
5113
5389
|
sourceUnlocalizable,
|
|
5114
5390
|
targetUnlocalizable
|
|
5115
5391
|
);
|
|
@@ -5160,7 +5436,6 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5160
5436
|
bucket.type,
|
|
5161
5437
|
bucketPath.pathPattern,
|
|
5162
5438
|
{
|
|
5163
|
-
isCacheRestore: false,
|
|
5164
5439
|
defaultLocale: sourceLocale,
|
|
5165
5440
|
injectLocale: bucket.injectLocale
|
|
5166
5441
|
},
|
|
@@ -5191,13 +5466,13 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5191
5466
|
targetData,
|
|
5192
5467
|
checksums: checksums2
|
|
5193
5468
|
});
|
|
5194
|
-
let processableData =
|
|
5469
|
+
let processableData = _30.chain(sourceData).entries().filter(
|
|
5195
5470
|
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!flags.force
|
|
5196
5471
|
).fromPairs().value();
|
|
5197
5472
|
if (flags.key) {
|
|
5198
|
-
processableData =
|
|
5473
|
+
processableData = _30.pickBy(
|
|
5199
5474
|
processableData,
|
|
5200
|
-
(
|
|
5475
|
+
(_34, key) => key === flags.key
|
|
5201
5476
|
);
|
|
5202
5477
|
}
|
|
5203
5478
|
if (flags.verbose) {
|
|
@@ -5230,13 +5505,13 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5230
5505
|
if (flags.verbose) {
|
|
5231
5506
|
bucketOra.info(JSON.stringify(processedTargetData, null, 2));
|
|
5232
5507
|
}
|
|
5233
|
-
let finalTargetData =
|
|
5508
|
+
let finalTargetData = _30.merge(
|
|
5234
5509
|
{},
|
|
5235
5510
|
sourceData,
|
|
5236
5511
|
targetData,
|
|
5237
5512
|
processedTargetData
|
|
5238
5513
|
);
|
|
5239
|
-
finalTargetData =
|
|
5514
|
+
finalTargetData = _30.chain(finalTargetData).entries().map(([key, value]) => {
|
|
5240
5515
|
const renaming = delta.renamed.find(
|
|
5241
5516
|
([oldKey, newKey]) => oldKey === key
|
|
5242
5517
|
);
|
|
@@ -5260,7 +5535,7 @@ var i18n_default = new Command12().command("i18n").description("Run Localization
|
|
|
5260
5535
|
`Applying changes to ${bucketPath} (${targetLocale})`
|
|
5261
5536
|
);
|
|
5262
5537
|
}
|
|
5263
|
-
const finalDiffSize =
|
|
5538
|
+
const finalDiffSize = _30.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
|
|
5264
5539
|
await bucketLoader.push(targetLocale, finalTargetData);
|
|
5265
5540
|
if (finalDiffSize > 0 || flags.force) {
|
|
5266
5541
|
bucketOra.succeed(
|
|
@@ -5387,7 +5662,9 @@ async function reviewChanges(args) {
|
|
|
5387
5662
|
if (currentStr === proposedStr && !args.force) {
|
|
5388
5663
|
console.log(
|
|
5389
5664
|
`
|
|
5390
|
-
${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5665
|
+
${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5666
|
+
args.targetLocale
|
|
5667
|
+
)}): ${chalk6.gray("No changes to review")}`
|
|
5391
5668
|
);
|
|
5392
5669
|
return args.proposedData;
|
|
5393
5670
|
}
|
|
@@ -5408,7 +5685,9 @@ ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(args.targetLocale)}): ${chalk6
|
|
|
5408
5685
|
}).join("\n");
|
|
5409
5686
|
console.log(
|
|
5410
5687
|
`
|
|
5411
|
-
Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5688
|
+
Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
|
|
5689
|
+
args.targetLocale
|
|
5690
|
+
)}):`
|
|
5412
5691
|
);
|
|
5413
5692
|
console.log(coloredDiff);
|
|
5414
5693
|
const { action } = await inquirer2.prompt([
|
|
@@ -5431,7 +5710,7 @@ Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(args.tar
|
|
|
5431
5710
|
return args.currentData;
|
|
5432
5711
|
}
|
|
5433
5712
|
const customData = { ...args.currentData };
|
|
5434
|
-
const changes =
|
|
5713
|
+
const changes = _30.reduce(
|
|
5435
5714
|
args.proposedData,
|
|
5436
5715
|
(result, value, key) => {
|
|
5437
5716
|
if (args.currentData[key] !== value) {
|
|
@@ -5504,7 +5783,7 @@ import path14 from "path";
|
|
|
5504
5783
|
import Z4 from "zod";
|
|
5505
5784
|
import YAML5 from "yaml";
|
|
5506
5785
|
import { MD5 as MD52 } from "object-hash";
|
|
5507
|
-
import
|
|
5786
|
+
import _31 from "lodash";
|
|
5508
5787
|
function createLockfileHelper() {
|
|
5509
5788
|
return {
|
|
5510
5789
|
isLockfileExists: () => {
|
|
@@ -5514,23 +5793,33 @@ function createLockfileHelper() {
|
|
|
5514
5793
|
registerSourceData: (pathPattern, sourceData) => {
|
|
5515
5794
|
const lockfile = _loadLockfile();
|
|
5516
5795
|
const sectionKey = MD52(pathPattern);
|
|
5517
|
-
const sectionChecksums =
|
|
5796
|
+
const sectionChecksums = _31.mapValues(sourceData, (value) => MD52(value));
|
|
5518
5797
|
lockfile.checksums[sectionKey] = sectionChecksums;
|
|
5519
5798
|
_saveLockfile(lockfile);
|
|
5520
5799
|
},
|
|
5521
5800
|
registerPartialSourceData: (pathPattern, partialSourceData) => {
|
|
5522
5801
|
const lockfile = _loadLockfile();
|
|
5523
5802
|
const sectionKey = MD52(pathPattern);
|
|
5524
|
-
const sectionChecksums =
|
|
5525
|
-
|
|
5803
|
+
const sectionChecksums = _31.mapValues(
|
|
5804
|
+
partialSourceData,
|
|
5805
|
+
(value) => MD52(value)
|
|
5806
|
+
);
|
|
5807
|
+
lockfile.checksums[sectionKey] = _31.merge(
|
|
5808
|
+
{},
|
|
5809
|
+
lockfile.checksums[sectionKey] ?? {},
|
|
5810
|
+
sectionChecksums
|
|
5811
|
+
);
|
|
5526
5812
|
_saveLockfile(lockfile);
|
|
5527
5813
|
},
|
|
5528
5814
|
extractUpdatedData: (pathPattern, sourceData) => {
|
|
5529
5815
|
const lockfile = _loadLockfile();
|
|
5530
5816
|
const sectionKey = MD52(pathPattern);
|
|
5531
|
-
const currentChecksums =
|
|
5817
|
+
const currentChecksums = _31.mapValues(sourceData, (value) => MD52(value));
|
|
5532
5818
|
const savedChecksums = lockfile.checksums[sectionKey] || {};
|
|
5533
|
-
const updatedData =
|
|
5819
|
+
const updatedData = _31.pickBy(
|
|
5820
|
+
sourceData,
|
|
5821
|
+
(value, key) => savedChecksums[key] !== currentChecksums[key]
|
|
5822
|
+
);
|
|
5534
5823
|
return updatedData;
|
|
5535
5824
|
}
|
|
5536
5825
|
};
|
|
@@ -5574,20 +5863,31 @@ var lockfile_default = new Command13().command("lockfile").description("Create a
|
|
|
5574
5863
|
const ora = Ora8();
|
|
5575
5864
|
const lockfileHelper = createLockfileHelper();
|
|
5576
5865
|
if (lockfileHelper.isLockfileExists() && !flags.force) {
|
|
5577
|
-
ora.warn(
|
|
5866
|
+
ora.warn(
|
|
5867
|
+
`Lockfile won't be created because it already exists. Use --force to overwrite.`
|
|
5868
|
+
);
|
|
5578
5869
|
} else {
|
|
5579
5870
|
const i18nConfig = getConfig();
|
|
5580
5871
|
const buckets = getBuckets(i18nConfig);
|
|
5581
5872
|
for (const bucket of buckets) {
|
|
5582
5873
|
for (const bucketConfig of bucket.paths) {
|
|
5583
|
-
const sourceLocale = resolveOverriddenLocale4(
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5874
|
+
const sourceLocale = resolveOverriddenLocale4(
|
|
5875
|
+
i18nConfig.locale.source,
|
|
5876
|
+
bucketConfig.delimiter
|
|
5877
|
+
);
|
|
5878
|
+
const bucketLoader = createBucketLoader(
|
|
5879
|
+
bucket.type,
|
|
5880
|
+
bucketConfig.pathPattern,
|
|
5881
|
+
{
|
|
5882
|
+
defaultLocale: sourceLocale
|
|
5883
|
+
}
|
|
5884
|
+
);
|
|
5588
5885
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
5589
5886
|
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
5590
|
-
lockfileHelper.registerSourceData(
|
|
5887
|
+
lockfileHelper.registerSourceData(
|
|
5888
|
+
bucketConfig.pathPattern,
|
|
5889
|
+
sourceData
|
|
5890
|
+
);
|
|
5591
5891
|
}
|
|
5592
5892
|
}
|
|
5593
5893
|
ora.succeed("Lockfile created");
|
|
@@ -5600,9 +5900,11 @@ var flagsSchema = Z5.object({
|
|
|
5600
5900
|
// src/cli/cmd/cleanup.ts
|
|
5601
5901
|
import { resolveOverriddenLocale as resolveOverriddenLocale5 } from "@lingo.dev/_spec";
|
|
5602
5902
|
import { Command as Command14 } from "interactive-commander";
|
|
5603
|
-
import
|
|
5903
|
+
import _32 from "lodash";
|
|
5604
5904
|
import Ora9 from "ora";
|
|
5605
|
-
var cleanup_default = new Command14().command("cleanup").description(
|
|
5905
|
+
var cleanup_default = new Command14().command("cleanup").description(
|
|
5906
|
+
"Remove keys from target files that do not exist in the source file"
|
|
5907
|
+
).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
5908
|
"--verbose",
|
|
5607
5909
|
"Show detailed output including:\n - List of keys that would be removed.\n - Processing steps."
|
|
5608
5910
|
).action(async function(options) {
|
|
@@ -5615,44 +5917,69 @@ var cleanup_default = new Command14().command("cleanup").description("Remove key
|
|
|
5615
5917
|
ora.succeed("Configuration loaded");
|
|
5616
5918
|
let buckets = getBuckets(i18nConfig);
|
|
5617
5919
|
if (options.bucket) {
|
|
5618
|
-
buckets = buckets.filter(
|
|
5920
|
+
buckets = buckets.filter(
|
|
5921
|
+
(bucket) => bucket.type === options.bucket
|
|
5922
|
+
);
|
|
5619
5923
|
}
|
|
5620
5924
|
const targetLocales = options.locale ? [options.locale] : i18nConfig.locale.targets;
|
|
5621
5925
|
for (const bucket of buckets) {
|
|
5622
5926
|
console.log();
|
|
5623
5927
|
ora.info(`Processing bucket: ${bucket.type}`);
|
|
5624
5928
|
for (const bucketConfig of bucket.paths) {
|
|
5625
|
-
const sourceLocale = resolveOverriddenLocale5(
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5929
|
+
const sourceLocale = resolveOverriddenLocale5(
|
|
5930
|
+
i18nConfig.locale.source,
|
|
5931
|
+
bucketConfig.delimiter
|
|
5932
|
+
);
|
|
5933
|
+
const bucketOra = Ora9({ indent: 2 }).info(
|
|
5934
|
+
`Processing path: ${bucketConfig.pathPattern}`
|
|
5935
|
+
);
|
|
5936
|
+
const bucketLoader = createBucketLoader(
|
|
5937
|
+
bucket.type,
|
|
5938
|
+
bucketConfig.pathPattern,
|
|
5939
|
+
{
|
|
5940
|
+
defaultLocale: sourceLocale
|
|
5941
|
+
}
|
|
5942
|
+
);
|
|
5631
5943
|
bucketLoader.setDefaultLocale(sourceLocale);
|
|
5632
5944
|
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
5633
5945
|
const sourceKeys = Object.keys(sourceData);
|
|
5634
5946
|
for (const _targetLocale of targetLocales) {
|
|
5635
|
-
const targetLocale = resolveOverriddenLocale5(
|
|
5947
|
+
const targetLocale = resolveOverriddenLocale5(
|
|
5948
|
+
_targetLocale,
|
|
5949
|
+
bucketConfig.delimiter
|
|
5950
|
+
);
|
|
5636
5951
|
try {
|
|
5637
5952
|
const targetData = await bucketLoader.pull(targetLocale);
|
|
5638
5953
|
const targetKeys = Object.keys(targetData);
|
|
5639
|
-
const keysToRemove =
|
|
5954
|
+
const keysToRemove = _32.difference(targetKeys, sourceKeys);
|
|
5640
5955
|
if (keysToRemove.length === 0) {
|
|
5641
5956
|
bucketOra.succeed(`[${targetLocale}] No keys to remove`);
|
|
5642
5957
|
continue;
|
|
5643
5958
|
}
|
|
5644
5959
|
if (options.verbose) {
|
|
5645
|
-
bucketOra.info(
|
|
5960
|
+
bucketOra.info(
|
|
5961
|
+
`[${targetLocale}] Keys to remove: ${JSON.stringify(
|
|
5962
|
+
keysToRemove,
|
|
5963
|
+
null,
|
|
5964
|
+
2
|
|
5965
|
+
)}`
|
|
5966
|
+
);
|
|
5646
5967
|
}
|
|
5647
5968
|
if (!options.dryRun) {
|
|
5648
|
-
const cleanedData =
|
|
5969
|
+
const cleanedData = _32.pick(targetData, sourceKeys);
|
|
5649
5970
|
await bucketLoader.push(targetLocale, cleanedData);
|
|
5650
|
-
bucketOra.succeed(
|
|
5971
|
+
bucketOra.succeed(
|
|
5972
|
+
`[${targetLocale}] Removed ${keysToRemove.length} keys`
|
|
5973
|
+
);
|
|
5651
5974
|
} else {
|
|
5652
|
-
bucketOra.succeed(
|
|
5975
|
+
bucketOra.succeed(
|
|
5976
|
+
`[${targetLocale}] Would remove ${keysToRemove.length} keys (dry run)`
|
|
5977
|
+
);
|
|
5653
5978
|
}
|
|
5654
5979
|
} catch (error) {
|
|
5655
|
-
bucketOra.fail(
|
|
5980
|
+
bucketOra.fail(
|
|
5981
|
+
`[${targetLocale}] Failed to cleanup: ${error.message}`
|
|
5982
|
+
);
|
|
5656
5983
|
results.push({
|
|
5657
5984
|
step: `Cleanup ${bucket.type}/${bucketConfig} for ${targetLocale}`,
|
|
5658
5985
|
status: "Failed",
|
|
@@ -5700,7 +6027,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
5700
6027
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5701
6028
|
import Z6 from "zod";
|
|
5702
6029
|
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 (
|
|
6030
|
+
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
6031
|
const apiKey = program.args[0];
|
|
5705
6032
|
const settings = getSettings(apiKey);
|
|
5706
6033
|
if (!settings.auth.apiKey) {
|
|
@@ -5802,7 +6129,9 @@ function createLingoDotDevLocalizer(explicitApiKey) {
|
|
|
5802
6129
|
if (!auth) {
|
|
5803
6130
|
throw new Error(
|
|
5804
6131
|
dedent5`
|
|
5805
|
-
You're trying to use ${chalk8.hex(colors.green)(
|
|
6132
|
+
You're trying to use ${chalk8.hex(colors.green)(
|
|
6133
|
+
"Lingo.dev"
|
|
6134
|
+
)} provider, however, you are not authenticated.
|
|
5806
6135
|
|
|
5807
6136
|
To fix this issue:
|
|
5808
6137
|
1. Run ${chalk8.dim("lingo.dev login")} to authenticate, or
|
|
@@ -5854,6 +6183,7 @@ import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
|
5854
6183
|
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
5855
6184
|
import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
5856
6185
|
import { createOpenRouter as createOpenRouter2 } from "@openrouter/ai-sdk-provider";
|
|
6186
|
+
import { createMistral as createMistral2 } from "@ai-sdk/mistral";
|
|
5857
6187
|
import chalk9 from "chalk";
|
|
5858
6188
|
import dedent6 from "dedent";
|
|
5859
6189
|
import { generateText as generateText2 } from "ai";
|
|
@@ -5868,7 +6198,11 @@ function createExplicitLocalizer(provider) {
|
|
|
5868
6198
|
|
|
5869
6199
|
To fix this issue:
|
|
5870
6200
|
1. Switch to one of the supported providers, or
|
|
5871
|
-
2. Remove the ${chalk9.italic(
|
|
6201
|
+
2. Remove the ${chalk9.italic(
|
|
6202
|
+
"provider"
|
|
6203
|
+
)} node from your i18n.json configuration to switch to ${chalk9.hex(
|
|
6204
|
+
colors.green
|
|
6205
|
+
)("Lingo.dev")}
|
|
5872
6206
|
|
|
5873
6207
|
${chalk9.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
5874
6208
|
`
|
|
@@ -5912,6 +6246,14 @@ function createExplicitLocalizer(provider) {
|
|
|
5912
6246
|
prompt: provider.prompt,
|
|
5913
6247
|
skipAuth: true
|
|
5914
6248
|
});
|
|
6249
|
+
case "mistral":
|
|
6250
|
+
return createAiSdkLocalizer({
|
|
6251
|
+
factory: (params) => createMistral2(params).languageModel(provider.model),
|
|
6252
|
+
id: provider.id,
|
|
6253
|
+
prompt: provider.prompt,
|
|
6254
|
+
apiKeyName: "MISTRAL_API_KEY",
|
|
6255
|
+
baseUrl: provider.baseUrl
|
|
6256
|
+
});
|
|
5915
6257
|
}
|
|
5916
6258
|
}
|
|
5917
6259
|
function createAiSdkLocalizer(params) {
|
|
@@ -5920,11 +6262,19 @@ function createAiSdkLocalizer(params) {
|
|
|
5920
6262
|
if (!skipAuth && !apiKey || !params.apiKeyName) {
|
|
5921
6263
|
throw new Error(
|
|
5922
6264
|
dedent6`
|
|
5923
|
-
You're trying to use raw ${chalk9.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${chalk9.dim(
|
|
6265
|
+
You're trying to use raw ${chalk9.dim(params.id)} API for translation. ${params.apiKeyName ? `However, ${chalk9.dim(
|
|
6266
|
+
params.apiKeyName
|
|
6267
|
+
)} environment variable is not set.` : "However, that provider is unavailable."}
|
|
5924
6268
|
|
|
5925
6269
|
To fix this issue:
|
|
5926
|
-
1. ${params.apiKeyName ? `Set ${chalk9.dim(
|
|
5927
|
-
|
|
6270
|
+
1. ${params.apiKeyName ? `Set ${chalk9.dim(
|
|
6271
|
+
params.apiKeyName
|
|
6272
|
+
)} in your environment variables` : "Set the environment variable for your provider (if required)"}, or
|
|
6273
|
+
2. Remove the ${chalk9.italic(
|
|
6274
|
+
"provider"
|
|
6275
|
+
)} node from your i18n.json configuration to switch to ${chalk9.hex(
|
|
6276
|
+
colors.green
|
|
6277
|
+
)("Lingo.dev")}
|
|
5928
6278
|
|
|
5929
6279
|
${chalk9.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
|
|
5930
6280
|
`
|
|
@@ -6064,10 +6414,14 @@ async function setup(input2) {
|
|
|
6064
6414
|
const authStatus = await ctx.localizer.checkAuth();
|
|
6065
6415
|
if (!authStatus.authenticated) {
|
|
6066
6416
|
throw new Error(
|
|
6067
|
-
`Failed to authenticate with ${chalk10.hex(colors.yellow)(
|
|
6417
|
+
`Failed to authenticate with ${chalk10.hex(colors.yellow)(
|
|
6418
|
+
ctx.localizer.id
|
|
6419
|
+
)} provider. Please check your API key and try again.`
|
|
6068
6420
|
);
|
|
6069
6421
|
}
|
|
6070
|
-
task.title = `Authenticated as ${chalk10.hex(colors.yellow)(
|
|
6422
|
+
task.title = `Authenticated as ${chalk10.hex(colors.yellow)(
|
|
6423
|
+
authStatus.username
|
|
6424
|
+
)}`;
|
|
6071
6425
|
}
|
|
6072
6426
|
},
|
|
6073
6427
|
{
|
|
@@ -6128,14 +6482,22 @@ async function plan(input2) {
|
|
|
6128
6482
|
title: "Locating content buckets",
|
|
6129
6483
|
task: async (ctx, task) => {
|
|
6130
6484
|
const bucketCount = buckets.length;
|
|
6131
|
-
const bucketFilter = input2.flags.bucket ? ` ${chalk11.dim(
|
|
6132
|
-
|
|
6485
|
+
const bucketFilter = input2.flags.bucket ? ` ${chalk11.dim(
|
|
6486
|
+
`(filtered by: ${chalk11.hex(colors.yellow)(
|
|
6487
|
+
input2.flags.bucket.join(", ")
|
|
6488
|
+
)})`
|
|
6489
|
+
)}` : "";
|
|
6490
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6491
|
+
bucketCount.toString()
|
|
6492
|
+
)} bucket(s)${bucketFilter}`;
|
|
6133
6493
|
}
|
|
6134
6494
|
},
|
|
6135
6495
|
{
|
|
6136
6496
|
title: "Detecting locales",
|
|
6137
6497
|
task: async (ctx, task) => {
|
|
6138
|
-
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6498
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6499
|
+
_targetLocales.length.toString()
|
|
6500
|
+
)} target locale(s)`;
|
|
6139
6501
|
}
|
|
6140
6502
|
},
|
|
6141
6503
|
{
|
|
@@ -6154,8 +6516,14 @@ async function plan(input2) {
|
|
|
6154
6516
|
patterns.push(bucketPath.pathPattern);
|
|
6155
6517
|
}
|
|
6156
6518
|
}
|
|
6157
|
-
const fileFilter = input2.flags.file ? ` ${chalk11.dim(
|
|
6158
|
-
|
|
6519
|
+
const fileFilter = input2.flags.file ? ` ${chalk11.dim(
|
|
6520
|
+
`(filtered by: ${chalk11.hex(colors.yellow)(
|
|
6521
|
+
input2.flags.file.join(", ")
|
|
6522
|
+
)})`
|
|
6523
|
+
)}` : "";
|
|
6524
|
+
task.title = `Found ${chalk11.hex(colors.yellow)(
|
|
6525
|
+
patterns.length.toString()
|
|
6526
|
+
)} path pattern(s)${fileFilter}`;
|
|
6159
6527
|
}
|
|
6160
6528
|
},
|
|
6161
6529
|
{
|
|
@@ -6193,7 +6561,9 @@ async function plan(input2) {
|
|
|
6193
6561
|
}
|
|
6194
6562
|
}
|
|
6195
6563
|
}
|
|
6196
|
-
task.title = `Prepared ${chalk11.hex(colors.green)(
|
|
6564
|
+
task.title = `Prepared ${chalk11.hex(colors.green)(
|
|
6565
|
+
ctx.tasks.length.toString()
|
|
6566
|
+
)} translation task(s)`;
|
|
6197
6567
|
}
|
|
6198
6568
|
}
|
|
6199
6569
|
],
|
|
@@ -6207,7 +6577,7 @@ async function plan(input2) {
|
|
|
6207
6577
|
import chalk12 from "chalk";
|
|
6208
6578
|
import { Listr as Listr3 } from "listr2";
|
|
6209
6579
|
import pLimit from "p-limit";
|
|
6210
|
-
import
|
|
6580
|
+
import _33 from "lodash";
|
|
6211
6581
|
|
|
6212
6582
|
// ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
6213
6583
|
var balanced = (a, b, str) => {
|
|
@@ -6898,7 +7268,7 @@ var AST = class _AST {
|
|
|
6898
7268
|
if (!this.type) {
|
|
6899
7269
|
const noEmpty = this.isStart() && this.isEnd();
|
|
6900
7270
|
const src = this.#parts.map((p) => {
|
|
6901
|
-
const [re,
|
|
7271
|
+
const [re, _34, hasMagic, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
|
|
6902
7272
|
this.#hasMagic = this.#hasMagic || hasMagic;
|
|
6903
7273
|
this.#uflag = this.#uflag || uflag;
|
|
6904
7274
|
return re;
|
|
@@ -6971,7 +7341,7 @@ var AST = class _AST {
|
|
|
6971
7341
|
if (typeof p === "string") {
|
|
6972
7342
|
throw new Error("string type in extglob ast??");
|
|
6973
7343
|
}
|
|
6974
|
-
const [re,
|
|
7344
|
+
const [re, _34, _hasMagic, uflag] = p.toRegExpSource(dot);
|
|
6975
7345
|
this.#uflag = this.#uflag || uflag;
|
|
6976
7346
|
return re;
|
|
6977
7347
|
}).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
|
|
@@ -7216,7 +7586,7 @@ var Minimatch = class {
|
|
|
7216
7586
|
}
|
|
7217
7587
|
return false;
|
|
7218
7588
|
}
|
|
7219
|
-
debug(...
|
|
7589
|
+
debug(..._34) {
|
|
7220
7590
|
}
|
|
7221
7591
|
make() {
|
|
7222
7592
|
const pattern = this.pattern;
|
|
@@ -7238,7 +7608,7 @@ var Minimatch = class {
|
|
|
7238
7608
|
const rawGlobParts = this.globSet.map((s) => this.slashSplit(s));
|
|
7239
7609
|
this.globParts = this.preprocess(rawGlobParts);
|
|
7240
7610
|
this.debug(this.pattern, this.globParts);
|
|
7241
|
-
let set = this.globParts.map((s,
|
|
7611
|
+
let set = this.globParts.map((s, _34, __) => {
|
|
7242
7612
|
if (this.isWindows && this.windowsNoMagicRoot) {
|
|
7243
7613
|
const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]);
|
|
7244
7614
|
const isDrive = /^[a-z]:/i.test(s[0]);
|
|
@@ -7761,11 +8131,15 @@ async function execute(input2) {
|
|
|
7761
8131
|
{
|
|
7762
8132
|
title: "Initializing localization engine",
|
|
7763
8133
|
task: async (ctx, task) => {
|
|
7764
|
-
task.title = `Localization engine ${chalk12.hex(colors.green)(
|
|
8134
|
+
task.title = `Localization engine ${chalk12.hex(colors.green)(
|
|
8135
|
+
"ready"
|
|
8136
|
+
)} (${ctx.localizer.id})`;
|
|
7765
8137
|
}
|
|
7766
8138
|
},
|
|
7767
8139
|
{
|
|
7768
|
-
title: `Processing localization tasks ${chalk12.dim(
|
|
8140
|
+
title: `Processing localization tasks ${chalk12.dim(
|
|
8141
|
+
`(tasks: ${input2.tasks.length}, concurrency: ${effectiveConcurrency})`
|
|
8142
|
+
)}`,
|
|
7769
8143
|
task: (ctx, task) => {
|
|
7770
8144
|
if (input2.tasks.length < 1) {
|
|
7771
8145
|
task.title = `Skipping, nothing to localize.`;
|
|
@@ -7778,7 +8152,7 @@ async function execute(input2) {
|
|
|
7778
8152
|
const workerTasks = [];
|
|
7779
8153
|
for (let i = 0; i < workersCount; i++) {
|
|
7780
8154
|
const assignedTasks = ctx.tasks.filter(
|
|
7781
|
-
(
|
|
8155
|
+
(_34, idx) => idx % workersCount === i
|
|
7782
8156
|
);
|
|
7783
8157
|
workerTasks.push(
|
|
7784
8158
|
createWorkerTask({
|
|
@@ -7814,11 +8188,11 @@ function createWorkerStatusMessage(args) {
|
|
|
7814
8188
|
"[locale]",
|
|
7815
8189
|
args.assignedTask.targetLocale
|
|
7816
8190
|
);
|
|
7817
|
-
return `[${chalk12.hex(colors.yellow)(
|
|
7818
|
-
|
|
7819
|
-
)}
|
|
7820
|
-
|
|
7821
|
-
)(args.assignedTask.targetLocale)})`;
|
|
8191
|
+
return `[${chalk12.hex(colors.yellow)(
|
|
8192
|
+
`${args.percentage}%`
|
|
8193
|
+
)}] Processing: ${chalk12.dim(displayPath)} (${chalk12.hex(colors.yellow)(
|
|
8194
|
+
args.assignedTask.sourceLocale
|
|
8195
|
+
)} -> ${chalk12.hex(colors.yellow)(args.assignedTask.targetLocale)})`;
|
|
7822
8196
|
}
|
|
7823
8197
|
function createExecutionProgressMessage(ctx) {
|
|
7824
8198
|
const succeededTasksCount = countTasks(
|
|
@@ -7833,7 +8207,9 @@ function createExecutionProgressMessage(ctx) {
|
|
|
7833
8207
|
ctx,
|
|
7834
8208
|
(_t, result) => result.status === "skipped"
|
|
7835
8209
|
);
|
|
7836
|
-
return `Processed ${chalk12.green(succeededTasksCount)}/${ctx.tasks.length}, Failed ${chalk12.red(failedTasksCount)}, Skipped ${chalk12.dim(
|
|
8210
|
+
return `Processed ${chalk12.green(succeededTasksCount)}/${ctx.tasks.length}, Failed ${chalk12.red(failedTasksCount)}, Skipped ${chalk12.dim(
|
|
8211
|
+
skippedTasksCount
|
|
8212
|
+
)}`;
|
|
7837
8213
|
}
|
|
7838
8214
|
function createLoaderForTask(assignedTask) {
|
|
7839
8215
|
const bucketLoader = createBucketLoader(
|
|
@@ -7841,7 +8217,6 @@ function createLoaderForTask(assignedTask) {
|
|
|
7841
8217
|
assignedTask.bucketPathPattern,
|
|
7842
8218
|
{
|
|
7843
8219
|
defaultLocale: assignedTask.sourceLocale,
|
|
7844
|
-
isCacheRestore: false,
|
|
7845
8220
|
injectLocale: assignedTask.injectLocale
|
|
7846
8221
|
},
|
|
7847
8222
|
assignedTask.lockedKeys,
|
|
@@ -7877,7 +8252,7 @@ function createWorkerTask(args) {
|
|
|
7877
8252
|
targetData,
|
|
7878
8253
|
checksums
|
|
7879
8254
|
});
|
|
7880
|
-
const processableData =
|
|
8255
|
+
const processableData = _33.chain(sourceData).entries().filter(
|
|
7881
8256
|
([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!args.ctx.flags.force
|
|
7882
8257
|
).filter(
|
|
7883
8258
|
([key]) => !assignedTask.onlyKeys.length || assignedTask.onlyKeys?.some(
|
|
@@ -7895,33 +8270,47 @@ function createWorkerTask(args) {
|
|
|
7895
8270
|
targetData,
|
|
7896
8271
|
processableData
|
|
7897
8272
|
},
|
|
7898
|
-
(progress) => {
|
|
8273
|
+
async (progress, _sourceChunk, processedChunk) => {
|
|
8274
|
+
await args.ioLimiter(async () => {
|
|
8275
|
+
await bucketLoader.pull(assignedTask.sourceLocale);
|
|
8276
|
+
const latestTargetData = await bucketLoader.pull(
|
|
8277
|
+
assignedTask.targetLocale
|
|
8278
|
+
);
|
|
8279
|
+
const _partialData = _33.merge(
|
|
8280
|
+
{},
|
|
8281
|
+
latestTargetData,
|
|
8282
|
+
processedChunk
|
|
8283
|
+
);
|
|
8284
|
+
const finalChunkTargetData = processRenamedKeys(
|
|
8285
|
+
delta,
|
|
8286
|
+
_partialData
|
|
8287
|
+
);
|
|
8288
|
+
await bucketLoader.push(
|
|
8289
|
+
assignedTask.targetLocale,
|
|
8290
|
+
finalChunkTargetData
|
|
8291
|
+
);
|
|
8292
|
+
});
|
|
7899
8293
|
subTask.title = createWorkerStatusMessage({
|
|
7900
8294
|
assignedTask,
|
|
7901
8295
|
percentage: progress
|
|
7902
8296
|
});
|
|
7903
8297
|
}
|
|
7904
8298
|
);
|
|
7905
|
-
|
|
8299
|
+
const finalTargetData = _33.merge(
|
|
7906
8300
|
{},
|
|
7907
8301
|
sourceData,
|
|
7908
8302
|
targetData,
|
|
7909
8303
|
processedTargetData
|
|
7910
8304
|
);
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
if (!renaming) {
|
|
7916
|
-
return [key, value];
|
|
7917
|
-
}
|
|
7918
|
-
return [renaming[1], value];
|
|
7919
|
-
}).fromPairs().value();
|
|
8305
|
+
const finalRenamedTargetData = processRenamedKeys(
|
|
8306
|
+
delta,
|
|
8307
|
+
finalTargetData
|
|
8308
|
+
);
|
|
7920
8309
|
await args.ioLimiter(async () => {
|
|
7921
8310
|
await bucketLoader.pull(assignedTask.sourceLocale);
|
|
7922
8311
|
await bucketLoader.push(
|
|
7923
8312
|
assignedTask.targetLocale,
|
|
7924
|
-
|
|
8313
|
+
finalRenamedTargetData
|
|
7925
8314
|
);
|
|
7926
8315
|
const checksums2 = await deltaProcessor.createChecksums(sourceData);
|
|
7927
8316
|
await deltaProcessor.saveChecksums(checksums2);
|
|
@@ -7945,6 +8334,15 @@ function countTasks(ctx, predicate) {
|
|
|
7945
8334
|
([task, result]) => predicate(task, result)
|
|
7946
8335
|
).length;
|
|
7947
8336
|
}
|
|
8337
|
+
function processRenamedKeys(delta, targetData) {
|
|
8338
|
+
return _33.chain(targetData).entries().map(([key, value]) => {
|
|
8339
|
+
const renaming = delta.renamed.find(([oldKey]) => oldKey === key);
|
|
8340
|
+
if (!renaming) {
|
|
8341
|
+
return [key, value];
|
|
8342
|
+
}
|
|
8343
|
+
return [renaming[1], value];
|
|
8344
|
+
}).fromPairs().value();
|
|
8345
|
+
}
|
|
7948
8346
|
|
|
7949
8347
|
// src/cli/cmd/run/_types.ts
|
|
7950
8348
|
import {
|
|
@@ -8075,7 +8473,9 @@ var InBranchFlow = class extends IntegrationFlow {
|
|
|
8075
8473
|
execSync(`git add .`, { stdio: "inherit" });
|
|
8076
8474
|
execSync(`git status --porcelain`, { stdio: "inherit" });
|
|
8077
8475
|
execSync(
|
|
8078
|
-
`git commit -m ${escapeShellArg(
|
|
8476
|
+
`git commit -m ${escapeShellArg(
|
|
8477
|
+
this.platformKit.config.commitMessage
|
|
8478
|
+
)} --no-verify`,
|
|
8079
8479
|
{
|
|
8080
8480
|
stdio: "inherit"
|
|
8081
8481
|
}
|
|
@@ -8198,7 +8598,9 @@ var PullRequestFlow = class extends InBranchFlow {
|
|
|
8198
8598
|
this.ora.start("Checking if PR already exists");
|
|
8199
8599
|
const pullRequestNumber = await this.ensureFreshPr(this.i18nBranchName);
|
|
8200
8600
|
this.ora.succeed(
|
|
8201
|
-
`Pull request ready: ${this.platformKit.buildPullRequestUrl(
|
|
8601
|
+
`Pull request ready: ${this.platformKit.buildPullRequestUrl(
|
|
8602
|
+
pullRequestNumber
|
|
8603
|
+
)}`
|
|
8202
8604
|
);
|
|
8203
8605
|
}
|
|
8204
8606
|
calculatePrBranchName() {
|
|
@@ -8368,11 +8770,17 @@ var PlatformKit = class {
|
|
|
8368
8770
|
get config() {
|
|
8369
8771
|
const env = Z7.object({
|
|
8370
8772
|
LINGODOTDEV_API_KEY: Z7.string(),
|
|
8371
|
-
LINGODOTDEV_PULL_REQUEST: Z7.preprocess(
|
|
8773
|
+
LINGODOTDEV_PULL_REQUEST: Z7.preprocess(
|
|
8774
|
+
(val) => val === "true" || val === true,
|
|
8775
|
+
Z7.boolean()
|
|
8776
|
+
),
|
|
8372
8777
|
LINGODOTDEV_COMMIT_MESSAGE: Z7.string().optional(),
|
|
8373
8778
|
LINGODOTDEV_PULL_REQUEST_TITLE: Z7.string().optional(),
|
|
8374
8779
|
LINGODOTDEV_WORKING_DIRECTORY: Z7.string().optional(),
|
|
8375
|
-
LINGODOTDEV_PROCESS_OWN_COMMITS: Z7.preprocess(
|
|
8780
|
+
LINGODOTDEV_PROCESS_OWN_COMMITS: Z7.preprocess(
|
|
8781
|
+
(val) => val === "true" || val === true,
|
|
8782
|
+
Z7.boolean()
|
|
8783
|
+
).optional()
|
|
8376
8784
|
}).parse(process.env);
|
|
8377
8785
|
return {
|
|
8378
8786
|
replexicaApiKey: env.LINGODOTDEV_API_KEY,
|
|
@@ -8767,16 +9175,34 @@ function parseBooleanArg(val) {
|
|
|
8767
9175
|
}
|
|
8768
9176
|
|
|
8769
9177
|
// src/cli/cmd/status.ts
|
|
8770
|
-
import {
|
|
9178
|
+
import {
|
|
9179
|
+
bucketTypeSchema as bucketTypeSchema4,
|
|
9180
|
+
localeCodeSchema as localeCodeSchema3,
|
|
9181
|
+
resolveOverriddenLocale as resolveOverriddenLocale7
|
|
9182
|
+
} from "@lingo.dev/_spec";
|
|
8771
9183
|
import { Command as Command18 } from "interactive-commander";
|
|
8772
9184
|
import Z11 from "zod";
|
|
8773
9185
|
import Ora10 from "ora";
|
|
8774
9186
|
import chalk13 from "chalk";
|
|
8775
9187
|
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(
|
|
9188
|
+
var status_default = new Command18().command("status").description("Show the status of the localization process").helpOption("-h, --help", "Show help").option(
|
|
9189
|
+
"--locale <locale>",
|
|
9190
|
+
"Locale to process",
|
|
9191
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
9192
|
+
).option(
|
|
9193
|
+
"--bucket <bucket>",
|
|
9194
|
+
"Bucket to process",
|
|
9195
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
9196
|
+
).option(
|
|
8777
9197
|
"--file [files...]",
|
|
8778
9198
|
"File to process. Process only a specific path, may contain asterisk * to match multiple files."
|
|
8779
|
-
).option(
|
|
9199
|
+
).option(
|
|
9200
|
+
"--force",
|
|
9201
|
+
"Ignore lockfile and process all keys, useful for estimating full re-translation"
|
|
9202
|
+
).option("--verbose", "Show detailed output including key-level word counts").option(
|
|
9203
|
+
"--api-key <api-key>",
|
|
9204
|
+
"Explicitly set the API key to use, override the default API key from settings"
|
|
9205
|
+
).action(async function(options) {
|
|
8780
9206
|
const ora = Ora10();
|
|
8781
9207
|
const flags = parseFlags2(options);
|
|
8782
9208
|
let authId = null;
|
|
@@ -8808,16 +9234,22 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8808
9234
|
});
|
|
8809
9235
|
let buckets = getBuckets(i18nConfig);
|
|
8810
9236
|
if (flags.bucket?.length) {
|
|
8811
|
-
buckets = buckets.filter(
|
|
9237
|
+
buckets = buckets.filter(
|
|
9238
|
+
(bucket) => flags.bucket.includes(bucket.type)
|
|
9239
|
+
);
|
|
8812
9240
|
}
|
|
8813
9241
|
ora.succeed("Buckets retrieved");
|
|
8814
9242
|
if (flags.file?.length) {
|
|
8815
9243
|
buckets = buckets.map((bucket) => {
|
|
8816
|
-
const paths = bucket.paths.filter(
|
|
9244
|
+
const paths = bucket.paths.filter(
|
|
9245
|
+
(path17) => flags.file.find((file) => path17.pathPattern?.match(file))
|
|
9246
|
+
);
|
|
8817
9247
|
return { ...bucket, paths };
|
|
8818
9248
|
}).filter((bucket) => bucket.paths.length > 0);
|
|
8819
9249
|
if (buckets.length === 0) {
|
|
8820
|
-
ora.fail(
|
|
9250
|
+
ora.fail(
|
|
9251
|
+
"No buckets found. All buckets were filtered out by --file option."
|
|
9252
|
+
);
|
|
8821
9253
|
process.exit(1);
|
|
8822
9254
|
} else {
|
|
8823
9255
|
ora.info(`\x1B[36mProcessing only filtered buckets:\x1B[0m`);
|
|
@@ -8850,13 +9282,17 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8850
9282
|
console.log();
|
|
8851
9283
|
ora.info(`Analyzing bucket: ${bucket.type}`);
|
|
8852
9284
|
for (const bucketPath of bucket.paths) {
|
|
8853
|
-
const bucketOra = Ora10({ indent: 2 }).info(
|
|
8854
|
-
|
|
9285
|
+
const bucketOra = Ora10({ indent: 2 }).info(
|
|
9286
|
+
`Analyzing path: ${bucketPath.pathPattern}`
|
|
9287
|
+
);
|
|
9288
|
+
const sourceLocale = resolveOverriddenLocale7(
|
|
9289
|
+
i18nConfig.locale.source,
|
|
9290
|
+
bucketPath.delimiter
|
|
9291
|
+
);
|
|
8855
9292
|
const bucketLoader = createBucketLoader(
|
|
8856
9293
|
bucket.type,
|
|
8857
9294
|
bucketPath.pathPattern,
|
|
8858
9295
|
{
|
|
8859
|
-
isCacheRestore: false,
|
|
8860
9296
|
defaultLocale: sourceLocale,
|
|
8861
9297
|
injectLocale: bucket.injectLocale
|
|
8862
9298
|
},
|
|
@@ -8895,8 +9331,13 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8895
9331
|
}
|
|
8896
9332
|
fileStats[filePath].wordCount = sourceWordCount;
|
|
8897
9333
|
for (const _targetLocale of targetLocales) {
|
|
8898
|
-
const targetLocale = resolveOverriddenLocale7(
|
|
8899
|
-
|
|
9334
|
+
const targetLocale = resolveOverriddenLocale7(
|
|
9335
|
+
_targetLocale,
|
|
9336
|
+
bucketPath.delimiter
|
|
9337
|
+
);
|
|
9338
|
+
bucketOra.start(
|
|
9339
|
+
`[${sourceLocale} -> ${targetLocale}] Analyzing translation status...`
|
|
9340
|
+
);
|
|
8900
9341
|
let targetData = {};
|
|
8901
9342
|
let fileExists = true;
|
|
8902
9343
|
try {
|
|
@@ -8912,13 +9353,20 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8912
9353
|
fileStats[filePath].languageStats[_targetLocale].words = sourceWordCount;
|
|
8913
9354
|
languageStats[_targetLocale].missing += sourceKeys.length;
|
|
8914
9355
|
languageStats[_targetLocale].words += sourceWordCount;
|
|
8915
|
-
totalWordCount.set(
|
|
9356
|
+
totalWordCount.set(
|
|
9357
|
+
_targetLocale,
|
|
9358
|
+
(totalWordCount.get(_targetLocale) || 0) + sourceWordCount
|
|
9359
|
+
);
|
|
8916
9360
|
bucketOra.succeed(
|
|
8917
|
-
`[${sourceLocale} -> ${targetLocale}] ${chalk13.red(
|
|
9361
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk13.red(
|
|
9362
|
+
`0% complete`
|
|
9363
|
+
)} (0/${sourceKeys.length} keys) - file not found`
|
|
8918
9364
|
);
|
|
8919
9365
|
continue;
|
|
8920
9366
|
}
|
|
8921
|
-
const deltaProcessor = createDeltaProcessor(
|
|
9367
|
+
const deltaProcessor = createDeltaProcessor(
|
|
9368
|
+
bucketPath.pathPattern
|
|
9369
|
+
);
|
|
8922
9370
|
const checksums = await deltaProcessor.loadChecksums();
|
|
8923
9371
|
const delta = await deltaProcessor.calculateDelta({
|
|
8924
9372
|
sourceData,
|
|
@@ -8927,7 +9375,9 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8927
9375
|
});
|
|
8928
9376
|
const missingKeys = delta.added;
|
|
8929
9377
|
const updatedKeys = delta.updated;
|
|
8930
|
-
const completeKeys = sourceKeys.filter(
|
|
9378
|
+
const completeKeys = sourceKeys.filter(
|
|
9379
|
+
(key) => !missingKeys.includes(key) && !updatedKeys.includes(key)
|
|
9380
|
+
);
|
|
8931
9381
|
let wordsToTranslate = 0;
|
|
8932
9382
|
const keysToProcess = flags.force ? sourceKeys : [...missingKeys, ...updatedKeys];
|
|
8933
9383
|
for (const key of keysToProcess) {
|
|
@@ -8945,25 +9395,39 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8945
9395
|
languageStats[_targetLocale].updated += updatedKeys.length;
|
|
8946
9396
|
languageStats[_targetLocale].complete += completeKeys.length;
|
|
8947
9397
|
languageStats[_targetLocale].words += wordsToTranslate;
|
|
8948
|
-
totalWordCount.set(
|
|
9398
|
+
totalWordCount.set(
|
|
9399
|
+
_targetLocale,
|
|
9400
|
+
(totalWordCount.get(_targetLocale) || 0) + wordsToTranslate
|
|
9401
|
+
);
|
|
8949
9402
|
const totalKeysInFile = sourceKeys.length;
|
|
8950
9403
|
const completionPercent = (completeKeys.length / totalKeysInFile * 100).toFixed(1);
|
|
8951
9404
|
if (missingKeys.length === 0 && updatedKeys.length === 0) {
|
|
8952
9405
|
bucketOra.succeed(
|
|
8953
|
-
`[${sourceLocale} -> ${targetLocale}] ${chalk13.green(
|
|
9406
|
+
`[${sourceLocale} -> ${targetLocale}] ${chalk13.green(
|
|
9407
|
+
`100% complete`
|
|
9408
|
+
)} (${completeKeys.length}/${totalKeysInFile} keys)`
|
|
8954
9409
|
);
|
|
8955
9410
|
} else {
|
|
8956
9411
|
const message = `[${sourceLocale} -> ${targetLocale}] ${parseFloat(completionPercent) > 50 ? chalk13.yellow(`${completionPercent}% complete`) : chalk13.red(`${completionPercent}% complete`)} (${completeKeys.length}/${totalKeysInFile} keys)`;
|
|
8957
9412
|
bucketOra.succeed(message);
|
|
8958
9413
|
if (flags.verbose) {
|
|
8959
9414
|
if (missingKeys.length > 0) {
|
|
8960
|
-
console.log(` ${chalk13.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`);
|
|
8961
9415
|
console.log(
|
|
8962
|
-
` ${chalk13.
|
|
9416
|
+
` ${chalk13.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`
|
|
9417
|
+
);
|
|
9418
|
+
console.log(
|
|
9419
|
+
` ${chalk13.red(`Missing:`)} ${missingKeys.length} keys, ~${wordsToTranslate} words`
|
|
9420
|
+
);
|
|
9421
|
+
console.log(
|
|
9422
|
+
` ${chalk13.dim(
|
|
9423
|
+
`Example missing: ${missingKeys.slice(0, 2).join(", ")}${missingKeys.length > 2 ? "..." : ""}`
|
|
9424
|
+
)}`
|
|
8963
9425
|
);
|
|
8964
9426
|
}
|
|
8965
9427
|
if (updatedKeys.length > 0) {
|
|
8966
|
-
console.log(
|
|
9428
|
+
console.log(
|
|
9429
|
+
` ${chalk13.yellow(`Updated:`)} ${updatedKeys.length} keys that changed in source`
|
|
9430
|
+
);
|
|
8967
9431
|
}
|
|
8968
9432
|
}
|
|
8969
9433
|
}
|
|
@@ -8973,9 +9437,12 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8973
9437
|
ora.fail(`Failed to analyze bucket ${bucket.type}: ${error.message}`);
|
|
8974
9438
|
}
|
|
8975
9439
|
}
|
|
8976
|
-
const totalKeysNeedingTranslation = Object.values(languageStats).reduce(
|
|
8977
|
-
|
|
8978
|
-
|
|
9440
|
+
const totalKeysNeedingTranslation = Object.values(languageStats).reduce(
|
|
9441
|
+
(sum, stats) => {
|
|
9442
|
+
return sum + stats.missing + stats.updated;
|
|
9443
|
+
},
|
|
9444
|
+
0
|
|
9445
|
+
);
|
|
8979
9446
|
const totalCompletedKeys = totalSourceKeyCount - totalKeysNeedingTranslation / targetLocales.length;
|
|
8980
9447
|
console.log();
|
|
8981
9448
|
ora.succeed(chalk13.green(`Localization status completed.`));
|
|
@@ -8985,12 +9452,26 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
8985
9452
|
console.log(chalk13.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`));
|
|
8986
9453
|
console.log(chalk13.bold(`
|
|
8987
9454
|
\u{1F4DD} SOURCE CONTENT:`));
|
|
8988
|
-
console.log(
|
|
8989
|
-
|
|
9455
|
+
console.log(
|
|
9456
|
+
`\u2022 Source language: ${chalk13.green(i18nConfig.locale.source)}`
|
|
9457
|
+
);
|
|
9458
|
+
console.log(
|
|
9459
|
+
`\u2022 Source keys: ${chalk13.yellow(
|
|
9460
|
+
totalSourceKeyCount.toString()
|
|
9461
|
+
)} keys across all files`
|
|
9462
|
+
);
|
|
8990
9463
|
console.log(chalk13.bold(`
|
|
8991
9464
|
\u{1F310} LANGUAGE BY LANGUAGE BREAKDOWN:`));
|
|
8992
9465
|
const table = new Table({
|
|
8993
|
-
head: [
|
|
9466
|
+
head: [
|
|
9467
|
+
"Language",
|
|
9468
|
+
"Status",
|
|
9469
|
+
"Complete",
|
|
9470
|
+
"Missing",
|
|
9471
|
+
"Updated",
|
|
9472
|
+
"Total Keys",
|
|
9473
|
+
"Words to Translate"
|
|
9474
|
+
],
|
|
8994
9475
|
style: {
|
|
8995
9476
|
head: ["white"],
|
|
8996
9477
|
// White color for headers
|
|
@@ -9039,15 +9520,21 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9039
9520
|
console.log(chalk13.bold(`
|
|
9040
9521
|
\u{1F4CA} USAGE ESTIMATE:`));
|
|
9041
9522
|
console.log(
|
|
9042
|
-
`\u2022 WORDS TO BE CONSUMED: ~${chalk13.yellow.bold(
|
|
9523
|
+
`\u2022 WORDS TO BE CONSUMED: ~${chalk13.yellow.bold(
|
|
9524
|
+
totalWordsToTranslate.toLocaleString()
|
|
9525
|
+
)} words across all languages`
|
|
9526
|
+
);
|
|
9527
|
+
console.log(
|
|
9528
|
+
` (Words are counted from source language for keys that need translation in target languages)`
|
|
9043
9529
|
);
|
|
9044
|
-
console.log(` (Words are counted from source language for keys that need translation in target languages)`);
|
|
9045
9530
|
if (targetLocales.length > 1) {
|
|
9046
9531
|
console.log(`\u2022 Per-language breakdown:`);
|
|
9047
9532
|
for (const locale of targetLocales) {
|
|
9048
9533
|
const words = totalWordCount.get(locale) || 0;
|
|
9049
9534
|
const percent = (words / totalWordsToTranslate * 100).toFixed(1);
|
|
9050
|
-
console.log(
|
|
9535
|
+
console.log(
|
|
9536
|
+
` - ${locale}: ~${words.toLocaleString()} words (${percent}% of total)`
|
|
9537
|
+
);
|
|
9051
9538
|
}
|
|
9052
9539
|
}
|
|
9053
9540
|
if (flags.confirm && Object.keys(fileStats).length > 0) {
|
|
@@ -9057,7 +9544,9 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9057
9544
|
if (stats.sourceKeys === 0) return;
|
|
9058
9545
|
console.log(chalk13.bold(`
|
|
9059
9546
|
\u2022 ${path17}:`));
|
|
9060
|
-
console.log(
|
|
9547
|
+
console.log(
|
|
9548
|
+
` ${stats.sourceKeys} source keys, ~${stats.wordCount.toLocaleString()} source words`
|
|
9549
|
+
);
|
|
9061
9550
|
const fileTable = new Table({
|
|
9062
9551
|
head: ["Language", "Status", "Details"],
|
|
9063
9552
|
style: {
|
|
@@ -9084,8 +9573,10 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9084
9573
|
let details = "";
|
|
9085
9574
|
if (langStats.missing > 0 || langStats.updated > 0) {
|
|
9086
9575
|
const parts = [];
|
|
9087
|
-
if (langStats.missing > 0)
|
|
9088
|
-
|
|
9576
|
+
if (langStats.missing > 0)
|
|
9577
|
+
parts.push(`${langStats.missing} missing`);
|
|
9578
|
+
if (langStats.updated > 0)
|
|
9579
|
+
parts.push(`${langStats.updated} changed`);
|
|
9089
9580
|
details = `${parts.join(", ")}, ~${langStats.words} words`;
|
|
9090
9581
|
} else {
|
|
9091
9582
|
details = "All keys translated";
|
|
@@ -9098,7 +9589,9 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9098
9589
|
const completeLanguages = targetLocales.filter(
|
|
9099
9590
|
(locale) => languageStats[locale].missing === 0 && languageStats[locale].updated === 0
|
|
9100
9591
|
);
|
|
9101
|
-
const missingLanguages = targetLocales.filter(
|
|
9592
|
+
const missingLanguages = targetLocales.filter(
|
|
9593
|
+
(locale) => languageStats[locale].complete === 0
|
|
9594
|
+
);
|
|
9102
9595
|
console.log(chalk13.bold.green(`
|
|
9103
9596
|
\u{1F4A1} OPTIMIZATION TIPS:`));
|
|
9104
9597
|
if (missingLanguages.length > 0) {
|
|
@@ -9113,7 +9606,9 @@ var status_default = new Command18().command("status").description("Show the sta
|
|
|
9113
9606
|
}
|
|
9114
9607
|
if (targetLocales.length > 1) {
|
|
9115
9608
|
console.log(`\u2022 Translating one language at a time reduces complexity`);
|
|
9116
|
-
console.log(
|
|
9609
|
+
console.log(
|
|
9610
|
+
`\u2022 Try 'lingo.dev@latest i18n --locale ${targetLocales[0]}' to process just one language`
|
|
9611
|
+
);
|
|
9117
9612
|
}
|
|
9118
9613
|
trackEvent(authId || "status", "cmd.status.success", {
|
|
9119
9614
|
i18nConfig,
|
|
@@ -9175,7 +9670,9 @@ function validateParams2(i18nConfig, flags) {
|
|
|
9175
9670
|
message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
|
|
9176
9671
|
docUrl: "localeTargetNotFound"
|
|
9177
9672
|
});
|
|
9178
|
-
} else if (flags.bucket?.some(
|
|
9673
|
+
} else if (flags.bucket?.some(
|
|
9674
|
+
(bucket) => !i18nConfig.buckets[bucket]
|
|
9675
|
+
)) {
|
|
9179
9676
|
throw new CLIError({
|
|
9180
9677
|
message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
|
|
9181
9678
|
docUrl: "bucketNotFound"
|
|
@@ -9220,7 +9717,9 @@ var may_the_fourth_default = new Command19().command("may-the-fourth").descripti
|
|
|
9220
9717
|
});
|
|
9221
9718
|
await renderSpacer2();
|
|
9222
9719
|
console.log(
|
|
9223
|
-
`${chalk14.hex(colors2.green)("We hope you enjoyed it! :)")} ${chalk14.hex(
|
|
9720
|
+
`${chalk14.hex(colors2.green)("We hope you enjoyed it! :)")} ${chalk14.hex(
|
|
9721
|
+
colors2.blue
|
|
9722
|
+
)("May the Fourth be with you! \u{1F680}")}`
|
|
9224
9723
|
);
|
|
9225
9724
|
await renderSpacer2();
|
|
9226
9725
|
console.log(chalk14.dim(`---`));
|
|
@@ -9246,7 +9745,9 @@ async function renderBanner2() {
|
|
|
9246
9745
|
}
|
|
9247
9746
|
async function renderHero2() {
|
|
9248
9747
|
console.log(
|
|
9249
|
-
`\u26A1\uFE0F ${chalk14.hex(colors2.green)(
|
|
9748
|
+
`\u26A1\uFE0F ${chalk14.hex(colors2.green)(
|
|
9749
|
+
"Lingo.dev"
|
|
9750
|
+
)} - open-source, AI-powered i18n CLI for web & mobile localization.`
|
|
9250
9751
|
);
|
|
9251
9752
|
console.log(" ");
|
|
9252
9753
|
console.log(
|
|
@@ -9258,7 +9759,7 @@ async function renderHero2() {
|
|
|
9258
9759
|
// package.json
|
|
9259
9760
|
var package_default = {
|
|
9260
9761
|
name: "lingo.dev",
|
|
9261
|
-
version: "0.
|
|
9762
|
+
version: "0.101.0",
|
|
9262
9763
|
description: "Lingo.dev CLI",
|
|
9263
9764
|
private: false,
|
|
9264
9765
|
publishConfig: {
|
|
@@ -9372,6 +9873,7 @@ var package_default = {
|
|
|
9372
9873
|
dependencies: {
|
|
9373
9874
|
"@ai-sdk/anthropic": "^1.2.11",
|
|
9374
9875
|
"@ai-sdk/google": "^1.2.19",
|
|
9876
|
+
"@ai-sdk/mistral": "^1.2.8",
|
|
9375
9877
|
"@ai-sdk/openai": "^1.3.22",
|
|
9376
9878
|
"@babel/generator": "^7.27.1",
|
|
9377
9879
|
"@babel/parser": "^7.27.1",
|
|
@@ -9488,6 +9990,167 @@ var package_default = {
|
|
|
9488
9990
|
packageManager: "pnpm@9.12.3"
|
|
9489
9991
|
};
|
|
9490
9992
|
|
|
9993
|
+
// src/cli/cmd/purge.ts
|
|
9994
|
+
import { Command as Command20 } from "interactive-commander";
|
|
9995
|
+
import Ora11 from "ora";
|
|
9996
|
+
import { resolveOverriddenLocale as resolveOverriddenLocale8 } from "@lingo.dev/_spec";
|
|
9997
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
9998
|
+
var purge_default = new Command20().command("purge").description(
|
|
9999
|
+
"Remove translations for given --bucket, --file, --key, --locale"
|
|
10000
|
+
).helpOption("-h, --help", "Show help").option(
|
|
10001
|
+
"--bucket <bucket>",
|
|
10002
|
+
"Bucket to process",
|
|
10003
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
10004
|
+
).option(
|
|
10005
|
+
"--file [files...]",
|
|
10006
|
+
"File(s) to process. Only process files that match the given glob pattern(s)."
|
|
10007
|
+
).option(
|
|
10008
|
+
"--key <key>",
|
|
10009
|
+
"Key to remove. Remove all translation keys matching the given glob pattern."
|
|
10010
|
+
).option(
|
|
10011
|
+
"--locale <locale>",
|
|
10012
|
+
"Locale to process",
|
|
10013
|
+
(val, prev) => prev ? [...prev, val] : [val]
|
|
10014
|
+
).option(
|
|
10015
|
+
"--yes-really",
|
|
10016
|
+
"Skip interactive confirmation and delete without asking."
|
|
10017
|
+
).action(async function(options) {
|
|
10018
|
+
const ora = Ora11();
|
|
10019
|
+
try {
|
|
10020
|
+
ora.start("Loading configuration...");
|
|
10021
|
+
const i18nConfig = getConfig();
|
|
10022
|
+
if (!i18nConfig) {
|
|
10023
|
+
throw new Error("i18n.json not found. Please run `lingo.dev init`.");
|
|
10024
|
+
}
|
|
10025
|
+
ora.succeed("Configuration loaded");
|
|
10026
|
+
let buckets = getBuckets(i18nConfig);
|
|
10027
|
+
if (options.bucket && options.bucket.length) {
|
|
10028
|
+
buckets = buckets.filter(
|
|
10029
|
+
(bucket) => options.bucket.includes(bucket.type)
|
|
10030
|
+
);
|
|
10031
|
+
}
|
|
10032
|
+
if (options.file && options.file.length) {
|
|
10033
|
+
buckets = buckets.map((bucket) => {
|
|
10034
|
+
const paths = bucket.paths.filter(
|
|
10035
|
+
(bucketPath) => options.file?.some((f) => bucketPath.pathPattern.includes(f))
|
|
10036
|
+
);
|
|
10037
|
+
return { ...bucket, paths };
|
|
10038
|
+
}).filter((bucket) => bucket.paths.length > 0);
|
|
10039
|
+
if (buckets.length === 0) {
|
|
10040
|
+
ora.fail("All files were filtered out by --file option.");
|
|
10041
|
+
process.exit(1);
|
|
10042
|
+
}
|
|
10043
|
+
}
|
|
10044
|
+
const sourceLocale = i18nConfig.locale.source;
|
|
10045
|
+
const targetLocales = options.locale && options.locale.length ? options.locale : i18nConfig.locale.targets;
|
|
10046
|
+
let removedAny = false;
|
|
10047
|
+
for (const bucket of buckets) {
|
|
10048
|
+
console.log();
|
|
10049
|
+
ora.info(`Processing bucket: ${bucket.type}`);
|
|
10050
|
+
for (const bucketPath of bucket.paths) {
|
|
10051
|
+
for (const _targetLocale of targetLocales) {
|
|
10052
|
+
const targetLocale = resolveOverriddenLocale8(
|
|
10053
|
+
_targetLocale,
|
|
10054
|
+
bucketPath.delimiter
|
|
10055
|
+
);
|
|
10056
|
+
const bucketOra = Ora11({ indent: 2 }).start(
|
|
10057
|
+
`Processing path: ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10058
|
+
);
|
|
10059
|
+
try {
|
|
10060
|
+
const bucketLoader = createBucketLoader(
|
|
10061
|
+
bucket.type,
|
|
10062
|
+
bucketPath.pathPattern,
|
|
10063
|
+
{
|
|
10064
|
+
defaultLocale: sourceLocale,
|
|
10065
|
+
injectLocale: bucket.injectLocale
|
|
10066
|
+
},
|
|
10067
|
+
bucket.lockedKeys,
|
|
10068
|
+
bucket.lockedPatterns,
|
|
10069
|
+
bucket.ignoredKeys
|
|
10070
|
+
);
|
|
10071
|
+
await bucketLoader.init();
|
|
10072
|
+
bucketLoader.setDefaultLocale(sourceLocale);
|
|
10073
|
+
await bucketLoader.pull(sourceLocale);
|
|
10074
|
+
let targetData = await bucketLoader.pull(targetLocale);
|
|
10075
|
+
if (!targetData || Object.keys(targetData).length === 0) {
|
|
10076
|
+
bucketOra.info(
|
|
10077
|
+
`No translations found for ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10078
|
+
);
|
|
10079
|
+
continue;
|
|
10080
|
+
}
|
|
10081
|
+
let newData = { ...targetData };
|
|
10082
|
+
let keysToRemove = [];
|
|
10083
|
+
if (options.key) {
|
|
10084
|
+
keysToRemove = Object.keys(newData).filter(
|
|
10085
|
+
(k) => minimatch(k, options.key)
|
|
10086
|
+
);
|
|
10087
|
+
} else {
|
|
10088
|
+
keysToRemove = Object.keys(newData);
|
|
10089
|
+
}
|
|
10090
|
+
if (keysToRemove.length > 0) {
|
|
10091
|
+
if (options.key) {
|
|
10092
|
+
bucketOra.info(
|
|
10093
|
+
`About to delete ${keysToRemove.length} key(s) matching '${options.key}' from ${bucketPath.pathPattern} [${targetLocale}]:
|
|
10094
|
+
${keysToRemove.slice(0, 10).join(", ")}${keysToRemove.length > 10 ? ", ..." : ""}`
|
|
10095
|
+
);
|
|
10096
|
+
} else {
|
|
10097
|
+
bucketOra.info(
|
|
10098
|
+
`About to delete all (${keysToRemove.length}) keys from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10099
|
+
);
|
|
10100
|
+
}
|
|
10101
|
+
if (!options.yesReally) {
|
|
10102
|
+
bucketOra.warn(
|
|
10103
|
+
"This is a destructive operation. If you are sure, type 'y' to continue. (Use --yes-really to skip this check.)"
|
|
10104
|
+
);
|
|
10105
|
+
const confirmed = await confirm3({
|
|
10106
|
+
message: `Delete these keys from ${bucketPath.pathPattern} [${targetLocale}]?`,
|
|
10107
|
+
default: false
|
|
10108
|
+
});
|
|
10109
|
+
if (!confirmed) {
|
|
10110
|
+
bucketOra.info("Skipped by user.");
|
|
10111
|
+
continue;
|
|
10112
|
+
}
|
|
10113
|
+
}
|
|
10114
|
+
for (const key of keysToRemove) {
|
|
10115
|
+
delete newData[key];
|
|
10116
|
+
}
|
|
10117
|
+
removedAny = true;
|
|
10118
|
+
await bucketLoader.push(targetLocale, newData);
|
|
10119
|
+
if (options.key) {
|
|
10120
|
+
bucketOra.succeed(
|
|
10121
|
+
`Removed ${keysToRemove.length} key(s) matching '${options.key}' from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10122
|
+
);
|
|
10123
|
+
} else {
|
|
10124
|
+
bucketOra.succeed(
|
|
10125
|
+
`Removed all keys (${keysToRemove.length}) from ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10126
|
+
);
|
|
10127
|
+
}
|
|
10128
|
+
} else if (options.key) {
|
|
10129
|
+
bucketOra.info(
|
|
10130
|
+
`No keys matching '${options.key}' found in ${bucketPath.pathPattern} [${targetLocale}]`
|
|
10131
|
+
);
|
|
10132
|
+
} else {
|
|
10133
|
+
bucketOra.info("No keys to remove.");
|
|
10134
|
+
}
|
|
10135
|
+
} catch (error) {
|
|
10136
|
+
const err = error;
|
|
10137
|
+
bucketOra.fail(`Failed: ${err.message}`);
|
|
10138
|
+
}
|
|
10139
|
+
}
|
|
10140
|
+
}
|
|
10141
|
+
}
|
|
10142
|
+
if (!removedAny) {
|
|
10143
|
+
ora.info("No keys were removed.");
|
|
10144
|
+
} else {
|
|
10145
|
+
ora.succeed("Purge completed.");
|
|
10146
|
+
}
|
|
10147
|
+
} catch (error) {
|
|
10148
|
+
const err = error;
|
|
10149
|
+
ora.fail(err.message);
|
|
10150
|
+
process.exit(1);
|
|
10151
|
+
}
|
|
10152
|
+
});
|
|
10153
|
+
|
|
9491
10154
|
// src/cli/index.ts
|
|
9492
10155
|
dotenv.config();
|
|
9493
10156
|
var cli_default = new InteractiveCommand2().name("lingo.dev").description("Lingo.dev CLI").helpOption("-h, --help", "Show help").addHelpText(
|
|
@@ -9505,7 +10168,7 @@ ${vice3(
|
|
|
9505
10168
|
|
|
9506
10169
|
Star the the repo :) https://github.com/LingoDotDev/lingo.dev
|
|
9507
10170
|
`
|
|
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
|
|
10171
|
+
).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
10172
|
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
9510
10173
|
process.exit(0);
|
|
9511
10174
|
}
|