feat(i18n): migrate hardcoded German strings to t() across 104 components/pages — AST-based batch with re-parse gate, 423 new de.json keys; tsc clean; vitest failures byte-identical to clean-tree baseline (pre-existing)

This commit is contained in:
Agent Zero
2026-08-27 01:43:06 +02:00
parent 5680179260
commit 4cb5298768
105 changed files with 1204 additions and 459 deletions
@@ -1,6 +1,7 @@
import React from 'react';
import { Card } from '@/components/ui/Card';
import { Avatar } from '@/components/ui/Avatar';
import { useTranslation } from 'react-i18next';
export interface ActivityItem {
id: string;
@@ -17,11 +18,12 @@ export interface ActivityFeedProps {
}
export function ActivityFeed({ activities, title = 'Letzte Aktivitäten', maxItems = 10 }: ActivityFeedProps) {
const { t } = useTranslation();
const visible = activities.slice(0, maxItems);
return (
<Card title={title} data-testid="activity-feed">
{visible.length === 0 ? (
<p className="text-sm text-secondary-500 py-4 text-center">Keine Aktivitäten vorhanden.</p>
<p className="text-sm text-secondary-500 py-4 text-center">{t('activityFeed.keineaktivitätenvorhanden')}</p>
) : (
<ul className="space-y-3" role="list">
{visible.map((activity) => (
+1 -1
View File
@@ -112,7 +112,7 @@ export function DataGrid<T extends Record<string, any>>({
ref={scrollRef}
className="overflow-x-auto"
role="region"
aria-label="Data grid"
aria-label={t('dataGrid.datagrid')}
style={shouldVirtualize ? { maxHeight: '70vh', overflowY: 'auto' } : undefined}
>
<table className="min-w-full divide-y divide-secondary-200">
@@ -143,7 +143,7 @@ export function SearchDropdown({ placeholder }: SearchDropdownProps) {
onClick={handleSeeAll}
className="text-sm text-primary-600 hover:text-primary-700 font-medium min-h-touch"
>
Alle Ergebnisse anzeigen
{t('searchDropdown.alleergebnisseanzeigen')}
</button>
</div>
</>
+6 -4
View File
@@ -10,12 +10,14 @@ import React from 'react';
import { Users } from 'lucide-react';
import { useUsers, useGroups } from '@/api/hooks';
import { Avatar } from '@/components/ui/Avatar';
import { useTranslation } from 'react-i18next';
interface SharedTeamPanelProps {
onStartDirectChat?: (userId: string, userName: string) => void;
}
export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
const { t } = useTranslation();
const { data: usersData, isLoading: usersLoading } = useUsers();
const { data: groupsData, isLoading: groupsLoading } = useGroups();
const users: any[] = usersData?.items || [];
@@ -28,7 +30,7 @@ export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
{usersLoading ? (
<p className="text-sm text-secondary-400">Laden...</p>
) : users.length === 0 ? (
<p className="text-sm text-secondary-400">Keine Mitarbeiter</p>
<p className="text-sm text-secondary-400">{t('teamPanel.keinemitarbeiter')}</p>
) : (
<div className="space-y-1">
{users.map((u) =>
@@ -40,7 +42,7 @@ export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
>
<div className="relative flex-shrink-0">
<Avatar name={u.name} size="sm" />
<span className="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full border-2 border-white bg-secondary-300" aria-label="offline" />
<span className="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full border-2 border-white bg-secondary-300" aria-label={t('teamPanel.offline')} />
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-secondary-700 truncate">{u.name}</p>
@@ -52,7 +54,7 @@ export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
<div key={u.id} className="flex items-center gap-2 px-2 py-1.5 rounded-lg hover:bg-secondary-50 transition-colors">
<div className="relative flex-shrink-0">
<Avatar name={u.name} size="sm" />
<span className="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full border-2 border-white bg-secondary-300" aria-label="offline" />
<span className="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full border-2 border-white bg-secondary-300" aria-label={t('teamPanel.offline')} />
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-secondary-700 truncate">{u.name}</p>
@@ -70,7 +72,7 @@ export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
{groupsLoading ? (
<p className="text-sm text-secondary-400">Laden...</p>
) : groups.length === 0 ? (
<p className="text-sm text-secondary-400">Keine Gruppen</p>
<p className="text-sm text-secondary-400">{t('teamPanel.keinegruppen')}</p>
) : (
<div className="space-y-1">
{groups.map((g) => (