@medusajs/dashboard 3.0.0-snapshot-20251216135612 → 3.0.0-snapshot-20251216145629
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/dist/app.css +13 -0
- package/dist/app.js +227 -68
- package/dist/app.mjs +1 -1
- package/dist/{chunk-YKYVCQRS.mjs → chunk-UULAOAFM.mjs} +34 -10
- package/dist/en.json +13 -1
- package/dist/{product-attributes-EFIRUBRO.mjs → product-attributes-K4FGFORS.mjs} +1 -1
- package/dist/{product-create-K6EWZHIT.mjs → product-create-7YTRHZQQ.mjs} +1 -1
- package/dist/{product-detail-DKPZDEIY.mjs → product-detail-32ZXNWOP.mjs} +1 -1
- package/dist/{product-edit-55YXTIGO.mjs → product-edit-FBAKONMR.mjs} +1 -1
- package/dist/{product-organization-N3VBRXF4.mjs → product-organization-IUSVX22S.mjs} +1 -1
- package/dist/{translation-list-S5Z6PG2R.mjs → translation-list-UF7FLXOW.mjs} +151 -5
- package/dist/{translations-edit-HUNKY7CO.mjs → translations-edit-KECSHYZY.mjs} +7 -18
- package/package.json +9 -9
- package/src/i18n/translations/$schema.json +47 -2
- package/src/i18n/translations/en.json +13 -1
- package/src/i18n/translations/es.json +13 -1
- package/src/routes/translations/translation-list/components/translations-completion-section/translations-completion-section.tsx +153 -2
- package/src/routes/translations/translation-list/translation-list.tsx +8 -2
- package/src/routes/translations/translations-edit/components/translations-edit-form/translations-edit-form.tsx +7 -19
|
@@ -122,7 +122,9 @@
|
|
|
122
122
|
},
|
|
123
123
|
"actions": {
|
|
124
124
|
"save": "Guardar",
|
|
125
|
+
"saveChanges": "Guardar cambios",
|
|
125
126
|
"saveAsDraft": "Guardar como borrador",
|
|
127
|
+
"saveAndClose": "Guardar y cerrar",
|
|
126
128
|
"copy": "Copiar",
|
|
127
129
|
"copied": "Copiado",
|
|
128
130
|
"duplicate": "Duplicar",
|
|
@@ -2460,13 +2462,23 @@
|
|
|
2460
2462
|
"header": "Editor de Traducciones en Masa",
|
|
2461
2463
|
"locale": "Idioma"
|
|
2462
2464
|
},
|
|
2465
|
+
"edit": {
|
|
2466
|
+
"successToast": "Traducciones actualizadas exitosamente",
|
|
2467
|
+
"unsavedChanges": {
|
|
2468
|
+
"title": "Traducciones sin guardar",
|
|
2469
|
+
"description": "No pierdas tu trabajo. Tienes cambios que no han sido guardados aún"
|
|
2470
|
+
}
|
|
2471
|
+
},
|
|
2463
2472
|
"activeLocales": {
|
|
2464
2473
|
"heading": "Idiomas",
|
|
2465
2474
|
"subtitle": "Traducciones activas",
|
|
2466
2475
|
"noLocalesTip": "Configura al menos un idioma para empezar a traducir tu información"
|
|
2467
2476
|
},
|
|
2468
2477
|
"completion": {
|
|
2469
|
-
"heading": "Textos traducidos"
|
|
2478
|
+
"heading": "Textos traducidos",
|
|
2479
|
+
"translated": "Traducidos",
|
|
2480
|
+
"toTranslate": "Por traducir",
|
|
2481
|
+
"footer": "Idiomas"
|
|
2470
2482
|
}
|
|
2471
2483
|
},
|
|
2472
2484
|
"store": {
|
|
@@ -1,15 +1,28 @@
|
|
|
1
|
-
import { AdminTranslationEntityStatistics } from "@medusajs/types"
|
|
2
|
-
import { Container, Heading, Text } from "@medusajs/ui"
|
|
1
|
+
import { AdminTranslationEntityStatistics, HttpTypes } from "@medusajs/types"
|
|
2
|
+
import { Container, Heading, Text, Tooltip } from "@medusajs/ui"
|
|
3
|
+
import { useMemo, useState } from "react"
|
|
3
4
|
import { useTranslation } from "react-i18next"
|
|
4
5
|
|
|
5
6
|
type TranslationsCompletionSectionProps = {
|
|
6
7
|
statistics: Record<string, AdminTranslationEntityStatistics>
|
|
8
|
+
locales: HttpTypes.AdminLocale[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type LocaleStats = {
|
|
12
|
+
code: string
|
|
13
|
+
name: string
|
|
14
|
+
translated: number
|
|
15
|
+
toTranslate: number
|
|
16
|
+
total: number
|
|
7
17
|
}
|
|
8
18
|
|
|
9
19
|
export const TranslationsCompletionSection = ({
|
|
10
20
|
statistics,
|
|
21
|
+
locales,
|
|
11
22
|
}: TranslationsCompletionSectionProps) => {
|
|
12
23
|
const { t } = useTranslation()
|
|
24
|
+
const [hoveredLocale, setHoveredLocale] = useState<string | null>(null)
|
|
25
|
+
|
|
13
26
|
const { translatedCount, totalCount } = Object.values(statistics).reduce(
|
|
14
27
|
(acc, curr) => ({
|
|
15
28
|
translatedCount: acc.translatedCount + curr.translated,
|
|
@@ -21,6 +34,47 @@ export const TranslationsCompletionSection = ({
|
|
|
21
34
|
const percentage = totalCount > 0 ? (translatedCount / totalCount) * 100 : 0
|
|
22
35
|
const remaining = Math.max(0, totalCount - translatedCount)
|
|
23
36
|
|
|
37
|
+
const localeStats = useMemo((): LocaleStats[] => {
|
|
38
|
+
const localeMap = new Map<
|
|
39
|
+
string,
|
|
40
|
+
{ translated: number; expected: number }
|
|
41
|
+
>()
|
|
42
|
+
|
|
43
|
+
locales.forEach((locale) => {
|
|
44
|
+
localeMap.set(locale.code, { translated: 0, expected: 0 })
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
Object.values(statistics).forEach((entityStats) => {
|
|
48
|
+
if (entityStats.by_locale) {
|
|
49
|
+
Object.entries(entityStats.by_locale).forEach(
|
|
50
|
+
([localeCode, localeData]) => {
|
|
51
|
+
const existing = localeMap.get(localeCode)
|
|
52
|
+
if (existing) {
|
|
53
|
+
existing.translated += localeData.translated
|
|
54
|
+
existing.expected += localeData.expected
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
return locales.map((locale) => {
|
|
62
|
+
const stats = localeMap.get(locale.code) || { translated: 0, expected: 0 }
|
|
63
|
+
return {
|
|
64
|
+
code: locale.code,
|
|
65
|
+
name: locale.name,
|
|
66
|
+
translated: stats.translated,
|
|
67
|
+
toTranslate: Math.max(0, stats.expected - stats.translated),
|
|
68
|
+
total: stats.expected,
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}, [statistics, locales])
|
|
72
|
+
|
|
73
|
+
const maxTotal = useMemo(
|
|
74
|
+
() => Math.max(...localeStats.map((s) => s.total), 1),
|
|
75
|
+
[localeStats]
|
|
76
|
+
)
|
|
77
|
+
|
|
24
78
|
return (
|
|
25
79
|
<Container className="flex flex-col gap-y-3 px-6 py-4">
|
|
26
80
|
<div className="flex items-center justify-between">
|
|
@@ -68,6 +122,103 @@ export const TranslationsCompletionSection = ({
|
|
|
68
122
|
{remaining.toLocaleString()} {t("general.remaining").toLowerCase()}
|
|
69
123
|
</Text>
|
|
70
124
|
</div>
|
|
125
|
+
|
|
126
|
+
{localeStats.length > 0 && (
|
|
127
|
+
<div className="mt-4 flex flex-col gap-y-2">
|
|
128
|
+
<div className="flex h-32 w-full items-end gap-1">
|
|
129
|
+
{localeStats.map((locale) => {
|
|
130
|
+
const heightPercent = (locale.total / maxTotal) * 100
|
|
131
|
+
const translatedPercent =
|
|
132
|
+
locale.total > 0 ? (locale.translated / locale.total) * 100 : 0
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<Tooltip
|
|
136
|
+
key={locale.code}
|
|
137
|
+
open={hoveredLocale === locale.code}
|
|
138
|
+
content={
|
|
139
|
+
<div className="flex flex-col gap-y-1 p-1">
|
|
140
|
+
<Text size="small" weight="plus">
|
|
141
|
+
{locale.name}
|
|
142
|
+
</Text>
|
|
143
|
+
<div className="flex items-center justify-between">
|
|
144
|
+
<div className="flex items-center gap-x-2">
|
|
145
|
+
<div
|
|
146
|
+
className="h-2 w-2 rounded-full"
|
|
147
|
+
style={{ backgroundColor: "var(--bg-interactive)" }}
|
|
148
|
+
/>
|
|
149
|
+
<Text
|
|
150
|
+
size="small"
|
|
151
|
+
weight="plus"
|
|
152
|
+
className="text-ui-fg-subtle"
|
|
153
|
+
>
|
|
154
|
+
{t("translations.completion.translated")}
|
|
155
|
+
</Text>
|
|
156
|
+
</div>
|
|
157
|
+
<Text size="small" weight="plus">
|
|
158
|
+
{locale.translated}
|
|
159
|
+
</Text>
|
|
160
|
+
</div>
|
|
161
|
+
<div className="flex items-center gap-x-2">
|
|
162
|
+
<div
|
|
163
|
+
className="h-2 w-2 rounded-full"
|
|
164
|
+
style={{
|
|
165
|
+
backgroundColor: "var(--bg-interactive)",
|
|
166
|
+
opacity: 0.3,
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
<Text
|
|
170
|
+
size="small"
|
|
171
|
+
weight="plus"
|
|
172
|
+
className="text-ui-fg-subtle"
|
|
173
|
+
>
|
|
174
|
+
{t("translations.completion.toTranslate")}
|
|
175
|
+
</Text>
|
|
176
|
+
<Text size="small" weight="plus">
|
|
177
|
+
{locale.toTranslate}
|
|
178
|
+
</Text>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
}
|
|
182
|
+
>
|
|
183
|
+
<div
|
|
184
|
+
className="flex min-w-2 flex-1 cursor-pointer flex-col justify-end overflow-hidden rounded-t-sm transition-opacity"
|
|
185
|
+
style={{ height: `${heightPercent}%` }}
|
|
186
|
+
onMouseEnter={() => setHoveredLocale(locale.code)}
|
|
187
|
+
onMouseLeave={() => setHoveredLocale(null)}
|
|
188
|
+
>
|
|
189
|
+
<div
|
|
190
|
+
className="w-full rounded-t-sm"
|
|
191
|
+
style={{
|
|
192
|
+
height: `${100 - translatedPercent}%`,
|
|
193
|
+
backgroundColor: "var(--bg-interactive)",
|
|
194
|
+
opacity: 0.3,
|
|
195
|
+
minHeight: locale.toTranslate > 0 ? "2px" : "0",
|
|
196
|
+
}}
|
|
197
|
+
/>
|
|
198
|
+
{translatedPercent > 0 && (
|
|
199
|
+
<div
|
|
200
|
+
className="mt-0.5 w-full rounded-sm"
|
|
201
|
+
style={{
|
|
202
|
+
height: `${translatedPercent}%`,
|
|
203
|
+
backgroundColor: "var(--bg-interactive)",
|
|
204
|
+
minHeight: locale.translated > 0 ? "2px" : "0",
|
|
205
|
+
}}
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
</Tooltip>
|
|
210
|
+
)
|
|
211
|
+
})}
|
|
212
|
+
</div>
|
|
213
|
+
<Text
|
|
214
|
+
size="small"
|
|
215
|
+
weight="plus"
|
|
216
|
+
className="text-ui-fg-muted text-center"
|
|
217
|
+
>
|
|
218
|
+
{t("translations.completion.footer")}
|
|
219
|
+
</Text>
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
71
222
|
</Container>
|
|
72
223
|
)
|
|
73
224
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Container, Heading, Text } from "@medusajs/ui"
|
|
2
2
|
import { TwoColumnPage } from "../../../components/layout/pages"
|
|
3
3
|
import { useTranslation } from "react-i18next"
|
|
4
|
-
import { Buildings } from "@medusajs/icons"
|
|
5
4
|
import {
|
|
6
5
|
useStore,
|
|
7
6
|
useTranslationSettings,
|
|
@@ -125,7 +124,14 @@ export const TranslationList = () => {
|
|
|
125
124
|
) ?? []
|
|
126
125
|
}
|
|
127
126
|
></ActiveLocalesSection>
|
|
128
|
-
<TranslationsCompletionSection
|
|
127
|
+
<TranslationsCompletionSection
|
|
128
|
+
statistics={statistics ?? {}}
|
|
129
|
+
locales={
|
|
130
|
+
store?.supported_locales?.map(
|
|
131
|
+
(supportedLocale) => supportedLocale.locale
|
|
132
|
+
) ?? []
|
|
133
|
+
}
|
|
134
|
+
/>
|
|
129
135
|
</TwoColumnPage.Sidebar>
|
|
130
136
|
</TwoColumnPage>
|
|
131
137
|
)
|
|
@@ -426,7 +426,7 @@ export const TranslationsEditForm = ({
|
|
|
426
426
|
const calculateColumnWidth = () => {
|
|
427
427
|
if (containerRef.current) {
|
|
428
428
|
const containerWidth = containerRef.current.offsetWidth
|
|
429
|
-
const availableWidth = containerWidth - FIELD_COLUMN_WIDTH -
|
|
429
|
+
const availableWidth = containerWidth - FIELD_COLUMN_WIDTH - 16
|
|
430
430
|
const columnWidth = Math.max(300, Math.floor(availableWidth / 2))
|
|
431
431
|
setDynamicColumnWidth(columnWidth)
|
|
432
432
|
}
|
|
@@ -588,11 +588,7 @@ export const TranslationsEditForm = ({
|
|
|
588
588
|
async (closeOnSuccess: boolean = false) => {
|
|
589
589
|
const success = await saveCurrentLocale()
|
|
590
590
|
if (success) {
|
|
591
|
-
toast.success(
|
|
592
|
-
t("translations.edit.successToast", {
|
|
593
|
-
defaultValue: "Translations updated successfully",
|
|
594
|
-
})
|
|
595
|
-
)
|
|
591
|
+
toast.success(t("translations.edit.successToast"))
|
|
596
592
|
if (closeOnSuccess) {
|
|
597
593
|
handleSuccess()
|
|
598
594
|
}
|
|
@@ -613,9 +609,6 @@ export const TranslationsEditForm = ({
|
|
|
613
609
|
payload.update.length === 0 &&
|
|
614
610
|
payload.delete.length === 0
|
|
615
611
|
) {
|
|
616
|
-
toast.info(
|
|
617
|
-
t("translations.noChanges", { defaultValue: "No changes to save" })
|
|
618
|
-
)
|
|
619
612
|
return
|
|
620
613
|
}
|
|
621
614
|
|
|
@@ -736,7 +729,7 @@ export const TranslationsEditForm = ({
|
|
|
736
729
|
onClick={() => handleSave(false)}
|
|
737
730
|
isLoading={isPending}
|
|
738
731
|
>
|
|
739
|
-
{t("actions.saveChanges"
|
|
732
|
+
{t("actions.saveChanges")}
|
|
740
733
|
</Button>
|
|
741
734
|
<Button
|
|
742
735
|
size="small"
|
|
@@ -744,7 +737,7 @@ export const TranslationsEditForm = ({
|
|
|
744
737
|
onClick={() => handleSave(true)}
|
|
745
738
|
isLoading={isPending}
|
|
746
739
|
>
|
|
747
|
-
{t("actions.saveAndClose"
|
|
740
|
+
{t("actions.saveAndClose")}
|
|
748
741
|
</Button>
|
|
749
742
|
</div>
|
|
750
743
|
</RouteFocusModal.Footer>
|
|
@@ -754,15 +747,10 @@ export const TranslationsEditForm = ({
|
|
|
754
747
|
<Prompt.Content>
|
|
755
748
|
<Prompt.Header>
|
|
756
749
|
<Prompt.Title>
|
|
757
|
-
{t("translations.unsavedChanges.title"
|
|
758
|
-
defaultValue: "Unsaved changes",
|
|
759
|
-
})}
|
|
750
|
+
{t("translations.edit.unsavedChanges.title")}
|
|
760
751
|
</Prompt.Title>
|
|
761
752
|
<Prompt.Description>
|
|
762
|
-
{t("translations.unsavedChanges.description"
|
|
763
|
-
defaultValue:
|
|
764
|
-
"You have unsaved changes for this locale. Save them before switching?",
|
|
765
|
-
})}
|
|
753
|
+
{t("translations.edit.unsavedChanges.description")}
|
|
766
754
|
</Prompt.Description>
|
|
767
755
|
</Prompt.Header>
|
|
768
756
|
<Prompt.Footer>
|
|
@@ -780,7 +768,7 @@ export const TranslationsEditForm = ({
|
|
|
780
768
|
type="button"
|
|
781
769
|
isLoading={isPending}
|
|
782
770
|
>
|
|
783
|
-
{t("actions.saveChanges"
|
|
771
|
+
{t("actions.saveChanges")}
|
|
784
772
|
</Button>
|
|
785
773
|
</Prompt.Footer>
|
|
786
774
|
</Prompt.Content>
|