lingo.dev 0.74.17 → 0.75.1

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.cjs CHANGED
@@ -287,6 +287,8 @@ function findLocaleFiles(bucket) {
287
287
  return findLocaleFilesWithExtension(".xml");
288
288
  case "markdown":
289
289
  return findLocaleFilesWithExtension(".md");
290
+ case "php":
291
+ return findLocaleFilesWithExtension(".php");
290
292
  case "xcode-xcstrings":
291
293
  return findLocaleFilesForFilename("Localizable.xcstrings");
292
294
  case "xcode-strings":
@@ -301,24 +303,31 @@ function findLocaleFilesWithExtension(ext) {
301
303
  const files = _glob.glob.sync(`**/*${ext}`, {
302
304
  ignore: ["node_modules/**", "package*.json", "i18n.json", "lingo.json"]
303
305
  });
304
- const localeFilePattern = new RegExp(`[/\\\\]([a-z]{2}(-[A-Z]{2})?)${ext}$`);
305
- const localeDirectoryPattern = new RegExp(`[/\\\\]([a-z]{2}(-[A-Z]{2})?)[/\\\\][^/\\\\]+${ext}$`);
306
+ const localeFilePattern = new RegExp(`/([a-z]{2}(-[A-Z]{2})?)${ext}$`);
307
+ const localeDirectoryPattern = new RegExp(`/([a-z]{2}(-[A-Z]{2})?)/[^/]+${ext}$`);
306
308
  const potentialLocaleFiles = files.filter(
307
309
  (file) => localeFilePattern.test(file) || localeDirectoryPattern.test(file)
308
310
  );
309
- const localeFilesAndPatterns = potentialLocaleFiles.map((file) => {
310
- const match = file.match(new RegExp(`[/|\\\\]([a-z]{2}(-[A-Z]{2})?)(/|\\\\|${ext})`));
311
- const locale = _optionalChain([match, 'optionalAccess', _29 => _29[1]]);
312
- const localeInDir = _optionalChain([match, 'optionalAccess', _30 => _30[3]]) !== ext;
313
- const filePattern = localeInDir ? file.replace(`/${locale}/`, `/[locale]/`) : _path2.default.join(_path2.default.dirname(file), `[locale]${ext}`);
314
- return { file, locale, pattern: filePattern };
315
- }).filter(({ locale }) => {
316
- try {
317
- __spec.resolveLocaleCode.call(void 0, locale);
318
- return true;
319
- } catch (e) {
311
+ const potantialLocaleFilesAndPatterns = potentialLocaleFiles.map((file) => {
312
+ const matchPotentialLocales = Array.from(
313
+ file.matchAll(new RegExp(`/([a-z]{2}(-[A-Z]{2})?|[^/]+)(?=/|${ext})`, "g"))
314
+ );
315
+ const potantialLocales = matchPotentialLocales.map((match) => match[1]);
316
+ return { file, potantialLocales };
317
+ }).map(({ file, potantialLocales }) => {
318
+ for (const locale of potantialLocales) {
319
+ try {
320
+ __spec.resolveLocaleCode.call(void 0, locale);
321
+ return { locale, file };
322
+ } catch (e) {
323
+ }
320
324
  }
321
- return false;
325
+ return { file, locale: null };
326
+ }).filter(({ locale }) => locale !== null);
327
+ const localeFilesAndPatterns = potantialLocaleFilesAndPatterns.map(({ file, locale }) => {
328
+ const localeInDir = file.match(`/${locale}/`);
329
+ const pattern = localeInDir ? file.replace(`/${locale}/`, `/[locale]/`) : _path2.default.join(_path2.default.dirname(file), `[locale]${ext}`);
330
+ return { pattern, file };
322
331
  });
323
332
  const grouppedFilesAndPatterns = _lodash2.default.groupBy(localeFilesAndPatterns, "pattern");
324
333
  const patterns = Object.keys(grouppedFilesAndPatterns);
@@ -517,6 +526,8 @@ var init_default = new (0, _interactivecommander.InteractiveCommand)().command("
517
526
  });
518
527
  } else {
519
528
  spinner.succeed("No existing locale files found.");
529
+ }
530
+ if (selectedPatterns.length === 0) {
520
531
  const useDefault = await _prompts.confirm.call(void 0, {
521
532
  message: `Use (and create) default path ${patterns.join(", ")}?`
522
533
  });
@@ -565,7 +576,7 @@ var init_default = new (0, _interactivecommander.InteractiveCommand)().command("
565
576
  });
566
577
  const auth2 = await newAuthenticator.whoami();
567
578
  if (auth2) {
568
- _ora2.default.call(void 0, ).succeed(`Authenticated as ${_optionalChain([auth2, 'optionalAccess', _31 => _31.email])}`);
579
+ _ora2.default.call(void 0, ).succeed(`Authenticated as ${_optionalChain([auth2, 'optionalAccess', _29 => _29.email])}`);
569
580
  } else {
570
581
  _ora2.default.call(void 0, ).fail("Authentication failed.");
571
582
  }
@@ -644,7 +655,7 @@ var locale_default = new (0, _interactivecommander.Command)().command("locale").
644
655
  function getBuckets(i18nConfig) {
645
656
  const result = Object.entries(i18nConfig.buckets).map(([bucketType, bucketEntry]) => {
646
657
  const includeItems = bucketEntry.include.map((item) => resolveBucketItem(item));
647
- const excludeItems = _optionalChain([bucketEntry, 'access', _32 => _32.exclude, 'optionalAccess', _33 => _33.map, 'call', _34 => _34((item) => resolveBucketItem(item))]);
658
+ const excludeItems = _optionalChain([bucketEntry, 'access', _30 => _30.exclude, 'optionalAccess', _31 => _31.map, 'call', _32 => _32((item) => resolveBucketItem(item))]);
648
659
  return {
649
660
  type: bucketType,
650
661
  config: extractPathPatterns(i18nConfig.locale.source, includeItems, excludeItems)
@@ -661,7 +672,7 @@ function extractPathPatterns(sourceLocale, include, exclude) {
661
672
  })
662
673
  )
663
674
  );
664
- const excludedPatterns = _optionalChain([exclude, 'optionalAccess', _35 => _35.flatMap, 'call', _36 => _36(
675
+ const excludedPatterns = _optionalChain([exclude, 'optionalAccess', _33 => _33.flatMap, 'call', _34 => _34(
665
676
  (pattern) => expandPlaceholderedGlob(pattern.path, __spec.resolveOverridenLocale.call(void 0, sourceLocale, pattern.delimiter)).map(
666
677
  (pathPattern) => ({
667
678
  pathPattern,
@@ -695,7 +706,7 @@ function expandPlaceholderedGlob(_pathPattern, sourceLocale) {
695
706
  }
696
707
  const pathPatternChunks = pathPattern.split(_path2.default.sep);
697
708
  const localeSegmentIndex = pathPatternChunks.findIndex((segment) => segment.includes("[locale]"));
698
- const localePlaceholderIndex = _nullishCoalesce(_optionalChain([pathPatternChunks, 'access', _37 => _37[localeSegmentIndex], 'optionalAccess', _38 => _38.indexOf, 'call', _39 => _39("[locale]")]), () => ( -1));
709
+ const localePlaceholderIndex = _nullishCoalesce(_optionalChain([pathPatternChunks, 'access', _35 => _35[localeSegmentIndex], 'optionalAccess', _36 => _36.indexOf, 'call', _37 => _37("[locale]")]), () => ( -1));
699
710
  const sourcePathPattern = pathPattern.replace(/\[locale\]/g, sourceLocale);
700
711
  const sourcePaths = glob2.sync(sourcePathPattern, { follow: true, withFileTypes: true }).filter((file) => file.isFile() || file.isSymbolicLink()).map((file) => file.fullpath()).map((fullpath) => _path2.default.relative(process.cwd(), fullpath));
701
712
  const placeholderedPaths = sourcePaths.map((sourcePath) => {
@@ -780,12 +791,12 @@ function composeLoaders(...loaders) {
780
791
  return {
781
792
  init: async () => {
782
793
  for (const loader of loaders) {
783
- await _optionalChain([loader, 'access', _40 => _40.init, 'optionalCall', _41 => _41()]);
794
+ await _optionalChain([loader, 'access', _38 => _38.init, 'optionalCall', _39 => _39()]);
784
795
  }
785
796
  },
786
797
  setDefaultLocale(locale) {
787
798
  for (const loader of loaders) {
788
- _optionalChain([loader, 'access', _42 => _42.setDefaultLocale, 'optionalCall', _43 => _43(locale)]);
799
+ _optionalChain([loader, 'access', _40 => _40.setDefaultLocale, 'optionalCall', _41 => _41(locale)]);
789
800
  }
790
801
  return this;
791
802
  },
@@ -816,7 +827,7 @@ function createLoader(lDefinition) {
816
827
  if (state.initCtx) {
817
828
  return state.initCtx;
818
829
  }
819
- state.initCtx = await _optionalChain([lDefinition, 'access', _44 => _44.init, 'optionalCall', _45 => _45()]);
830
+ state.initCtx = await _optionalChain([lDefinition, 'access', _42 => _42.init, 'optionalCall', _43 => _43()]);
820
831
  return state.initCtx;
821
832
  },
822
833
  setDefaultLocale(locale) {
@@ -905,7 +916,7 @@ function createNormalizeLoader() {
905
916
  return normalized;
906
917
  },
907
918
  push: async (locale, data, originalInput) => {
908
- const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _46 => _46.keysMap]), () => ( {}));
919
+ const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _44 => _44.keysMap]), () => ( {}));
909
920
  const input2 = mapDenormalizedKeys(data, keysMap);
910
921
  const denormalized = _flat.unflatten.call(void 0, input2, {
911
922
  delimiter: "/",
@@ -1008,8 +1019,8 @@ async function getTrailingNewLine(pathPattern, locale, originalLocale) {
1008
1019
  if (!templateData) {
1009
1020
  templateData = await readFileForLocale(pathPattern, originalLocale);
1010
1021
  }
1011
- if (_optionalChain([templateData, 'optionalAccess', _47 => _47.match, 'call', _48 => _48(/[\r\n]$/)])) {
1012
- const ending = _optionalChain([templateData, 'optionalAccess', _49 => _49.includes, 'call', _50 => _50("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _51 => _51.includes, 'call', _52 => _52("\r")]) ? "\r" : "\n";
1022
+ if (_optionalChain([templateData, 'optionalAccess', _45 => _45.match, 'call', _46 => _46(/[\r\n]$/)])) {
1023
+ const ending = _optionalChain([templateData, 'optionalAccess', _47 => _47.includes, 'call', _48 => _48("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _49 => _49.includes, 'call', _50 => _50("\r")]) ? "\r" : "\n";
1013
1024
  return ending;
1014
1025
  }
1015
1026
  return "";
@@ -1236,7 +1247,7 @@ function createHtmlLoader() {
1236
1247
  break;
1237
1248
  }
1238
1249
  const siblings = Array.from(parent.childNodes).filter(
1239
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _53 => _53.textContent, 'optionalAccess', _54 => _54.trim, 'call', _55 => _55()])
1250
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _51 => _51.textContent, 'optionalAccess', _52 => _52.trim, 'call', _53 => _53()])
1240
1251
  );
1241
1252
  const index = siblings.indexOf(current);
1242
1253
  if (index !== -1) {
@@ -1271,11 +1282,11 @@ function createHtmlLoader() {
1271
1282
  result[getPath(element, attr)] = value;
1272
1283
  }
1273
1284
  });
1274
- Array.from(element.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _56 => _56.textContent, 'optionalAccess', _57 => _57.trim, 'call', _58 => _58()])).forEach(processNode);
1285
+ Array.from(element.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _54 => _54.textContent, 'optionalAccess', _55 => _55.trim, 'call', _56 => _56()])).forEach(processNode);
1275
1286
  }
1276
1287
  };
1277
- Array.from(document.head.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _59 => _59.textContent, 'optionalAccess', _60 => _60.trim, 'call', _61 => _61()])).forEach(processNode);
1278
- Array.from(document.body.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _62 => _62.textContent, 'optionalAccess', _63 => _63.trim, 'call', _64 => _64()])).forEach(processNode);
1288
+ Array.from(document.head.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _57 => _57.textContent, 'optionalAccess', _58 => _58.trim, 'call', _59 => _59()])).forEach(processNode);
1289
+ Array.from(document.body.childNodes).filter((n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _60 => _60.textContent, 'optionalAccess', _61 => _61.trim, 'call', _62 => _62()])).forEach(processNode);
1279
1290
  return result;
1280
1291
  },
1281
1292
  async push(locale, data, originalInput) {
@@ -1297,7 +1308,7 @@ function createHtmlLoader() {
1297
1308
  for (let i = 0; i < indices.length; i++) {
1298
1309
  const index = parseInt(indices[i]);
1299
1310
  const siblings = Array.from(parent.childNodes).filter(
1300
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _65 => _65.textContent, 'optionalAccess', _66 => _66.trim, 'call', _67 => _67()])
1311
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _63 => _63.textContent, 'optionalAccess', _64 => _64.trim, 'call', _65 => _65()])
1301
1312
  );
1302
1313
  if (index >= siblings.length) {
1303
1314
  if (i === indices.length - 1) {
@@ -1404,7 +1415,7 @@ function isSkippableLine(line) {
1404
1415
  function parsePropertyLine(line) {
1405
1416
  const [key, ...valueParts] = line.split("=");
1406
1417
  return {
1407
- key: _optionalChain([key, 'optionalAccess', _68 => _68.trim, 'call', _69 => _69()]) || "",
1418
+ key: _optionalChain([key, 'optionalAccess', _66 => _66.trim, 'call', _67 => _67()]) || "",
1408
1419
  value: valueParts.join("=").trim()
1409
1420
  };
1410
1421
  }
@@ -1486,7 +1497,7 @@ function createXcodeXcstringsLoader() {
1486
1497
  const resultData = {};
1487
1498
  for (const [translationKey, _translationEntity] of Object.entries(input2.strings)) {
1488
1499
  const rootTranslationEntity = _translationEntity;
1489
- const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _70 => _70.localizations, 'optionalAccess', _71 => _71[locale]]);
1500
+ const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _68 => _68.localizations, 'optionalAccess', _69 => _69[locale]]);
1490
1501
  if (langTranslationEntity) {
1491
1502
  if ("stringUnit" in langTranslationEntity) {
1492
1503
  resultData[translationKey] = langTranslationEntity.stringUnit.value;
@@ -1495,7 +1506,7 @@ function createXcodeXcstringsLoader() {
1495
1506
  resultData[translationKey] = {};
1496
1507
  const pluralForms = langTranslationEntity.variations.plural;
1497
1508
  for (const form in pluralForms) {
1498
- if (_optionalChain([pluralForms, 'access', _72 => _72[form], 'optionalAccess', _73 => _73.stringUnit, 'optionalAccess', _74 => _74.value])) {
1509
+ if (_optionalChain([pluralForms, 'access', _70 => _70[form], 'optionalAccess', _71 => _71.stringUnit, 'optionalAccess', _72 => _72.value])) {
1499
1510
  resultData[translationKey][form] = pluralForms[form].stringUnit.value;
1500
1511
  }
1501
1512
  }
@@ -1645,7 +1656,7 @@ function createPoDataLoader(params) {
1645
1656
  Object.entries(entries).forEach(([msgid, entry]) => {
1646
1657
  if (msgid && entry.msgid) {
1647
1658
  const context = entry.msgctxt || "";
1648
- const fullEntry = _optionalChain([parsedPo, 'access', _75 => _75.translations, 'access', _76 => _76[context], 'optionalAccess', _77 => _77[msgid]]);
1659
+ const fullEntry = _optionalChain([parsedPo, 'access', _73 => _73.translations, 'access', _74 => _74[context], 'optionalAccess', _75 => _75[msgid]]);
1649
1660
  if (fullEntry) {
1650
1661
  result[msgid] = fullEntry;
1651
1662
  }
@@ -1655,7 +1666,7 @@ function createPoDataLoader(params) {
1655
1666
  return result;
1656
1667
  },
1657
1668
  async push(locale, data, originalInput) {
1658
- const sections = _optionalChain([originalInput, 'optionalAccess', _78 => _78.split, 'call', _79 => _79("\n\n"), 'access', _80 => _80.filter, 'call', _81 => _81(Boolean)]) || [];
1669
+ const sections = _optionalChain([originalInput, 'optionalAccess', _76 => _76.split, 'call', _77 => _77("\n\n"), 'access', _78 => _78.filter, 'call', _79 => _79(Boolean)]) || [];
1659
1670
  const result = sections.map((section) => {
1660
1671
  const sectionPo = _gettextparser2.default.po.parse(section);
1661
1672
  const contextKey = _lodash2.default.keys(sectionPo.translations)[0];
@@ -1697,7 +1708,7 @@ function createPoContentLoader() {
1697
1708
  entry.msgid,
1698
1709
  {
1699
1710
  ...entry,
1700
- msgstr: [_optionalChain([data, 'access', _82 => _82[entry.msgid], 'optionalAccess', _83 => _83.singular]), _optionalChain([data, 'access', _84 => _84[entry.msgid], 'optionalAccess', _85 => _85.plural]) || null].filter(Boolean)
1711
+ msgstr: [_optionalChain([data, 'access', _80 => _80[entry.msgid], 'optionalAccess', _81 => _81.singular]), _optionalChain([data, 'access', _82 => _82[entry.msgid], 'optionalAccess', _83 => _83.plural]) || null].filter(Boolean)
1701
1712
  }
1702
1713
  ]).fromPairs().value();
1703
1714
  return result;
@@ -1943,7 +1954,7 @@ function createDatoClient(params) {
1943
1954
  only_valid: "true",
1944
1955
  ids: !records.length ? void 0 : records.join(",")
1945
1956
  }
1946
- }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _86 => _86.response, 'optionalAccess', _87 => _87.body, 'optionalAccess', _88 => _88.data, 'optionalAccess', _89 => _89[0]]) || error));
1957
+ }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _84 => _84.response, 'optionalAccess', _85 => _85.body, 'optionalAccess', _86 => _86.data, 'optionalAccess', _87 => _87[0]]) || error));
1947
1958
  },
1948
1959
  findRecordsForModel: async (modelId, records) => {
1949
1960
  try {
@@ -1953,9 +1964,9 @@ function createDatoClient(params) {
1953
1964
  filter: {
1954
1965
  type: modelId,
1955
1966
  only_valid: "true",
1956
- ids: !_optionalChain([records, 'optionalAccess', _90 => _90.length]) ? void 0 : records.join(",")
1967
+ ids: !_optionalChain([records, 'optionalAccess', _88 => _88.length]) ? void 0 : records.join(",")
1957
1968
  }
1958
- }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _91 => _91.response, 'optionalAccess', _92 => _92.body, 'optionalAccess', _93 => _93.data, 'optionalAccess', _94 => _94[0]]) || error));
1969
+ }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _89 => _89.response, 'optionalAccess', _90 => _90.body, 'optionalAccess', _91 => _91.data, 'optionalAccess', _92 => _92[0]]) || error));
1959
1970
  return result;
1960
1971
  } catch (_error) {
1961
1972
  throw new Error(
@@ -1969,9 +1980,9 @@ function createDatoClient(params) {
1969
1980
  },
1970
1981
  updateRecord: async (id, payload) => {
1971
1982
  try {
1972
- await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _95 => _95.response, 'optionalAccess', _96 => _96.body, 'optionalAccess', _97 => _97.data, 'optionalAccess', _98 => _98[0]]) || error));
1983
+ await dato.items.update(id, payload).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _93 => _93.response, 'optionalAccess', _94 => _94.body, 'optionalAccess', _95 => _95.data, 'optionalAccess', _96 => _96[0]]) || error));
1973
1984
  } catch (_error) {
1974
- if (_optionalChain([_error, 'optionalAccess', _99 => _99.attributes, 'optionalAccess', _100 => _100.details, 'optionalAccess', _101 => _101.message])) {
1985
+ if (_optionalChain([_error, 'optionalAccess', _97 => _97.attributes, 'optionalAccess', _98 => _98.details, 'optionalAccess', _99 => _99.message])) {
1975
1986
  throw new Error(
1976
1987
  [
1977
1988
  `${_error.attributes.details.message}`,
@@ -1992,9 +2003,9 @@ function createDatoClient(params) {
1992
2003
  },
1993
2004
  enableFieldLocalization: async (args) => {
1994
2005
  try {
1995
- await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _102 => _102.response, 'optionalAccess', _103 => _103.body, 'optionalAccess', _104 => _104.data, 'optionalAccess', _105 => _105[0]]) || error));
2006
+ await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch((error) => Promise.reject(_optionalChain([error, 'optionalAccess', _100 => _100.response, 'optionalAccess', _101 => _101.body, 'optionalAccess', _102 => _102.data, 'optionalAccess', _103 => _103[0]]) || error));
1996
2007
  } catch (_error) {
1997
- if (_optionalChain([_error, 'optionalAccess', _106 => _106.attributes, 'optionalAccess', _107 => _107.code]) === "NOT_FOUND") {
2008
+ if (_optionalChain([_error, 'optionalAccess', _104 => _104.attributes, 'optionalAccess', _105 => _105.code]) === "NOT_FOUND") {
1998
2009
  throw new Error(
1999
2010
  [
2000
2011
  `Field "${args.fieldId}" not found in model "${args.modelId}".`,
@@ -2002,7 +2013,7 @@ function createDatoClient(params) {
2002
2013
  ].join("\n\n")
2003
2014
  );
2004
2015
  }
2005
- if (_optionalChain([_error, 'optionalAccess', _108 => _108.attributes, 'optionalAccess', _109 => _109.details, 'optionalAccess', _110 => _110.message])) {
2016
+ if (_optionalChain([_error, 'optionalAccess', _106 => _106.attributes, 'optionalAccess', _107 => _107.details, 'optionalAccess', _108 => _108.message])) {
2006
2017
  throw new Error(
2007
2018
  [`${_error.attributes.details.message}`, `Error: ${JSON.stringify(_error, null, 2)}`].join("\n\n")
2008
2019
  );
@@ -2068,7 +2079,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
2068
2079
  }
2069
2080
  }
2070
2081
  const records = await dato.findRecordsForModel(modelId);
2071
- const recordChoices = createRecordChoices(records, _optionalChain([config, 'access', _111 => _111.models, 'access', _112 => _112[modelId], 'optionalAccess', _113 => _113.records]) || [], project);
2082
+ const recordChoices = createRecordChoices(records, _optionalChain([config, 'access', _109 => _109.models, 'access', _110 => _110[modelId], 'optionalAccess', _111 => _111.records]) || [], project);
2072
2083
  const selectedRecords = await promptRecordSelection(modelName, recordChoices);
2073
2084
  result.models[modelId].records = records.filter((record) => selectedRecords.includes(record.id));
2074
2085
  updatedConfig.models[modelId].records = selectedRecords;
@@ -2080,14 +2091,14 @@ function createDatoApiLoader(config, onConfigUpdate) {
2080
2091
  },
2081
2092
  async pull(locale, input2, initCtx) {
2082
2093
  const result = {};
2083
- for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _114 => _114.models]) || {})) {
2084
- let records = _optionalChain([initCtx, 'optionalAccess', _115 => _115.models, 'access', _116 => _116[modelId], 'access', _117 => _117.records]) || [];
2094
+ for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _112 => _112.models]) || {})) {
2095
+ let records = _optionalChain([initCtx, 'optionalAccess', _113 => _113.models, 'access', _114 => _114[modelId], 'access', _115 => _115.records]) || [];
2085
2096
  const recordIds = records.map((record) => record.id);
2086
2097
  records = await dato.findRecords(recordIds);
2087
2098
  console.log(`Fetched ${records.length} records for model ${modelId}`);
2088
2099
  if (records.length > 0) {
2089
2100
  result[modelId] = {
2090
- fields: _optionalChain([initCtx, 'optionalAccess', _118 => _118.models, 'optionalAccess', _119 => _119[modelId], 'optionalAccess', _120 => _120.fields]) || [],
2101
+ fields: _optionalChain([initCtx, 'optionalAccess', _116 => _116.models, 'optionalAccess', _117 => _117[modelId], 'optionalAccess', _118 => _118.fields]) || [],
2091
2102
  records
2092
2103
  };
2093
2104
  }
@@ -2146,7 +2157,7 @@ function createRecordChoices(records, selectedIds = [], project) {
2146
2157
  return records.map((record) => ({
2147
2158
  name: `${record.id} - https://${project.internal_domain}/editor/item_types/${record.item_type.id}/items/${record.id}`,
2148
2159
  value: record.id,
2149
- checked: _optionalChain([selectedIds, 'optionalAccess', _121 => _121.includes, 'call', _122 => _122(record.id)])
2160
+ checked: _optionalChain([selectedIds, 'optionalAccess', _119 => _119.includes, 'call', _120 => _120(record.id)])
2150
2161
  }));
2151
2162
  }
2152
2163
  async function promptRecordSelection(modelName, choices) {
@@ -2413,7 +2424,7 @@ var _nodewebvtt = require('node-webvtt'); var _nodewebvtt2 = _interopRequireDefa
2413
2424
  function createVttLoader() {
2414
2425
  return createLoader({
2415
2426
  async pull(locale, input2) {
2416
- const vtt = _optionalChain([_nodewebvtt2.default, 'access', _123 => _123.parse, 'call', _124 => _124(input2), 'optionalAccess', _125 => _125.cues]);
2427
+ const vtt = _optionalChain([_nodewebvtt2.default, 'access', _121 => _121.parse, 'call', _122 => _122(input2), 'optionalAccess', _123 => _123.cues]);
2417
2428
  if (Object.keys(vtt).length === 0) {
2418
2429
  return {};
2419
2430
  } else {
@@ -2465,7 +2476,7 @@ function variableExtractLoader(params) {
2465
2476
  for (let i = 0; i < matches.length; i++) {
2466
2477
  const match = matches[i];
2467
2478
  const currentValue = result[key].value;
2468
- const newValue = _optionalChain([currentValue, 'optionalAccess', _126 => _126.replace, 'call', _127 => _127(match, `{variable:${i}}`)]);
2479
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _124 => _124.replace, 'call', _125 => _125(match, `{variable:${i}}`)]);
2469
2480
  result[key].value = newValue;
2470
2481
  result[key].variables[i] = match;
2471
2482
  }
@@ -2479,7 +2490,7 @@ function variableExtractLoader(params) {
2479
2490
  for (let i = 0; i < valueObj.variables.length; i++) {
2480
2491
  const variable = valueObj.variables[i];
2481
2492
  const currentValue = result[key];
2482
- const newValue = _optionalChain([currentValue, 'optionalAccess', _128 => _128.replace, 'call', _129 => _129(`{variable:${i}}`, variable)]);
2493
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _126 => _126.replace, 'call', _127 => _127(`{variable:${i}}`, variable)]);
2483
2494
  result[key] = newValue;
2484
2495
  }
2485
2496
  }
@@ -2537,10 +2548,10 @@ function createSyncLoader() {
2537
2548
 
2538
2549
  // src/cli/utils/plutil-formatter.ts
2539
2550
  function formatPlutilStyle(jsonData, existingJson) {
2540
- const indent = existingJson ? detectIndentation(existingJson) : " ";
2551
+ const indent2 = existingJson ? detectIndentation(existingJson) : " ";
2541
2552
  function format(data, level = 0) {
2542
- const currentIndent = indent.repeat(level);
2543
- const nextIndent = indent.repeat(level + 1);
2553
+ const currentIndent = indent2.repeat(level);
2554
+ const nextIndent = indent2.repeat(level + 1);
2544
2555
  if (typeof data !== "object" || data === null) {
2545
2556
  return JSON.stringify(data);
2546
2557
  }
@@ -2594,6 +2605,66 @@ function createPlutilJsonTextLoader() {
2594
2605
  });
2595
2606
  }
2596
2607
 
2608
+ // src/cli/loaders/php.ts
2609
+ var _phparrayreader = require('php-array-reader');
2610
+ function createPhpLoader() {
2611
+ return createLoader({
2612
+ pull: async (locale, input2) => {
2613
+ try {
2614
+ const output = _phparrayreader.fromString.call(void 0, input2);
2615
+ return output;
2616
+ } catch (error) {
2617
+ throw new Error(`Error parsing PHP file for locale ${locale}`);
2618
+ }
2619
+ },
2620
+ push: async (locale, data, originalInput) => {
2621
+ const output = toPhpString(data, originalInput);
2622
+ return output;
2623
+ }
2624
+ });
2625
+ }
2626
+ function toPhpString(data, originalPhpString) {
2627
+ const defaultFilePrefix = "<?php\n\n";
2628
+ if (originalPhpString) {
2629
+ const [filePrefix = defaultFilePrefix] = originalPhpString.split("return ");
2630
+ const shortArraySyntax = !originalPhpString.includes("array(");
2631
+ const output = `${filePrefix}return ${toPhpArray(data, shortArraySyntax)};`;
2632
+ return output;
2633
+ }
2634
+ return `${defaultFilePrefix}return ${toPhpArray(data)};`;
2635
+ }
2636
+ function toPhpArray(data, shortSyntax = true, indentLevel = 1) {
2637
+ if (data === null || data === void 0) {
2638
+ return "null";
2639
+ }
2640
+ if (typeof data === "string") {
2641
+ return `'${escapePhpString(data)}'`;
2642
+ }
2643
+ if (typeof data === "number") {
2644
+ return data.toString();
2645
+ }
2646
+ if (typeof data === "boolean") {
2647
+ return data ? "true" : "false";
2648
+ }
2649
+ const arrayStart = shortSyntax ? "[" : "array(";
2650
+ const arrayEnd = shortSyntax ? "]" : ")";
2651
+ if (Array.isArray(data)) {
2652
+ return `${arrayStart}
2653
+ ${data.map((value) => `${indent(indentLevel)}${toPhpArray(value, shortSyntax, indentLevel + 1)}`).join(",\n")}
2654
+ ${indent(indentLevel - 1)}${arrayEnd}`;
2655
+ }
2656
+ const output = `${arrayStart}
2657
+ ${Object.entries(data).map(([key, value]) => `${indent(indentLevel)}'${key}' => ${toPhpArray(value, shortSyntax, indentLevel + 1)}`).join(",\n")}
2658
+ ${indent(indentLevel - 1)}${arrayEnd}`;
2659
+ return output;
2660
+ }
2661
+ function indent(level) {
2662
+ return " ".repeat(level);
2663
+ }
2664
+ function escapePhpString(str) {
2665
+ return str.replaceAll("\\", "\\\\").replaceAll("'", "\\'").replaceAll("\r", "\\r").replaceAll("\n", "\\n").replaceAll(" ", "\\t");
2666
+ }
2667
+
2597
2668
  // src/cli/loaders/index.ts
2598
2669
  function createBucketLoader(bucketType, bucketPathPattern, { isCacheRestore = false } = {}) {
2599
2670
  switch (bucketType) {
@@ -2748,6 +2819,14 @@ function createBucketLoader(bucketType, bucketPathPattern, { isCacheRestore = fa
2748
2819
  createSyncLoader(),
2749
2820
  createUnlocalizableLoader(isCacheRestore)
2750
2821
  );
2822
+ case "php":
2823
+ return composeLoaders(
2824
+ createTextFileLoader(bucketPathPattern),
2825
+ createPhpLoader(),
2826
+ createSyncLoader(),
2827
+ createFlatLoader(),
2828
+ createUnlocalizableLoader()
2829
+ );
2751
2830
  }
2752
2831
  }
2753
2832
 
@@ -2919,11 +2998,11 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
2919
2998
  const auth = await validateAuth(settings);
2920
2999
  ora.succeed(`Authenticated as ${auth.email}`);
2921
3000
  let buckets = getBuckets(i18nConfig);
2922
- if (_optionalChain([flags, 'access', _130 => _130.bucket, 'optionalAccess', _131 => _131.length])) {
3001
+ if (_optionalChain([flags, 'access', _128 => _128.bucket, 'optionalAccess', _129 => _129.length])) {
2923
3002
  buckets = buckets.filter((bucket) => flags.bucket.includes(bucket.type));
2924
3003
  }
2925
3004
  ora.succeed("Buckets retrieved");
2926
- const targetLocales = _optionalChain([flags, 'access', _132 => _132.locale, 'optionalAccess', _133 => _133.length]) ? flags.locale : i18nConfig.locale.targets;
3005
+ const targetLocales = _optionalChain([flags, 'access', _130 => _130.locale, 'optionalAccess', _131 => _131.length]) ? flags.locale : i18nConfig.locale.targets;
2927
3006
  const lockfileHelper = createLockfileHelper();
2928
3007
  ora.start("Ensuring i18n.lock exists...");
2929
3008
  if (!lockfileHelper.isLockfileExists()) {
@@ -3209,12 +3288,12 @@ function validateParams(i18nConfig, flags) {
3209
3288
  message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
3210
3289
  docUrl: "bucketNotFound"
3211
3290
  });
3212
- } else if (_optionalChain([flags, 'access', _134 => _134.locale, 'optionalAccess', _135 => _135.some, 'call', _136 => _136((locale) => !i18nConfig.locale.targets.includes(locale))])) {
3291
+ } else if (_optionalChain([flags, 'access', _132 => _132.locale, 'optionalAccess', _133 => _133.some, 'call', _134 => _134((locale) => !i18nConfig.locale.targets.includes(locale))])) {
3213
3292
  throw new CLIError({
3214
3293
  message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
3215
3294
  docUrl: "localeTargetNotFound"
3216
3295
  });
3217
- } else if (_optionalChain([flags, 'access', _137 => _137.bucket, 'optionalAccess', _138 => _138.some, 'call', _139 => _139((bucket) => !i18nConfig.buckets[bucket])])) {
3296
+ } else if (_optionalChain([flags, 'access', _135 => _135.bucket, 'optionalAccess', _136 => _136.some, 'call', _137 => _137((bucket) => !i18nConfig.buckets[bucket])])) {
3218
3297
  throw new CLIError({
3219
3298
  message: `One or more specified buckets do not exist in i18n.json. Please add them to the list and try again.`,
3220
3299
  docUrl: "bucketNotFound"
@@ -3441,7 +3520,7 @@ function displaySummary(results) {
3441
3520
  // package.json
3442
3521
  var package_default = {
3443
3522
  name: "lingo.dev",
3444
- version: "0.74.17",
3523
+ version: "0.75.1",
3445
3524
  description: "Lingo.dev CLI",
3446
3525
  private: false,
3447
3526
  publishConfig: {
@@ -3485,10 +3564,10 @@ var package_default = {
3485
3564
  author: "",
3486
3565
  license: "Apache-2.0",
3487
3566
  dependencies: {
3488
- "@lingo.dev/_sdk": "workspace:*",
3489
- "@lingo.dev/_spec": "workspace:*",
3490
3567
  "@datocms/cma-client-node": "^3.4.0",
3491
3568
  "@inquirer/prompts": "^7.2.3",
3569
+ "@lingo.dev/_sdk": "workspace:*",
3570
+ "@lingo.dev/_spec": "workspace:*",
3492
3571
  "@paralleldrive/cuid2": "^2.2.2",
3493
3572
  chalk: "^5.4.1",
3494
3573
  cors: "^2.8.5",
@@ -3522,6 +3601,7 @@ var package_default = {
3522
3601
  open: "^10.1.0",
3523
3602
  ora: "^8.1.1",
3524
3603
  "p-limit": "^6.2.0",
3604
+ "php-array-reader": "^2.1.2",
3525
3605
  plist: "^3.1.0",
3526
3606
  prettier: "^3.4.2",
3527
3607
  "properties-parser": "^0.6.0",