Complete translation implementation for admin interface
- Fixed all hardcoded strings in admin components to use t() function - Updated BrandingPage.tsx to use translations for watermark settings - Updated EventsListPage.tsx to use translations for status labels - Added missing translation keys to both en.json and de.json - Fixed translations for: - System settings (general, storage, categories tabs) - Branding page (watermark settings, positions, opacity) - Email configuration and templates - Event list view (status labels, filters, actions) - Event detail view (all sections properly translated) - Added comprehensive German translations for all new keys - Ensured consistent translation usage across all admin pages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { api } from '../../config/api';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { categoriesService } from '../../services/categories.service';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface PhotoUploadProps {
|
||||
eventId: number;
|
||||
@@ -13,6 +14,7 @@ interface PhotoUploadProps {
|
||||
}
|
||||
|
||||
export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadComplete }) => {
|
||||
const { t } = useTranslation();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
@@ -79,7 +81,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
}
|
||||
|
||||
// Show success message
|
||||
toast.success(`Successfully uploaded ${selectedFiles.length} photo${selectedFiles.length > 1 ? 's' : ''}`);
|
||||
toast.success(t('toast.uploadSuccess'));
|
||||
|
||||
// Call callback
|
||||
if (onUploadComplete) {
|
||||
@@ -87,7 +89,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Upload error:', error);
|
||||
toast.error(error.response?.data?.error || 'Failed to upload photos');
|
||||
toast.error(error.response?.data?.error || t('toast.uploadError'));
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
setUploadProgress(0);
|
||||
@@ -105,17 +107,17 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
{/* Category Selection */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
Photo Category
|
||||
{t('upload.photoCategory')}
|
||||
</label>
|
||||
<select
|
||||
value={selectedCategoryId || ''}
|
||||
onChange={(e) => setSelectedCategoryId(e.target.value ? Number(e.target.value) : null)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-primary-500"
|
||||
>
|
||||
<option value="">No category</option>
|
||||
<option value="">{t('upload.noCategory')}</option>
|
||||
{categories.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name} {!category.is_global && '(Event specific)'}
|
||||
{category.name} {!category.is_global && t('upload.eventSpecific')}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -132,10 +134,10 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
>
|
||||
<Upload className="w-12 h-12 mx-auto text-neutral-400 mb-4" />
|
||||
<p className="text-neutral-700 font-medium mb-1">
|
||||
Click to upload or drag and drop
|
||||
{t('upload.clickToUpload')}
|
||||
</p>
|
||||
<p className="text-sm text-neutral-500">
|
||||
JPEG, PNG or WebP (max 50MB per file)
|
||||
{t('upload.fileRequirements')}
|
||||
</p>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
@@ -151,7 +153,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
{selectedFiles.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-neutral-700">
|
||||
Selected files ({selectedFiles.length})
|
||||
{t('upload.selectedFiles')} ({selectedFiles.length})
|
||||
</p>
|
||||
<div className="max-h-48 overflow-y-auto space-y-2">
|
||||
{selectedFiles.map((file, index) => (
|
||||
@@ -193,7 +195,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
disabled={selectedFiles.length === 0 || isUploading}
|
||||
leftIcon={isUploading ? <Loader2 className="w-4 h-4 animate-spin" /> : <Upload className="w-4 h-4" />}
|
||||
>
|
||||
{isUploading ? 'Uploading...' : `Upload ${selectedFiles.length} Photo${selectedFiles.length !== 1 ? 's' : ''}`}
|
||||
{isUploading ? t('upload.uploading') : t('common.upload') + ` ${selectedFiles.length} ${t(selectedFiles.length === 1 ? 'common.photo' : 'common.photos')}`}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -201,7 +203,7 @@ export const PhotoUpload: React.FC<PhotoUploadProps> = ({ eventId, onUploadCompl
|
||||
{isUploading && (
|
||||
<div className="mt-4">
|
||||
<div className="flex justify-between text-sm text-neutral-600 mb-1">
|
||||
<span>Uploading...</span>
|
||||
<span>{t('upload.uploading')}</span>
|
||||
<span>{uploadProgress}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-neutral-200 rounded-full h-2">
|
||||
|
||||
Reference in New Issue
Block a user