lingo.dev 0.77.1 → 0.77.3

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
@@ -264,8 +264,8 @@ function _getConfigFilePath() {
264
264
 
265
265
  // src/cli/cmd/init.ts
266
266
  import { defaultConfig, resolveLocaleCode as resolveLocaleCode2, bucketTypes } from "@lingo.dev/_spec";
267
- import fs4 from "fs";
268
- import path5 from "path";
267
+ import fs5 from "fs";
268
+ import path6 from "path";
269
269
  import { spawn } from "child_process";
270
270
  import _3 from "lodash";
271
271
  import { checkbox, confirm, input } from "@inquirer/prompts";
@@ -289,6 +289,8 @@ function findLocaleFiles(bucket) {
289
289
  return findLocaleFilesWithExtension(".md");
290
290
  case "php":
291
291
  return findLocaleFilesWithExtension(".php");
292
+ case "po":
293
+ return findLocaleFilesWithExtension(".po");
292
294
  case "xcode-xcstrings":
293
295
  return findLocaleFilesForFilename("Localizable.xcstrings");
294
296
  case "xcode-strings":
@@ -434,10 +436,47 @@ function getDefaultContent(ext, source) {
434
436
  }
435
437
  }
436
438
 
439
+ // src/cli/utils/update-gitignore.ts
440
+ import fs4 from "fs";
441
+ import path5 from "path";
442
+ function updateGitignore() {
443
+ const cacheFile = "i18n.cache";
444
+ const projectRoot = findCurrentProjectRoot();
445
+ if (!projectRoot) {
446
+ return;
447
+ }
448
+ const gitignorePath = path5.join(projectRoot, ".gitignore");
449
+ const gitignore = fs4.readFileSync(gitignorePath, "utf8").split("\n");
450
+ const cacheIsIgnored = gitignore.includes(cacheFile);
451
+ if (!cacheIsIgnored) {
452
+ let content = "";
453
+ if (fs4.existsSync(gitignorePath)) {
454
+ content = fs4.readFileSync(gitignorePath, "utf8");
455
+ if (content !== "" && !content.endsWith("\n")) {
456
+ content += "\n";
457
+ }
458
+ }
459
+ content += `${cacheFile}
460
+ `;
461
+ fs4.writeFileSync(gitignorePath, content);
462
+ }
463
+ }
464
+ function findCurrentProjectRoot() {
465
+ let currentDir = process.cwd();
466
+ while (currentDir !== path5.parse(currentDir).root) {
467
+ const gitDirPath = path5.join(currentDir, ".git");
468
+ if (fs4.existsSync(gitDirPath) && fs4.lstatSync(gitDirPath).isDirectory()) {
469
+ return currentDir;
470
+ }
471
+ currentDir = path5.dirname(currentDir);
472
+ }
473
+ return null;
474
+ }
475
+
437
476
  // src/cli/cmd/init.ts
438
- var openUrl = (path11) => {
477
+ var openUrl = (path12) => {
439
478
  const settings = getSettings(void 0);
440
- spawn("open", [`${settings.auth.webUrl}${path11}`]);
479
+ spawn("open", [`${settings.auth.webUrl}${path12}`]);
441
480
  };
442
481
  var throwHelpError = (option, value) => {
443
482
  if (value === "help") {
@@ -483,8 +522,8 @@ var init_default = new InteractiveCommand().command("init").description("Initial
483
522
  const values = value.includes(",") ? value.split(",") : value.split(" ");
484
523
  for (const p of values) {
485
524
  try {
486
- const dirPath = path5.dirname(p);
487
- const stats = fs4.statSync(dirPath);
525
+ const dirPath = path6.dirname(p);
526
+ const stats = fs5.statSync(dirPath);
488
527
  if (!stats.isDirectory()) {
489
528
  throw new Error(`${dirPath} is not a directory`);
490
529
  }
@@ -586,6 +625,7 @@ var init_default = new InteractiveCommand().command("init").description("Initial
586
625
  } else {
587
626
  Ora2().succeed(`Authenticated as ${auth.email}`);
588
627
  }
628
+ updateGitignore();
589
629
  if (!isInteractive) {
590
630
  Ora2().info("Please see https://docs.lingo.dev/");
591
631
  }
@@ -597,8 +637,8 @@ import { Command as Command5 } from "interactive-commander";
597
637
  // src/cli/cmd/show/config.ts
598
638
  import { Command as Command2 } from "interactive-commander";
599
639
  import _4 from "lodash";
600
- import fs5 from "fs";
601
- import path6 from "path";
640
+ import fs6 from "fs";
641
+ import path7 from "path";
602
642
  import { defaultConfig as defaultConfig2 } from "@lingo.dev/_spec";
603
643
  var config_default = new Command2().command("config").description("Print out the current configuration").helpOption("-h, --help", "Show help").action(async (options) => {
604
644
  const fileConfig = loadReplexicaFileConfig();
@@ -606,12 +646,12 @@ var config_default = new Command2().command("config").description("Print out the
606
646
  console.log(JSON.stringify(config, null, 2));
607
647
  });
608
648
  function loadReplexicaFileConfig() {
609
- const replexicaConfigPath = path6.resolve(process.cwd(), "i18n.json");
610
- const fileExists = fs5.existsSync(replexicaConfigPath);
649
+ const replexicaConfigPath = path7.resolve(process.cwd(), "i18n.json");
650
+ const fileExists = fs6.existsSync(replexicaConfigPath);
611
651
  if (!fileExists) {
612
652
  return void 0;
613
653
  }
614
- const fileContent = fs5.readFileSync(replexicaConfigPath, "utf-8");
654
+ const fileContent = fs6.readFileSync(replexicaConfigPath, "utf-8");
615
655
  const replexicaFileConfig = JSON.parse(fileContent);
616
656
  return replexicaFileConfig;
617
657
  }
@@ -648,7 +688,7 @@ import Ora4 from "ora";
648
688
 
649
689
  // src/cli/utils/buckets.ts
650
690
  import _5 from "lodash";
651
- import path7 from "path";
691
+ import path8 from "path";
652
692
  import * as glob2 from "glob";
653
693
  import { resolveOverridenLocale } from "@lingo.dev/_spec";
654
694
  function getBuckets(i18nConfig) {
@@ -683,9 +723,9 @@ function extractPathPatterns(sourceLocale, include, exclude) {
683
723
  return result;
684
724
  }
685
725
  function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
686
- const absolutePathPattern = path7.resolve(_pathPattern);
687
- const pathPattern = path7.relative(process.cwd(), absolutePathPattern);
688
- if (path7.relative(process.cwd(), pathPattern).startsWith("..")) {
726
+ const absolutePathPattern = path8.resolve(_pathPattern);
727
+ const pathPattern = path8.relative(process.cwd(), absolutePathPattern);
728
+ if (path8.relative(process.cwd(), pathPattern).startsWith("..")) {
689
729
  throw new CLIError({
690
730
  message: `Invalid path pattern: ${pathPattern}. Path pattern must be within the current working directory.`,
691
731
  docUrl: "invalidPathPattern"
@@ -697,7 +737,7 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
697
737
  docUrl: "invalidPathPattern"
698
738
  });
699
739
  }
700
- const pathPatternChunks = pathPattern.split(path7.sep);
740
+ const pathPatternChunks = pathPattern.split(path8.sep);
701
741
  const localeSegmentIndexes = pathPatternChunks.reduce((indexes, segment, index) => {
702
742
  if (segment.includes("[locale]")) {
703
743
  indexes.push(index);
@@ -705,9 +745,9 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
705
745
  return indexes;
706
746
  }, []);
707
747
  const sourcePathPattern = pathPattern.replaceAll(/\[locale\]/g, sourceLocale);
708
- const sourcePaths = glob2.sync(sourcePathPattern, { follow: true, withFileTypes: true }).filter((file) => file.isFile() || file.isSymbolicLink()).map((file) => file.fullpath()).map((fullpath) => path7.relative(process.cwd(), fullpath));
748
+ const sourcePaths = glob2.sync(sourcePathPattern, { follow: true, withFileTypes: true }).filter((file) => file.isFile() || file.isSymbolicLink()).map((file) => file.fullpath()).map((fullpath) => path8.relative(process.cwd(), fullpath));
709
749
  const placeholderedPaths = sourcePaths.map((sourcePath) => {
710
- const sourcePathChunks = sourcePath.split(path7.sep);
750
+ const sourcePathChunks = sourcePath.split(path8.sep);
711
751
  localeSegmentIndexes.forEach((localeSegmentIndex) => {
712
752
  const localePlaceholderIndex = pathPatternChunks[localeSegmentIndex]?.indexOf("[locale]") ?? -1;
713
753
  if (localeSegmentIndex >= 0 && localePlaceholderIndex >= 0) {
@@ -716,7 +756,7 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
716
756
  sourcePathChunks[localeSegmentIndex] = placeholderedSegment;
717
757
  }
718
758
  });
719
- const placeholderedPath = sourcePathChunks.join(path7.sep);
759
+ const placeholderedPath = sourcePathChunks.join(path8.sep);
720
760
  return placeholderedPath;
721
761
  });
722
762
  return placeholderedPaths;
@@ -758,8 +798,8 @@ var files_default = new Command4().command("files").description("Print out the l
758
798
  } else if (type.target) {
759
799
  result.push(...targetPaths);
760
800
  }
761
- result.forEach((path11) => {
762
- console.log(path11);
801
+ result.forEach((path12) => {
802
+ console.log(path12);
763
803
  });
764
804
  }
765
805
  }
@@ -981,8 +1021,8 @@ function normalizeObjectKeys(obj) {
981
1021
  }
982
1022
 
983
1023
  // src/cli/loaders/text-file.ts
984
- import fs6 from "fs/promises";
985
- import path8 from "path";
1024
+ import fs7 from "fs/promises";
1025
+ import path9 from "path";
986
1026
  function createTextFileLoader(pathPattern) {
987
1027
  return createLoader({
988
1028
  async pull(locale) {
@@ -992,13 +1032,13 @@ function createTextFileLoader(pathPattern) {
992
1032
  },
993
1033
  async push(locale, data, _21, originalLocale) {
994
1034
  const draftPath = pathPattern.replaceAll("[locale]", locale);
995
- const finalPath = path8.resolve(draftPath);
996
- const dirPath = path8.dirname(finalPath);
997
- await fs6.mkdir(dirPath, { recursive: true });
1035
+ const finalPath = path9.resolve(draftPath);
1036
+ const dirPath = path9.dirname(finalPath);
1037
+ await fs7.mkdir(dirPath, { recursive: true });
998
1038
  const trimmedPayload = data.trim();
999
1039
  const trailingNewLine = await getTrailingNewLine(pathPattern, locale, originalLocale);
1000
1040
  let finalPayload = trimmedPayload + trailingNewLine;
1001
- await fs6.writeFile(finalPath, finalPayload, {
1041
+ await fs7.writeFile(finalPath, finalPayload, {
1002
1042
  encoding: "utf-8",
1003
1043
  flag: "w"
1004
1044
  });
@@ -1007,12 +1047,12 @@ function createTextFileLoader(pathPattern) {
1007
1047
  }
1008
1048
  async function readFileForLocale(pathPattern, locale) {
1009
1049
  const draftPath = pathPattern.replaceAll("[locale]", locale);
1010
- const finalPath = path8.resolve(draftPath);
1011
- const exists = await fs6.access(finalPath).then(() => true).catch(() => false);
1050
+ const finalPath = path9.resolve(draftPath);
1051
+ const exists = await fs7.access(finalPath).then(() => true).catch(() => false);
1012
1052
  if (!exists) {
1013
1053
  return "";
1014
1054
  }
1015
- return fs6.readFile(finalPath, "utf-8");
1055
+ return fs7.readFile(finalPath, "utf-8");
1016
1056
  }
1017
1057
  async function getTrailingNewLine(pathPattern, locale, originalLocale) {
1018
1058
  let templateData = await readFileForLocale(pathPattern, locale);
@@ -1299,9 +1339,9 @@ function createHtmlLoader() {
1299
1339
  const bDepth = b.split("/").length;
1300
1340
  return aDepth - bDepth;
1301
1341
  });
1302
- paths.forEach((path11) => {
1303
- const value = data[path11];
1304
- const [nodePath, attribute] = path11.split("#");
1342
+ paths.forEach((path12) => {
1343
+ const value = data[path12];
1344
+ const [nodePath, attribute] = path12.split("#");
1305
1345
  const [rootTag, ...indices] = nodePath.split("/");
1306
1346
  let parent = rootTag === "head" ? document.head : document.body;
1307
1347
  let current = parent;
@@ -1805,7 +1845,7 @@ function createSrtLoader() {
1805
1845
  }
1806
1846
 
1807
1847
  // src/cli/loaders/dato/index.ts
1808
- import fs7 from "fs";
1848
+ import fs8 from "fs";
1809
1849
  import JSON5 from "json5";
1810
1850
 
1811
1851
  // src/cli/loaders/dato/_base.ts
@@ -2308,18 +2348,18 @@ function createRawDatoValue(parsedDatoValue, originalRawDatoValue, isClean = fal
2308
2348
  }
2309
2349
  function serializeStructuredText(rawStructuredText) {
2310
2350
  return serializeStructuredTextNode(rawStructuredText);
2311
- function serializeStructuredTextNode(node, path11 = [], acc = {}) {
2351
+ function serializeStructuredTextNode(node, path12 = [], acc = {}) {
2312
2352
  if ("document" in node) {
2313
- return serializeStructuredTextNode(node.document, [...path11, "document"], acc);
2353
+ return serializeStructuredTextNode(node.document, [...path12, "document"], acc);
2314
2354
  }
2315
2355
  if (!_15.isNil(node.value)) {
2316
- acc[[...path11, "value"].join(".")] = node.value;
2356
+ acc[[...path12, "value"].join(".")] = node.value;
2317
2357
  } else if (_15.get(node, "type") === "block") {
2318
- acc[[...path11, "item"].join(".")] = serializeBlock(node.item);
2358
+ acc[[...path12, "item"].join(".")] = serializeBlock(node.item);
2319
2359
  }
2320
2360
  if (node.children) {
2321
2361
  for (let i = 0; i < node.children.length; i++) {
2322
- serializeStructuredTextNode(node.children[i], [...path11, i.toString()], acc);
2362
+ serializeStructuredTextNode(node.children[i], [...path12, i.toString()], acc);
2323
2363
  }
2324
2364
  }
2325
2365
  return acc;
@@ -2378,8 +2418,8 @@ function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = f
2378
2418
  }
2379
2419
  function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
2380
2420
  const result = _15.cloneDeep(originalRawStructuredText);
2381
- for (const [path11, value] of _15.entries(parsedStructuredText)) {
2382
- const realPath = _15.chain(path11.split(".")).flatMap((s) => !_15.isNaN(_15.toNumber(s)) ? ["children", s] : s).value();
2421
+ for (const [path12, value] of _15.entries(parsedStructuredText)) {
2422
+ const realPath = _15.chain(path12.split(".")).flatMap((s) => !_15.isNaN(_15.toNumber(s)) ? ["children", s] : s).value();
2383
2423
  const deserializedValue = createRawDatoValue(value, _15.get(originalRawStructuredText, realPath), true);
2384
2424
  _15.set(result, realPath, deserializedValue);
2385
2425
  }
@@ -2404,12 +2444,12 @@ function _isVideo(rawDatoValue) {
2404
2444
  // src/cli/loaders/dato/index.ts
2405
2445
  function createDatoLoader(configFilePath) {
2406
2446
  try {
2407
- const configContent = fs7.readFileSync(configFilePath, "utf-8");
2447
+ const configContent = fs8.readFileSync(configFilePath, "utf-8");
2408
2448
  const datoConfig = datoConfigSchema.parse(JSON5.parse(configContent));
2409
2449
  return composeLoaders(
2410
2450
  createDatoApiLoader(
2411
2451
  datoConfig,
2412
- (updatedConfig) => fs7.writeFileSync(configFilePath, JSON5.stringify(updatedConfig, null, 2))
2452
+ (updatedConfig) => fs8.writeFileSync(configFilePath, JSON5.stringify(updatedConfig, null, 2))
2413
2453
  ),
2414
2454
  createDatoFilterLoader(),
2415
2455
  createDatoExtractLoader()
@@ -2831,8 +2871,8 @@ function createBucketLoader(bucketType, bucketPathPattern, { isCacheRestore = fa
2831
2871
  }
2832
2872
 
2833
2873
  // src/cli/utils/lockfile.ts
2834
- import fs8 from "fs";
2835
- import path9 from "path";
2874
+ import fs9 from "fs";
2875
+ import path10 from "path";
2836
2876
  import Z3 from "zod";
2837
2877
  import YAML3 from "yaml";
2838
2878
  import { MD5 } from "object-hash";
@@ -2841,7 +2881,7 @@ function createLockfileHelper() {
2841
2881
  return {
2842
2882
  isLockfileExists: () => {
2843
2883
  const lockfilePath = _getLockfilePath();
2844
- return fs8.existsSync(lockfilePath);
2884
+ return fs9.existsSync(lockfilePath);
2845
2885
  },
2846
2886
  registerSourceData: (pathPattern, sourceData) => {
2847
2887
  const lockfile = _loadLockfile();
@@ -2868,20 +2908,20 @@ function createLockfileHelper() {
2868
2908
  };
2869
2909
  function _loadLockfile() {
2870
2910
  const lockfilePath = _getLockfilePath();
2871
- if (!fs8.existsSync(lockfilePath)) {
2911
+ if (!fs9.existsSync(lockfilePath)) {
2872
2912
  return LockfileSchema.parse({});
2873
2913
  }
2874
- const content = fs8.readFileSync(lockfilePath, "utf-8");
2914
+ const content = fs9.readFileSync(lockfilePath, "utf-8");
2875
2915
  const result = LockfileSchema.parse(YAML3.parse(content));
2876
2916
  return result;
2877
2917
  }
2878
2918
  function _saveLockfile(lockfile) {
2879
2919
  const lockfilePath = _getLockfilePath();
2880
2920
  const content = YAML3.stringify(lockfile);
2881
- fs8.writeFileSync(lockfilePath, content);
2921
+ fs9.writeFileSync(lockfilePath, content);
2882
2922
  }
2883
2923
  function _getLockfilePath() {
2884
- return path9.join(process.cwd(), "i18n.lock");
2924
+ return path10.join(process.cwd(), "i18n.lock");
2885
2925
  }
2886
2926
  }
2887
2927
  var LockfileSchema = Z3.object({
@@ -2906,8 +2946,8 @@ import inquirer2 from "inquirer";
2906
2946
  import externalEditor from "external-editor";
2907
2947
 
2908
2948
  // src/cli/utils/cache.ts
2909
- import path10 from "path";
2910
- import fs9 from "fs";
2949
+ import path11 from "path";
2950
+ import fs10 from "fs";
2911
2951
  var cacheChunk = (targetLocale, sourceChunk, processedChunk) => {
2912
2952
  const rows = Object.entries(sourceChunk).map(([key, source]) => ({
2913
2953
  targetLocale,
@@ -2937,26 +2977,26 @@ function getNormalizedCache() {
2937
2977
  function deleteCache() {
2938
2978
  const cacheFilePath = _getCacheFilePath();
2939
2979
  try {
2940
- fs9.unlinkSync(cacheFilePath);
2980
+ fs10.unlinkSync(cacheFilePath);
2941
2981
  } catch (e) {
2942
2982
  }
2943
2983
  }
2944
2984
  function _loadCache() {
2945
2985
  const cacheFilePath = _getCacheFilePath();
2946
- if (!fs9.existsSync(cacheFilePath)) {
2986
+ if (!fs10.existsSync(cacheFilePath)) {
2947
2987
  return [];
2948
2988
  }
2949
- const content = fs9.readFileSync(cacheFilePath, "utf-8");
2989
+ const content = fs10.readFileSync(cacheFilePath, "utf-8");
2950
2990
  const result = _parseJSONLines(content);
2951
2991
  return result;
2952
2992
  }
2953
2993
  function _appendToCache(rows) {
2954
2994
  const cacheFilePath = _getCacheFilePath();
2955
2995
  const lines = _buildJSONLines(rows);
2956
- fs9.appendFileSync(cacheFilePath, lines);
2996
+ fs10.appendFileSync(cacheFilePath, lines);
2957
2997
  }
2958
2998
  function _getCacheFilePath() {
2959
- return path10.join(process.cwd(), "i18n.cache");
2999
+ return path11.join(process.cwd(), "i18n.cache");
2960
3000
  }
2961
3001
  function _buildJSONLines(rows) {
2962
3002
  return rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
@@ -2974,6 +3014,7 @@ function _tryParseJSON(line) {
2974
3014
 
2975
3015
  // src/cli/cmd/i18n.ts
2976
3016
  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) {
3017
+ updateGitignore();
2977
3018
  const ora = Ora5();
2978
3019
  const flags = parseFlags(options);
2979
3020
  if (flags.debug) {
@@ -3577,7 +3618,7 @@ var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model
3577
3618
  // package.json
3578
3619
  var package_default = {
3579
3620
  name: "lingo.dev",
3580
- version: "0.77.1",
3621
+ version: "0.77.3",
3581
3622
  description: "Lingo.dev CLI",
3582
3623
  private: false,
3583
3624
  publishConfig: {