lingo.dev 0.70.3 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/{chunk-DTGLPBE5.cjs → chunk-BCCNAFJB.cjs} +1 -0
- package/build/chunk-BCCNAFJB.cjs.map +1 -0
- package/build/{chunk-VHJ5VG2A.cjs → chunk-HODTYTE5.cjs} +10 -9
- package/build/chunk-HODTYTE5.cjs.map +1 -0
- package/build/{chunk-3TBVVQ2O.mjs → chunk-NF6GBJ2R.mjs} +1 -0
- package/build/chunk-NF6GBJ2R.mjs.map +1 -0
- package/build/{chunk-KXNC44RG.mjs → chunk-NUMPOGXY.mjs} +7 -6
- package/build/chunk-NUMPOGXY.mjs.map +1 -0
- package/build/cli.cjs +268 -105
- package/build/cli.cjs.map +1 -0
- package/build/cli.mjs +246 -83
- package/build/cli.mjs.map +1 -0
- package/build/sdk.cjs +4 -3
- package/build/sdk.cjs.map +1 -0
- package/build/sdk.mjs +3 -2
- package/build/sdk.mjs.map +1 -0
- package/build/spec.cjs +3 -2
- package/build/spec.cjs.map +1 -0
- package/build/spec.mjs +2 -1
- package/build/spec.mjs.map +1 -0
- package/package.json +6 -2
package/build/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ReplexicaEngine
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NUMPOGXY.mjs";
|
|
4
4
|
import {
|
|
5
5
|
bucketTypeSchema,
|
|
6
6
|
bucketTypes,
|
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
parseI18nConfig,
|
|
11
11
|
resolveLocaleCode,
|
|
12
12
|
resolveOverridenLocale
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-NF6GBJ2R.mjs";
|
|
14
14
|
|
|
15
15
|
// src/cli/index.ts
|
|
16
16
|
import dotenv from "dotenv";
|
|
17
17
|
import { InteractiveCommand as InteractiveCommand2 } from "interactive-commander";
|
|
18
|
+
import figlet from "figlet";
|
|
19
|
+
import { vice } from "gradient-string";
|
|
18
20
|
|
|
19
21
|
// src/cli/cli/auth.ts
|
|
20
22
|
import { Command } from "interactive-commander";
|
|
@@ -34,11 +36,12 @@ function getSettings(explicitApiKey) {
|
|
|
34
36
|
const env = _loadEnv();
|
|
35
37
|
const systemFile = _loadSystemFile();
|
|
36
38
|
const defaults = _loadDefaults();
|
|
39
|
+
_legacyEnvVarWarning();
|
|
37
40
|
return {
|
|
38
41
|
auth: {
|
|
39
|
-
apiKey: explicitApiKey || env.
|
|
40
|
-
apiUrl: env.
|
|
41
|
-
webUrl: env.
|
|
42
|
+
apiKey: explicitApiKey || env.LINGODOTDEV_API_KEY || systemFile.auth?.apiKey || defaults.auth.apiKey,
|
|
43
|
+
apiUrl: env.LINGODOTDEV_API_URL || systemFile.auth?.apiUrl || defaults.auth.apiUrl,
|
|
44
|
+
webUrl: env.LINGODOTDEV_WEB_URL || systemFile.auth?.webUrl || defaults.auth.webUrl
|
|
42
45
|
}
|
|
43
46
|
};
|
|
44
47
|
}
|
|
@@ -56,16 +59,16 @@ function _loadDefaults() {
|
|
|
56
59
|
return {
|
|
57
60
|
auth: {
|
|
58
61
|
apiKey: "",
|
|
59
|
-
apiUrl: "https://engine.
|
|
60
|
-
webUrl: "https://
|
|
62
|
+
apiUrl: "https://engine.lingo.dev",
|
|
63
|
+
webUrl: "https://lingo.dev"
|
|
61
64
|
}
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
function _loadEnv() {
|
|
65
68
|
return Z.object({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
LINGODOTDEV_API_KEY: Z.string().optional(),
|
|
70
|
+
LINGODOTDEV_API_URL: Z.string().optional(),
|
|
71
|
+
LINGODOTDEV_WEB_URL: Z.string().optional()
|
|
69
72
|
}).passthrough().parse(process.env);
|
|
70
73
|
}
|
|
71
74
|
function _loadSystemFile() {
|
|
@@ -86,30 +89,45 @@ function _saveSystemFile(settings) {
|
|
|
86
89
|
fs.writeFileSync(settingsFilePath, content);
|
|
87
90
|
}
|
|
88
91
|
function _getSettingsFilePath() {
|
|
89
|
-
const settingsFile = ".
|
|
92
|
+
const settingsFile = ".lingodotdevrc";
|
|
90
93
|
const homedir = os.homedir();
|
|
91
94
|
const settingsFilePath = path.join(homedir, settingsFile);
|
|
92
95
|
return settingsFilePath;
|
|
93
96
|
}
|
|
97
|
+
function _legacyEnvVarWarning() {
|
|
98
|
+
const env = _loadEnv();
|
|
99
|
+
if (env.REPLEXICA_API_KEY && !env.LINGODOTDEV_API_KEY) {
|
|
100
|
+
console.warn(
|
|
101
|
+
"\x1B[33m%s\x1B[0m",
|
|
102
|
+
`
|
|
103
|
+
\u26A0\uFE0F WARNING: REPLEXICA_API_KEY env var is deprecated \u26A0\uFE0F
|
|
104
|
+
===========================================================
|
|
105
|
+
|
|
106
|
+
Please use LINGODOTDEV_API_KEY instead.
|
|
107
|
+
===========================================================
|
|
108
|
+
`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
94
112
|
|
|
95
113
|
// src/cli/utils/errors.ts
|
|
96
114
|
var docLinks = {
|
|
97
|
-
i18nNotFound: "https://docs.
|
|
98
|
-
bucketNotFound: "https://docs.
|
|
99
|
-
authError: "https://docs.
|
|
100
|
-
localeTargetNotFound: "https://docs.
|
|
101
|
-
lockFiletNotFound: "https://docs.
|
|
102
|
-
failedReplexicaEngine: "https://docs.
|
|
103
|
-
placeHolderFailed: "https://docs.
|
|
104
|
-
translationFailed: "https://docs.
|
|
105
|
-
connectionFailed: "https://docs.
|
|
106
|
-
invalidType: "https://docs.
|
|
107
|
-
invalidPathPattern: "https://docs.
|
|
108
|
-
androidResouceError: "https://docs.
|
|
109
|
-
invalidBucketType: "https://docs.
|
|
110
|
-
invalidStringDict: "https://docs.
|
|
115
|
+
i18nNotFound: "https://docs.lingo.dev/quickstart#initialization",
|
|
116
|
+
bucketNotFound: "https://docs.lingo.dev/config#buckets",
|
|
117
|
+
authError: "https://docs.lingo.dev/auth",
|
|
118
|
+
localeTargetNotFound: "https://docs.lingo.dev/config#locale",
|
|
119
|
+
lockFiletNotFound: "https://docs.lingo.dev/config#i18n-lock",
|
|
120
|
+
failedReplexicaEngine: "https://docs.lingo.dev/",
|
|
121
|
+
placeHolderFailed: "https://docs.lingo.dev/formats/json",
|
|
122
|
+
translationFailed: "https://docs.lingo.dev/setup/cli#core-command-i18n",
|
|
123
|
+
connectionFailed: "https://docs.lingo.dev/",
|
|
124
|
+
invalidType: "https://docs.lingo.dev/setup/cli#configuration-commands",
|
|
125
|
+
invalidPathPattern: "https://docs.lingo.dev/config#buckets",
|
|
126
|
+
androidResouceError: "https://docs.lingo.dev/formats/android",
|
|
127
|
+
invalidBucketType: "https://docs.lingo.dev/config#buckets",
|
|
128
|
+
invalidStringDict: "https://docs.lingo.dev/formats/xcode-stringsdict"
|
|
111
129
|
};
|
|
112
|
-
var
|
|
130
|
+
var CLIError = class extends Error {
|
|
113
131
|
docUrl;
|
|
114
132
|
constructor({ message, docUrl }) {
|
|
115
133
|
super(message);
|
|
@@ -144,7 +162,7 @@ function createAuthenticator(params) {
|
|
|
144
162
|
} catch (error) {
|
|
145
163
|
const isNetworkError = error instanceof TypeError && error.message === "fetch failed";
|
|
146
164
|
if (isNetworkError) {
|
|
147
|
-
throw new
|
|
165
|
+
throw new CLIError({
|
|
148
166
|
message: `Failed to connect to the API at ${params.apiUrl}. Please check your connection and try again.`,
|
|
149
167
|
docUrl: "connectionFailed"
|
|
150
168
|
});
|
|
@@ -157,7 +175,7 @@ function createAuthenticator(params) {
|
|
|
157
175
|
}
|
|
158
176
|
|
|
159
177
|
// src/cli/cli/auth.ts
|
|
160
|
-
var auth_default = new Command().command("auth").description("Authenticate with
|
|
178
|
+
var auth_default = new Command().command("auth").description("Authenticate with Lingo.dev API").helpOption("-h, --help", "Show help").option("--logout", "Delete existing authentication").option("--login", "Authenticate with Lingo.dev API").action(async (options) => {
|
|
161
179
|
try {
|
|
162
180
|
let settings = await getSettings(void 0);
|
|
163
181
|
if (options.logout) {
|
|
@@ -195,7 +213,7 @@ Press Enter to open the browser for authentication.
|
|
|
195
213
|
|
|
196
214
|
---
|
|
197
215
|
|
|
198
|
-
Having issues? Put
|
|
216
|
+
Having issues? Put LINGODOTDEV_API_KEY in your .env file instead.
|
|
199
217
|
`.trim() + "\n"
|
|
200
218
|
);
|
|
201
219
|
const spinner = Ora().start("Waiting for the API key");
|
|
@@ -262,9 +280,9 @@ import fs3 from "fs";
|
|
|
262
280
|
import { spawn } from "child_process";
|
|
263
281
|
import _2 from "lodash";
|
|
264
282
|
import { confirm } from "@inquirer/prompts";
|
|
265
|
-
var openUrl = (
|
|
283
|
+
var openUrl = (path8) => {
|
|
266
284
|
const settings = getSettings(void 0);
|
|
267
|
-
spawn("open", [`${settings.auth.webUrl}${
|
|
285
|
+
spawn("open", [`${settings.auth.webUrl}${path8}`]);
|
|
268
286
|
};
|
|
269
287
|
var throwHelpError = (option, value) => {
|
|
270
288
|
if (value === "help") {
|
|
@@ -276,7 +294,7 @@ var throwHelpError = (option, value) => {
|
|
|
276
294
|
Do you need support for ${value} ${option}? Type "help" and we will.`
|
|
277
295
|
);
|
|
278
296
|
};
|
|
279
|
-
var init_default = new InteractiveCommand().command("init").description("Initialize
|
|
297
|
+
var init_default = new InteractiveCommand().command("init").description("Initialize Lingo.dev project").helpOption("-h, --help", "Show help").addOption(new InteractiveOption("-f --force", "Overwrite existing config").prompt(void 0).default(false)).addOption(
|
|
280
298
|
new InteractiveOption("-s --source <locale>", "Source locale").argParser((value) => {
|
|
281
299
|
try {
|
|
282
300
|
resolveLocaleCode(value);
|
|
@@ -307,24 +325,24 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
307
325
|
).addOption(
|
|
308
326
|
new InteractiveOption("-p, --paths <path...>", "List of paths for the bucket").argParser((value) => {
|
|
309
327
|
const values = value.includes(",") ? value.split(",") : value.split(" ");
|
|
310
|
-
for (const
|
|
328
|
+
for (const path8 of values) {
|
|
311
329
|
try {
|
|
312
|
-
const stats = fs3.statSync(
|
|
330
|
+
const stats = fs3.statSync(path8);
|
|
313
331
|
if (!stats.isDirectory()) {
|
|
314
|
-
throw new Error(`${
|
|
332
|
+
throw new Error(`${path8} is not a directory`);
|
|
315
333
|
}
|
|
316
334
|
} catch (err) {
|
|
317
|
-
throw new Error(`Invalid directory path: ${
|
|
335
|
+
throw new Error(`Invalid directory path: ${path8}`);
|
|
318
336
|
}
|
|
319
337
|
}
|
|
320
338
|
return values;
|
|
321
339
|
}).default(".")
|
|
322
340
|
).action(async (options) => {
|
|
323
341
|
const settings = getSettings(void 0);
|
|
324
|
-
const spinner = Ora2().start("Initializing
|
|
342
|
+
const spinner = Ora2().start("Initializing Lingo.dev project");
|
|
325
343
|
let existingConfig = await getConfig(false);
|
|
326
344
|
if (existingConfig && !options.force) {
|
|
327
|
-
spinner.fail("
|
|
345
|
+
spinner.fail("Lingo.dev project already initialized");
|
|
328
346
|
return process.exit(1);
|
|
329
347
|
}
|
|
330
348
|
const newConfig = _2.cloneDeep(defaultConfig);
|
|
@@ -334,7 +352,7 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
334
352
|
[options.bucket]: options.paths
|
|
335
353
|
};
|
|
336
354
|
await saveConfig(newConfig);
|
|
337
|
-
spinner.succeed("
|
|
355
|
+
spinner.succeed("Lingo.dev project initialized");
|
|
338
356
|
const isInteractive = !process.argv.includes("-y") && !process.argv.includes("--no-interactive");
|
|
339
357
|
if (isInteractive) {
|
|
340
358
|
const openDocs = await confirm({ message: "Would you like to see our docs?" });
|
|
@@ -368,13 +386,13 @@ var init_default = new InteractiveCommand().command("init").description("Initial
|
|
|
368
386
|
}
|
|
369
387
|
}
|
|
370
388
|
} else {
|
|
371
|
-
Ora2().warn("You are not logged in. Run `npx
|
|
389
|
+
Ora2().warn("You are not logged in. Run `npx lingo.dev@latest auth --login` to login.");
|
|
372
390
|
}
|
|
373
391
|
} else {
|
|
374
392
|
Ora2().succeed(`Authenticated as ${auth.email}`);
|
|
375
393
|
}
|
|
376
394
|
if (!isInteractive) {
|
|
377
|
-
Ora2().info("Please see https://docs.
|
|
395
|
+
Ora2().info("Please see https://docs.lingo.dev/");
|
|
378
396
|
}
|
|
379
397
|
});
|
|
380
398
|
|
|
@@ -410,7 +428,7 @@ var locale_default = new Command3().command("locale").description("Print out the
|
|
|
410
428
|
try {
|
|
411
429
|
switch (type) {
|
|
412
430
|
default:
|
|
413
|
-
throw new
|
|
431
|
+
throw new CLIError({
|
|
414
432
|
message: `Invalid type: ${type}`,
|
|
415
433
|
docUrl: "invalidType"
|
|
416
434
|
});
|
|
@@ -470,19 +488,19 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
|
|
|
470
488
|
const absolutePathPattern = path4.resolve(_pathPattern);
|
|
471
489
|
const pathPattern = path4.relative(process.cwd(), absolutePathPattern);
|
|
472
490
|
if (path4.relative(process.cwd(), pathPattern).startsWith("..")) {
|
|
473
|
-
throw new
|
|
491
|
+
throw new CLIError({
|
|
474
492
|
message: `Invalid path pattern: ${pathPattern}. Path pattern must be within the current working directory.`,
|
|
475
493
|
docUrl: "invalidPathPattern"
|
|
476
494
|
});
|
|
477
495
|
}
|
|
478
496
|
if (pathPattern.includes("**")) {
|
|
479
|
-
throw new
|
|
497
|
+
throw new CLIError({
|
|
480
498
|
message: `Invalid path pattern: ${pathPattern}. Recursive path patterns are not supported.`,
|
|
481
499
|
docUrl: "invalidPathPattern"
|
|
482
500
|
});
|
|
483
501
|
}
|
|
484
502
|
if (pathPattern.split("[locale]").length > 2) {
|
|
485
|
-
throw new
|
|
503
|
+
throw new CLIError({
|
|
486
504
|
message: `Invalid path pattern: ${pathPattern}. Path pattern must contain at most one "[locale]" placeholder.`,
|
|
487
505
|
docUrl: "invalidPathPattern"
|
|
488
506
|
});
|
|
@@ -512,14 +530,14 @@ function resolveBucketItem(bucketItem) {
|
|
|
512
530
|
}
|
|
513
531
|
|
|
514
532
|
// src/cli/cli/show/files.ts
|
|
515
|
-
var files_default = new Command4().command("files").description("Print out the list of files managed by
|
|
533
|
+
var files_default = new Command4().command("files").description("Print out the list of files managed by Lingo.dev").option("--source", "Only show source files").option("--target", "Only show target files").helpOption("-h, --help", "Show help").action(async (type) => {
|
|
516
534
|
const ora = Ora4();
|
|
517
535
|
try {
|
|
518
536
|
try {
|
|
519
537
|
const i18nConfig = await getConfig();
|
|
520
538
|
if (!i18nConfig) {
|
|
521
|
-
throw new
|
|
522
|
-
message: "i18n.json not found. Please run `
|
|
539
|
+
throw new CLIError({
|
|
540
|
+
message: "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
|
|
523
541
|
docUrl: "i18nNotFound"
|
|
524
542
|
});
|
|
525
543
|
}
|
|
@@ -540,13 +558,13 @@ var files_default = new Command4().command("files").description("Print out the l
|
|
|
540
558
|
} else if (type.target) {
|
|
541
559
|
result.push(...targetPaths);
|
|
542
560
|
}
|
|
543
|
-
result.forEach((
|
|
544
|
-
console.log(
|
|
561
|
+
result.forEach((path8) => {
|
|
562
|
+
console.log(path8);
|
|
545
563
|
});
|
|
546
564
|
}
|
|
547
565
|
}
|
|
548
566
|
} catch (error) {
|
|
549
|
-
throw new
|
|
567
|
+
throw new CLIError({
|
|
550
568
|
message: `Failed to expand placeholdered globs: ${error.message}`,
|
|
551
569
|
docUrl: "placeHolderFailed"
|
|
552
570
|
});
|
|
@@ -807,7 +825,7 @@ function createAndroidLoader() {
|
|
|
807
825
|
return result;
|
|
808
826
|
} catch (error) {
|
|
809
827
|
console.error("Error parsing Android resource file:", error);
|
|
810
|
-
throw new
|
|
828
|
+
throw new CLIError({
|
|
811
829
|
message: "Failed to parse Android resource file",
|
|
812
830
|
docUrl: "androidResouceError"
|
|
813
831
|
});
|
|
@@ -979,9 +997,9 @@ function createHtmlLoader() {
|
|
|
979
997
|
const bDepth = b.split("/").length;
|
|
980
998
|
return aDepth - bDepth;
|
|
981
999
|
});
|
|
982
|
-
paths.forEach((
|
|
983
|
-
const value = data[
|
|
984
|
-
const [nodePath, attribute] =
|
|
1000
|
+
paths.forEach((path8) => {
|
|
1001
|
+
const value = data[path8];
|
|
1002
|
+
const [nodePath, attribute] = path8.split("#");
|
|
985
1003
|
const [rootTag, ...indices] = nodePath.split("/");
|
|
986
1004
|
let parent = rootTag === "head" ? document.head : document.body;
|
|
987
1005
|
let current = parent;
|
|
@@ -1149,14 +1167,14 @@ function createXcodeStringsdictLoader() {
|
|
|
1149
1167
|
try {
|
|
1150
1168
|
const parsed = plist.parse(input || emptyData);
|
|
1151
1169
|
if (typeof parsed !== "object" || parsed === null) {
|
|
1152
|
-
throw new
|
|
1170
|
+
throw new CLIError({
|
|
1153
1171
|
message: "Invalid .stringsdict format",
|
|
1154
1172
|
docUrl: "invalidStringDict"
|
|
1155
1173
|
});
|
|
1156
1174
|
}
|
|
1157
1175
|
return parsed;
|
|
1158
1176
|
} catch (error) {
|
|
1159
|
-
throw new
|
|
1177
|
+
throw new CLIError({
|
|
1160
1178
|
message: `Invalid .stringsdict format: ${error.message}`,
|
|
1161
1179
|
docUrl: "invalidStringDict"
|
|
1162
1180
|
});
|
|
@@ -1979,18 +1997,18 @@ function createRawDatoValue(parsedDatoValue, originalRawDatoValue, isClean = fal
|
|
|
1979
1997
|
}
|
|
1980
1998
|
function serializeStructuredText(rawStructuredText) {
|
|
1981
1999
|
return serializeStructuredTextNode(rawStructuredText);
|
|
1982
|
-
function serializeStructuredTextNode(node,
|
|
2000
|
+
function serializeStructuredTextNode(node, path8 = [], acc = {}) {
|
|
1983
2001
|
if ("document" in node) {
|
|
1984
|
-
return serializeStructuredTextNode(node.document, [...
|
|
2002
|
+
return serializeStructuredTextNode(node.document, [...path8, "document"], acc);
|
|
1985
2003
|
}
|
|
1986
2004
|
if (!_13.isNil(node.value)) {
|
|
1987
|
-
acc[[...
|
|
2005
|
+
acc[[...path8, "value"].join(".")] = node.value;
|
|
1988
2006
|
} else if (_13.get(node, "type") === "block") {
|
|
1989
|
-
acc[[...
|
|
2007
|
+
acc[[...path8, "item"].join(".")] = serializeBlock(node.item);
|
|
1990
2008
|
}
|
|
1991
2009
|
if (node.children) {
|
|
1992
2010
|
for (let i = 0; i < node.children.length; i++) {
|
|
1993
|
-
serializeStructuredTextNode(node.children[i], [...
|
|
2011
|
+
serializeStructuredTextNode(node.children[i], [...path8, i.toString()], acc);
|
|
1994
2012
|
}
|
|
1995
2013
|
}
|
|
1996
2014
|
return acc;
|
|
@@ -2049,8 +2067,8 @@ function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = f
|
|
|
2049
2067
|
}
|
|
2050
2068
|
function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
|
|
2051
2069
|
const result = _13.cloneDeep(originalRawStructuredText);
|
|
2052
|
-
for (const [
|
|
2053
|
-
const realPath = _13.chain(
|
|
2070
|
+
for (const [path8, value] of _13.entries(parsedStructuredText)) {
|
|
2071
|
+
const realPath = _13.chain(path8.split(".")).flatMap((s) => !_13.isNaN(_13.toNumber(s)) ? ["children", s] : s).value();
|
|
2054
2072
|
const deserializedValue = createRawDatoValue(value, _13.get(originalRawStructuredText, realPath), true);
|
|
2055
2073
|
_13.set(result, realPath, deserializedValue);
|
|
2056
2074
|
}
|
|
@@ -2395,6 +2413,13 @@ function createLockfileHelper() {
|
|
|
2395
2413
|
lockfile.checksums[sectionKey] = sectionChecksums;
|
|
2396
2414
|
_saveLockfile(lockfile);
|
|
2397
2415
|
},
|
|
2416
|
+
registerPartialSourceData: (pathPattern, partialSourceData) => {
|
|
2417
|
+
const lockfile = _loadLockfile();
|
|
2418
|
+
const sectionKey = MD5(pathPattern);
|
|
2419
|
+
const sectionChecksums = _16.mapValues(partialSourceData, (value) => MD5(value));
|
|
2420
|
+
lockfile.checksums[sectionKey] = _16.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
|
|
2421
|
+
_saveLockfile(lockfile);
|
|
2422
|
+
},
|
|
2398
2423
|
extractUpdatedData: (pathPattern, sourceData) => {
|
|
2399
2424
|
const lockfile = _loadLockfile();
|
|
2400
2425
|
const sectionKey = MD5(pathPattern);
|
|
@@ -2442,6 +2467,75 @@ import chalk from "chalk";
|
|
|
2442
2467
|
import { createTwoFilesPatch } from "diff";
|
|
2443
2468
|
import inquirer2 from "inquirer";
|
|
2444
2469
|
import externalEditor from "external-editor";
|
|
2470
|
+
|
|
2471
|
+
// src/cli/utils/cache.ts
|
|
2472
|
+
import path7 from "path";
|
|
2473
|
+
import fs8 from "fs";
|
|
2474
|
+
var cacheChunk = (targetLocale, sourceChunk, processedChunk) => {
|
|
2475
|
+
const rows = Object.entries(sourceChunk).map(([key, source]) => ({
|
|
2476
|
+
targetLocale,
|
|
2477
|
+
key,
|
|
2478
|
+
source,
|
|
2479
|
+
processed: processedChunk[key]
|
|
2480
|
+
}));
|
|
2481
|
+
_appendToCache(rows);
|
|
2482
|
+
};
|
|
2483
|
+
function getNormalizedCache() {
|
|
2484
|
+
const rows = _loadCache();
|
|
2485
|
+
if (!rows.length) {
|
|
2486
|
+
return null;
|
|
2487
|
+
}
|
|
2488
|
+
const normalized = {};
|
|
2489
|
+
for (const row of rows) {
|
|
2490
|
+
if (!normalized[row.targetLocale]) {
|
|
2491
|
+
normalized[row.targetLocale] = {};
|
|
2492
|
+
}
|
|
2493
|
+
normalized[row.targetLocale][row.key] = {
|
|
2494
|
+
source: row.source,
|
|
2495
|
+
result: row.processed
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
return normalized;
|
|
2499
|
+
}
|
|
2500
|
+
function deleteCache() {
|
|
2501
|
+
const cacheFilePath = _getCacheFilePath();
|
|
2502
|
+
try {
|
|
2503
|
+
fs8.unlinkSync(cacheFilePath);
|
|
2504
|
+
} catch (e) {
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
function _loadCache() {
|
|
2508
|
+
const cacheFilePath = _getCacheFilePath();
|
|
2509
|
+
if (!fs8.existsSync(cacheFilePath)) {
|
|
2510
|
+
return [];
|
|
2511
|
+
}
|
|
2512
|
+
const content = fs8.readFileSync(cacheFilePath, "utf-8");
|
|
2513
|
+
const result = _parseJSONLines(content);
|
|
2514
|
+
return result;
|
|
2515
|
+
}
|
|
2516
|
+
function _appendToCache(rows) {
|
|
2517
|
+
const cacheFilePath = _getCacheFilePath();
|
|
2518
|
+
const lines = _buildJSONLines(rows);
|
|
2519
|
+
fs8.appendFileSync(cacheFilePath, lines);
|
|
2520
|
+
}
|
|
2521
|
+
function _getCacheFilePath() {
|
|
2522
|
+
return path7.join(process.cwd(), "i18n.cache");
|
|
2523
|
+
}
|
|
2524
|
+
function _buildJSONLines(rows) {
|
|
2525
|
+
return rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
|
|
2526
|
+
}
|
|
2527
|
+
function _parseJSONLines(lines) {
|
|
2528
|
+
return lines.split("\n").map(_tryParseJSON).filter((line) => line !== null);
|
|
2529
|
+
}
|
|
2530
|
+
function _tryParseJSON(line) {
|
|
2531
|
+
try {
|
|
2532
|
+
return JSON.parse(line);
|
|
2533
|
+
} catch (e) {
|
|
2534
|
+
return null;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
// src/cli/cli/i18n.ts
|
|
2445
2539
|
var i18n_default = new Command6().command("i18n").description("Run Localization engine").helpOption("-h, --help", "Show help").option("--locale <locale>", "Locale to process", (val, prev) => prev ? [...prev, val] : [val]).option("--bucket <bucket>", "Bucket to process", (val, prev) => prev ? [...prev, val] : [val]).option("--key <key>", "Key to process").option("--frozen", `Don't update the translations and fail if an update is needed`).option("--force", "Ignore lockfile and process all keys").option("--verbose", "Show verbose output").option("--interactive", "Interactive mode").option("--api-key <api-key>", "Explicitly set the API key to use").option("--debug", "Debug mode").option("--strict", "Stop on first error").action(async function(options) {
|
|
2446
2540
|
const ora = Ora5();
|
|
2447
2541
|
const flags = parseFlags(options);
|
|
@@ -2490,6 +2584,45 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
2490
2584
|
} else {
|
|
2491
2585
|
ora.succeed("i18n.lock loaded");
|
|
2492
2586
|
}
|
|
2587
|
+
const cache = getNormalizedCache();
|
|
2588
|
+
if (cache) {
|
|
2589
|
+
console.log();
|
|
2590
|
+
ora.succeed(`Cache loaded. Attempting recovery...`);
|
|
2591
|
+
const cacheOra = Ora5({ indent: 2 });
|
|
2592
|
+
for (const bucket of buckets) {
|
|
2593
|
+
cacheOra.info(`Processing bucket: ${bucket.type}`);
|
|
2594
|
+
for (const bucketConfig of bucket.config) {
|
|
2595
|
+
const bucketOra = ora.info(`Processing path: ${bucketConfig.pathPattern}`);
|
|
2596
|
+
const sourceLocale = resolveOverridenLocale(i18nConfig.locale.source, bucketConfig.delimiter);
|
|
2597
|
+
const bucketLoader = createBucketLoader(bucket.type, bucketConfig.pathPattern);
|
|
2598
|
+
bucketLoader.setDefaultLocale(sourceLocale);
|
|
2599
|
+
await bucketLoader.init();
|
|
2600
|
+
const sourceData = await bucketLoader.pull(sourceLocale);
|
|
2601
|
+
const cachedSourceData = {};
|
|
2602
|
+
for (const targetLocale in cache) {
|
|
2603
|
+
const targetData = await bucketLoader.pull(targetLocale);
|
|
2604
|
+
for (const key in cache[targetLocale]) {
|
|
2605
|
+
const { source, result } = cache[targetLocale][key];
|
|
2606
|
+
if (sourceData[key] === source && targetData[key] !== result) {
|
|
2607
|
+
targetData[key] = result;
|
|
2608
|
+
cachedSourceData[key] = source;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
await bucketLoader.push(targetLocale, targetData);
|
|
2612
|
+
lockfileHelper.registerPartialSourceData(bucketConfig.pathPattern, cachedSourceData);
|
|
2613
|
+
bucketOra.succeed(
|
|
2614
|
+
`[${sourceLocale} -> ${targetLocale}] Recovered ${Object.keys(cachedSourceData).length} entries from cache`
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
deleteCache();
|
|
2620
|
+
if (flags.verbose) {
|
|
2621
|
+
cacheOra.info("Cache file deleted.");
|
|
2622
|
+
}
|
|
2623
|
+
} else if (flags.verbose) {
|
|
2624
|
+
ora.info("Cache file not found. Skipping recovery.");
|
|
2625
|
+
}
|
|
2493
2626
|
if (flags.frozen) {
|
|
2494
2627
|
ora.start("Checking for lockfile updates...");
|
|
2495
2628
|
let requiresUpdate = false;
|
|
@@ -2559,8 +2692,17 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
2559
2692
|
targetLocale,
|
|
2560
2693
|
targetData
|
|
2561
2694
|
},
|
|
2562
|
-
(progress) => {
|
|
2563
|
-
|
|
2695
|
+
(progress, sourceChunk, processedChunk) => {
|
|
2696
|
+
cacheChunk(targetLocale, sourceChunk, processedChunk);
|
|
2697
|
+
const progressLog = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length} entries] (${progress}%) AI localization in progress...`;
|
|
2698
|
+
if (flags.verbose) {
|
|
2699
|
+
ora.info(progressLog);
|
|
2700
|
+
ora.info(
|
|
2701
|
+
`Caching chunk ${JSON.stringify(sourceChunk, null, 2)} -> ${JSON.stringify(processedChunk, null, 2)}`
|
|
2702
|
+
);
|
|
2703
|
+
} else {
|
|
2704
|
+
ora.text = progressLog;
|
|
2705
|
+
}
|
|
2564
2706
|
}
|
|
2565
2707
|
);
|
|
2566
2708
|
if (flags.verbose) {
|
|
@@ -2612,6 +2754,10 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
|
|
|
2612
2754
|
console.log();
|
|
2613
2755
|
if (!hasErrors) {
|
|
2614
2756
|
ora.succeed("Localization completed.");
|
|
2757
|
+
deleteCache();
|
|
2758
|
+
if (flags.verbose) {
|
|
2759
|
+
ora.info("Cache file deleted.");
|
|
2760
|
+
}
|
|
2615
2761
|
} else {
|
|
2616
2762
|
ora.warn("Localization completed with errors.");
|
|
2617
2763
|
}
|
|
@@ -2675,8 +2821,8 @@ function parseFlags(options) {
|
|
|
2675
2821
|
}
|
|
2676
2822
|
async function validateAuth(settings) {
|
|
2677
2823
|
if (!settings.auth.apiKey) {
|
|
2678
|
-
throw new
|
|
2679
|
-
message: "Not authenticated. Please run `
|
|
2824
|
+
throw new CLIError({
|
|
2825
|
+
message: "Not authenticated. Please run `lingo.dev auth --login` to authenticate.",
|
|
2680
2826
|
docUrl: "authError"
|
|
2681
2827
|
});
|
|
2682
2828
|
}
|
|
@@ -2686,8 +2832,8 @@ async function validateAuth(settings) {
|
|
|
2686
2832
|
});
|
|
2687
2833
|
const user = await authenticator.whoami();
|
|
2688
2834
|
if (!user) {
|
|
2689
|
-
throw new
|
|
2690
|
-
message: "Invalid API key. Please run `
|
|
2835
|
+
throw new CLIError({
|
|
2836
|
+
message: "Invalid API key. Please run `lingo.dev auth --login` to authenticate.",
|
|
2691
2837
|
docUrl: "authError"
|
|
2692
2838
|
});
|
|
2693
2839
|
}
|
|
@@ -2695,22 +2841,22 @@ async function validateAuth(settings) {
|
|
|
2695
2841
|
}
|
|
2696
2842
|
function validateParams(i18nConfig, flags) {
|
|
2697
2843
|
if (!i18nConfig) {
|
|
2698
|
-
throw new
|
|
2699
|
-
message: "i18n.json not found. Please run `
|
|
2844
|
+
throw new CLIError({
|
|
2845
|
+
message: "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
|
|
2700
2846
|
docUrl: "i18nNotFound"
|
|
2701
2847
|
});
|
|
2702
2848
|
} else if (!i18nConfig.buckets || !Object.keys(i18nConfig.buckets).length) {
|
|
2703
|
-
throw new
|
|
2849
|
+
throw new CLIError({
|
|
2704
2850
|
message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
|
|
2705
2851
|
docUrl: "bucketNotFound"
|
|
2706
2852
|
});
|
|
2707
2853
|
} else if (flags.locale?.some((locale) => !i18nConfig.locale.targets.includes(locale))) {
|
|
2708
|
-
throw new
|
|
2854
|
+
throw new CLIError({
|
|
2709
2855
|
message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
|
|
2710
2856
|
docUrl: "localeTargetNotFound"
|
|
2711
2857
|
});
|
|
2712
2858
|
} else if (flags.bucket?.some((bucket) => !i18nConfig.buckets[bucket])) {
|
|
2713
|
-
throw new
|
|
2859
|
+
throw new CLIError({
|
|
2714
2860
|
message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
|
|
2715
2861
|
docUrl: "bucketNotFound"
|
|
2716
2862
|
});
|
|
@@ -2910,13 +3056,13 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
|
|
|
2910
3056
|
});
|
|
2911
3057
|
function validateConfig(i18nConfig) {
|
|
2912
3058
|
if (!i18nConfig) {
|
|
2913
|
-
throw new
|
|
2914
|
-
message: "i18n.json not found. Please run `
|
|
3059
|
+
throw new CLIError({
|
|
3060
|
+
message: "i18n.json not found. Please run `lingo.dev init` to initialize the project.",
|
|
2915
3061
|
docUrl: "i18nNotFound"
|
|
2916
3062
|
});
|
|
2917
3063
|
}
|
|
2918
3064
|
if (!i18nConfig.buckets || !Object.keys(i18nConfig.buckets).length) {
|
|
2919
|
-
throw new
|
|
3065
|
+
throw new CLIError({
|
|
2920
3066
|
message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
|
|
2921
3067
|
docUrl: "bucketNotFound"
|
|
2922
3068
|
});
|
|
@@ -2934,7 +3080,7 @@ function displaySummary(results) {
|
|
|
2934
3080
|
// package.json
|
|
2935
3081
|
var package_default = {
|
|
2936
3082
|
name: "lingo.dev",
|
|
2937
|
-
version: "0.
|
|
3083
|
+
version: "0.71.0",
|
|
2938
3084
|
description: "Lingo.dev CLI",
|
|
2939
3085
|
private: false,
|
|
2940
3086
|
type: "module",
|
|
@@ -2964,7 +3110,7 @@ var package_default = {
|
|
|
2964
3110
|
"build"
|
|
2965
3111
|
],
|
|
2966
3112
|
scripts: {
|
|
2967
|
-
"lingo.dev": "node ./bin/cli.mjs",
|
|
3113
|
+
"lingo.dev": "node --inspect=9229 ./bin/cli.mjs",
|
|
2968
3114
|
dev: "tsup --watch",
|
|
2969
3115
|
build: "tsc --noEmit && tsup",
|
|
2970
3116
|
test: "vitest run",
|
|
@@ -2986,9 +3132,12 @@ var package_default = {
|
|
|
2986
3132
|
dotenv: "^16.4.7",
|
|
2987
3133
|
express: "^4.21.2",
|
|
2988
3134
|
"external-editor": "^3.1.0",
|
|
3135
|
+
figlet: "^1.8.0",
|
|
3136
|
+
"figlet-cli": "^0.2.0",
|
|
2989
3137
|
flat: "^6.0.1",
|
|
2990
3138
|
"gettext-parser": "^8.0.0",
|
|
2991
3139
|
glob: "<11.0.0",
|
|
3140
|
+
"gradient-string": "^3.0.0",
|
|
2992
3141
|
"gray-matter": "^4.0.3",
|
|
2993
3142
|
ini: "^5.0.0",
|
|
2994
3143
|
inquirer: "^12.3.0",
|
|
@@ -3026,6 +3175,7 @@ var package_default = {
|
|
|
3026
3175
|
"@types/cors": "^2.8.17",
|
|
3027
3176
|
"@types/diff": "^6.0.0",
|
|
3028
3177
|
"@types/express": "^5.0.0",
|
|
3178
|
+
"@types/figlet": "^1.7.0",
|
|
3029
3179
|
"@types/gettext-parser": "^4.0.4",
|
|
3030
3180
|
"@types/glob": "^8.1.0",
|
|
3031
3181
|
"@types/ini": "^4.1.1",
|
|
@@ -3049,13 +3199,26 @@ var package_default = {
|
|
|
3049
3199
|
|
|
3050
3200
|
// src/cli/index.ts
|
|
3051
3201
|
dotenv.config();
|
|
3052
|
-
var cli_default = new InteractiveCommand2().name("
|
|
3202
|
+
var cli_default = new InteractiveCommand2().name("lingo.dev").description("Lingo.dev CLI").helpOption("-h, --help", "Show help").addHelpText(
|
|
3053
3203
|
"beforeAll",
|
|
3054
3204
|
`
|
|
3055
|
-
|
|
3205
|
+
${vice(
|
|
3206
|
+
figlet.textSync("LINGO.DEV", {
|
|
3207
|
+
font: "ANSI Shadow",
|
|
3208
|
+
horizontalLayout: "default",
|
|
3209
|
+
verticalLayout: "default"
|
|
3210
|
+
})
|
|
3211
|
+
)}
|
|
3212
|
+
|
|
3056
3213
|
Website: https://lingo.dev
|
|
3057
3214
|
`
|
|
3058
|
-
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default)
|
|
3215
|
+
).version(`v${package_default.version}`, "-v, --version", "Show version").addCommand(init_default).interactive("-y, --no-interactive", "Disable interactive mode").addCommand(i18n_default).addCommand(auth_default).addCommand(show_default).addCommand(lockfile_default).addCommand(cleanup_default).exitOverride((err) => {
|
|
3216
|
+
if (err.code === "commander.helpDisplayed" || err.code === "commander.version" || err.code === "commander.help") {
|
|
3217
|
+
process.exit(0);
|
|
3218
|
+
}
|
|
3219
|
+
throw err;
|
|
3220
|
+
});
|
|
3059
3221
|
export {
|
|
3060
3222
|
cli_default as default
|
|
3061
3223
|
};
|
|
3224
|
+
//# sourceMappingURL=cli.mjs.map
|