Implement multilingual support: Integrate i18next for language translation across components, update configuration for multilingual descriptions and keywords, and enhance user interface elements with dynamic language switching. Add new dependencies for i18next and related libraries in package.json and package-lock.json.
This commit is contained in:
209
MULTILINGUAL_IMPLEMENTATION.md
Normal file
209
MULTILINGUAL_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# Multilingual Implementation Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Your website now supports multiple languages using **react-i18next**. The implementation is designed to work seamlessly with your existing class components and provides:
|
||||
|
||||
- **German (default)** and **English** support
|
||||
- Language persistence in localStorage
|
||||
- Dynamic language switching
|
||||
- SEO-friendly language attributes
|
||||
- Class component compatibility
|
||||
|
||||
## Features Implemented
|
||||
|
||||
### 1. Language Switcher
|
||||
- Located in the header next to the login/profile button
|
||||
- Shows current language (DE/EN) with flag icon
|
||||
- Dropdown menu for language selection
|
||||
- Persists selection in browser storage
|
||||
|
||||
### 2. Translated Components
|
||||
- **Header navigation**: Categories, Home links
|
||||
- **Authentication**: Login/register forms, profile menu
|
||||
- **Main pages**: Home, Actions, Store pages
|
||||
- **Cart**: Shopping cart title and sync dialog
|
||||
- **Product pages**: Basic UI elements (more can be added)
|
||||
- **Footer**: Basic elements (can be expanded)
|
||||
|
||||
### 3. Architecture
|
||||
- `src/i18n/index.js` - Main i18n configuration
|
||||
- `src/i18n/withTranslation.js` - HOCs for class components
|
||||
- `src/i18n/locales/de/translation.json` - German translations
|
||||
- `src/i18n/locales/en/translation.json` - English translations
|
||||
- `src/components/LanguageSwitcher.js` - Language selection component
|
||||
|
||||
## Usage for Developers
|
||||
|
||||
### Using Translations in Class Components
|
||||
|
||||
```javascript
|
||||
import { withI18n } from '../i18n/withTranslation.js';
|
||||
|
||||
class MyComponent extends Component {
|
||||
render() {
|
||||
const { t } = this.props; // Translation function
|
||||
|
||||
return (
|
||||
<Typography>
|
||||
{t('navigation.home')} // Translates to "Startseite" or "Home"
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withI18n()(MyComponent);
|
||||
```
|
||||
|
||||
### Using Translations in Function Components
|
||||
|
||||
```javascript
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MyComponent = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Typography>
|
||||
{t('navigation.home')}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Language Context Access
|
||||
|
||||
```javascript
|
||||
import { withLanguage } from '../i18n/withTranslation.js';
|
||||
|
||||
class MyComponent extends Component {
|
||||
render() {
|
||||
const { languageContext } = this.props;
|
||||
|
||||
return (
|
||||
<Button onClick={() => languageContext.changeLanguage('en')}>
|
||||
Switch to English
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withLanguage(MyComponent);
|
||||
```
|
||||
|
||||
## Adding New Translations
|
||||
|
||||
### 1. Add to German (`src/i18n/locales/de/translation.json`)
|
||||
```json
|
||||
{
|
||||
"newSection": {
|
||||
"title": "Neuer Titel",
|
||||
"description": "Neue Beschreibung"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add to English (`src/i18n/locales/en/translation.json`)
|
||||
```json
|
||||
{
|
||||
"newSection": {
|
||||
"title": "New Title",
|
||||
"description": "New Description"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use in Components
|
||||
```javascript
|
||||
{t('newSection.title')}
|
||||
```
|
||||
|
||||
## Adding New Languages
|
||||
|
||||
### 1. Create Translation File
|
||||
Create `src/i18n/locales/fr/translation.json` for French
|
||||
|
||||
### 2. Update i18n Configuration
|
||||
```javascript
|
||||
// src/i18n/index.js
|
||||
import translationFR from './locales/fr/translation.json';
|
||||
|
||||
const resources = {
|
||||
de: { translation: translationDE },
|
||||
en: { translation: translationEN },
|
||||
fr: { translation: translationFR } // Add new language
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Update Language Provider
|
||||
```javascript
|
||||
// src/i18n/withTranslation.js
|
||||
availableLanguages: ['de', 'en', 'fr'] // Add to available languages
|
||||
```
|
||||
|
||||
### 4. Update Language Switcher
|
||||
```javascript
|
||||
// src/components/LanguageSwitcher.js
|
||||
const names = {
|
||||
'de': 'Deutsch',
|
||||
'en': 'English',
|
||||
'fr': 'Français' // Add language name
|
||||
};
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Language Detection Order
|
||||
Currently set to: `['localStorage', 'navigator', 'htmlTag']`
|
||||
- First checks localStorage for saved preference
|
||||
- Falls back to browser language
|
||||
- Finally checks HTML lang attribute
|
||||
|
||||
### Fallback Language
|
||||
Set to German (`de`) as your primary language
|
||||
|
||||
### Debug Mode
|
||||
Enabled in development mode for easier debugging
|
||||
|
||||
## SEO Considerations
|
||||
|
||||
- HTML `lang` attribute updates automatically
|
||||
- Config object provides language-specific metadata
|
||||
- Descriptions and keywords are language-aware
|
||||
- Can be extended for hreflang tags and URL localization
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Namespace your translations** - Use nested objects for organization
|
||||
2. **Provide fallbacks** - Always have German as fallback since it's your primary market
|
||||
3. **Use interpolation** - For dynamic content: `t('welcome', { name: 'John' })`
|
||||
4. **Keep translations consistent** - Use same structure in all language files
|
||||
5. **Test thoroughly** - Verify all UI elements in both languages
|
||||
|
||||
## Current Translation Coverage
|
||||
|
||||
- ✅ Navigation and menus
|
||||
- ✅ Authentication flows
|
||||
- ✅ Basic product elements
|
||||
- ✅ Cart functionality
|
||||
- ✅ Main page content
|
||||
- ⏳ Detailed product descriptions (can be added)
|
||||
- ⏳ Legal pages content (can be added)
|
||||
- ⏳ Form validation messages (can be added)
|
||||
- ⏳ Error messages (can be added)
|
||||
|
||||
## Performance
|
||||
|
||||
- Translations are bundled and loaded immediately
|
||||
- No additional network requests
|
||||
- Lightweight implementation
|
||||
- Language switching is instant
|
||||
|
||||
## Browser Support
|
||||
|
||||
Works with all modern browsers that support:
|
||||
- ES6 modules
|
||||
- localStorage
|
||||
- React 19
|
||||
|
||||
The implementation is production-ready and can be extended based on your specific needs!
|
||||
94
package-lock.json
generated
94
package-lock.json
generated
@@ -16,10 +16,14 @@
|
||||
"@stripe/react-stripe-js": "^3.7.0",
|
||||
"@stripe/stripe-js": "^7.3.1",
|
||||
"chart.js": "^4.5.0",
|
||||
"country-flag-icons": "^1.5.19",
|
||||
"html-react-parser": "^5.2.5",
|
||||
"i18next": "^25.3.2",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"react": "^19.1.0",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-i18next": "^15.6.0",
|
||||
"react-router-dom": "^7.6.2",
|
||||
"sharp": "^0.34.2",
|
||||
"socket.io-client": "^4.7.5"
|
||||
@@ -4860,6 +4864,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/country-flag-icons": {
|
||||
"version": "1.5.19",
|
||||
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.19.tgz",
|
||||
"integrity": "sha512-D/ZkRyj+ywJC6b2IrAN3/tpbReMUqmuRLlcKFoY/o0+EPQN9Ev/e8tV+D3+9scvu/tarxwLErNwS73C3yzxs/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
@@ -7249,6 +7259,15 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-react-parser": {
|
||||
"version": "5.2.5",
|
||||
"resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-5.2.5.tgz",
|
||||
@@ -7482,6 +7501,46 @@
|
||||
"node": ">=10.18"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "25.3.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.2.tgz",
|
||||
"integrity": "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com/i18next.html"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-browser-languagedetector": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz",
|
||||
"integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
@@ -9699,6 +9758,32 @@
|
||||
"react": "^19.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "15.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.6.0.tgz",
|
||||
"integrity": "sha512-W135dB0rDfiFmbMipC17nOhGdttO5mzH8BivY+2ybsQBbXvxWIwl3cmeH3T9d+YPBSJu/ouyJKFJTtkK7rJofw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.6",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 23.2.3",
|
||||
"react": ">= 16.8.0",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz",
|
||||
@@ -11825,6 +11910,15 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
||||
|
||||
@@ -27,10 +27,14 @@
|
||||
"@stripe/react-stripe-js": "^3.7.0",
|
||||
"@stripe/stripe-js": "^7.3.1",
|
||||
"chart.js": "^4.5.0",
|
||||
"country-flag-icons": "^1.5.19",
|
||||
"html-react-parser": "^5.2.5",
|
||||
"i18next": "^25.3.2",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"react": "^19.1.0",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-i18next": "^15.6.0",
|
||||
"react-router-dom": "^7.6.2",
|
||||
"sharp": "^0.34.2",
|
||||
"socket.io-client": "^4.7.5"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<html lang="de" data-i18n-lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
58
src/App.js
58
src/App.js
@@ -21,6 +21,11 @@ import SocketContext from "./contexts/SocketContext.js";
|
||||
import { CarouselProvider } from "./contexts/CarouselContext.js";
|
||||
import config from "./config.js";
|
||||
import ScrollToTop from "./components/ScrollToTop.js";
|
||||
|
||||
// Import i18n
|
||||
import './i18n/index.js';
|
||||
import { LanguageProvider } from './i18n/withTranslation.js';
|
||||
import i18n from './i18n/index.js';
|
||||
//import TelemetryService from './services/telemetryService.js';
|
||||
|
||||
import Header from "./components/Header.js";
|
||||
@@ -361,30 +366,37 @@ const App = () => {
|
||||
setDynamicTheme(createTheme(newTheme));
|
||||
};
|
||||
|
||||
// Make config globally available for language switching
|
||||
useEffect(() => {
|
||||
window.shopConfig = config;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={dynamicTheme}>
|
||||
<CssBaseline />
|
||||
<SocketProvider
|
||||
url={config.apiBaseUrl}
|
||||
fallback={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
}}
|
||||
>
|
||||
<CircularProgress color="primary" />
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<AppContent
|
||||
currentTheme={currentTheme}
|
||||
onThemeChange={handleThemeChange}
|
||||
/>
|
||||
</SocketProvider>
|
||||
</ThemeProvider>
|
||||
<LanguageProvider i18n={i18n}>
|
||||
<ThemeProvider theme={dynamicTheme}>
|
||||
<CssBaseline />
|
||||
<SocketProvider
|
||||
url={config.apiBaseUrl}
|
||||
fallback={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
}}
|
||||
>
|
||||
<CircularProgress color="primary" />
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<AppContent
|
||||
currentTheme={currentTheme}
|
||||
onThemeChange={handleThemeChange}
|
||||
/>
|
||||
</SocketProvider>
|
||||
</ThemeProvider>
|
||||
</LanguageProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
248
src/components/LanguageSwitcher.js
Normal file
248
src/components/LanguageSwitcher.js
Normal file
@@ -0,0 +1,248 @@
|
||||
import React, { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { withI18n } from '../i18n/withTranslation.js';
|
||||
|
||||
class LanguageSwitcher extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
anchorEl: null,
|
||||
loadedFlags: {}
|
||||
};
|
||||
}
|
||||
|
||||
handleClick = (event) => {
|
||||
this.setState({ anchorEl: event.currentTarget });
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ anchorEl: null });
|
||||
};
|
||||
|
||||
handleLanguageChange = (language) => {
|
||||
const { languageContext } = this.props;
|
||||
if (languageContext) {
|
||||
languageContext.changeLanguage(language);
|
||||
}
|
||||
this.handleClose();
|
||||
};
|
||||
|
||||
// Lazy load flag components
|
||||
loadFlagComponent = async (lang) => {
|
||||
if (this.state.loadedFlags[lang]) {
|
||||
return this.state.loadedFlags[lang];
|
||||
}
|
||||
|
||||
try {
|
||||
const flagMap = {
|
||||
'de': () => import('country-flag-icons/react/3x2').then(m => m.DE),
|
||||
'en': () => import('country-flag-icons/react/3x2').then(m => m.US),
|
||||
'es': () => import('country-flag-icons/react/3x2').then(m => m.ES),
|
||||
'fr': () => import('country-flag-icons/react/3x2').then(m => m.FR),
|
||||
'it': () => import('country-flag-icons/react/3x2').then(m => m.IT),
|
||||
'pl': () => import('country-flag-icons/react/3x2').then(m => m.PL),
|
||||
'hu': () => import('country-flag-icons/react/3x2').then(m => m.HU),
|
||||
'sr': () => import('country-flag-icons/react/3x2').then(m => m.RS),
|
||||
'bg': () => import('country-flag-icons/react/3x2').then(m => m.BG),
|
||||
'ru': () => import('country-flag-icons/react/3x2').then(m => m.RU),
|
||||
'uk': () => import('country-flag-icons/react/3x2').then(m => m.UA),
|
||||
'sk': () => import('country-flag-icons/react/3x2').then(m => m.SK),
|
||||
'cs': () => import('country-flag-icons/react/3x2').then(m => m.CZ),
|
||||
'ro': () => import('country-flag-icons/react/3x2').then(m => m.RO)
|
||||
};
|
||||
|
||||
const flagLoader = flagMap[lang];
|
||||
if (flagLoader) {
|
||||
const FlagComponent = await flagLoader();
|
||||
this.setState(prevState => ({
|
||||
loadedFlags: {
|
||||
...prevState.loadedFlags,
|
||||
[lang]: FlagComponent
|
||||
}
|
||||
}));
|
||||
return FlagComponent;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to load flag for language: ${lang}`, error);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
getLanguageFlag = (lang) => {
|
||||
const FlagComponent = this.state.loadedFlags[lang];
|
||||
|
||||
if (FlagComponent) {
|
||||
return (
|
||||
<FlagComponent
|
||||
style={{
|
||||
width: '20px',
|
||||
height: '14px',
|
||||
borderRadius: '2px',
|
||||
border: '1px solid #ddd'
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Loading placeholder or fallback
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minWidth: '20px',
|
||||
height: '14px',
|
||||
backgroundColor: '#f5f5f5',
|
||||
color: '#666',
|
||||
fontSize: '8px',
|
||||
fontWeight: 'bold',
|
||||
borderRadius: '2px',
|
||||
fontFamily: 'monospace',
|
||||
border: '1px solid #ddd'
|
||||
}}
|
||||
>
|
||||
{this.getLanguageLabel(lang)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
// Load flags when menu opens
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { anchorEl } = this.state;
|
||||
const { languageContext } = this.props;
|
||||
|
||||
if (anchorEl && !prevState.anchorEl && languageContext) {
|
||||
// Menu just opened, lazy load all flags
|
||||
languageContext.availableLanguages.forEach(lang => {
|
||||
if (!this.state.loadedFlags[lang]) {
|
||||
this.loadFlagComponent(lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getLanguageLabel = (lang) => {
|
||||
const labels = {
|
||||
'de': 'DE',
|
||||
'en': 'US',
|
||||
'es': 'ES',
|
||||
'fr': 'FR',
|
||||
'it': 'IT',
|
||||
'pl': 'PL',
|
||||
'hu': 'HU',
|
||||
'sr': 'RS',
|
||||
'bg': 'BG',
|
||||
'ru': 'RU',
|
||||
'uk': 'UA',
|
||||
'sk': 'SK',
|
||||
'cs': 'CZ',
|
||||
'ro': 'RO'
|
||||
};
|
||||
return labels[lang] || lang.toUpperCase();
|
||||
};
|
||||
|
||||
getLanguageName = (lang) => {
|
||||
const names = {
|
||||
'de': 'Deutsch',
|
||||
'en': 'English',
|
||||
'es': 'Español',
|
||||
'fr': 'Français',
|
||||
'it': 'Italiano',
|
||||
'pl': 'Polski',
|
||||
'hu': 'Magyar',
|
||||
'sr': 'Српски',
|
||||
'bg': 'Български',
|
||||
'ru': 'Русский',
|
||||
'uk': 'Українська',
|
||||
'sk': 'Slovenčina',
|
||||
'cs': 'Čeština',
|
||||
'ro': 'Română'
|
||||
};
|
||||
return names[lang] || lang;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { languageContext } = this.props;
|
||||
const { anchorEl } = this.state;
|
||||
|
||||
if (!languageContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { currentLanguage, availableLanguages } = languageContext;
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Button
|
||||
aria-controls={open ? 'language-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={open ? 'true' : undefined}
|
||||
onClick={this.handleClick}
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{
|
||||
my: 1,
|
||||
mx: 0.5,
|
||||
minWidth: 'auto',
|
||||
textTransform: 'none',
|
||||
fontSize: '0.875rem'
|
||||
}}
|
||||
>
|
||||
{this.getLanguageLabel(currentLanguage)}
|
||||
</Button>
|
||||
<Menu
|
||||
id="language-menu"
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={this.handleClose}
|
||||
disableScrollLock={true}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'language-button',
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: 'top',
|
||||
horizontal: 'right',
|
||||
}}
|
||||
>
|
||||
{availableLanguages.map((language) => (
|
||||
<MenuItem
|
||||
key={language}
|
||||
onClick={() => this.handleLanguageChange(language)}
|
||||
selected={language === currentLanguage}
|
||||
sx={{
|
||||
minWidth: 160,
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
gap: 2
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{this.getLanguageFlag(language)}
|
||||
<Typography variant="body2">
|
||||
{this.getLanguageName(language)}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ ml: 'auto' }}>
|
||||
{this.getLanguageLabel(language)}
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withI18n()(LanguageSwitcher);
|
||||
@@ -22,6 +22,7 @@ import GoogleLoginButton from './GoogleLoginButton.js';
|
||||
import CartSyncDialog from './CartSyncDialog.js';
|
||||
import { localAndArchiveServer, mergeCarts } from '../utils/cartUtils.js';
|
||||
import config from '../config.js';
|
||||
import { withI18n } from '../i18n/withTranslation.js';
|
||||
|
||||
// Lazy load GoogleAuthProvider
|
||||
const GoogleAuthProvider = lazy(() => import('../providers/GoogleAuthProvider.js'));
|
||||
@@ -510,7 +511,7 @@ export class LoginComponent extends Component {
|
||||
color={isAdmin ? 'secondary' : 'inherit'}
|
||||
sx={{ my: 1, mx: 1.5 }}
|
||||
>
|
||||
Profil
|
||||
{this.props.t ? this.props.t('auth.profile') : 'Profil'}
|
||||
</Button>
|
||||
<Menu
|
||||
disableScrollLock={true}
|
||||
@@ -526,14 +527,28 @@ export class LoginComponent extends Component {
|
||||
horizontal: 'right',
|
||||
}}
|
||||
>
|
||||
<MenuItem component={Link} to="/profile" onClick={this.handleUserMenuClose}>Profil</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#cart" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>Bestellabschluss</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#orders" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>Bestellungen</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#settings" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>Einstellungen</MenuItem>
|
||||
<MenuItem component={Link} to="/profile" onClick={this.handleUserMenuClose}>
|
||||
{this.props.t ? this.props.t('auth.menu.profile') : 'Profil'}
|
||||
</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#cart" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
|
||||
{this.props.t ? this.props.t('auth.menu.checkout') : 'Bestellabschluss'}
|
||||
</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#orders" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
|
||||
{this.props.t ? this.props.t('auth.menu.orders') : 'Bestellungen'}
|
||||
</MenuItem>
|
||||
<MenuItem component={Link} to="/profile#settings" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
|
||||
{this.props.t ? this.props.t('auth.menu.settings') : 'Einstellungen'}
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
{isAdmin ? <MenuItem component={Link} to="/admin" onClick={this.handleUserMenuClose}>Admin Dashboard</MenuItem> : null}
|
||||
{isAdmin ? <MenuItem component={Link} to="/admin/users" onClick={this.handleUserMenuClose}>Admin Users</MenuItem> : null}
|
||||
<MenuItem onClick={this.handleLogout}>Abmelden</MenuItem>
|
||||
{isAdmin ? <MenuItem component={Link} to="/admin" onClick={this.handleUserMenuClose}>
|
||||
{this.props.t ? this.props.t('auth.menu.adminDashboard') : 'Admin Dashboard'}
|
||||
</MenuItem> : null}
|
||||
{isAdmin ? <MenuItem component={Link} to="/admin/users" onClick={this.handleUserMenuClose}>
|
||||
{this.props.t ? this.props.t('auth.menu.adminUsers') : 'Admin Users'}
|
||||
</MenuItem> : null}
|
||||
<MenuItem onClick={this.handleLogout}>
|
||||
{this.props.t ? this.props.t('auth.logout') : 'Abmelden'}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
) : (
|
||||
@@ -543,7 +558,7 @@ export class LoginComponent extends Component {
|
||||
onClick={this.handleOpen}
|
||||
sx={{ my: 1, mx: 1.5 }}
|
||||
>
|
||||
Login
|
||||
{this.props.t ? this.props.t('auth.login') : 'Login'}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
@@ -558,7 +573,10 @@ export class LoginComponent extends Component {
|
||||
<DialogTitle sx={{ bgcolor: 'white', pb: 0 }}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||
<Typography variant="h6" color="#2e7d32" fontWeight="bold">
|
||||
{tabValue === 0 ? 'Anmelden' : 'Registrieren'}
|
||||
{tabValue === 0 ?
|
||||
(this.props.t ? this.props.t('auth.login') : 'Anmelden') :
|
||||
(this.props.t ? this.props.t('auth.register') : 'Registrieren')
|
||||
}
|
||||
</Typography>
|
||||
<IconButton edge="end" onClick={this.handleClose} aria-label="close">
|
||||
<CloseIcon />
|
||||
@@ -578,14 +596,14 @@ export class LoginComponent extends Component {
|
||||
textColor="inherit"
|
||||
>
|
||||
<Tab
|
||||
label="ANMELDEN"
|
||||
label={this.props.t ? this.props.t('auth.login').toUpperCase() : "ANMELDEN"}
|
||||
sx={{
|
||||
color: tabValue === 0 ? '#2e7d32' : 'inherit',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
/>
|
||||
<Tab
|
||||
label="REGISTRIEREN"
|
||||
label={this.props.t ? this.props.t('auth.register').toUpperCase() : "REGISTRIEREN"}
|
||||
sx={{
|
||||
color: tabValue === 1 ? '#2e7d32' : 'inherit',
|
||||
fontWeight: 'bold'
|
||||
@@ -598,7 +616,14 @@ export class LoginComponent extends Component {
|
||||
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', mb: 2 }}>
|
||||
{!privacyConfirmed && (
|
||||
<Typography variant="caption" sx={{ mb: 1, textAlign: 'center' }}>
|
||||
Mit dem Click auf "Mit Google anmelden" akzeptiere ich die <Link to="/datenschutz" style={{ color: '#4285F4' }}>Datenschutzbestimmungen</Link>
|
||||
{this.props.t ?
|
||||
<>
|
||||
{this.props.t('auth.privacyAccept')} <Link to="/datenschutz" style={{ color: '#4285F4' }}>{this.props.t('auth.privacyPolicy')}</Link>
|
||||
</> :
|
||||
<>
|
||||
Mit dem Click auf "Mit Google anmelden" akzeptiere ich die <Link to="/datenschutz" style={{ color: '#4285F4' }}>Datenschutzbestimmungen</Link>
|
||||
</>
|
||||
}
|
||||
</Typography>
|
||||
)}
|
||||
{!showGoogleAuth && (
|
||||
@@ -611,7 +636,7 @@ export class LoginComponent extends Component {
|
||||
}}
|
||||
sx={{ width: '100%', backgroundColor: '#4285F4', color: 'white' }}
|
||||
>
|
||||
Mit Google anmelden
|
||||
{this.props.t ? this.props.t('auth.loginWithGoogle') : 'Mit Google anmelden'}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -643,7 +668,9 @@ export class LoginComponent extends Component {
|
||||
{/* OR Divider */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', my: 2 }}>
|
||||
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#e0e0e0' }} />
|
||||
<Typography variant="body2" sx={{ px: 2, color: '#757575' }}>ODER</Typography>
|
||||
<Typography variant="body2" sx={{ px: 2, color: '#757575' }}>
|
||||
{this.props.t ? this.props.t('auth.or') : 'ODER'}
|
||||
</Typography>
|
||||
<Box sx={{ flex: 1, height: '1px', backgroundColor: '#e0e0e0' }} />
|
||||
</Box>
|
||||
|
||||
@@ -654,7 +681,7 @@ export class LoginComponent extends Component {
|
||||
<Box sx={{ py: 1 }}>
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="E-Mail"
|
||||
label={this.props.t ? this.props.t('auth.email') : 'E-Mail'}
|
||||
type="email"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -665,7 +692,7 @@ export class LoginComponent extends Component {
|
||||
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="Passwort"
|
||||
label={this.props.t ? this.props.t('auth.password') : 'Passwort'}
|
||||
type="password"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
@@ -687,7 +714,7 @@ export class LoginComponent extends Component {
|
||||
'&:hover': { backgroundColor: 'transparent', textDecoration: 'underline' }
|
||||
}}
|
||||
>
|
||||
Passwort vergessen?
|
||||
{this.props.t ? this.props.t('auth.forgotPassword') : 'Passwort vergessen?'}
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
@@ -740,4 +767,4 @@ export class LoginComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(LoginComponent);
|
||||
export default withRouter(withI18n()(LoginComponent));
|
||||
@@ -10,10 +10,12 @@ import ChevronRight from "@mui/icons-material/ChevronRight";
|
||||
import { Link } from "react-router-dom";
|
||||
import SharedCarousel from "./SharedCarousel.js";
|
||||
import { getCombinedAnimatedBorderStyles } from "../utils/animatedBorderStyles.js";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MainPageLayout = () => {
|
||||
const location = useLocation();
|
||||
const currentPath = location.pathname;
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Determine which page we're on
|
||||
const isHome = currentPath === "/";
|
||||
@@ -24,18 +26,18 @@ const MainPageLayout = () => {
|
||||
const getNavigationConfig = () => {
|
||||
if (isHome) {
|
||||
return {
|
||||
leftNav: { text: "Aktionen", link: "/aktionen" },
|
||||
rightNav: { text: "Filiale", link: "/filiale" }
|
||||
leftNav: { text: t('navigation.aktionen'), link: "/aktionen" },
|
||||
rightNav: { text: t('navigation.filiale'), link: "/filiale" }
|
||||
};
|
||||
} else if (isAktionen) {
|
||||
return {
|
||||
leftNav: { text: "Filiale", link: "/filiale" },
|
||||
rightNav: { text: "Home", link: "/" }
|
||||
leftNav: { text: t('navigation.filiale'), link: "/filiale" },
|
||||
rightNav: { text: t('navigation.home'), link: "/" }
|
||||
};
|
||||
} else if (isFiliale) {
|
||||
return {
|
||||
leftNav: { text: "Home", link: "/" },
|
||||
rightNav: { text: "Aktionen", link: "/aktionen" }
|
||||
leftNav: { text: t('navigation.home'), link: "/" },
|
||||
rightNav: { text: t('navigation.aktionen'), link: "/aktionen" }
|
||||
};
|
||||
}
|
||||
return { leftNav: null, rightNav: null };
|
||||
@@ -51,13 +53,13 @@ const MainPageLayout = () => {
|
||||
const allContentBoxes = {
|
||||
home: [
|
||||
{
|
||||
title: "Seeds",
|
||||
title: t('sections.seeds'),
|
||||
image: "/assets/images/seeds.jpg",
|
||||
bgcolor: "#e1f0d3",
|
||||
link: "/Kategorie/Seeds"
|
||||
},
|
||||
{
|
||||
title: "Stecklinge",
|
||||
title: t('sections.stecklinge'),
|
||||
image: "/assets/images/cutlings.jpg",
|
||||
bgcolor: "#e8f5d6",
|
||||
link: "/Kategorie/Stecklinge"
|
||||
@@ -65,13 +67,13 @@ const MainPageLayout = () => {
|
||||
],
|
||||
aktionen: [
|
||||
{
|
||||
title: "Ölpresse ausleihen",
|
||||
title: t('sections.oilPress'),
|
||||
image: "/assets/images/presse.jpg",
|
||||
bgcolor: "#e1f0d3",
|
||||
link: "/presseverleih"
|
||||
},
|
||||
{
|
||||
title: "THC Test",
|
||||
title: t('sections.thcTest'),
|
||||
image: "/assets/images/purpl.jpg",
|
||||
bgcolor: "#e8f5d6",
|
||||
link: "/thc-test"
|
||||
@@ -79,13 +81,13 @@ const MainPageLayout = () => {
|
||||
],
|
||||
filiale: [
|
||||
{
|
||||
title: "Trachenberger Straße 14",
|
||||
title: t('sections.address1'),
|
||||
image: "/assets/images/filiale1.jpg",
|
||||
bgcolor: "#e1f0d3",
|
||||
link: "/filiale"
|
||||
},
|
||||
{
|
||||
title: "01129 Dresden",
|
||||
title: t('sections.address2'),
|
||||
image: "/assets/images/filiale2.jpg",
|
||||
bgcolor: "#e8f5d6",
|
||||
link: "/filiale"
|
||||
@@ -103,6 +105,13 @@ const MainPageLayout = () => {
|
||||
|
||||
const navConfig = getNavigationConfig();
|
||||
|
||||
// Navigation text mapping for translation
|
||||
const navTexts = [
|
||||
{ key: 'aktionen', text: t('navigation.aktionen'), link: '/aktionen' },
|
||||
{ key: 'filiale', text: t('navigation.filiale'), link: '/filiale' },
|
||||
{ key: 'home', text: t('navigation.home'), link: '/' }
|
||||
];
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ py: 2 }}>
|
||||
<style>{getCombinedAnimatedBorderStyles(['seeds', 'cutlings'])}</style>
|
||||
@@ -126,13 +135,13 @@ const MainPageLayout = () => {
|
||||
position: "relative",
|
||||
mr: 2
|
||||
}}>
|
||||
{["Aktionen", "Filiale", "Home"].map((text, index) => {
|
||||
const isActive = navConfig.leftNav && navConfig.leftNav.text === text;
|
||||
const link = text === "Aktionen" ? "/aktionen" : text === "Filiale" ? "/filiale" : "/";
|
||||
{navTexts.map((navItem, index) => {
|
||||
const isActive = navConfig.leftNav && navConfig.leftNav.text === navItem.text;
|
||||
const link = navItem.link;
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={text}
|
||||
key={navItem.key}
|
||||
component={Link}
|
||||
to={link}
|
||||
sx={{
|
||||
@@ -161,7 +170,7 @@ const MainPageLayout = () => {
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
{navItem.text}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
@@ -216,13 +225,13 @@ const MainPageLayout = () => {
|
||||
position: "relative",
|
||||
ml: 2
|
||||
}}>
|
||||
{["Aktionen", "Filiale", "Home"].map((text, index) => {
|
||||
const isActive = navConfig.rightNav && navConfig.rightNav.text === text;
|
||||
const link = text === "Aktionen" ? "/aktionen" : text === "Filiale" ? "/filiale" : "/";
|
||||
{navTexts.map((navItem, index) => {
|
||||
const isActive = navConfig.rightNav && navConfig.rightNav.text === navItem.text;
|
||||
const link = navItem.link;
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={text}
|
||||
key={navItem.key}
|
||||
component={Link}
|
||||
to={link}
|
||||
sx={{
|
||||
@@ -250,7 +259,7 @@ const MainPageLayout = () => {
|
||||
whiteSpace: "nowrap"
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
{navItem.text}
|
||||
</Typography>
|
||||
<ChevronRight sx={{ fontSize: "2rem", ml: 1 }} />
|
||||
</Box>
|
||||
|
||||
@@ -10,7 +10,9 @@ import CloseIcon from '@mui/icons-material/Close';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import LoginComponent from '../LoginComponent.js';
|
||||
import CartDropdown from '../CartDropdown.js';
|
||||
import LanguageSwitcher from '../LanguageSwitcher.js';
|
||||
import { isUserLoggedIn } from '../LoginComponent.js';
|
||||
import { withI18n } from '../../i18n/withTranslation.js';
|
||||
|
||||
function getBadgeNumber() {
|
||||
let count = 0;
|
||||
@@ -116,14 +118,14 @@ class ButtonGroup extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { socket, navigate } = this.props;
|
||||
const { socket, navigate, t } = this.props;
|
||||
const { isCartOpen } = this.state;
|
||||
const cartItems = Array.isArray(window.cart) ? window.cart : [];
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: { xs: 0.5, sm: 1 } }}>
|
||||
|
||||
|
||||
<LanguageSwitcher />
|
||||
<LoginComponent socket={socket} />
|
||||
|
||||
<IconButton
|
||||
@@ -164,7 +166,7 @@ class ButtonGroup extends Component {
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6">Warenkorb</Typography>
|
||||
<Typography variant="h6">{t ? t('cart.title') : 'Warenkorb'}</Typography>
|
||||
</Box>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
@@ -189,10 +191,11 @@ class ButtonGroup extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for ButtonGroup to provide navigate function
|
||||
// Wrapper for ButtonGroup to provide navigate function and translations
|
||||
const ButtonGroupWithRouter = (props) => {
|
||||
const navigate = useNavigate();
|
||||
return <ButtonGroup {...props} navigate={navigate} />;
|
||||
const ButtonGroupWithTranslation = withI18n()(ButtonGroup);
|
||||
return <ButtonGroupWithTranslation {...props} navigate={navigate} />;
|
||||
};
|
||||
|
||||
export default ButtonGroupWithRouter;
|
||||
@@ -8,6 +8,7 @@ import { Link } from "react-router-dom";
|
||||
import HomeIcon from "@mui/icons-material/Home";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import { withI18n } from "../../i18n/withTranslation.js";
|
||||
|
||||
class CategoryList extends Component {
|
||||
findCategoryById = (category, targetId) => {
|
||||
@@ -410,7 +411,7 @@ class CategoryList extends Component {
|
||||
zIndex: 2,
|
||||
}}
|
||||
>
|
||||
Startseite
|
||||
{this.props.t ? this.props.t('navigation.home') : 'Startseite'}
|
||||
</Box>
|
||||
{/* Thin text (positioned on top) */}
|
||||
<Box
|
||||
@@ -424,7 +425,7 @@ class CategoryList extends Component {
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
Startseite
|
||||
{this.props.t ? this.props.t('navigation.home') : 'Startseite'}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
@@ -595,7 +596,10 @@ class CategoryList extends Component {
|
||||
onClick={this.handleMobileMenuToggle}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label={mobileMenuOpen ? "Kategorien schließen" : "Kategorien öffnen"}
|
||||
aria-label={this.props.t ?
|
||||
(mobileMenuOpen ? this.props.t('navigation.categories') + ' schließen' : this.props.t('navigation.categories') + ' öffnen') :
|
||||
(mobileMenuOpen ? "Kategorien schließen" : "Kategorien öffnen")
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
@@ -607,7 +611,7 @@ class CategoryList extends Component {
|
||||
fontWeight: "bold",
|
||||
textShadow: "0 1px 2px rgba(0,0,0,0.3)"
|
||||
}}>
|
||||
Kategorien
|
||||
{this.props.t ? this.props.t('navigation.categories') : 'Kategorien'}
|
||||
</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
{mobileMenuOpen ? <CloseIcon /> : <MenuIcon />}
|
||||
@@ -628,4 +632,4 @@ class CategoryList extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default CategoryList;
|
||||
export default withI18n()(CategoryList);
|
||||
|
||||
157
src/config.js
157
src/config.js
@@ -8,17 +8,160 @@ const config = {
|
||||
siteName: "Growheads.de",
|
||||
brandName: "GrowHeads",
|
||||
currency: "EUR",
|
||||
language: "de-DE",
|
||||
language: "de-DE", // Will be updated dynamically based on i18n
|
||||
country: "DE",
|
||||
|
||||
// Shop Descriptions
|
||||
descriptions: {
|
||||
short: "GrowHeads - Online-Shop für Cannanis-Samen, Stecklinge und Gartenbedarf",
|
||||
long: "GrowHeads - Ihr Online-Shop für hochwertige Samen, Pflanzen und Gartenbedarf zur Cannabis Kultivierung. Entdecken Sie unser großes Sortiment an Saatgut, Pflanzen und Gartenzubehör für Ihren grünen Daumen."
|
||||
// Multilingual configurations
|
||||
languages: {
|
||||
de: {
|
||||
code: "de-DE",
|
||||
name: "Deutsch",
|
||||
shortName: "DE"
|
||||
},
|
||||
en: {
|
||||
code: "en-US",
|
||||
name: "English",
|
||||
shortName: "EN"
|
||||
},
|
||||
es: {
|
||||
code: "es-ES",
|
||||
name: "Español",
|
||||
shortName: "ES"
|
||||
},
|
||||
fr: {
|
||||
code: "fr-FR",
|
||||
name: "Français",
|
||||
shortName: "FR"
|
||||
},
|
||||
it: {
|
||||
code: "it-IT",
|
||||
name: "Italiano",
|
||||
shortName: "IT"
|
||||
},
|
||||
pl: {
|
||||
code: "pl-PL",
|
||||
name: "Polski",
|
||||
shortName: "PL"
|
||||
},
|
||||
hu: {
|
||||
code: "hu-HU",
|
||||
name: "Magyar",
|
||||
shortName: "HU"
|
||||
},
|
||||
sr: {
|
||||
code: "sr-RS",
|
||||
name: "Српски",
|
||||
shortName: "SR"
|
||||
},
|
||||
bg: {
|
||||
code: "bg-BG",
|
||||
name: "Български",
|
||||
shortName: "BG"
|
||||
},
|
||||
ru: {
|
||||
code: "ru-RU",
|
||||
name: "Русский",
|
||||
shortName: "RU"
|
||||
},
|
||||
uk: {
|
||||
code: "uk-UA",
|
||||
name: "Українська",
|
||||
shortName: "UK"
|
||||
},
|
||||
sk: {
|
||||
code: "sk-SK",
|
||||
name: "Slovenčina",
|
||||
shortName: "SK"
|
||||
},
|
||||
cs: {
|
||||
code: "cs-CZ",
|
||||
name: "Čeština",
|
||||
shortName: "CS"
|
||||
},
|
||||
ro: {
|
||||
code: "ro-RO",
|
||||
name: "Română",
|
||||
shortName: "RO"
|
||||
}
|
||||
},
|
||||
|
||||
// Keywords
|
||||
keywords: "Seeds, Steckling, Cannabis, Biobizz, Growheads",
|
||||
// Shop Descriptions - Multilingual
|
||||
descriptions: {
|
||||
de: {
|
||||
short: "GrowHeads - Online-Shop für Cannabis-Samen, Stecklinge und Gartenbedarf",
|
||||
long: "GrowHeads - Ihr Online-Shop für hochwertige Samen, Pflanzen und Gartenbedarf zur Cannabis Kultivierung. Entdecken Sie unser großes Sortiment an Saatgut, Pflanzen und Gartenzubehör für Ihren grünen Daumen."
|
||||
},
|
||||
en: {
|
||||
short: "GrowHeads - Online Shop for Cannabis Seeds, Cuttings and Garden Supplies",
|
||||
long: "GrowHeads - Your online shop for high-quality seeds, plants and garden supplies for cannabis cultivation. Discover our large assortment of seeds, plants and garden accessories for your green thumb."
|
||||
},
|
||||
es: {
|
||||
short: "GrowHeads - Tienda Online de Semillas de Cannabis, Esquejes y Suministros de Jardín",
|
||||
long: "GrowHeads - Tu tienda online de semillas, plantas y suministros de jardín de alta calidad para el cultivo de cannabis. Descubre nuestro gran surtido de semillas, plantas y accesorios de jardín para tu pulgar verde."
|
||||
},
|
||||
fr: {
|
||||
short: "GrowHeads - Boutique en ligne de Graines de Cannabis, Boutures et Fournitures de Jardinage",
|
||||
long: "GrowHeads - Votre boutique en ligne pour des graines, plantes et fournitures de jardinage de haute qualité pour la culture du cannabis. Découvrez notre large assortiment de graines, plantes et accessoires de jardinage pour votre pouce vert."
|
||||
},
|
||||
it: {
|
||||
short: "GrowHeads - Negozio Online di Semi di Cannabis, Talee e Forniture da Giardino",
|
||||
long: "GrowHeads - Il tuo negozio online per semi, piante e forniture da giardino di alta qualità per la coltivazione di cannabis. Scopri il nostro vasto assortimento di semi, piante e accessori da giardino per il tuo pollice verde."
|
||||
},
|
||||
pl: {
|
||||
short: "GrowHeads - Sklep Online z Nasionami Konopi, Sadzonkami i Artykułami Ogrodniczymi",
|
||||
long: "GrowHeads - Twój sklep online z wysokiej jakości nasionami, roślinami i artykułami ogrodniczymi do uprawy konopi. Odkryj nasz duży asortyment nasion, roślin i akcesoriów ogrodniczych dla Twojego zielonego kciuka."
|
||||
},
|
||||
hu: {
|
||||
short: "GrowHeads - Online Bolt Kannabisz Magokhoz, Dugványokhoz és Kerti Kellékekhez",
|
||||
long: "GrowHeads - Az Ön online boltja minőségi magokhoz, növényekhez és kerti kellékekhez a kannabisz termesztéshez. Fedezze fel nagy választékunkat magokból, növényekből és kerti kiegészítőkből a zöld hüvelykujjához."
|
||||
},
|
||||
sr: {
|
||||
short: "GrowHeads - Онлајн продавница за семена канабиса, резнице и вртларски прибор",
|
||||
long: "GrowHeads - Ваша онлајн продавница за висококвалитетна семена, биљке и вртларски прибор за узгајање канабиса. Откријте наш велики асортиман семена, биљака и вртларских додатака за ваш зелени палац."
|
||||
},
|
||||
bg: {
|
||||
short: "GrowHeads - Онлайн магазин за семена на канабис, резници и градински принадлежности",
|
||||
long: "GrowHeads - Вашият онлайн магазин за висококачествени семена, растения и градински принадлежности за отглеждане на канабис. Открийте нашия голям асортимент от семена, растения и градински аксесоари за вашия зелен палец."
|
||||
},
|
||||
ru: {
|
||||
short: "GrowHeads - Интернет-магазин семян каннабиса, черенков и садовых принадлежностей",
|
||||
long: "GrowHeads - Ваш интернет-магазин высококачественных семян, растений и садовых принадлежностей для выращивания каннабиса. Откройте для себя наш большой ассортимент семян, растений и садовых аксессуаров для вашего зеленого пальца."
|
||||
},
|
||||
uk: {
|
||||
short: "GrowHeads - Інтернет-магазин насіння канабісу, живців та садових приладдя",
|
||||
long: "GrowHeads - Ваш інтернет-магазин високоякісного насіння, рослин та садових приладдя для вирощування канабісу. Відкрийте для себе наш великий асортимент насіння, рослин та садових аксесуарів для вашого зеленого пальця."
|
||||
},
|
||||
sk: {
|
||||
short: "GrowHeads - Online obchod so semenami konopy, sadenicami a záhradnými potrebami",
|
||||
long: "GrowHeads - Váš online obchod s vysoko kvalitnými semenami, rastlinami a záhradnými potrebami na pestovanie konopy. Objavte náš veľký sortiment semien, rastlín a záhradných doplnkov pre váš zelený palec."
|
||||
},
|
||||
cs: {
|
||||
short: "GrowHeads - Online obchod se semeny konopí, sazenicemi a zahradními potřebami",
|
||||
long: "GrowHeads - Váš online obchod s vysoce kvalitními semeny, rostlinami a zahradními potřebami pro pěstování konopí. Objevte náš velký sortiment semen, rostlin a zahradních doplňků pro váš zelený palec."
|
||||
},
|
||||
ro: {
|
||||
short: "GrowHeads - Magazin Online de Semințe de Cannabis, Butași și Articole de Grădinărit",
|
||||
long: "GrowHeads - Magazinul dumneavoastră online pentru semințe, plante și articole de grădinărit de înaltă calitate pentru cultivarea de cannabis. Descoperiți sortimentul nostru mare de semințe, plante și accesorii de grădinărit pentru degetul verde."
|
||||
}
|
||||
},
|
||||
|
||||
// Keywords - Multilingual
|
||||
keywords: {
|
||||
de: "Seeds, Steckling, Cannabis, Biobizz, Growheads",
|
||||
en: "Seeds, Cuttings, Cannabis, Biobizz, Growheads",
|
||||
es: "Semillas, Esquejes, Cannabis, Biobizz, Growheads",
|
||||
fr: "Graines, Boutures, Cannabis, Biobizz, Growheads",
|
||||
it: "Semi, Talee, Cannabis, Biobizz, Growheads",
|
||||
pl: "Nasiona, Sadzonki, Konopie, Biobizz, Growheads",
|
||||
hu: "Magok, Dugványok, Kannabisz, Biobizz, Growheads",
|
||||
sr: "Семена, Резнице, Канабис, Biobizz, Growheads",
|
||||
bg: "Семена, Резници, Канабис, Biobizz, Growheads",
|
||||
ru: "Семена, Черенки, Каннабис, Biobizz, Growheads",
|
||||
uk: "Насіння, Живці, Канабіс, Biobizz, Growheads",
|
||||
sk: "Semená, Sadenky, Konope, Biobizz, Growheads",
|
||||
cs: "Semena, Sazenice, Konopí, Biobizz, Growheads",
|
||||
ro: "Semințe, Butași, Cannabis, Biobizz, Growheads"
|
||||
},
|
||||
|
||||
// Shipping
|
||||
shipping: {
|
||||
|
||||
98
src/i18n/index.js
Normal file
98
src/i18n/index.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
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 translationFR from './locales/fr/translation.json';
|
||||
import translationIT from './locales/it/translation.json';
|
||||
import translationPL from './locales/pl/translation.json';
|
||||
import translationHU from './locales/hu/translation.json';
|
||||
import translationSR from './locales/sr/translation.json';
|
||||
import translationBG from './locales/bg/translation.json';
|
||||
import translationRU from './locales/ru/translation.json';
|
||||
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
|
||||
},
|
||||
fr: {
|
||||
translation: translationFR
|
||||
},
|
||||
it: {
|
||||
translation: translationIT
|
||||
},
|
||||
pl: {
|
||||
translation: translationPL
|
||||
},
|
||||
hu: {
|
||||
translation: translationHU
|
||||
},
|
||||
sr: {
|
||||
translation: translationSR
|
||||
},
|
||||
bg: {
|
||||
translation: translationBG
|
||||
},
|
||||
ru: {
|
||||
translation: translationRU
|
||||
},
|
||||
uk: {
|
||||
translation: translationUK
|
||||
},
|
||||
sk: {
|
||||
translation: translationSK
|
||||
},
|
||||
cs: {
|
||||
translation: translationCS
|
||||
},
|
||||
ro: {
|
||||
translation: translationRO
|
||||
}
|
||||
};
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources,
|
||||
fallbackLng: 'de', // German as fallback since it's your primary language
|
||||
lng: 'de', // Default language
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
|
||||
// Language detection options
|
||||
detection: {
|
||||
// Order of language detection methods
|
||||
order: ['localStorage', 'navigator', 'htmlTag'],
|
||||
// Cache the language selection
|
||||
caches: ['localStorage'],
|
||||
// Check for language in localStorage
|
||||
lookupLocalStorage: 'i18nextLng'
|
||||
},
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false // React already escapes values
|
||||
},
|
||||
|
||||
// Namespace configuration
|
||||
defaultNS: 'translation',
|
||||
|
||||
// React-specific options
|
||||
react: {
|
||||
useSuspense: false // Disable suspense for class components compatibility
|
||||
}
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
162
src/i18n/locales/bg/translation.json
Normal file
162
src/i18n/locales/bg/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Начало",
|
||||
"aktionen": "Действия",
|
||||
"filiale": "Клон",
|
||||
"categories": "Категории"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Вход",
|
||||
"register": "Регистрация",
|
||||
"logout": "Изход",
|
||||
"profile": "Профил",
|
||||
"email": "Имейл",
|
||||
"password": "Парола",
|
||||
"confirmPassword": "Потвърди парола",
|
||||
"forgotPassword": "Забравена парола?",
|
||||
"loginWithGoogle": "Вход с Google",
|
||||
"or": "ИЛИ",
|
||||
"privacyAccept": "Като кликна \"Вход с Google\", приемам",
|
||||
"privacyPolicy": "Политиката за поверителност",
|
||||
"passwordMinLength": "Паролата трябва да съдържа поне 8 символа",
|
||||
"newPasswordMinLength": "Новата парола трябва да съдържа поне 8 символа",
|
||||
"menu": {
|
||||
"profile": "Профил",
|
||||
"checkout": "Финализиране на поръчката",
|
||||
"orders": "Поръчки",
|
||||
"settings": "Настройки",
|
||||
"adminDashboard": "Админ панел",
|
||||
"adminUsers": "Админ потребители"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Кошница",
|
||||
"empty": "празна",
|
||||
"sync": {
|
||||
"title": "Синхронизация на кошницата",
|
||||
"description": "Имате запазена кошница в профила си. Моля, изберете как да продължите:",
|
||||
"deleteServer": "Изтрий кошницата от сървъра",
|
||||
"useServer": "Използвай кошницата от сървъра",
|
||||
"merge": "Обедини кошниците",
|
||||
"currentCart": "Вашата текуща кошница",
|
||||
"serverCart": "Кошница запазена в профила ви"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Зареждане на продукт...",
|
||||
"notFound": "Продуктът не е намерен",
|
||||
"notFoundDescription": "Търсеният продукт не съществува или е премахнат.",
|
||||
"backToHome": "Обратно към началото",
|
||||
"error": "Грешка",
|
||||
"articleNumber": "Номер на артикул",
|
||||
"manufacturer": "Производител",
|
||||
"inclVat": "включително {{vat}}% ДДС",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Нов",
|
||||
"arriving": "Пристигане:",
|
||||
"inclVatFooter": "включително {{vat}}% ДДС,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Можеш да ме попиташ за сортове канабис...",
|
||||
"recording": "Записване в ход..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Прочетено и прието"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Габаритен товар",
|
||||
"pickup": "Вземане от клона"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Стандартна доставка",
|
||||
"standardFree": "Стандартна доставка - БЕЗПЛАТНО от 100€ стойност на стоката!",
|
||||
"notAvailable": "недостъпно, защото един или повече артикули могат да бъдат само взети",
|
||||
"bulky": "За големи и тежки предмети"
|
||||
},
|
||||
"prices": {
|
||||
"free": "безплатно",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Адрес за фактуриране",
|
||||
"deliveryAddress": "Адрес за доставка",
|
||||
"saveForFuture": "Запази за бъдещи поръчки",
|
||||
"pickupDate": "За коя дата желаете да вземете саженците?",
|
||||
"note": "Забележка",
|
||||
"sameAddress": "Адресът за доставка е същият като адреса за фактуриране",
|
||||
"termsAccept": "Прочетох условията за ползване, политиката за поверителност и условията за оттегляне"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Съб 11-19",
|
||||
"address": "Trachenberger Straße 14 - Дрезден",
|
||||
"location": "Между спирка Pieschen и Trachenberger Platz",
|
||||
"allPricesIncl": "* Всички цени включват законен ДДС, плюс доставка",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Защита на данните",
|
||||
"agb": "Условия за ползване",
|
||||
"sitemap": "Карта на сайта",
|
||||
"impressum": "Импресум",
|
||||
"batteriegesetzhinweise": "Информация за закона за батериите",
|
||||
"widerrufsrecht": "Право на оттегляне"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Семена и саженци канабис",
|
||||
"aktionen": "Текущи действия и оферти",
|
||||
"filiale": "Нашият клон в Дрезден"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Семена",
|
||||
"stecklinge": "Саженци",
|
||||
"oilPress": "Наемане на преса за масло",
|
||||
"thcTest": "ТХК тест",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Дрезден"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Наемане на преса за масло",
|
||||
"comingSoon": "Съдържанието идва скоро..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "ТХК тест",
|
||||
"comingSoon": "Съдържанието идва скоро..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "в обработка",
|
||||
"pending": "Нов",
|
||||
"processing": "в обработка",
|
||||
"cancelled": "Отменен",
|
||||
"shipped": "Изпратен",
|
||||
"delivered": "Доставен",
|
||||
"return": "Връщане",
|
||||
"partialReturn": "Частично връщане",
|
||||
"partialDelivered": "Частично доставен"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Зареждане...",
|
||||
"error": "Грешка",
|
||||
"close": "Затвори",
|
||||
"save": "Запази",
|
||||
"cancel": "Отмени",
|
||||
"ok": "OK",
|
||||
"yes": "Да",
|
||||
"no": "Не",
|
||||
"next": "Напред",
|
||||
"back": "Назад",
|
||||
"edit": "Редактирай",
|
||||
"delete": "Изтрий",
|
||||
"add": "Добави",
|
||||
"remove": "Премахни"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/cs/translation.json
Normal file
162
src/i18n/locales/cs/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Domů",
|
||||
"aktionen": "Akce",
|
||||
"filiale": "Pobočka",
|
||||
"categories": "Kategorie"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Přihlásit se",
|
||||
"register": "Registrovat se",
|
||||
"logout": "Odhlásit se",
|
||||
"profile": "Profil",
|
||||
"email": "E-mail",
|
||||
"password": "Heslo",
|
||||
"confirmPassword": "Potvrdit heslo",
|
||||
"forgotPassword": "Zapomenuté heslo?",
|
||||
"loginWithGoogle": "Přihlásit se přes Google",
|
||||
"or": "NEBO",
|
||||
"privacyAccept": "Kliknutím na \"Přihlásit se přes Google\" souhlasím s",
|
||||
"privacyPolicy": "Zásadami ochrany osobních údajů",
|
||||
"passwordMinLength": "Heslo musí mít alespoň 8 znaků",
|
||||
"newPasswordMinLength": "Nové heslo musí mít alespoň 8 znaků",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Dokončení objednávky",
|
||||
"orders": "Objednávky",
|
||||
"settings": "Nastavení",
|
||||
"adminDashboard": "Admin panel",
|
||||
"adminUsers": "Admin uživatelé"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Košík",
|
||||
"empty": "prázdný",
|
||||
"sync": {
|
||||
"title": "Synchronizace košíku",
|
||||
"description": "Máte uložený košík ve svém účtu. Prosím vyberte, jak chcete pokračovat:",
|
||||
"deleteServer": "Smazat serverový košík",
|
||||
"useServer": "Použít serverový košík",
|
||||
"merge": "Sloučit košíky",
|
||||
"currentCart": "Váš aktuální košík",
|
||||
"serverCart": "Košík uložený ve vašem profilu"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Načítání produktu...",
|
||||
"notFound": "Produkt nenalezen",
|
||||
"notFoundDescription": "Hledaný produkt neexistuje nebo byl odstraněn.",
|
||||
"backToHome": "Zpět na domovskou stránku",
|
||||
"error": "Chyba",
|
||||
"articleNumber": "Číslo artiklu",
|
||||
"manufacturer": "Výrobce",
|
||||
"inclVat": "včetně {{vat}}% DPH",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nový",
|
||||
"arriving": "Příjezd:",
|
||||
"inclVatFooter": "včetně {{vat}}% DPH,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Můžeš se mě zeptat na odrůdy konopí...",
|
||||
"recording": "Probíhá nahrávání..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Přečteno a přijato"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Nadrozměrné zboží",
|
||||
"pickup": "Vyzvednutí na pobočce"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Standardní doprava",
|
||||
"standardFree": "Standardní doprava - ZDARMA od 100€ hodnoty zboží!",
|
||||
"notAvailable": "nedostupné, protože jeden nebo více článků lze pouze vyzvednout",
|
||||
"bulky": "Pro velké a těžké předměty"
|
||||
},
|
||||
"prices": {
|
||||
"free": "zdarma",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Fakturační adresa",
|
||||
"deliveryAddress": "Dodací adresa",
|
||||
"saveForFuture": "Uložit pro budoucí objednávky",
|
||||
"pickupDate": "Na které datum si přejete vyzvednout sazenice?",
|
||||
"note": "Poznámka",
|
||||
"sameAddress": "Dodací adresa je shodná s fakturační adresou",
|
||||
"termsAccept": "Přečetl jsem si obchodní podmínky, zásady ochrany osobních údajů a podmínky odstoupení"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "So 11-19",
|
||||
"address": "Trachenberger Straße 14 - Drážďany",
|
||||
"location": "Mezi zastávkou Pieschen a Trachenberger Platz",
|
||||
"allPricesIncl": "* Všechny ceny včetně zákonné DPH, plus doprava",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Ochrana údajů",
|
||||
"agb": "Obchodní podmínky",
|
||||
"sitemap": "Mapa stránek",
|
||||
"impressum": "Tiráž",
|
||||
"batteriegesetzhinweise": "Informace o zákoně o bateriích",
|
||||
"widerrufsrecht": "Právo na odstoupení"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Semena a sazenice konopí",
|
||||
"aktionen": "Aktuální akce a nabídky",
|
||||
"filiale": "Naše pobočka v Drážďanech"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Semena",
|
||||
"stecklinge": "Sazenice",
|
||||
"oilPress": "Půjčení lisů na olej",
|
||||
"thcTest": "THC test",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Drážďany"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Půjčení lisů na olej",
|
||||
"comingSoon": "Obsah bude brzy..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "THC test",
|
||||
"comingSoon": "Obsah bude brzy..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "zpracovává se",
|
||||
"pending": "Nový",
|
||||
"processing": "zpracovává se",
|
||||
"cancelled": "Zrušeno",
|
||||
"shipped": "Odesláno",
|
||||
"delivered": "Doručeno",
|
||||
"return": "Vrácení",
|
||||
"partialReturn": "Částečné vrácení",
|
||||
"partialDelivered": "Částečně doručeno"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Načítá...",
|
||||
"error": "Chyba",
|
||||
"close": "Zavřít",
|
||||
"save": "Uložit",
|
||||
"cancel": "Zrušit",
|
||||
"ok": "OK",
|
||||
"yes": "Ano",
|
||||
"no": "Ne",
|
||||
"next": "Další",
|
||||
"back": "Zpět",
|
||||
"edit": "Upravit",
|
||||
"delete": "Smazat",
|
||||
"add": "Přidat",
|
||||
"remove": "Odebrat"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/de/translation.json
Normal file
162
src/i18n/locales/de/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Startseite",
|
||||
"aktionen": "Aktionen",
|
||||
"filiale": "Filiale",
|
||||
"categories": "Kategorien"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Anmelden",
|
||||
"register": "Registrieren",
|
||||
"logout": "Abmelden",
|
||||
"profile": "Profil",
|
||||
"email": "E-Mail",
|
||||
"password": "Passwort",
|
||||
"confirmPassword": "Passwort bestätigen",
|
||||
"forgotPassword": "Passwort vergessen?",
|
||||
"loginWithGoogle": "Mit Google anmelden",
|
||||
"or": "ODER",
|
||||
"privacyAccept": "Mit dem Click auf \"Mit Google anmelden\" akzeptiere ich die",
|
||||
"privacyPolicy": "Datenschutzbestimmungen",
|
||||
"passwordMinLength": "Das Passwort muss mindestens 8 Zeichen lang sein",
|
||||
"newPasswordMinLength": "Das neue Passwort muss mindestens 8 Zeichen lang sein",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Bestellabschluss",
|
||||
"orders": "Bestellungen",
|
||||
"settings": "Einstellungen",
|
||||
"adminDashboard": "Admin Dashboard",
|
||||
"adminUsers": "Admin Users"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Warenkorb",
|
||||
"empty": "leer",
|
||||
"sync": {
|
||||
"title": "Warenkorb-Synchronisierung",
|
||||
"description": "Sie haben einen gespeicherten Warenkorb in ihrem Account. Bitte wählen Sie, wie Sie verfahren möchten:",
|
||||
"deleteServer": "Server-Warenkorb löschen",
|
||||
"useServer": "Server-Warenkorb übernehmen",
|
||||
"merge": "Warenkörbe zusammenführen",
|
||||
"currentCart": "Ihr aktueller Warenkorb",
|
||||
"serverCart": "In Ihrem Profil gespeicherter Warenkorb"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Produkt wird geladen...",
|
||||
"notFound": "Produkt nicht gefunden",
|
||||
"notFoundDescription": "Das gesuchte Produkt existiert nicht oder wurde entfernt.",
|
||||
"backToHome": "Zurück zur Startseite",
|
||||
"error": "Fehler",
|
||||
"articleNumber": "Artikelnummer",
|
||||
"manufacturer": "Hersteller",
|
||||
"inclVat": "inkl. {{vat}}% MwSt.",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Neu",
|
||||
"arriving": "Ankunft:",
|
||||
"inclVatFooter": "incl. {{vat}}% USt.,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Du kannst mich nach Cannabissorten fragen...",
|
||||
"recording": "Aufnahme läuft..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Gelesen & Akzeptiert"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Sperrgut",
|
||||
"pickup": "Abholung in der Filiale"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Standardversand",
|
||||
"standardFree": "Standardversand - KOSTENLOS ab 100€ Warenwert!",
|
||||
"notAvailable": "nicht auswählbar weil ein oder mehrere Artikel nur abgeholt werden können",
|
||||
"bulky": "Für große und schwere Artikel"
|
||||
},
|
||||
"prices": {
|
||||
"free": "kostenlos",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Rechnungsadresse",
|
||||
"deliveryAddress": "Lieferadresse",
|
||||
"saveForFuture": "Für zukünftige Bestellungen speichern",
|
||||
"pickupDate": "Für welchen Termin ist die Abholung der Stecklinge gewünscht?",
|
||||
"note": "Anmerkung",
|
||||
"sameAddress": "Lieferadresse ist identisch mit Rechnungsadresse",
|
||||
"termsAccept": "Ich habe die AGBs, die Datenschutzerklärung und die Bestimmungen zum Widerrufsrecht gelesen"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sa 11-19",
|
||||
"address": "Trachenberger Straße 14 - Dresden",
|
||||
"location": "Zwischen Haltepunkt Pieschen und Trachenberger Platz",
|
||||
"allPricesIncl": "* Alle Preise inkl. gesetzlicher USt., zzgl. Versand",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Datenschutz",
|
||||
"agb": "AGB",
|
||||
"sitemap": "Sitemap",
|
||||
"impressum": "Impressum",
|
||||
"batteriegesetzhinweise": "Batteriegesetzhinweise",
|
||||
"widerrufsrecht": "Widerrufsrecht"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "ine annabis eeds & uttings",
|
||||
"aktionen": "tuelle ktionen & gebote",
|
||||
"filiale": "nsere iliale in resden"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Seeds",
|
||||
"stecklinge": "Stecklinge",
|
||||
"oilPress": "Ölpresse ausleihen",
|
||||
"thcTest": "THC Test",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Dresden"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Ölpresse ausleihen",
|
||||
"comingSoon": "Inhalt kommt bald..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "THC Test",
|
||||
"comingSoon": "Inhalt kommt bald..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "in Bearbeitung",
|
||||
"pending": "Neu",
|
||||
"processing": "in Bearbeitung",
|
||||
"cancelled": "Storniert",
|
||||
"shipped": "Verschickt",
|
||||
"delivered": "Geliefert",
|
||||
"return": "Retoure",
|
||||
"partialReturn": "Teil Retoure",
|
||||
"partialDelivered": "Teil geliefert"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Lädt...",
|
||||
"error": "Fehler",
|
||||
"close": "Schließen",
|
||||
"save": "Speichern",
|
||||
"cancel": "Abbrechen",
|
||||
"ok": "OK",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"next": "Weiter",
|
||||
"back": "Zurück",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen",
|
||||
"add": "Hinzufügen",
|
||||
"remove": "Entfernen"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/en/translation.json
Normal file
162
src/i18n/locales/en/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"aktionen": "Actions",
|
||||
"filiale": "Store",
|
||||
"categories": "Categories"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Sign In",
|
||||
"register": "Register",
|
||||
"logout": "Sign Out",
|
||||
"profile": "Profile",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"forgotPassword": "Forgot Password?",
|
||||
"loginWithGoogle": "Sign in with Google",
|
||||
"or": "OR",
|
||||
"privacyAccept": "By clicking \"Sign in with Google\" I accept the",
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"passwordMinLength": "Password must be at least 8 characters long",
|
||||
"newPasswordMinLength": "New password must be at least 8 characters long",
|
||||
"menu": {
|
||||
"profile": "Profile",
|
||||
"checkout": "Checkout",
|
||||
"orders": "Orders",
|
||||
"settings": "Settings",
|
||||
"adminDashboard": "Admin Dashboard",
|
||||
"adminUsers": "Admin Users"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Shopping Cart",
|
||||
"empty": "empty",
|
||||
"sync": {
|
||||
"title": "Cart Synchronization",
|
||||
"description": "You have a saved cart in your account. Please choose how you would like to proceed:",
|
||||
"deleteServer": "Delete server cart",
|
||||
"useServer": "Use server cart",
|
||||
"merge": "Merge carts",
|
||||
"currentCart": "Your current cart",
|
||||
"serverCart": "Cart saved in your profile"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Loading product...",
|
||||
"notFound": "Product not found",
|
||||
"notFoundDescription": "The requested product does not exist or has been removed.",
|
||||
"backToHome": "Back to homepage",
|
||||
"error": "Error",
|
||||
"articleNumber": "Article Number",
|
||||
"manufacturer": "Manufacturer",
|
||||
"inclVat": "incl. {{vat}}% VAT",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "New",
|
||||
"arriving": "Arriving:",
|
||||
"inclVatFooter": "incl. {{vat}}% VAT,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "You can ask me about cannabis varieties...",
|
||||
"recording": "Recording..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Read & Accepted"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Bulky Goods",
|
||||
"pickup": "Store Pickup"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Standard Shipping",
|
||||
"standardFree": "Standard Shipping - FREE for orders over €100!",
|
||||
"notAvailable": "not available because one or more items require store pickup",
|
||||
"bulky": "For large and heavy items"
|
||||
},
|
||||
"prices": {
|
||||
"free": "free",
|
||||
"dhl": "€6.99",
|
||||
"dpd": "€4.90",
|
||||
"sperrgut": "€28.99"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Billing Address",
|
||||
"deliveryAddress": "Delivery Address",
|
||||
"saveForFuture": "Save for future orders",
|
||||
"pickupDate": "What date would you like to pick up the cuttings?",
|
||||
"note": "Note",
|
||||
"sameAddress": "Delivery address is the same as billing address",
|
||||
"termsAccept": "I have read the Terms & Conditions, Privacy Policy and Return Policy"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sat 11-19",
|
||||
"address": "Trachenberger Straße 14 - Dresden",
|
||||
"location": "Between Pieschen station and Trachenberger Platz",
|
||||
"allPricesIncl": "* All prices incl. VAT, plus shipping",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Privacy Policy",
|
||||
"agb": "Terms & Conditions",
|
||||
"sitemap": "Sitemap",
|
||||
"impressum": "Legal Notice",
|
||||
"batteriegesetzhinweise": "Battery Regulations",
|
||||
"widerrufsrecht": "Right of Withdrawal"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "ine annabis eeds & uttings",
|
||||
"aktionen": "urrent ctions & ffers",
|
||||
"filiale": "ur tore in resden"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Seeds",
|
||||
"stecklinge": "Cuttings",
|
||||
"oilPress": "Oil Press Rental",
|
||||
"thcTest": "THC Test",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Dresden"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Oil Press Rental",
|
||||
"comingSoon": "Content coming soon..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "THC Test",
|
||||
"comingSoon": "Content coming soon..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "Processing",
|
||||
"pending": "New",
|
||||
"processing": "Processing",
|
||||
"cancelled": "Cancelled",
|
||||
"shipped": "Shipped",
|
||||
"delivered": "Delivered",
|
||||
"return": "Return",
|
||||
"partialReturn": "Partial Return",
|
||||
"partialDelivered": "Partially Delivered"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Loading...",
|
||||
"error": "Error",
|
||||
"close": "Close",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"ok": "OK",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"next": "Next",
|
||||
"back": "Back",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"add": "Add",
|
||||
"remove": "Remove"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/es/translation.json
Normal file
162
src/i18n/locales/es/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Inicio",
|
||||
"aktionen": "Acciones",
|
||||
"filiale": "Sucursal",
|
||||
"categories": "Categorías"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Iniciar sesión",
|
||||
"register": "Registrarse",
|
||||
"logout": "Cerrar sesión",
|
||||
"profile": "Perfil",
|
||||
"email": "Correo electrónico",
|
||||
"password": "Contraseña",
|
||||
"confirmPassword": "Confirmar contraseña",
|
||||
"forgotPassword": "¿Olvidaste tu contraseña?",
|
||||
"loginWithGoogle": "Iniciar sesión con Google",
|
||||
"or": "O",
|
||||
"privacyAccept": "Al hacer clic en \"Iniciar sesión con Google\" acepto la",
|
||||
"privacyPolicy": "Política de privacidad",
|
||||
"passwordMinLength": "La contraseña debe tener al menos 8 caracteres",
|
||||
"newPasswordMinLength": "La nueva contraseña debe tener al menos 8 caracteres",
|
||||
"menu": {
|
||||
"profile": "Perfil",
|
||||
"checkout": "Finalizar pedido",
|
||||
"orders": "Pedidos",
|
||||
"settings": "Configuración",
|
||||
"adminDashboard": "Panel de administración",
|
||||
"adminUsers": "Usuarios administradores"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Carrito",
|
||||
"empty": "vacío",
|
||||
"sync": {
|
||||
"title": "Sincronización del carrito",
|
||||
"description": "Tienes un carrito guardado en tu cuenta. Por favor elige cómo proceder:",
|
||||
"deleteServer": "Eliminar carrito del servidor",
|
||||
"useServer": "Usar carrito del servidor",
|
||||
"merge": "Combinar carritos",
|
||||
"currentCart": "Tu carrito actual",
|
||||
"serverCart": "Carrito guardado en tu perfil"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Cargando producto...",
|
||||
"notFound": "Producto no encontrado",
|
||||
"notFoundDescription": "El producto buscado no existe o ha sido eliminado.",
|
||||
"backToHome": "Volver al inicio",
|
||||
"error": "Error",
|
||||
"articleNumber": "Número de artículo",
|
||||
"manufacturer": "Fabricante",
|
||||
"inclVat": "incluido {{vat}}% IVA",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nuevo",
|
||||
"arriving": "Llegada:",
|
||||
"inclVatFooter": "incluido {{vat}}% IVA,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Puedes preguntarme sobre variedades de cannabis...",
|
||||
"recording": "Grabando..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Leído y aceptado"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Mercancía voluminosa",
|
||||
"pickup": "Recogida en sucursal"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Envío estándar",
|
||||
"standardFree": "Envío estándar - ¡GRATIS a partir de 100€ de valor de mercancía!",
|
||||
"notAvailable": "no seleccionable porque uno o más artículos solo se pueden recoger",
|
||||
"bulky": "Para artículos grandes y pesados"
|
||||
},
|
||||
"prices": {
|
||||
"free": "gratis",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Dirección de facturación",
|
||||
"deliveryAddress": "Dirección de entrega",
|
||||
"saveForFuture": "Guardar para pedidos futuros",
|
||||
"pickupDate": "¿Para qué fecha deseas la recogida de los esquejes?",
|
||||
"note": "Nota",
|
||||
"sameAddress": "La dirección de entrega es idéntica a la de facturación",
|
||||
"termsAccept": "He leído los términos y condiciones, la política de privacidad y las condiciones de desistimiento"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sáb 11-19",
|
||||
"address": "Trachenberger Straße 14 - Dresde",
|
||||
"location": "Entre la parada Pieschen y Trachenberger Platz",
|
||||
"allPricesIncl": "* Todos los precios incluyen IVA legal, más envío",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Protección de datos",
|
||||
"agb": "Términos y condiciones",
|
||||
"sitemap": "Mapa del sitio",
|
||||
"impressum": "Aviso legal",
|
||||
"batteriegesetzhinweise": "Información sobre la ley de baterías",
|
||||
"widerrufsrecht": "Derecho de desistimiento"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Semillas y esquejes de cannabis",
|
||||
"aktionen": "Acciones y ofertas actuales",
|
||||
"filiale": "Nuestra sucursal en Dresde"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Semillas",
|
||||
"stecklinge": "Esquejes",
|
||||
"oilPress": "Alquiler de prensa de aceite",
|
||||
"thcTest": "Test de THC",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Dresde"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Alquiler de prensa de aceite",
|
||||
"comingSoon": "Contenido próximamente..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Test de THC",
|
||||
"comingSoon": "Contenido próximamente..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "en procesamiento",
|
||||
"pending": "Nuevo",
|
||||
"processing": "en procesamiento",
|
||||
"cancelled": "Cancelado",
|
||||
"shipped": "Enviado",
|
||||
"delivered": "Entregado",
|
||||
"return": "Devolución",
|
||||
"partialReturn": "Devolución parcial",
|
||||
"partialDelivered": "Parcialmente entregado"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Cargando...",
|
||||
"error": "Error",
|
||||
"close": "Cerrar",
|
||||
"save": "Guardar",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "OK",
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"next": "Siguiente",
|
||||
"back": "Atrás",
|
||||
"edit": "Editar",
|
||||
"delete": "Eliminar",
|
||||
"add": "Añadir",
|
||||
"remove": "Quitar"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/fr/translation.json
Normal file
162
src/i18n/locales/fr/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Accueil",
|
||||
"aktionen": "Actions",
|
||||
"filiale": "Magasin",
|
||||
"categories": "Catégories"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Se connecter",
|
||||
"register": "S'inscrire",
|
||||
"logout": "Se déconnecter",
|
||||
"profile": "Profil",
|
||||
"email": "E-mail",
|
||||
"password": "Mot de passe",
|
||||
"confirmPassword": "Confirmer le mot de passe",
|
||||
"forgotPassword": "Mot de passe oublié ?",
|
||||
"loginWithGoogle": "Se connecter avec Google",
|
||||
"or": "OU",
|
||||
"privacyAccept": "En cliquant sur \"Se connecter avec Google\", j'accepte la",
|
||||
"privacyPolicy": "Politique de confidentialité",
|
||||
"passwordMinLength": "Le mot de passe doit contenir au moins 8 caractères",
|
||||
"newPasswordMinLength": "Le nouveau mot de passe doit contenir au moins 8 caractères",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Finaliser la commande",
|
||||
"orders": "Commandes",
|
||||
"settings": "Paramètres",
|
||||
"adminDashboard": "Tableau de bord admin",
|
||||
"adminUsers": "Utilisateurs admin"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Panier",
|
||||
"empty": "vide",
|
||||
"sync": {
|
||||
"title": "Synchronisation du panier",
|
||||
"description": "Vous avez un panier sauvegardé dans votre compte. Veuillez choisir comment procéder :",
|
||||
"deleteServer": "Supprimer le panier du serveur",
|
||||
"useServer": "Utiliser le panier du serveur",
|
||||
"merge": "Fusionner les paniers",
|
||||
"currentCart": "Votre panier actuel",
|
||||
"serverCart": "Panier sauvegardé dans votre profil"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Chargement du produit...",
|
||||
"notFound": "Produit introuvable",
|
||||
"notFoundDescription": "Le produit recherché n'existe pas ou a été supprimé.",
|
||||
"backToHome": "Retour à l'accueil",
|
||||
"error": "Erreur",
|
||||
"articleNumber": "Numéro d'article",
|
||||
"manufacturer": "Fabricant",
|
||||
"inclVat": "TVA {{vat}}% incluse",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nouveau",
|
||||
"arriving": "Arrivée :",
|
||||
"inclVatFooter": "TVA {{vat}}% incluse,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Tu peux me demander des variétés de cannabis...",
|
||||
"recording": "Enregistrement en cours..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Lu et accepté"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Colis volumineux",
|
||||
"pickup": "Retrait en magasin"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Livraison standard",
|
||||
"standardFree": "Livraison standard - GRATUITE à partir de 100€ d'achat !",
|
||||
"notAvailable": "non disponible car un ou plusieurs articles ne peuvent être que retirés",
|
||||
"bulky": "Pour les articles volumineux et lourds"
|
||||
},
|
||||
"prices": {
|
||||
"free": "gratuit",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Adresse de facturation",
|
||||
"deliveryAddress": "Adresse de livraison",
|
||||
"saveForFuture": "Sauvegarder pour les commandes futures",
|
||||
"pickupDate": "Pour quelle date souhaitez-vous le retrait des boutures ?",
|
||||
"note": "Remarque",
|
||||
"sameAddress": "L'adresse de livraison est identique à l'adresse de facturation",
|
||||
"termsAccept": "J'ai lu les CGV, la politique de confidentialité et les conditions de rétractation"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sa 11-19",
|
||||
"address": "Trachenberger Straße 14 - Dresde",
|
||||
"location": "Entre l'arrêt Pieschen et Trachenberger Platz",
|
||||
"allPricesIncl": "* Tous les prix TVA légale incluse, hors frais de port",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Protection des données",
|
||||
"agb": "CGV",
|
||||
"sitemap": "Plan du site",
|
||||
"impressum": "Mentions légales",
|
||||
"batteriegesetzhinweise": "Informations sur la loi sur les batteries",
|
||||
"widerrufsrecht": "Droit de rétractation"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Graines et boutures de cannabis",
|
||||
"aktionen": "Actions et offres actuelles",
|
||||
"filiale": "Notre magasin à Dresde"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Graines",
|
||||
"stecklinge": "Boutures",
|
||||
"oilPress": "Louer une presse à huile",
|
||||
"thcTest": "Test THC",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Dresde"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Louer une presse à huile",
|
||||
"comingSoon": "Contenu à venir..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Test THC",
|
||||
"comingSoon": "Contenu à venir..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "en cours de traitement",
|
||||
"pending": "Nouveau",
|
||||
"processing": "en cours de traitement",
|
||||
"cancelled": "Annulé",
|
||||
"shipped": "Expédié",
|
||||
"delivered": "Livré",
|
||||
"return": "Retour",
|
||||
"partialReturn": "Retour partiel",
|
||||
"partialDelivered": "Partiellement livré"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Chargement...",
|
||||
"error": "Erreur",
|
||||
"close": "Fermer",
|
||||
"save": "Sauvegarder",
|
||||
"cancel": "Annuler",
|
||||
"ok": "OK",
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"next": "Suivant",
|
||||
"back": "Retour",
|
||||
"edit": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"add": "Ajouter",
|
||||
"remove": "Retirer"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/hu/translation.json
Normal file
162
src/i18n/locales/hu/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Főoldal",
|
||||
"aktionen": "Akciók",
|
||||
"filiale": "Fiók",
|
||||
"categories": "Kategóriák"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Bejelentkezés",
|
||||
"register": "Regisztráció",
|
||||
"logout": "Kijelentkezés",
|
||||
"profile": "Profil",
|
||||
"email": "E-mail",
|
||||
"password": "Jelszó",
|
||||
"confirmPassword": "Jelszó megerősítése",
|
||||
"forgotPassword": "Elfelejtett jelszó?",
|
||||
"loginWithGoogle": "Bejelentkezés Google-lal",
|
||||
"or": "VAGY",
|
||||
"privacyAccept": "A \"Bejelentkezés Google-lal\" gombra kattintva elfogadom a",
|
||||
"privacyPolicy": "Adatvédelmi szabályzatot",
|
||||
"passwordMinLength": "A jelszónak legalább 8 karaktert kell tartalmaznia",
|
||||
"newPasswordMinLength": "Az új jelszónak legalább 8 karaktert kell tartalmaznia",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Rendelés befejezése",
|
||||
"orders": "Rendelések",
|
||||
"settings": "Beállítások",
|
||||
"adminDashboard": "Admin irányítópult",
|
||||
"adminUsers": "Admin felhasználók"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Kosár",
|
||||
"empty": "üres",
|
||||
"sync": {
|
||||
"title": "Kosár szinkronizálás",
|
||||
"description": "Van egy mentett kosara a fiókjában. Kérjük, válassza ki, hogyan szeretne folytatni:",
|
||||
"deleteServer": "Szerver kosár törlése",
|
||||
"useServer": "Szerver kosár használata",
|
||||
"merge": "Kosaras egyesítése",
|
||||
"currentCart": "Az Ön jelenlegi kosara",
|
||||
"serverCart": "A profiljában mentett kosár"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Termék betöltése...",
|
||||
"notFound": "Termék nem található",
|
||||
"notFoundDescription": "A keresett termék nem létezik vagy el lett távolítva.",
|
||||
"backToHome": "Vissza a főoldalra",
|
||||
"error": "Hiba",
|
||||
"articleNumber": "Cikkszám",
|
||||
"manufacturer": "Gyártó",
|
||||
"inclVat": "{{vat}}% áfával",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Új",
|
||||
"arriving": "Érkezés:",
|
||||
"inclVatFooter": "{{vat}}% áfával,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Kérdezhetsz tőlem kannabisz fajtákról...",
|
||||
"recording": "Felvétel folyamatban..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Elolvasva és elfogadva"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Túlméretes áru",
|
||||
"pickup": "Átvétel a fiókban"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Normál szállítás",
|
||||
"standardFree": "Normál szállítás - INGYENES 100€ áruvásárlás felett!",
|
||||
"notAvailable": "nem elérhető, mert egy vagy több cikket csak át lehet venni",
|
||||
"bulky": "Nagy és nehéz tárgyakhoz"
|
||||
},
|
||||
"prices": {
|
||||
"free": "ingyenes",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Számlázási cím",
|
||||
"deliveryAddress": "Szállítási cím",
|
||||
"saveForFuture": "Mentés jövőbeli rendelésekhez",
|
||||
"pickupDate": "Melyik időpontra kéri a dugványok átvételét?",
|
||||
"note": "Megjegyzés",
|
||||
"sameAddress": "A szállítási cím megegyezik a számlázási címmel",
|
||||
"termsAccept": "Elolvastam az ÁSZF-et, az adatvédelmi szabályzatot és az elállási jog feltételeit"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Szo 11-19",
|
||||
"address": "Trachenberger Straße 14 - Drezda",
|
||||
"location": "A Pieschen megálló és a Trachenberger Platz között",
|
||||
"allPricesIncl": "* Minden ár tartalmazza a törvényes áfát, plusz szállítás",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Adatvédelem",
|
||||
"agb": "ÁSZF",
|
||||
"sitemap": "Oldaltérkép",
|
||||
"impressum": "Impresszum",
|
||||
"batteriegesetzhinweise": "Elemtörvény tájékoztató",
|
||||
"widerrufsrecht": "Elállási jog"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Kannabisz magok és dugványok",
|
||||
"aktionen": "Aktuális akciók és ajánlatok",
|
||||
"filiale": "Drezdai fiókunk"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Magok",
|
||||
"stecklinge": "Dugványok",
|
||||
"oilPress": "Olajprés kölcsönzés",
|
||||
"thcTest": "THC teszt",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Drezda"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Olajprés kölcsönzés",
|
||||
"comingSoon": "Tartalom hamarosan..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "THC teszt",
|
||||
"comingSoon": "Tartalom hamarosan..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "feldolgozás alatt",
|
||||
"pending": "Új",
|
||||
"processing": "feldolgozás alatt",
|
||||
"cancelled": "Törölve",
|
||||
"shipped": "Elküldve",
|
||||
"delivered": "Kézbesítve",
|
||||
"return": "Visszaküldés",
|
||||
"partialReturn": "Részleges visszaküldés",
|
||||
"partialDelivered": "Részlegesen kézbesítve"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Betöltés...",
|
||||
"error": "Hiba",
|
||||
"close": "Bezárás",
|
||||
"save": "Mentés",
|
||||
"cancel": "Mégse",
|
||||
"ok": "OK",
|
||||
"yes": "Igen",
|
||||
"no": "Nem",
|
||||
"next": "Következő",
|
||||
"back": "Vissza",
|
||||
"edit": "Szerkesztés",
|
||||
"delete": "Törlés",
|
||||
"add": "Hozzáadás",
|
||||
"remove": "Eltávolítás"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/it/translation.json
Normal file
162
src/i18n/locales/it/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"aktionen": "Azioni",
|
||||
"filiale": "Filiale",
|
||||
"categories": "Categorie"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Accedi",
|
||||
"register": "Registrati",
|
||||
"logout": "Esci",
|
||||
"profile": "Profilo",
|
||||
"email": "E-mail",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Conferma password",
|
||||
"forgotPassword": "Password dimenticata?",
|
||||
"loginWithGoogle": "Accedi con Google",
|
||||
"or": "OPPURE",
|
||||
"privacyAccept": "Cliccando \"Accedi con Google\" accetto la",
|
||||
"privacyPolicy": "Politica sulla privacy",
|
||||
"passwordMinLength": "La password deve contenere almeno 8 caratteri",
|
||||
"newPasswordMinLength": "La nuova password deve contenere almeno 8 caratteri",
|
||||
"menu": {
|
||||
"profile": "Profilo",
|
||||
"checkout": "Finalizza ordine",
|
||||
"orders": "Ordini",
|
||||
"settings": "Impostazioni",
|
||||
"adminDashboard": "Dashboard amministratore",
|
||||
"adminUsers": "Utenti amministratore"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Carrello",
|
||||
"empty": "vuoto",
|
||||
"sync": {
|
||||
"title": "Sincronizzazione carrello",
|
||||
"description": "Hai un carrello salvato nel tuo account. Per favore scegli come procedere:",
|
||||
"deleteServer": "Elimina carrello dal server",
|
||||
"useServer": "Usa carrello dal server",
|
||||
"merge": "Unisci carrelli",
|
||||
"currentCart": "Il tuo carrello attuale",
|
||||
"serverCart": "Carrello salvato nel tuo profilo"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Caricamento prodotto...",
|
||||
"notFound": "Prodotto non trovato",
|
||||
"notFoundDescription": "Il prodotto cercato non esiste o è stato rimosso.",
|
||||
"backToHome": "Torna alla home",
|
||||
"error": "Errore",
|
||||
"articleNumber": "Numero articolo",
|
||||
"manufacturer": "Produttore",
|
||||
"inclVat": "inclusa IVA {{vat}}%",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nuovo",
|
||||
"arriving": "Arrivo:",
|
||||
"inclVatFooter": "inclusa IVA {{vat}}%,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Puoi chiedermi delle varietà di cannabis...",
|
||||
"recording": "Registrazione in corso..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Letto e accettato"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Merce ingombrante",
|
||||
"pickup": "Ritiro in filiale"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Spedizione standard",
|
||||
"standardFree": "Spedizione standard - GRATUITA da 100€ di valore merce!",
|
||||
"notAvailable": "non selezionabile perché uno o più articoli possono essere solo ritirati",
|
||||
"bulky": "Per articoli grandi e pesanti"
|
||||
},
|
||||
"prices": {
|
||||
"free": "gratuito",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Indirizzo di fatturazione",
|
||||
"deliveryAddress": "Indirizzo di consegna",
|
||||
"saveForFuture": "Salva per ordini futuri",
|
||||
"pickupDate": "Per quale data desideri il ritiro delle talee?",
|
||||
"note": "Nota",
|
||||
"sameAddress": "L'indirizzo di consegna è identico a quello di fatturazione",
|
||||
"termsAccept": "Ho letto i termini e condizioni, l'informativa sulla privacy e le condizioni di recesso"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sab 11-19",
|
||||
"address": "Trachenberger Straße 14 - Dresda",
|
||||
"location": "Tra la fermata Pieschen e Trachenberger Platz",
|
||||
"allPricesIncl": "* Tutti i prezzi includono IVA legale, più spedizione",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Privacy",
|
||||
"agb": "Termini e condizioni",
|
||||
"sitemap": "Mappa del sito",
|
||||
"impressum": "Note legali",
|
||||
"batteriegesetzhinweise": "Informazioni sulla legge sulle batterie",
|
||||
"widerrufsrecht": "Diritto di recesso"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Semi e talee di cannabis",
|
||||
"aktionen": "Azioni e offerte attuali",
|
||||
"filiale": "La nostra filiale a Dresda"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Semi",
|
||||
"stecklinge": "Talee",
|
||||
"oilPress": "Noleggio pressa per olio",
|
||||
"thcTest": "Test THC",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Dresda"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Noleggio pressa per olio",
|
||||
"comingSoon": "Contenuto in arrivo..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Test THC",
|
||||
"comingSoon": "Contenuto in arrivo..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "in elaborazione",
|
||||
"pending": "Nuovo",
|
||||
"processing": "in elaborazione",
|
||||
"cancelled": "Annullato",
|
||||
"shipped": "Spedito",
|
||||
"delivered": "Consegnato",
|
||||
"return": "Reso",
|
||||
"partialReturn": "Reso parziale",
|
||||
"partialDelivered": "Parzialmente consegnato"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Caricamento...",
|
||||
"error": "Errore",
|
||||
"close": "Chiudi",
|
||||
"save": "Salva",
|
||||
"cancel": "Annulla",
|
||||
"ok": "OK",
|
||||
"yes": "Sì",
|
||||
"no": "No",
|
||||
"next": "Avanti",
|
||||
"back": "Indietro",
|
||||
"edit": "Modifica",
|
||||
"delete": "Elimina",
|
||||
"add": "Aggiungi",
|
||||
"remove": "Rimuovi"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/pl/translation.json
Normal file
162
src/i18n/locales/pl/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Strona główna",
|
||||
"aktionen": "Akcje",
|
||||
"filiale": "Oddział",
|
||||
"categories": "Kategorie"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Zaloguj się",
|
||||
"register": "Zarejestruj się",
|
||||
"logout": "Wyloguj się",
|
||||
"profile": "Profil",
|
||||
"email": "E-mail",
|
||||
"password": "Hasło",
|
||||
"confirmPassword": "Potwierdź hasło",
|
||||
"forgotPassword": "Zapomniałeś hasła?",
|
||||
"loginWithGoogle": "Zaloguj się przez Google",
|
||||
"or": "LUB",
|
||||
"privacyAccept": "Klikając \"Zaloguj się przez Google\" akceptuję",
|
||||
"privacyPolicy": "Politykę prywatności",
|
||||
"passwordMinLength": "Hasło musi zawierać co najmniej 8 znaków",
|
||||
"newPasswordMinLength": "Nowe hasło musi zawierać co najmniej 8 znaków",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Finalizacja zamówienia",
|
||||
"orders": "Zamówienia",
|
||||
"settings": "Ustawienia",
|
||||
"adminDashboard": "Panel administratora",
|
||||
"adminUsers": "Użytkownicy administratora"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Koszyk",
|
||||
"empty": "pusty",
|
||||
"sync": {
|
||||
"title": "Synchronizacja koszyka",
|
||||
"description": "Masz zapisany koszyk w swoim koncie. Proszę wybierz, jak chcesz kontynuować:",
|
||||
"deleteServer": "Usuń koszyk z serwera",
|
||||
"useServer": "Użyj koszyka z serwera",
|
||||
"merge": "Połącz koszyki",
|
||||
"currentCart": "Twój obecny koszyk",
|
||||
"serverCart": "Koszyk zapisany w Twoim profilu"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Ładowanie produktu...",
|
||||
"notFound": "Produkt nie znaleziony",
|
||||
"notFoundDescription": "Szukany produkt nie istnieje lub został usunięty.",
|
||||
"backToHome": "Powrót do strony głównej",
|
||||
"error": "Błąd",
|
||||
"articleNumber": "Numer artykułu",
|
||||
"manufacturer": "Producent",
|
||||
"inclVat": "w tym {{vat}}% VAT",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nowy",
|
||||
"arriving": "Przyjazd:",
|
||||
"inclVatFooter": "w tym {{vat}}% VAT,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Możesz zapytać mnie o odmiany marihuany...",
|
||||
"recording": "Nagrywanie w toku..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Przeczytane i zaakceptowane"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Przesyłka gabarytowa",
|
||||
"pickup": "Odbiór w oddziale"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Dostawa standardowa",
|
||||
"standardFree": "Dostawa standardowa - DARMOWA od 100€ wartości towaru!",
|
||||
"notAvailable": "niedostępne, ponieważ jeden lub więcej artykułów można tylko odebrać",
|
||||
"bulky": "Dla dużych i ciężkich przedmiotów"
|
||||
},
|
||||
"prices": {
|
||||
"free": "darmowe",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Adres do faktury",
|
||||
"deliveryAddress": "Adres dostawy",
|
||||
"saveForFuture": "Zapisz dla przyszłych zamówień",
|
||||
"pickupDate": "Na kiedy chcesz odebrać sadzonki?",
|
||||
"note": "Uwaga",
|
||||
"sameAddress": "Adres dostawy jest taki sam jak adres do faktury",
|
||||
"termsAccept": "Przeczytałem regulamin, politykę prywatności i warunki odstąpienia"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Sob 11-19",
|
||||
"address": "Trachenberger Straße 14 - Drezno",
|
||||
"location": "Między przystankiem Pieschen a Trachenberger Platz",
|
||||
"allPricesIncl": "* Wszystkie ceny zawierają ustawowy VAT, plus dostawa",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Ochrona danych",
|
||||
"agb": "Regulamin",
|
||||
"sitemap": "Mapa strony",
|
||||
"impressum": "Stopka redakcyjna",
|
||||
"batteriegesetzhinweise": "Informacje o ustawie o bateriach",
|
||||
"widerrufsrecht": "Prawo odstąpienia"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Nasiona i sadzonki marihuany",
|
||||
"aktionen": "Bieżące akcje i oferty",
|
||||
"filiale": "Nasz oddział w Dreźnie"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Nasiona",
|
||||
"stecklinge": "Sadzonki",
|
||||
"oilPress": "Wypożyczenie prasy do oleju",
|
||||
"thcTest": "Test THC",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Drezno"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Wypożyczenie prasy do oleju",
|
||||
"comingSoon": "Treść wkrótce..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Test THC",
|
||||
"comingSoon": "Treść wkrótce..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "w trakcie realizacji",
|
||||
"pending": "Nowe",
|
||||
"processing": "w trakcie realizacji",
|
||||
"cancelled": "Anulowane",
|
||||
"shipped": "Wysłane",
|
||||
"delivered": "Dostarczone",
|
||||
"return": "Zwrot",
|
||||
"partialReturn": "Częściowy zwrot",
|
||||
"partialDelivered": "Częściowo dostarczone"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Ładowanie...",
|
||||
"error": "Błąd",
|
||||
"close": "Zamknij",
|
||||
"save": "Zapisz",
|
||||
"cancel": "Anuluj",
|
||||
"ok": "OK",
|
||||
"yes": "Tak",
|
||||
"no": "Nie",
|
||||
"next": "Dalej",
|
||||
"back": "Wstecz",
|
||||
"edit": "Edytuj",
|
||||
"delete": "Usuń",
|
||||
"add": "Dodaj",
|
||||
"remove": "Usuń"
|
||||
}
|
||||
}
|
||||
185
src/i18n/locales/ro/translation.json
Normal file
185
src/i18n/locales/ro/translation.json
Normal file
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Acasă",
|
||||
"aktionen": "Acțiuni",
|
||||
"filiale": "Filială",
|
||||
"categories": "Categorii"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Conectare",
|
||||
"register": "Înregistrare",
|
||||
"logout": "Deconectare",
|
||||
"profile": "Profil",
|
||||
"email": "Email",
|
||||
"password": "Parolă",
|
||||
"confirmPassword": "Confirmă parola",
|
||||
"forgotPassword": "Ați uitat parola?",
|
||||
"loginWithGoogle": "Conectare cu Google",
|
||||
"or": "SAU",
|
||||
"privacyAccept": "Făcând clic pe \"Conectare cu Google\" accept",
|
||||
"privacyPolicy": "Politica de confidențialitate",
|
||||
"and": "și",
|
||||
"termsOfService": "Termenii de serviciu",
|
||||
"profileMenu": {
|
||||
"profile": "Profil",
|
||||
"orders": "Comenzi",
|
||||
"wishlist": "Lista de dorințe",
|
||||
"settings": "Setări",
|
||||
"logout": "Deconectare"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Coș de cumpărături",
|
||||
"empty": "Coșul este gol",
|
||||
"total": "Total",
|
||||
"checkout": "Finalizare comandă",
|
||||
"continue": "Continuă cumpărăturile",
|
||||
"sync": {
|
||||
"title": "Sincronizare coș",
|
||||
"message": "S-au găsit articole în coșul local și coșul de pe server. Ce doriți să faceți?",
|
||||
"keepLocal": "Păstrează local",
|
||||
"keepServer": "Păstrează server",
|
||||
"merge": "Combină ambele"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Se încarcă produsul...",
|
||||
"error": "Eroare la încărcarea produsului",
|
||||
"notFound": "Produsul nu a fost găsit",
|
||||
"addToCart": "Adaugă în coș",
|
||||
"description": "Descriere",
|
||||
"specifications": "Specificații",
|
||||
"reviews": "Recenzii",
|
||||
"price": "Preț",
|
||||
"availability": "Disponibilitate",
|
||||
"inStock": "În stoc",
|
||||
"outOfStock": "Stoc epuizat",
|
||||
"category": "Categorie"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"standard": "Livrare standard",
|
||||
"express": "Livrare express",
|
||||
"pickup": "Ridicare personală"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Livrare în 3-5 zile lucrătoare",
|
||||
"express": "Livrare în 1-2 zile lucrătoare",
|
||||
"pickup": "Ridicare din magazin"
|
||||
},
|
||||
"costs": {
|
||||
"standard": "4,99 EUR",
|
||||
"express": "9,99 EUR",
|
||||
"pickup": "Gratuit"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"title": "Finalizare comandă",
|
||||
"steps": {
|
||||
"shipping": "Adresa de livrare",
|
||||
"payment": "Plată",
|
||||
"review": "Revizuire",
|
||||
"confirmation": "Confirmare"
|
||||
},
|
||||
"shipping": {
|
||||
"firstName": "Prenume",
|
||||
"lastName": "Nume",
|
||||
"street": "Strada",
|
||||
"houseNumber": "Numărul casei",
|
||||
"postalCode": "Cod poștal",
|
||||
"city": "Oraș",
|
||||
"country": "Țară",
|
||||
"phone": "Telefon"
|
||||
},
|
||||
"payment": {
|
||||
"method": "Metodă de plată",
|
||||
"creditCard": "Card de credit",
|
||||
"paypal": "PayPal",
|
||||
"bankTransfer": "Transfer bancar",
|
||||
"cashOnDelivery": "Plată la livrare"
|
||||
},
|
||||
"review": {
|
||||
"orderSummary": "Rezumatul comenzii",
|
||||
"shippingAddress": "Adresa de livrare",
|
||||
"paymentMethod": "Metodă de plată",
|
||||
"orderTotal": "Total comandă"
|
||||
},
|
||||
"placeOrder": "Plasează comanda",
|
||||
"processing": "Se procesează comanda..."
|
||||
},
|
||||
"footer": {
|
||||
"company": "Companie",
|
||||
"about": "Despre noi",
|
||||
"contact": "Contact",
|
||||
"careers": "Cariere",
|
||||
"legal": "Legal",
|
||||
"privacy": "Confidențialitate",
|
||||
"terms": "Termeni",
|
||||
"imprint": "Imprint",
|
||||
"support": "Suport",
|
||||
"faq": "Întrebări frecvente",
|
||||
"shipping": "Informații livrare",
|
||||
"returns": "Returnări",
|
||||
"social": "Social",
|
||||
"newsletter": "Newsletter",
|
||||
"subscribe": "Abonați-vă",
|
||||
"copyright": "Toate drepturile rezervate."
|
||||
},
|
||||
"pages": {
|
||||
"thcTest": {
|
||||
"title": "Test THC",
|
||||
"subtitle": "Testare profesională a conținutului de THC",
|
||||
"description": "Oferim servicii profesionale de testare a conținutului de THC pentru produsele dumneavoastră. Rezultate precise și rapide.",
|
||||
"features": {
|
||||
"accurate": "Rezultate precise",
|
||||
"fast": "Procesare rapidă",
|
||||
"certified": "Laborator certificat",
|
||||
"confidential": "Confidențial"
|
||||
},
|
||||
"process": {
|
||||
"title": "Procesul de testare",
|
||||
"step1": "Trimiteți proba",
|
||||
"step2": "Analiză de laborator",
|
||||
"step3": "Primiți rezultatele"
|
||||
}
|
||||
},
|
||||
"presseverleih": {
|
||||
"title": "Închiriere presă",
|
||||
"subtitle": "Echipament profesional de presare pentru închiriere",
|
||||
"description": "Închiriați echipamentul nostru profesional de presare pentru nevoile dumneavoastră de producție.",
|
||||
"equipment": {
|
||||
"rosinPress": "Presă rosin",
|
||||
"hydraulicPress": "Presă hidraulică",
|
||||
"heatPress": "Presă cu căldură"
|
||||
},
|
||||
"rental": {
|
||||
"daily": "Tarif zilnic",
|
||||
"weekly": "Tarif săptămânal",
|
||||
"monthly": "Tarif lunar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Se încarcă...",
|
||||
"error": "Eroare",
|
||||
"success": "Succes",
|
||||
"warning": "Avertisment",
|
||||
"info": "Informație",
|
||||
"yes": "Da",
|
||||
"no": "Nu",
|
||||
"ok": "OK",
|
||||
"cancel": "Anulează",
|
||||
"save": "Salvează",
|
||||
"edit": "Editează",
|
||||
"delete": "Șterge",
|
||||
"search": "Căutare",
|
||||
"filter": "Filtru",
|
||||
"sort": "Sortează",
|
||||
"page": "Pagina",
|
||||
"of": "din",
|
||||
"next": "Următorul",
|
||||
"previous": "Anterior",
|
||||
"first": "Primul",
|
||||
"last": "Ultimul"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/ru/translation.json
Normal file
162
src/i18n/locales/ru/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Главная",
|
||||
"aktionen": "Акции",
|
||||
"filiale": "Филиал",
|
||||
"categories": "Категории"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Войти",
|
||||
"register": "Зарегистрироваться",
|
||||
"logout": "Выйти",
|
||||
"profile": "Профиль",
|
||||
"email": "Электронная почта",
|
||||
"password": "Пароль",
|
||||
"confirmPassword": "Подтвердить пароль",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"loginWithGoogle": "Войти через Google",
|
||||
"or": "ИЛИ",
|
||||
"privacyAccept": "Нажимая \"Войти через Google\", я принимаю",
|
||||
"privacyPolicy": "Политику конфиденциальности",
|
||||
"passwordMinLength": "Пароль должен содержать не менее 8 символов",
|
||||
"newPasswordMinLength": "Новый пароль должен содержать не менее 8 символов",
|
||||
"menu": {
|
||||
"profile": "Профиль",
|
||||
"checkout": "Оформление заказа",
|
||||
"orders": "Заказы",
|
||||
"settings": "Настройки",
|
||||
"adminDashboard": "Панель администратора",
|
||||
"adminUsers": "Пользователи администратора"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Корзина",
|
||||
"empty": "пустая",
|
||||
"sync": {
|
||||
"title": "Синхронизация корзины",
|
||||
"description": "У вас есть сохраненная корзина в вашем аккаунте. Пожалуйста, выберите, как продолжить:",
|
||||
"deleteServer": "Удалить корзину с сервера",
|
||||
"useServer": "Использовать корзину с сервера",
|
||||
"merge": "Объединить корзины",
|
||||
"currentCart": "Ваша текущая корзина",
|
||||
"serverCart": "Корзина, сохраненная в вашем профиле"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Загрузка товара...",
|
||||
"notFound": "Товар не найден",
|
||||
"notFoundDescription": "Искомый товар не существует или был удален.",
|
||||
"backToHome": "Вернуться на главную",
|
||||
"error": "Ошибка",
|
||||
"articleNumber": "Номер артикула",
|
||||
"manufacturer": "Производитель",
|
||||
"inclVat": "включая {{vat}}% НДС",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Новый",
|
||||
"arriving": "Прибытие:",
|
||||
"inclVatFooter": "включая {{vat}}% НДС,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Ты можешь спросить меня о сортах конопли...",
|
||||
"recording": "Идет запись..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Прочитано и принято"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Габаритный груз",
|
||||
"pickup": "Самовывоз в филиале"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Стандартная доставка",
|
||||
"standardFree": "Стандартная доставка - БЕСПЛАТНО от 100€ стоимости товара!",
|
||||
"notAvailable": "недоступно, поскольку один или несколько товаров можно только забрать",
|
||||
"bulky": "Для больших и тяжелых предметов"
|
||||
},
|
||||
"prices": {
|
||||
"free": "бесплатно",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Адрес для счета",
|
||||
"deliveryAddress": "Адрес доставки",
|
||||
"saveForFuture": "Сохранить для будущих заказов",
|
||||
"pickupDate": "На какую дату вы желаете забрать саженцы?",
|
||||
"note": "Примечание",
|
||||
"sameAddress": "Адрес доставки совпадает с адресом для счета",
|
||||
"termsAccept": "Я прочитал условия использования, политику конфиденциальности и условия отказа"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Сб 11-19",
|
||||
"address": "Trachenberger Straße 14 - Дрезден",
|
||||
"location": "Между остановкой Pieschen и Trachenberger Platz",
|
||||
"allPricesIncl": "* Все цены включают законный НДС, плюс доставка",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Защита данных",
|
||||
"agb": "Условия использования",
|
||||
"sitemap": "Карта сайта",
|
||||
"impressum": "Выходные данные",
|
||||
"batteriegesetzhinweise": "Информация о законе о батареях",
|
||||
"widerrufsrecht": "Право на отказ"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Семена и саженцы конопли",
|
||||
"aktionen": "Текущие акции и предложения",
|
||||
"filiale": "Наш филиал в Дрездене"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Семена",
|
||||
"stecklinge": "Саженцы",
|
||||
"oilPress": "Аренда пресса для масла",
|
||||
"thcTest": "Тест на ТГК",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Дрезден"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Аренда пресса для масла",
|
||||
"comingSoon": "Контент скоро появится..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Тест на ТГК",
|
||||
"comingSoon": "Контент скоро появится..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "в обработке",
|
||||
"pending": "Новый",
|
||||
"processing": "в обработке",
|
||||
"cancelled": "Отменен",
|
||||
"shipped": "Отправлен",
|
||||
"delivered": "Доставлен",
|
||||
"return": "Возврат",
|
||||
"partialReturn": "Частичный возврат",
|
||||
"partialDelivered": "Частично доставлен"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Загрузка...",
|
||||
"error": "Ошибка",
|
||||
"close": "Закрыть",
|
||||
"save": "Сохранить",
|
||||
"cancel": "Отменить",
|
||||
"ok": "OK",
|
||||
"yes": "Да",
|
||||
"no": "Нет",
|
||||
"next": "Далее",
|
||||
"back": "Назад",
|
||||
"edit": "Редактировать",
|
||||
"delete": "Удалить",
|
||||
"add": "Добавить",
|
||||
"remove": "Удалить"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/sk/translation.json
Normal file
162
src/i18n/locales/sk/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Domov",
|
||||
"aktionen": "Akcie",
|
||||
"filiale": "Pobočka",
|
||||
"categories": "Kategórie"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Prihlásiť sa",
|
||||
"register": "Registrovať sa",
|
||||
"logout": "Odhlásiť sa",
|
||||
"profile": "Profil",
|
||||
"email": "E-mail",
|
||||
"password": "Heslo",
|
||||
"confirmPassword": "Potvrdiť heslo",
|
||||
"forgotPassword": "Zabudnuté heslo?",
|
||||
"loginWithGoogle": "Prihlásiť sa cez Google",
|
||||
"or": "ALEBO",
|
||||
"privacyAccept": "Kliknutím na \"Prihlásiť sa cez Google\" súhlasím s",
|
||||
"privacyPolicy": "Zásadami ochrany osobných údajov",
|
||||
"passwordMinLength": "Heslo musí mať aspoň 8 znakov",
|
||||
"newPasswordMinLength": "Nové heslo musí mať aspoň 8 znakov",
|
||||
"menu": {
|
||||
"profile": "Profil",
|
||||
"checkout": "Dokončenie objednávky",
|
||||
"orders": "Objednávky",
|
||||
"settings": "Nastavenia",
|
||||
"adminDashboard": "Admin panel",
|
||||
"adminUsers": "Admin používatelia"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Košík",
|
||||
"empty": "prázdny",
|
||||
"sync": {
|
||||
"title": "Synchronizácia košíka",
|
||||
"description": "Máte uložený košík vo svojom účte. Prosím vyberte, ako chcete pokračovať:",
|
||||
"deleteServer": "Zmazať serverový košík",
|
||||
"useServer": "Použiť serverový košík",
|
||||
"merge": "Spojiť košíky",
|
||||
"currentCart": "Váš aktuálny košík",
|
||||
"serverCart": "Košík uložený vo vašom profile"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Načítavanie produktu...",
|
||||
"notFound": "Produkt nenájdený",
|
||||
"notFoundDescription": "Hľadaný produkt neexistuje alebo bol odstránený.",
|
||||
"backToHome": "Späť na domovskú stránku",
|
||||
"error": "Chyba",
|
||||
"articleNumber": "Číslo článku",
|
||||
"manufacturer": "Výrobca",
|
||||
"inclVat": "vrátane {{vat}}% DPH",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Nový",
|
||||
"arriving": "Príchod:",
|
||||
"inclVatFooter": "vrátane {{vat}}% DPH,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Môžeš sa ma opýtať na odrody konope...",
|
||||
"recording": "Prebieha nahrávanie..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Prečítané a akceptované"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Nadrozmerný tovar",
|
||||
"pickup": "Vyzdvihnutie na pobočke"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Štandardná doprava",
|
||||
"standardFree": "Štandardná doprava - ZDARMA od 100€ hodnoty tovaru!",
|
||||
"notAvailable": "nedostupné, pretože jeden alebo viac článkov možno iba vyzdvihnúť",
|
||||
"bulky": "Pre veľké a ťažké predmety"
|
||||
},
|
||||
"prices": {
|
||||
"free": "zdarma",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Fakturačná adresa",
|
||||
"deliveryAddress": "Dodacia adresa",
|
||||
"saveForFuture": "Uložiť pre budúce objednávky",
|
||||
"pickupDate": "Na ktorý dátum si želáte vyzdvihnúť sadenky?",
|
||||
"note": "Poznámka",
|
||||
"sameAddress": "Dodacia adresa je totožná s fakturačnou adresou",
|
||||
"termsAccept": "Prečítal som si obchodné podmienky, zásady ochrany osobných údajov a podmienky odstúpenia"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "So 11-19",
|
||||
"address": "Trachenberger Straße 14 - Drážďany",
|
||||
"location": "Medzi zastávkou Pieschen a Trachenberger Platz",
|
||||
"allPricesIncl": "* Všetky ceny vrátane zákonnej DPH, plus doprava",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Ochrana údajov",
|
||||
"agb": "Obchodné podmienky",
|
||||
"sitemap": "Mapa stránok",
|
||||
"impressum": "Tiráž",
|
||||
"batteriegesetzhinweise": "Informácie o zákone o batériách",
|
||||
"widerrufsrecht": "Právo na odstúpenie"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Semená a sadenky konope",
|
||||
"aktionen": "Aktuálne akcie a ponuky",
|
||||
"filiale": "Naša pobočka v Drážďanoch"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Semená",
|
||||
"stecklinge": "Sadenky",
|
||||
"oilPress": "Požičanie lisu na olej",
|
||||
"thcTest": "THC test",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Drážďany"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Požičanie lisu na olej",
|
||||
"comingSoon": "Obsah bude čoskoro..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "THC test",
|
||||
"comingSoon": "Obsah bude čoskoro..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "spracováva sa",
|
||||
"pending": "Nový",
|
||||
"processing": "spracováva sa",
|
||||
"cancelled": "Zrušené",
|
||||
"shipped": "Odoslané",
|
||||
"delivered": "Doručené",
|
||||
"return": "Vrátenie",
|
||||
"partialReturn": "Čiastočné vrátenie",
|
||||
"partialDelivered": "Čiastočne doručené"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Načítava...",
|
||||
"error": "Chyba",
|
||||
"close": "Zavrieť",
|
||||
"save": "Uložiť",
|
||||
"cancel": "Zrušiť",
|
||||
"ok": "OK",
|
||||
"yes": "Áno",
|
||||
"no": "Nie",
|
||||
"next": "Ďalej",
|
||||
"back": "Späť",
|
||||
"edit": "Upraviť",
|
||||
"delete": "Zmazať",
|
||||
"add": "Pridať",
|
||||
"remove": "Odobrať"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/sr/translation.json
Normal file
162
src/i18n/locales/sr/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Почетна",
|
||||
"aktionen": "Акције",
|
||||
"filiale": "Филијала",
|
||||
"categories": "Категорије"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Пријава",
|
||||
"register": "Регистрација",
|
||||
"logout": "Одјава",
|
||||
"profile": "Профил",
|
||||
"email": "Е-мејл",
|
||||
"password": "Лозинка",
|
||||
"confirmPassword": "Потврди лозинку",
|
||||
"forgotPassword": "Заборавили сте лозинку?",
|
||||
"loginWithGoogle": "Пријави се преко Google",
|
||||
"or": "ИЛИ",
|
||||
"privacyAccept": "Кликом на \"Пријави се преко Google\" прихватам",
|
||||
"privacyPolicy": "Политику приватности",
|
||||
"passwordMinLength": "Лозинка мора да садржи најмање 8 карактера",
|
||||
"newPasswordMinLength": "Нова лозинка мора да садржи најмање 8 карактера",
|
||||
"menu": {
|
||||
"profile": "Профил",
|
||||
"checkout": "Завршавање поруџбе",
|
||||
"orders": "Поруџбе",
|
||||
"settings": "Подешавања",
|
||||
"adminDashboard": "Админ табла",
|
||||
"adminUsers": "Админ корисници"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Корпа",
|
||||
"empty": "празна",
|
||||
"sync": {
|
||||
"title": "Синхронизација корпе",
|
||||
"description": "Имате сачувану корпу у свом налогу. Молимо изаберите како желите да наставите:",
|
||||
"deleteServer": "Обриши корпус са сервера",
|
||||
"useServer": "Користи корпус са сервера",
|
||||
"merge": "Споји корпе",
|
||||
"currentCart": "Ваша тренутна корпа",
|
||||
"serverCart": "Корпа сачувана у вашем профилу"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Учитавање производа...",
|
||||
"notFound": "Производ није пронађен",
|
||||
"notFoundDescription": "Тражени производ не постоји или је уклоњен.",
|
||||
"backToHome": "Назад на почетну",
|
||||
"error": "Грешка",
|
||||
"articleNumber": "Број артикла",
|
||||
"manufacturer": "Произвођач",
|
||||
"inclVat": "укључујући {{vat}}% ПДВ",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Нов",
|
||||
"arriving": "Долазак:",
|
||||
"inclVatFooter": "укључујући {{vat}}% ПДВ,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Можеш да ме питаш о сортама канабиса...",
|
||||
"recording": "Снимање у току..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Прочитано и прихваћено"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Габаритни терет",
|
||||
"pickup": "Преузимање у филијали"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Стандардна достава",
|
||||
"standardFree": "Стандардна достава - БЕСПЛАТНО од 100€ вредности робе!",
|
||||
"notAvailable": "недоступно јер се један или више артикала може само преузети",
|
||||
"bulky": "За велике и тешке предмете"
|
||||
},
|
||||
"prices": {
|
||||
"free": "бесплатно",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Адреса за фактуру",
|
||||
"deliveryAddress": "Адреса за доставу",
|
||||
"saveForFuture": "Сачувај за будуће поруџбе",
|
||||
"pickupDate": "За који датум желите да преузмете саднице?",
|
||||
"note": "Напомена",
|
||||
"sameAddress": "Адреса за доставу је иста као адреса за фактуру",
|
||||
"termsAccept": "Прочитао сам услове коришћења, политику приватности и услове опозива"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Суб 11-19",
|
||||
"address": "Trachenberger Straße 14 - Дрезден",
|
||||
"location": "Између станице Pieschen и Trachenberger Platz",
|
||||
"allPricesIncl": "* Све цене укључују законски ПДВ, плус достава",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Заштита података",
|
||||
"agb": "Услови коришћења",
|
||||
"sitemap": "Мапа сајта",
|
||||
"impressum": "Импресум",
|
||||
"batteriegesetzhinweise": "Информације о закону о батеријама",
|
||||
"widerrufsrecht": "Право на опозив"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Семе и саднице канабиса",
|
||||
"aktionen": "Тренутне акције и понуде",
|
||||
"filiale": "Наша филијала у Дрездену"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Семе",
|
||||
"stecklinge": "Саднице",
|
||||
"oilPress": "Изнајмљивање пресе за уље",
|
||||
"thcTest": "ТХЦ тест",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Дрезден"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Изнајмљивање пресе за уље",
|
||||
"comingSoon": "Садржај ускоро долази..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "ТХЦ тест",
|
||||
"comingSoon": "Садржај ускоро долази..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "у обради",
|
||||
"pending": "Нов",
|
||||
"processing": "у обради",
|
||||
"cancelled": "Отказан",
|
||||
"shipped": "Послат",
|
||||
"delivered": "Доставен",
|
||||
"return": "Повраћај",
|
||||
"partialReturn": "Делимичан повраћај",
|
||||
"partialDelivered": "Делимично доставен"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Учитава...",
|
||||
"error": "Грешка",
|
||||
"close": "Затвори",
|
||||
"save": "Сачувај",
|
||||
"cancel": "Откажи",
|
||||
"ok": "OK",
|
||||
"yes": "Да",
|
||||
"no": "Не",
|
||||
"next": "Следеће",
|
||||
"back": "Назад",
|
||||
"edit": "Уреди",
|
||||
"delete": "Обриши",
|
||||
"add": "Додај",
|
||||
"remove": "Уклони"
|
||||
}
|
||||
}
|
||||
162
src/i18n/locales/uk/translation.json
Normal file
162
src/i18n/locales/uk/translation.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Головна",
|
||||
"aktionen": "Акції",
|
||||
"filiale": "Філія",
|
||||
"categories": "Категорії"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Увійти",
|
||||
"register": "Зареєструватися",
|
||||
"logout": "Вийти",
|
||||
"profile": "Профіль",
|
||||
"email": "Електронна пошта",
|
||||
"password": "Пароль",
|
||||
"confirmPassword": "Підтвердити пароль",
|
||||
"forgotPassword": "Забули пароль?",
|
||||
"loginWithGoogle": "Увійти через Google",
|
||||
"or": "АБО",
|
||||
"privacyAccept": "Натиснувши \"Увійти через Google\", я приймаю",
|
||||
"privacyPolicy": "Політику конфіденційності",
|
||||
"passwordMinLength": "Пароль повинен містити принаймні 8 символів",
|
||||
"newPasswordMinLength": "Новий пароль повинен містити принаймні 8 символів",
|
||||
"menu": {
|
||||
"profile": "Профіль",
|
||||
"checkout": "Оформлення замовлення",
|
||||
"orders": "Замовлення",
|
||||
"settings": "Налаштування",
|
||||
"adminDashboard": "Панель адміністратора",
|
||||
"adminUsers": "Користувачі адміністратора"
|
||||
}
|
||||
},
|
||||
"cart": {
|
||||
"title": "Кошик",
|
||||
"empty": "порожній",
|
||||
"sync": {
|
||||
"title": "Синхронізація кошика",
|
||||
"description": "У вашому обліковому записі є збережений кошик. Будь ласка, виберіть, як продовжити:",
|
||||
"deleteServer": "Видалити кошик з сервера",
|
||||
"useServer": "Використати кошик з сервера",
|
||||
"merge": "Об'єднати кошики",
|
||||
"currentCart": "Ваш поточний кошик",
|
||||
"serverCart": "Кошик, збережений у вашому профілі"
|
||||
}
|
||||
},
|
||||
"product": {
|
||||
"loading": "Завантаження товару...",
|
||||
"notFound": "Товар не знайдено",
|
||||
"notFoundDescription": "Шуканий товар не існує або був видалений.",
|
||||
"backToHome": "Повернутися на головну",
|
||||
"error": "Помилка",
|
||||
"articleNumber": "Номер артикулу",
|
||||
"manufacturer": "Виробник",
|
||||
"inclVat": "включаючи {{vat}}% ПДВ",
|
||||
"priceUnit": "{{price}}/{{unit}}",
|
||||
"new": "Новий",
|
||||
"arriving": "Прибуття:",
|
||||
"inclVatFooter": "включаючи {{vat}}% ПДВ,*"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Ти можеш запитати мене про сорти конопель...",
|
||||
"recording": "Йде запис..."
|
||||
},
|
||||
"chat": {
|
||||
"privacyRead": "Прочитано та прийнято"
|
||||
},
|
||||
"delivery": {
|
||||
"methods": {
|
||||
"dhl": "DHL",
|
||||
"dpd": "DPD",
|
||||
"sperrgut": "Габаритний вантаж",
|
||||
"pickup": "Самовивіз у філії"
|
||||
},
|
||||
"descriptions": {
|
||||
"standard": "Стандартна доставка",
|
||||
"standardFree": "Стандартна доставка - БЕЗКОШТОВНО від 100€ вартості товару!",
|
||||
"notAvailable": "недоступно, оскільки один або кілька товарів можна лише забрати",
|
||||
"bulky": "Для великих та важких предметів"
|
||||
},
|
||||
"prices": {
|
||||
"free": "безкоштовно",
|
||||
"dhl": "6,99 €",
|
||||
"dpd": "4,90 €",
|
||||
"sperrgut": "28,99 €"
|
||||
}
|
||||
},
|
||||
"checkout": {
|
||||
"invoiceAddress": "Адреса для рахунку",
|
||||
"deliveryAddress": "Адреса доставки",
|
||||
"saveForFuture": "Зберегти для майбутніх замовлень",
|
||||
"pickupDate": "На яку дату ви бажаєте забрати саджанці?",
|
||||
"note": "Примітка",
|
||||
"sameAddress": "Адреса доставки збігається з адресою для рахунку",
|
||||
"termsAccept": "Я прочитав умови використання, політику конфіденційності та умови відмови"
|
||||
},
|
||||
"footer": {
|
||||
"hours": "Сб 11-19",
|
||||
"address": "Trachenberger Straße 14 - Дрезден",
|
||||
"location": "Між зупинкою Pieschen та Trachenberger Platz",
|
||||
"allPricesIncl": "* Усі ціни включають законний ПДВ, плюс доставка",
|
||||
"copyright": "© {{year}} GrowHeads.de",
|
||||
"legal": {
|
||||
"datenschutz": "Захист даних",
|
||||
"agb": "Умови використання",
|
||||
"sitemap": "Карта сайту",
|
||||
"impressum": "Вихідні дані",
|
||||
"batteriegesetzhinweise": "Інформація про закон про батареї",
|
||||
"widerrufsrecht": "Право на відмову"
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"home": "Насіння та саджанці конопель",
|
||||
"aktionen": "Поточні акції та пропозиції",
|
||||
"filiale": "Наша філія в Дрездені"
|
||||
},
|
||||
"sections": {
|
||||
"seeds": "Насіння",
|
||||
"stecklinge": "Саджанці",
|
||||
"oilPress": "Оренда преса для олії",
|
||||
"thcTest": "Тест на ТГК",
|
||||
"address1": "Trachenberger Straße 14",
|
||||
"address2": "01129 Дрезден"
|
||||
},
|
||||
"pages": {
|
||||
"oilPress": {
|
||||
"title": "Оренда преса для олії",
|
||||
"comingSoon": "Контент скоро з'явиться..."
|
||||
},
|
||||
"thcTest": {
|
||||
"title": "Тест на ТГК",
|
||||
"comingSoon": "Контент скоро з'явиться..."
|
||||
}
|
||||
},
|
||||
"orders": {
|
||||
"status": {
|
||||
"new": "в обробці",
|
||||
"pending": "Новий",
|
||||
"processing": "в обробці",
|
||||
"cancelled": "Скасовано",
|
||||
"shipped": "Відправлено",
|
||||
"delivered": "Доставлено",
|
||||
"return": "Повернення",
|
||||
"partialReturn": "Часткове повернення",
|
||||
"partialDelivered": "Частково доставлено"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"loading": "Завантаження...",
|
||||
"error": "Помилка",
|
||||
"close": "Закрити",
|
||||
"save": "Зберегти",
|
||||
"cancel": "Скасувати",
|
||||
"ok": "OK",
|
||||
"yes": "Так",
|
||||
"no": "Ні",
|
||||
"next": "Далі",
|
||||
"back": "Назад",
|
||||
"edit": "Редагувати",
|
||||
"delete": "Видалити",
|
||||
"add": "Додати",
|
||||
"remove": "Видалити"
|
||||
}
|
||||
}
|
||||
113
src/i18n/withTranslation.js
Normal file
113
src/i18n/withTranslation.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import React, { Component } from 'react';
|
||||
import { withTranslation as reactI18nextWithTranslation } from 'react-i18next';
|
||||
|
||||
// HOC to provide translation functions to class components
|
||||
export const withTranslation = (namespaces = 'translation') => (WrappedComponent) => {
|
||||
return reactI18nextWithTranslation(namespaces)(WrappedComponent);
|
||||
};
|
||||
|
||||
// Context for language switching
|
||||
export const LanguageContext = React.createContext({
|
||||
currentLanguage: 'de',
|
||||
changeLanguage: () => {},
|
||||
availableLanguages: ['bg', 'cs', 'de', 'es', 'fr', 'hu', 'it', 'pl', 'ro', 'sr', 'ru', 'sk', 'uk', 'en']
|
||||
});
|
||||
|
||||
// Provider component for language management
|
||||
export class LanguageProvider extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Get initial language from i18n instance
|
||||
const currentLanguage = props.i18n?.language || 'de';
|
||||
|
||||
this.state = {
|
||||
currentLanguage,
|
||||
availableLanguages: ['bg', 'cs', 'de', 'es', 'fr', 'hu', 'it', 'pl', 'ro', 'sr', 'ru', 'sk', 'uk', 'en']
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Listen for language changes from i18n
|
||||
if (this.props.i18n) {
|
||||
this.props.i18n.on('languageChanged', this.handleLanguageChanged);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// Clean up listener
|
||||
if (this.props.i18n) {
|
||||
this.props.i18n.off('languageChanged', this.handleLanguageChanged);
|
||||
}
|
||||
}
|
||||
|
||||
handleLanguageChanged = (lng) => {
|
||||
this.setState({ currentLanguage: lng });
|
||||
|
||||
// Update HTML lang attribute for SEO
|
||||
document.documentElement.lang = lng;
|
||||
|
||||
// Update config if available
|
||||
if (window.shopConfig) {
|
||||
// Language code mapping for all supported languages
|
||||
const languageMap = {
|
||||
'de': 'de-DE',
|
||||
'en': 'en-US',
|
||||
'es': 'es-ES',
|
||||
'fr': 'fr-FR',
|
||||
'it': 'it-IT',
|
||||
'pl': 'pl-PL',
|
||||
'hu': 'hu-HU',
|
||||
'sr': 'sr-RS',
|
||||
'bg': 'bg-BG',
|
||||
'ru': 'ru-RU',
|
||||
'uk': 'uk-UA',
|
||||
'sk': 'sk-SK',
|
||||
'cs': 'cs-CZ',
|
||||
'ro': 'ro-RO'
|
||||
};
|
||||
window.shopConfig.language = languageMap[lng] || 'de-DE';
|
||||
}
|
||||
};
|
||||
|
||||
changeLanguage = (language) => {
|
||||
if (this.props.i18n && this.state.availableLanguages.includes(language)) {
|
||||
this.props.i18n.changeLanguage(language);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const contextValue = {
|
||||
currentLanguage: this.state.currentLanguage,
|
||||
changeLanguage: this.changeLanguage,
|
||||
availableLanguages: this.state.availableLanguages
|
||||
};
|
||||
|
||||
return (
|
||||
<LanguageContext.Provider value={contextValue}>
|
||||
{this.props.children}
|
||||
</LanguageContext.Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// HOC to inject language context into class components
|
||||
export const withLanguage = (WrappedComponent) => {
|
||||
return class extends Component {
|
||||
render() {
|
||||
return (
|
||||
<LanguageContext.Consumer>
|
||||
{(languageContext) => (
|
||||
<WrappedComponent {...this.props} languageContext={languageContext} />
|
||||
)}
|
||||
</LanguageContext.Consumer>
|
||||
);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Combined HOC that provides both translation and language context
|
||||
export const withI18n = (namespaces = 'translation') => (WrappedComponent) => {
|
||||
const WithTranslationComponent = withTranslation(namespaces)(WrappedComponent);
|
||||
return withLanguage(WithTranslationComponent);
|
||||
};
|
||||
@@ -2,8 +2,11 @@ import React from "react";
|
||||
import Container from "@mui/material/Container";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const PresseverleihPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ pt: 4, pb: 2, maxWidth: '1200px !important' }}>
|
||||
<Typography
|
||||
@@ -17,7 +20,7 @@ const PresseverleihPage = () => {
|
||||
textShadow: "3px 3px 10px rgba(0, 0, 0, 0.4)"
|
||||
}}
|
||||
>
|
||||
Ölpresse ausleihen
|
||||
{t('pages.oilPress.title')}
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
@@ -36,7 +39,7 @@ const PresseverleihPage = () => {
|
||||
fontStyle: "italic"
|
||||
}}
|
||||
>
|
||||
Inhalt kommt bald...
|
||||
{t('pages.oilPress.comingSoon')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Container>
|
||||
|
||||
@@ -2,8 +2,11 @@ import React from "react";
|
||||
import Container from "@mui/material/Container";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ThcTestPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ pt: 4, pb: 2, maxWidth: '1200px !important' }}>
|
||||
<Typography
|
||||
@@ -17,7 +20,7 @@ const ThcTestPage = () => {
|
||||
textShadow: "3px 3px 10px rgba(0, 0, 0, 0.4)"
|
||||
}}
|
||||
>
|
||||
THC Test
|
||||
{t('pages.thcTest.title')}
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
@@ -36,7 +39,7 @@ const ThcTestPage = () => {
|
||||
fontStyle: "italic"
|
||||
}}
|
||||
>
|
||||
Inhalt kommt bald...
|
||||
{t('pages.thcTest.comingSoon')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Container>
|
||||
|
||||
Reference in New Issue
Block a user