lingo.dev 0.80.1 → 0.82.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
@@ -621,9 +621,9 @@ function makeGitlabInitializer(spinner) {
621
621
 
622
622
  // src/cli/cmd/init.ts
623
623
  import open2 from "open";
624
- var openUrl = (path15) => {
624
+ var openUrl = (path18) => {
625
625
  const settings = getSettings(void 0);
626
- open2(`${settings.auth.webUrl}${path15}`, { wait: false });
626
+ open2(`${settings.auth.webUrl}${path18}`, { wait: false });
627
627
  };
628
628
  var throwHelpError = (option, value) => {
629
629
  if (value === "help") {
@@ -862,6 +862,9 @@ function getBuckets(i18nConfig) {
862
862
  if (bucketEntry.injectLocale) {
863
863
  config.injectLocale = bucketEntry.injectLocale;
864
864
  }
865
+ if (bucketEntry.lockedKeys) {
866
+ config.lockedKeys = bucketEntry.lockedKeys;
867
+ }
865
868
  return config;
866
869
  });
867
870
  return result;
@@ -967,8 +970,8 @@ var files_default = new Command4().command("files").description("Print out the l
967
970
  } else if (type.target) {
968
971
  result.push(...targetPaths);
969
972
  }
970
- result.forEach((path15) => {
971
- console.log(path15);
973
+ result.forEach((path18) => {
974
+ console.log(path18);
972
975
  });
973
976
  }
974
977
  }
@@ -990,8 +993,9 @@ var show_default = new Command5().command("show").description("Prints out the cu
990
993
  // src/cli/cmd/i18n.ts
991
994
  import { bucketTypeSchema, localeCodeSchema, resolveOverriddenLocale as resolveOverriddenLocale3 } from "@lingo.dev/_spec";
992
995
  import { Command as Command6 } from "interactive-commander";
993
- import Z4 from "zod";
994
- import _20 from "lodash";
996
+ import Z3 from "zod";
997
+ import _21 from "lodash";
998
+ import * as path15 from "path";
995
999
  import Ora5 from "ora";
996
1000
 
997
1001
  // src/cli/loaders/_utils.ts
@@ -1198,7 +1202,7 @@ function createTextFileLoader(pathPattern) {
1198
1202
  const trimmedResult = result.trim();
1199
1203
  return trimmedResult;
1200
1204
  },
1201
- async push(locale, data, _22, originalLocale) {
1205
+ async push(locale, data, _24, originalLocale) {
1202
1206
  const draftPath = pathPattern.replaceAll("[locale]", locale);
1203
1207
  const finalPath = path10.resolve(draftPath);
1204
1208
  const dirPath = path10.dirname(finalPath);
@@ -1535,9 +1539,9 @@ function createHtmlLoader() {
1535
1539
  const bDepth = b.split("/").length;
1536
1540
  return aDepth - bDepth;
1537
1541
  });
1538
- paths.forEach((path15) => {
1539
- const value = data[path15];
1540
- const [nodePath, attribute] = path15.split("#");
1542
+ paths.forEach((path18) => {
1543
+ const value = data[path18];
1544
+ const [nodePath, attribute] = path18.split("#");
1541
1545
  const [rootTag, ...indices] = nodePath.split("/");
1542
1546
  let parent = rootTag === "head" ? document.head : document.body;
1543
1547
  let current = parent;
@@ -1640,7 +1644,7 @@ function createPropertiesLoader() {
1640
1644
  return result;
1641
1645
  },
1642
1646
  async push(locale, payload) {
1643
- const result = Object.entries(payload).filter(([_22, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1647
+ const result = Object.entries(payload).filter(([_24, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
1644
1648
  return result;
1645
1649
  }
1646
1650
  });
@@ -1889,10 +1893,10 @@ function createUnlocalizableLoader(isCacheRestore = false, returnUnlocalizedKeys
1889
1893
  }
1890
1894
  }
1891
1895
  return false;
1892
- }).map(([key, _22]) => key);
1893
- const result = _10.omitBy(input2, (_22, key) => passthroughKeys.includes(key));
1896
+ }).map(([key, _24]) => key);
1897
+ const result = _10.omitBy(input2, (_24, key) => passthroughKeys.includes(key));
1894
1898
  if (returnUnlocalizedKeys) {
1895
- result.unlocalizable = _10.omitBy(input2, (_22, key) => !passthroughKeys.includes(key));
1899
+ result.unlocalizable = _10.omitBy(input2, (_24, key) => !passthroughKeys.includes(key));
1896
1900
  }
1897
1901
  return result;
1898
1902
  },
@@ -2583,18 +2587,18 @@ function createRawDatoValue(parsedDatoValue, originalRawDatoValue, isClean = fal
2583
2587
  }
2584
2588
  function serializeStructuredText(rawStructuredText) {
2585
2589
  return serializeStructuredTextNode(rawStructuredText);
2586
- function serializeStructuredTextNode(node, path15 = [], acc = {}) {
2590
+ function serializeStructuredTextNode(node, path18 = [], acc = {}) {
2587
2591
  if ("document" in node) {
2588
- return serializeStructuredTextNode(node.document, [...path15, "document"], acc);
2592
+ return serializeStructuredTextNode(node.document, [...path18, "document"], acc);
2589
2593
  }
2590
2594
  if (!_15.isNil(node.value)) {
2591
- acc[[...path15, "value"].join(".")] = node.value;
2595
+ acc[[...path18, "value"].join(".")] = node.value;
2592
2596
  } else if (_15.get(node, "type") === "block") {
2593
- acc[[...path15, "item"].join(".")] = serializeBlock(node.item);
2597
+ acc[[...path18, "item"].join(".")] = serializeBlock(node.item);
2594
2598
  }
2595
2599
  if (node.children) {
2596
2600
  for (let i = 0; i < node.children.length; i++) {
2597
- serializeStructuredTextNode(node.children[i], [...path15, i.toString()], acc);
2601
+ serializeStructuredTextNode(node.children[i], [...path18, i.toString()], acc);
2598
2602
  }
2599
2603
  }
2600
2604
  return acc;
@@ -2653,8 +2657,8 @@ function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = f
2653
2657
  }
2654
2658
  function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
2655
2659
  const result = _15.cloneDeep(originalRawStructuredText);
2656
- for (const [path15, value] of _15.entries(parsedStructuredText)) {
2657
- const realPath = _15.chain(path15.split(".")).flatMap((s) => !_15.isNaN(_15.toNumber(s)) ? ["children", s] : s).value();
2660
+ for (const [path18, value] of _15.entries(parsedStructuredText)) {
2661
+ const realPath = _15.chain(path18.split(".")).flatMap((s) => !_15.isNaN(_15.toNumber(s)) ? ["children", s] : s).value();
2658
2662
  const deserializedValue = createRawDatoValue(value, _15.get(originalRawStructuredText, realPath), true);
2659
2663
  _15.set(result, realPath, deserializedValue);
2660
2664
  }
@@ -3005,8 +3009,24 @@ function createInjectLocaleLoader(injectLocaleKeys) {
3005
3009
  });
3006
3010
  }
3007
3011
 
3012
+ // src/cli/loaders/locked-keys.ts
3013
+ import _19 from "lodash";
3014
+ function createLockedKeysLoader(lockedKeys, isCacheRestore = false) {
3015
+ return createLoader({
3016
+ pull: async (locale, data) => _19.chain(data).pickBy((value, key) => !lockedKeys.includes(key)).value(),
3017
+ push: async (locale, data, originalInput) => {
3018
+ const lockedSubObject = _19.chain(originalInput).pickBy((value, key) => lockedKeys.includes(key)).value();
3019
+ if (isCacheRestore) {
3020
+ return _19.merge({}, data, lockedSubObject);
3021
+ } else {
3022
+ return _19.merge({}, originalInput, data, lockedSubObject);
3023
+ }
3024
+ }
3025
+ });
3026
+ }
3027
+
3008
3028
  // src/cli/loaders/index.ts
3009
- function createBucketLoader(bucketType, bucketPathPattern, options) {
3029
+ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys) {
3010
3030
  switch (bucketType) {
3011
3031
  default:
3012
3032
  throw new Error(`Unsupported bucket type: ${bucketType}`);
@@ -3041,6 +3061,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options) {
3041
3061
  createJsonLoader(),
3042
3062
  createInjectLocaleLoader(options.injectLocale),
3043
3063
  createFlatLoader(),
3064
+ createLockedKeysLoader(lockedKeys || [], options.isCacheRestore),
3044
3065
  createSyncLoader(),
3045
3066
  createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
3046
3067
  );
@@ -3100,6 +3121,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options) {
3100
3121
  createPrettierLoader({ parser: "yaml", bucketPathPattern }),
3101
3122
  createYamlLoader(),
3102
3123
  createFlatLoader(),
3124
+ createLockedKeysLoader(lockedKeys || [], options.isCacheRestore),
3103
3125
  createSyncLoader(),
3104
3126
  createUnlocalizableLoader(options.isCacheRestore, options.returnUnlocalizedKeys)
3105
3127
  );
@@ -3179,75 +3201,6 @@ function createBucketLoader(bucketType, bucketPathPattern, options) {
3179
3201
  }
3180
3202
  }
3181
3203
 
3182
- // src/cli/utils/lockfile.ts
3183
- import fs10 from "fs";
3184
- import path12 from "path";
3185
- import Z3 from "zod";
3186
- import YAML3 from "yaml";
3187
- import { MD5 } from "object-hash";
3188
- import _19 from "lodash";
3189
- function createLockfileHelper() {
3190
- return {
3191
- isLockfileExists: () => {
3192
- const lockfilePath = _getLockfilePath();
3193
- return fs10.existsSync(lockfilePath);
3194
- },
3195
- registerSourceData: (pathPattern, sourceData) => {
3196
- const lockfile = _loadLockfile();
3197
- const sectionKey = MD5(pathPattern);
3198
- const sectionChecksums = _19.mapValues(sourceData, (value) => MD5(value));
3199
- lockfile.checksums[sectionKey] = sectionChecksums;
3200
- _saveLockfile(lockfile);
3201
- },
3202
- registerPartialSourceData: (pathPattern, partialSourceData) => {
3203
- const lockfile = _loadLockfile();
3204
- const sectionKey = MD5(pathPattern);
3205
- const sectionChecksums = _19.mapValues(partialSourceData, (value) => MD5(value));
3206
- lockfile.checksums[sectionKey] = _19.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
3207
- _saveLockfile(lockfile);
3208
- },
3209
- extractUpdatedData: (pathPattern, sourceData) => {
3210
- const lockfile = _loadLockfile();
3211
- const sectionKey = MD5(pathPattern);
3212
- const currentChecksums = _19.mapValues(sourceData, (value) => MD5(value));
3213
- const savedChecksums = lockfile.checksums[sectionKey] || {};
3214
- const updatedData = _19.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
3215
- return updatedData;
3216
- }
3217
- };
3218
- function _loadLockfile() {
3219
- const lockfilePath = _getLockfilePath();
3220
- if (!fs10.existsSync(lockfilePath)) {
3221
- return LockfileSchema.parse({});
3222
- }
3223
- const content = fs10.readFileSync(lockfilePath, "utf-8");
3224
- const result = LockfileSchema.parse(YAML3.parse(content));
3225
- return result;
3226
- }
3227
- function _saveLockfile(lockfile) {
3228
- const lockfilePath = _getLockfilePath();
3229
- const content = YAML3.stringify(lockfile);
3230
- fs10.writeFileSync(lockfilePath, content);
3231
- }
3232
- function _getLockfilePath() {
3233
- return path12.join(process.cwd(), "i18n.lock");
3234
- }
3235
- }
3236
- var LockfileSchema = Z3.object({
3237
- version: Z3.literal(1).default(1),
3238
- checksums: Z3.record(
3239
- Z3.string(),
3240
- // localizable files' keys
3241
- Z3.record(
3242
- // checksums hashmap
3243
- Z3.string(),
3244
- // key
3245
- Z3.string()
3246
- // checksum of the key's value in the source locale
3247
- ).default({})
3248
- ).default({})
3249
- });
3250
-
3251
3204
  // src/cli/cmd/i18n.ts
3252
3205
  import chalk from "chalk";
3253
3206
  import { createTwoFilesPatch } from "diff";
@@ -3255,8 +3208,8 @@ import inquirer2 from "inquirer";
3255
3208
  import externalEditor from "external-editor";
3256
3209
 
3257
3210
  // src/cli/utils/cache.ts
3258
- import path13 from "path";
3259
- import fs11 from "fs";
3211
+ import path12 from "path";
3212
+ import fs10 from "fs";
3260
3213
  var cacheChunk = (targetLocale, sourceChunk, processedChunk) => {
3261
3214
  const rows = Object.entries(sourceChunk).map(([key, source]) => ({
3262
3215
  targetLocale,
@@ -3286,26 +3239,26 @@ function getNormalizedCache() {
3286
3239
  function deleteCache() {
3287
3240
  const cacheFilePath = _getCacheFilePath();
3288
3241
  try {
3289
- fs11.unlinkSync(cacheFilePath);
3242
+ fs10.unlinkSync(cacheFilePath);
3290
3243
  } catch (e) {
3291
3244
  }
3292
3245
  }
3293
3246
  function _loadCache() {
3294
3247
  const cacheFilePath = _getCacheFilePath();
3295
- if (!fs11.existsSync(cacheFilePath)) {
3248
+ if (!fs10.existsSync(cacheFilePath)) {
3296
3249
  return [];
3297
3250
  }
3298
- const content = fs11.readFileSync(cacheFilePath, "utf-8");
3251
+ const content = fs10.readFileSync(cacheFilePath, "utf-8");
3299
3252
  const result = _parseJSONLines(content);
3300
3253
  return result;
3301
3254
  }
3302
3255
  function _appendToCache(rows) {
3303
3256
  const cacheFilePath = _getCacheFilePath();
3304
3257
  const lines = _buildJSONLines(rows);
3305
- fs11.appendFileSync(cacheFilePath, lines);
3258
+ fs10.appendFileSync(cacheFilePath, lines);
3306
3259
  }
3307
3260
  function _getCacheFilePath() {
3308
- return path13.join(process.cwd(), "i18n.cache");
3261
+ return path12.join(process.cwd(), "i18n.cache");
3309
3262
  }
3310
3263
  function _buildJSONLines(rows) {
3311
3264
  return rows.map((row) => JSON.stringify(row)).join("\n") + "\n";
@@ -3325,6 +3278,9 @@ function _tryParseJSON(line) {
3325
3278
  import { LingoDotDevEngine } from "@lingo.dev/_sdk";
3326
3279
  function createLingoLocalizer(params) {
3327
3280
  return async (input2, onProgress) => {
3281
+ if (!Object.keys(input2.processableData).length) {
3282
+ return input2.processableData;
3283
+ }
3328
3284
  const lingo = new LingoDotDevEngine({
3329
3285
  apiKey: params.apiKey,
3330
3286
  apiUrl: params.apiUrl
@@ -3345,10 +3301,13 @@ function createLingoLocalizer(params) {
3345
3301
  };
3346
3302
  }
3347
3303
 
3348
- // src/cli/processor/openai.ts
3304
+ // src/cli/processor/basic.ts
3349
3305
  import { generateText } from "ai";
3350
3306
  function createBasicTranslator(model, systemPrompt) {
3351
3307
  return async (input2, onProgress) => {
3308
+ if (!Object.keys(input2.processableData).length) {
3309
+ return input2.processableData;
3310
+ }
3352
3311
  if (!process.env.OPENAI_API_KEY) {
3353
3312
  throw new Error("OPENAI_API_KEY is not set");
3354
3313
  }
@@ -3393,7 +3352,7 @@ function createBasicTranslator(model, systemPrompt) {
3393
3352
  ]
3394
3353
  });
3395
3354
  const result = JSON.parse(response.text);
3396
- return result;
3355
+ return result?.data || {};
3397
3356
  };
3398
3357
  }
3399
3358
 
@@ -3454,20 +3413,141 @@ async function trackEvent(distinctId, event, properties) {
3454
3413
  if (process.env.DO_NOT_TRACK) {
3455
3414
  return;
3456
3415
  }
3457
- const posthog = new PostHog("phc_eR0iSoQufBxNY36k0f0T15UvHJdTfHlh8rJcxsfhfXk", {
3458
- host: "https://eu.i.posthog.com",
3459
- flushAt: 1,
3460
- flushInterval: 0
3461
- });
3462
- await posthog.capture({
3463
- distinctId,
3464
- event,
3465
- properties
3466
- });
3467
- await posthog.shutdown();
3416
+ try {
3417
+ const posthog = new PostHog("phc_eR0iSoQufBxNY36k0f0T15UvHJdTfHlh8rJcxsfhfXk", {
3418
+ host: "https://eu.i.posthog.com",
3419
+ flushAt: 1,
3420
+ flushInterval: 0
3421
+ });
3422
+ await posthog.capture({
3423
+ distinctId,
3424
+ event,
3425
+ properties: {
3426
+ ...properties,
3427
+ meta: {
3428
+ version: process.env.npm_package_version,
3429
+ isCi: process.env.CI === "true"
3430
+ }
3431
+ }
3432
+ });
3433
+ await posthog.shutdown();
3434
+ } catch (error) {
3435
+ if (process.env.DEBUG) {
3436
+ console.error(error);
3437
+ }
3438
+ }
3439
+ }
3440
+
3441
+ // src/cli/utils/delta.ts
3442
+ import _20 from "lodash";
3443
+ import z from "zod";
3444
+ import { MD5 } from "object-hash";
3445
+
3446
+ // src/cli/utils/fs.ts
3447
+ import * as fs11 from "fs";
3448
+ import * as path13 from "path";
3449
+ function tryReadFile(filePath, defaultValue = null) {
3450
+ try {
3451
+ const content = fs11.readFileSync(filePath, "utf-8");
3452
+ return content;
3453
+ } catch (error) {
3454
+ return defaultValue;
3455
+ }
3456
+ }
3457
+ function writeFile(filePath, content) {
3458
+ const dir = path13.dirname(filePath);
3459
+ if (!fs11.existsSync(dir)) {
3460
+ fs11.mkdirSync(dir, { recursive: true });
3461
+ }
3462
+ fs11.writeFileSync(filePath, content);
3463
+ }
3464
+ function checkIfFileExists(filePath) {
3465
+ return fs11.existsSync(filePath);
3466
+ }
3467
+
3468
+ // src/cli/utils/delta.ts
3469
+ import * as path14 from "path";
3470
+ import YAML3 from "yaml";
3471
+ var LockSchema = z.object({
3472
+ version: z.literal(1).default(1),
3473
+ checksums: z.record(
3474
+ z.string(),
3475
+ // localizable files' keys
3476
+ // checksums hashmap
3477
+ z.record(
3478
+ // key
3479
+ z.string(),
3480
+ // checksum of the key's value in the source locale
3481
+ z.string()
3482
+ ).default({})
3483
+ ).default({})
3484
+ });
3485
+ function createDeltaProcessor(fileKey) {
3486
+ const lockfilePath = path14.join(process.cwd(), "i18n.lock");
3487
+ return {
3488
+ async checkIfLockExists() {
3489
+ return checkIfFileExists(lockfilePath);
3490
+ },
3491
+ async calculateDelta(params) {
3492
+ let added = _20.difference(Object.keys(params.sourceData), Object.keys(params.targetData));
3493
+ let removed = _20.difference(Object.keys(params.targetData), Object.keys(params.sourceData));
3494
+ const updated = _20.filter(Object.keys(params.sourceData), (key) => {
3495
+ return MD5(params.sourceData[key]) !== params.checksums[key] && params.checksums[key];
3496
+ });
3497
+ const renamed = [];
3498
+ for (const addedKey of added) {
3499
+ const addedHash = MD5(params.sourceData[addedKey]);
3500
+ for (const removedKey of removed) {
3501
+ if (params.checksums[removedKey] === addedHash) {
3502
+ renamed.push([removedKey, addedKey]);
3503
+ break;
3504
+ }
3505
+ }
3506
+ }
3507
+ added = added.filter((key) => !renamed.some(([oldKey, newKey]) => newKey === key));
3508
+ removed = removed.filter((key) => !renamed.some(([oldKey, newKey]) => oldKey === key));
3509
+ const hasChanges = [added.length > 0, removed.length > 0, updated.length > 0, renamed.length > 0].some((v) => v);
3510
+ return {
3511
+ added,
3512
+ removed,
3513
+ updated,
3514
+ renamed,
3515
+ hasChanges
3516
+ };
3517
+ },
3518
+ async loadLock() {
3519
+ const lockfileContent = tryReadFile(lockfilePath, null);
3520
+ const lockfileYaml = lockfileContent ? YAML3.parse(lockfileContent) : null;
3521
+ const lockfileData = lockfileYaml ? LockSchema.parse(lockfileYaml) : {
3522
+ version: 1,
3523
+ checksums: {}
3524
+ };
3525
+ return lockfileData;
3526
+ },
3527
+ async saveLock(lockData) {
3528
+ const lockfileYaml = YAML3.stringify(lockData);
3529
+ writeFile(lockfilePath, lockfileYaml);
3530
+ },
3531
+ async loadChecksums() {
3532
+ const id = MD5(fileKey);
3533
+ const lockfileData = await this.loadLock();
3534
+ return lockfileData.checksums[id] || {};
3535
+ },
3536
+ async saveChecksums(checksums) {
3537
+ const id = MD5(fileKey);
3538
+ const lockfileData = await this.loadLock();
3539
+ lockfileData.checksums[id] = checksums;
3540
+ await this.saveLock(lockfileData);
3541
+ },
3542
+ async createChecksums(sourceData) {
3543
+ const checksums = _20.mapValues(sourceData, (value) => MD5(value));
3544
+ return checksums;
3545
+ }
3546
+ };
3468
3547
  }
3469
3548
 
3470
3549
  // src/cli/cmd/i18n.ts
3550
+ import { flatten as flatten2, unflatten as unflatten2 } from "flat";
3471
3551
  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(
3472
3552
  "--key <key>",
3473
3553
  "Key to process. Process only a specific translation key, useful for debugging or updating a single entry"
@@ -3515,7 +3595,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3515
3595
  ora.succeed("Buckets retrieved");
3516
3596
  if (flags.file?.length) {
3517
3597
  buckets = buckets.map((bucket) => {
3518
- const paths = bucket.paths.filter((path15) => flags.file.find((file) => path15.pathPattern?.match(file)));
3598
+ const paths = bucket.paths.filter((path18) => flags.file.find((file) => path18.pathPattern?.match(file)));
3519
3599
  return { ...bucket, paths };
3520
3600
  }).filter((bucket) => bucket.paths.length > 0);
3521
3601
  if (buckets.length === 0) {
@@ -3525,34 +3605,94 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3525
3605
  ora.info(`\x1B[36mProcessing only filtered buckets:\x1B[0m`);
3526
3606
  buckets.map((bucket) => {
3527
3607
  ora.info(` ${bucket.type}:`);
3528
- bucket.paths.forEach((path15) => {
3529
- ora.info(` - ${path15.pathPattern}`);
3608
+ bucket.paths.forEach((path18) => {
3609
+ ora.info(` - ${path18.pathPattern}`);
3530
3610
  });
3531
3611
  });
3532
3612
  }
3533
3613
  }
3534
3614
  const targetLocales = flags.locale?.length ? flags.locale : i18nConfig.locale.targets;
3535
- const lockfileHelper = createLockfileHelper();
3536
- ora.start("Ensuring i18n.lock exists...");
3537
- if (!lockfileHelper.isLockfileExists()) {
3615
+ ora.start("Setting up localization cache...");
3616
+ const checkLockfileProcessor = createDeltaProcessor("");
3617
+ const lockfileExists = await checkLockfileProcessor.checkIfLockExists();
3618
+ if (!lockfileExists) {
3538
3619
  ora.start("Creating i18n.lock...");
3539
3620
  for (const bucket of buckets) {
3540
3621
  for (const bucketPath of bucket.paths) {
3541
3622
  const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3542
- const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3543
- isCacheRestore: false,
3544
- defaultLocale: sourceLocale,
3545
- injectLocale: bucket.injectLocale
3546
- });
3623
+ const bucketLoader = createBucketLoader(
3624
+ bucket.type,
3625
+ bucketPath.pathPattern,
3626
+ {
3627
+ isCacheRestore: false,
3628
+ defaultLocale: sourceLocale,
3629
+ injectLocale: bucket.injectLocale
3630
+ },
3631
+ bucket.lockedKeys
3632
+ );
3547
3633
  bucketLoader.setDefaultLocale(sourceLocale);
3548
3634
  await bucketLoader.init();
3549
3635
  const sourceData = await bucketLoader.pull(i18nConfig.locale.source);
3550
- lockfileHelper.registerSourceData(bucketPath.pathPattern, sourceData);
3636
+ const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
3637
+ const checksums = await deltaProcessor.createChecksums(sourceData);
3638
+ await deltaProcessor.saveChecksums(checksums);
3551
3639
  }
3552
3640
  }
3553
- ora.succeed("i18n.lock created");
3641
+ ora.succeed("Localization cache initialized");
3554
3642
  } else {
3555
- ora.succeed("i18n.lock loaded");
3643
+ ora.succeed("Localization cache loaded");
3644
+ }
3645
+ for (const bucket of buckets) {
3646
+ if (bucket.type !== "json") {
3647
+ continue;
3648
+ }
3649
+ ora.start("Validating localization state...");
3650
+ for (const bucketPath of bucket.paths) {
3651
+ const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3652
+ const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
3653
+ const sourcePath = path15.join(process.cwd(), bucketPath.pathPattern.replace("[locale]", sourceLocale));
3654
+ const sourceContent = tryReadFile(sourcePath, null);
3655
+ const sourceData = JSON.parse(sourceContent || "{}");
3656
+ const sourceFlattenedData = flatten2(sourceData, {
3657
+ delimiter: "/",
3658
+ transformKey(key) {
3659
+ return encodeURIComponent(key);
3660
+ }
3661
+ });
3662
+ for (const _targetLocale of targetLocales) {
3663
+ const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketPath.delimiter);
3664
+ const targetPath = path15.join(process.cwd(), bucketPath.pathPattern.replace("[locale]", targetLocale));
3665
+ const targetContent = tryReadFile(targetPath, null);
3666
+ const targetData = JSON.parse(targetContent || "{}");
3667
+ const targetFlattenedData = flatten2(targetData, {
3668
+ delimiter: "/",
3669
+ transformKey(key) {
3670
+ return encodeURIComponent(key);
3671
+ }
3672
+ });
3673
+ const checksums = await deltaProcessor.loadChecksums();
3674
+ const delta = await deltaProcessor.calculateDelta({
3675
+ sourceData: sourceFlattenedData,
3676
+ targetData: targetFlattenedData,
3677
+ checksums
3678
+ });
3679
+ if (!delta.hasChanges) {
3680
+ continue;
3681
+ }
3682
+ for (const [oldKey, newKey] of delta.renamed) {
3683
+ targetFlattenedData[newKey] = targetFlattenedData[oldKey];
3684
+ delete targetFlattenedData[oldKey];
3685
+ }
3686
+ const updatedTargetData = unflatten2(targetFlattenedData, {
3687
+ delimiter: "/",
3688
+ transformKey(key) {
3689
+ return decodeURIComponent(key);
3690
+ }
3691
+ });
3692
+ await writeFile(targetPath, JSON.stringify(updatedTargetData, null, 2));
3693
+ }
3694
+ }
3695
+ ora.succeed("Localization state check completed");
3556
3696
  }
3557
3697
  const cache = getNormalizedCache();
3558
3698
  if (cache) {
@@ -3565,11 +3705,16 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3565
3705
  const bucketOra = Ora5({ indent: 4 });
3566
3706
  bucketOra.info(`Processing path: ${bucketPath.pathPattern}`);
3567
3707
  const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3568
- const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3569
- isCacheRestore: true,
3570
- defaultLocale: sourceLocale,
3571
- injectLocale: bucket.injectLocale
3572
- });
3708
+ const bucketLoader = createBucketLoader(
3709
+ bucket.type,
3710
+ bucketPath.pathPattern,
3711
+ {
3712
+ isCacheRestore: true,
3713
+ defaultLocale: sourceLocale,
3714
+ injectLocale: bucket.injectLocale
3715
+ },
3716
+ bucket.lockedKeys
3717
+ );
3573
3718
  bucketLoader.setDefaultLocale(sourceLocale);
3574
3719
  await bucketLoader.init();
3575
3720
  const sourceData = await bucketLoader.pull(sourceLocale);
@@ -3584,7 +3729,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3584
3729
  }
3585
3730
  }
3586
3731
  await bucketLoader.push(targetLocale, targetData);
3587
- lockfileHelper.registerPartialSourceData(bucketPath.pathPattern, cachedSourceData);
3732
+ const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
3733
+ const checksums = await deltaProcessor.createChecksums(cachedSourceData);
3734
+ await deltaProcessor.saveChecksums(checksums);
3588
3735
  bucketOra.succeed(
3589
3736
  `[${sourceLocale} -> ${targetLocale}] Recovered ${Object.keys(cachedSourceData).length} entries from cache`
3590
3737
  );
@@ -3604,18 +3751,29 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3604
3751
  bucketLoop: for (const bucket of buckets) {
3605
3752
  for (const bucketPath of bucket.paths) {
3606
3753
  const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3607
- const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3608
- isCacheRestore: false,
3609
- defaultLocale: sourceLocale,
3610
- returnUnlocalizedKeys: true,
3611
- injectLocale: bucket.injectLocale
3612
- });
3754
+ const bucketLoader = createBucketLoader(
3755
+ bucket.type,
3756
+ bucketPath.pathPattern,
3757
+ {
3758
+ isCacheRestore: false,
3759
+ defaultLocale: sourceLocale,
3760
+ returnUnlocalizedKeys: true,
3761
+ injectLocale: bucket.injectLocale
3762
+ },
3763
+ bucket.lockedKeys
3764
+ );
3613
3765
  bucketLoader.setDefaultLocale(sourceLocale);
3614
3766
  await bucketLoader.init();
3615
3767
  const { unlocalizable: sourceUnlocalizable, ...sourceData } = await bucketLoader.pull(
3616
3768
  i18nConfig.locale.source
3617
3769
  );
3618
- const updatedSourceData = lockfileHelper.extractUpdatedData(bucketPath.pathPattern, sourceData);
3770
+ const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
3771
+ const sourceChecksums = await deltaProcessor.createChecksums(sourceData);
3772
+ const savedChecksums = await deltaProcessor.loadChecksums();
3773
+ const updatedSourceData = _21.pickBy(
3774
+ sourceData,
3775
+ (value, key) => sourceChecksums[key] !== savedChecksums[key]
3776
+ );
3619
3777
  if (Object.keys(updatedSourceData).length > 0) {
3620
3778
  requiresUpdate = "updated";
3621
3779
  break bucketLoop;
@@ -3623,9 +3781,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3623
3781
  for (const _targetLocale of targetLocales) {
3624
3782
  const targetLocale = resolveOverriddenLocale3(_targetLocale, bucketPath.delimiter);
3625
3783
  const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
3626
- const missingKeys = _20.difference(Object.keys(sourceData), Object.keys(targetData));
3627
- const extraKeys = _20.difference(Object.keys(targetData), Object.keys(sourceData));
3628
- const unlocalizableDataDiff = !_20.isEqual(sourceUnlocalizable, targetUnlocalizable);
3784
+ const missingKeys = _21.difference(Object.keys(sourceData), Object.keys(targetData));
3785
+ const extraKeys = _21.difference(Object.keys(targetData), Object.keys(sourceData));
3786
+ const unlocalizableDataDiff = !_21.isEqual(sourceUnlocalizable, targetUnlocalizable);
3629
3787
  if (missingKeys.length > 0) {
3630
3788
  requiresUpdate = "missing";
3631
3789
  break bucketLoop;
@@ -3662,11 +3820,16 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3662
3820
  for (const bucketPath of bucket.paths) {
3663
3821
  const bucketOra = Ora5({ indent: 2 }).info(`Processing path: ${bucketPath.pathPattern}`);
3664
3822
  const sourceLocale = resolveOverriddenLocale3(i18nConfig.locale.source, bucketPath.delimiter);
3665
- const bucketLoader = createBucketLoader(bucket.type, bucketPath.pathPattern, {
3666
- isCacheRestore: false,
3667
- defaultLocale: sourceLocale,
3668
- injectLocale: bucket.injectLocale
3669
- });
3823
+ const bucketLoader = createBucketLoader(
3824
+ bucket.type,
3825
+ bucketPath.pathPattern,
3826
+ {
3827
+ isCacheRestore: false,
3828
+ defaultLocale: sourceLocale,
3829
+ injectLocale: bucket.injectLocale
3830
+ },
3831
+ bucket.lockedKeys
3832
+ );
3670
3833
  bucketLoader.setDefaultLocale(sourceLocale);
3671
3834
  await bucketLoader.init();
3672
3835
  let sourceData = await bucketLoader.pull(sourceLocale);
@@ -3675,15 +3838,17 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3675
3838
  try {
3676
3839
  bucketOra.start(`[${sourceLocale} -> ${targetLocale}] (0%) Localization in progress...`);
3677
3840
  sourceData = await bucketLoader.pull(sourceLocale);
3678
- const updatedSourceData = flags.force ? sourceData : lockfileHelper.extractUpdatedData(bucketPath.pathPattern, sourceData);
3679
3841
  const targetData = await bucketLoader.pull(targetLocale);
3680
- let processableData = calculateDataDelta({
3842
+ const deltaProcessor2 = createDeltaProcessor(bucketPath.pathPattern);
3843
+ const checksums2 = await deltaProcessor2.loadChecksums();
3844
+ const delta = await deltaProcessor2.calculateDelta({
3681
3845
  sourceData,
3682
- updatedSourceData,
3683
- targetData
3846
+ targetData,
3847
+ checksums: checksums2
3684
3848
  });
3849
+ let processableData = _21.chain(sourceData).entries().filter(([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!flags.force).fromPairs().value();
3685
3850
  if (flags.key) {
3686
- processableData = _20.pickBy(processableData, (_22, key) => key === flags.key);
3851
+ processableData = _21.pickBy(processableData, (_24, key) => key === flags.key);
3687
3852
  }
3688
3853
  if (flags.verbose) {
3689
3854
  bucketOra.info(JSON.stringify(processableData, null, 2));
@@ -3720,7 +3885,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3720
3885
  if (flags.verbose) {
3721
3886
  bucketOra.info(JSON.stringify(processedTargetData, null, 2));
3722
3887
  }
3723
- let finalTargetData = _20.merge({}, sourceData, targetData, processedTargetData);
3888
+ let finalTargetData = _21.merge({}, sourceData, targetData, processedTargetData);
3724
3889
  if (flags.interactive) {
3725
3890
  bucketOra.stop();
3726
3891
  const reviewedData = await reviewChanges({
@@ -3734,7 +3899,7 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3734
3899
  finalTargetData = reviewedData;
3735
3900
  bucketOra.start(`Applying changes to ${bucketPath} (${targetLocale})`);
3736
3901
  }
3737
- const finalDiffSize = _20.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
3902
+ const finalDiffSize = _21.chain(finalTargetData).omitBy((value, key) => value === targetData[key]).size().value();
3738
3903
  await bucketLoader.push(targetLocale, finalTargetData);
3739
3904
  if (finalDiffSize > 0 || flags.force) {
3740
3905
  bucketOra.succeed(`[${sourceLocale} -> ${targetLocale}] Localization completed`);
@@ -3751,7 +3916,9 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3751
3916
  }
3752
3917
  }
3753
3918
  }
3754
- lockfileHelper.registerSourceData(bucketPath.pathPattern, sourceData);
3919
+ const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
3920
+ const checksums = await deltaProcessor.createChecksums(sourceData);
3921
+ await deltaProcessor.saveChecksums(checksums);
3755
3922
  }
3756
3923
  } catch (_error) {
3757
3924
  const error = new Error(`Failed to process bucket ${bucket.type}: ${_error.message}`);
@@ -3786,25 +3953,19 @@ var i18n_default = new Command6().command("i18n").description("Run Localization
3786
3953
  process.exit(1);
3787
3954
  }
3788
3955
  });
3789
- function calculateDataDelta(args) {
3790
- const newKeys = _20.difference(Object.keys(args.sourceData), Object.keys(args.targetData));
3791
- const updatedKeys = Object.keys(args.updatedSourceData);
3792
- const result = _20.chain(args.sourceData).pickBy((value, key) => newKeys.includes(key) || updatedKeys.includes(key)).value();
3793
- return result;
3794
- }
3795
3956
  function parseFlags(options) {
3796
- return Z4.object({
3797
- apiKey: Z4.string().optional(),
3798
- locale: Z4.array(localeCodeSchema).optional(),
3799
- bucket: Z4.array(bucketTypeSchema).optional(),
3800
- force: Z4.boolean().optional(),
3801
- frozen: Z4.boolean().optional(),
3802
- verbose: Z4.boolean().optional(),
3803
- strict: Z4.boolean().optional(),
3804
- key: Z4.string().optional(),
3805
- file: Z4.array(Z4.string()).optional(),
3806
- interactive: Z4.boolean().default(false),
3807
- debug: Z4.boolean().default(false)
3957
+ return Z3.object({
3958
+ apiKey: Z3.string().optional(),
3959
+ locale: Z3.array(localeCodeSchema).optional(),
3960
+ bucket: Z3.array(bucketTypeSchema).optional(),
3961
+ force: Z3.boolean().optional(),
3962
+ frozen: Z3.boolean().optional(),
3963
+ verbose: Z3.boolean().optional(),
3964
+ strict: Z3.boolean().optional(),
3965
+ key: Z3.string().optional(),
3966
+ file: Z3.array(Z3.string()).optional(),
3967
+ interactive: Z3.boolean().default(false),
3968
+ debug: Z3.boolean().default(false)
3808
3969
  }).parse(options);
3809
3970
  }
3810
3971
  async function validateAuth(settings) {
@@ -3898,7 +4059,7 @@ Reviewing changes for ${chalk.blue(args.pathPattern)} (${chalk.yellow(args.targe
3898
4059
  return args.currentData;
3899
4060
  }
3900
4061
  const customData = { ...args.currentData };
3901
- const changes = _20.reduce(
4062
+ const changes = _21.reduce(
3902
4063
  args.proposedData,
3903
4064
  (result, value, key) => {
3904
4065
  if (args.currentData[key] !== value) {
@@ -3950,6 +4111,77 @@ Editing value for: ${chalk.cyan(key)}`);
3950
4111
  import { Command as Command7 } from "interactive-commander";
3951
4112
  import Z5 from "zod";
3952
4113
  import Ora6 from "ora";
4114
+
4115
+ // src/cli/utils/lockfile.ts
4116
+ import fs12 from "fs";
4117
+ import path16 from "path";
4118
+ import Z4 from "zod";
4119
+ import YAML4 from "yaml";
4120
+ import { MD5 as MD52 } from "object-hash";
4121
+ import _22 from "lodash";
4122
+ function createLockfileHelper() {
4123
+ return {
4124
+ isLockfileExists: () => {
4125
+ const lockfilePath = _getLockfilePath();
4126
+ return fs12.existsSync(lockfilePath);
4127
+ },
4128
+ registerSourceData: (pathPattern, sourceData) => {
4129
+ const lockfile = _loadLockfile();
4130
+ const sectionKey = MD52(pathPattern);
4131
+ const sectionChecksums = _22.mapValues(sourceData, (value) => MD52(value));
4132
+ lockfile.checksums[sectionKey] = sectionChecksums;
4133
+ _saveLockfile(lockfile);
4134
+ },
4135
+ registerPartialSourceData: (pathPattern, partialSourceData) => {
4136
+ const lockfile = _loadLockfile();
4137
+ const sectionKey = MD52(pathPattern);
4138
+ const sectionChecksums = _22.mapValues(partialSourceData, (value) => MD52(value));
4139
+ lockfile.checksums[sectionKey] = _22.merge({}, lockfile.checksums[sectionKey] ?? {}, sectionChecksums);
4140
+ _saveLockfile(lockfile);
4141
+ },
4142
+ extractUpdatedData: (pathPattern, sourceData) => {
4143
+ const lockfile = _loadLockfile();
4144
+ const sectionKey = MD52(pathPattern);
4145
+ const currentChecksums = _22.mapValues(sourceData, (value) => MD52(value));
4146
+ const savedChecksums = lockfile.checksums[sectionKey] || {};
4147
+ const updatedData = _22.pickBy(sourceData, (value, key) => savedChecksums[key] !== currentChecksums[key]);
4148
+ return updatedData;
4149
+ }
4150
+ };
4151
+ function _loadLockfile() {
4152
+ const lockfilePath = _getLockfilePath();
4153
+ if (!fs12.existsSync(lockfilePath)) {
4154
+ return LockfileSchema.parse({});
4155
+ }
4156
+ const content = fs12.readFileSync(lockfilePath, "utf-8");
4157
+ const result = LockfileSchema.parse(YAML4.parse(content));
4158
+ return result;
4159
+ }
4160
+ function _saveLockfile(lockfile) {
4161
+ const lockfilePath = _getLockfilePath();
4162
+ const content = YAML4.stringify(lockfile);
4163
+ fs12.writeFileSync(lockfilePath, content);
4164
+ }
4165
+ function _getLockfilePath() {
4166
+ return path16.join(process.cwd(), "i18n.lock");
4167
+ }
4168
+ }
4169
+ var LockfileSchema = Z4.object({
4170
+ version: Z4.literal(1).default(1),
4171
+ checksums: Z4.record(
4172
+ Z4.string(),
4173
+ // localizable files' keys
4174
+ Z4.record(
4175
+ // checksums hashmap
4176
+ Z4.string(),
4177
+ // key
4178
+ Z4.string()
4179
+ // checksum of the key's value in the source locale
4180
+ ).default({})
4181
+ ).default({})
4182
+ });
4183
+
4184
+ // src/cli/cmd/lockfile.ts
3953
4185
  import { resolveOverriddenLocale as resolveOverriddenLocale4 } from "@lingo.dev/_spec";
3954
4186
  var lockfile_default = new Command7().command("lockfile").description("Create a lockfile if it does not exist").helpOption("-h, --help", "Show help").option("-f, --force", "Force create a lockfile").action(async (options) => {
3955
4187
  const flags = flagsSchema.parse(options);
@@ -3982,7 +4214,7 @@ var flagsSchema = Z5.object({
3982
4214
  // src/cli/cmd/cleanup.ts
3983
4215
  import { resolveOverriddenLocale as resolveOverriddenLocale5 } from "@lingo.dev/_spec";
3984
4216
  import { Command as Command8 } from "interactive-commander";
3985
- import _21 from "lodash";
4217
+ import _23 from "lodash";
3986
4218
  import Ora7 from "ora";
3987
4219
  var cleanup_default = new Command8().command("cleanup").description("Remove keys from target files that do not exist in the source file").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(
3988
4220
  "--verbose",
@@ -4018,7 +4250,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
4018
4250
  try {
4019
4251
  const targetData = await bucketLoader.pull(targetLocale);
4020
4252
  const targetKeys = Object.keys(targetData);
4021
- const keysToRemove = _21.difference(targetKeys, sourceKeys);
4253
+ const keysToRemove = _23.difference(targetKeys, sourceKeys);
4022
4254
  if (keysToRemove.length === 0) {
4023
4255
  bucketOra.succeed(`[${targetLocale}] No keys to remove`);
4024
4256
  continue;
@@ -4027,7 +4259,7 @@ var cleanup_default = new Command8().command("cleanup").description("Remove keys
4027
4259
  bucketOra.info(`[${targetLocale}] Keys to remove: ${JSON.stringify(keysToRemove, null, 2)}`);
4028
4260
  }
4029
4261
  if (!options.dryRun) {
4030
- const cleanedData = _21.pick(targetData, sourceKeys);
4262
+ const cleanedData = _23.pick(targetData, sourceKeys);
4031
4263
  await bucketLoader.push(targetLocale, cleanedData);
4032
4264
  bucketOra.succeed(`[${targetLocale}] Removed ${keysToRemove.length} keys`);
4033
4265
  } else {
@@ -4082,7 +4314,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4082
4314
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4083
4315
  import Z6 from "zod";
4084
4316
  import { ReplexicaEngine } from "@lingo.dev/_sdk";
4085
- var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_22, program) => {
4317
+ var mcp_default = new Command9().command("mcp").description("Use Lingo.dev model context provider with your AI agent").helpOption("-h, --help", "Show help").action(async (_24, program) => {
4086
4318
  const apiKey = program.args[0];
4087
4319
  const settings = getSettings(apiKey);
4088
4320
  if (!settings.auth.apiKey) {
@@ -4140,7 +4372,7 @@ import { execSync as execSync2 } from "child_process";
4140
4372
 
4141
4373
  // ../../action/src/flows/in-branch.ts
4142
4374
  import { execSync } from "child_process";
4143
- import path14 from "path";
4375
+ import path17 from "path";
4144
4376
 
4145
4377
  // ../../action/src/flows/_base.ts
4146
4378
  var IntegrationFlow = class {
@@ -4218,7 +4450,7 @@ var InBranchFlow = class extends IntegrationFlow {
4218
4450
  return false;
4219
4451
  }
4220
4452
  }
4221
- const workingDir = path14.resolve(process.cwd(), this.platformKit.config.workingDir);
4453
+ const workingDir = path17.resolve(process.cwd(), this.platformKit.config.workingDir);
4222
4454
  if (workingDir !== process.cwd()) {
4223
4455
  this.ora.info(`Changing to working directory: ${this.platformKit.config.workingDir}`);
4224
4456
  process.chdir(workingDir);
@@ -4387,15 +4619,21 @@ Hey team,
4387
4619
  };
4388
4620
 
4389
4621
  // ../../action/src/platforms/bitbucket.ts
4390
- import { execSync as execSync3 } from "child_process";
4622
+ import { execSync as execSync4 } from "child_process";
4391
4623
  import bbLib from "bitbucket";
4392
4624
  import Z8 from "zod";
4393
4625
 
4394
4626
  // ../../action/src/platforms/_base.ts
4627
+ import { execSync as execSync3 } from "child_process";
4395
4628
  import Z7 from "zod";
4396
4629
  var defaultMessage = "feat: update translations via @lingodotdev";
4397
4630
  var PlatformKit = class {
4398
- gitConfig() {
4631
+ gitConfig(token, repoUrl) {
4632
+ if (token && repoUrl) {
4633
+ execSync3(`git remote set-url origin ${repoUrl}`, {
4634
+ stdio: "inherit"
4635
+ });
4636
+ }
4399
4637
  }
4400
4638
  get config() {
4401
4639
  const env = Z7.object({
@@ -4479,10 +4717,10 @@ var BitbucketPlatformKit = class extends PlatformKit {
4479
4717
  });
4480
4718
  }
4481
4719
  async gitConfig() {
4482
- execSync3("git config --unset http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy", {
4720
+ execSync4("git config --unset http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy", {
4483
4721
  stdio: "inherit"
4484
4722
  });
4485
- execSync3("git config http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy http://host.docker.internal:29418/", {
4723
+ execSync4("git config http.${BITBUCKET_GIT_HTTP_ORIGIN}.proxy http://host.docker.internal:29418/", {
4486
4724
  stdio: "inherit"
4487
4725
  });
4488
4726
  }
@@ -4509,7 +4747,6 @@ var BitbucketPlatformKit = class extends PlatformKit {
4509
4747
  // ../../action/src/platforms/github.ts
4510
4748
  import { Octokit } from "octokit";
4511
4749
  import Z9 from "zod";
4512
- import { execSync as execSync4 } from "child_process";
4513
4750
  var GitHubPlatformKit = class extends PlatformKit {
4514
4751
  _octokit;
4515
4752
  get octokit() {
@@ -4566,9 +4803,7 @@ var GitHubPlatformKit = class extends PlatformKit {
4566
4803
  if (ghToken && processOwnCommits) {
4567
4804
  console.log("Using provided GH_TOKEN. This will trigger your CI/CD pipeline to run again.");
4568
4805
  const url = `https://${ghToken}@github.com/${repositoryOwner}/${repositoryName}.git`;
4569
- execSync4(`git remote set-url origin ${url}`, {
4570
- stdio: "inherit"
4571
- });
4806
+ super.gitConfig(ghToken, url);
4572
4807
  }
4573
4808
  }
4574
4809
  get platformConfig() {
@@ -4596,7 +4831,6 @@ var GitHubPlatformKit = class extends PlatformKit {
4596
4831
  // ../../action/src/platforms/gitlab.ts
4597
4832
  import { Gitlab } from "@gitbeaker/rest";
4598
4833
  import Z10 from "zod";
4599
- import { execSync as execSync5 } from "child_process";
4600
4834
  var gl = new Gitlab({ token: "" });
4601
4835
  var GitlabPlatformKit = class extends PlatformKit {
4602
4836
  _gitlab;
@@ -4671,10 +4905,9 @@ var GitlabPlatformKit = class extends PlatformKit {
4671
4905
  await this.gitlab.MergeRequestNotes.create(this.platformConfig.gitlabProjectId, pullRequestNumber, body);
4672
4906
  }
4673
4907
  gitConfig() {
4674
- const url = `https://oauth2:${this.platformConfig.glToken}@gitlab.com/${this.platformConfig.repositoryOwner}/${this.platformConfig.repositoryName}.git`;
4675
- execSync5(`git remote set-url origin ${url}`, {
4676
- stdio: "inherit"
4677
- });
4908
+ const glToken = this.platformConfig.glToken;
4909
+ const url = `https://oauth2:${glToken}@gitlab.com/${this.platformConfig.repositoryOwner}/${this.platformConfig.repositoryName}.git`;
4910
+ super.gitConfig(glToken, url);
4678
4911
  }
4679
4912
  buildPullRequestUrl(pullRequestNumber) {
4680
4913
  return `https://gitlab.com/${this.platformConfig.repositoryOwner}/${this.platformConfig.repositoryName}/-/merge_requests/${pullRequestNumber}`;
@@ -4745,7 +4978,7 @@ var ci_default = new Command10().command("ci").description("Run Lingo.dev CI/CD
4745
4978
  // package.json
4746
4979
  var package_default = {
4747
4980
  name: "lingo.dev",
4748
- version: "0.80.1",
4981
+ version: "0.82.0",
4749
4982
  description: "Lingo.dev CLI",
4750
4983
  private: false,
4751
4984
  publishConfig: {