lingo.dev 0.113.2 → 0.113.4

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
@@ -1874,9 +1874,9 @@ function createJsoncLoader() {
1874
1874
  var _flat = require('flat');
1875
1875
 
1876
1876
  var OBJECT_NUMERIC_KEY_PREFIX = "__lingodotdev__obj__";
1877
- function createFlatLoader() {
1877
+ function createFlatLoader(options) {
1878
1878
  const composedLoader = composeLoaders(
1879
- createDenormalizeLoader(),
1879
+ createDenormalizeLoader(options),
1880
1880
  createNormalizeLoader()
1881
1881
  );
1882
1882
  return {
@@ -1889,16 +1889,29 @@ function createFlatLoader() {
1889
1889
  }
1890
1890
  };
1891
1891
  }
1892
- function createDenormalizeLoader() {
1892
+ function createDenormalizeLoader(options) {
1893
1893
  return createLoader({
1894
1894
  pull: async (locale, input2) => {
1895
1895
  const inputDenormalized = denormalizeObjectKeys(input2 || {});
1896
- const denormalized = _flat.flatten.call(void 0, inputDenormalized, {
1896
+ const preservedObjects = {};
1897
+ const nonPreservedInput = {};
1898
+ for (const [key, value] of Object.entries(inputDenormalized)) {
1899
+ if (_optionalChain([options, 'optionalAccess', _102 => _102.shouldPreserveObject, 'optionalCall', _103 => _103(value)])) {
1900
+ preservedObjects[key] = value;
1901
+ } else {
1902
+ nonPreservedInput[key] = value;
1903
+ }
1904
+ }
1905
+ const flattened = _flat.flatten.call(void 0, nonPreservedInput, {
1897
1906
  delimiter: "/",
1898
1907
  transformKey(key) {
1899
1908
  return encodeURIComponent(String(key));
1900
1909
  }
1901
1910
  });
1911
+ const denormalized = {
1912
+ ...flattened,
1913
+ ...preservedObjects
1914
+ };
1902
1915
  const keysMap = buildDenormalizedKeysMap(denormalized);
1903
1916
  return { denormalized, keysMap };
1904
1917
  },
@@ -1915,7 +1928,7 @@ function createNormalizeLoader() {
1915
1928
  return normalized;
1916
1929
  },
1917
1930
  push: async (locale, data, originalInput) => {
1918
- const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _102 => _102.keysMap]), () => ( {}));
1931
+ const keysMap = _nullishCoalesce(_optionalChain([originalInput, 'optionalAccess', _104 => _104.keysMap]), () => ( {}));
1919
1932
  const input2 = mapDenormalizedKeys(data, keysMap);
1920
1933
  const denormalized = _flat.unflatten.call(void 0, input2, {
1921
1934
  delimiter: "/",
@@ -2049,8 +2062,8 @@ async function getTrailingNewLine(pathPattern, locale, originalLocale) {
2049
2062
  if (!templateData) {
2050
2063
  templateData = await readFileForLocale(pathPattern, originalLocale);
2051
2064
  }
2052
- if (_optionalChain([templateData, 'optionalAccess', _103 => _103.match, 'call', _104 => _104(/[\r\n]$/)])) {
2053
- const ending = _optionalChain([templateData, 'optionalAccess', _105 => _105.includes, 'call', _106 => _106("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _107 => _107.includes, 'call', _108 => _108("\r")]) ? "\r" : "\n";
2065
+ if (_optionalChain([templateData, 'optionalAccess', _105 => _105.match, 'call', _106 => _106(/[\r\n]$/)])) {
2066
+ const ending = _optionalChain([templateData, 'optionalAccess', _107 => _107.includes, 'call', _108 => _108("\r\n")]) ? "\r\n" : _optionalChain([templateData, 'optionalAccess', _109 => _109.includes, 'call', _110 => _110("\r")]) ? "\r" : "\n";
2054
2067
  return ending;
2055
2068
  }
2056
2069
  return "";
@@ -2321,7 +2334,7 @@ var _sync3 = require('csv-stringify/sync');
2321
2334
 
2322
2335
  function detectKeyColumnName(csvString) {
2323
2336
  const row = _sync.parse.call(void 0, csvString)[0];
2324
- const firstColumn = _optionalChain([row, 'optionalAccess', _109 => _109[0], 'optionalAccess', _110 => _110.trim, 'call', _111 => _111()]);
2337
+ const firstColumn = _optionalChain([row, 'optionalAccess', _111 => _111[0], 'optionalAccess', _112 => _112.trim, 'call', _113 => _113()]);
2325
2338
  return firstColumn || "KEY";
2326
2339
  }
2327
2340
  function createCsvLoader() {
@@ -2423,7 +2436,7 @@ function createHtmlLoader() {
2423
2436
  break;
2424
2437
  }
2425
2438
  const siblings = Array.from(parent.childNodes).filter(
2426
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _112 => _112.textContent, 'optionalAccess', _113 => _113.trim, 'call', _114 => _114()])
2439
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _114 => _114.textContent, 'optionalAccess', _115 => _115.trim, 'call', _116 => _116()])
2427
2440
  );
2428
2441
  const index = siblings.indexOf(current);
2429
2442
  if (index !== -1) {
@@ -2459,15 +2472,15 @@ function createHtmlLoader() {
2459
2472
  }
2460
2473
  });
2461
2474
  Array.from(element.childNodes).filter(
2462
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _115 => _115.textContent, 'optionalAccess', _116 => _116.trim, 'call', _117 => _117()])
2475
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _117 => _117.textContent, 'optionalAccess', _118 => _118.trim, 'call', _119 => _119()])
2463
2476
  ).forEach(processNode);
2464
2477
  }
2465
2478
  };
2466
2479
  Array.from(document.head.childNodes).filter(
2467
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _118 => _118.textContent, 'optionalAccess', _119 => _119.trim, 'call', _120 => _120()])
2480
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _120 => _120.textContent, 'optionalAccess', _121 => _121.trim, 'call', _122 => _122()])
2468
2481
  ).forEach(processNode);
2469
2482
  Array.from(document.body.childNodes).filter(
2470
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _121 => _121.textContent, 'optionalAccess', _122 => _122.trim, 'call', _123 => _123()])
2483
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _123 => _123.textContent, 'optionalAccess', _124 => _124.trim, 'call', _125 => _125()])
2471
2484
  ).forEach(processNode);
2472
2485
  return result;
2473
2486
  },
@@ -2492,7 +2505,7 @@ function createHtmlLoader() {
2492
2505
  for (let i = 0; i < indices.length; i++) {
2493
2506
  const index = parseInt(indices[i]);
2494
2507
  const siblings = Array.from(parent.childNodes).filter(
2495
- (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _124 => _124.textContent, 'optionalAccess', _125 => _125.trim, 'call', _126 => _126()])
2508
+ (n) => n.nodeType === 1 || n.nodeType === 3 && _optionalChain([n, 'access', _126 => _126.textContent, 'optionalAccess', _127 => _127.trim, 'call', _128 => _128()])
2496
2509
  );
2497
2510
  if (index >= siblings.length) {
2498
2511
  if (i === indices.length - 1) {
@@ -2543,7 +2556,7 @@ function createMarkdownLoader() {
2543
2556
  yaml: yamlEngine
2544
2557
  }
2545
2558
  });
2546
- const sections = content.split(SECTION_REGEX).map((section) => _nullishCoalesce(_optionalChain([section, 'optionalAccess', _127 => _127.trim, 'call', _128 => _128()]), () => ( ""))).filter(Boolean);
2559
+ const sections = content.split(SECTION_REGEX).map((section) => _nullishCoalesce(_optionalChain([section, 'optionalAccess', _129 => _129.trim, 'call', _130 => _130()]), () => ( ""))).filter(Boolean);
2547
2560
  return {
2548
2561
  ...Object.fromEntries(
2549
2562
  sections.map((section, index) => [`${MD_SECTION_PREFIX}${index}`, section]).filter(([, section]) => Boolean(section))
@@ -2562,7 +2575,7 @@ function createMarkdownLoader() {
2562
2575
  );
2563
2576
  let content = Object.entries(data).filter(([key]) => key.startsWith(MD_SECTION_PREFIX)).sort(
2564
2577
  ([a], [b]) => Number(a.split("-").pop()) - Number(b.split("-").pop())
2565
- ).map(([, value]) => _nullishCoalesce(_optionalChain([value, 'optionalAccess', _129 => _129.trim, 'call', _130 => _130()]), () => ( ""))).filter(Boolean).join("\n\n");
2578
+ ).map(([, value]) => _nullishCoalesce(_optionalChain([value, 'optionalAccess', _131 => _131.trim, 'call', _132 => _132()]), () => ( ""))).filter(Boolean).join("\n\n");
2566
2579
  if (Object.keys(frontmatter).length > 0) {
2567
2580
  content = `
2568
2581
  ${content}`;
@@ -2587,7 +2600,7 @@ function createMarkdocLoader() {
2587
2600
  const result = {};
2588
2601
  const counters = {};
2589
2602
  traverseAndExtract(ast, "", result, counters);
2590
- if (_optionalChain([ast, 'access', _131 => _131.attributes, 'optionalAccess', _132 => _132.frontmatter])) {
2603
+ if (_optionalChain([ast, 'access', _133 => _133.attributes, 'optionalAccess', _134 => _134.frontmatter])) {
2591
2604
  const frontmatter = _yaml2.default.parse(ast.attributes.frontmatter);
2592
2605
  Object.entries(frontmatter).forEach(([key, value]) => {
2593
2606
  if (typeof value === "string") {
@@ -2633,7 +2646,7 @@ function traverseAndExtract(node, path19, result, counters, parentType) {
2633
2646
  if (nodeSemanticType && !["text", "strong", "em", "inline", "link"].includes(nodeSemanticType)) {
2634
2647
  semanticType = nodeSemanticType;
2635
2648
  }
2636
- if (node.type === "text" && _optionalChain([node, 'access', _133 => _133.attributes, 'optionalAccess', _134 => _134.content])) {
2649
+ if (node.type === "text" && _optionalChain([node, 'access', _135 => _135.attributes, 'optionalAccess', _136 => _136.content])) {
2637
2650
  const content = node.attributes.content;
2638
2651
  if (typeof content === "string" && content.trim()) {
2639
2652
  if (semanticType) {
@@ -2660,7 +2673,7 @@ function buildPathMap(node, path19, counters, pathMap, parentType) {
2660
2673
  if (nodeSemanticType && !["text", "strong", "em", "inline", "link"].includes(nodeSemanticType)) {
2661
2674
  semanticType = nodeSemanticType;
2662
2675
  }
2663
- if (node.type === "text" && _optionalChain([node, 'access', _135 => _135.attributes, 'optionalAccess', _136 => _136.content])) {
2676
+ if (node.type === "text" && _optionalChain([node, 'access', _137 => _137.attributes, 'optionalAccess', _138 => _138.content])) {
2664
2677
  const content = node.attributes.content;
2665
2678
  if (typeof content === "string" && content.trim()) {
2666
2679
  if (semanticType) {
@@ -2683,7 +2696,7 @@ function applyTranslations(node, path19, data, pathMap) {
2683
2696
  if (!node || typeof node !== "object") {
2684
2697
  return;
2685
2698
  }
2686
- if (node.type === "text" && _optionalChain([node, 'access', _137 => _137.attributes, 'optionalAccess', _138 => _138.content])) {
2699
+ if (node.type === "text" && _optionalChain([node, 'access', _139 => _139.attributes, 'optionalAccess', _140 => _140.content])) {
2687
2700
  const content = node.attributes.content;
2688
2701
  if (typeof content === "string") {
2689
2702
  const contentPath = path19 ? `${path19}/attributes/content` : "attributes/content";
@@ -2733,7 +2746,7 @@ function isSkippableLine(line) {
2733
2746
  function parsePropertyLine(line) {
2734
2747
  const [key, ...valueParts] = line.split("=");
2735
2748
  return {
2736
- key: _optionalChain([key, 'optionalAccess', _139 => _139.trim, 'call', _140 => _140()]) || "",
2749
+ key: _optionalChain([key, 'optionalAccess', _141 => _141.trim, 'call', _142 => _142()]) || "",
2737
2750
  value: valueParts.join("=").trim()
2738
2751
  };
2739
2752
  }
@@ -2821,7 +2834,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2821
2834
  if (rootTranslationEntity.shouldTranslate === false) {
2822
2835
  continue;
2823
2836
  }
2824
- const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _141 => _141.localizations, 'optionalAccess', _142 => _142[locale]]);
2837
+ const langTranslationEntity = _optionalChain([rootTranslationEntity, 'optionalAccess', _143 => _143.localizations, 'optionalAccess', _144 => _144[locale]]);
2825
2838
  if (langTranslationEntity) {
2826
2839
  if ("stringUnit" in langTranslationEntity) {
2827
2840
  resultData[translationKey] = langTranslationEntity.stringUnit.value;
@@ -2830,7 +2843,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2830
2843
  resultData[translationKey] = {};
2831
2844
  const pluralForms = langTranslationEntity.variations.plural;
2832
2845
  for (const form in pluralForms) {
2833
- if (_optionalChain([pluralForms, 'access', _143 => _143[form], 'optionalAccess', _144 => _144.stringUnit, 'optionalAccess', _145 => _145.value])) {
2846
+ if (_optionalChain([pluralForms, 'access', _145 => _145[form], 'optionalAccess', _146 => _146.stringUnit, 'optionalAccess', _147 => _147.value])) {
2834
2847
  resultData[translationKey][form] = pluralForms[form].stringUnit.value;
2835
2848
  }
2836
2849
  }
@@ -2856,7 +2869,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2856
2869
  const hasDoNotTranslateFlag = originalInput && originalInput.strings && originalInput.strings[key] && originalInput.strings[key].shouldTranslate === false;
2857
2870
  if (typeof value === "string") {
2858
2871
  langDataToMerge.strings[key] = {
2859
- extractionState: _optionalChain([originalInput, 'optionalAccess', _146 => _146.strings, 'optionalAccess', _147 => _147[key], 'optionalAccess', _148 => _148.extractionState]),
2872
+ extractionState: _optionalChain([originalInput, 'optionalAccess', _148 => _148.strings, 'optionalAccess', _149 => _149[key], 'optionalAccess', _150 => _150.extractionState]),
2860
2873
  localizations: {
2861
2874
  [locale]: {
2862
2875
  stringUnit: {
@@ -2914,7 +2927,7 @@ function createXcodeXcstringsLoader(defaultLocale) {
2914
2927
  for (const [locale, localization] of Object.entries(
2915
2928
  entity.localizations
2916
2929
  )) {
2917
- if (_optionalChain([localization, 'access', _149 => _149.variations, 'optionalAccess', _150 => _150.plural])) {
2930
+ if (_optionalChain([localization, 'access', _151 => _151.variations, 'optionalAccess', _152 => _152.plural])) {
2918
2931
  const pluralForms = localization.variations.plural;
2919
2932
  for (const form in pluralForms) {
2920
2933
  const pluralKey = `${translationKey}/${form}`;
@@ -2934,13 +2947,387 @@ function _removeLocale(input2, locale) {
2934
2947
  const { strings } = input2;
2935
2948
  const newStrings = _lodash2.default.cloneDeep(strings);
2936
2949
  for (const [key, value] of Object.entries(newStrings)) {
2937
- if (_optionalChain([value, 'access', _151 => _151.localizations, 'optionalAccess', _152 => _152[locale]])) {
2950
+ if (_optionalChain([value, 'access', _153 => _153.localizations, 'optionalAccess', _154 => _154[locale]])) {
2938
2951
  delete value.localizations[locale];
2939
2952
  }
2940
2953
  }
2941
2954
  return { ...input2, strings: newStrings };
2942
2955
  }
2943
2956
 
2957
+ // src/cli/loaders/xcode-xcstrings-icu.ts
2958
+ var ICU_TYPE_MARKER = Symbol.for("@lingo.dev/icu-plural-object");
2959
+ var CLDR_PLURAL_CATEGORIES = /* @__PURE__ */ new Set([
2960
+ "zero",
2961
+ "one",
2962
+ "two",
2963
+ "few",
2964
+ "many",
2965
+ "other"
2966
+ ]);
2967
+ function isICUPluralObject(value) {
2968
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2969
+ return false;
2970
+ }
2971
+ if (ICU_TYPE_MARKER in value) {
2972
+ return true;
2973
+ }
2974
+ if (!("icu" in value) || typeof value.icu !== "string") {
2975
+ return false;
2976
+ }
2977
+ const icuPluralPattern = /^\{[\w]+,\s*plural,\s*.+\}$/;
2978
+ if (!icuPluralPattern.test(value.icu)) {
2979
+ return false;
2980
+ }
2981
+ if (value._meta !== void 0) {
2982
+ if (typeof value._meta !== "object" || !value._meta.variables || typeof value._meta.variables !== "object") {
2983
+ return false;
2984
+ }
2985
+ for (const [varName, varMeta] of Object.entries(value._meta.variables)) {
2986
+ if (!varMeta || typeof varMeta !== "object" || typeof varMeta.format !== "string" || varMeta.role !== "plural" && varMeta.role !== "other") {
2987
+ return false;
2988
+ }
2989
+ }
2990
+ }
2991
+ return true;
2992
+ }
2993
+ function isPluralFormsObject(value) {
2994
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2995
+ return false;
2996
+ }
2997
+ const keys = Object.keys(value);
2998
+ if (keys.length === 0) {
2999
+ return false;
3000
+ }
3001
+ const allKeysAreCldr = keys.every((key) => CLDR_PLURAL_CATEGORIES.has(key));
3002
+ if (!allKeysAreCldr) {
3003
+ return false;
3004
+ }
3005
+ const allValuesAreStrings = keys.every(
3006
+ (key) => typeof value[key] === "string"
3007
+ );
3008
+ if (!allValuesAreStrings) {
3009
+ return false;
3010
+ }
3011
+ if (!("other" in value)) {
3012
+ return false;
3013
+ }
3014
+ return true;
3015
+ }
3016
+ function getRequiredPluralCategories(locale) {
3017
+ try {
3018
+ const pluralRules = new Intl.PluralRules(locale);
3019
+ const categories = pluralRules.resolvedOptions().pluralCategories;
3020
+ if (!categories || categories.length === 0) {
3021
+ throw new Error(`No plural categories found for locale: ${locale}`);
3022
+ }
3023
+ return categories;
3024
+ } catch (error) {
3025
+ console.warn(
3026
+ `[xcode-xcstrings-icu] Failed to resolve plural categories for locale "${locale}". Using fallback ["one", "other"]. Error: ${error instanceof Error ? error.message : String(error)}`
3027
+ );
3028
+ return ["one", "other"];
3029
+ }
3030
+ }
3031
+ var CLDR_CATEGORY_TO_NUMBER = {
3032
+ zero: 0,
3033
+ one: 1,
3034
+ two: 2
3035
+ };
3036
+ var NUMBER_TO_CLDR_CATEGORY = {
3037
+ 0: "zero",
3038
+ 1: "one",
3039
+ 2: "two"
3040
+ };
3041
+ function xcstringsToPluralWithMeta(pluralForms, sourceLocale = "en") {
3042
+ if (!pluralForms || Object.keys(pluralForms).length === 0) {
3043
+ throw new Error("pluralForms cannot be empty");
3044
+ }
3045
+ const requiredCategories = getRequiredPluralCategories(sourceLocale);
3046
+ const variables = {};
3047
+ const formatRegex = /(%(?:(\d+)\$)?(?:[+-])?(?:\d+)?(?:\.(\d+))?([lhqLzjt]*)([diuoxXfFeEgGaAcspn@]))/g;
3048
+ let maxMatches = [];
3049
+ let maxMatchText = "";
3050
+ for (const [form, text] of Object.entries(pluralForms)) {
3051
+ if (typeof text !== "string") {
3052
+ console.warn(
3053
+ `Warning: Plural form "${form}" has non-string value:`,
3054
+ text
3055
+ );
3056
+ continue;
3057
+ }
3058
+ const matches = [...text.matchAll(formatRegex)];
3059
+ if (matches.length > maxMatches.length) {
3060
+ maxMatches = matches;
3061
+ maxMatchText = text;
3062
+ }
3063
+ }
3064
+ let lastNumericIndex = -1;
3065
+ maxMatches.forEach((match2, idx) => {
3066
+ const specifier = match2[5];
3067
+ if (/[diuoxXfFeE]/.test(specifier)) {
3068
+ lastNumericIndex = idx;
3069
+ }
3070
+ });
3071
+ let nonPluralCounter = 0;
3072
+ maxMatches.forEach((match2, idx) => {
3073
+ const fullFormat = match2[1];
3074
+ const position = match2[2];
3075
+ const precision = match2[3];
3076
+ const lengthMod = match2[4];
3077
+ const specifier = match2[5];
3078
+ const isPluralVar = idx === lastNumericIndex;
3079
+ const varName = isPluralVar ? "count" : `var${nonPluralCounter++}`;
3080
+ variables[varName] = {
3081
+ format: fullFormat,
3082
+ role: isPluralVar ? "plural" : "other"
3083
+ };
3084
+ });
3085
+ const variableKeys = Object.keys(variables);
3086
+ const icuForms = Object.entries(pluralForms).filter(([form, text]) => {
3087
+ if (typeof text !== "string") {
3088
+ return false;
3089
+ }
3090
+ return true;
3091
+ }).map(([form, text]) => {
3092
+ let processed = text;
3093
+ let vIdx = 0;
3094
+ processed = processed.replace(formatRegex, () => {
3095
+ if (vIdx >= variableKeys.length) {
3096
+ vIdx++;
3097
+ return "#";
3098
+ }
3099
+ const varName = variableKeys[vIdx];
3100
+ const varMeta = variables[varName];
3101
+ vIdx++;
3102
+ if (varMeta.role === "plural") {
3103
+ return "#";
3104
+ } else {
3105
+ return `{${varName}}`;
3106
+ }
3107
+ });
3108
+ const isRequired = requiredCategories.includes(form);
3109
+ const formKey = !isRequired && form in CLDR_CATEGORY_TO_NUMBER ? `=${CLDR_CATEGORY_TO_NUMBER[form]}` : form;
3110
+ return `${formKey} {${processed}}`;
3111
+ }).join(" ");
3112
+ const pluralVarName = Object.keys(variables).find((name) => variables[name].role === "plural") || "count";
3113
+ const icu = `{${pluralVarName}, plural, ${icuForms}}`;
3114
+ const result = {
3115
+ icu,
3116
+ _meta: Object.keys(variables).length > 0 ? { variables } : void 0,
3117
+ [ICU_TYPE_MARKER]: true
3118
+ // Add type marker for robust detection
3119
+ };
3120
+ return result;
3121
+ }
3122
+ function pluralWithMetaToXcstrings(data) {
3123
+ if (!data.icu) {
3124
+ throw new Error("ICU string is required");
3125
+ }
3126
+ const ast = parseICU(data.icu);
3127
+ if (!ast || ast.length === 0) {
3128
+ throw new Error("Invalid ICU format");
3129
+ }
3130
+ const pluralNode = ast.find((node) => node.type === "plural");
3131
+ if (!pluralNode) {
3132
+ throw new Error("No plural found in ICU format");
3133
+ }
3134
+ const forms = {};
3135
+ for (const [form, option] of Object.entries(pluralNode.options)) {
3136
+ let text = "";
3137
+ const optionValue = option.value;
3138
+ for (const element of optionValue) {
3139
+ if (element.type === "literal") {
3140
+ text += element.value;
3141
+ } else if (element.type === "pound") {
3142
+ const pluralVar = Object.entries(_optionalChain([data, 'access', _155 => _155._meta, 'optionalAccess', _156 => _156.variables]) || {}).find(
3143
+ ([_36, meta]) => meta.role === "plural"
3144
+ );
3145
+ text += _optionalChain([pluralVar, 'optionalAccess', _157 => _157[1], 'access', _158 => _158.format]) || "%lld";
3146
+ } else if (element.type === "argument") {
3147
+ const varName = element.value;
3148
+ const varMeta = _optionalChain([data, 'access', _159 => _159._meta, 'optionalAccess', _160 => _160.variables, 'optionalAccess', _161 => _161[varName]]);
3149
+ text += _optionalChain([varMeta, 'optionalAccess', _162 => _162.format]) || "%@";
3150
+ }
3151
+ }
3152
+ let xcstringsFormName = form;
3153
+ if (form.startsWith("=")) {
3154
+ const numValue = parseInt(form.substring(1), 10);
3155
+ xcstringsFormName = NUMBER_TO_CLDR_CATEGORY[numValue] || form;
3156
+ }
3157
+ forms[xcstringsFormName] = text;
3158
+ }
3159
+ return forms;
3160
+ }
3161
+ function parseICU(icu) {
3162
+ const match2 = icu.match(/\{(\w+),\s*plural,\s*(.+)\}$/);
3163
+ if (!match2) {
3164
+ throw new Error("Invalid ICU plural format");
3165
+ }
3166
+ const varName = match2[1];
3167
+ const formsText = match2[2];
3168
+ const options = {};
3169
+ let i = 0;
3170
+ while (i < formsText.length) {
3171
+ while (i < formsText.length && /\s/.test(formsText[i])) {
3172
+ i++;
3173
+ }
3174
+ if (i >= formsText.length) break;
3175
+ let formName = "";
3176
+ if (formsText[i] === "=") {
3177
+ formName += formsText[i];
3178
+ i++;
3179
+ while (i < formsText.length && /\d/.test(formsText[i])) {
3180
+ formName += formsText[i];
3181
+ i++;
3182
+ }
3183
+ } else {
3184
+ while (i < formsText.length && /\w/.test(formsText[i])) {
3185
+ formName += formsText[i];
3186
+ i++;
3187
+ }
3188
+ }
3189
+ if (!formName) break;
3190
+ while (i < formsText.length && /\s/.test(formsText[i])) {
3191
+ i++;
3192
+ }
3193
+ if (i >= formsText.length || formsText[i] !== "{") {
3194
+ throw new Error(`Expected '{' after form name '${formName}'`);
3195
+ }
3196
+ i++;
3197
+ let braceCount = 1;
3198
+ let formText = "";
3199
+ while (i < formsText.length && braceCount > 0) {
3200
+ if (formsText[i] === "{") {
3201
+ braceCount++;
3202
+ formText += formsText[i];
3203
+ } else if (formsText[i] === "}") {
3204
+ braceCount--;
3205
+ if (braceCount > 0) {
3206
+ formText += formsText[i];
3207
+ }
3208
+ } else {
3209
+ formText += formsText[i];
3210
+ }
3211
+ i++;
3212
+ }
3213
+ if (braceCount !== 0) {
3214
+ const preview = formsText.substring(
3215
+ Math.max(0, i - 50),
3216
+ Math.min(formsText.length, i + 50)
3217
+ );
3218
+ throw new Error(
3219
+ `Unclosed brace for form '${formName}' in ICU MessageFormat.
3220
+ Expected ${braceCount} more closing brace(s).
3221
+ Context: ...${preview}...
3222
+ Full ICU: {${varName}, plural, ${formsText}}`
3223
+ );
3224
+ }
3225
+ const elements = parseFormText(formText);
3226
+ options[formName] = {
3227
+ value: elements
3228
+ };
3229
+ }
3230
+ return [
3231
+ {
3232
+ type: "plural",
3233
+ value: varName,
3234
+ options
3235
+ }
3236
+ ];
3237
+ }
3238
+ function parseFormText(text) {
3239
+ const elements = [];
3240
+ let currentText = "";
3241
+ let i = 0;
3242
+ while (i < text.length) {
3243
+ if (text[i] === "#") {
3244
+ if (currentText) {
3245
+ elements.push({ type: "literal", value: currentText });
3246
+ currentText = "";
3247
+ }
3248
+ elements.push({ type: "pound" });
3249
+ i++;
3250
+ } else if (text[i] === "{") {
3251
+ if (currentText) {
3252
+ elements.push({ type: "literal", value: currentText });
3253
+ currentText = "";
3254
+ }
3255
+ let braceCount = 1;
3256
+ let j = i + 1;
3257
+ while (j < text.length && braceCount > 0) {
3258
+ if (text[j] === "{") {
3259
+ braceCount++;
3260
+ } else if (text[j] === "}") {
3261
+ braceCount--;
3262
+ }
3263
+ j++;
3264
+ }
3265
+ if (braceCount !== 0) {
3266
+ throw new Error("Unclosed variable reference");
3267
+ }
3268
+ const varName = text.slice(i + 1, j - 1);
3269
+ elements.push({ type: "argument", value: varName });
3270
+ i = j;
3271
+ } else {
3272
+ currentText += text[i];
3273
+ i++;
3274
+ }
3275
+ }
3276
+ if (currentText) {
3277
+ elements.push({ type: "literal", value: currentText });
3278
+ }
3279
+ return elements;
3280
+ }
3281
+
3282
+ // src/cli/loaders/xcode-xcstrings-v2-loader.ts
3283
+ function createXcodeXcstringsV2Loader(defaultLocale = "en") {
3284
+ return createLoader({
3285
+ async pull(locale, input2) {
3286
+ const result = {};
3287
+ for (const [key, value] of Object.entries(input2)) {
3288
+ if (isPluralFormsObject(value)) {
3289
+ try {
3290
+ result[key] = xcstringsToPluralWithMeta(value, locale);
3291
+ } catch (error) {
3292
+ console.error(
3293
+ `
3294
+ [xcode-xcstrings-icu] Failed to convert plural forms for key "${key}":`,
3295
+ `
3296
+ Error: ${error instanceof Error ? error.message : String(error)}`,
3297
+ `
3298
+ Locale: ${locale}
3299
+ `
3300
+ );
3301
+ result[key] = value;
3302
+ }
3303
+ } else {
3304
+ result[key] = value;
3305
+ }
3306
+ }
3307
+ return result;
3308
+ },
3309
+ async push(locale, payload) {
3310
+ const result = {};
3311
+ for (const [key, value] of Object.entries(payload)) {
3312
+ if (isICUPluralObject(value)) {
3313
+ try {
3314
+ const pluralForms = pluralWithMetaToXcstrings(value);
3315
+ result[key] = pluralForms;
3316
+ } catch (error) {
3317
+ throw new Error(
3318
+ `Failed to write plural translation for key "${key}" (locale: ${locale}).
3319
+ ${error instanceof Error ? error.message : String(error)}`
3320
+ );
3321
+ }
3322
+ } else {
3323
+ result[key] = value;
3324
+ }
3325
+ }
3326
+ return result;
3327
+ }
3328
+ });
3329
+ }
3330
+
2944
3331
  // src/cli/loaders/unlocalizable.ts
2945
3332
 
2946
3333
  var _isurl = require('is-url'); var _isurl2 = _interopRequireDefault(_isurl);
@@ -3137,8 +3524,8 @@ async function formatDataWithBiome(data, filePath, options) {
3137
3524
  });
3138
3525
  return formatted.content;
3139
3526
  } catch (error) {
3140
- const errorMessage = error instanceof Error ? error.message || _optionalChain([error, 'access', _153 => _153.stackTrace, 'optionalAccess', _154 => _154.toString, 'call', _155 => _155(), 'access', _156 => _156.split, 'call', _157 => _157("\n"), 'access', _158 => _158[0]]) : "";
3141
- if (_optionalChain([errorMessage, 'optionalAccess', _159 => _159.includes, 'call', _160 => _160("does not exist in the workspace")])) {
3527
+ const errorMessage = error instanceof Error ? error.message || _optionalChain([error, 'access', _163 => _163.stackTrace, 'optionalAccess', _164 => _164.toString, 'call', _165 => _165(), 'access', _166 => _166.split, 'call', _167 => _167("\n"), 'access', _168 => _168[0]]) : "";
3528
+ if (_optionalChain([errorMessage, 'optionalAccess', _169 => _169.includes, 'call', _170 => _170("does not exist in the workspace")])) {
3142
3529
  } else {
3143
3530
  console.log(`\u26A0\uFE0F Biome skipped ${path14.default.basename(filePath)}`);
3144
3531
  if (errorMessage) {
@@ -3185,7 +3572,7 @@ function createPoDataLoader(params) {
3185
3572
  Object.entries(entries).forEach(([msgid, entry]) => {
3186
3573
  if (msgid && entry.msgid) {
3187
3574
  const context = entry.msgctxt || "";
3188
- const fullEntry = _optionalChain([parsedPo, 'access', _161 => _161.translations, 'access', _162 => _162[context], 'optionalAccess', _163 => _163[msgid]]);
3575
+ const fullEntry = _optionalChain([parsedPo, 'access', _171 => _171.translations, 'access', _172 => _172[context], 'optionalAccess', _173 => _173[msgid]]);
3189
3576
  if (fullEntry) {
3190
3577
  result[msgid] = fullEntry;
3191
3578
  }
@@ -3195,8 +3582,8 @@ function createPoDataLoader(params) {
3195
3582
  return result;
3196
3583
  },
3197
3584
  async push(locale, data, originalInput, originalLocale, pullInput) {
3198
- const currentSections = _optionalChain([pullInput, 'optionalAccess', _164 => _164.split, 'call', _165 => _165("\n\n"), 'access', _166 => _166.filter, 'call', _167 => _167(Boolean)]) || [];
3199
- const originalSections = _optionalChain([originalInput, 'optionalAccess', _168 => _168.split, 'call', _169 => _169("\n\n"), 'access', _170 => _170.filter, 'call', _171 => _171(Boolean)]) || [];
3585
+ const currentSections = _optionalChain([pullInput, 'optionalAccess', _174 => _174.split, 'call', _175 => _175("\n\n"), 'access', _176 => _176.filter, 'call', _177 => _177(Boolean)]) || [];
3586
+ const originalSections = _optionalChain([originalInput, 'optionalAccess', _178 => _178.split, 'call', _179 => _179("\n\n"), 'access', _180 => _180.filter, 'call', _181 => _181(Boolean)]) || [];
3200
3587
  const result = originalSections.map((section) => {
3201
3588
  const sectionPo = _gettextparser2.default.po.parse(section);
3202
3589
  if (Object.keys(sectionPo.translations).length === 0) {
@@ -3265,8 +3652,8 @@ function createPoContentLoader() {
3265
3652
  {
3266
3653
  ...entry,
3267
3654
  msgstr: [
3268
- _optionalChain([data, 'access', _172 => _172[entry.msgid], 'optionalAccess', _173 => _173.singular]),
3269
- _optionalChain([data, 'access', _174 => _174[entry.msgid], 'optionalAccess', _175 => _175.plural]) || null
3655
+ _optionalChain([data, 'access', _182 => _182[entry.msgid], 'optionalAccess', _183 => _183.singular]),
3656
+ _optionalChain([data, 'access', _184 => _184[entry.msgid], 'optionalAccess', _185 => _185.plural]) || null
3270
3657
  ].filter(Boolean)
3271
3658
  }
3272
3659
  ]).fromPairs().value();
@@ -3388,7 +3775,7 @@ function pullV1(xliffElement, locale, originalLocale) {
3388
3775
  let key = getTransUnitKey(unit);
3389
3776
  if (!key) return;
3390
3777
  if (seenKeys.has(key)) {
3391
- const id = _optionalChain([unit, 'access', _176 => _176.getAttribute, 'call', _177 => _177("id"), 'optionalAccess', _178 => _178.trim, 'call', _179 => _179()]);
3778
+ const id = _optionalChain([unit, 'access', _186 => _186.getAttribute, 'call', _187 => _187("id"), 'optionalAccess', _188 => _188.trim, 'call', _189 => _189()]);
3392
3779
  if (id) {
3393
3780
  key = `${key}#${id}`;
3394
3781
  } else {
@@ -3436,7 +3823,7 @@ function pushV1(dom, xliffElement, locale, translations, originalLocale, origina
3436
3823
  let key = getTransUnitKey(unit);
3437
3824
  if (!key) return;
3438
3825
  if (seenKeys.has(key)) {
3439
- const id = _optionalChain([unit, 'access', _180 => _180.getAttribute, 'call', _181 => _181("id"), 'optionalAccess', _182 => _182.trim, 'call', _183 => _183()]);
3826
+ const id = _optionalChain([unit, 'access', _190 => _190.getAttribute, 'call', _191 => _191("id"), 'optionalAccess', _192 => _192.trim, 'call', _193 => _193()]);
3440
3827
  if (id) {
3441
3828
  key = `${key}#${id}`;
3442
3829
  } else {
@@ -3478,7 +3865,7 @@ function pushV1(dom, xliffElement, locale, translations, originalLocale, origina
3478
3865
  const translationKeys = new Set(Object.keys(translations));
3479
3866
  existingUnits.forEach((unit, key) => {
3480
3867
  if (!translationKeys.has(key)) {
3481
- _optionalChain([unit, 'access', _184 => _184.parentNode, 'optionalAccess', _185 => _185.removeChild, 'call', _186 => _186(unit)]);
3868
+ _optionalChain([unit, 'access', _194 => _194.parentNode, 'optionalAccess', _195 => _195.removeChild, 'call', _196 => _196(unit)]);
3482
3869
  }
3483
3870
  });
3484
3871
  return serializeWithDeclaration(
@@ -3521,18 +3908,18 @@ function traverseUnitsV2(container, fileId, currentPath, result) {
3521
3908
  Array.from(container.children).forEach((child) => {
3522
3909
  const tagName = child.tagName;
3523
3910
  if (tagName === "unit") {
3524
- const unitId = _optionalChain([child, 'access', _187 => _187.getAttribute, 'call', _188 => _188("id"), 'optionalAccess', _189 => _189.trim, 'call', _190 => _190()]);
3911
+ const unitId = _optionalChain([child, 'access', _197 => _197.getAttribute, 'call', _198 => _198("id"), 'optionalAccess', _199 => _199.trim, 'call', _200 => _200()]);
3525
3912
  if (!unitId) return;
3526
3913
  const key = `resources/${fileId}/${currentPath}${unitId}/source`;
3527
3914
  const segment = child.querySelector("segment");
3528
- const source = _optionalChain([segment, 'optionalAccess', _191 => _191.querySelector, 'call', _192 => _192("source")]);
3915
+ const source = _optionalChain([segment, 'optionalAccess', _201 => _201.querySelector, 'call', _202 => _202("source")]);
3529
3916
  if (source) {
3530
3917
  result[key] = extractTextContent(source);
3531
3918
  } else {
3532
3919
  result[key] = unitId;
3533
3920
  }
3534
3921
  } else if (tagName === "group") {
3535
- const groupId = _optionalChain([child, 'access', _193 => _193.getAttribute, 'call', _194 => _194("id"), 'optionalAccess', _195 => _195.trim, 'call', _196 => _196()]);
3922
+ const groupId = _optionalChain([child, 'access', _203 => _203.getAttribute, 'call', _204 => _204("id"), 'optionalAccess', _205 => _205.trim, 'call', _206 => _206()]);
3536
3923
  const newPath = groupId ? `${currentPath}${groupId}/groupUnits/` : currentPath;
3537
3924
  traverseUnitsV2(child, fileId, newPath, result);
3538
3925
  }
@@ -3568,12 +3955,12 @@ function indexUnitsV2(container, fileId, currentPath, index) {
3568
3955
  Array.from(container.children).forEach((child) => {
3569
3956
  const tagName = child.tagName;
3570
3957
  if (tagName === "unit") {
3571
- const unitId = _optionalChain([child, 'access', _197 => _197.getAttribute, 'call', _198 => _198("id"), 'optionalAccess', _199 => _199.trim, 'call', _200 => _200()]);
3958
+ const unitId = _optionalChain([child, 'access', _207 => _207.getAttribute, 'call', _208 => _208("id"), 'optionalAccess', _209 => _209.trim, 'call', _210 => _210()]);
3572
3959
  if (!unitId) return;
3573
3960
  const key = `resources/${fileId}/${currentPath}${unitId}/source`;
3574
3961
  index.set(key, child);
3575
3962
  } else if (tagName === "group") {
3576
- const groupId = _optionalChain([child, 'access', _201 => _201.getAttribute, 'call', _202 => _202("id"), 'optionalAccess', _203 => _203.trim, 'call', _204 => _204()]);
3963
+ const groupId = _optionalChain([child, 'access', _211 => _211.getAttribute, 'call', _212 => _212("id"), 'optionalAccess', _213 => _213.trim, 'call', _214 => _214()]);
3577
3964
  const newPath = groupId ? `${currentPath}${groupId}/groupUnits/` : currentPath;
3578
3965
  indexUnitsV2(child, fileId, newPath, index);
3579
3966
  }
@@ -3594,9 +3981,9 @@ function updateUnitV2(unit, value) {
3594
3981
  setTextContent(source, value);
3595
3982
  }
3596
3983
  function getTransUnitKey(transUnit) {
3597
- const resname = _optionalChain([transUnit, 'access', _205 => _205.getAttribute, 'call', _206 => _206("resname"), 'optionalAccess', _207 => _207.trim, 'call', _208 => _208()]);
3984
+ const resname = _optionalChain([transUnit, 'access', _215 => _215.getAttribute, 'call', _216 => _216("resname"), 'optionalAccess', _217 => _217.trim, 'call', _218 => _218()]);
3598
3985
  if (resname) return resname;
3599
- const id = _optionalChain([transUnit, 'access', _209 => _209.getAttribute, 'call', _210 => _210("id"), 'optionalAccess', _211 => _211.trim, 'call', _212 => _212()]);
3986
+ const id = _optionalChain([transUnit, 'access', _219 => _219.getAttribute, 'call', _220 => _220("id"), 'optionalAccess', _221 => _221.trim, 'call', _222 => _222()]);
3600
3987
  if (id) return id;
3601
3988
  const sourceElement = transUnit.querySelector("source");
3602
3989
  if (sourceElement) {
@@ -3653,7 +4040,7 @@ function formatXml(xml) {
3653
4040
  if (cdataNode) {
3654
4041
  return `${indent2}${openTag}<![CDATA[${cdataNode.nodeValue}]]></${tagName}>`;
3655
4042
  }
3656
- const textContent = _optionalChain([element, 'access', _213 => _213.textContent, 'optionalAccess', _214 => _214.trim, 'call', _215 => _215()]) || "";
4043
+ const textContent = _optionalChain([element, 'access', _223 => _223.textContent, 'optionalAccess', _224 => _224.trim, 'call', _225 => _225()]) || "";
3657
4044
  const hasOnlyText = element.childNodes.length === 1 && element.childNodes[0].nodeType === 3;
3658
4045
  if (hasOnlyText && textContent) {
3659
4046
  return `${indent2}${openTag}${textContent}</${tagName}>`;
@@ -3946,7 +4333,7 @@ function createDatoClient(params) {
3946
4333
  ids: !records.length ? void 0 : records.join(",")
3947
4334
  }
3948
4335
  }).catch(
3949
- (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _216 => _216.response, 'optionalAccess', _217 => _217.body, 'optionalAccess', _218 => _218.data, 'optionalAccess', _219 => _219[0]]) || error)
4336
+ (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _226 => _226.response, 'optionalAccess', _227 => _227.body, 'optionalAccess', _228 => _228.data, 'optionalAccess', _229 => _229[0]]) || error)
3950
4337
  );
3951
4338
  },
3952
4339
  findRecordsForModel: async (modelId, records) => {
@@ -3957,10 +4344,10 @@ function createDatoClient(params) {
3957
4344
  filter: {
3958
4345
  type: modelId,
3959
4346
  only_valid: "true",
3960
- ids: !_optionalChain([records, 'optionalAccess', _220 => _220.length]) ? void 0 : records.join(",")
4347
+ ids: !_optionalChain([records, 'optionalAccess', _230 => _230.length]) ? void 0 : records.join(",")
3961
4348
  }
3962
4349
  }).catch(
3963
- (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _221 => _221.response, 'optionalAccess', _222 => _222.body, 'optionalAccess', _223 => _223.data, 'optionalAccess', _224 => _224[0]]) || error)
4350
+ (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _231 => _231.response, 'optionalAccess', _232 => _232.body, 'optionalAccess', _233 => _233.data, 'optionalAccess', _234 => _234[0]]) || error)
3964
4351
  );
3965
4352
  return result;
3966
4353
  } catch (_error) {
@@ -3976,10 +4363,10 @@ function createDatoClient(params) {
3976
4363
  updateRecord: async (id, payload) => {
3977
4364
  try {
3978
4365
  await dato.items.update(id, payload).catch(
3979
- (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _225 => _225.response, 'optionalAccess', _226 => _226.body, 'optionalAccess', _227 => _227.data, 'optionalAccess', _228 => _228[0]]) || error)
4366
+ (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _235 => _235.response, 'optionalAccess', _236 => _236.body, 'optionalAccess', _237 => _237.data, 'optionalAccess', _238 => _238[0]]) || error)
3980
4367
  );
3981
4368
  } catch (_error) {
3982
- if (_optionalChain([_error, 'optionalAccess', _229 => _229.attributes, 'optionalAccess', _230 => _230.details, 'optionalAccess', _231 => _231.message])) {
4369
+ if (_optionalChain([_error, 'optionalAccess', _239 => _239.attributes, 'optionalAccess', _240 => _240.details, 'optionalAccess', _241 => _241.message])) {
3983
4370
  throw new Error(
3984
4371
  [
3985
4372
  `${_error.attributes.details.message}`,
@@ -4001,10 +4388,10 @@ function createDatoClient(params) {
4001
4388
  enableFieldLocalization: async (args) => {
4002
4389
  try {
4003
4390
  await dato.fields.update(`${args.modelId}::${args.fieldId}`, { localized: true }).catch(
4004
- (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _232 => _232.response, 'optionalAccess', _233 => _233.body, 'optionalAccess', _234 => _234.data, 'optionalAccess', _235 => _235[0]]) || error)
4391
+ (error) => Promise.reject(_optionalChain([error, 'optionalAccess', _242 => _242.response, 'optionalAccess', _243 => _243.body, 'optionalAccess', _244 => _244.data, 'optionalAccess', _245 => _245[0]]) || error)
4005
4392
  );
4006
4393
  } catch (_error) {
4007
- if (_optionalChain([_error, 'optionalAccess', _236 => _236.attributes, 'optionalAccess', _237 => _237.code]) === "NOT_FOUND") {
4394
+ if (_optionalChain([_error, 'optionalAccess', _246 => _246.attributes, 'optionalAccess', _247 => _247.code]) === "NOT_FOUND") {
4008
4395
  throw new Error(
4009
4396
  [
4010
4397
  `Field "${args.fieldId}" not found in model "${args.modelId}".`,
@@ -4012,7 +4399,7 @@ function createDatoClient(params) {
4012
4399
  ].join("\n\n")
4013
4400
  );
4014
4401
  }
4015
- if (_optionalChain([_error, 'optionalAccess', _238 => _238.attributes, 'optionalAccess', _239 => _239.details, 'optionalAccess', _240 => _240.message])) {
4402
+ if (_optionalChain([_error, 'optionalAccess', _248 => _248.attributes, 'optionalAccess', _249 => _249.details, 'optionalAccess', _250 => _250.message])) {
4016
4403
  throw new Error(
4017
4404
  [
4018
4405
  `${_error.attributes.details.message}`,
@@ -4090,7 +4477,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
4090
4477
  const records = await dato.findRecordsForModel(modelId);
4091
4478
  const recordChoices = createRecordChoices(
4092
4479
  records,
4093
- _optionalChain([config, 'access', _241 => _241.models, 'access', _242 => _242[modelId], 'optionalAccess', _243 => _243.records]) || [],
4480
+ _optionalChain([config, 'access', _251 => _251.models, 'access', _252 => _252[modelId], 'optionalAccess', _253 => _253.records]) || [],
4094
4481
  project
4095
4482
  );
4096
4483
  const selectedRecords = await promptRecordSelection(
@@ -4109,14 +4496,14 @@ function createDatoApiLoader(config, onConfigUpdate) {
4109
4496
  },
4110
4497
  async pull(locale, input2, initCtx) {
4111
4498
  const result = {};
4112
- for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _244 => _244.models]) || {})) {
4113
- let records = _optionalChain([initCtx, 'optionalAccess', _245 => _245.models, 'access', _246 => _246[modelId], 'access', _247 => _247.records]) || [];
4499
+ for (const modelId of _lodash2.default.keys(_optionalChain([initCtx, 'optionalAccess', _254 => _254.models]) || {})) {
4500
+ let records = _optionalChain([initCtx, 'optionalAccess', _255 => _255.models, 'access', _256 => _256[modelId], 'access', _257 => _257.records]) || [];
4114
4501
  const recordIds = records.map((record) => record.id);
4115
4502
  records = await dato.findRecords(recordIds);
4116
4503
  console.log(`Fetched ${records.length} records for model ${modelId}`);
4117
4504
  if (records.length > 0) {
4118
4505
  result[modelId] = {
4119
- fields: _optionalChain([initCtx, 'optionalAccess', _248 => _248.models, 'optionalAccess', _249 => _249[modelId], 'optionalAccess', _250 => _250.fields]) || [],
4506
+ fields: _optionalChain([initCtx, 'optionalAccess', _258 => _258.models, 'optionalAccess', _259 => _259[modelId], 'optionalAccess', _260 => _260.fields]) || [],
4120
4507
  records
4121
4508
  };
4122
4509
  }
@@ -4179,7 +4566,7 @@ function createRecordChoices(records, selectedIds = [], project) {
4179
4566
  return records.map((record) => ({
4180
4567
  name: `${record.id} - https://${project.internal_domain}/editor/item_types/${record.item_type.id}/items/${record.id}`,
4181
4568
  value: record.id,
4182
- checked: _optionalChain([selectedIds, 'optionalAccess', _251 => _251.includes, 'call', _252 => _252(record.id)])
4569
+ checked: _optionalChain([selectedIds, 'optionalAccess', _261 => _261.includes, 'call', _262 => _262(record.id)])
4183
4570
  }));
4184
4571
  }
4185
4572
  async function promptRecordSelection(modelName, choices) {
@@ -4498,7 +4885,7 @@ function createVttLoader() {
4498
4885
  if (!input2) {
4499
4886
  return "";
4500
4887
  }
4501
- const vtt = _optionalChain([_nodewebvtt2.default, 'access', _253 => _253.parse, 'call', _254 => _254(input2), 'optionalAccess', _255 => _255.cues]);
4888
+ const vtt = _optionalChain([_nodewebvtt2.default, 'access', _263 => _263.parse, 'call', _264 => _264(input2), 'optionalAccess', _265 => _265.cues]);
4502
4889
  if (Object.keys(vtt).length === 0) {
4503
4890
  return {};
4504
4891
  } else {
@@ -4544,6 +4931,15 @@ function variableExtractLoader(params) {
4544
4931
  const inputValues = _lodash2.default.omitBy(input2, _lodash2.default.isEmpty);
4545
4932
  for (const [key, value] of Object.entries(inputValues)) {
4546
4933
  const originalValue = originalInput[key];
4934
+ if (isICUPluralObject(originalValue)) {
4935
+ const icuValue = isICUPluralObject(value) ? { icu: value.icu } : value;
4936
+ result[key] = {
4937
+ value: icuValue,
4938
+ variables: []
4939
+ // Metadata stored separately, not in variables
4940
+ };
4941
+ continue;
4942
+ }
4547
4943
  const matches = originalValue.match(specifierPattern) || [];
4548
4944
  result[key] = result[key] || {
4549
4945
  value,
@@ -4552,7 +4948,7 @@ function variableExtractLoader(params) {
4552
4948
  for (let i = 0; i < matches.length; i++) {
4553
4949
  const match2 = matches[i];
4554
4950
  const currentValue = result[key].value;
4555
- const newValue = _optionalChain([currentValue, 'optionalAccess', _256 => _256.replace, 'call', _257 => _257(match2, `{variable:${i}}`)]);
4951
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _266 => _266.replace, 'call', _267 => _267(match2, `{variable:${i}}`)]);
4556
4952
  result[key].value = newValue;
4557
4953
  result[key].variables[i] = match2;
4558
4954
  }
@@ -4563,11 +4959,21 @@ function variableExtractLoader(params) {
4563
4959
  const result = {};
4564
4960
  for (const [key, valueObj] of Object.entries(data)) {
4565
4961
  result[key] = valueObj.value;
4962
+ const resultValue = result[key];
4963
+ if (isICUPluralObject(resultValue)) {
4964
+ const originalValue = _optionalChain([originalInput, 'optionalAccess', _268 => _268[key]]);
4965
+ if (isICUPluralObject(originalValue) && originalValue._meta) {
4966
+ resultValue._meta = originalValue._meta;
4967
+ resultValue[Symbol.for("@lingo.dev/icu-plural-object")] = true;
4968
+ }
4969
+ }
4566
4970
  for (let i = 0; i < valueObj.variables.length; i++) {
4567
4971
  const variable = valueObj.variables[i];
4568
4972
  const currentValue = result[key];
4569
- const newValue = _optionalChain([currentValue, 'optionalAccess', _258 => _258.replace, 'call', _259 => _259(`{variable:${i}}`, variable)]);
4570
- result[key] = newValue;
4973
+ if (typeof currentValue === "string") {
4974
+ const newValue = _optionalChain([currentValue, 'optionalAccess', _269 => _269.replace, 'call', _270 => _270(`{variable:${i}}`, variable)]);
4975
+ result[key] = newValue;
4976
+ }
4571
4977
  }
4572
4978
  }
4573
4979
  return result;
@@ -4766,7 +5172,7 @@ function createVueJsonLoader() {
4766
5172
  return createLoader({
4767
5173
  pull: async (locale, input2, ctx) => {
4768
5174
  const parsed = parseVueFile(input2);
4769
- return _nullishCoalesce(_optionalChain([parsed, 'optionalAccess', _260 => _260.i18n, 'optionalAccess', _261 => _261[locale]]), () => ( {}));
5175
+ return _nullishCoalesce(_optionalChain([parsed, 'optionalAccess', _271 => _271.i18n, 'optionalAccess', _272 => _272[locale]]), () => ( {}));
4770
5176
  },
4771
5177
  push: async (locale, data, originalInput) => {
4772
5178
  const parsed = parseVueFile(_nullishCoalesce(originalInput, () => ( "")));
@@ -4951,7 +5357,7 @@ function updateStringsInObjectExpression(objectExpression, data) {
4951
5357
  objectExpression.properties.forEach((prop) => {
4952
5358
  if (!t.isObjectProperty(prop)) return;
4953
5359
  const key = getPropertyKey(prop);
4954
- const incomingVal = _optionalChain([data, 'optionalAccess', _262 => _262[key]]);
5360
+ const incomingVal = _optionalChain([data, 'optionalAccess', _273 => _273[key]]);
4955
5361
  if (incomingVal === void 0) {
4956
5362
  return;
4957
5363
  }
@@ -4987,7 +5393,7 @@ function updateStringsInArrayExpression(arrayExpression, incoming) {
4987
5393
  let modified = false;
4988
5394
  arrayExpression.elements.forEach((element, index) => {
4989
5395
  if (!element) return;
4990
- const incomingVal = _optionalChain([incoming, 'optionalAccess', _263 => _263[index]]);
5396
+ const incomingVal = _optionalChain([incoming, 'optionalAccess', _274 => _274[index]]);
4991
5397
  if (incomingVal === void 0) return;
4992
5398
  if (t.isStringLiteral(element) && typeof incomingVal === "string") {
4993
5399
  if (element.value !== incomingVal) {
@@ -5478,7 +5884,7 @@ var AST = class _AST {
5478
5884
  const ret = this.type === null ? this.#parts.slice().map((p) => typeof p === "string" ? p : p.toJSON()) : [this.type, ...this.#parts.map((p) => p.toJSON())];
5479
5885
  if (this.isStart() && !this.type)
5480
5886
  ret.unshift([]);
5481
- if (this.isEnd() && (this === this.#root || this.#root.#filledNegs && _optionalChain([this, 'access', _264 => _264.#parent, 'optionalAccess', _265 => _265.type]) === "!")) {
5887
+ if (this.isEnd() && (this === this.#root || this.#root.#filledNegs && _optionalChain([this, 'access', _275 => _275.#parent, 'optionalAccess', _276 => _276.type]) === "!")) {
5482
5888
  ret.push({});
5483
5889
  }
5484
5890
  return ret;
@@ -5486,7 +5892,7 @@ var AST = class _AST {
5486
5892
  isStart() {
5487
5893
  if (this.#root === this)
5488
5894
  return true;
5489
- if (!_optionalChain([this, 'access', _266 => _266.#parent, 'optionalAccess', _267 => _267.isStart, 'call', _268 => _268()]))
5895
+ if (!_optionalChain([this, 'access', _277 => _277.#parent, 'optionalAccess', _278 => _278.isStart, 'call', _279 => _279()]))
5490
5896
  return false;
5491
5897
  if (this.#parentIndex === 0)
5492
5898
  return true;
@@ -5502,12 +5908,12 @@ var AST = class _AST {
5502
5908
  isEnd() {
5503
5909
  if (this.#root === this)
5504
5910
  return true;
5505
- if (_optionalChain([this, 'access', _269 => _269.#parent, 'optionalAccess', _270 => _270.type]) === "!")
5911
+ if (_optionalChain([this, 'access', _280 => _280.#parent, 'optionalAccess', _281 => _281.type]) === "!")
5506
5912
  return true;
5507
- if (!_optionalChain([this, 'access', _271 => _271.#parent, 'optionalAccess', _272 => _272.isEnd, 'call', _273 => _273()]))
5913
+ if (!_optionalChain([this, 'access', _282 => _282.#parent, 'optionalAccess', _283 => _283.isEnd, 'call', _284 => _284()]))
5508
5914
  return false;
5509
5915
  if (!this.type)
5510
- return _optionalChain([this, 'access', _274 => _274.#parent, 'optionalAccess', _275 => _275.isEnd, 'call', _276 => _276()]);
5916
+ return _optionalChain([this, 'access', _285 => _285.#parent, 'optionalAccess', _286 => _286.isEnd, 'call', _287 => _287()]);
5511
5917
  const pl = this.#parent ? this.#parent.#parts.length : 0;
5512
5918
  return this.#parentIndex === pl - 1;
5513
5919
  }
@@ -5752,7 +6158,7 @@ var AST = class _AST {
5752
6158
  }
5753
6159
  }
5754
6160
  let end = "";
5755
- if (this.isEnd() && this.#root.#filledNegs && _optionalChain([this, 'access', _277 => _277.#parent, 'optionalAccess', _278 => _278.type]) === "!") {
6161
+ if (this.isEnd() && this.#root.#filledNegs && _optionalChain([this, 'access', _288 => _288.#parent, 'optionalAccess', _289 => _289.type]) === "!") {
5756
6162
  end = "(?:$|\\/)";
5757
6163
  }
5758
6164
  const final2 = start2 + src + end;
@@ -6842,7 +7248,7 @@ function createMdxSectionsSplit2Loader() {
6842
7248
  const content = _lodash2.default.chain(data.sections).values().join("\n\n").value();
6843
7249
  const result = {
6844
7250
  frontmatter: data.frontmatter,
6845
- codePlaceholders: _optionalChain([pullInput, 'optionalAccess', _279 => _279.codePlaceholders]) || {},
7251
+ codePlaceholders: _optionalChain([pullInput, 'optionalAccess', _290 => _290.codePlaceholders]) || {},
6846
7252
  content
6847
7253
  };
6848
7254
  return result;
@@ -6916,11 +7322,10 @@ function createIgnoredKeysLoader(ignoredKeys) {
6916
7322
  return result;
6917
7323
  },
6918
7324
  push: async (locale, data, originalInput, originalLocale, pullInput) => {
6919
- const ignoredSubObject = _lodash2.default.pickBy(
6920
- pullInput,
7325
+ const result = _lodash2.default.omitBy(
7326
+ data,
6921
7327
  (value, key) => matchesKeyPattern(key, ignoredKeys)
6922
7328
  );
6923
- const result = _lodash2.default.merge({}, data, ignoredSubObject);
6924
7329
  return result;
6925
7330
  }
6926
7331
  });
@@ -7251,6 +7656,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7251
7656
  createFlatLoader(),
7252
7657
  createInjectLocaleLoader(options.injectLocale),
7253
7658
  createLockedKeysLoader(lockedKeys || []),
7659
+ createIgnoredKeysLoader(ignoredKeys || []),
7254
7660
  createSyncLoader(),
7255
7661
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7256
7662
  );
@@ -7262,6 +7668,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7262
7668
  createFlatLoader(),
7263
7669
  createInjectLocaleLoader(options.injectLocale),
7264
7670
  createLockedKeysLoader(lockedKeys || []),
7671
+ createIgnoredKeysLoader(ignoredKeys || []),
7265
7672
  createSyncLoader(),
7266
7673
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7267
7674
  );
@@ -7273,6 +7680,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7273
7680
  createFlatLoader(),
7274
7681
  createInjectLocaleLoader(options.injectLocale),
7275
7682
  createLockedKeysLoader(lockedKeys || []),
7683
+ createIgnoredKeysLoader(ignoredKeys || []),
7276
7684
  createSyncLoader(),
7277
7685
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7278
7686
  );
@@ -7305,6 +7713,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7305
7713
  createFlatLoader(),
7306
7714
  createEnsureKeyOrderLoader(),
7307
7715
  createLockedKeysLoader(lockedKeys || []),
7716
+ createIgnoredKeysLoader(ignoredKeys || []),
7308
7717
  createSyncLoader(),
7309
7718
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7310
7719
  );
@@ -7350,6 +7759,21 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7350
7759
  createFlatLoader(),
7351
7760
  createEnsureKeyOrderLoader(),
7352
7761
  createLockedKeysLoader(lockedKeys || []),
7762
+ createIgnoredKeysLoader(ignoredKeys || []),
7763
+ createSyncLoader(),
7764
+ createVariableLoader({ type: "ieee" }),
7765
+ createUnlocalizableLoader(options.returnUnlocalizedKeys)
7766
+ );
7767
+ case "xcode-xcstrings-v2":
7768
+ return composeLoaders(
7769
+ createTextFileLoader(bucketPathPattern),
7770
+ createPlutilJsonTextLoader(),
7771
+ createJsonLoader(),
7772
+ createXcodeXcstringsLoader(options.defaultLocale),
7773
+ createXcodeXcstringsV2Loader(options.defaultLocale),
7774
+ createFlatLoader({ shouldPreserveObject: isICUPluralObject }),
7775
+ createEnsureKeyOrderLoader(),
7776
+ createLockedKeysLoader(lockedKeys || []),
7353
7777
  createSyncLoader(),
7354
7778
  createVariableLoader({ type: "ieee" }),
7355
7779
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
@@ -7362,6 +7786,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7362
7786
  createFlatLoader(),
7363
7787
  createEnsureKeyOrderLoader(),
7364
7788
  createLockedKeysLoader(lockedKeys || []),
7789
+ createIgnoredKeysLoader(ignoredKeys || []),
7365
7790
  createSyncLoader(),
7366
7791
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7367
7792
  );
@@ -7478,6 +7903,7 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
7478
7903
  createFlatLoader(),
7479
7904
  createInjectLocaleLoader(options.injectLocale),
7480
7905
  createLockedKeysLoader(lockedKeys || []),
7906
+ createIgnoredKeysLoader(ignoredKeys || []),
7481
7907
  createSyncLoader(),
7482
7908
  createUnlocalizableLoader(options.returnUnlocalizedKeys)
7483
7909
  );
@@ -7855,7 +8281,7 @@ function createBasicTranslator(model, systemPrompt, settings = {}) {
7855
8281
  ]
7856
8282
  });
7857
8283
  const result = JSON.parse(response.text);
7858
- return _optionalChain([result, 'optionalAccess', _280 => _280.data]) || {};
8284
+ return _optionalChain([result, 'optionalAccess', _291 => _291.data]) || {};
7859
8285
  }
7860
8286
  }
7861
8287
  function extractPayloadChunks(payload) {
@@ -7938,7 +8364,7 @@ function getPureModelProvider(provider) {
7938
8364
 
7939
8365
  ${_chalk2.default.hex(colors.blue)("Docs: https://lingo.dev/go/docs")}
7940
8366
  `;
7941
- switch (_optionalChain([provider, 'optionalAccess', _281 => _281.id])) {
8367
+ switch (_optionalChain([provider, 'optionalAccess', _292 => _292.id])) {
7942
8368
  case "openai": {
7943
8369
  if (!process.env.OPENAI_API_KEY) {
7944
8370
  throw new Error(
@@ -7996,7 +8422,7 @@ function getPureModelProvider(provider) {
7996
8422
  })(provider.model);
7997
8423
  }
7998
8424
  default: {
7999
- throw new Error(createUnsupportedProviderErrorMessage(_optionalChain([provider, 'optionalAccess', _282 => _282.id])));
8425
+ throw new Error(createUnsupportedProviderErrorMessage(_optionalChain([provider, 'optionalAccess', _293 => _293.id])));
8000
8426
  }
8001
8427
  }
8002
8428
  }
@@ -8281,7 +8707,7 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
8281
8707
  validateParams(i18nConfig, flags);
8282
8708
  ora.succeed("Localization configuration is valid");
8283
8709
  ora.start("Connecting to Lingo.dev Localization Engine...");
8284
- const isByokMode = !!_optionalChain([i18nConfig, 'optionalAccess', _283 => _283.provider]);
8710
+ const isByokMode = !!_optionalChain([i18nConfig, 'optionalAccess', _294 => _294.provider]);
8285
8711
  if (isByokMode) {
8286
8712
  authId = null;
8287
8713
  ora.succeed("Using external provider (BYOK mode)");
@@ -8295,16 +8721,16 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
8295
8721
  flags
8296
8722
  });
8297
8723
  let buckets = getBuckets(i18nConfig);
8298
- if (_optionalChain([flags, 'access', _284 => _284.bucket, 'optionalAccess', _285 => _285.length])) {
8724
+ if (_optionalChain([flags, 'access', _295 => _295.bucket, 'optionalAccess', _296 => _296.length])) {
8299
8725
  buckets = buckets.filter(
8300
8726
  (bucket) => flags.bucket.includes(bucket.type)
8301
8727
  );
8302
8728
  }
8303
8729
  ora.succeed("Buckets retrieved");
8304
- if (_optionalChain([flags, 'access', _286 => _286.file, 'optionalAccess', _287 => _287.length])) {
8730
+ if (_optionalChain([flags, 'access', _297 => _297.file, 'optionalAccess', _298 => _298.length])) {
8305
8731
  buckets = buckets.map((bucket) => {
8306
8732
  const paths = bucket.paths.filter(
8307
- (path19) => flags.file.find((file) => _optionalChain([path19, 'access', _288 => _288.pathPattern, 'optionalAccess', _289 => _289.includes, 'call', _290 => _290(file)]))
8733
+ (path19) => flags.file.find((file) => _optionalChain([path19, 'access', _299 => _299.pathPattern, 'optionalAccess', _300 => _300.includes, 'call', _301 => _301(file)]))
8308
8734
  );
8309
8735
  return { ...bucket, paths };
8310
8736
  }).filter((bucket) => bucket.paths.length > 0);
@@ -8325,7 +8751,7 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
8325
8751
  });
8326
8752
  }
8327
8753
  }
8328
- const targetLocales = _optionalChain([flags, 'access', _291 => _291.locale, 'optionalAccess', _292 => _292.length]) ? flags.locale : i18nConfig.locale.targets;
8754
+ const targetLocales = _optionalChain([flags, 'access', _302 => _302.locale, 'optionalAccess', _303 => _303.length]) ? flags.locale : i18nConfig.locale.targets;
8329
8755
  ora.start("Setting up localization cache...");
8330
8756
  const checkLockfileProcessor = createDeltaProcessor("");
8331
8757
  const lockfileExists = await checkLockfileProcessor.checkIfLockExists();
@@ -8602,7 +9028,7 @@ var i18n_default = new (0, _interactivecommander.Command)().command("i18n").desc
8602
9028
  }
8603
9029
  const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
8604
9030
  const checksums = await deltaProcessor.createChecksums(sourceData);
8605
- if (!_optionalChain([flags, 'access', _293 => _293.locale, 'optionalAccess', _294 => _294.length])) {
9031
+ if (!_optionalChain([flags, 'access', _304 => _304.locale, 'optionalAccess', _305 => _305.length])) {
8606
9032
  await deltaProcessor.saveChecksums(checksums);
8607
9033
  }
8608
9034
  }
@@ -8726,12 +9152,12 @@ function validateParams(i18nConfig, flags) {
8726
9152
  message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
8727
9153
  docUrl: "bucketNotFound"
8728
9154
  });
8729
- } else if (_optionalChain([flags, 'access', _295 => _295.locale, 'optionalAccess', _296 => _296.some, 'call', _297 => _297((locale) => !i18nConfig.locale.targets.includes(locale))])) {
9155
+ } else if (_optionalChain([flags, 'access', _306 => _306.locale, 'optionalAccess', _307 => _307.some, 'call', _308 => _308((locale) => !i18nConfig.locale.targets.includes(locale))])) {
8730
9156
  throw new ValidationError({
8731
9157
  message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
8732
9158
  docUrl: "localeTargetNotFound"
8733
9159
  });
8734
- } else if (_optionalChain([flags, 'access', _298 => _298.bucket, 'optionalAccess', _299 => _299.some, 'call', _300 => _300(
9160
+ } else if (_optionalChain([flags, 'access', _309 => _309.bucket, 'optionalAccess', _310 => _310.some, 'call', _311 => _311(
8735
9161
  (bucket) => !i18nConfig.buckets[bucket]
8736
9162
  )])) {
8737
9163
  throw new ValidationError({
@@ -9257,7 +9683,7 @@ function createLingoDotDevLocalizer(explicitApiKey) {
9257
9683
  const response = await engine.whoami();
9258
9684
  return {
9259
9685
  authenticated: !!response,
9260
- username: _optionalChain([response, 'optionalAccess', _301 => _301.email])
9686
+ username: _optionalChain([response, 'optionalAccess', _312 => _312.email])
9261
9687
  };
9262
9688
  } catch (error) {
9263
9689
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -9373,7 +9799,7 @@ function createExplicitLocalizer(provider) {
9373
9799
  }
9374
9800
  function createAiSdkLocalizer(params) {
9375
9801
  const skipAuth = params.skipAuth === true;
9376
- const apiKey = process.env[_nullishCoalesce(_optionalChain([params, 'optionalAccess', _302 => _302.apiKeyName]), () => ( ""))];
9802
+ const apiKey = process.env[_nullishCoalesce(_optionalChain([params, 'optionalAccess', _313 => _313.apiKeyName]), () => ( ""))];
9377
9803
  if (!skipAuth && !apiKey || !params.apiKeyName) {
9378
9804
  throw new Error(
9379
9805
  _dedent2.default`
@@ -9507,8 +9933,8 @@ async function setup(input2) {
9507
9933
  throw new Error(
9508
9934
  "No buckets found in i18n.json. Please add at least one bucket containing i18n content."
9509
9935
  );
9510
- } else if (_optionalChain([ctx, 'access', _303 => _303.flags, 'access', _304 => _304.bucket, 'optionalAccess', _305 => _305.some, 'call', _306 => _306(
9511
- (bucket) => !_optionalChain([ctx, 'access', _307 => _307.config, 'optionalAccess', _308 => _308.buckets, 'access', _309 => _309[bucket]])
9936
+ } else if (_optionalChain([ctx, 'access', _314 => _314.flags, 'access', _315 => _315.bucket, 'optionalAccess', _316 => _316.some, 'call', _317 => _317(
9937
+ (bucket) => !_optionalChain([ctx, 'access', _318 => _318.config, 'optionalAccess', _319 => _319.buckets, 'access', _320 => _320[bucket]])
9512
9938
  )])) {
9513
9939
  throw new Error(
9514
9940
  `One or more specified buckets do not exist in i18n.json. Please add them to the list first and try again.`
@@ -9521,7 +9947,7 @@ async function setup(input2) {
9521
9947
  title: "Selecting localization provider",
9522
9948
  task: async (ctx, task) => {
9523
9949
  ctx.localizer = createLocalizer(
9524
- _optionalChain([ctx, 'access', _310 => _310.config, 'optionalAccess', _311 => _311.provider]),
9950
+ _optionalChain([ctx, 'access', _321 => _321.config, 'optionalAccess', _322 => _322.provider]),
9525
9951
  ctx.flags.apiKey
9526
9952
  );
9527
9953
  if (!ctx.localizer) {
@@ -9534,7 +9960,7 @@ async function setup(input2) {
9534
9960
  },
9535
9961
  {
9536
9962
  title: "Checking authentication",
9537
- enabled: (ctx) => _optionalChain([ctx, 'access', _312 => _312.localizer, 'optionalAccess', _313 => _313.id]) === "Lingo.dev",
9963
+ enabled: (ctx) => _optionalChain([ctx, 'access', _323 => _323.localizer, 'optionalAccess', _324 => _324.id]) === "Lingo.dev",
9538
9964
  task: async (ctx, task) => {
9539
9965
  const authStatus = await ctx.localizer.checkAuth();
9540
9966
  if (!authStatus.authenticated) {
@@ -9547,7 +9973,7 @@ async function setup(input2) {
9547
9973
  },
9548
9974
  {
9549
9975
  title: "Validating configuration",
9550
- enabled: (ctx) => _optionalChain([ctx, 'access', _314 => _314.localizer, 'optionalAccess', _315 => _315.id]) !== "Lingo.dev",
9976
+ enabled: (ctx) => _optionalChain([ctx, 'access', _325 => _325.localizer, 'optionalAccess', _326 => _326.id]) !== "Lingo.dev",
9551
9977
  task: async (ctx, task) => {
9552
9978
  const validationStatus = await ctx.localizer.validateSettings();
9553
9979
  if (!validationStatus.valid) {
@@ -9690,6 +10116,7 @@ async function plan(input2) {
9690
10116
  injectLocale: bucket.injectLocale || [],
9691
10117
  lockedKeys: bucket.lockedKeys || [],
9692
10118
  lockedPatterns: bucket.lockedPatterns || [],
10119
+ ignoredKeys: bucket.ignoredKeys || [],
9693
10120
  onlyKeys: input2.flags.key || [],
9694
10121
  formatter: input2.config.formatter
9695
10122
  });
@@ -9826,7 +10253,8 @@ function createLoaderForTask(assignedTask) {
9826
10253
  formatter: assignedTask.formatter
9827
10254
  },
9828
10255
  assignedTask.lockedKeys,
9829
- assignedTask.lockedPatterns
10256
+ assignedTask.lockedPatterns,
10257
+ assignedTask.ignoredKeys
9830
10258
  );
9831
10259
  bucketLoader.setDefaultLocale(assignedTask.sourceLocale);
9832
10260
  return bucketLoader;
@@ -9862,7 +10290,7 @@ function createWorkerTask(args) {
9862
10290
  const processableData = _lodash2.default.chain(sourceData).entries().filter(
9863
10291
  ([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!args.ctx.flags.force
9864
10292
  ).filter(
9865
- ([key]) => !assignedTask.onlyKeys.length || _optionalChain([assignedTask, 'access', _316 => _316.onlyKeys, 'optionalAccess', _317 => _317.some, 'call', _318 => _318(
10293
+ ([key]) => !assignedTask.onlyKeys.length || _optionalChain([assignedTask, 'access', _327 => _327.onlyKeys, 'optionalAccess', _328 => _328.some, 'call', _329 => _329(
9866
10294
  (pattern) => minimatch(key, pattern)
9867
10295
  )])
9868
10296
  ).fromPairs().value();
@@ -9930,7 +10358,7 @@ function createWorkerTask(args) {
9930
10358
  finalRenamedTargetData
9931
10359
  );
9932
10360
  const checksums = await deltaProcessor.createChecksums(sourceData);
9933
- if (!_optionalChain([args, 'access', _319 => _319.ctx, 'access', _320 => _320.flags, 'access', _321 => _321.targetLocale, 'optionalAccess', _322 => _322.length])) {
10361
+ if (!_optionalChain([args, 'access', _330 => _330.ctx, 'access', _331 => _331.flags, 'access', _332 => _332.targetLocale, 'optionalAccess', _333 => _333.length])) {
9934
10362
  await deltaProcessor.saveChecksums(checksums);
9935
10363
  }
9936
10364
  });
@@ -10135,10 +10563,10 @@ var flagsSchema2 = _zod.z.object({
10135
10563
  async function frozen(input2) {
10136
10564
  console.log(_chalk2.default.hex(colors.orange)("[Frozen]"));
10137
10565
  let buckets = getBuckets(input2.config);
10138
- if (_optionalChain([input2, 'access', _323 => _323.flags, 'access', _324 => _324.bucket, 'optionalAccess', _325 => _325.length])) {
10566
+ if (_optionalChain([input2, 'access', _334 => _334.flags, 'access', _335 => _335.bucket, 'optionalAccess', _336 => _336.length])) {
10139
10567
  buckets = buckets.filter((b) => input2.flags.bucket.includes(b.type));
10140
10568
  }
10141
- if (_optionalChain([input2, 'access', _326 => _326.flags, 'access', _327 => _327.file, 'optionalAccess', _328 => _328.length])) {
10569
+ if (_optionalChain([input2, 'access', _337 => _337.flags, 'access', _338 => _338.file, 'optionalAccess', _339 => _339.length])) {
10142
10570
  buckets = buckets.map((bucket) => {
10143
10571
  const paths = bucket.paths.filter(
10144
10572
  (p) => input2.flags.file.some(
@@ -10208,7 +10636,9 @@ async function frozen(input2) {
10208
10636
  returnUnlocalizedKeys: true,
10209
10637
  injectLocale: bucket.injectLocale
10210
10638
  },
10211
- bucket.lockedKeys
10639
+ bucket.lockedKeys,
10640
+ bucket.lockedPatterns,
10641
+ bucket.ignoredKeys
10212
10642
  );
10213
10643
  loader.setDefaultLocale(resolvedSourceLocale);
10214
10644
  await loader.init();
@@ -10273,13 +10703,13 @@ async function frozen(input2) {
10273
10703
 
10274
10704
  // src/cli/cmd/run/_utils.ts
10275
10705
  async function determineAuthId(ctx) {
10276
- const isByokMode = !!_optionalChain([ctx, 'access', _329 => _329.config, 'optionalAccess', _330 => _330.provider]);
10706
+ const isByokMode = !!_optionalChain([ctx, 'access', _340 => _340.config, 'optionalAccess', _341 => _341.provider]);
10277
10707
  if (isByokMode) {
10278
10708
  return null;
10279
10709
  } else {
10280
10710
  try {
10281
- const authStatus = await _optionalChain([ctx, 'access', _331 => _331.localizer, 'optionalAccess', _332 => _332.checkAuth, 'call', _333 => _333()]);
10282
- return _optionalChain([authStatus, 'optionalAccess', _334 => _334.username]) || null;
10711
+ const authStatus = await _optionalChain([ctx, 'access', _342 => _342.localizer, 'optionalAccess', _343 => _343.checkAuth, 'call', _344 => _344()]);
10712
+ return _optionalChain([authStatus, 'optionalAccess', _345 => _345.username]) || null;
10283
10713
  } catch (e3) {
10284
10714
  return null;
10285
10715
  }
@@ -10476,7 +10906,7 @@ var InBranchFlow = class extends IntegrationFlow {
10476
10906
  _child_process.execSync.call(void 0, `git config --global safe.directory ${process.cwd()}`);
10477
10907
  _child_process.execSync.call(void 0, `git config user.name "${gitConfig.userName}"`);
10478
10908
  _child_process.execSync.call(void 0, `git config user.email "${gitConfig.userEmail}"`);
10479
- _optionalChain([this, 'access', _335 => _335.platformKit, 'optionalAccess', _336 => _336.gitConfig, 'call', _337 => _337()]);
10909
+ _optionalChain([this, 'access', _346 => _346.platformKit, 'optionalAccess', _347 => _347.gitConfig, 'call', _348 => _348()]);
10480
10910
  _child_process.execSync.call(void 0, `git fetch origin ${baseBranchName}`, { stdio: "inherit" });
10481
10911
  _child_process.execSync.call(void 0, `git checkout ${baseBranchName} --`, { stdio: "inherit" });
10482
10912
  if (!processOwnCommits) {
@@ -10508,7 +10938,7 @@ var InBranchFlow = class extends IntegrationFlow {
10508
10938
  // src/cli/cmd/ci/flows/pull-request.ts
10509
10939
  var PullRequestFlow = class extends InBranchFlow {
10510
10940
  async preRun() {
10511
- const canContinue = await _optionalChain([super.preRun.bind(this), 'optionalCall', _338 => _338()]);
10941
+ const canContinue = await _optionalChain([super.preRun.bind(this), 'optionalCall', _349 => _349()]);
10512
10942
  if (!canContinue) {
10513
10943
  return false;
10514
10944
  }
@@ -10771,10 +11201,10 @@ var BitbucketPlatformKit = class extends PlatformKit {
10771
11201
  repo_slug: this.platformConfig.repositoryName,
10772
11202
  state: "OPEN"
10773
11203
  }).then(({ data: { values } }) => {
10774
- return _optionalChain([values, 'optionalAccess', _339 => _339.find, 'call', _340 => _340(
10775
- ({ source, destination }) => _optionalChain([source, 'optionalAccess', _341 => _341.branch, 'optionalAccess', _342 => _342.name]) === branch && _optionalChain([destination, 'optionalAccess', _343 => _343.branch, 'optionalAccess', _344 => _344.name]) === this.platformConfig.baseBranchName
11204
+ return _optionalChain([values, 'optionalAccess', _350 => _350.find, 'call', _351 => _351(
11205
+ ({ source, destination }) => _optionalChain([source, 'optionalAccess', _352 => _352.branch, 'optionalAccess', _353 => _353.name]) === branch && _optionalChain([destination, 'optionalAccess', _354 => _354.branch, 'optionalAccess', _355 => _355.name]) === this.platformConfig.baseBranchName
10776
11206
  )]);
10777
- }).then((pr) => _optionalChain([pr, 'optionalAccess', _345 => _345.id]));
11207
+ }).then((pr) => _optionalChain([pr, 'optionalAccess', _356 => _356.id]));
10778
11208
  }
10779
11209
  async closePullRequest({ pullRequestNumber }) {
10780
11210
  await this.bb.repositories.declinePullRequest({
@@ -10870,7 +11300,7 @@ var GitHubPlatformKit = class extends PlatformKit {
10870
11300
  repo: this.platformConfig.repositoryName,
10871
11301
  base: this.platformConfig.baseBranchName,
10872
11302
  state: "open"
10873
- }).then(({ data }) => data[0]).then((pr) => _optionalChain([pr, 'optionalAccess', _346 => _346.number]));
11303
+ }).then(({ data }) => data[0]).then((pr) => _optionalChain([pr, 'optionalAccess', _357 => _357.number]));
10874
11304
  }
10875
11305
  async closePullRequest({ pullRequestNumber }) {
10876
11306
  await this.octokit.rest.pulls.update({
@@ -10997,7 +11427,7 @@ var GitlabPlatformKit = class extends PlatformKit {
10997
11427
  sourceBranch: branch,
10998
11428
  state: "opened"
10999
11429
  });
11000
- return _optionalChain([mergeRequests, 'access', _347 => _347[0], 'optionalAccess', _348 => _348.iid]);
11430
+ return _optionalChain([mergeRequests, 'access', _358 => _358[0], 'optionalAccess', _359 => _359.iid]);
11001
11431
  }
11002
11432
  async closePullRequest({
11003
11433
  pullRequestNumber
@@ -11103,7 +11533,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
11103
11533
  }
11104
11534
  const env = {
11105
11535
  LINGODOTDEV_API_KEY: settings.auth.apiKey,
11106
- LINGODOTDEV_PULL_REQUEST: _optionalChain([options, 'access', _349 => _349.pullRequest, 'optionalAccess', _350 => _350.toString, 'call', _351 => _351()]) || "false",
11536
+ LINGODOTDEV_PULL_REQUEST: _optionalChain([options, 'access', _360 => _360.pullRequest, 'optionalAccess', _361 => _361.toString, 'call', _362 => _362()]) || "false",
11107
11537
  ...options.commitMessage && {
11108
11538
  LINGODOTDEV_COMMIT_MESSAGE: options.commitMessage
11109
11539
  },
@@ -11123,7 +11553,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
11123
11553
  const { isPullRequestMode } = platformKit.config;
11124
11554
  ora.info(`Pull request mode: ${isPullRequestMode ? "on" : "off"}`);
11125
11555
  const flow = isPullRequestMode ? new PullRequestFlow(ora, platformKit) : new InBranchFlow(ora, platformKit);
11126
- const canRun = await _optionalChain([flow, 'access', _352 => _352.preRun, 'optionalCall', _353 => _353()]);
11556
+ const canRun = await _optionalChain([flow, 'access', _363 => _363.preRun, 'optionalCall', _364 => _364()]);
11127
11557
  if (canRun === false) {
11128
11558
  return;
11129
11559
  }
@@ -11133,7 +11563,7 @@ var ci_default = new (0, _interactivecommander.Command)().command("ci").descript
11133
11563
  if (!hasChanges) {
11134
11564
  return;
11135
11565
  }
11136
- await _optionalChain([flow, 'access', _354 => _354.postRun, 'optionalCall', _355 => _355()]);
11566
+ await _optionalChain([flow, 'access', _365 => _365.postRun, 'optionalCall', _366 => _366()]);
11137
11567
  });
11138
11568
  function parseBooleanArg(val) {
11139
11569
  if (val === true) return true;
@@ -11170,8 +11600,8 @@ function exitGracefully(elapsedMs = 0) {
11170
11600
  }
11171
11601
  }
11172
11602
  function checkForPendingOperations() {
11173
- const activeHandles = _optionalChain([process, 'access', _356 => _356._getActiveHandles, 'optionalCall', _357 => _357()]) || [];
11174
- const activeRequests = _optionalChain([process, 'access', _358 => _358._getActiveRequests, 'optionalCall', _359 => _359()]) || [];
11603
+ const activeHandles = _optionalChain([process, 'access', _367 => _367._getActiveHandles, 'optionalCall', _368 => _368()]) || [];
11604
+ const activeRequests = _optionalChain([process, 'access', _369 => _369._getActiveRequests, 'optionalCall', _370 => _370()]) || [];
11175
11605
  const nonStandardHandles = activeHandles.filter((handle) => {
11176
11606
  if (handle === process.stdin || handle === process.stdout || handle === process.stderr) {
11177
11607
  return false;
@@ -11240,17 +11670,17 @@ var status_default = new (0, _interactivecommander.Command)().command("status").
11240
11670
  flags
11241
11671
  });
11242
11672
  let buckets = getBuckets(i18nConfig);
11243
- if (_optionalChain([flags, 'access', _360 => _360.bucket, 'optionalAccess', _361 => _361.length])) {
11673
+ if (_optionalChain([flags, 'access', _371 => _371.bucket, 'optionalAccess', _372 => _372.length])) {
11244
11674
  buckets = buckets.filter(
11245
11675
  (bucket) => flags.bucket.includes(bucket.type)
11246
11676
  );
11247
11677
  }
11248
11678
  ora.succeed("Buckets retrieved");
11249
- if (_optionalChain([flags, 'access', _362 => _362.file, 'optionalAccess', _363 => _363.length])) {
11679
+ if (_optionalChain([flags, 'access', _373 => _373.file, 'optionalAccess', _374 => _374.length])) {
11250
11680
  buckets = buckets.map((bucket) => {
11251
11681
  const paths = bucket.paths.filter(
11252
11682
  (path19) => flags.file.find(
11253
- (file) => _optionalChain([path19, 'access', _364 => _364.pathPattern, 'optionalAccess', _365 => _365.includes, 'call', _366 => _366(file)]) || _optionalChain([path19, 'access', _367 => _367.pathPattern, 'optionalAccess', _368 => _368.match, 'call', _369 => _369(file)]) || minimatch(path19.pathPattern, file)
11683
+ (file) => _optionalChain([path19, 'access', _375 => _375.pathPattern, 'optionalAccess', _376 => _376.includes, 'call', _377 => _377(file)]) || _optionalChain([path19, 'access', _378 => _378.pathPattern, 'optionalAccess', _379 => _379.match, 'call', _380 => _380(file)]) || minimatch(path19.pathPattern, file)
11254
11684
  )
11255
11685
  );
11256
11686
  return { ...bucket, paths };
@@ -11270,7 +11700,7 @@ var status_default = new (0, _interactivecommander.Command)().command("status").
11270
11700
  });
11271
11701
  }
11272
11702
  }
11273
- const targetLocales = _optionalChain([flags, 'access', _370 => _370.locale, 'optionalAccess', _371 => _371.length]) ? flags.locale : i18nConfig.locale.targets;
11703
+ const targetLocales = _optionalChain([flags, 'access', _381 => _381.locale, 'optionalAccess', _382 => _382.length]) ? flags.locale : i18nConfig.locale.targets;
11274
11704
  let totalSourceKeyCount = 0;
11275
11705
  let uniqueKeysToTranslate = 0;
11276
11706
  let totalExistingTranslations = 0;
@@ -11676,12 +12106,12 @@ function validateParams2(i18nConfig, flags) {
11676
12106
  message: "No buckets found in i18n.json. Please add at least one bucket containing i18n content.",
11677
12107
  docUrl: "bucketNotFound"
11678
12108
  });
11679
- } else if (_optionalChain([flags, 'access', _372 => _372.locale, 'optionalAccess', _373 => _373.some, 'call', _374 => _374((locale) => !i18nConfig.locale.targets.includes(locale))])) {
12109
+ } else if (_optionalChain([flags, 'access', _383 => _383.locale, 'optionalAccess', _384 => _384.some, 'call', _385 => _385((locale) => !i18nConfig.locale.targets.includes(locale))])) {
11680
12110
  throw new CLIError({
11681
12111
  message: `One or more specified locales do not exist in i18n.json locale.targets. Please add them to the list and try again.`,
11682
12112
  docUrl: "localeTargetNotFound"
11683
12113
  });
11684
- } else if (_optionalChain([flags, 'access', _375 => _375.bucket, 'optionalAccess', _376 => _376.some, 'call', _377 => _377(
12114
+ } else if (_optionalChain([flags, 'access', _386 => _386.bucket, 'optionalAccess', _387 => _387.some, 'call', _388 => _388(
11685
12115
  (bucket) => !i18nConfig.buckets[bucket]
11686
12116
  )])) {
11687
12117
  throw new CLIError({
@@ -11773,7 +12203,7 @@ async function renderHero2() {
11773
12203
  // package.json
11774
12204
  var package_default = {
11775
12205
  name: "lingo.dev",
11776
- version: "0.113.2",
12206
+ version: "0.113.4",
11777
12207
  description: "Lingo.dev CLI",
11778
12208
  private: false,
11779
12209
  publishConfig: {
@@ -12063,7 +12493,7 @@ var purge_default = new (0, _interactivecommander.Command)().command("purge").de
12063
12493
  if (options.file && options.file.length) {
12064
12494
  buckets = buckets.map((bucket) => {
12065
12495
  const paths = bucket.paths.filter(
12066
- (bucketPath) => _optionalChain([options, 'access', _378 => _378.file, 'optionalAccess', _379 => _379.some, 'call', _380 => _380((f) => bucketPath.pathPattern.includes(f))])
12496
+ (bucketPath) => _optionalChain([options, 'access', _389 => _389.file, 'optionalAccess', _390 => _390.some, 'call', _391 => _391((f) => bucketPath.pathPattern.includes(f))])
12067
12497
  );
12068
12498
  return { ...bucket, paths };
12069
12499
  }).filter((bucket) => bucket.paths.length > 0);