fix(i18n): RemoteTargets S3/SFTP-Labels + NTP-Interface-Labels vollständig lokalisieren
RemoteTargets: alle 20+ hardkodierten Form-Labels und deutschen Hilfetexte
(S3: Endpoint/Region/Bucket/AccessKey/SecretKey/PathPrefix/HTTPS;
SFTP: Host/Port/Username/Password/PrivateKey/RemoteDir/HostKeyFp)
sind jetzt in t()-Aufrufen mit remotes.s3.*/remotes.sftp.*-Keys.
NTP: Listen-Address-Dropdown-Labels (alle IPv4/IPv6-Interfaces, Loopback)
verwenden jetzt dns.settings.allIPv4/allIPv6/loopback (identisch zu DNS-Settings).
NTP-Pool-Adresse-Placeholder → t('ntp.pool.addressPlaceholder').
en/de: alle neuen Keys ergänzt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,7 +60,7 @@ import (
|
|||||||
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.85"
|
var version = "1.1.86"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.85"
|
var version = "1.1.86"
|
||||||
|
|
||||||
const usage = `edgeguard-ctl — EdgeGuard CLI
|
const usage = `edgeguard-ctl — EdgeGuard CLI
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.85"
|
var version = "1.1.86"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// renewTickInterval — how often we re-evaluate expiring certs.
|
// renewTickInterval — how often we re-evaluate expiring certs.
|
||||||
|
|||||||
@@ -806,6 +806,7 @@
|
|||||||
"kindServer": "server — einzelner Host",
|
"kindServer": "server — einzelner Host",
|
||||||
"address": "Adresse / Host",
|
"address": "Adresse / Host",
|
||||||
"addressExtra": "FQDN (für pool: 0.de.pool.ntp.org) oder IP.",
|
"addressExtra": "FQDN (für pool: 0.de.pool.ntp.org) oder IP.",
|
||||||
|
"addressPlaceholder": "0.de.pool.ntp.org oder 10.0.0.10",
|
||||||
"iburst": "iburst",
|
"iburst": "iburst",
|
||||||
"prefer": "prefer",
|
"prefer": "prefer",
|
||||||
"minpoll": "min-poll",
|
"minpoll": "min-poll",
|
||||||
@@ -1090,6 +1091,34 @@
|
|||||||
"testFailed": "Test fehlgeschlagen",
|
"testFailed": "Test fehlgeschlagen",
|
||||||
"confirmDelete": "Ziel {{name}} wirklich löschen?",
|
"confirmDelete": "Ziel {{name}} wirklich löschen?",
|
||||||
"targetExtra": "Frei-Text-Label für die Übersicht. Setze hier den Bucket/Path-Hinweis (s3://my-bucket oder sftp://backup@host).",
|
"targetExtra": "Frei-Text-Label für die Übersicht. Setze hier den Bucket/Path-Hinweis (s3://my-bucket oder sftp://backup@host).",
|
||||||
|
"namePlaceholder": "z.B. MinIO offsite / Hetzner Storage Box",
|
||||||
|
"kindS3": "S3 (AWS / MinIO / R2 / B2 / Hetzner Object)",
|
||||||
|
"kindSftp": "SFTP (SSH)",
|
||||||
|
"s3": {
|
||||||
|
"endpoint": "Endpoint",
|
||||||
|
"endpointExtra": "s3.amazonaws.com / minio.example.com:9000 / fsn1.your-objectstorage.com",
|
||||||
|
"region": "Region",
|
||||||
|
"regionPlaceholder": "eu-central-1 / auto (R2)",
|
||||||
|
"bucket": "Bucket",
|
||||||
|
"accessKey": "Access Key",
|
||||||
|
"secretKey": "Secret Key",
|
||||||
|
"pathPrefix": "Path Prefix",
|
||||||
|
"pathPrefixExtra": "z.B. edgeguard/utm-1 — wird vor jedem Dateinamen gesetzt",
|
||||||
|
"useSsl": "HTTPS (use_ssl)"
|
||||||
|
},
|
||||||
|
"sftp": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port",
|
||||||
|
"username": "Benutzername",
|
||||||
|
"password": "Passwort",
|
||||||
|
"passwordExtra": "Entweder Passwort ODER Private Key.",
|
||||||
|
"privateKey": "Private Key (OpenSSH, base64)",
|
||||||
|
"privateKeyPlaceholder": "base64-kodierter OpenSSH Private Key",
|
||||||
|
"remoteDir": "Remote-Verzeichnis",
|
||||||
|
"remoteDirExtra": "z.B. /backups/edgeguard",
|
||||||
|
"hostKeyFp": "Host-Key-Fingerprint",
|
||||||
|
"hostKeyFpExtra": "Optional. SHA256:... — leer lassen für TOFU (unsicher gegen MitM)"
|
||||||
|
},
|
||||||
"col": {
|
"col": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"kind": "Typ",
|
"kind": "Typ",
|
||||||
|
|||||||
@@ -806,6 +806,7 @@
|
|||||||
"kindServer": "server — single host",
|
"kindServer": "server — single host",
|
||||||
"address": "Address / host",
|
"address": "Address / host",
|
||||||
"addressExtra": "FQDN (for pool: 0.de.pool.ntp.org) or IP.",
|
"addressExtra": "FQDN (for pool: 0.de.pool.ntp.org) or IP.",
|
||||||
|
"addressPlaceholder": "0.de.pool.ntp.org or 10.0.0.10",
|
||||||
"iburst": "iburst",
|
"iburst": "iburst",
|
||||||
"prefer": "prefer",
|
"prefer": "prefer",
|
||||||
"minpoll": "min-poll",
|
"minpoll": "min-poll",
|
||||||
@@ -1090,6 +1091,34 @@
|
|||||||
"testFailed": "Test failed",
|
"testFailed": "Test failed",
|
||||||
"confirmDelete": "Really delete target {{name}}?",
|
"confirmDelete": "Really delete target {{name}}?",
|
||||||
"targetExtra": "Free-text label for the overview. Use bucket/path hint (s3://my-bucket or sftp://backup@host).",
|
"targetExtra": "Free-text label for the overview. Use bucket/path hint (s3://my-bucket or sftp://backup@host).",
|
||||||
|
"namePlaceholder": "e.g. MinIO offsite / Hetzner Storage Box",
|
||||||
|
"kindS3": "S3 (AWS / MinIO / R2 / B2 / Hetzner Object)",
|
||||||
|
"kindSftp": "SFTP (SSH)",
|
||||||
|
"s3": {
|
||||||
|
"endpoint": "Endpoint",
|
||||||
|
"endpointExtra": "s3.amazonaws.com / minio.example.com:9000 / fsn1.your-objectstorage.com",
|
||||||
|
"region": "Region",
|
||||||
|
"regionPlaceholder": "eu-central-1 / auto (R2)",
|
||||||
|
"bucket": "Bucket",
|
||||||
|
"accessKey": "Access Key",
|
||||||
|
"secretKey": "Secret Key",
|
||||||
|
"pathPrefix": "Path Prefix",
|
||||||
|
"pathPrefixExtra": "e.g. edgeguard/utm-1 — prepended to every filename",
|
||||||
|
"useSsl": "HTTPS (use_ssl)"
|
||||||
|
},
|
||||||
|
"sftp": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
|
"passwordExtra": "Either password OR private key.",
|
||||||
|
"privateKey": "Private Key (OpenSSH, base64)",
|
||||||
|
"privateKeyPlaceholder": "base64-encoded OpenSSH private key",
|
||||||
|
"remoteDir": "Remote Dir",
|
||||||
|
"remoteDirExtra": "e.g. /backups/edgeguard",
|
||||||
|
"hostKeyFp": "Host Key Fingerprint",
|
||||||
|
"hostKeyFpExtra": "Optional. SHA256:... — leave empty for TOFU (insecure against MitM)"
|
||||||
|
},
|
||||||
"col": {
|
"col": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"kind": "Kind",
|
"kind": "Kind",
|
||||||
|
|||||||
@@ -250,12 +250,12 @@ export default function RemoteTargetsTab() {
|
|||||||
<Form form={form} layout="vertical"
|
<Form form={form} layout="vertical"
|
||||||
onFinish={(v) => edit ? update.mutate({ id: edit.id, v }) : create.mutate(v)}>
|
onFinish={(v) => edit ? update.mutate({ id: edit.id, v }) : create.mutate(v)}>
|
||||||
<Form.Item label={t('remotes.col.name')} name="name" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.col.name')} name="name" rules={[{ required: true }]}>
|
||||||
<Input placeholder="MinIO offsite / Hetzner Storage Box" />
|
<Input placeholder={t('remotes.namePlaceholder')} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t('remotes.col.kind')} name="kind" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.col.kind')} name="kind" rules={[{ required: true }]}>
|
||||||
<Select options={[
|
<Select options={[
|
||||||
{ value: 's3', label: 'S3 (AWS / MinIO / R2 / B2 / Hetzner Object)' },
|
{ value: 's3', label: t('remotes.kindS3') },
|
||||||
{ value: 'sftp', label: 'SFTP (SSH)' },
|
{ value: 'sftp', label: t('remotes.kindSftp') },
|
||||||
]} />
|
]} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t('remotes.col.target')} name="target_url" rules={[{ required: true }]}
|
<Form.Item label={t('remotes.col.target')} name="target_url" rules={[{ required: true }]}
|
||||||
@@ -265,27 +265,27 @@ export default function RemoteTargetsTab() {
|
|||||||
|
|
||||||
{kind === 's3' && (
|
{kind === 's3' && (
|
||||||
<>
|
<>
|
||||||
<Form.Item label="Endpoint" name="endpoint" rules={[{ required: true }]}
|
<Form.Item label={t('remotes.s3.endpoint')} name="endpoint" rules={[{ required: true }]}
|
||||||
extra="s3.amazonaws.com / minio.example.com:9000 / fsn1.your-objectstorage.com">
|
extra={t('remotes.s3.endpointExtra')}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Region" name="region">
|
<Form.Item label={t('remotes.s3.region')} name="region">
|
||||||
<Input placeholder="eu-central-1 / auto (R2)" />
|
<Input placeholder={t('remotes.s3.regionPlaceholder')} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Bucket" name="bucket" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.s3.bucket')} name="bucket" rules={[{ required: true }]}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Access Key" name="access_key" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.s3.accessKey')} name="access_key" rules={[{ required: true }]}>
|
||||||
<Input autoComplete="off" />
|
<Input autoComplete="off" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Secret Key" name="secret_key" rules={[{ required: !edit }]}>
|
<Form.Item label={t('remotes.s3.secretKey')} name="secret_key" rules={[{ required: !edit }]}>
|
||||||
<Input.Password autoComplete="new-password" />
|
<Input.Password autoComplete="new-password" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Path Prefix" name="path_prefix"
|
<Form.Item label={t('remotes.s3.pathPrefix')} name="path_prefix"
|
||||||
extra="z.B. edgeguard/utm-1 — wird vor jedem Filename gesetzt">
|
extra={t('remotes.s3.pathPrefixExtra')}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="HTTPS (use_ssl)" name="use_ssl" valuePropName="checked">
|
<Form.Item label={t('remotes.s3.useSsl')} name="use_ssl" valuePropName="checked">
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
@@ -293,29 +293,29 @@ export default function RemoteTargetsTab() {
|
|||||||
|
|
||||||
{kind === 'sftp' && (
|
{kind === 'sftp' && (
|
||||||
<>
|
<>
|
||||||
<Form.Item label="Host" name="host" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.sftp.host')} name="host" rules={[{ required: true }]}>
|
||||||
<Input placeholder="backup.example.com" />
|
<Input placeholder="backup.example.com" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Port" name="port" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.sftp.port')} name="port" rules={[{ required: true }]}>
|
||||||
<InputNumber min={1} max={65535} style={{ width: '100%' }} />
|
<InputNumber min={1} max={65535} style={{ width: '100%' }} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Username" name="username" rules={[{ required: true }]}>
|
<Form.Item label={t('remotes.sftp.username')} name="username" rules={[{ required: true }]}>
|
||||||
<Input autoComplete="off" />
|
<Input autoComplete="off" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Password" name="password"
|
<Form.Item label={t('remotes.sftp.password')} name="password"
|
||||||
extra="Entweder Password ODER Private-Key.">
|
extra={t('remotes.sftp.passwordExtra')}>
|
||||||
<Input.Password autoComplete="new-password" />
|
<Input.Password autoComplete="new-password" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Private Key (OpenSSH, base64)" name="private_key">
|
<Form.Item label={t('remotes.sftp.privateKey')} name="private_key">
|
||||||
<Input.TextArea rows={3} autoComplete="off"
|
<Input.TextArea rows={3} autoComplete="off"
|
||||||
placeholder="base64-encoded OpenSSH private key" />
|
placeholder={t('remotes.sftp.privateKeyPlaceholder')} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Remote Dir" name="remote_dir" rules={[{ required: true }]}
|
<Form.Item label={t('remotes.sftp.remoteDir')} name="remote_dir" rules={[{ required: true }]}
|
||||||
extra="z.B. /backups/edgeguard">
|
extra={t('remotes.sftp.remoteDirExtra')}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Host-Key-Fingerprint" name="host_key_fingerprint"
|
<Form.Item label={t('remotes.sftp.hostKeyFp')} name="host_key_fingerprint"
|
||||||
extra="optional, SHA256:... — wenn leer wird TOFU verwendet (unsicher gegen MitM)">
|
extra={t('remotes.sftp.hostKeyFpExtra')}>
|
||||||
<Input placeholder="SHA256:abc123..." />
|
<Input placeholder="SHA256:abc123..." />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ function PoolsTab() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t('ntp.pool.address')} name="address" rules={[{ required: true }]}
|
<Form.Item label={t('ntp.pool.address')} name="address" rules={[{ required: true }]}
|
||||||
extra={t('ntp.pool.addressExtra')}>
|
extra={t('ntp.pool.addressExtra')}>
|
||||||
<Input placeholder="0.de.pool.ntp.org oder 10.0.0.10" />
|
<Input placeholder={t('ntp.pool.addressPlaceholder')} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Space>
|
<Space>
|
||||||
<Form.Item label={t('ntp.pool.iburst')} name="iburst" valuePropName="checked">
|
<Form.Item label={t('ntp.pool.iburst')} name="iburst" valuePropName="checked">
|
||||||
@@ -341,10 +341,10 @@ function SettingsTab() {
|
|||||||
const [form] = Form.useForm<SettingsForm>()
|
const [form] = Form.useForm<SettingsForm>()
|
||||||
|
|
||||||
const ipOptions: { value: string; label: string }[] = [
|
const ipOptions: { value: string; label: string }[] = [
|
||||||
{ value: '0.0.0.0', label: '0.0.0.0 — alle IPv4-Interfaces' },
|
{ value: '0.0.0.0', label: `0.0.0.0 — ${t('dns.settings.allIPv4')}` },
|
||||||
{ value: '::', label: ':: — alle IPv6-Interfaces' },
|
{ value: '::', label: `:: — ${t('dns.settings.allIPv6')}` },
|
||||||
{ value: '127.0.0.1', label: '127.0.0.1 — Loopback IPv4' },
|
{ value: '127.0.0.1', label: `127.0.0.1 — ${t('dns.settings.loopback')} IPv4` },
|
||||||
{ value: '::1', label: '::1 — Loopback IPv6' },
|
{ value: '::1', label: `::1 — ${t('dns.settings.loopback')} IPv6` },
|
||||||
]
|
]
|
||||||
for (const i of sys ?? []) {
|
for (const i of sys ?? []) {
|
||||||
if (i.ifname === 'lo') continue
|
if (i.ifname === 'lo') continue
|
||||||
|
|||||||
Reference in New Issue
Block a user