feat(Translation): add kitConfig.js for improved localization in GrowTentKonfigurator

- Updated the translation model by adding kitConfig.js to the list of translation files.
- Enhanced the GrowTentKonfigurator component to utilize translation functions for various UI texts, improving localization support throughout the configuration process.
This commit is contained in:
sebseb7
2025-11-22 09:59:47 +01:00
parent 3389a9b66c
commit 905eee57d5
24 changed files with 843 additions and 61 deletions

View File

@@ -68,6 +68,8 @@ function getCachedCategoryData(categoryId, language = 'de') {
return null;
}
import { withI18n } from '../i18n/withTranslation.js';
class GrowTentKonfigurator extends Component {
constructor(props) {
super(props);
@@ -287,7 +289,7 @@ class GrowTentKonfigurator extends Component {
// Now push to cart
const totalPrice = this.state.totalPrice;
const setName = `Growbox Set - ${this.state.selectedTentShape}`;
const setName = this.props.t ? this.props.t("kitConfig.setName", { shape: this.state.selectedTentShape }) : `Growbox Set - ${this.state.selectedTentShape}`;
window.cart.push({
id: null,
@@ -688,20 +690,22 @@ class GrowTentKonfigurator extends Component {
renderTentShapeSection() {
const { selectedTentShape } = this.state;
const { t } = this.props;
return (
<TentShapeSelector
tentShapes={tentShapes}
selectedShape={selectedTentShape}
onShapeSelect={this.handleTentShapeSelect}
title="1. Growbox-Form auswählen"
subtitle="Wähle zuerst die Grundfläche deiner Growbox aus"
title={t ? t("kitConfig.selectShapeTitle") : "1. Growbox-Form auswählen"}
subtitle={t ? t("kitConfig.selectShapeSubtitle") : "Wähle zuerst die Grundfläche deiner Growbox aus"}
/>
);
}
renderTentSizeSection() {
const { selectedTentShape } = this.state;
const { t } = this.props;
if (!selectedTentShape) {
return null; // Don't show tent sizes until shape is selected
@@ -711,7 +715,7 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ textAlign: 'center', py: 4 }}>
<Typography variant="h6" color="text.secondary">
Lade Growbox-Produkte...
{t ? t("kitConfig.loadingProducts") : "Lade Growbox-Produkte..."}
</Typography>
</Box>
);
@@ -724,7 +728,7 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ textAlign: 'center', py: 4 }}>
<Typography variant="h6" color="text.secondary">
Keine Produkte für diese Größe verfügbar
{t ? t("kitConfig.noProductsAvailable") : "Keine Produkte für diese Größe verfügbar"}
</Typography>
</Box>
);
@@ -732,10 +736,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
2. Growbox Produkt auswählen
{t ? t("kitConfig.selectProductTitle") : "2. Growbox Produkt auswählen"}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Wähle das passende Produkt für deine {selectedTentShape} Growbox
{t ? t("kitConfig.selectProductSubtitle", { shape: selectedTentShape }) : `Wähle das passende Produkt für deine ${selectedTentShape} Growbox`}
</Typography>
<Grid container spacing={2}>
{filteredTents.map((product, _index) => (
@@ -792,10 +796,10 @@ class GrowTentKonfigurator extends Component {
<span>{product.price ? new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(product.price) : 'Kein Preis'}</span>
}).format(product.price) : (t ? t("kitConfig.noPrice") : 'Kein Preis')}</span>
{product.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {product.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: product.vat }) : `incl. ${product.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -808,7 +812,7 @@ class GrowTentKonfigurator extends Component {
mt: 1,
textAlign: 'center'
}}>
Ausgewählt
{t ? t("kitConfig.selected") : "✓ Ausgewählt"}
</Typography>
)}
<Stack direction="row" spacing={1} justifyContent="center">
@@ -834,15 +838,16 @@ class GrowTentKonfigurator extends Component {
renderLightSection() {
const { selectedLightType, selectedTentShape } = this.state;
const { t } = this.props;
if (!selectedTentShape) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen
{t ? t("kitConfig.selectLightingTitle") : "3. Beleuchtung wählen"}
</Typography>
<Typography variant="body2" color="text.secondary">
Bitte wählen Sie zuerst eine Zeltgröße aus.
{t ? t("kitConfig.selectLightingSubtitle") : "Bitte wählen Sie zuerst eine Zeltgröße aus."}
</Typography>
</Box>
);
@@ -852,10 +857,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
{t ? t("kitConfig.selectLightingTitleShape", { shape: selectedTentShape }) : `3. Beleuchtung wählen - ${selectedTentShape}`}
</Typography>
<Typography variant="body2" color="text.secondary">
Lade Beleuchtungs-Produkte...
{t ? t("kitConfig.loadingLighting") : "Lade Beleuchtungs-Produkte..."}
</Typography>
</Box>
);
@@ -867,10 +872,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
{t ? t("kitConfig.selectLightingTitleShape", { shape: selectedTentShape }) : `3. Beleuchtung wählen - ${selectedTentShape}`}
</Typography>
<Typography variant="body2" color="text.secondary">
Keine passenden Lampen für Zeltgröße {selectedTentShape} verfügbar.
{t ? t("kitConfig.noLightingAvailable", { shape: selectedTentShape }) : `Keine passenden Lampen für Zeltgröße ${selectedTentShape} verfügbar.`}
</Typography>
</Box>
);
@@ -879,7 +884,7 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
{t ? t("kitConfig.selectLightingTitleShape", { shape: selectedTentShape }) : `3. Beleuchtung wählen - ${selectedTentShape}`}
</Typography>
<Grid container spacing={2}>
{availableLamps.map((lamp) => (
@@ -931,10 +936,10 @@ class GrowTentKonfigurator extends Component {
<span>{lamp.price ? new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(lamp.price) : 'Kein Preis'}</span>
}).format(lamp.price) : (t ? t("kitConfig.noPrice") : 'Kein Preis')}</span>
{lamp.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {lamp.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: lamp.vat }) : `incl. ${lamp.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -947,7 +952,7 @@ class GrowTentKonfigurator extends Component {
mt: 1,
textAlign: 'center'
}}>
Ausgewählt
{t ? t("kitConfig.selected") : "✓ Ausgewählt"}
</Typography>
)}
<Stack direction="row" spacing={1} justifyContent="center">
@@ -973,15 +978,16 @@ class GrowTentKonfigurator extends Component {
renderVentilationSection() {
const { selectedVentilationType, selectedTentShape } = this.state;
const { t } = this.props;
if (!selectedTentShape) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
4. Belüftung auswählen
{t ? t("kitConfig.selectVentilationTitle") : "4. Belüftung auswählen"}
</Typography>
<Typography variant="body2" color="text.secondary">
Bitte wählen Sie zuerst eine Zeltgröße aus.
{t ? t("kitConfig.selectVentilationSubtitle") : "Bitte wählen Sie zuerst eine Zeltgröße aus."}
</Typography>
</Box>
);
@@ -991,10 +997,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
4. Belüftung auswählen - {selectedTentShape}
{t ? t("kitConfig.selectVentilationTitleShape", { shape: selectedTentShape }) : `4. Belüftung auswählen - ${selectedTentShape}`}
</Typography>
<Typography variant="body2" color="text.secondary">
Lade Belüftungs-Produkte...
{t ? t("kitConfig.loadingVentilation") : "Lade Belüftungs-Produkte..."}
</Typography>
</Box>
);
@@ -1006,10 +1012,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
4. Belüftung auswählen - {selectedTentShape}
{t ? t("kitConfig.selectVentilationTitleShape", { shape: selectedTentShape }) : `4. Belüftung auswählen - ${selectedTentShape}`}
</Typography>
<Typography variant="body2" color="text.secondary">
Keine passenden Belüftung für Zeltgröße {selectedTentShape} verfügbar.
{t ? t("kitConfig.noVentilationAvailable", { shape: selectedTentShape }) : `Keine passenden Belüftung für Zeltgröße ${selectedTentShape} verfügbar.`}
</Typography>
</Box>
);
@@ -1018,7 +1024,7 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
4. Belüftung auswählen - {selectedTentShape}
{t ? t("kitConfig.selectVentilationTitleShape", { shape: selectedTentShape }) : `4. Belüftung auswählen - ${selectedTentShape}`}
</Typography>
<Grid container spacing={2}>
{availableVentilation.map((ventilation) => (
@@ -1072,7 +1078,7 @@ class GrowTentKonfigurator extends Component {
p: 1,
borderRadius: 1
}}>
Nicht lieferbar
{t ? t("kitConfig.notDeliverable") : "Nicht lieferbar"}
</Typography>
</Box>
)}
@@ -1108,10 +1114,10 @@ class GrowTentKonfigurator extends Component {
<span>{ventilation.price ? new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(ventilation.price) : 'Kein Preis'}</span>
}).format(ventilation.price) : (t ? t("kitConfig.noPrice") : 'Kein Preis')}</span>
{ventilation.vat && (
<small style={{ color: ventilation.isDeliverable ? '#77aa77' : '#999', fontSize: '0.6em' }}>
(incl. {ventilation.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: ventilation.vat }) : `incl. ${ventilation.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -1124,7 +1130,7 @@ class GrowTentKonfigurator extends Component {
mt: 1,
textAlign: 'center'
}}>
Ausgewählt
{t ? t("kitConfig.selected") : "✓ Ausgewählt"}
</Typography>
)}
<Stack direction="row" spacing={1} justifyContent="center">
@@ -1150,14 +1156,16 @@ class GrowTentKonfigurator extends Component {
renderExtrasSection() {
const { selectedExtras } = this.state;
const { t } = this.props;
if (!this.state.categoryLoadStatus["Set-zubehoer"]) {
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
5. Extras hinzufügen (optional)
{t ? t("kitConfig.selectExtrasTitle") : "5. Extras hinzufügen (optional)"}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Lade Extras...
{t ? t("kitConfig.loadingExtras") : "Lade Extras..."}
</Typography>
</Box>
);
@@ -1170,10 +1178,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
5. Extras hinzufügen (optional)
{t ? t("kitConfig.selectExtrasTitle") : "5. Extras hinzufügen (optional)"}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Keine Extras verfügbar
{t ? t("kitConfig.noExtrasAvailable") : "Keine Extras verfügbar"}
</Typography>
</Box>
);
@@ -1185,10 +1193,10 @@ class GrowTentKonfigurator extends Component {
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
5. Extras hinzufügen (optional)
{t ? t("kitConfig.selectExtrasTitle") : "5. Extras hinzufügen (optional)"}
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Keine Extras verfügbar
{t ? t("kitConfig.noExtrasAvailable") : "Keine Extras verfügbar"}
</Typography>
</Box>
);
@@ -1199,7 +1207,7 @@ class GrowTentKonfigurator extends Component {
extras={extras}
selectedExtras={selectedExtras}
onExtraToggle={this.handleExtraToggle}
title="5. Extras hinzufügen (optional)"
title={t ? t("kitConfig.selectExtrasTitle") : "5. Extras hinzufügen (optional)"}
gridSize={{ xs: 12, sm: 6, md: 4 }}
/>
);
@@ -1207,6 +1215,7 @@ class GrowTentKonfigurator extends Component {
renderInlineSummary() {
const { selectedTentSize, selectedLightType, selectedVentilationType, selectedExtras, totalPrice } = this.state;
const { t } = this.props;
// Find the selected tent from all available shapes
let selectedTent = null;
@@ -1240,21 +1249,21 @@ class GrowTentKonfigurator extends Component {
}}
>
<Typography variant="h5" sx={{ color: '#2e7d32', fontWeight: 'bold', mb: 3, textAlign: 'center' }}>
🎯 Ihre Konfiguration
{t ? t("kitConfig.yourConfiguration") : "🎯 Ihre Konfiguration"}
</Typography>
<List sx={{ '& .MuiListItem-root': { py: 1 } }}>
{selectedTent && (
<ListItem>
<ListItemText
primary={`Growbox: ${selectedTent.name}`}
primary={t ? t("kitConfig.growboxLabel", { name: selectedTent.name }) : `Growbox: ${selectedTent.name}`}
/>
<ListItemSecondaryAction>
<Typography variant="h6" sx={{ fontWeight: 'bold', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<span>{this.formatPrice(selectedTent.price)}</span>
{selectedTent.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {selectedTent.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: selectedTent.vat }) : `incl. ${selectedTent.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -1265,14 +1274,14 @@ class GrowTentKonfigurator extends Component {
{selectedLight && (
<ListItem>
<ListItemText
primary={`Beleuchtung: ${selectedLight.name}`}
primary={t ? t("kitConfig.lightingLabel", { name: selectedLight.name }) : `Beleuchtung: ${selectedLight.name}`}
/>
<ListItemSecondaryAction>
<Typography variant="h6" sx={{ fontWeight: 'bold', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<span>{this.formatPrice(selectedLight.price)}</span>
{selectedLight.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {selectedLight.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: selectedLight.vat }) : `incl. ${selectedLight.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -1283,14 +1292,14 @@ class GrowTentKonfigurator extends Component {
{selectedVentilation && (
<ListItem>
<ListItemText
primary={`Belüftung: ${selectedVentilation.name}`}
primary={t ? t("kitConfig.ventilationLabel", { name: selectedVentilation.name }) : `Belüftung: ${selectedVentilation.name}`}
/>
<ListItemSecondaryAction>
<Typography variant="h6" sx={{ fontWeight: 'bold', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<span>{this.formatPrice(selectedVentilation.price)}</span>
{selectedVentilation.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {selectedVentilation.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: selectedVentilation.vat }) : `incl. ${selectedVentilation.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -1301,14 +1310,14 @@ class GrowTentKonfigurator extends Component {
{selectedExtrasItems.map(extra => (
<ListItem key={extra.id}>
<ListItemText
primary={`Extra: ${extra.name}`}
primary={t ? t("kitConfig.extraLabel", { name: extra.name }) : `Extra: ${extra.name}`}
/>
<ListItemSecondaryAction>
<Typography variant="h6" sx={{ fontWeight: 'bold', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
<span>{this.formatPrice(extra.price)}</span>
{extra.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {extra.vat}% MwSt.,*)
({t ? t("product.inclVat", { vat: extra.vat }) : `incl. ${extra.vat}% MwSt.,*`})
</small>
)}
</Typography>
@@ -1322,24 +1331,24 @@ class GrowTentKonfigurator extends Component {
{savingsInfo.hasDiscount && (
<Box sx={{ mb: 2, textAlign: 'center' }}>
<Typography variant="h6" sx={{ color: '#d32f2f', fontWeight: 'bold' }}>
Sie sparen: {this.formatPrice(savingsInfo.savings)} ({savingsInfo.discountPercentage}% Bundle-Rabatt)
{t ? t("product.youSave", { amount: this.formatPrice(savingsInfo.savings) }) : `Sie sparen: ${this.formatPrice(savingsInfo.savings)}`} ({savingsInfo.discountPercentage}% Bundle-Rabatt)
</Typography>
<Typography variant="caption" sx={{ color: '#77aa77' }}>
(incl. 19% MwSt.,*)
({t ? t("product.inclVat", { vat: 19 }) : "incl. 19% MwSt.,*"})
</Typography>
</Box>
)}
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
<Typography variant="h5" sx={{ fontWeight: 'bold' }}>
Gesamtpreis:
{t ? t("kitConfig.totalPrice") : "Gesamtpreis:"}
</Typography>
<Box sx={{ textAlign: 'right' }}>
<Typography variant="h5" sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
{this.formatPrice(totalPrice)}
</Typography>
<Typography variant="caption" sx={{ color: '#77aa77' }}>
(incl. 19% MwSt.,*)
({t ? t("product.inclVat", { vat: 19 }) : "incl. 19% MwSt.,*"})
</Typography>
</Box>
</Box>
@@ -1356,7 +1365,7 @@ class GrowTentKonfigurator extends Component {
minWidth: 250
}}
>
In den Warenkorb
{t ? t("kitConfig.addToCart") : "In den Warenkorb"}
</Button>
</Box>
</Paper>
@@ -1383,15 +1392,16 @@ class GrowTentKonfigurator extends Component {
render() {
const { t } = this.props;
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Paper elevation={2} sx={{ p: 4, borderRadius: 2 }}>
<Box sx={{ textAlign: 'center', mb: 4 }}>
<Typography variant="h3" component="h1" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
🌱 Growbox Konfigurator
{t ? t("kitConfig.pageTitle") : "🌱 Growbox Konfigurator"}
</Typography>
<Typography variant="h6" color="text.secondary">
Stelle dein perfektes Indoor Grow Setup zusammen
{t ? t("kitConfig.pageSubtitle") : "Stelle dein perfektes Indoor Grow Setup zusammen"}
</Typography>
{/* Bundle Discount Information */}
@@ -1407,7 +1417,7 @@ class GrowTentKonfigurator extends Component {
}}
>
<Typography variant="h6" sx={{ color: '#2e7d32', fontWeight: 'bold', mb: 2 }}>
🎯 Bundle-Rabatt sichern!
{t ? t("kitConfig.bundleDiscountTitle") : "🎯 Bundle-Rabatt sichern!"}
</Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-around', flexWrap: 'wrap', gap: 2 }}>
<Box sx={{ textAlign: 'center' }}>
@@ -1416,7 +1426,7 @@ class GrowTentKonfigurator extends Component {
</Typography>
<Typography variant="body2">
{/* Note: Translation key would be: product.discount.from3Products */}
ab 3 Produkten
{t ? t("product.discount.from3Products") : "ab 3 Produkten"}
</Typography>
</Box>
<Box sx={{ textAlign: 'center' }}>
@@ -1425,7 +1435,7 @@ class GrowTentKonfigurator extends Component {
</Typography>
<Typography variant="body2">
{/* Note: Translation key would be: product.discount.from5Products */}
ab 5 Produkten
{t ? t("product.discount.from5Products") : "ab 5 Produkten"}
</Typography>
</Box>
<Box sx={{ textAlign: 'center' }}>
@@ -1434,13 +1444,13 @@ class GrowTentKonfigurator extends Component {
</Typography>
<Typography variant="body2">
{/* Note: Translation key would be: product.discount.from7Products */}
ab 7 Produkten
{t ? t("product.discount.from7Products") : "ab 7 Produkten"}
</Typography>
</Box>
</Box>
<Typography variant="caption" sx={{ color: '#666', mt: 1, display: 'block' }}>
{/* Note: Translation key would be: product.discount.moreProductsMoreSavings */}
Je mehr Produkte du auswählst, desto mehr sparst du!
{t ? t("product.discount.moreProductsMoreSavings") : "Je mehr Produkte du auswählst, desto mehr sparst du!"}
</Typography>
</Paper>
</Box>
@@ -1466,4 +1476,4 @@ class GrowTentKonfigurator extends Component {
}
}
export default GrowTentKonfigurator;
export default withI18n()(GrowTentKonfigurator);