lingo.dev 0.116.1 → 0.116.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.mjs CHANGED
@@ -2036,7 +2036,7 @@ function createTextFileLoader(pathPattern) {
2036
2036
  const trimmedResult = result.trim();
2037
2037
  return trimmedResult;
2038
2038
  },
2039
- async push(locale, data, _36, originalLocale) {
2039
+ async push(locale, data, _37, originalLocale) {
2040
2040
  const draftPath = pathPattern.replaceAll("[locale]", locale);
2041
2041
  const finalPath = path10.resolve(draftPath);
2042
2042
  const dirPath = path10.dirname(finalPath);
@@ -3666,7 +3666,7 @@ function createPropertiesLoader() {
3666
3666
  return result;
3667
3667
  },
3668
3668
  async push(locale, payload) {
3669
- const result = Object.entries(payload).filter(([_36, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
3669
+ const result = Object.entries(payload).filter(([_37, value]) => value != null).map(([key, value]) => `${key}=${value}`).join("\n");
3670
3670
  return result;
3671
3671
  }
3672
3672
  });
@@ -3988,7 +3988,7 @@ function createXcodeStringsLoader() {
3988
3988
  return result;
3989
3989
  },
3990
3990
  async push(locale, payload) {
3991
- const lines = Object.entries(payload).filter(([_36, value]) => value != null).map(([key, value]) => {
3991
+ const lines = Object.entries(payload).filter(([_37, value]) => value != null).map(([key, value]) => {
3992
3992
  const escapedValue = escapeString(value);
3993
3993
  return `"${key}" = "${escapedValue}";`;
3994
3994
  });
@@ -4050,6 +4050,11 @@ function createXcodeXcstringsLoader(defaultLocale) {
4050
4050
  if (langTranslationEntity) {
4051
4051
  if ("stringUnit" in langTranslationEntity) {
4052
4052
  resultData[translationKey] = langTranslationEntity.stringUnit.value;
4053
+ } else if ("stringSet" in langTranslationEntity) {
4054
+ const values = langTranslationEntity.stringSet.values;
4055
+ if (Array.isArray(values) && values.length > 0) {
4056
+ resultData[translationKey] = values;
4057
+ }
4053
4058
  } else if ("variations" in langTranslationEntity) {
4054
4059
  if ("plural" in langTranslationEntity.variations) {
4055
4060
  resultData[translationKey] = {};
@@ -4094,6 +4099,21 @@ function createXcodeXcstringsLoader(defaultLocale) {
4094
4099
  if (hasDoNotTranslateFlag) {
4095
4100
  langDataToMerge.strings[key].shouldTranslate = false;
4096
4101
  }
4102
+ } else if (Array.isArray(value)) {
4103
+ langDataToMerge.strings[key] = {
4104
+ extractionState: originalInput?.strings?.[key]?.extractionState,
4105
+ localizations: {
4106
+ [locale]: {
4107
+ stringSet: {
4108
+ state: "translated",
4109
+ values: value
4110
+ }
4111
+ }
4112
+ }
4113
+ };
4114
+ if (hasDoNotTranslateFlag) {
4115
+ langDataToMerge.strings[key].shouldTranslate = false;
4116
+ }
4097
4117
  } else {
4098
4118
  const updatedVariations = {};
4099
4119
  for (const form in value) {
@@ -4166,218 +4186,21 @@ function _removeLocale(input2, locale) {
4166
4186
  return { ...input2, strings: newStrings };
4167
4187
  }
4168
4188
 
4169
- // src/cli/loaders/xcode-xcstrings-icu.ts
4170
- var ICU_TYPE_MARKER = Symbol.for("@lingo.dev/icu-plural-object");
4171
- var CLDR_PLURAL_CATEGORIES = /* @__PURE__ */ new Set([
4172
- "zero",
4173
- "one",
4174
- "two",
4175
- "few",
4176
- "many",
4177
- "other"
4178
- ]);
4179
- function isICUPluralObject(value) {
4180
- if (!value || typeof value !== "object" || Array.isArray(value)) {
4181
- return false;
4182
- }
4183
- if (ICU_TYPE_MARKER in value) {
4184
- return true;
4185
- }
4186
- if (!("icu" in value) || typeof value.icu !== "string") {
4187
- return false;
4188
- }
4189
- const icuPluralPattern = /^\{[\w]+,\s*plural,\s*.+\}$/;
4190
- if (!icuPluralPattern.test(value.icu)) {
4191
- return false;
4192
- }
4193
- if (value._meta !== void 0) {
4194
- if (typeof value._meta !== "object" || !value._meta.variables || typeof value._meta.variables !== "object") {
4195
- return false;
4196
- }
4197
- for (const [varName, varMeta] of Object.entries(value._meta.variables)) {
4198
- if (!varMeta || typeof varMeta !== "object" || typeof varMeta.format !== "string" || varMeta.role !== "plural" && varMeta.role !== "other") {
4199
- return false;
4200
- }
4201
- }
4202
- }
4203
- return true;
4204
- }
4205
- function isPluralFormsObject(value) {
4206
- if (!value || typeof value !== "object" || Array.isArray(value)) {
4207
- return false;
4208
- }
4209
- const keys = Object.keys(value);
4210
- if (keys.length === 0) {
4211
- return false;
4212
- }
4213
- const allKeysAreCldr = keys.every((key) => CLDR_PLURAL_CATEGORIES.has(key));
4214
- if (!allKeysAreCldr) {
4215
- return false;
4216
- }
4217
- const allValuesAreStrings = keys.every(
4218
- (key) => typeof value[key] === "string"
4189
+ // src/cli/loaders/xcode-xcstrings-v2.ts
4190
+ import _10 from "lodash";
4191
+ function buildIcuPluralString(forms) {
4192
+ const parts = Object.entries(forms).map(
4193
+ ([form, text]) => `${form} {${text}}`
4219
4194
  );
4220
- if (!allValuesAreStrings) {
4221
- return false;
4222
- }
4223
- if (!("other" in value)) {
4224
- return false;
4225
- }
4226
- return true;
4227
- }
4228
- function getRequiredPluralCategories(locale) {
4229
- try {
4230
- const pluralRules = new Intl.PluralRules(locale);
4231
- const categories = pluralRules.resolvedOptions().pluralCategories;
4232
- if (!categories || categories.length === 0) {
4233
- throw new Error(`No plural categories found for locale: ${locale}`);
4234
- }
4235
- return categories;
4236
- } catch (error) {
4237
- console.warn(
4238
- `[xcode-xcstrings-icu] Failed to resolve plural categories for locale "${locale}". Using fallback ["one", "other"]. Error: ${error instanceof Error ? error.message : String(error)}`
4239
- );
4240
- return ["one", "other"];
4241
- }
4242
- }
4243
- var CLDR_CATEGORY_TO_NUMBER = {
4244
- zero: 0,
4245
- one: 1,
4246
- two: 2
4247
- };
4248
- var NUMBER_TO_CLDR_CATEGORY = {
4249
- 0: "zero",
4250
- 1: "one",
4251
- 2: "two"
4252
- };
4253
- function xcstringsToPluralWithMeta(pluralForms, sourceLocale = "en") {
4254
- if (!pluralForms || Object.keys(pluralForms).length === 0) {
4255
- throw new Error("pluralForms cannot be empty");
4256
- }
4257
- const requiredCategories = getRequiredPluralCategories(sourceLocale);
4258
- const variables = {};
4259
- const formatRegex = /(%(?:(\d+)\$)?(?:[+-])?(?:\d+)?(?:\.(\d+))?([lhqLzjt]*)([diuoxXfFeEgGaAcspn@]))/g;
4260
- let maxMatches = [];
4261
- let maxMatchText = "";
4262
- for (const [form, text] of Object.entries(pluralForms)) {
4263
- if (typeof text !== "string") {
4264
- console.warn(
4265
- `Warning: Plural form "${form}" has non-string value:`,
4266
- text
4267
- );
4268
- continue;
4269
- }
4270
- const matches = [...text.matchAll(formatRegex)];
4271
- if (matches.length > maxMatches.length) {
4272
- maxMatches = matches;
4273
- maxMatchText = text;
4274
- }
4275
- }
4276
- let lastNumericIndex = -1;
4277
- maxMatches.forEach((match2, idx) => {
4278
- const specifier = match2[5];
4279
- if (/[diuoxXfFeE]/.test(specifier)) {
4280
- lastNumericIndex = idx;
4281
- }
4282
- });
4283
- let nonPluralCounter = 0;
4284
- maxMatches.forEach((match2, idx) => {
4285
- const fullFormat = match2[1];
4286
- const position = match2[2];
4287
- const precision = match2[3];
4288
- const lengthMod = match2[4];
4289
- const specifier = match2[5];
4290
- const isPluralVar = idx === lastNumericIndex;
4291
- const varName = isPluralVar ? "count" : `var${nonPluralCounter++}`;
4292
- variables[varName] = {
4293
- format: fullFormat,
4294
- role: isPluralVar ? "plural" : "other"
4295
- };
4296
- });
4297
- const variableKeys = Object.keys(variables);
4298
- const icuForms = Object.entries(pluralForms).filter(([form, text]) => {
4299
- if (typeof text !== "string") {
4300
- return false;
4301
- }
4302
- return true;
4303
- }).map(([form, text]) => {
4304
- let processed = text;
4305
- let vIdx = 0;
4306
- processed = processed.replace(formatRegex, () => {
4307
- if (vIdx >= variableKeys.length) {
4308
- vIdx++;
4309
- return "#";
4310
- }
4311
- const varName = variableKeys[vIdx];
4312
- const varMeta = variables[varName];
4313
- vIdx++;
4314
- if (varMeta.role === "plural") {
4315
- return "#";
4316
- } else {
4317
- return `{${varName}}`;
4318
- }
4319
- });
4320
- const isRequired = requiredCategories.includes(form);
4321
- const formKey = !isRequired && form in CLDR_CATEGORY_TO_NUMBER ? `=${CLDR_CATEGORY_TO_NUMBER[form]}` : form;
4322
- return `${formKey} {${processed}}`;
4323
- }).join(" ");
4324
- const pluralVarName = Object.keys(variables).find((name) => variables[name].role === "plural") || "count";
4325
- const icu = `{${pluralVarName}, plural, ${icuForms}}`;
4326
- const result = {
4327
- icu,
4328
- _meta: Object.keys(variables).length > 0 ? { variables } : void 0,
4329
- [ICU_TYPE_MARKER]: true
4330
- // Add type marker for robust detection
4331
- };
4332
- return result;
4195
+ return `{count, plural, ${parts.join(" ")}}`;
4333
4196
  }
4334
- function pluralWithMetaToXcstrings(data) {
4335
- if (!data.icu) {
4336
- throw new Error("ICU string is required");
4337
- }
4338
- const ast = parseICU(data.icu);
4339
- if (!ast || ast.length === 0) {
4340
- throw new Error("Invalid ICU format");
4341
- }
4342
- const pluralNode = ast.find((node) => node.type === "plural");
4343
- if (!pluralNode) {
4344
- throw new Error("No plural found in ICU format");
4197
+ function parseIcuPluralString(icuString) {
4198
+ const pluralMatch = icuString.match(/\{[\w]+,\s*plural,\s*(.+)\}$/);
4199
+ if (!pluralMatch) {
4200
+ throw new Error(`Invalid ICU plural format: ${icuString}`);
4345
4201
  }
4202
+ const formsText = pluralMatch[1];
4346
4203
  const forms = {};
4347
- for (const [form, option] of Object.entries(pluralNode.options)) {
4348
- let text = "";
4349
- const optionValue = option.value;
4350
- for (const element of optionValue) {
4351
- if (element.type === "literal") {
4352
- text += element.value;
4353
- } else if (element.type === "pound") {
4354
- const pluralVar = Object.entries(data._meta?.variables || {}).find(
4355
- ([_36, meta]) => meta.role === "plural"
4356
- );
4357
- text += pluralVar?.[1].format || "%lld";
4358
- } else if (element.type === "argument") {
4359
- const varName = element.value;
4360
- const varMeta = data._meta?.variables?.[varName];
4361
- text += varMeta?.format || "%@";
4362
- }
4363
- }
4364
- let xcstringsFormName = form;
4365
- if (form.startsWith("=")) {
4366
- const numValue = parseInt(form.substring(1), 10);
4367
- xcstringsFormName = NUMBER_TO_CLDR_CATEGORY[numValue] || form;
4368
- }
4369
- forms[xcstringsFormName] = text;
4370
- }
4371
- return forms;
4372
- }
4373
- function parseICU(icu) {
4374
- const match2 = icu.match(/\{(\w+),\s*plural,\s*(.+)\}$/);
4375
- if (!match2) {
4376
- throw new Error("Invalid ICU plural format");
4377
- }
4378
- const varName = match2[1];
4379
- const formsText = match2[2];
4380
- const options = {};
4381
4204
  let i = 0;
4382
4205
  while (i < formsText.length) {
4383
4206
  while (i < formsText.length && /\s/.test(formsText[i])) {
@@ -4423,149 +4246,228 @@ function parseICU(icu) {
4423
4246
  i++;
4424
4247
  }
4425
4248
  if (braceCount !== 0) {
4426
- const preview = formsText.substring(
4427
- Math.max(0, i - 50),
4428
- Math.min(formsText.length, i + 50)
4429
- );
4430
4249
  throw new Error(
4431
- `Unclosed brace for form '${formName}' in ICU MessageFormat.
4432
- Expected ${braceCount} more closing brace(s).
4433
- Context: ...${preview}...
4434
- Full ICU: {${varName}, plural, ${formsText}}`
4250
+ `Unclosed brace for form '${formName}' in ICU: ${icuString}`
4435
4251
  );
4436
4252
  }
4437
- const elements = parseFormText(formText);
4438
- options[formName] = {
4439
- value: elements
4440
- };
4253
+ forms[formName] = formText;
4441
4254
  }
4442
- return [
4443
- {
4444
- type: "plural",
4445
- value: varName,
4446
- options
4447
- }
4448
- ];
4255
+ return forms;
4449
4256
  }
4450
- function parseFormText(text) {
4451
- const elements = [];
4452
- let currentText = "";
4453
- let i = 0;
4454
- while (i < text.length) {
4455
- if (text[i] === "#") {
4456
- if (currentText) {
4457
- elements.push({ type: "literal", value: currentText });
4458
- currentText = "";
4459
- }
4460
- elements.push({ type: "pound" });
4461
- i++;
4462
- } else if (text[i] === "{") {
4463
- if (currentText) {
4464
- elements.push({ type: "literal", value: currentText });
4465
- currentText = "";
4466
- }
4467
- let braceCount = 1;
4468
- let j = i + 1;
4469
- while (j < text.length && braceCount > 0) {
4470
- if (text[j] === "{") {
4471
- braceCount++;
4472
- } else if (text[j] === "}") {
4473
- braceCount--;
4474
- }
4475
- j++;
4476
- }
4477
- if (braceCount !== 0) {
4478
- throw new Error("Unclosed variable reference");
4479
- }
4480
- const varName = text.slice(i + 1, j - 1);
4481
- elements.push({ type: "argument", value: varName });
4482
- i = j;
4483
- } else {
4484
- currentText += text[i];
4485
- i++;
4486
- }
4487
- }
4488
- if (currentText) {
4489
- elements.push({ type: "literal", value: currentText });
4490
- }
4491
- return elements;
4257
+ function isIcuPluralString(value) {
4258
+ return typeof value === "string" && /^\{[\w]+,\s*plural,\s*.+\}$/.test(value);
4492
4259
  }
4493
-
4494
- // src/cli/loaders/xcode-xcstrings-v2-loader.ts
4495
- function createXcodeXcstringsV2Loader(defaultLocale = "en") {
4260
+ function createXcodeXcstringsV2Loader(defaultLocale) {
4496
4261
  return createLoader({
4497
- async pull(locale, input2) {
4498
- const result = {};
4499
- for (const [key, value] of Object.entries(input2)) {
4500
- if (isPluralFormsObject(value)) {
4501
- try {
4502
- result[key] = xcstringsToPluralWithMeta(value, locale);
4503
- } catch (error) {
4504
- console.error(
4505
- `
4506
- [xcode-xcstrings-icu] Failed to convert plural forms for key "${key}":`,
4507
- `
4508
- Error: ${error instanceof Error ? error.message : String(error)}`,
4509
- `
4510
- Locale: ${locale}
4511
- `
4512
- );
4513
- result[key] = value;
4262
+ async pull(locale, input2, initCtx) {
4263
+ const resultData = {};
4264
+ const isSourceLanguage = locale === defaultLocale;
4265
+ for (const [translationKey, _translationEntity] of Object.entries(
4266
+ input2.strings
4267
+ )) {
4268
+ const rootTranslationEntity = _translationEntity;
4269
+ if (rootTranslationEntity.shouldTranslate === false) {
4270
+ continue;
4271
+ }
4272
+ const langTranslationEntity = rootTranslationEntity?.localizations?.[locale];
4273
+ if (langTranslationEntity) {
4274
+ if (!resultData[translationKey]) {
4275
+ resultData[translationKey] = {};
4514
4276
  }
4515
- } else {
4516
- result[key] = value;
4277
+ if ("stringUnit" in langTranslationEntity) {
4278
+ resultData[translationKey].stringUnit = langTranslationEntity.stringUnit.value;
4279
+ if ("substitutions" in langTranslationEntity) {
4280
+ resultData[translationKey].substitutions = {};
4281
+ for (const [subName, subData] of Object.entries(
4282
+ langTranslationEntity.substitutions
4283
+ )) {
4284
+ const pluralForms = subData.variations?.plural;
4285
+ if (pluralForms) {
4286
+ const forms = {};
4287
+ for (const [form, formData] of Object.entries(pluralForms)) {
4288
+ forms[form] = formData.stringUnit.value;
4289
+ }
4290
+ const icuString = buildIcuPluralString(forms);
4291
+ resultData[translationKey].substitutions[subName] = {
4292
+ variations: {
4293
+ plural: icuString
4294
+ }
4295
+ };
4296
+ }
4297
+ }
4298
+ }
4299
+ } else if ("stringSet" in langTranslationEntity) {
4300
+ const values = langTranslationEntity.stringSet.values;
4301
+ if (Array.isArray(values) && values.length > 0) {
4302
+ resultData[translationKey].stringSet = values;
4303
+ }
4304
+ } else if ("variations" in langTranslationEntity) {
4305
+ if ("plural" in langTranslationEntity.variations) {
4306
+ const pluralForms = langTranslationEntity.variations.plural;
4307
+ const forms = {};
4308
+ for (const [form, formData] of Object.entries(pluralForms)) {
4309
+ if (formData?.stringUnit?.value) {
4310
+ forms[form] = formData.stringUnit.value;
4311
+ }
4312
+ }
4313
+ const icuString = buildIcuPluralString(forms);
4314
+ resultData[translationKey].variations = {
4315
+ plural: icuString
4316
+ };
4317
+ }
4318
+ }
4319
+ } else if (isSourceLanguage) {
4320
+ if (!resultData[translationKey]) {
4321
+ resultData[translationKey] = {};
4322
+ }
4323
+ resultData[translationKey].stringUnit = translationKey;
4517
4324
  }
4518
4325
  }
4519
- return result;
4326
+ return resultData;
4520
4327
  },
4521
- async push(locale, payload) {
4522
- const result = {};
4523
- for (const [key, value] of Object.entries(payload)) {
4524
- if (isICUPluralObject(value)) {
4525
- try {
4526
- const pluralForms = pluralWithMetaToXcstrings(value);
4527
- result[key] = pluralForms;
4528
- } catch (error) {
4529
- throw new Error(
4530
- `Failed to write plural translation for key "${key}" (locale: ${locale}).
4328
+ async push(locale, payload, originalInput) {
4329
+ const langDataToMerge = {};
4330
+ langDataToMerge.strings = {};
4331
+ const input2 = _10.cloneDeep(originalInput) || {
4332
+ sourceLanguage: locale,
4333
+ strings: {}
4334
+ };
4335
+ for (const [baseKey, keyData] of Object.entries(payload)) {
4336
+ if (!keyData || typeof keyData !== "object") {
4337
+ continue;
4338
+ }
4339
+ const hasDoNotTranslateFlag = originalInput && originalInput.strings && originalInput.strings[baseKey] && originalInput.strings[baseKey].shouldTranslate === false;
4340
+ const localizationData = {};
4341
+ if ("stringUnit" in keyData) {
4342
+ localizationData.stringUnit = {
4343
+ state: "translated",
4344
+ value: keyData.stringUnit
4345
+ };
4346
+ }
4347
+ if ("substitutions" in keyData && keyData.substitutions) {
4348
+ const subs = {};
4349
+ for (const [subName, subData] of Object.entries(
4350
+ keyData.substitutions
4351
+ )) {
4352
+ const pluralValue = subData?.variations?.plural;
4353
+ if (pluralValue && isIcuPluralString(pluralValue)) {
4354
+ try {
4355
+ const pluralForms = parseIcuPluralString(pluralValue);
4356
+ const pluralOut = {};
4357
+ for (const [form, text] of Object.entries(pluralForms)) {
4358
+ pluralOut[form] = {
4359
+ stringUnit: {
4360
+ state: "translated",
4361
+ value: text
4362
+ }
4363
+ };
4364
+ }
4365
+ const sourceLocale = originalInput?.sourceLanguage || "en";
4366
+ const origFormatSpec = originalInput?.strings?.[baseKey]?.localizations?.[sourceLocale]?.substitutions?.[subName]?.formatSpecifier || subName;
4367
+ subs[subName] = {
4368
+ formatSpecifier: origFormatSpec,
4369
+ variations: {
4370
+ plural: pluralOut
4371
+ }
4372
+ };
4373
+ } catch (error) {
4374
+ throw new Error(
4375
+ `Failed to write substitution plural translation for key "${baseKey}/substitutions/${subName}" (locale: ${locale}).
4531
4376
  ${error instanceof Error ? error.message : String(error)}`
4532
- );
4377
+ );
4378
+ }
4379
+ }
4380
+ }
4381
+ if (Object.keys(subs).length > 0) {
4382
+ localizationData.substitutions = subs;
4383
+ }
4384
+ }
4385
+ if ("stringSet" in keyData && Array.isArray(keyData.stringSet)) {
4386
+ localizationData.stringSet = {
4387
+ state: "translated",
4388
+ values: keyData.stringSet
4389
+ };
4390
+ }
4391
+ if ("variations" in keyData && keyData.variations?.plural) {
4392
+ const pluralValue = keyData.variations.plural;
4393
+ if (isIcuPluralString(pluralValue)) {
4394
+ try {
4395
+ const pluralForms = parseIcuPluralString(pluralValue);
4396
+ const pluralOut = {};
4397
+ for (const [form, text] of Object.entries(pluralForms)) {
4398
+ pluralOut[form] = {
4399
+ stringUnit: {
4400
+ state: "translated",
4401
+ value: text
4402
+ }
4403
+ };
4404
+ }
4405
+ localizationData.variations = {
4406
+ plural: pluralOut
4407
+ };
4408
+ } catch (error) {
4409
+ throw new Error(
4410
+ `Failed to write plural translation for key "${baseKey}" (locale: ${locale}).
4411
+ ${error instanceof Error ? error.message : String(error)}`
4412
+ );
4413
+ }
4414
+ }
4415
+ }
4416
+ if (Object.keys(localizationData).length > 0) {
4417
+ langDataToMerge.strings[baseKey] = {
4418
+ extractionState: originalInput?.strings?.[baseKey]?.extractionState,
4419
+ localizations: {
4420
+ [locale]: localizationData
4421
+ }
4422
+ };
4423
+ if (hasDoNotTranslateFlag) {
4424
+ langDataToMerge.strings[baseKey].shouldTranslate = false;
4533
4425
  }
4534
- } else {
4535
- result[key] = value;
4536
4426
  }
4537
4427
  }
4538
- return result;
4428
+ return _10.merge(input2, langDataToMerge);
4429
+ },
4430
+ async pullHints(input2) {
4431
+ const hints = {};
4432
+ for (const [translationKey, _translationEntity] of Object.entries(
4433
+ input2.strings || {}
4434
+ )) {
4435
+ const rootTranslationEntity = _translationEntity;
4436
+ if (rootTranslationEntity.comment && typeof rootTranslationEntity.comment === "string") {
4437
+ hints[translationKey] = { hint: rootTranslationEntity.comment };
4438
+ }
4439
+ }
4440
+ return hints;
4539
4441
  }
4540
4442
  });
4541
4443
  }
4542
4444
 
4543
4445
  // src/cli/loaders/unlocalizable.ts
4544
- import _10 from "lodash";
4446
+ import _11 from "lodash";
4545
4447
  import _isUrl from "is-url";
4546
4448
  import { isValid, parseISO } from "date-fns";
4547
4449
  function createUnlocalizableLoader(returnUnlocalizedKeys = false) {
4548
4450
  return createLoader({
4549
4451
  async pull(locale, input2) {
4550
4452
  const unlocalizableKeys = _getUnlocalizableKeys(input2);
4551
- const result = _10.omitBy(
4453
+ const result = _11.omitBy(
4552
4454
  input2,
4553
- (_36, key) => unlocalizableKeys.includes(key)
4455
+ (_37, key) => unlocalizableKeys.includes(key)
4554
4456
  );
4555
4457
  if (returnUnlocalizedKeys) {
4556
- result.unlocalizable = _10.omitBy(
4458
+ result.unlocalizable = _11.omitBy(
4557
4459
  input2,
4558
- (_36, key) => !unlocalizableKeys.includes(key)
4460
+ (_37, key) => !unlocalizableKeys.includes(key)
4559
4461
  );
4560
4462
  }
4561
4463
  return result;
4562
4464
  },
4563
4465
  async push(locale, data, originalInput) {
4564
4466
  const unlocalizableKeys = _getUnlocalizableKeys(originalInput);
4565
- const result = _10.merge(
4467
+ const result = _11.merge(
4566
4468
  {},
4567
4469
  data,
4568
- _10.omitBy(originalInput, (_36, key) => !unlocalizableKeys.includes(key))
4470
+ _11.omitBy(originalInput, (_37, key) => !unlocalizableKeys.includes(key))
4569
4471
  );
4570
4472
  return result;
4571
4473
  }
@@ -4579,12 +4481,12 @@ function _isIsoDate(v) {
4579
4481
  }
4580
4482
  function _getUnlocalizableKeys(input2) {
4581
4483
  const rules = {
4582
- isEmpty: (v) => _10.isEmpty(v),
4484
+ isEmpty: (v) => _11.isEmpty(v),
4583
4485
  isNumber: (v) => typeof v === "number" || /^[0-9]+$/.test(v),
4584
- isBoolean: (v) => _10.isBoolean(v),
4585
- isIsoDate: (v) => _10.isString(v) && _isIsoDate(v),
4586
- isSystemId: (v) => _10.isString(v) && _isSystemId(v),
4587
- isUrl: (v) => _10.isString(v) && _isUrl(v)
4486
+ isBoolean: (v) => _11.isBoolean(v),
4487
+ isIsoDate: (v) => _11.isString(v) && _isIsoDate(v),
4488
+ isSystemId: (v) => _11.isString(v) && _isSystemId(v),
4489
+ isUrl: (v) => _11.isString(v) && _isUrl(v)
4588
4490
  };
4589
4491
  if (!input2) {
4590
4492
  return [];
@@ -4596,7 +4498,7 @@ function _getUnlocalizableKeys(input2) {
4596
4498
  }
4597
4499
  }
4598
4500
  return false;
4599
- }).map(([key, _36]) => key);
4501
+ }).map(([key, _37]) => key);
4600
4502
  }
4601
4503
 
4602
4504
  // src/cli/loaders/formatters/prettier.ts
@@ -4763,7 +4665,7 @@ function createFormatterLoader(formatterType, parser, bucketPathPattern) {
4763
4665
  }
4764
4666
 
4765
4667
  // src/cli/loaders/po/index.ts
4766
- import _11 from "lodash";
4668
+ import _12 from "lodash";
4767
4669
  import gettextParser from "gettext-parser";
4768
4670
  function createPoLoader(params = { multiline: false }) {
4769
4671
  return composeLoaders(createPoDataLoader(params), createPoContentLoader());
@@ -4779,7 +4681,7 @@ function createPoDataLoader(params) {
4779
4681
  if (Object.keys(sectionPo.translations).length === 0) {
4780
4682
  continue;
4781
4683
  }
4782
- const contextKey = _11.keys(sectionPo.translations)[0];
4684
+ const contextKey = _12.keys(sectionPo.translations)[0];
4783
4685
  const entries = sectionPo.translations[contextKey];
4784
4686
  Object.entries(entries).forEach(([msgid, entry]) => {
4785
4687
  if (msgid && entry.msgid) {
@@ -4801,13 +4703,13 @@ function createPoDataLoader(params) {
4801
4703
  if (Object.keys(sectionPo.translations).length === 0) {
4802
4704
  return null;
4803
4705
  }
4804
- const contextKey = _11.keys(sectionPo.translations)[0];
4706
+ const contextKey = _12.keys(sectionPo.translations)[0];
4805
4707
  const entries = sectionPo.translations[contextKey];
4806
4708
  const msgid = Object.keys(entries).find((key) => entries[key].msgid);
4807
4709
  if (!msgid) {
4808
4710
  const currentSection = currentSections.find((cs) => {
4809
4711
  const csPo = gettextParser.po.parse(cs);
4810
- const csContextKey = _11.keys(csPo.translations)[0];
4712
+ const csContextKey = _12.keys(csPo.translations)[0];
4811
4713
  const csEntries = csPo.translations[csContextKey];
4812
4714
  const csMsgid = Object.keys(csEntries).find(
4813
4715
  (key) => csEntries[key].msgid
@@ -4820,7 +4722,7 @@ function createPoDataLoader(params) {
4820
4722
  return section;
4821
4723
  }
4822
4724
  if (data[msgid]) {
4823
- const updatedPo = _11.merge({}, sectionPo, {
4725
+ const updatedPo = _12.merge({}, sectionPo, {
4824
4726
  translations: {
4825
4727
  [contextKey]: {
4826
4728
  [msgid]: {
@@ -4844,7 +4746,7 @@ function createPoDataLoader(params) {
4844
4746
  function createPoContentLoader() {
4845
4747
  return createLoader({
4846
4748
  async pull(locale, input2, initCtx, originalLocale) {
4847
- const result = _11.chain(input2).entries().filter(([, entry]) => !!entry.msgid).map(([, entry]) => {
4749
+ const result = _12.chain(input2).entries().filter(([, entry]) => !!entry.msgid).map(([, entry]) => {
4848
4750
  const singularFallback = locale === originalLocale ? entry.msgid : null;
4849
4751
  const pluralFallback = locale === originalLocale ? entry.msgid_plural || entry.msgid : null;
4850
4752
  const hasPlural = entry.msgstr.length > 1;
@@ -4859,7 +4761,7 @@ function createPoContentLoader() {
4859
4761
  return result;
4860
4762
  },
4861
4763
  async push(locale, data, originalInput) {
4862
- const result = _11.chain(originalInput).entries().map(([, entry]) => [
4764
+ const result = _12.chain(originalInput).entries().map(([, entry]) => [
4863
4765
  entry.msgid,
4864
4766
  {
4865
4767
  ...entry,
@@ -5402,41 +5304,41 @@ var datoSettingsSchema = Z2.object({
5402
5304
  });
5403
5305
 
5404
5306
  // src/cli/loaders/dato/filter.ts
5405
- import _12 from "lodash";
5307
+ import _13 from "lodash";
5406
5308
  function createDatoFilterLoader() {
5407
5309
  return createLoader({
5408
5310
  async pull(locale, input2) {
5409
5311
  const result = {};
5410
- for (const [modelId, modelInfo] of _12.entries(input2)) {
5312
+ for (const [modelId, modelInfo] of _13.entries(input2)) {
5411
5313
  result[modelId] = {};
5412
5314
  for (const record of modelInfo.records) {
5413
- result[modelId][record.id] = _12.chain(modelInfo.fields).mapKeys((field) => field.api_key).mapValues((field) => _12.get(record, [field.api_key, locale])).value();
5315
+ result[modelId][record.id] = _13.chain(modelInfo.fields).mapKeys((field) => field.api_key).mapValues((field) => _13.get(record, [field.api_key, locale])).value();
5414
5316
  }
5415
5317
  }
5416
5318
  return result;
5417
5319
  },
5418
5320
  async push(locale, data, originalInput, originalLocale) {
5419
- const result = _12.cloneDeep(originalInput || {});
5420
- for (const [modelId, modelInfo] of _12.entries(result)) {
5321
+ const result = _13.cloneDeep(originalInput || {});
5322
+ for (const [modelId, modelInfo] of _13.entries(result)) {
5421
5323
  for (const record of modelInfo.records) {
5422
- for (const [fieldId, fieldValue] of _12.entries(record)) {
5324
+ for (const [fieldId, fieldValue] of _13.entries(record)) {
5423
5325
  const fieldInfo = modelInfo.fields.find(
5424
5326
  (field) => field.api_key === fieldId
5425
5327
  );
5426
5328
  if (fieldInfo) {
5427
- const sourceFieldValue = _12.get(fieldValue, [originalLocale]);
5428
- const targetFieldValue = _12.get(data, [
5329
+ const sourceFieldValue = _13.get(fieldValue, [originalLocale]);
5330
+ const targetFieldValue = _13.get(data, [
5429
5331
  modelId,
5430
5332
  record.id,
5431
5333
  fieldId
5432
5334
  ]);
5433
5335
  if (targetFieldValue) {
5434
- _12.set(record, [fieldId, locale], targetFieldValue);
5336
+ _13.set(record, [fieldId, locale], targetFieldValue);
5435
5337
  } else {
5436
- _12.set(record, [fieldId, locale], sourceFieldValue);
5338
+ _13.set(record, [fieldId, locale], sourceFieldValue);
5437
5339
  }
5438
- _12.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _12.isEmpty(_12.get(fieldValue, [loc]))).forEach(
5439
- (loc) => _12.set(record, [fieldId, loc], sourceFieldValue)
5340
+ _13.chain(fieldValue).keys().reject((loc) => loc === locale || loc === originalLocale).filter((loc) => _13.isEmpty(_13.get(fieldValue, [loc]))).forEach(
5341
+ (loc) => _13.set(record, [fieldId, loc], sourceFieldValue)
5440
5342
  ).value();
5441
5343
  }
5442
5344
  }
@@ -5448,10 +5350,10 @@ function createDatoFilterLoader() {
5448
5350
  }
5449
5351
 
5450
5352
  // src/cli/loaders/dato/api.ts
5451
- import _14 from "lodash";
5353
+ import _15 from "lodash";
5452
5354
 
5453
5355
  // src/cli/loaders/dato/_utils.ts
5454
- import _13 from "lodash";
5356
+ import _14 from "lodash";
5455
5357
  import { buildClient } from "@datocms/cma-client-node";
5456
5358
  function createDatoClient(params) {
5457
5359
  if (!params.apiKey) {
@@ -5644,7 +5546,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
5644
5546
  const result = {
5645
5547
  models: {}
5646
5548
  };
5647
- const updatedConfig = _14.cloneDeep(config);
5549
+ const updatedConfig = _15.cloneDeep(config);
5648
5550
  console.log(`Initializing DatoCMS loader...`);
5649
5551
  const project = await dato.findProject();
5650
5552
  const modelChoices = await getModelChoices(dato, config);
@@ -5662,7 +5564,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
5662
5564
  delete updatedConfig.models[modelId];
5663
5565
  }
5664
5566
  }
5665
- for (const modelId of _14.keys(updatedConfig.models)) {
5567
+ for (const modelId of _15.keys(updatedConfig.models)) {
5666
5568
  const { modelName, fields } = await getModelFields(dato, modelId);
5667
5569
  if (fields.length > 0) {
5668
5570
  result.models[modelId] = { fields: [], records: [] };
@@ -5680,7 +5582,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
5680
5582
  );
5681
5583
  if (isLocalized) {
5682
5584
  result.models[modelId].fields.push(fieldInfo);
5683
- updatedConfig.models[modelId].fields = _14.uniq([
5585
+ updatedConfig.models[modelId].fields = _15.uniq([
5684
5586
  ...updatedConfig.models[modelId].fields || [],
5685
5587
  fieldInfo.api_key
5686
5588
  ]);
@@ -5708,7 +5610,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
5708
5610
  },
5709
5611
  async pull(locale, input2, initCtx) {
5710
5612
  const result = {};
5711
- for (const modelId of _14.keys(initCtx?.models || {})) {
5613
+ for (const modelId of _15.keys(initCtx?.models || {})) {
5712
5614
  let records = initCtx?.models[modelId].records || [];
5713
5615
  const recordIds = records.map((record) => record.id);
5714
5616
  records = await dato.findRecords(recordIds);
@@ -5723,7 +5625,7 @@ function createDatoApiLoader(config, onConfigUpdate) {
5723
5625
  return result;
5724
5626
  },
5725
5627
  async push(locale, data, originalInput) {
5726
- for (const modelId of _14.keys(data)) {
5628
+ for (const modelId of _15.keys(data)) {
5727
5629
  for (let i = 0; i < data[modelId].records.length; i++) {
5728
5630
  const record = data[modelId].records[i];
5729
5631
  console.log(
@@ -5739,7 +5641,7 @@ async function getModelFields(dato, modelId) {
5739
5641
  const modelInfo = await dato.findModel(modelId);
5740
5642
  return {
5741
5643
  modelName: modelInfo.name,
5742
- fields: _14.filter(modelInfo.fields, (field) => field.type === "field")
5644
+ fields: _15.filter(modelInfo.fields, (field) => field.type === "field")
5743
5645
  };
5744
5646
  }
5745
5647
  async function getFieldDetails(dato, fields) {
@@ -5819,17 +5721,17 @@ async function promptModelSelection(choices) {
5819
5721
  }
5820
5722
 
5821
5723
  // src/cli/loaders/dato/extract.ts
5822
- import _15 from "lodash";
5724
+ import _16 from "lodash";
5823
5725
  function createDatoExtractLoader() {
5824
5726
  return createLoader({
5825
5727
  async pull(locale, input2) {
5826
5728
  const result = {};
5827
- for (const [modelId, modelInfo] of _15.entries(input2)) {
5828
- for (const [recordId, record] of _15.entries(modelInfo)) {
5829
- for (const [fieldName, fieldValue] of _15.entries(record)) {
5729
+ for (const [modelId, modelInfo] of _16.entries(input2)) {
5730
+ for (const [recordId, record] of _16.entries(modelInfo)) {
5731
+ for (const [fieldName, fieldValue] of _16.entries(record)) {
5830
5732
  const parsedValue = createParsedDatoValue(fieldValue);
5831
5733
  if (parsedValue) {
5832
- _15.set(result, [modelId, `_${recordId}`, fieldName], parsedValue);
5734
+ _16.set(result, [modelId, `_${recordId}`, fieldName], parsedValue);
5833
5735
  }
5834
5736
  }
5835
5737
  }
@@ -5837,12 +5739,12 @@ function createDatoExtractLoader() {
5837
5739
  return result;
5838
5740
  },
5839
5741
  async push(locale, data, originalInput) {
5840
- const result = _15.cloneDeep(originalInput || {});
5841
- for (const [modelId, modelInfo] of _15.entries(data)) {
5842
- for (const [virtualRecordId, record] of _15.entries(modelInfo)) {
5843
- for (const [fieldName, fieldValue] of _15.entries(record)) {
5742
+ const result = _16.cloneDeep(originalInput || {});
5743
+ for (const [modelId, modelInfo] of _16.entries(data)) {
5744
+ for (const [virtualRecordId, record] of _16.entries(modelInfo)) {
5745
+ for (const [fieldName, fieldValue] of _16.entries(record)) {
5844
5746
  const [, recordId] = virtualRecordId.split("_");
5845
- const originalFieldValue = _15.get(originalInput, [
5747
+ const originalFieldValue = _16.get(originalInput, [
5846
5748
  modelId,
5847
5749
  recordId,
5848
5750
  fieldName
@@ -5852,7 +5754,7 @@ function createDatoExtractLoader() {
5852
5754
  originalFieldValue,
5853
5755
  true
5854
5756
  );
5855
- _15.set(
5757
+ _16.set(
5856
5758
  result,
5857
5759
  [modelId, recordId, fieldName],
5858
5760
  rawValue || originalFieldValue
@@ -5865,25 +5767,25 @@ function createDatoExtractLoader() {
5865
5767
  });
5866
5768
  }
5867
5769
  function detectDatoFieldType(rawDatoValue) {
5868
- if (_15.has(rawDatoValue, "document") && _15.get(rawDatoValue, "schema") === "dast") {
5770
+ if (_16.has(rawDatoValue, "document") && _16.get(rawDatoValue, "schema") === "dast") {
5869
5771
  return "structured_text";
5870
- } else if (_15.has(rawDatoValue, "no_index") || _15.has(rawDatoValue, "twitter_card")) {
5772
+ } else if (_16.has(rawDatoValue, "no_index") || _16.has(rawDatoValue, "twitter_card")) {
5871
5773
  return "seo";
5872
- } else if (_15.get(rawDatoValue, "type") === "item") {
5774
+ } else if (_16.get(rawDatoValue, "type") === "item") {
5873
5775
  return "single_block";
5874
- } else if (_15.isArray(rawDatoValue) && _15.every(rawDatoValue, (item) => _15.get(item, "type") === "item")) {
5776
+ } else if (_16.isArray(rawDatoValue) && _16.every(rawDatoValue, (item) => _16.get(item, "type") === "item")) {
5875
5777
  return "rich_text";
5876
5778
  } else if (_isFile(rawDatoValue)) {
5877
5779
  return "file";
5878
- } else if (_15.isArray(rawDatoValue) && _15.every(rawDatoValue, (item) => _isFile(item))) {
5780
+ } else if (_16.isArray(rawDatoValue) && _16.every(rawDatoValue, (item) => _isFile(item))) {
5879
5781
  return "gallery";
5880
5782
  } else if (_isJson(rawDatoValue)) {
5881
5783
  return "json";
5882
- } else if (_15.isString(rawDatoValue)) {
5784
+ } else if (_16.isString(rawDatoValue)) {
5883
5785
  return "string";
5884
5786
  } else if (_isVideo(rawDatoValue)) {
5885
5787
  return "video";
5886
- } else if (_15.isArray(rawDatoValue) && _15.every(rawDatoValue, (item) => _15.isString(item))) {
5788
+ } else if (_16.isArray(rawDatoValue) && _16.every(rawDatoValue, (item) => _16.isString(item))) {
5887
5789
  return "ref_list";
5888
5790
  } else {
5889
5791
  return null;
@@ -5953,9 +5855,9 @@ function serializeStructuredText(rawStructuredText) {
5953
5855
  acc
5954
5856
  );
5955
5857
  }
5956
- if (!_15.isNil(node.value)) {
5858
+ if (!_16.isNil(node.value)) {
5957
5859
  acc[[...path19, "value"].join(".")] = node.value;
5958
- } else if (_15.get(node, "type") === "block") {
5860
+ } else if (_16.get(node, "type") === "block") {
5959
5861
  acc[[...path19, "item"].join(".")] = serializeBlock(node.item);
5960
5862
  }
5961
5863
  if (node.children) {
@@ -5971,48 +5873,48 @@ function serializeStructuredText(rawStructuredText) {
5971
5873
  }
5972
5874
  }
5973
5875
  function serializeSeo(rawSeo) {
5974
- return _15.chain(rawSeo).pick(["title", "description"]).value();
5876
+ return _16.chain(rawSeo).pick(["title", "description"]).value();
5975
5877
  }
5976
5878
  function serializeBlock(rawBlock) {
5977
- if (_15.get(rawBlock, "type") === "item" && _15.has(rawBlock, "id")) {
5879
+ if (_16.get(rawBlock, "type") === "item" && _16.has(rawBlock, "id")) {
5978
5880
  return serializeBlock(rawBlock.attributes);
5979
5881
  }
5980
5882
  const result = {};
5981
- for (const [attributeName, attributeValue] of _15.entries(rawBlock)) {
5883
+ for (const [attributeName, attributeValue] of _16.entries(rawBlock)) {
5982
5884
  result[attributeName] = createParsedDatoValue(attributeValue);
5983
5885
  }
5984
5886
  return result;
5985
5887
  }
5986
5888
  function serializeBlockList(rawBlockList) {
5987
- return _15.chain(rawBlockList).map((block) => serializeBlock(block)).value();
5889
+ return _16.chain(rawBlockList).map((block) => serializeBlock(block)).value();
5988
5890
  }
5989
5891
  function serializeVideo(rawVideo) {
5990
- return _15.chain(rawVideo).pick(["title"]).value();
5892
+ return _16.chain(rawVideo).pick(["title"]).value();
5991
5893
  }
5992
5894
  function serializeFile(rawFile) {
5993
- return _15.chain(rawFile).pick(["alt", "title"]).value();
5895
+ return _16.chain(rawFile).pick(["alt", "title"]).value();
5994
5896
  }
5995
5897
  function serializeGallery(rawGallery) {
5996
- return _15.chain(rawGallery).map((item) => serializeFile(item)).value();
5898
+ return _16.chain(rawGallery).map((item) => serializeFile(item)).value();
5997
5899
  }
5998
5900
  function deserializeFile(parsedFile, originalRawFile) {
5999
- return _15.chain(parsedFile).defaults(originalRawFile).value();
5901
+ return _16.chain(parsedFile).defaults(originalRawFile).value();
6000
5902
  }
6001
5903
  function deserializeGallery(parsedGallery, originalRawGallery) {
6002
- return _15.chain(parsedGallery).map((item, i) => deserializeFile(item, originalRawGallery[i])).value();
5904
+ return _16.chain(parsedGallery).map((item, i) => deserializeFile(item, originalRawGallery[i])).value();
6003
5905
  }
6004
5906
  function deserializeVideo(parsedVideo, originalRawVideo) {
6005
- return _15.chain(parsedVideo).defaults(originalRawVideo).value();
5907
+ return _16.chain(parsedVideo).defaults(originalRawVideo).value();
6006
5908
  }
6007
5909
  function deserializeBlock(payload, rawNode, isClean = false) {
6008
- const result = _15.cloneDeep(rawNode);
6009
- for (const [attributeName, attributeValue] of _15.entries(rawNode.attributes)) {
5910
+ const result = _16.cloneDeep(rawNode);
5911
+ for (const [attributeName, attributeValue] of _16.entries(rawNode.attributes)) {
6010
5912
  const rawValue = createRawDatoValue(
6011
5913
  payload[attributeName],
6012
5914
  attributeValue,
6013
5915
  isClean
6014
5916
  );
6015
- _15.set(result, ["attributes", attributeName], rawValue);
5917
+ _16.set(result, ["attributes", attributeName], rawValue);
6016
5918
  }
6017
5919
  if (isClean) {
6018
5920
  delete result["id"];
@@ -6020,40 +5922,40 @@ function deserializeBlock(payload, rawNode, isClean = false) {
6020
5922
  return result;
6021
5923
  }
6022
5924
  function deserializeSeo(parsedSeo, originalRawSeo) {
6023
- return _15.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
5925
+ return _16.chain(parsedSeo).pick(["title", "description"]).defaults(originalRawSeo).value();
6024
5926
  }
6025
5927
  function deserializeBlockList(parsedBlockList, originalRawBlockList, isClean = false) {
6026
- return _15.chain(parsedBlockList).map(
5928
+ return _16.chain(parsedBlockList).map(
6027
5929
  (block, i) => deserializeBlock(block, originalRawBlockList[i], isClean)
6028
5930
  ).value();
6029
5931
  }
6030
5932
  function deserializeStructuredText(parsedStructuredText, originalRawStructuredText) {
6031
- const result = _15.cloneDeep(originalRawStructuredText);
6032
- for (const [path19, value] of _15.entries(parsedStructuredText)) {
6033
- const realPath = _15.chain(path19.split(".")).flatMap((s) => !_15.isNaN(_15.toNumber(s)) ? ["children", s] : s).value();
5933
+ const result = _16.cloneDeep(originalRawStructuredText);
5934
+ for (const [path19, value] of _16.entries(parsedStructuredText)) {
5935
+ const realPath = _16.chain(path19.split(".")).flatMap((s) => !_16.isNaN(_16.toNumber(s)) ? ["children", s] : s).value();
6034
5936
  const deserializedValue = createRawDatoValue(
6035
5937
  value,
6036
- _15.get(originalRawStructuredText, realPath),
5938
+ _16.get(originalRawStructuredText, realPath),
6037
5939
  true
6038
5940
  );
6039
- _15.set(result, realPath, deserializedValue);
5941
+ _16.set(result, realPath, deserializedValue);
6040
5942
  }
6041
5943
  return result;
6042
5944
  }
6043
5945
  function _isJson(rawDatoValue) {
6044
5946
  try {
6045
- return _15.isString(rawDatoValue) && rawDatoValue.startsWith("{") && rawDatoValue.endsWith("}") && !!JSON.parse(rawDatoValue);
5947
+ return _16.isString(rawDatoValue) && rawDatoValue.startsWith("{") && rawDatoValue.endsWith("}") && !!JSON.parse(rawDatoValue);
6046
5948
  } catch (e) {
6047
5949
  return false;
6048
5950
  }
6049
5951
  }
6050
5952
  function _isFile(rawDatoValue) {
6051
- return _15.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every(
6052
- (key) => _15.has(rawDatoValue, key)
5953
+ return _16.isObject(rawDatoValue) && ["alt", "title", "custom_data", "focal_point", "upload_id"].every(
5954
+ (key) => _16.has(rawDatoValue, key)
6053
5955
  );
6054
5956
  }
6055
5957
  function _isVideo(rawDatoValue) {
6056
- return _15.isObject(rawDatoValue) && [
5958
+ return _16.isObject(rawDatoValue) && [
6057
5959
  "url",
6058
5960
  "title",
6059
5961
  "width",
@@ -6061,7 +5963,7 @@ function _isVideo(rawDatoValue) {
6061
5963
  "provider",
6062
5964
  "provider_uid",
6063
5965
  "thumbnail_url"
6064
- ].every((key) => _15.has(rawDatoValue, key));
5966
+ ].every((key) => _16.has(rawDatoValue, key));
6065
5967
  }
6066
5968
 
6067
5969
  // src/cli/loaders/dato/index.ts
@@ -6131,7 +6033,7 @@ function createVttLoader() {
6131
6033
  }
6132
6034
 
6133
6035
  // src/cli/loaders/variable/index.ts
6134
- import _16 from "lodash";
6036
+ import _17 from "lodash";
6135
6037
  function createVariableLoader(params) {
6136
6038
  return composeLoaders(variableExtractLoader(params), variableContentLoader());
6137
6039
  }
@@ -6140,18 +6042,9 @@ function variableExtractLoader(params) {
6140
6042
  return createLoader({
6141
6043
  pull: async (locale, input2, initXtx, originalLocale, originalInput) => {
6142
6044
  const result = {};
6143
- const inputValues = _16.omitBy(input2, _16.isEmpty);
6045
+ const inputValues = _17.omitBy(input2, _17.isEmpty);
6144
6046
  for (const [key, value] of Object.entries(inputValues)) {
6145
6047
  const originalValue = originalInput[key];
6146
- if (isICUPluralObject(originalValue)) {
6147
- const icuValue = isICUPluralObject(value) ? { icu: value.icu } : value;
6148
- result[key] = {
6149
- value: icuValue,
6150
- variables: []
6151
- // Metadata stored separately, not in variables
6152
- };
6153
- continue;
6154
- }
6155
6048
  const matches = originalValue.match(specifierPattern) || [];
6156
6049
  result[key] = result[key] || {
6157
6050
  value,
@@ -6171,19 +6064,14 @@ function variableExtractLoader(params) {
6171
6064
  const result = {};
6172
6065
  for (const [key, valueObj] of Object.entries(data)) {
6173
6066
  result[key] = valueObj.value;
6174
- const resultValue = result[key];
6175
- if (isICUPluralObject(resultValue)) {
6176
- const originalValue = originalInput?.[key];
6177
- if (isICUPluralObject(originalValue) && originalValue._meta) {
6178
- resultValue._meta = originalValue._meta;
6179
- resultValue[Symbol.for("@lingo.dev/icu-plural-object")] = true;
6180
- }
6181
- }
6182
6067
  for (let i = 0; i < valueObj.variables.length; i++) {
6183
6068
  const variable = valueObj.variables[i];
6184
6069
  const currentValue = result[key];
6185
6070
  if (typeof currentValue === "string") {
6186
- const newValue = currentValue?.replace(`{variable:${i}}`, variable);
6071
+ const newValue = currentValue?.replaceAll(
6072
+ `{variable:${i}}`,
6073
+ variable
6074
+ );
6187
6075
  result[key] = newValue;
6188
6076
  }
6189
6077
  }
@@ -6195,11 +6083,11 @@ function variableExtractLoader(params) {
6195
6083
  function variableContentLoader() {
6196
6084
  return createLoader({
6197
6085
  pull: async (locale, input2) => {
6198
- const result = _16.mapValues(input2, (payload) => payload.value);
6086
+ const result = _17.mapValues(input2, (payload) => payload.value);
6199
6087
  return result;
6200
6088
  },
6201
6089
  push: async (locale, data, originalInput, defaultLocale, pullInput) => {
6202
- const result = _16.cloneDeep(
6090
+ const result = _17.cloneDeep(
6203
6091
  originalInput || {}
6204
6092
  );
6205
6093
  for (const [key, originalValueObj] of Object.entries(result)) {
@@ -6224,20 +6112,20 @@ function getFormatSpecifierPattern(type) {
6224
6112
  }
6225
6113
 
6226
6114
  // src/cli/loaders/sync.ts
6227
- import _17 from "lodash";
6115
+ import _18 from "lodash";
6228
6116
  function createSyncLoader() {
6229
6117
  return createLoader({
6230
6118
  async pull(locale, input2, initCtx, originalLocale, originalInput) {
6231
6119
  if (!originalInput) {
6232
6120
  return input2;
6233
6121
  }
6234
- return _17.chain(originalInput).mapValues((value, key) => input2[key]).value();
6122
+ return _18.chain(originalInput).mapValues((value, key) => input2[key]).value();
6235
6123
  },
6236
6124
  async push(locale, data, originalInput) {
6237
6125
  if (!originalInput) {
6238
6126
  return data;
6239
6127
  }
6240
- return _17.chain(originalInput || {}).mapValues((value, key) => data[key]).value();
6128
+ return _18.chain(originalInput || {}).mapValues((value, key) => data[key]).value();
6241
6129
  }
6242
6130
  });
6243
6131
  }
@@ -6419,7 +6307,7 @@ function parseVueFile(input2) {
6419
6307
 
6420
6308
  // src/cli/loaders/typescript/index.ts
6421
6309
  import { parse as parse3 } from "@babel/parser";
6422
- import _18 from "lodash";
6310
+ import _19 from "lodash";
6423
6311
  import babelTraverseModule from "@babel/traverse";
6424
6312
  import * as t from "@babel/types";
6425
6313
  import babelGenerateModule from "@babel/generator";
@@ -6455,7 +6343,7 @@ function createTypescriptLoader() {
6455
6343
  },
6456
6344
  push: async (locale, data, originalInput, defaultLocale, pullInput, pullOutput) => {
6457
6345
  const ast = parseTypeScript(originalInput || "");
6458
- const finalData = _18.merge({}, pullOutput, data);
6346
+ const finalData = _19.merge({}, pullOutput, data);
6459
6347
  updateStringsInDefaultExport(ast, finalData);
6460
6348
  const { code } = generate(ast, {
6461
6349
  jsescOption: {
@@ -6656,7 +6544,7 @@ function getPropertyKey(prop) {
6656
6544
  }
6657
6545
 
6658
6546
  // src/cli/loaders/inject-locale.ts
6659
- import _19 from "lodash";
6547
+ import _20 from "lodash";
6660
6548
 
6661
6549
  // ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
6662
6550
  var balanced = (a, b, str) => {
@@ -7347,7 +7235,7 @@ var AST = class _AST {
7347
7235
  if (!this.type) {
7348
7236
  const noEmpty = this.isStart() && this.isEnd();
7349
7237
  const src = this.#parts.map((p) => {
7350
- const [re, _36, hasMagic, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
7238
+ const [re, _37, hasMagic, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
7351
7239
  this.#hasMagic = this.#hasMagic || hasMagic;
7352
7240
  this.#uflag = this.#uflag || uflag;
7353
7241
  return re;
@@ -7420,7 +7308,7 @@ var AST = class _AST {
7420
7308
  if (typeof p === "string") {
7421
7309
  throw new Error("string type in extglob ast??");
7422
7310
  }
7423
- const [re, _36, _hasMagic, uflag] = p.toRegExpSource(dot);
7311
+ const [re, _37, _hasMagic, uflag] = p.toRegExpSource(dot);
7424
7312
  this.#uflag = this.#uflag || uflag;
7425
7313
  return re;
7426
7314
  }).filter((p) => !(this.isStart() && this.isEnd()) || !!p).join("|");
@@ -7665,7 +7553,7 @@ var Minimatch = class {
7665
7553
  }
7666
7554
  return false;
7667
7555
  }
7668
- debug(..._36) {
7556
+ debug(..._37) {
7669
7557
  }
7670
7558
  make() {
7671
7559
  const pattern = this.pattern;
@@ -7687,7 +7575,7 @@ var Minimatch = class {
7687
7575
  const rawGlobParts = this.globSet.map((s) => this.slashSplit(s));
7688
7576
  this.globParts = this.preprocess(rawGlobParts);
7689
7577
  this.debug(this.pattern, this.globParts);
7690
- let set = this.globParts.map((s, _36, __) => {
7578
+ let set = this.globParts.map((s, _37, __) => {
7691
7579
  if (this.isWindows && this.windowsNoMagicRoot) {
7692
7580
  const isUNC = s[0] === "" && s[1] === "" && (s[2] === "?" || !globMagic.test(s[2])) && !globMagic.test(s[3]);
7693
7581
  const isDrive = /^[a-z]:/i.test(s[0]);
@@ -8204,7 +8092,7 @@ function createInjectLocaleLoader(injectLocaleKeys) {
8204
8092
  return data;
8205
8093
  }
8206
8094
  const omitKeys = _getKeysWithLocales(data, injectLocaleKeys, locale);
8207
- const result = _19.omit(data, omitKeys);
8095
+ const result = _20.omit(data, omitKeys);
8208
8096
  return result;
8209
8097
  },
8210
8098
  async push(locale, data, originalInput, originalLocale) {
@@ -8217,7 +8105,7 @@ function createInjectLocaleLoader(injectLocaleKeys) {
8217
8105
  originalLocale
8218
8106
  );
8219
8107
  localeKeys.forEach((key) => {
8220
- _19.set(data, key, locale);
8108
+ _20.set(data, key, locale);
8221
8109
  });
8222
8110
  return data;
8223
8111
  }
@@ -8226,7 +8114,7 @@ function createInjectLocaleLoader(injectLocaleKeys) {
8226
8114
  function _getKeysWithLocales(data, injectLocaleKeys, locale) {
8227
8115
  const allKeys = _getAllKeys(data);
8228
8116
  return allKeys.filter((key) => {
8229
- return injectLocaleKeys.some((pattern) => minimatch(key, pattern)) && _19.get(data, key) === locale;
8117
+ return injectLocaleKeys.some((pattern) => minimatch(key, pattern)) && _20.get(data, key) === locale;
8230
8118
  });
8231
8119
  }
8232
8120
  function _getAllKeys(obj, prefix = "") {
@@ -8244,7 +8132,7 @@ function _getAllKeys(obj, prefix = "") {
8244
8132
  }
8245
8133
 
8246
8134
  // src/cli/loaders/locked-keys.ts
8247
- import _20 from "lodash";
8135
+ import _21 from "lodash";
8248
8136
 
8249
8137
  // src/cli/utils/key-matching.ts
8250
8138
  function matchesKeyPattern(key, patterns) {
@@ -8263,14 +8151,14 @@ function formatDisplayValue(value, maxLength = 50) {
8263
8151
  function createLockedKeysLoader(lockedKeys) {
8264
8152
  return createLoader({
8265
8153
  pull: async (locale, data) => {
8266
- return _20.pickBy(
8154
+ return _21.pickBy(
8267
8155
  data,
8268
8156
  (value, key) => !matchesKeyPattern(key, lockedKeys)
8269
8157
  );
8270
8158
  },
8271
8159
  push: async (locale, data, originalInput) => {
8272
- const lockedSubObject = _20.chain(originalInput).pickBy((value, key) => matchesKeyPattern(key, lockedKeys)).value();
8273
- return _20.merge({}, data, lockedSubObject);
8160
+ const lockedSubObject = _21.chain(originalInput).pickBy((value, key) => matchesKeyPattern(key, lockedKeys)).value();
8161
+ return _21.merge({}, data, lockedSubObject);
8274
8162
  }
8275
8163
  });
8276
8164
  }
@@ -8322,7 +8210,7 @@ function md5(input2) {
8322
8210
  }
8323
8211
 
8324
8212
  // src/cli/loaders/mdx2/code-placeholder.ts
8325
- import _21 from "lodash";
8213
+ import _22 from "lodash";
8326
8214
  var fenceRegex = /([ \t]*)(^>\s*)?```([\s\S]*?)```/gm;
8327
8215
  var inlineCodeRegex = /(?<!`)`([^`\r\n]+?)`(?!`)/g;
8328
8216
  var imageRegex = /([ \t]*)(^>\s*)?!\[[^\]]*?\]\(([^()]*(\([^()]*\)[^()]*)*)\)/gm;
@@ -8345,7 +8233,7 @@ ${match2}
8345
8233
  found = true;
8346
8234
  }
8347
8235
  } while (found);
8348
- content = _21.chain(content).split("\n\n").map((section) => _21.trim(section, "\n")).filter(Boolean).join("\n\n").value();
8236
+ content = _22.chain(content).split("\n\n").map((section) => _22.trim(section, "\n")).filter(Boolean).join("\n\n").value();
8349
8237
  return content;
8350
8238
  }
8351
8239
  function ensureTrailingFenceNewline(_content) {
@@ -8367,7 +8255,7 @@ ${match2}
8367
8255
  found = true;
8368
8256
  }
8369
8257
  } while (found);
8370
- content = _21.chain(content).split("\n\n").map((section) => _21.trim(section, "\n")).filter(Boolean).join("\n\n").value();
8258
+ content = _22.chain(content).split("\n\n").map((section) => _22.trim(section, "\n")).filter(Boolean).join("\n\n").value();
8371
8259
  return content;
8372
8260
  }
8373
8261
  function extractCodePlaceholders(content) {
@@ -8409,7 +8297,7 @@ function createMdxCodePlaceholderLoader() {
8409
8297
  async push(locale, data, originalInput, originalLocale, pullInput) {
8410
8298
  const sourceInfo = extractCodePlaceholders(originalInput ?? "");
8411
8299
  const currentInfo = extractCodePlaceholders(pullInput ?? "");
8412
- const codePlaceholders = _21.merge(
8300
+ const codePlaceholders = _22.merge(
8413
8301
  sourceInfo.codePlaceholders,
8414
8302
  currentInfo.codePlaceholders,
8415
8303
  globalPlaceholderRegistry
@@ -8417,7 +8305,7 @@ function createMdxCodePlaceholderLoader() {
8417
8305
  );
8418
8306
  let result = data;
8419
8307
  for (const [placeholder, original] of Object.entries(codePlaceholders)) {
8420
- const replacement = original.startsWith(">") ? _21.trimStart(original, "> ") : original;
8308
+ const replacement = original.startsWith(">") ? _22.trimStart(original, "> ") : original;
8421
8309
  result = result.replaceAll(placeholder, () => replacement);
8422
8310
  }
8423
8311
  return result;
@@ -8445,11 +8333,11 @@ function createLocalizableMdxDocumentLoader() {
8445
8333
  }
8446
8334
 
8447
8335
  // src/cli/loaders/mdx2/sections-split-2.ts
8448
- import _22 from "lodash";
8336
+ import _23 from "lodash";
8449
8337
  function createMdxSectionsSplit2Loader() {
8450
8338
  return createLoader({
8451
8339
  async pull(locale, input2) {
8452
- const sections = _22.chain(input2.content).split("\n\n").filter(Boolean).map((section, index) => [index, section]).fromPairs().value();
8340
+ const sections = _23.chain(input2.content).split("\n\n").filter(Boolean).map((section, index) => [index, section]).fromPairs().value();
8453
8341
  const result = {
8454
8342
  frontmatter: input2.frontmatter,
8455
8343
  sections
@@ -8457,7 +8345,7 @@ function createMdxSectionsSplit2Loader() {
8457
8345
  return result;
8458
8346
  },
8459
8347
  async push(locale, data, originalInput, _originalLocale, pullInput) {
8460
- const content = _22.chain(data.sections).values().join("\n\n").value();
8348
+ const content = _23.chain(data.sections).values().join("\n\n").value();
8461
8349
  const result = {
8462
8350
  frontmatter: data.frontmatter,
8463
8351
  codePlaceholders: pullInput?.codePlaceholders || {},
@@ -8523,18 +8411,18 @@ function createLockedPatternsLoader(defaultPatterns) {
8523
8411
  }
8524
8412
 
8525
8413
  // src/cli/loaders/ignored-keys.ts
8526
- import _23 from "lodash";
8414
+ import _24 from "lodash";
8527
8415
  function createIgnoredKeysLoader(ignoredKeys) {
8528
8416
  return createLoader({
8529
8417
  pull: async (locale, data) => {
8530
- const result = _23.omitBy(
8418
+ const result = _24.omitBy(
8531
8419
  data,
8532
8420
  (value, key) => matchesKeyPattern(key, ignoredKeys)
8533
8421
  );
8534
8422
  return result;
8535
8423
  },
8536
8424
  push: async (locale, data, originalInput, originalLocale, pullInput) => {
8537
- const result = _23.omitBy(
8425
+ const result = _24.omitBy(
8538
8426
  data,
8539
8427
  (value, key) => matchesKeyPattern(key, ignoredKeys)
8540
8428
  );
@@ -8675,7 +8563,7 @@ function createEjsLoader() {
8675
8563
  }
8676
8564
 
8677
8565
  // src/cli/loaders/ensure-key-order.ts
8678
- import _24 from "lodash";
8566
+ import _25 from "lodash";
8679
8567
  function createEnsureKeyOrderLoader() {
8680
8568
  return createLoader({
8681
8569
  pull: async (_locale, input2) => {
@@ -8690,10 +8578,10 @@ function createEnsureKeyOrderLoader() {
8690
8578
  });
8691
8579
  }
8692
8580
  function reorderKeys(data, originalInput) {
8693
- if (_24.isArray(originalInput) && _24.isArray(data)) {
8581
+ if (_25.isArray(originalInput) && _25.isArray(data)) {
8694
8582
  return data.map((item, idx) => reorderKeys(item, originalInput[idx] ?? {}));
8695
8583
  }
8696
- if (!_24.isObject(data) || _24.isArray(data) || _24.isDate(data)) {
8584
+ if (!_25.isObject(data) || _25.isArray(data) || _25.isDate(data)) {
8697
8585
  return data;
8698
8586
  }
8699
8587
  const orderedData = {};
@@ -8725,13 +8613,13 @@ function createTxtLoader() {
8725
8613
  const sortedEntries = Object.entries(payload).sort(
8726
8614
  ([a], [b]) => parseInt(a) - parseInt(b)
8727
8615
  );
8728
- return sortedEntries.map(([_36, value]) => value).join("\n");
8616
+ return sortedEntries.map(([_37, value]) => value).join("\n");
8729
8617
  }
8730
8618
  });
8731
8619
  }
8732
8620
 
8733
8621
  // src/cli/loaders/json-dictionary.ts
8734
- import _25 from "lodash";
8622
+ import _26 from "lodash";
8735
8623
  var TOP_LEVEL_KEY = "--content--";
8736
8624
  function createJsonDictionaryLoader() {
8737
8625
  return createLoader({
@@ -8746,7 +8634,7 @@ function createJsonDictionaryLoader() {
8746
8634
  if (!originalInput) {
8747
8635
  throw new Error("Error while parsing json-dictionary bucket");
8748
8636
  }
8749
- const input2 = _25.cloneDeep(originalInput);
8637
+ const input2 = _26.cloneDeep(originalInput);
8750
8638
  if (Object.keys(data).length === 1 && Object.keys(data)[0] === TOP_LEVEL_KEY) {
8751
8639
  setNestedLocale(
8752
8640
  { [TOP_LEVEL_KEY]: input2 },
@@ -9016,9 +8904,8 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
9016
8904
  createPlutilJsonTextLoader(),
9017
8905
  createLockedPatternsLoader(lockedPatterns),
9018
8906
  createJsonLoader(),
9019
- createXcodeXcstringsLoader(options.defaultLocale),
9020
8907
  createXcodeXcstringsV2Loader(options.defaultLocale),
9021
- createFlatLoader({ shouldPreserveObject: isICUPluralObject }),
8908
+ createFlatLoader(),
9022
8909
  createEnsureKeyOrderLoader(),
9023
8910
  createLockedKeysLoader(lockedKeys || []),
9024
8911
  createIgnoredKeysLoader(ignoredKeys || []),
@@ -9327,7 +9214,7 @@ import { Command as Command13 } from "interactive-commander";
9327
9214
  import { Command as Command10 } from "interactive-commander";
9328
9215
  import chalk2 from "chalk";
9329
9216
  import dedent from "dedent";
9330
- import _26 from "lodash";
9217
+ import _27 from "lodash";
9331
9218
  var set_default = new Command10().name("set").description("Set or update a CLI setting in ~/.lingodotdevrc").addHelpText("afterAll", `
9332
9219
  Available keys:
9333
9220
  ${SETTINGS_KEYS.join("\n ")}`).argument(
@@ -9345,8 +9232,8 @@ Available keys:
9345
9232
  return;
9346
9233
  }
9347
9234
  const current = loadSystemSettings();
9348
- const updated = _26.cloneDeep(current);
9349
- _26.set(updated, key, value);
9235
+ const updated = _27.cloneDeep(current);
9236
+ _27.set(updated, key, value);
9350
9237
  try {
9351
9238
  saveSettings(updated);
9352
9239
  console.log(`${chalk2.green("\u2714")} Set ${chalk2.bold(key)}`);
@@ -9366,7 +9253,7 @@ Available keys:
9366
9253
  import { Command as Command11 } from "interactive-commander";
9367
9254
  import chalk3 from "chalk";
9368
9255
  import dedent2 from "dedent";
9369
- import _27 from "lodash";
9256
+ import _28 from "lodash";
9370
9257
  var unset_default = new Command11().name("unset").description("Remove a CLI setting from ~/.lingodotdevrc").addHelpText("afterAll", `
9371
9258
  Available keys:
9372
9259
  ${SETTINGS_KEYS.join("\n ")}`).argument(
@@ -9386,13 +9273,13 @@ Available keys:
9386
9273
  return;
9387
9274
  }
9388
9275
  const settings = loadSystemSettings();
9389
- const currentValue = _27.get(settings, key);
9390
- if (!_27.trim(String(currentValue || ""))) {
9276
+ const currentValue = _28.get(settings, key);
9277
+ if (!_28.trim(String(currentValue || ""))) {
9391
9278
  console.log(`${chalk3.cyan("\u2139")} ${chalk3.bold(key)} is not set.`);
9392
9279
  return;
9393
9280
  } else {
9394
- const updated = _27.cloneDeep(settings);
9395
- _27.unset(updated, key);
9281
+ const updated = _28.cloneDeep(settings);
9282
+ _28.unset(updated, key);
9396
9283
  try {
9397
9284
  saveSettings(updated);
9398
9285
  console.log(
@@ -9414,7 +9301,7 @@ Available keys:
9414
9301
  // src/cli/cmd/config/get.ts
9415
9302
  import { Command as Command12 } from "interactive-commander";
9416
9303
  import chalk4 from "chalk";
9417
- import _28 from "lodash";
9304
+ import _29 from "lodash";
9418
9305
  import dedent3 from "dedent";
9419
9306
  var get_default = new Command12().name("get").description("Display the value of a CLI setting from ~/.lingodotdevrc").addHelpText("afterAll", `
9420
9307
  Available keys:
@@ -9433,7 +9320,7 @@ Available keys:
9433
9320
  return;
9434
9321
  }
9435
9322
  const settings = loadSystemSettings();
9436
- const value = _28.get(settings, key);
9323
+ const value = _29.get(settings, key);
9437
9324
  if (!value) {
9438
9325
  console.log(`${chalk4.cyan("\u2139")} ${chalk4.bold(key)} is not set.`);
9439
9326
  return;
@@ -9458,7 +9345,7 @@ import {
9458
9345
  } from "@lingo.dev/_spec";
9459
9346
  import { Command as Command14 } from "interactive-commander";
9460
9347
  import Z3 from "zod";
9461
- import _31 from "lodash";
9348
+ import _32 from "lodash";
9462
9349
  import Ora9 from "ora";
9463
9350
  import chalk6 from "chalk";
9464
9351
  import { createTwoFilesPatch } from "diff";
@@ -9498,7 +9385,7 @@ function createLingoLocalizer(params) {
9498
9385
 
9499
9386
  // src/cli/processor/basic.ts
9500
9387
  import { generateText } from "ai";
9501
- import _29 from "lodash";
9388
+ import _30 from "lodash";
9502
9389
  function createBasicTranslator(model, systemPrompt, settings = {}) {
9503
9390
  return async (input2, onProgress) => {
9504
9391
  const chunks = extractPayloadChunks(input2.processableData);
@@ -9512,7 +9399,7 @@ function createBasicTranslator(model, systemPrompt, settings = {}) {
9512
9399
  subResults.push(result2);
9513
9400
  onProgress(i / chunks.length * 100, chunk, result2);
9514
9401
  }
9515
- const result = _29.merge({}, ...subResults);
9402
+ const result = _30.merge({}, ...subResults);
9516
9403
  return result;
9517
9404
  };
9518
9405
  async function doJob(input2) {
@@ -9789,7 +9676,7 @@ function trackEvent(distinctId, event, properties) {
9789
9676
  }
9790
9677
 
9791
9678
  // src/cli/utils/delta.ts
9792
- import _30 from "lodash";
9679
+ import _31 from "lodash";
9793
9680
  import z from "zod";
9794
9681
 
9795
9682
  // src/cli/utils/fs.ts
@@ -9838,11 +9725,11 @@ function createDeltaProcessor(fileKey) {
9838
9725
  return checkIfFileExists(lockfilePath);
9839
9726
  },
9840
9727
  async calculateDelta(params) {
9841
- let added = _30.difference(
9728
+ let added = _31.difference(
9842
9729
  Object.keys(params.sourceData),
9843
9730
  Object.keys(params.targetData)
9844
9731
  );
9845
- let removed = _30.difference(
9732
+ let removed = _31.difference(
9846
9733
  Object.keys(params.targetData),
9847
9734
  Object.keys(params.sourceData)
9848
9735
  );
@@ -9904,12 +9791,41 @@ function createDeltaProcessor(fileKey) {
9904
9791
  await this.saveLock(lockfileData);
9905
9792
  },
9906
9793
  async createChecksums(sourceData) {
9907
- const checksums = _30.mapValues(sourceData, (value) => md5(value));
9794
+ const checksums = _31.mapValues(sourceData, (value) => md5(value));
9908
9795
  return checksums;
9909
9796
  }
9910
9797
  };
9911
9798
  }
9912
9799
 
9800
+ // src/cli/loaders/xcode-xcstrings-icu.ts
9801
+ var ICU_TYPE_MARKER = Symbol.for("@lingo.dev/icu-plural-object");
9802
+ function isICUPluralObject(value) {
9803
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
9804
+ return false;
9805
+ }
9806
+ if (ICU_TYPE_MARKER in value) {
9807
+ return true;
9808
+ }
9809
+ if (!("icu" in value) || typeof value.icu !== "string") {
9810
+ return false;
9811
+ }
9812
+ const icuPluralPattern = /^\{[\w]+,\s*plural,\s*.+\}$/;
9813
+ if (!icuPluralPattern.test(value.icu)) {
9814
+ return false;
9815
+ }
9816
+ if (value._meta !== void 0) {
9817
+ if (typeof value._meta !== "object" || !value._meta.variables || typeof value._meta.variables !== "object") {
9818
+ return false;
9819
+ }
9820
+ for (const [varName, varMeta] of Object.entries(value._meta.variables)) {
9821
+ if (!varMeta || typeof varMeta !== "object" || typeof varMeta.format !== "string" || varMeta.role !== "plural" && varMeta.role !== "other") {
9822
+ return false;
9823
+ }
9824
+ }
9825
+ }
9826
+ return true;
9827
+ }
9828
+
9913
9829
  // src/cli/cmd/i18n.ts
9914
9830
  var i18n_default = new Command14().command("i18n").description(
9915
9831
  "DEPRECATED: Run localization pipeline (prefer `run` command instead)"
@@ -10097,7 +10013,7 @@ var i18n_default = new Command14().command("i18n").description(
10097
10013
  const deltaProcessor = createDeltaProcessor(bucketPath.pathPattern);
10098
10014
  const sourceChecksums = await deltaProcessor.createChecksums(sourceData);
10099
10015
  const savedChecksums = await deltaProcessor.loadChecksums();
10100
- const updatedSourceData = _31.pickBy(
10016
+ const updatedSourceData = _32.pickBy(
10101
10017
  sourceData,
10102
10018
  (value, key) => sourceChecksums[key] !== savedChecksums[key]
10103
10019
  );
@@ -10111,15 +10027,15 @@ var i18n_default = new Command14().command("i18n").description(
10111
10027
  bucketPath.delimiter
10112
10028
  );
10113
10029
  const { unlocalizable: targetUnlocalizable, ...targetData } = await bucketLoader.pull(targetLocale);
10114
- const missingKeys = _31.difference(
10030
+ const missingKeys = _32.difference(
10115
10031
  Object.keys(sourceData),
10116
10032
  Object.keys(targetData)
10117
10033
  );
10118
- const extraKeys = _31.difference(
10034
+ const extraKeys = _32.difference(
10119
10035
  Object.keys(targetData),
10120
10036
  Object.keys(sourceData)
10121
10037
  );
10122
- const unlocalizableDataDiff = !_31.isEqual(
10038
+ const unlocalizableDataDiff = !_32.isEqual(
10123
10039
  sourceUnlocalizable,
10124
10040
  targetUnlocalizable
10125
10041
  );
@@ -10203,13 +10119,13 @@ var i18n_default = new Command14().command("i18n").description(
10203
10119
  targetData,
10204
10120
  checksums: checksums2
10205
10121
  });
10206
- let processableData = _31.chain(sourceData).entries().filter(
10122
+ let processableData = _32.chain(sourceData).entries().filter(
10207
10123
  ([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!flags.force
10208
10124
  ).fromPairs().value();
10209
10125
  if (flags.key) {
10210
- processableData = _31.pickBy(
10126
+ processableData = _32.pickBy(
10211
10127
  processableData,
10212
- (_36, key) => key === flags.key
10128
+ (_37, key) => key === flags.key
10213
10129
  );
10214
10130
  }
10215
10131
  if (flags.verbose) {
@@ -10242,13 +10158,13 @@ var i18n_default = new Command14().command("i18n").description(
10242
10158
  if (flags.verbose) {
10243
10159
  bucketOra.info(JSON.stringify(processedTargetData, null, 2));
10244
10160
  }
10245
- let finalTargetData = _31.merge(
10161
+ let finalTargetData = _32.merge(
10246
10162
  {},
10247
10163
  sourceData,
10248
10164
  targetData,
10249
10165
  processedTargetData
10250
10166
  );
10251
- finalTargetData = _31.chain(finalTargetData).entries().map(([key, value]) => {
10167
+ finalTargetData = _32.chain(finalTargetData).entries().map(([key, value]) => {
10252
10168
  const renaming = delta.renamed.find(
10253
10169
  ([oldKey, newKey]) => oldKey === key
10254
10170
  );
@@ -10272,10 +10188,10 @@ var i18n_default = new Command14().command("i18n").description(
10272
10188
  `Applying changes to ${bucketPath} (${targetLocale})`
10273
10189
  );
10274
10190
  }
10275
- const finalDiffSize = _31.chain(finalTargetData).omitBy((value, key) => {
10191
+ const finalDiffSize = _32.chain(finalTargetData).omitBy((value, key) => {
10276
10192
  const targetValue = targetData[key];
10277
10193
  if (isICUPluralObject(value) && isICUPluralObject(targetValue)) {
10278
- return _31.isEqual(
10194
+ return _32.isEqual(
10279
10195
  { icu: value.icu, _meta: value._meta },
10280
10196
  { icu: targetValue.icu, _meta: targetValue._meta }
10281
10197
  );
@@ -10512,7 +10428,7 @@ Reviewing changes for ${chalk6.blue(args.pathPattern)} (${chalk6.yellow(
10512
10428
  return args.currentData;
10513
10429
  }
10514
10430
  const customData = { ...args.currentData };
10515
- const changes = _31.reduce(
10431
+ const changes = _32.reduce(
10516
10432
  args.proposedData,
10517
10433
  (result, value, key) => {
10518
10434
  if (args.currentData[key] !== value) {
@@ -10585,7 +10501,7 @@ import path16 from "path";
10585
10501
  import Z4 from "zod";
10586
10502
  import YAML6 from "yaml";
10587
10503
  import { MD5 as MD52 } from "object-hash";
10588
- import _32 from "lodash";
10504
+ import _33 from "lodash";
10589
10505
  function createLockfileHelper() {
10590
10506
  return {
10591
10507
  isLockfileExists: () => {
@@ -10595,18 +10511,18 @@ function createLockfileHelper() {
10595
10511
  registerSourceData: (pathPattern, sourceData) => {
10596
10512
  const lockfile = _loadLockfile();
10597
10513
  const sectionKey = MD52(pathPattern);
10598
- const sectionChecksums = _32.mapValues(sourceData, (value) => MD52(value));
10514
+ const sectionChecksums = _33.mapValues(sourceData, (value) => MD52(value));
10599
10515
  lockfile.checksums[sectionKey] = sectionChecksums;
10600
10516
  _saveLockfile(lockfile);
10601
10517
  },
10602
10518
  registerPartialSourceData: (pathPattern, partialSourceData) => {
10603
10519
  const lockfile = _loadLockfile();
10604
10520
  const sectionKey = MD52(pathPattern);
10605
- const sectionChecksums = _32.mapValues(
10521
+ const sectionChecksums = _33.mapValues(
10606
10522
  partialSourceData,
10607
10523
  (value) => MD52(value)
10608
10524
  );
10609
- lockfile.checksums[sectionKey] = _32.merge(
10525
+ lockfile.checksums[sectionKey] = _33.merge(
10610
10526
  {},
10611
10527
  lockfile.checksums[sectionKey] ?? {},
10612
10528
  sectionChecksums
@@ -10616,9 +10532,9 @@ function createLockfileHelper() {
10616
10532
  extractUpdatedData: (pathPattern, sourceData) => {
10617
10533
  const lockfile = _loadLockfile();
10618
10534
  const sectionKey = MD52(pathPattern);
10619
- const currentChecksums = _32.mapValues(sourceData, (value) => MD52(value));
10535
+ const currentChecksums = _33.mapValues(sourceData, (value) => MD52(value));
10620
10536
  const savedChecksums = lockfile.checksums[sectionKey] || {};
10621
- const updatedData = _32.pickBy(
10537
+ const updatedData = _33.pickBy(
10622
10538
  sourceData,
10623
10539
  (value, key) => savedChecksums[key] !== currentChecksums[key]
10624
10540
  );
@@ -10711,7 +10627,7 @@ var flagsSchema = Z5.object({
10711
10627
  // src/cli/cmd/cleanup.ts
10712
10628
  import { resolveOverriddenLocale as resolveOverriddenLocale6 } from "@lingo.dev/_spec";
10713
10629
  import { Command as Command16 } from "interactive-commander";
10714
- import _33 from "lodash";
10630
+ import _34 from "lodash";
10715
10631
  import Ora11 from "ora";
10716
10632
  var cleanup_default = new Command16().command("cleanup").description(
10717
10633
  "Remove translation keys from target locales that no longer exist in the source locale"
@@ -10775,7 +10691,7 @@ var cleanup_default = new Command16().command("cleanup").description(
10775
10691
  try {
10776
10692
  const targetData = await bucketLoader.pull(targetLocale);
10777
10693
  const targetKeys = Object.keys(targetData);
10778
- const keysToRemove = _33.difference(targetKeys, sourceKeys);
10694
+ const keysToRemove = _34.difference(targetKeys, sourceKeys);
10779
10695
  if (keysToRemove.length === 0) {
10780
10696
  bucketOra.succeed(`[${targetLocale}] No keys to remove`);
10781
10697
  continue;
@@ -10790,7 +10706,7 @@ var cleanup_default = new Command16().command("cleanup").description(
10790
10706
  );
10791
10707
  }
10792
10708
  if (!options.dryRun) {
10793
- const cleanedData = _33.pick(targetData, sourceKeys);
10709
+ const cleanedData = _34.pick(targetData, sourceKeys);
10794
10710
  await bucketLoader.push(targetLocale, cleanedData);
10795
10711
  bucketOra.succeed(
10796
10712
  `[${targetLocale}] Removed ${keysToRemove.length} keys`
@@ -10853,7 +10769,7 @@ import Z6 from "zod";
10853
10769
  import { ReplexicaEngine } from "@lingo.dev/_sdk";
10854
10770
  var mcp_default = new Command17().command("mcp").description(
10855
10771
  "Start a Model Context Protocol (MCP) server for AI assistant integration"
10856
- ).helpOption("-h, --help", "Show help").action(async (_36, program) => {
10772
+ ).helpOption("-h, --help", "Show help").action(async (_37, program) => {
10857
10773
  const apiKey = program.args[0];
10858
10774
  const settings = getSettings(apiKey);
10859
10775
  if (!settings.auth.apiKey) {
@@ -11439,7 +11355,7 @@ async function plan(input2) {
11439
11355
  import chalk12 from "chalk";
11440
11356
  import { Listr as Listr3 } from "listr2";
11441
11357
  import pLimit from "p-limit";
11442
- import _34 from "lodash";
11358
+ import _35 from "lodash";
11443
11359
  var MAX_WORKER_COUNT = 10;
11444
11360
  async function execute(input2) {
11445
11361
  const effectiveConcurrency = Math.min(
@@ -11469,7 +11385,7 @@ async function execute(input2) {
11469
11385
  return;
11470
11386
  }
11471
11387
  const initialChecksumsMap = /* @__PURE__ */ new Map();
11472
- const uniqueBucketPatterns = _34.uniq(
11388
+ const uniqueBucketPatterns = _35.uniq(
11473
11389
  ctx.tasks.map((t2) => t2.bucketPathPattern)
11474
11390
  );
11475
11391
  for (const bucketPathPattern of uniqueBucketPatterns) {
@@ -11491,7 +11407,7 @@ async function execute(input2) {
11491
11407
  const workerTasks = [];
11492
11408
  for (let i = 0; i < workersCount; i++) {
11493
11409
  const assignedTasks = ctx.tasks.filter(
11494
- (_36, idx) => idx % workersCount === i
11410
+ (_37, idx) => idx % workersCount === i
11495
11411
  );
11496
11412
  workerTasks.push(
11497
11413
  createWorkerTask({
@@ -11601,7 +11517,7 @@ function createWorkerTask(args) {
11601
11517
  targetData,
11602
11518
  checksums: initialChecksums
11603
11519
  });
11604
- const processableData = _34.chain(sourceData).entries().filter(
11520
+ const processableData = _35.chain(sourceData).entries().filter(
11605
11521
  ([key, value]) => delta.added.includes(key) || delta.updated.includes(key) || !!args.ctx.flags.force
11606
11522
  ).filter(
11607
11523
  ([key]) => !assignedTask.onlyKeys.length || assignedTask.onlyKeys?.some(
@@ -11619,7 +11535,7 @@ function createWorkerTask(args) {
11619
11535
  targetLocale: assignedTask.targetLocale
11620
11536
  };
11621
11537
  }
11622
- const relevantHints = _34.pick(hints, Object.keys(processableData));
11538
+ const relevantHints = _35.pick(hints, Object.keys(processableData));
11623
11539
  const processedTargetData = await args.ctx.localizer.localize(
11624
11540
  {
11625
11541
  sourceLocale: assignedTask.sourceLocale,
@@ -11635,7 +11551,7 @@ function createWorkerTask(args) {
11635
11551
  const latestTargetData = await bucketLoader.pull(
11636
11552
  assignedTask.targetLocale
11637
11553
  );
11638
- const _partialData = _34.merge(
11554
+ const _partialData = _35.merge(
11639
11555
  {},
11640
11556
  latestTargetData,
11641
11557
  processedChunk
@@ -11655,7 +11571,7 @@ function createWorkerTask(args) {
11655
11571
  });
11656
11572
  }
11657
11573
  );
11658
- const finalTargetData = _34.merge(
11574
+ const finalTargetData = _35.merge(
11659
11575
  {},
11660
11576
  sourceData,
11661
11577
  targetData,
@@ -11704,7 +11620,7 @@ function countTasks(ctx, predicate) {
11704
11620
  ).length;
11705
11621
  }
11706
11622
  function processRenamedKeys(delta, targetData) {
11707
- return _34.chain(targetData).entries().map(([key, value]) => {
11623
+ return _35.chain(targetData).entries().map(([key, value]) => {
11708
11624
  const renaming = delta.renamed.find(([oldKey]) => oldKey === key);
11709
11625
  if (!renaming) {
11710
11626
  return [key, value];
@@ -11872,7 +11788,7 @@ var flagsSchema2 = z2.object({
11872
11788
  // src/cli/cmd/run/frozen.ts
11873
11789
  import chalk14 from "chalk";
11874
11790
  import { Listr as Listr4 } from "listr2";
11875
- import _35 from "lodash";
11791
+ import _36 from "lodash";
11876
11792
  import { resolveOverriddenLocale as resolveOverriddenLocale8 } from "@lingo.dev/_spec";
11877
11793
  async function frozen(input2) {
11878
11794
  console.log(chalk14.hex(colors.orange)("[Frozen]"));
@@ -11960,7 +11876,7 @@ async function frozen(input2) {
11960
11876
  const delta = createDeltaProcessor(bucketPath.pathPattern);
11961
11877
  const sourceChecksums = await delta.createChecksums(src);
11962
11878
  const savedChecksums = await delta.loadChecksums();
11963
- const updatedSourceData = _35.pickBy(
11879
+ const updatedSourceData = _36.pickBy(
11964
11880
  src,
11965
11881
  (value, key) => sourceChecksums[key] !== savedChecksums[key]
11966
11882
  );
@@ -11975,7 +11891,7 @@ async function frozen(input2) {
11975
11891
  bucketPath.delimiter
11976
11892
  );
11977
11893
  const { unlocalizable: tgtUnlocalizable, ...tgt } = await loader.pull(resolvedTargetLocale);
11978
- const missingKeys = _35.difference(
11894
+ const missingKeys = _36.difference(
11979
11895
  Object.keys(src),
11980
11896
  Object.keys(tgt)
11981
11897
  );
@@ -11984,7 +11900,7 @@ async function frozen(input2) {
11984
11900
  `Localization data has changed; please update i18n.lock or run without --frozen. Details: Target file is missing translations.`
11985
11901
  );
11986
11902
  }
11987
- const extraKeys = _35.difference(
11903
+ const extraKeys = _36.difference(
11988
11904
  Object.keys(tgt),
11989
11905
  Object.keys(src)
11990
11906
  );
@@ -11993,7 +11909,7 @@ async function frozen(input2) {
11993
11909
  `Localization data has changed; please update i18n.lock or run without --frozen. Details: Target file has extra translations not present in the source file.`
11994
11910
  );
11995
11911
  }
11996
- const unlocalizableDataDiff = !_35.isEqual(
11912
+ const unlocalizableDataDiff = !_36.isEqual(
11997
11913
  srcUnlocalizable,
11998
11914
  tgtUnlocalizable
11999
11915
  );
@@ -13536,7 +13452,7 @@ async function renderHero2() {
13536
13452
  // package.json
13537
13453
  var package_default = {
13538
13454
  name: "lingo.dev",
13539
- version: "0.116.1",
13455
+ version: "0.116.3",
13540
13456
  description: "Lingo.dev CLI",
13541
13457
  private: false,
13542
13458
  publishConfig: {