lingo.dev 0.70.4 → 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/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ReplexicaEngine
3
- } from "./chunk-FAB4HZX7.mjs";
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-3TBVVQ2O.mjs";
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.REPLEXICA_API_KEY || systemFile.auth?.apiKey || defaults.auth.apiKey,
40
- apiUrl: env.REPLEXICA_API_URL || systemFile.auth?.apiUrl || defaults.auth.apiUrl,
41
- webUrl: env.REPLEXICA_WEB_URL || systemFile.auth?.webUrl || defaults.auth.webUrl
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
  }
@@ -63,9 +66,9 @@ function _loadDefaults() {
63
66
  }
64
67
  function _loadEnv() {
65
68
  return Z.object({
66
- REPLEXICA_API_KEY: Z.string().optional(),
67
- REPLEXICA_API_URL: Z.string().optional(),
68
- REPLEXICA_WEB_URL: Z.string().optional()
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() {
@@ -91,6 +94,21 @@ function _getSettingsFilePath() {
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 = {
@@ -195,7 +213,7 @@ Press Enter to open the browser for authentication.
195
213
 
196
214
  ---
197
215
 
198
- Having issues? Put REPLEXICA_API_KEY in your .env file instead.
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 = (path7) => {
283
+ var openUrl = (path8) => {
266
284
  const settings = getSettings(void 0);
267
- spawn("open", [`${settings.auth.webUrl}${path7}`]);
285
+ spawn("open", [`${settings.auth.webUrl}${path8}`]);
268
286
  };
269
287
  var throwHelpError = (option, value) => {
270
288
  if (value === "help") {
@@ -307,14 +325,14 @@ 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 path7 of values) {
328
+ for (const path8 of values) {
311
329
  try {
312
- const stats = fs3.statSync(path7);
330
+ const stats = fs3.statSync(path8);
313
331
  if (!stats.isDirectory()) {
314
- throw new Error(`${path7} is not a directory`);
332
+ throw new Error(`${path8} is not a directory`);
315
333
  }
316
334
  } catch (err) {
317
- throw new Error(`Invalid directory path: ${path7}`);
335
+ throw new Error(`Invalid directory path: ${path8}`);
318
336
  }
319
337
  }
320
338
  return values;
@@ -540,8 +558,8 @@ 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((path7) => {
544
- console.log(path7);
561
+ result.forEach((path8) => {
562
+ console.log(path8);
545
563
  });
546
564
  }
547
565
  }
@@ -979,9 +997,9 @@ function createHtmlLoader() {
979
997
  const bDepth = b.split("/").length;
980
998
  return aDepth - bDepth;
981
999
  });
982
- paths.forEach((path7) => {
983
- const value = data[path7];
984
- const [nodePath, attribute] = path7.split("#");
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;
@@ -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, path7 = [], acc = {}) {
2000
+ function serializeStructuredTextNode(node, path8 = [], acc = {}) {
1983
2001
  if ("document" in node) {
1984
- return serializeStructuredTextNode(node.document, [...path7, "document"], acc);
2002
+ return serializeStructuredTextNode(node.document, [...path8, "document"], acc);
1985
2003
  }
1986
2004
  if (!_13.isNil(node.value)) {
1987
- acc[[...path7, "value"].join(".")] = node.value;
2005
+ acc[[...path8, "value"].join(".")] = node.value;
1988
2006
  } else if (_13.get(node, "type") === "block") {
1989
- acc[[...path7, "item"].join(".")] = serializeBlock(node.item);
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], [...path7, i.toString()], acc);
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 [path7, value] of _13.entries(parsedStructuredText)) {
2053
- const realPath = _13.chain(path7.split(".")).flatMap((s) => !_13.isNaN(_13.toNumber(s)) ? ["children", s] : s).value();
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
- bucketOra.text = `[${sourceLocale} -> ${targetLocale}] [${Object.keys(processableData).length} entries] (${progress}%) AI localization in progress...`;
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
  }
@@ -2934,7 +3080,7 @@ function displaySummary(results) {
2934
3080
  // package.json
2935
3081
  var package_default = {
2936
3082
  name: "lingo.dev",
2937
- version: "0.70.4",
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",
@@ -3052,10 +3202,23 @@ dotenv.config();
3052
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
- Lingo.dev CLI
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