fix(i18n): relative-time strings vollständig lokalisiert

relativeTime() in Dashboard, relTime() in WireGuard Clients+Servers und
CertExpiry() im Cluster-Page haben bisher hardcodiertes Deutsch
(„vor 5s", „abgelaufen vor X Tagen") gerendert, unabhängig von der
gewählten UI-Sprache.

Neu: gemeinsame i18n-Keys common.relTime.{Xs,Xm,Xh,Xd,never} in EN+DE,
sowie cluster.{certDaysRemaining,certExpiredDaysAgo}. Alle Helper-
Funktionen nehmen jetzt t() als Parameter und sind damit sprachunabhängig.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-24 12:02:27 +02:00
parent 3c95bc58d9
commit e18037375f
8 changed files with 52 additions and 31 deletions

View File

@@ -39,13 +39,13 @@ function fmtBytes(n: number): string {
while (v >= 1024 && i < u.length - 1) { v /= 1024; i++ }
return `${v.toFixed(1)} ${u[i]}`
}
function relTime(unix: number, never: string): string {
if (!unix) return never
function relTime(unix: number, t: (k: string, v?: Record<string, unknown>) => string): string {
if (!unix) return t('common.relTime.never')
const sec = Math.max(0, Math.floor(Date.now() / 1000) - unix)
if (sec < 60) return `${sec}s ago`
if (sec < 3600) return `${Math.floor(sec / 60)}m ago`
if (sec < 86400) return `${Math.floor(sec / 3600)}h ago`
return `${Math.floor(sec / 86400)}d ago`
if (sec < 60) return t('common.relTime.Xs', { n: sec })
if (sec < 3600) return t('common.relTime.Xm', { n: Math.floor(sec / 60) })
if (sec < 86400) return t('common.relTime.Xh', { n: Math.floor(sec / 3600) })
return t('common.relTime.Xd', { n: Math.floor(sec / 86400) })
}
interface ClientForm {
@@ -145,7 +145,7 @@ export default function ClientsTab() {
{live && (
<Tooltip title={`${fmtBytes(live.transfer_rx)}${fmtBytes(live.transfer_tx)}`}>
<Text type="secondary" style={{ fontSize: 11 }}>
{relTime(live.last_handshake_unix, t('wg.peer.never'))}
{relTime(live.last_handshake_unix, t)}
</Text>
</Tooltip>
)}

View File

@@ -79,13 +79,13 @@ function fmtBytes(n: number): string {
while (v >= 1024 && i < u.length - 1) { v /= 1024; i++ }
return `${v.toFixed(1)} ${u[i]}`
}
function relTime(unix: number, never: string): string {
if (!unix) return never
function relTime(unix: number, t: (k: string, v?: Record<string, unknown>) => string): string {
if (!unix) return t('common.relTime.never')
const sec = Math.max(0, Math.floor(Date.now() / 1000) - unix)
if (sec < 60) return `vor ${sec}s`
if (sec < 3600) return `vor ${Math.floor(sec / 60)}m`
if (sec < 86400) return `vor ${Math.floor(sec / 3600)}h`
return `vor ${Math.floor(sec / 86400)}d`
if (sec < 60) return t('common.relTime.Xs', { n: sec })
if (sec < 3600) return t('common.relTime.Xm', { n: Math.floor(sec / 60) })
if (sec < 86400) return t('common.relTime.Xh', { n: Math.floor(sec / 3600) })
return t('common.relTime.Xd', { n: Math.floor(sec / 86400) })
}
interface FwZoneLite { name: string; builtin: boolean }
@@ -405,7 +405,7 @@ function PeerDrawer({ iface, onClose }: PeerDrawerProps) {
inactiveLabel={t('wg.peer.offline')}
/>
<Text type="secondary" style={{ fontSize: 11 }}>
{live ? relTime(live.last_handshake_unix, t('wg.peer.never')) : t('wg.peer.never')}
{live ? relTime(live.last_handshake_unix, t) : t('common.relTime.never')}
</Text>
</Space>
)