From 5c90d048fb61286d1b796c3caed11c67af73a6f2 Mon Sep 17 00:00:00 2001 From: sebseb7 Date: Wed, 16 Jul 2025 03:03:47 +0200 Subject: [PATCH] Integrate i18n support across multiple components: Update AddToCartButton, CartDropdown, CartItem, Footer, ProductFilters, ProductList, and profile components to utilize translation functions for dynamic text rendering. Enhance user experience by providing localized content for various UI elements, including buttons, labels, and tax information. --- src/components/AddToCartButton.js | 11 +++-- src/components/CartDropdown.js | 19 ++++---- src/components/CartItem.js | 16 ++++--- src/components/Footer.js | 17 +++---- src/components/ProductFilters.js | 13 ++--- src/components/ProductList.js | 11 +++-- src/components/header/CategoryList.js | 2 +- src/components/profile/OrderDetailsDialog.js | 13 +++-- src/components/profile/OrderSummary.js | 6 ++- .../profile/PaymentConfirmationDialog.js | 17 ++++--- src/i18n/index.js | 8 ++-- src/i18n/locales/de/translation.json | 48 +++++++++++++++++-- 12 files changed, 122 insertions(+), 59 deletions(-) diff --git a/src/components/AddToCartButton.js b/src/components/AddToCartButton.js index a43cb27..a6cc129 100644 --- a/src/components/AddToCartButton.js +++ b/src/components/AddToCartButton.js @@ -10,6 +10,7 @@ import AddIcon from "@mui/icons-material/Add"; import RemoveIcon from "@mui/icons-material/Remove"; import ShoppingCartIcon from "@mui/icons-material/ShoppingCart"; import DeleteIcon from "@mui/icons-material/Delete"; +import { withI18n } from "../i18n/withTranslation.js"; if (!Array.isArray(window.cart)) window.cart = []; @@ -184,7 +185,9 @@ class AddToCartButton extends Component { }, }} > - {this.props.steckling ? "Als Steckling vorbestellen" : "In den Korb"} + {this.props.steckling ? + (this.props.t ? this.props.t('cart.preorderCutting') : "Als Steckling vorbestellen") : + (this.props.t ? this.props.t('cart.addToCart') : "In den Korb")} ); } @@ -330,7 +333,9 @@ class AddToCartButton extends Component { }, }} > - {this.props.steckling ? "Als Steckling vorbestellen" : "In den Korb"} + {this.props.steckling ? + (this.props.t ? this.props.t('cart.preorderCutting') : "Als Steckling vorbestellen") : + (this.props.t ? this.props.t('cart.addToCart') : "In den Korb")} ); } @@ -439,4 +444,4 @@ class AddToCartButton extends Component { } } -export default AddToCartButton; +export default withI18n()(AddToCartButton); diff --git a/src/components/CartDropdown.js b/src/components/CartDropdown.js index 64b5471..188fde8 100644 --- a/src/components/CartDropdown.js +++ b/src/components/CartDropdown.js @@ -8,6 +8,7 @@ import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableRow from '@mui/material/TableRow'; import CartItem from './CartItem.js'; +import { withI18n } from '../i18n/withTranslation.js'; class CartDropdown extends Component { @@ -119,7 +120,7 @@ class CartDropdown extends Component { )} {totalVat7 > 0 && ( - 7% Mehrwertsteuer: + {this.props.t ? this.props.t('tax.vat7') : '7% Mehrwertsteuer'}: {currencyFormatter.format(totalVat7)} @@ -127,7 +128,7 @@ class CartDropdown extends Component { )} {totalVat19 > 0 && ( - 19% Mehrwertsteuer (inkl. Versand): + {this.props.t ? this.props.t('tax.vat19WithShipping') : '19% Mehrwertsteuer (inkl. Versand)'}: {currencyFormatter.format(totalVat19)} @@ -170,14 +171,14 @@ class CartDropdown extends Component { - Gesamtnettopreis: + {this.props.t ? this.props.t('tax.totalNet') : 'Gesamtnettopreis'}: {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format(priceCalculations.totalNet)} {priceCalculations.vat7 > 0 && ( - 7% Mehrwertsteuer: + {this.props.t ? this.props.t('tax.vat7') : '7% Mehrwertsteuer'}: {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format(priceCalculations.vat7)} @@ -185,14 +186,14 @@ class CartDropdown extends Component { )} {priceCalculations.vat19 > 0 && ( - 19% Mehrwertsteuer: + {this.props.t ? this.props.t('tax.vat19') : '19% Mehrwertsteuer'}: {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format(priceCalculations.vat19)} )} - Gesamtbruttopreis ohne Versand: + {this.props.t ? this.props.t('tax.totalGross') : 'Gesamtbruttopreis ohne Versand'}: {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format(priceCalculations.totalGross)} @@ -210,7 +211,7 @@ class CartDropdown extends Component { fullWidth onClick={onClose} > - Weiter einkaufen + {this.props.t ? this.props.t('cart.continueShopping') : 'Weiter einkaufen'} )} @@ -222,7 +223,7 @@ class CartDropdown extends Component { sx={{ mt: 2 }} onClick={onCheckout} > - Weiter zur Kasse + {this.props.t ? this.props.t('cart.proceedToCheckout') : 'Weiter zur Kasse'} )} @@ -232,4 +233,4 @@ class CartDropdown extends Component { } } -export default CartDropdown; \ No newline at end of file +export default withI18n()(CartDropdown); \ No newline at end of file diff --git a/src/components/CartItem.js b/src/components/CartItem.js index 7cf602e..fd6deec 100644 --- a/src/components/CartItem.js +++ b/src/components/CartItem.js @@ -6,6 +6,7 @@ import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; import { Link } from 'react-router-dom'; import AddToCartButton from './AddToCartButton.js'; +import { withI18n } from '../i18n/withTranslation.js'; class CartItem extends Component { @@ -126,9 +127,9 @@ class CartItem extends Component { fontStyle="italic" component="div" > - inkl. {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format( + {this.props.t ? this.props.t('product.inclShort') : 'inkl.'} {new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'}).format( (item.price * item.quantity) - ((item.price * item.quantity) / (1 + item.vat / 100)) - )} MwSt. ({item.vat}%) + )} {this.props.t ? this.props.t('product.vatShort') : 'MwSt.'} ({item.vat}%) )} @@ -146,9 +147,12 @@ class CartItem extends Component { display: "block" }} > - {this.props.id.toString().endsWith("steckling") ? "Lieferzeit: 14 Tage" : - item.available == 1 ? "Lieferzeit: 2-3 Tage" : - item.availableSupplier == 1 ? "Lieferzeit: 7-9 Tage" : ""} + {this.props.id.toString().endsWith("steckling") ? + (this.props.t ? this.props.t('delivery.times.cutting14Days') : "Lieferzeit: 14 Tage") : + item.available == 1 ? + (this.props.t ? this.props.t('delivery.times.standard2to3Days') : "Lieferzeit: 2-3 Tage") : + item.availableSupplier == 1 ? + (this.props.t ? this.props.t('delivery.times.supplier7to9Days') : "Lieferzeit: 7-9 Tage") : ""} @@ -159,4 +163,4 @@ class CartItem extends Component { } } -export default CartItem; \ No newline at end of file +export default withI18n()(CartItem); \ No newline at end of file diff --git a/src/components/Footer.js b/src/components/Footer.js index af57413..40925b6 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -6,6 +6,7 @@ import Link from '@mui/material/Link'; import { Link as RouterLink } from 'react-router-dom'; import { styled } from '@mui/material/styles'; import Paper from '@mui/material/Paper'; +import { withI18n } from '../i18n/withTranslation.js'; // Styled component for the router links const StyledRouterLink = styled(RouterLink)(() => ({ @@ -229,9 +230,9 @@ class Footer extends Component { alignItems={{ xs: 'center', md: 'left' }} flexWrap="wrap" > - Datenschutz - AGB - Sitemap + {this.props.t ? this.props.t('footer.legal.datenschutz') : 'Datenschutz'} + {this.props.t ? this.props.t('footer.legal.agb') : 'AGB'} + {this.props.t ? this.props.t('footer.legal.sitemap') : 'Sitemap'} - Impressum - Batteriegesetzhinweise - Widerrufsrecht + {this.props.t ? this.props.t('footer.legal.impressum') : 'Impressum'} + {this.props.t ? this.props.t('footer.legal.batteriegesetzhinweise') : 'Batteriegesetzhinweise'} + {this.props.t ? this.props.t('footer.legal.widerrufsrecht') : 'Widerrufsrecht'} {/* Payment Methods Section */} @@ -338,7 +339,7 @@ class Footer extends Component { {/* Copyright Section */} - * Alle Preise inkl. gesetzlicher USt., zzgl. Versand + {this.props.t ? this.props.t('footer.allPricesIncl') : '* Alle Preise inkl. gesetzlicher USt., zzgl. Versand'} © {new Date().getFullYear()} GrowHeads.de @@ -351,4 +352,4 @@ class Footer extends Component { } } -export default Footer; +export default withI18n()(Footer); diff --git a/src/components/ProductFilters.js b/src/components/ProductFilters.js index 9be4dd2..659be5c 100644 --- a/src/components/ProductFilters.js +++ b/src/components/ProductFilters.js @@ -4,6 +4,7 @@ import Typography from '@mui/material/Typography'; import Filter from './Filter.js'; import { useParams, useSearchParams, useNavigate, useLocation } from 'react-router-dom'; import { setSessionSetting, removeSessionSetting, clearAllSessionSettings } from '../utils/sessionStorage.js'; +import { withI18n } from '../i18n/withTranslation.js'; const isNew = (neu) => neu && (new Date().getTime() - new Date(neu).getTime() < 30 * 24 * 60 * 60 * 1000); @@ -93,14 +94,14 @@ class ProductFilters extends Component { } _getAvailabilityValues = (products) => { - const filters = [{id:1,name:'auf Lager'}]; + const filters = [{id:1,name: this.props.t ? this.props.t('product.inStock') : 'auf Lager'}]; for(const product of products){ if(isNew(product.neu)){ - if(!filters.find(filter => filter.id == 2)) filters.push({id:2,name:'Neu'}); + if(!filters.find(filter => filter.id == 2)) filters.push({id:2,name: this.props.t ? this.props.t('product.new') : 'Neu'}); } if(!product.available && product.incomingDate){ - if(!filters.find(filter => filter.id == 3)) filters.push({id:3,name:'Bald verfügbar'}); + if(!filters.find(filter => filter.id == 3)) filters.push({id:3,name: this.props.t ? this.props.t('product.comingSoon') : 'Bald verfügbar'}); } } return filters @@ -193,7 +194,7 @@ class ProductFilters extends Component { {this.props.products.length > 0 && ( <> - Sortierung + {this.props.t ? this.props.t('filters.sorting') : 'Sortierung'} { diff --git a/src/components/profile/OrderDetailsDialog.js b/src/components/profile/OrderDetailsDialog.js index d229da7..6f94c6c 100644 --- a/src/components/profile/OrderDetailsDialog.js +++ b/src/components/profile/OrderDetailsDialog.js @@ -15,8 +15,11 @@ import { TableRow, Paper } from '@mui/material'; +import { useTranslation } from 'react-i18next'; const OrderDetailsDialog = ({ open, onClose, order }) => { + const { t } = useTranslation(); + if (!order) { return null; } @@ -108,7 +111,7 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { - Gesamtnettopreis + {t ? t('tax.totalNet') : 'Gesamtnettopreis'} {currencyFormatter.format(vatCalculations.totalNet)} @@ -117,21 +120,21 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { {vatCalculations.vat7 > 0 && ( - 7% Mehrwertsteuer + {t ? t('tax.vat7') : '7% Mehrwertsteuer'} {currencyFormatter.format(vatCalculations.vat7)} )} {vatCalculations.vat19 > 0 && ( - 19% Mehrwertsteuer + {t ? t('tax.vat19') : '19% Mehrwertsteuer'} {currencyFormatter.format(vatCalculations.vat19)} )} - Zwischensumme + {t ? t('tax.subtotal') : 'Zwischensumme'} {currencyFormatter.format(subtotal)} @@ -162,7 +165,7 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { Bestellung stornieren )} - + ); diff --git a/src/components/profile/OrderSummary.js b/src/components/profile/OrderSummary.js index 97080e4..0d978a0 100644 --- a/src/components/profile/OrderSummary.js +++ b/src/components/profile/OrderSummary.js @@ -5,8 +5,10 @@ import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableRow from '@mui/material/TableRow'; +import { useTranslation } from 'react-i18next'; const OrderSummary = ({ deliveryCost, cartItems = [] }) => { + const { t } = useTranslation(); const currencyFormatter = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' @@ -63,7 +65,7 @@ const OrderSummary = ({ deliveryCost, cartItems = [] }) => { )} {totalVat7 > 0 && ( - 7% Mehrwertsteuer: + {t ? t('tax.vat7') : '7% Mehrwertsteuer'}: {currencyFormatter.format(totalVat7)} @@ -71,7 +73,7 @@ const OrderSummary = ({ deliveryCost, cartItems = [] }) => { )} {totalVat19 > 0 && ( - 19% Mehrwertsteuer (inkl. Versand): + {t ? t('tax.vat19WithShipping') : '19% Mehrwertsteuer (inkl. Versand)'}: {currencyFormatter.format(totalVat19)} diff --git a/src/components/profile/PaymentConfirmationDialog.js b/src/components/profile/PaymentConfirmationDialog.js index 151db14..5e76bc1 100644 --- a/src/components/profile/PaymentConfirmationDialog.js +++ b/src/components/profile/PaymentConfirmationDialog.js @@ -1,5 +1,6 @@ import React, { Component } from "react"; import { Box, Typography, Button } from "@mui/material"; +import { withI18n } from "../../i18n/withTranslation.js"; class PaymentConfirmationDialog extends Component { render() { @@ -28,24 +29,26 @@ class PaymentConfirmationDialog extends Component { color: paymentCompletionData.isSuccessful ? '#2e7d32' : '#d32f2f', fontWeight: 'bold' }}> - {paymentCompletionData.isSuccessful ? 'Zahlung erfolgreich!' : 'Zahlung fehlgeschlagen'} + {paymentCompletionData.isSuccessful ? + (this.props.t ? this.props.t('payment.successful') : 'Zahlung erfolgreich!') : + (this.props.t ? this.props.t('payment.failed') : 'Zahlung fehlgeschlagen')} {paymentCompletionData.isSuccessful ? ( <> {orderCompleted ? ( - 🎉 Ihre Bestellung wurde erfolgreich abgeschlossen! Sie können jetzt Ihre Bestellungen einsehen. +{this.props.t ? this.props.t('payment.orderCompleted') : '🎉 Ihre Bestellung wurde erfolgreich abgeschlossen! Sie können jetzt Ihre Bestellungen einsehen.'} ) : ( - Ihre Zahlung wurde erfolgreich verarbeitet. Die Bestellung wird automatisch abgeschlossen. +{this.props.t ? this.props.t('payment.orderProcessing') : 'Ihre Zahlung wurde erfolgreich verarbeitet. Die Bestellung wird automatisch abgeschlossen.'} )} ) : ( - Ihre Zahlung konnte nicht verarbeitet werden. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode. +{this.props.t ? this.props.t('payment.paymentError') : 'Ihre Zahlung konnte nicht verarbeitet werden. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode.'} )} @@ -75,7 +78,7 @@ class PaymentConfirmationDialog extends Component { } }} > - Weiter einkaufen +{this.props.t ? this.props.t('cart.continueShopping') : 'Weiter einkaufen'} )} @@ -94,4 +97,4 @@ class PaymentConfirmationDialog extends Component { } } -export default PaymentConfirmationDialog; \ No newline at end of file +export default withI18n()(PaymentConfirmationDialog); \ No newline at end of file diff --git a/src/i18n/index.js b/src/i18n/index.js index 99b5c70..e3d8aca 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -5,7 +5,7 @@ import LanguageDetector from 'i18next-browser-languagedetector'; // Import all translation files import translationDE from './locales/de/translation.json'; import translationEN from './locales/en/translation.json'; -import translationES from './locales/es/translation.json'; +/*import translationES from './locales/es/translation.json'; import translationFR from './locales/fr/translation.json'; import translationIT from './locales/it/translation.json'; import translationPL from './locales/pl/translation.json'; @@ -17,14 +17,14 @@ import translationUK from './locales/uk/translation.json'; import translationSK from './locales/sk/translation.json'; import translationCS from './locales/cs/translation.json'; import translationRO from './locales/ro/translation.json'; - +*/ const resources = { de: { translation: translationDE }, en: { translation: translationEN - }, + }/*, es: { translation: translationES }, @@ -60,7 +60,7 @@ const resources = { }, ro: { translation: translationRO - } + }*/ }; i18n diff --git a/src/i18n/locales/de/translation.json b/src/i18n/locales/de/translation.json index 4ce4dd2..174d372 100644 --- a/src/i18n/locales/de/translation.json +++ b/src/i18n/locales/de/translation.json @@ -3,7 +3,9 @@ "home": "Startseite", "aktionen": "Aktionen", "filiale": "Filiale", - "categories": "Kategorien" + "categories": "Kategorien", + "categoriesOpen": "Kategorien öffnen", + "categoriesClose": "Kategorien schließen" }, "auth": { "login": "Anmelden", @@ -32,6 +34,10 @@ "cart": { "title": "Warenkorb", "empty": "leer", + "addToCart": "In den Korb", + "preorderCutting": "Als Steckling vorbestellen", + "continueShopping": "Weiter einkaufen", + "proceedToCheckout": "Weiter zur Kasse", "sync": { "title": "Warenkorb-Synchronisierung", "description": "Sie haben einen gespeicherten Warenkorb in ihrem Account. Bitte wählen Sie, wie Sie verfahren möchten:", @@ -54,7 +60,13 @@ "priceUnit": "{{price}}/{{unit}}", "new": "Neu", "arriving": "Ankunft:", - "inclVatFooter": "incl. {{vat}}% USt.,*" + "inclVatFooter": "incl. {{vat}}% USt.,*", + "availability": "Verfügbarkeit", + "inStock": "auf Lager", + "comingSoon": "Bald verfügbar", + "deliveryTime": "Lieferzeit", + "inclShort": "inkl.", + "vatShort": "MwSt." }, "search": { "placeholder": "Du kannst mich nach Cannabissorten fragen...", @@ -81,6 +93,11 @@ "dhl": "6,99 €", "dpd": "4,90 €", "sperrgut": "28,99 €" + }, + "times": { + "cutting14Days": "Lieferzeit: 14 Tage", + "standard2to3Days": "Lieferzeit: 2-3 Tage", + "supplier7to9Days": "Lieferzeit: 7-9 Tage" } }, "checkout": { @@ -92,6 +109,29 @@ "sameAddress": "Lieferadresse ist identisch mit Rechnungsadresse", "termsAccept": "Ich habe die AGBs, die Datenschutzerklärung und die Bestimmungen zum Widerrufsrecht gelesen" }, + "payment": { + "successful": "Zahlung erfolgreich!", + "failed": "Zahlung fehlgeschlagen", + "orderCompleted": "🎉 Ihre Bestellung wurde erfolgreich abgeschlossen! Sie können jetzt Ihre Bestellungen einsehen.", + "orderProcessing": "Ihre Zahlung wurde erfolgreich verarbeitet. Die Bestellung wird automatisch abgeschlossen.", + "paymentError": "Ihre Zahlung konnte nicht verarbeitet werden. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode.", + "viewOrders": "Zu meinen Bestellungen" + }, + "filters": { + "sorting": "Sortierung", + "perPage": "pro Seite", + "availability": "Verfügbarkeit", + "manufacturer": "Hersteller" + }, + "tax": { + "vat": "Mehrwertsteuer", + "vat7": "7% Mehrwertsteuer", + "vat19": "19% Mehrwertsteuer", + "vat19WithShipping": "19% Mehrwertsteuer (inkl. Versand)", + "totalNet": "Gesamtnettopreis", + "totalGross": "Gesamtbruttopreis ohne Versand", + "subtotal": "Zwischensumme" + }, "footer": { "hours": "Sa 11-19", "address": "Trachenberger Straße 14 - Dresden", @@ -157,6 +197,8 @@ "edit": "Bearbeiten", "delete": "Löschen", "add": "Hinzufügen", - "remove": "Entfernen" + "remove": "Entfernen", + "products": "Produkte", + "product": "Produkt" } } \ No newline at end of file