diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 013f484..5758755 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -8,9 +8,11 @@ import { useThemeStore } from '@/store/themeStore'; import { ErrorBoundary } from '@/components/common/ErrorBoundary'; import { useToast } from '@/components/ui/Toast'; import { useOnlineStatus } from '@/hooks/useOnlineStatus'; +import { useTranslation } from 'react-i18next'; function QueryClientWrapper({ children }: { children: React.ReactNode }) { + const { t } = useTranslation(); const toast = useToast(); const [queryClient] = React.useState(() => new QueryClient({ @@ -40,18 +42,20 @@ function QueryClientWrapper({ children }: { children: React.ReactNode }) { } function OfflineBanner() { + const { t } = useTranslation(); const isOnline = useOnlineStatus(); if (isOnline) return null; return (
- Sie sind offline. Änderungen werden gespeichert wenn die Verbindung wiederhergestellt ist. + {t('app.siesindofflineänderungenwerdengespeicher')}
); } export default function App() { + const { t } = useTranslation(); const { logout } = useAuthStore(); const loadThemeFromStorage = useThemeStore((s) => s.loadFromStorage); const toast = useToast(); @@ -76,7 +80,7 @@ export default function App() { href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:z-[300] focus:px-4 focus:py-2 focus:bg-primary-600 focus:text-white focus:rounded-md" > - Zum Hauptinhalt springen + {t('app.zumhauptinhaltspringen')} diff --git a/frontend/src/components/activity/ActivityFilter.tsx b/frontend/src/components/activity/ActivityFilter.tsx index e670683..32b1181 100644 --- a/frontend/src/components/activity/ActivityFilter.tsx +++ b/frontend/src/components/activity/ActivityFilter.tsx @@ -80,7 +80,7 @@ export function ActivityFilter({ onFilter, initialValues }: ActivityFilterProps) type="text" value={user} onChange={(e) => setUser(e.target.value)} - placeholder="Benutzername" + placeholder={t('activityFilter.benutzername')} className="block w-full rounded-md border border-secondary-300 px-3 py-2 text-base min-h-touch text-secondary-900 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500" /> diff --git a/frontend/src/components/ai/ImprovementPanel.tsx b/frontend/src/components/ai/ImprovementPanel.tsx index cca6328..07f4f87 100644 --- a/frontend/src/components/ai/ImprovementPanel.tsx +++ b/frontend/src/components/ai/ImprovementPanel.tsx @@ -6,10 +6,12 @@ import { useState } from 'react'; import { useSignals, useCollectSignals, usePatterns, useDetectPatterns, useProposals, useEvaluateProposal, useActivateProposal, useRollbackProposal, useMeasureImpact } from '@/api/improvement'; import { TrendingUp, AlertCircle, CheckCircle, RefreshCw, Play, RotateCcw, BarChart3 } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; type SubView = 'signals' | 'patterns' | 'proposals'; export function ImprovementPanel() { + const { t } = useTranslation(); const [subView, setSubView] = useState('signals'); return ( @@ -47,6 +49,7 @@ export function ImprovementPanel() { } function SignalsView() { + const { t } = useTranslation(); const { data, isLoading } = useSignals(1, 20); const collectMut = useCollectSignals(); const signals = data?.items ?? []; @@ -59,7 +62,7 @@ function SignalsView() { onClick={() => collectMut.mutate({ limit: 100 })} disabled={collectMut.isPending} className="inline-flex items-center gap-1 px-2 py-1 rounded text-xs font-medium text-primary-600 hover:bg-primary-50 disabled:opacity-50 min-h-touch" - aria-label="Signale sammeln" + aria-label={t('improvementPanel.signalesammeln')} >