diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5758755..013f484 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -8,11 +8,9 @@ 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({ @@ -42,20 +40,18 @@ function QueryClientWrapper({ children }: { children: React.ReactNode }) { } function OfflineBanner() { - const { t } = useTranslation(); const isOnline = useOnlineStatus(); if (isOnline) return null; return (
Laden...
} {!isLoading && signals.length === 0 && ( -{t('improvementPanel.keinesignaleklickensieaufsammeln')}
+Keine Signale. Klicken Sie auf „Sammeln" um zu starten.
)} {signals.map(s => ( @@ -95,7 +92,6 @@ function SignalsView() { } function PatternsView() { - const { t } = useTranslation(); const { data, isLoading } = usePatterns(1, 20); const detectMut = useDetectPatterns(); const patterns = data?.items ?? []; @@ -108,7 +104,7 @@ function PatternsView() { onClick={() => detectMut.mutate({ min_occurrences: 2 })} disabled={detectMut.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={t('improvementPanel.mustererkennen')} + aria-label="Muster erkennen" > Erkennen @@ -117,7 +113,7 @@ function PatternsView() { {isLoading &&Laden...
} {!isLoading && patterns.length === 0 && ( -{t('improvementPanel.keinemustersammelnsiezuerstsignale')}
+Keine Muster. Sammeln Sie zuerst Signale und klicken Sie dann auf „Erkennen".
)} {patterns.map(p => ( @@ -147,7 +143,6 @@ function PatternsView() { } function ProposalsView() { - const { t } = useTranslation(); const { data, isLoading } = useProposals(1, 20); const evalMut = useEvaluateProposal(); const activateMut = useActivateProposal(); @@ -173,7 +168,7 @@ function ProposalsView() { {isLoading &&Laden...
} {!isLoading && proposals.length === 0 && ( -{t('improvementPanel.keinevorschläge')}
+Keine Vorschläge.
)} {proposals.map(p => ( @@ -196,7 +191,7 @@ function ProposalsView() { onClick={() => evalMut.mutate(p.id)} disabled={evalMut.isPending} className="inline-flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-blue-600 hover:bg-blue-50 disabled:opacity-50 min-h-touch" - aria-label={t('improvementPanel.evaluieren')} + aria-label="Evaluieren" > Evaluieren @@ -207,7 +202,7 @@ function ProposalsView() { onClick={() => activateMut.mutate(p.id)} disabled={activateMut.isPending} className="inline-flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-green-600 hover:bg-green-50 disabled:opacity-50 min-h-touch" - aria-label={t('improvementPanel.aktivieren')} + aria-label="Aktivieren" > Aktivieren @@ -219,7 +214,7 @@ function ProposalsView() { onClick={() => rollbackMut.mutate({ proposalId: p.id, reason: 'Manual rollback' })} disabled={rollbackMut.isPending} className="inline-flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-danger-600 hover:bg-danger-50 disabled:opacity-50 min-h-touch" - aria-label={t('improvementPanel.rollback')} + aria-label="Rollback" > Rollback @@ -228,7 +223,7 @@ function ProposalsView() { onClick={() => measureMut.mutate(p.id)} disabled={measureMut.isPending} className="inline-flex items-center gap-1 px-2 py-1 rounded text-[11px] font-medium text-purple-600 hover:bg-purple-50 disabled:opacity-50 min-h-touch" - aria-label={t('improvementPanel.impactmessen')} + aria-label="Impact messen" > Messen diff --git a/frontend/src/components/ai/SuggestionBadge.tsx b/frontend/src/components/ai/SuggestionBadge.tsx index 980027d..c5abe9a 100644 --- a/frontend/src/components/ai/SuggestionBadge.tsx +++ b/frontend/src/components/ai/SuggestionBadge.tsx @@ -1,13 +1,11 @@ import { useState, useEffect } from 'react'; import { apiClient } from '@/api/client'; -import { useTranslation } from 'react-i18next'; interface SuggestionBadgeProps { onClick: () => void; } export function SuggestionBadge({ onClick }: SuggestionBadgeProps) { - const { t } = useTranslation(); const [count, setCount] = useState(0); const [pulsing, setPulsing] = useState(false); @@ -33,7 +31,7 @@ export function SuggestionBadge({ onClick }: SuggestionBadgeProps) { diff --git a/frontend/src/components/ai/SuggestionCard.tsx b/frontend/src/components/ai/SuggestionCard.tsx index e8e2af1..97501b5 100644 --- a/frontend/src/components/ai/SuggestionCard.tsx +++ b/frontend/src/components/ai/SuggestionCard.tsx @@ -1,6 +1,5 @@ import { useState } from 'react'; import type { Suggestion } from '@/api/aiProactive'; -import { useTranslation } from 'react-i18next'; const typeConfig = { info: { icon: '💡', color: 'blue', bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-700', bar: 'bg-blue-500' }, @@ -16,7 +15,6 @@ interface SuggestionCardProps { } export function SuggestionCard({ suggestion, onDismiss, onAct }: SuggestionCardProps) { - const { t } = useTranslation(); const [expanded, setExpanded] = useState(false); const config = typeConfig[suggestion.suggestion_type] || typeConfig.info; const confidencePercent = Math.round(suggestion.confidence * 100); @@ -34,7 +32,7 @@ export function SuggestionCard({ suggestion, onDismiss, onAct }: SuggestionCardP @@ -88,7 +86,7 @@ export function SuggestionCard({ suggestion, onDismiss, onAct }: SuggestionCardP {/* Acted upon badge */} {suggestion.is_acted_upon && ({t('suggestionSidebar.keinevorschlägevorhanden')}
-{t('suggestionSidebar.diekianalysiertdeinenkontext')}
+Keine Vorschläge vorhanden
+Die KI analysiert deinen Kontext...
{contactName}
-{t('contactCardBlock.kontaktanzeigen')}
+Kontakt anzeigen
{t('miniAppBlock.keinekonfiguration')}
+Keine Konfiguration
)}- {t('saveFilterDialog.keineaktivenfilterkriterien')} + Keine aktiven Filterkriterien
); } @@ -86,7 +85,6 @@ export function SaveFilterDialog({ ); const handleSave = async () => { - const { t } = useTranslation(); const trimmed = name.trim(); if (!trimmed) return; setSubmitting(true); diff --git a/frontend/src/components/common/ShareDialog.tsx b/frontend/src/components/common/ShareDialog.tsx index c8e17ed..52269c5 100644 --- a/frontend/src/components/common/ShareDialog.tsx +++ b/frontend/src/components/common/ShareDialog.tsx @@ -25,7 +25,6 @@ import { import { useUsers } from '@/api/users'; import { useGroups } from '@/api/groups'; import type { EntityPermission, PermissionLevel } from '@/api/entityPermissions'; -import { useTranslation } from 'react-i18next'; interface ShareDialogProps { entityType: string; @@ -52,7 +51,6 @@ function permLabel(level: string) { } export function ShareDialog({ entityType, entityId, entityName, onClose }: ShareDialogProps) { - const { t } = useTranslation(); const { data: permData, isLoading } = useEntityPermissions(entityType, entityId); const { data: accessData } = useEntityAccess(entityType, entityId); const { data: usersData } = useUsers(1, 100); @@ -135,7 +133,7 @@ export function ShareDialog({ entityType, entityId, entityName, onClose }: Share @@ -145,9 +143,10 @@ export function ShareDialog({ entityType, entityId, entityName, onClose }: Share{t('shareDialog.elementteilen')}
+Element teilen
- {t('shareDialog.gewährebenutzernodergruppenzugriffauf')} + Gewähre Benutzern oder Gruppen Zugriff auf dieses Element. Die Berechtigungsstufe bestimmt, + welche Aktionen durchgeführt werden können.
- {selectedContactIds?.size || 0} {t('contactList.kontaktewirklichlöschen')} + {selectedContactIds?.size || 0} Kontakt(e) wirklich löschen?