@empty-complete-org/medusa-product-attributes 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,6 +61,8 @@ const no$1 = "Нет";
61
61
  const upload$1 = "Загрузить";
62
62
  const uploadError$1 = "Ошибка загрузки файла";
63
63
  const fileUrl$1 = "URL файла";
64
+ const applyTemplateError$1 = "Ошибка при применении шаблона";
65
+ const createError$1 = "Ошибка при создании атрибута";
64
66
  const templates$1 = "Шаблоны атрибутов";
65
67
  const templatesDesc$1 = "Заготовки атрибутов, которые можно применить к любой категории.";
66
68
  const globals$1 = "Глобальные атрибуты";
@@ -100,6 +102,8 @@ const ru = {
100
102
  upload: upload$1,
101
103
  uploadError: uploadError$1,
102
104
  fileUrl: fileUrl$1,
105
+ applyTemplateError: applyTemplateError$1,
106
+ createError: createError$1,
103
107
  templates: templates$1,
104
108
  templatesDesc: templatesDesc$1,
105
109
  globals: globals$1,
@@ -134,6 +138,8 @@ const no = "No";
134
138
  const upload = "Upload";
135
139
  const uploadError = "Upload failed";
136
140
  const fileUrl = "File URL";
141
+ const applyTemplateError = "Failed to apply template";
142
+ const createError = "Failed to create attribute";
137
143
  const templates = "Attribute Templates";
138
144
  const templatesDesc = "Reusable attribute blueprints. Apply to any category in one click.";
139
145
  const globals = "Global Attributes";
@@ -173,6 +179,8 @@ const en = {
173
179
  upload,
174
180
  uploadError,
175
181
  fileUrl,
182
+ applyTemplateError,
183
+ createError,
176
184
  templates,
177
185
  templatesDesc,
178
186
  globals,
@@ -181,7 +189,7 @@ const en = {
181
189
  const locales = { ru, en };
182
190
  function detectLang() {
183
191
  var _a, _b, _c;
184
- if (typeof window === "undefined") return "ru";
192
+ if (typeof window === "undefined") return "en";
185
193
  const stored = window.localStorage.getItem("i18nextLng");
186
194
  if (stored) {
187
195
  const short = stored.slice(0, 2).toLowerCase();
@@ -189,8 +197,8 @@ function detectLang() {
189
197
  }
190
198
  const htmlLang = (_b = (_a = document.documentElement) == null ? void 0 : _a.lang) == null ? void 0 : _b.slice(0, 2).toLowerCase();
191
199
  if (htmlLang && locales[htmlLang]) return htmlLang;
192
- const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "ru").slice(0, 2).toLowerCase();
193
- return locales[nav] ? nav : "ru";
200
+ const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "en").slice(0, 2).toLowerCase();
201
+ return locales[nav] ? nav : "en";
194
202
  }
195
203
  function useT() {
196
204
  const dict = React.useMemo(() => {
@@ -228,7 +236,7 @@ const CategoryAttributeTemplatesWidget = ({
228
236
  setShowTemplateList(false);
229
237
  },
230
238
  onError: (err) => {
231
- setMutationError((err == null ? void 0 : err.message) || "Ошибка при применении шаблона");
239
+ setMutationError((err == null ? void 0 : err.message) || t("applyTemplateError"));
232
240
  }
233
241
  });
234
242
  const {
@@ -254,7 +262,7 @@ const CategoryAttributeTemplatesWidget = ({
254
262
  setMutationError(null);
255
263
  },
256
264
  onError: (err) => {
257
- setMutationError((err == null ? void 0 : err.message) || "Ошибка при создании атрибута");
265
+ setMutationError((err == null ? void 0 : err.message) || t("createError"));
258
266
  }
259
267
  });
260
268
  const deleteMutation = reactQuery.useMutation({
@@ -302,19 +310,19 @@ const CategoryAttributeTemplatesWidget = ({
302
310
  ] }),
303
311
  showTemplateList && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-3", children: [
304
312
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
305
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Выберите шаблон" }),
313
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t("chooseTemplate") }),
306
314
  /* @__PURE__ */ jsxRuntime.jsx(
307
315
  ui.Button,
308
316
  {
309
317
  size: "small",
310
318
  variant: "secondary",
311
319
  onClick: () => setShowTemplateList(false),
312
- children: "Закрыть"
320
+ children: t("close")
313
321
  }
314
322
  )
315
323
  ] }),
316
324
  templatesQuery.isLoading && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }),
317
- ((_a = templatesQuery.data) == null ? void 0 : _a.attribute_templates.length) === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "Пресетов нет. Создайте в настройках Product Attributes." }),
325
+ ((_a = templatesQuery.data) == null ? void 0 : _a.attribute_templates.length) === 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("noTemplates") }),
318
326
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: (_b = templatesQuery.data) == null ? void 0 : _b.attribute_templates.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
319
327
  "button",
320
328
  {
@@ -333,9 +341,9 @@ const CategoryAttributeTemplatesWidget = ({
333
341
  )) })
334
342
  ] }),
335
343
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
336
- isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: "Не удалось загрузить атрибуты." }) }),
344
+ isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
337
345
  inheritedAttributes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
338
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: "Унаследованные" }) }),
346
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: t("inherited") }) }),
339
347
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: inheritedAttributes.map((attr) => /* @__PURE__ */ jsxRuntime.jsxs(
340
348
  "div",
341
349
  {
@@ -352,18 +360,14 @@ const CategoryAttributeTemplatesWidget = ({
352
360
  )) })
353
361
  ] }),
354
362
  ownAttributes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
355
- inheritedAttributes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: "Свои" }) }),
363
+ inheritedAttributes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: t("own") }) }),
356
364
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: ownAttributes.map(
357
365
  (attr) => confirmDeleteId === attr.id ? /* @__PURE__ */ jsxRuntime.jsxs(
358
366
  "div",
359
367
  {
360
368
  className: "flex items-center gap-3 px-6 py-3 text-sm",
361
369
  children: [
362
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex-1 text-ui-fg-base", children: [
363
- "Удалить «",
364
- attr.label,
365
- "»?"
366
- ] }),
370
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-ui-fg-base", children: t("confirmDelete").replace("{name}", attr.label) }),
367
371
  /* @__PURE__ */ jsxRuntime.jsx(
368
372
  ui.Button,
369
373
  {
@@ -371,7 +375,7 @@ const CategoryAttributeTemplatesWidget = ({
371
375
  variant: "danger",
372
376
  onClick: () => deleteMutation.mutate(attr.id),
373
377
  isLoading: deleteMutation.isPending,
374
- children: "Удалить"
378
+ children: t("delete")
375
379
  }
376
380
  ),
377
381
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -380,7 +384,7 @@ const CategoryAttributeTemplatesWidget = ({
380
384
  size: "small",
381
385
  variant: "secondary",
382
386
  onClick: () => setConfirmDeleteId(null),
383
- children: "Отмена"
387
+ children: t("cancel")
384
388
  }
385
389
  )
386
390
  ]
@@ -401,7 +405,7 @@ const CategoryAttributeTemplatesWidget = ({
401
405
  {
402
406
  onClick: () => setConfirmDeleteId(attr.id),
403
407
  className: "text-xs text-ui-fg-error hover:underline",
404
- children: "Удалить"
408
+ children: t("delete")
405
409
  }
406
410
  )
407
411
  ]
@@ -410,14 +414,14 @@ const CategoryAttributeTemplatesWidget = ({
410
414
  )
411
415
  ) })
412
416
  ] }),
413
- !isLoading && !isError && attributes2.length === 0 && !showAddForm && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "Нет атрибутов. Добавьте первый." }) }),
417
+ !isLoading && !isError && attributes2.length === 0 && !showAddForm && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("noAttributes") }) }),
414
418
  showAddForm && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-6 py-3", children: [
415
419
  /* @__PURE__ */ jsxRuntime.jsx(
416
420
  ui.Input,
417
421
  {
418
422
  value: addForm.label,
419
423
  onChange: (e) => setAddForm((f) => ({ ...f, label: e.target.value })),
420
- placeholder: "Название атрибута",
424
+ placeholder: t("name"),
421
425
  className: "flex-1 h-8 text-sm",
422
426
  autoFocus: true
423
427
  }
@@ -433,10 +437,10 @@ const CategoryAttributeTemplatesWidget = ({
433
437
  })),
434
438
  className: "h-8 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
435
439
  children: [
436
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Текст" }),
437
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: "Число" }),
438
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "file", children: "Файл" }),
439
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: "Да/Нет" })
440
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: t("type.text") }),
441
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: t("type.number") }),
442
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "file", children: t("type.file") }),
443
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: t("type.boolean") })
440
444
  ]
441
445
  }
442
446
  ),
@@ -445,7 +449,7 @@ const CategoryAttributeTemplatesWidget = ({
445
449
  {
446
450
  value: addForm.unit,
447
451
  onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })),
448
- placeholder: "ед. (кг, м, шт...)",
452
+ placeholder: t("unit"),
449
453
  className: "w-28 h-8 text-sm"
450
454
  }
451
455
  ),
@@ -455,7 +459,7 @@ const CategoryAttributeTemplatesWidget = ({
455
459
  size: "small",
456
460
  onClick: handleAdd,
457
461
  isLoading: createMutation.isPending,
458
- children: "Добавить"
462
+ children: t("add")
459
463
  }
460
464
  ),
461
465
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -468,7 +472,7 @@ const CategoryAttributeTemplatesWidget = ({
468
472
  setAddForm(emptyForm$1());
469
473
  setMutationError(null);
470
474
  },
471
- children: "Отмена"
475
+ children: t("cancel")
472
476
  }
473
477
  )
474
478
  ] }),
@@ -484,6 +488,7 @@ const ProductAttributeValuesWidget = ({
484
488
  var _a;
485
489
  const productId = data.id;
486
490
  const productHandle = data.handle || productId;
491
+ const t = useT();
487
492
  const qc = reactQuery.useQueryClient();
488
493
  const [formValues, setFormValues] = React.useState({});
489
494
  const [saveSuccess, setSaveSuccess] = React.useState(false);
@@ -558,7 +563,7 @@ const ProductAttributeValuesWidget = ({
558
563
  if (!response.ok) {
559
564
  const text = await response.text();
560
565
  console.error("Upload failed", response.status, text);
561
- alert(`Ошибка загрузки файла: ${response.status}`);
566
+ alert(`${t("uploadError")}: ${response.status}`);
562
567
  return;
563
568
  }
564
569
  const res = await response.json();
@@ -567,11 +572,11 @@ const ProductAttributeValuesWidget = ({
567
572
  setFormValues((prev) => ({ ...prev, [attrId]: url }));
568
573
  } else {
569
574
  console.error("No URL in upload response", res);
570
- alert("Файл загружен, но URL не получен");
575
+ alert(t("uploadError"));
571
576
  }
572
577
  } catch (err) {
573
578
  console.error("Upload error", err);
574
- alert("Ошибка загрузки файла");
579
+ alert(t("uploadError"));
575
580
  } finally {
576
581
  setUploadingId(null);
577
582
  }
@@ -580,10 +585,10 @@ const ProductAttributeValuesWidget = ({
580
585
  const isError = attributesQuery.isError || valuesQuery.isError;
581
586
  const attributes2 = ((_a = attributesQuery.data) == null ? void 0 : _a.attributes) ?? [];
582
587
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
583
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Характеристики" }) }),
584
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "Загрузка…" }) }),
585
- isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: "Не удалось загрузить характеристики." }) }),
586
- !isLoading && !isError && attributes2.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: "В категории нет атрибутов. Добавьте их в настройках категории." }) }),
588
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("characteristics") }) }),
589
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
590
+ isError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
591
+ !isLoading && !isError && attributes2.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted text-sm", children: t("noAttributes") }) }),
587
592
  !isLoading && !isError && attributes2.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
588
593
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: attributes2.map((attr) => /* @__PURE__ */ jsxRuntime.jsxs(
589
594
  "div",
@@ -605,8 +610,8 @@ const ProductAttributeValuesWidget = ({
605
610
  className: "h-8 flex-1 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
606
611
  children: [
607
612
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "—" }),
608
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "true", children: "Да" }),
609
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "false", children: "Нет" })
613
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "true", children: t("yes") }),
614
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "false", children: t("no") })
610
615
  ]
611
616
  }
612
617
  ) : attr.type === "file" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -633,7 +638,7 @@ const ProductAttributeValuesWidget = ({
633
638
  ...prev,
634
639
  [attr.id]: e.target.value
635
640
  })),
636
- placeholder: "URL файла",
641
+ placeholder: t("fileUrl"),
637
642
  className: "h-8 text-sm flex-1"
638
643
  }
639
644
  ),
@@ -648,7 +653,7 @@ const ProductAttributeValuesWidget = ({
648
653
  return (_a2 = fileInputs.current[attr.id]) == null ? void 0 : _a2.click();
649
654
  },
650
655
  isLoading: uploadingId === attr.id,
651
- children: "Загрузить"
656
+ children: t("upload")
652
657
  }
653
658
  )
654
659
  ] }) : /* @__PURE__ */ jsxRuntime.jsx(
@@ -660,7 +665,7 @@ const ProductAttributeValuesWidget = ({
660
665
  ...prev,
661
666
  [attr.id]: e.target.value
662
667
  })),
663
- placeholder: attr.type === "number" ? "0" : "Значение",
668
+ placeholder: attr.type === "number" ? "0" : t("value"),
664
669
  className: "h-8 text-sm flex-1"
665
670
  }
666
671
  ) })
@@ -674,7 +679,7 @@ const ProductAttributeValuesWidget = ({
674
679
  size: "small",
675
680
  onClick: handleSave,
676
681
  isLoading: saveMutation.isPending,
677
- children: saveSuccess ? "Сохранено ✓" : "Сохранить"
682
+ children: saveSuccess ? t("saved") : t("save")
678
683
  }
679
684
  ) })
680
685
  ] })
@@ -41,6 +41,8 @@ const no$1 = "Нет";
41
41
  const upload$1 = "Загрузить";
42
42
  const uploadError$1 = "Ошибка загрузки файла";
43
43
  const fileUrl$1 = "URL файла";
44
+ const applyTemplateError$1 = "Ошибка при применении шаблона";
45
+ const createError$1 = "Ошибка при создании атрибута";
44
46
  const templates$1 = "Шаблоны атрибутов";
45
47
  const templatesDesc$1 = "Заготовки атрибутов, которые можно применить к любой категории.";
46
48
  const globals$1 = "Глобальные атрибуты";
@@ -80,6 +82,8 @@ const ru = {
80
82
  upload: upload$1,
81
83
  uploadError: uploadError$1,
82
84
  fileUrl: fileUrl$1,
85
+ applyTemplateError: applyTemplateError$1,
86
+ createError: createError$1,
83
87
  templates: templates$1,
84
88
  templatesDesc: templatesDesc$1,
85
89
  globals: globals$1,
@@ -114,6 +118,8 @@ const no = "No";
114
118
  const upload = "Upload";
115
119
  const uploadError = "Upload failed";
116
120
  const fileUrl = "File URL";
121
+ const applyTemplateError = "Failed to apply template";
122
+ const createError = "Failed to create attribute";
117
123
  const templates = "Attribute Templates";
118
124
  const templatesDesc = "Reusable attribute blueprints. Apply to any category in one click.";
119
125
  const globals = "Global Attributes";
@@ -153,6 +159,8 @@ const en = {
153
159
  upload,
154
160
  uploadError,
155
161
  fileUrl,
162
+ applyTemplateError,
163
+ createError,
156
164
  templates,
157
165
  templatesDesc,
158
166
  globals,
@@ -161,7 +169,7 @@ const en = {
161
169
  const locales = { ru, en };
162
170
  function detectLang() {
163
171
  var _a, _b, _c;
164
- if (typeof window === "undefined") return "ru";
172
+ if (typeof window === "undefined") return "en";
165
173
  const stored = window.localStorage.getItem("i18nextLng");
166
174
  if (stored) {
167
175
  const short = stored.slice(0, 2).toLowerCase();
@@ -169,8 +177,8 @@ function detectLang() {
169
177
  }
170
178
  const htmlLang = (_b = (_a = document.documentElement) == null ? void 0 : _a.lang) == null ? void 0 : _b.slice(0, 2).toLowerCase();
171
179
  if (htmlLang && locales[htmlLang]) return htmlLang;
172
- const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "ru").slice(0, 2).toLowerCase();
173
- return locales[nav] ? nav : "ru";
180
+ const nav = (((_c = window.navigator) == null ? void 0 : _c.language) || "en").slice(0, 2).toLowerCase();
181
+ return locales[nav] ? nav : "en";
174
182
  }
175
183
  function useT() {
176
184
  const dict = useMemo(() => {
@@ -208,7 +216,7 @@ const CategoryAttributeTemplatesWidget = ({
208
216
  setShowTemplateList(false);
209
217
  },
210
218
  onError: (err) => {
211
- setMutationError((err == null ? void 0 : err.message) || "Ошибка при применении шаблона");
219
+ setMutationError((err == null ? void 0 : err.message) || t("applyTemplateError"));
212
220
  }
213
221
  });
214
222
  const {
@@ -234,7 +242,7 @@ const CategoryAttributeTemplatesWidget = ({
234
242
  setMutationError(null);
235
243
  },
236
244
  onError: (err) => {
237
- setMutationError((err == null ? void 0 : err.message) || "Ошибка при создании атрибута");
245
+ setMutationError((err == null ? void 0 : err.message) || t("createError"));
238
246
  }
239
247
  });
240
248
  const deleteMutation = useMutation({
@@ -282,19 +290,19 @@ const CategoryAttributeTemplatesWidget = ({
282
290
  ] }),
283
291
  showTemplateList && /* @__PURE__ */ jsxs("div", { className: "px-6 py-3", children: [
284
292
  /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
285
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Выберите шаблон" }),
293
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: t("chooseTemplate") }),
286
294
  /* @__PURE__ */ jsx(
287
295
  Button,
288
296
  {
289
297
  size: "small",
290
298
  variant: "secondary",
291
299
  onClick: () => setShowTemplateList(false),
292
- children: "Закрыть"
300
+ children: t("close")
293
301
  }
294
302
  )
295
303
  ] }),
296
304
  templatesQuery.isLoading && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }),
297
- ((_a = templatesQuery.data) == null ? void 0 : _a.attribute_templates.length) === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "Пресетов нет. Создайте в настройках Product Attributes." }),
305
+ ((_a = templatesQuery.data) == null ? void 0 : _a.attribute_templates.length) === 0 && /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("noTemplates") }),
298
306
  /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: (_b = templatesQuery.data) == null ? void 0 : _b.attribute_templates.map((p) => /* @__PURE__ */ jsxs(
299
307
  "button",
300
308
  {
@@ -313,9 +321,9 @@ const CategoryAttributeTemplatesWidget = ({
313
321
  )) })
314
322
  ] }),
315
323
  isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
316
- isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: "Не удалось загрузить атрибуты." }) }),
324
+ isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
317
325
  inheritedAttributes.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
318
- /* @__PURE__ */ jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: "Унаследованные" }) }),
326
+ /* @__PURE__ */ jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: t("inherited") }) }),
319
327
  /* @__PURE__ */ jsx("div", { className: "divide-y", children: inheritedAttributes.map((attr) => /* @__PURE__ */ jsxs(
320
328
  "div",
321
329
  {
@@ -332,18 +340,14 @@ const CategoryAttributeTemplatesWidget = ({
332
340
  )) })
333
341
  ] }),
334
342
  ownAttributes.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
335
- inheritedAttributes.length > 0 && /* @__PURE__ */ jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: "Свои" }) }),
343
+ inheritedAttributes.length > 0 && /* @__PURE__ */ jsx("div", { className: "px-6 py-2 bg-ui-bg-subtle", children: /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-muted uppercase", children: t("own") }) }),
336
344
  /* @__PURE__ */ jsx("div", { className: "divide-y", children: ownAttributes.map(
337
345
  (attr) => confirmDeleteId === attr.id ? /* @__PURE__ */ jsxs(
338
346
  "div",
339
347
  {
340
348
  className: "flex items-center gap-3 px-6 py-3 text-sm",
341
349
  children: [
342
- /* @__PURE__ */ jsxs("span", { className: "flex-1 text-ui-fg-base", children: [
343
- "Удалить «",
344
- attr.label,
345
- "»?"
346
- ] }),
350
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-ui-fg-base", children: t("confirmDelete").replace("{name}", attr.label) }),
347
351
  /* @__PURE__ */ jsx(
348
352
  Button,
349
353
  {
@@ -351,7 +355,7 @@ const CategoryAttributeTemplatesWidget = ({
351
355
  variant: "danger",
352
356
  onClick: () => deleteMutation.mutate(attr.id),
353
357
  isLoading: deleteMutation.isPending,
354
- children: "Удалить"
358
+ children: t("delete")
355
359
  }
356
360
  ),
357
361
  /* @__PURE__ */ jsx(
@@ -360,7 +364,7 @@ const CategoryAttributeTemplatesWidget = ({
360
364
  size: "small",
361
365
  variant: "secondary",
362
366
  onClick: () => setConfirmDeleteId(null),
363
- children: "Отмена"
367
+ children: t("cancel")
364
368
  }
365
369
  )
366
370
  ]
@@ -381,7 +385,7 @@ const CategoryAttributeTemplatesWidget = ({
381
385
  {
382
386
  onClick: () => setConfirmDeleteId(attr.id),
383
387
  className: "text-xs text-ui-fg-error hover:underline",
384
- children: "Удалить"
388
+ children: t("delete")
385
389
  }
386
390
  )
387
391
  ]
@@ -390,14 +394,14 @@ const CategoryAttributeTemplatesWidget = ({
390
394
  )
391
395
  ) })
392
396
  ] }),
393
- !isLoading && !isError && attributes2.length === 0 && !showAddForm && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "Нет атрибутов. Добавьте первый." }) }),
397
+ !isLoading && !isError && attributes2.length === 0 && !showAddForm && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("noAttributes") }) }),
394
398
  showAddForm && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-6 py-3", children: [
395
399
  /* @__PURE__ */ jsx(
396
400
  Input,
397
401
  {
398
402
  value: addForm.label,
399
403
  onChange: (e) => setAddForm((f) => ({ ...f, label: e.target.value })),
400
- placeholder: "Название атрибута",
404
+ placeholder: t("name"),
401
405
  className: "flex-1 h-8 text-sm",
402
406
  autoFocus: true
403
407
  }
@@ -413,10 +417,10 @@ const CategoryAttributeTemplatesWidget = ({
413
417
  })),
414
418
  className: "h-8 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
415
419
  children: [
416
- /* @__PURE__ */ jsx("option", { value: "text", children: "Текст" }),
417
- /* @__PURE__ */ jsx("option", { value: "number", children: "Число" }),
418
- /* @__PURE__ */ jsx("option", { value: "file", children: "Файл" }),
419
- /* @__PURE__ */ jsx("option", { value: "boolean", children: "Да/Нет" })
420
+ /* @__PURE__ */ jsx("option", { value: "text", children: t("type.text") }),
421
+ /* @__PURE__ */ jsx("option", { value: "number", children: t("type.number") }),
422
+ /* @__PURE__ */ jsx("option", { value: "file", children: t("type.file") }),
423
+ /* @__PURE__ */ jsx("option", { value: "boolean", children: t("type.boolean") })
420
424
  ]
421
425
  }
422
426
  ),
@@ -425,7 +429,7 @@ const CategoryAttributeTemplatesWidget = ({
425
429
  {
426
430
  value: addForm.unit,
427
431
  onChange: (e) => setAddForm((f) => ({ ...f, unit: e.target.value })),
428
- placeholder: "ед. (кг, м, шт...)",
432
+ placeholder: t("unit"),
429
433
  className: "w-28 h-8 text-sm"
430
434
  }
431
435
  ),
@@ -435,7 +439,7 @@ const CategoryAttributeTemplatesWidget = ({
435
439
  size: "small",
436
440
  onClick: handleAdd,
437
441
  isLoading: createMutation.isPending,
438
- children: "Добавить"
442
+ children: t("add")
439
443
  }
440
444
  ),
441
445
  /* @__PURE__ */ jsx(
@@ -448,7 +452,7 @@ const CategoryAttributeTemplatesWidget = ({
448
452
  setAddForm(emptyForm$1());
449
453
  setMutationError(null);
450
454
  },
451
- children: "Отмена"
455
+ children: t("cancel")
452
456
  }
453
457
  )
454
458
  ] }),
@@ -464,6 +468,7 @@ const ProductAttributeValuesWidget = ({
464
468
  var _a;
465
469
  const productId = data.id;
466
470
  const productHandle = data.handle || productId;
471
+ const t = useT();
467
472
  const qc = useQueryClient();
468
473
  const [formValues, setFormValues] = useState({});
469
474
  const [saveSuccess, setSaveSuccess] = useState(false);
@@ -538,7 +543,7 @@ const ProductAttributeValuesWidget = ({
538
543
  if (!response.ok) {
539
544
  const text = await response.text();
540
545
  console.error("Upload failed", response.status, text);
541
- alert(`Ошибка загрузки файла: ${response.status}`);
546
+ alert(`${t("uploadError")}: ${response.status}`);
542
547
  return;
543
548
  }
544
549
  const res = await response.json();
@@ -547,11 +552,11 @@ const ProductAttributeValuesWidget = ({
547
552
  setFormValues((prev) => ({ ...prev, [attrId]: url }));
548
553
  } else {
549
554
  console.error("No URL in upload response", res);
550
- alert("Файл загружен, но URL не получен");
555
+ alert(t("uploadError"));
551
556
  }
552
557
  } catch (err) {
553
558
  console.error("Upload error", err);
554
- alert("Ошибка загрузки файла");
559
+ alert(t("uploadError"));
555
560
  } finally {
556
561
  setUploadingId(null);
557
562
  }
@@ -560,10 +565,10 @@ const ProductAttributeValuesWidget = ({
560
565
  const isError = attributesQuery.isError || valuesQuery.isError;
561
566
  const attributes2 = ((_a = attributesQuery.data) == null ? void 0 : _a.attributes) ?? [];
562
567
  return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
563
- /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Характеристики" }) }),
564
- isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "Загрузка…" }) }),
565
- isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: "Не удалось загрузить характеристики." }) }),
566
- !isLoading && !isError && attributes2.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: "В категории нет атрибутов. Добавьте их в настройках категории." }) }),
568
+ /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: t("characteristics") }) }),
569
+ isLoading && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("loading") }) }),
570
+ isError && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-error text-sm", children: t("loadFailed") }) }),
571
+ !isLoading && !isError && attributes2.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-sm", children: t("noAttributes") }) }),
567
572
  !isLoading && !isError && attributes2.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
568
573
  /* @__PURE__ */ jsx("div", { className: "divide-y", children: attributes2.map((attr) => /* @__PURE__ */ jsxs(
569
574
  "div",
@@ -585,8 +590,8 @@ const ProductAttributeValuesWidget = ({
585
590
  className: "h-8 flex-1 rounded border border-ui-border-base bg-ui-bg-base px-2 text-sm",
586
591
  children: [
587
592
  /* @__PURE__ */ jsx("option", { value: "", children: "—" }),
588
- /* @__PURE__ */ jsx("option", { value: "true", children: "Да" }),
589
- /* @__PURE__ */ jsx("option", { value: "false", children: "Нет" })
593
+ /* @__PURE__ */ jsx("option", { value: "true", children: t("yes") }),
594
+ /* @__PURE__ */ jsx("option", { value: "false", children: t("no") })
590
595
  ]
591
596
  }
592
597
  ) : attr.type === "file" ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -613,7 +618,7 @@ const ProductAttributeValuesWidget = ({
613
618
  ...prev,
614
619
  [attr.id]: e.target.value
615
620
  })),
616
- placeholder: "URL файла",
621
+ placeholder: t("fileUrl"),
617
622
  className: "h-8 text-sm flex-1"
618
623
  }
619
624
  ),
@@ -628,7 +633,7 @@ const ProductAttributeValuesWidget = ({
628
633
  return (_a2 = fileInputs.current[attr.id]) == null ? void 0 : _a2.click();
629
634
  },
630
635
  isLoading: uploadingId === attr.id,
631
- children: "Загрузить"
636
+ children: t("upload")
632
637
  }
633
638
  )
634
639
  ] }) : /* @__PURE__ */ jsx(
@@ -640,7 +645,7 @@ const ProductAttributeValuesWidget = ({
640
645
  ...prev,
641
646
  [attr.id]: e.target.value
642
647
  })),
643
- placeholder: attr.type === "number" ? "0" : "Значение",
648
+ placeholder: attr.type === "number" ? "0" : t("value"),
644
649
  className: "h-8 text-sm flex-1"
645
650
  }
646
651
  ) })
@@ -654,7 +659,7 @@ const ProductAttributeValuesWidget = ({
654
659
  size: "small",
655
660
  onClick: handleSave,
656
661
  isLoading: saveMutation.isPending,
657
- children: saveSuccess ? "Сохранено ✓" : "Сохранить"
662
+ children: saveSuccess ? t("saved") : t("save")
658
663
  }
659
664
  ) })
660
665
  ] })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empty-complete-org/medusa-product-attributes",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Custom attributes module for Medusa v2 with support for text, number, file types and units of measurement",
5
5
  "author": "empty-complete",
6
6
  "license": "MIT",