Add multilanguage catalog translations UI for products and categories.

Include AI translate-all with locale picker, count badges, MultiLanguage Data module gating, and shared modal action layout polish.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-04 09:51:11 +03:30
co-authored by Cursor
parent 8c187b18be
commit 2a32c46b2e
43 changed files with 1624 additions and 78 deletions
@@ -494,6 +494,22 @@
border-top: 1px solid rgba(148, 163, 184, 0.28);
}
.modulesChartsRow {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px 16px;
}
@media (max-width: 560px) {
.modulesChartsRow {
grid-template-columns: 1fr;
}
}
.modulesChecks .entityCheck span {
white-space: nowrap;
}
.modulesCharts .field select {
appearance: none;
-webkit-appearance: none;
+40 -37
View File
@@ -2087,6 +2087,7 @@ export function BusinessesPage() {
: 'Modules'
}
onClose={closeModules}
wide
>
{modulesError ? (
<p className={styles.alertError} role="alert">
@@ -2141,43 +2142,45 @@ export function BusinessesPage() {
</div>
<div className={styles.modulesCharts}>
<p className={styles.entityGroupLabel}>Home charts</p>
<div className={styles.field}>
<label htmlFor="modules-chart-1">Chart 1</label>
<select
id="modules-chart-1"
value={modulesCharts[0]}
disabled={modulesSubmitting}
onChange={(e) => {
const value = e.target.value
if (!HOME_CHART_IDS.includes(value as HomeChartId)) return
setModulesCharts([value as HomeChartId, modulesCharts[1]])
}}
>
{HOME_CHART_IDS.map((id) => (
<option key={id} value={id}>
{HOME_CHART_LABELS[id]}
</option>
))}
</select>
</div>
<div className={styles.field}>
<label htmlFor="modules-chart-2">Chart 2</label>
<select
id="modules-chart-2"
value={modulesCharts[1]}
disabled={modulesSubmitting}
onChange={(e) => {
const value = e.target.value
if (!HOME_CHART_IDS.includes(value as HomeChartId)) return
setModulesCharts([modulesCharts[0], value as HomeChartId])
}}
>
{HOME_CHART_IDS.map((id) => (
<option key={id} value={id}>
{HOME_CHART_LABELS[id]}
</option>
))}
</select>
<div className={styles.modulesChartsRow}>
<div className={styles.field}>
<label htmlFor="modules-chart-1">Chart 1</label>
<select
id="modules-chart-1"
value={modulesCharts[0]}
disabled={modulesSubmitting}
onChange={(e) => {
const value = e.target.value
if (!HOME_CHART_IDS.includes(value as HomeChartId)) return
setModulesCharts([value as HomeChartId, modulesCharts[1]])
}}
>
{HOME_CHART_IDS.map((id) => (
<option key={id} value={id}>
{HOME_CHART_LABELS[id]}
</option>
))}
</select>
</div>
<div className={styles.field}>
<label htmlFor="modules-chart-2">Chart 2</label>
<select
id="modules-chart-2"
value={modulesCharts[1]}
disabled={modulesSubmitting}
onChange={(e) => {
const value = e.target.value
if (!HOME_CHART_IDS.includes(value as HomeChartId)) return
setModulesCharts([modulesCharts[0], value as HomeChartId])
}}
>
{HOME_CHART_IDS.map((id) => (
<option key={id} value={id}>
{HOME_CHART_LABELS[id]}
</option>
))}
</select>
</div>
</div>
</div>
<div style={{ height: 12 }} />
@@ -9,6 +9,7 @@ export const BUSINESS_DASHBOARD_MODULE_IDS = [
'instructions',
'workshops',
'finance',
'multilanguage_data',
] as const
/** Optional customer-dashboard modules. Always-on: home, profile, addresses, orders, favorites. */
@@ -38,6 +39,7 @@ export const BUSINESS_DASHBOARD_MODULE_LABELS: Record<
instructions: 'Instructions',
workshops: 'Workshops',
finance: 'Finance',
multilanguage_data: 'MultiLanguage Data',
}
export const CUSTOMER_MODULE_LABELS: Record<CustomerModuleId, string> = {
@@ -79,7 +81,9 @@ export const HOME_CHART_LABELS: Record<HomeChartId, string> = {
* enabled except opt-in modules. Customer modules stay opt-in.
*/
export const DEFAULT_ENABLED_BUSINESS_MODULES: BusinessModuleId[] =
BUSINESS_DASHBOARD_MODULE_IDS.filter((id) => id !== 'workshops')
BUSINESS_DASHBOARD_MODULE_IDS.filter(
(id) => id !== 'workshops' && id !== 'multilanguage_data',
)
export const DEFAULT_HOME_CHARTS: [HomeChartId, HomeChartId] = [
'orders_30d',