Refactor project for i18n support: Rename project to "i18n-translator" and update package.json and package-lock.json accordingly. Enhance localization by integrating translation functions across various components, including AddToCartButton, Content, GoogleLoginButton, and others, to provide dynamic text rendering based on user language preferences. Update localization files for multiple languages, ensuring comprehensive support for internationalization.

This commit is contained in:
sebseb7
2025-07-16 05:59:48 +02:00
parent 859a2c06d8
commit 51471d4a55
33 changed files with 3949 additions and 13945 deletions

View File

@@ -154,12 +154,17 @@ class AddToCartButton extends Component {
},
}}
>
Ab{" "}
{new Date(incoming).toLocaleDateString("de-DE", {
{this.props.t ? this.props.t('cart.availableFrom', {
date: new Date(incoming).toLocaleDateString("de-DE", {
year: "numeric",
month: "long",
day: "numeric",
})
}) : `Ab ${new Date(incoming).toLocaleDateString("de-DE", {
year: "numeric",
month: "long",
day: "numeric",
})}
})}`}
</Button>
);
}
@@ -265,7 +270,7 @@ class AddToCartButton extends Component {
<AddIcon />
</IconButton>
<Tooltip title="Aus dem Warenkorb entfernen" arrow>
<Tooltip title={this.props.t ? this.props.t('cart.removeFromCart') : 'Aus dem Warenkorb entfernen'} arrow>
<IconButton
color="inherit"
onClick={this.handleClearCart}
@@ -278,7 +283,7 @@ class AddToCartButton extends Component {
</IconButton>
</Tooltip>
{this.props.cartButton && (
<Tooltip title="Warenkorb öffnen" arrow>
<Tooltip title={this.props.t ? this.props.t('cart.openCart') : 'Warenkorb öffnen'} arrow>
<IconButton
color="inherit"
onClick={this.toggleCart}
@@ -308,7 +313,7 @@ class AddToCartButton extends Component {
fontWeight: "bold",
}}
>
Out of Stock
{this.props.t ? this.props.t('product.outOfStock') : 'Out of Stock'}
</Button>
);
}
@@ -412,7 +417,7 @@ class AddToCartButton extends Component {
<AddIcon />
</IconButton>
<Tooltip title="Aus dem Warenkorb entfernen" arrow>
<Tooltip title={this.props.t ? this.props.t('cart.removeFromCart') : 'Aus dem Warenkorb entfernen'} arrow>
<IconButton
color="inherit"
onClick={this.handleClearCart}
@@ -425,7 +430,7 @@ class AddToCartButton extends Component {
</IconButton>
</Tooltip>
{this.props.cartButton && (
<Tooltip title="Warenkorb öffnen" arrow>
<Tooltip title={this.props.t ? this.props.t('cart.openCart') : 'Warenkorb öffnen'} arrow>
<IconButton
color="inherit"
onClick={this.toggleCart}

View File

@@ -13,6 +13,7 @@ import CategoryBox from './CategoryBox.js';
import { useParams, useSearchParams } from 'react-router-dom';
import { getAllSettingsWithPrefix } 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);
@@ -149,17 +150,17 @@ function getFilteredProducts(unfilteredProducts, attributes) {
// Check for "auf Lager" filter (in stock) - it's active when filter_availability is NOT set to '1'
if (availabilityFilter !== '1') {
activeAvailabilityFilters.push({id: '1', name: 'auf Lager'});
activeAvailabilityFilters.push({id: '1', name: this.props.t ? this.props.t('product.inStock') : 'auf Lager'});
}
// Check for "Neu" filter (new) - only show if there are actually new products and filter is active
if (availabilityFilters.includes('2') && hasNewProducts) {
activeAvailabilityFilters.push({id: '2', name: 'Neu'});
activeAvailabilityFilters.push({id: '2', name: this.props.t ? this.props.t('product.new') : 'Neu'});
}
// Check for "Bald verfügbar" filter (coming soon) - only show if there are actually coming soon products and filter is active
if (availabilityFilters.includes('3') && hasComingSoonProducts) {
activeAvailabilityFilters.push({id: '3', name: 'Bald verfügbar'});
activeAvailabilityFilters.push({id: '3', name: this.props.t ? this.props.t('product.comingSoon') : 'Bald verfügbar'});
}
return {filteredProducts,activeAttributeFilters:activeAttributeFiltersWithNames,activeManufacturerFilters:activeManufacturerFiltersWithNames,activeAvailabilityFilters};
@@ -602,7 +603,7 @@ class Content extends Component {
{(this.getCurrentCategoryId() == 706 || this.getCurrentCategoryId() == 689) &&
<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
<Typography variant="h6" sx={{mt:3}}>
Andere Kategorien
{this.props.t ? this.props.t('navigation.otherCategories') : 'Andere Kategorien'}
</Typography>
</Box>
}
@@ -647,7 +648,7 @@ class Content extends Component {
p: 2,
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
Seeds
{this.props.t('sections.seeds')}
</Typography>
</Box>
</Box>
@@ -694,7 +695,7 @@ class Content extends Component {
p: 2,
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
Stecklinge
{this.props.t('sections.stecklinge')}
</Typography>
</Box>
</Box>
@@ -723,4 +724,4 @@ class Content extends Component {
}
}
export default withRouter(Content);
export default withRouter(withI18n()(Content));

View File

@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import Button from '@mui/material/Button';
import GoogleIcon from '@mui/icons-material/Google';
import GoogleAuthContext from '../contexts/GoogleAuthContext.js';
import { withI18n } from '../i18n/index.js';
class GoogleLoginButton extends Component {
static contextType = GoogleAuthContext;
@@ -186,7 +187,7 @@ class GoogleLoginButton extends Component {
};
render() {
const { disabled, style, className, text = 'Mit Google anmelden' } = this.props;
const { disabled, style, className, text = (this.props.t ? this.props.t('auth.loginWithGoogle') : 'Mit Google anmelden') } = this.props;
const { isInitializing, isPrompting } = this.state;
const isLoading = isInitializing || isPrompting || (this.context && !this.context.isLoaded);
@@ -205,4 +206,4 @@ class GoogleLoginButton extends Component {
}
}
export default GoogleLoginButton;
export default withI18n(GoogleLoginButton);

View File

@@ -744,7 +744,7 @@ export class LoginComponent extends Component {
onClick={tabValue === 0 ? this.handleLogin : this.handleRegister}
sx={{ mt: 2, bgcolor: '#2e7d32', '&:hover': { bgcolor: '#1b5e20' } }}
>
{tabValue === 0 ? 'ANMELDEN' : 'REGISTRIEREN'}
{tabValue === 0 ? (this.props.t ? this.props.t('auth.login').toUpperCase() : 'ANMELDEN') : (this.props.t ? this.props.t('auth.register').toUpperCase() : 'REGISTRIEREN')}
</Button>
)}
</Box>

View File

@@ -44,9 +44,9 @@ const MainPageLayout = () => {
};
const allTitles = {
home: "ine annabis eeds & uttings",
aktionen: "tuelle ktionen & gebote",
filiale: "nsere iliale in resden"
home: t('titles.home'),
aktionen: t('titles.aktionen'),
filiale: t('titles.filiale')
};
// Define all content boxes for layered rendering

View File

@@ -490,7 +490,7 @@ class ProductDetailPage extends Component {
<Typography>{error}</Typography>
<Link to="/" style={{ textDecoration: "none" }}>
<Typography color="primary" sx={{ mt: 2 }}>
Zurück zur Startseite
{this.props.t ? this.props.t('product.backToHome') : 'Zurück zur Startseite'}
</Typography>
</Link>
</Box>
@@ -508,7 +508,7 @@ class ProductDetailPage extends Component {
</Typography>
<Link to="/" style={{ textDecoration: "none" }}>
<Typography color="primary" sx={{ mt: 2 }}>
Zurück zur Startseite
{this.props.t ? this.props.t('product.backToHome') : 'Zurück zur Startseite'}
</Typography>
</Link>
</Box>
@@ -573,7 +573,7 @@ class ProductDetailPage extends Component {
fontWeight: "bold",
}}
>
Zurück
{this.props.t ? this.props.t('common.back') : 'Zurück'}
</Link>
</Typography>
</Box>
@@ -634,7 +634,7 @@ class ProductDetailPage extends Component {
{/* Product identifiers */}
<Box sx={{ mb: 1 }}>
<Typography variant="body2" color="text.secondary">
Artikelnummer: {product.articleNumber} {product.gtin ? ` | GTIN: ${product.gtin}` : ""}
{this.props.t ? this.props.t('product.articleNumber') : 'Artikelnummer'}: {product.articleNumber} {product.gtin ? ` | GTIN: ${product.gtin}` : ""}
</Typography>
</Box>
@@ -652,7 +652,7 @@ class ProductDetailPage extends Component {
{product.manufacturer && (
<Box sx={{ display: "flex", alignItems: "center", mb: 2 }}>
<Typography variant="body2" sx={{ fontStyle: "italic" }}>
Hersteller: {product.manufacturer}
{this.props.t ? this.props.t('product.manufacturer') : 'Hersteller'}: {product.manufacturer}
</Typography>
</Box>
)}

View File

@@ -185,7 +185,7 @@ class ProductList extends Component {
px: 2
}}>
<Typography variant="h6" color="text.secondary" sx={{ textAlign: 'center' }}>
Entferne Filter um Produkte zu sehen
{this.props.t ? this.props.t('product.removeFiltersToSee') : 'Entferne Filter um Produkte zu sehen'}
</Typography>
</Box>
);
@@ -354,10 +354,10 @@ class ProductList extends Component {
}
}}
>
<MenuItem value="name">Name</MenuItem>
{window.currentSearchQuery && <MenuItem value="searchField">Suchbegriff</MenuItem>}
<MenuItem value="price-low-high">Preis: Niedrig zu Hoch</MenuItem>
<MenuItem value="price-high-low">Preis: Hoch zu Niedrig</MenuItem>
<MenuItem value="name">{this.props.t ? this.props.t('sorting.name') : 'Name'}</MenuItem>
{window.currentSearchQuery && <MenuItem value="searchField">{this.props.t ? this.props.t('sorting.searchField') : 'Suchbegriff'}</MenuItem>}
<MenuItem value="price-low-high">{this.props.t ? this.props.t('sorting.priceLowHigh') : 'Preis: Niedrig zu Hoch'}</MenuItem>
<MenuItem value="price-high-low">{this.props.t ? this.props.t('sorting.priceHighLow') : 'Preis: Hoch zu Niedrig'}</MenuItem>
</Select>
</FormControl>

View File

@@ -7,6 +7,7 @@ import ChevronRight from "@mui/icons-material/ChevronRight";
import CategoryBox from "./CategoryBox.js";
import SocketContext from "../contexts/SocketContext.js";
import { useCarousel } from "../contexts/CarouselContext.js";
import { useTranslation } from 'react-i18next';
// Helper to process and set categories
const processCategoryTree = (categoryTree) => {
@@ -52,6 +53,7 @@ const initializeCategories = () => {
const SharedCarousel = () => {
const { carouselRef, filteredCategories, setFilteredCategories, moveCarousel } = useCarousel();
const context = useContext(SocketContext);
const { t } = useTranslation();
const [rootCategories, setRootCategories] = useState([]);
useEffect(() => {
@@ -111,7 +113,7 @@ const SharedCarousel = () => {
textShadow: "3px 3px 10px rgba(0, 0, 0, 0.4)"
}}
>
Kategorien
{t('navigation.categories')}
</Typography>
<div

View File

@@ -6,6 +6,7 @@ import PaymentConfirmationDialog from "./PaymentConfirmationDialog.js";
import OrderProcessingService from "./OrderProcessingService.js";
import CheckoutValidation from "./CheckoutValidation.js";
import SocketContext from "../../contexts/SocketContext.js";
import { withI18n } from "../../i18n/index.js";
class CartTab extends Component {
constructor(props) {
@@ -497,7 +498,7 @@ class CartTab extends Component {
}
}}
>
Zurück zur Bestellung
{this.props.t ? this.props.t('cart.backToOrder') : '← Zurück zur Bestellung'}
</Button>
</Box>
<StripeComponent clientSecret={stripeClientSecret} />
@@ -541,4 +542,4 @@ class CartTab extends Component {
// Set static contextType to access the socket
CartTab.contextType = SocketContext;
export default CartTab;
export default withI18n(CartTab);