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
+3 -1
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useRef } from 'react';
import clsx from 'clsx';
import { X } from 'lucide-react';
import { useTranslation } from 'react-i18next';
export interface ModalProps {
open: boolean;
@@ -32,6 +33,7 @@ export function Modal({
showCloseButton = true,
fullScreenMobile = false,
}: ModalProps) {
const { t } = useTranslation();
const dialogRef = useRef<HTMLDivElement>(null);
const previouslyFocused = useRef<HTMLElement | null>(null);
@@ -98,7 +100,7 @@ export function Modal({
<button
onClick={onClose}
className="absolute top-3 right-3 md:top-4 md:right-4 text-secondary-400 hover:text-secondary-600 min-h-touch min-w-touch flex items-center justify-center rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"
aria-label="Close dialog"
aria-label={t('modal.closedialog')}
>
<X className="h-5 w-5" aria-hidden="true" />
</button>
+1 -1
View File
@@ -31,7 +31,7 @@ export function Pagination({ currentPage, totalPages, total, pageSize, onPageCha
if (totalPages <= 1) return null;
return (
<nav className="flex items-center justify-between px-3 py-1.5 border-t border-secondary-200 bg-white" aria-label="Pagination">
<nav className="flex items-center justify-between px-3 py-1.5 border-t border-secondary-200 bg-white" aria-label={t('pagination.pagination')}>
<div className="text-xs text-secondary-500">
<span>{start}{end}</span> <span>{t('table.of')}</span> <span>{total}</span>
</div>
+5 -2
View File
@@ -1,5 +1,6 @@
import React from 'react';
import clsx from 'clsx';
import { useTranslation } from 'react-i18next';
export interface SkeletonProps {
className?: string;
@@ -9,6 +10,7 @@ export interface SkeletonProps {
}
export function Skeleton({ className, variant = 'rect', width, height }: SkeletonProps) {
const { t } = useTranslation();
const variantClass = {
text: 'rounded',
rect: 'rounded-md',
@@ -24,14 +26,15 @@ export function Skeleton({ className, variant = 'rect', width, height }: Skeleto
)}
style={{ width, height }}
role="status"
aria-label="Wird geladen"
aria-label={t('skeleton.wirdgeladen')}
/>
);
}
export function SkeletonText({ lines = 3, className }: { lines?: number; className?: string }) {
const { t } = useTranslation();
return (
<div className={clsx('space-y-2', className)} role="status" aria-label="Wird geladen">
<div className={clsx('space-y-2', className)} role="status" aria-label={t('skeleton.wirdgeladen')}>
{Array.from({ length: lines }).map((_, i) => (
<Skeleton
key={i}
+4 -2
View File
@@ -1,6 +1,7 @@
import React, { useState, useMemo } from 'react';
import clsx from 'clsx';
import { Loader2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
export interface TableColumn<T> {
key: string;
@@ -30,6 +31,7 @@ export function Table<T extends Record<string, any>>({
emptyMessage = 'Keine Daten vorhanden',
loading = false,
}: TableProps<T>) {
const { t } = useTranslation();
const [sortColumn, setSortColumn] = useState<string | null>(null);
const [sortDirection, setSortDirection] = useState<SortDirection>('asc');
@@ -59,7 +61,7 @@ export function Table<T extends Record<string, any>>({
};
return (
<div className="overflow-x-auto" role="region" aria-label="Data table">
<div className="overflow-x-auto" role="region" aria-label={t('table.datatable')}>
<table className="min-w-full divide-y divide-secondary-200">
<thead>
<tr>
@@ -102,7 +104,7 @@ export function Table<T extends Record<string, any>>({
<td colSpan={columns.length} className="px-6 py-8 text-center text-secondary-500">
<span className="inline-flex items-center gap-2">
<Loader2 className="animate-spin motion-reduce:animate-none h-5 w-5" aria-hidden="true" />
Wird geladen...
{t('table.wirdgeladen')}
</span>
</td>
</tr>
+3 -1
View File
@@ -2,6 +2,7 @@ import React, { useEffect, useCallback } from 'react';
import clsx from 'clsx';
import { Check, X, AlertTriangle, Info } from 'lucide-react';
import { useUIStore, Toast as ToastType } from '@/store/uiStore';
import { useTranslation } from 'react-i18next';
const toastStyles: Record<ToastType['type'], string> = {
success: 'bg-success-50 border-success-500 text-success-800',
@@ -18,6 +19,7 @@ const toastIcons: Record<ToastType['type'], React.ComponentType<{ className?: st
};
function ToastItem({ toast, onRemove }: { toast: ToastType; onRemove: (id: string) => void }) {
const { t } = useTranslation();
useEffect(() => {
const duration = toast.duration ?? 5000;
const timer = setTimeout(() => onRemove(toast.id), duration);
@@ -42,7 +44,7 @@ function ToastItem({ toast, onRemove }: { toast: ToastType; onRemove: (id: strin
<button
onClick={() => onRemove(toast.id)}
className="flex-shrink-0 text-current opacity-60 hover:opacity-100 min-h-touch min-w-touch flex items-center justify-center rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-current"
aria-label="Close notification"
aria-label={t('toast.closenotification')}
>
<X className="h-4 w-4" aria-hidden="true" />
</button>