Englisch als zweite Sprache fuer die oeffentlichen Seiten
Hub und Bot-Produktseite lassen sich jetzt auf Englisch umstellen. Die Wahl haengt am Browser (Deutsch nur, wenn der Browser es will) und bleibt im localStorage stehen. - src/i18n.jsx: Context mit t(), tOr(), Datums- und Zahlenformat der Sprache. Keine Bibliothek, die Woerterbuecher werden mitgebaut — kein Nachlade-Blitzer. - Platzhalter im %s-Stil, dieselbe Schreibweise wie in den Bot-Texten. - Umschalter in der Navigation, zusaetzlich im Schubladen-Menue: .auth ist auf schmalen Schirmen ausgeblendet, sonst waere der Wechsel dort unerreichbar. - Datums- und Zahlenformat folgen mit (31.07.2026 / 31/07/2026, 45.231 / 45,231). - Die Funktionsliste kommt weiter deutsch vom Server; englische Modulnamen liegen unter feat.<id> im Woerterbuch. Fehlt einer, bleibt der Servertext stehen — ein neues Modul verschwindet nie von der Seite. Das Config-Panel und die Discord-Texte bleiben deutsch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,24 +3,26 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { apiGet } from '../api.js';
|
||||
import { useT } from '../i18n.jsx';
|
||||
import {
|
||||
IconDevlog, IconLevel, IconRoles, IconServer, IconSupport, IconGiveaway,
|
||||
IconBirthday, IconShield, IconMagic, IconKey, IconArrowRight, IconBot,
|
||||
} from '../icons.jsx';
|
||||
|
||||
const HIGHLIGHTS = [
|
||||
[IconDevlog, 'Devlogs & Feeds', 'Entwicklungs-Berichte landen als gebrandetes Embed im Discord und werden gleichzeitig durchsuchbar archiviert. Commits und Releases aus Gitea genauso.'],
|
||||
[IconServer, 'Server-Monitor', 'Über 300 Spiele per gamedig, dazu FiveM und einfache Erreichbarkeits-Checks. Ein Live-Embed pro Server, Alarm bei Ausfall, Spielerzahl in der Bot-Präsenz.'],
|
||||
[IconLevel, 'Level & Aktivität', 'XP fürs Mitreden mit Rollen-Belohnungen, öffentliche Bestenliste und Aktivitäts-Statistik des Servers.'],
|
||||
[IconRoles, 'Rollen-Menüs', 'Selbstbedienung per Knopfdruck — im Discord und im Browser. Farben pro Knopf, wahlweise exklusiv.'],
|
||||
[IconSupport, 'Support & Kontakt', 'Tickets als private Threads mit Gesprächsprotokoll, dazu Modmail: eine Direktnachricht an den Bot landet beim Team.'],
|
||||
[IconShield, 'Moderation', 'Verwarnungen mit Verlauf, Auszeiten, Aufräumen — alles im Mod-Log, dazu Protokoll für Beitritte, Namens- und Rollenwechsel.'],
|
||||
[IconGiveaway, 'Verlosungen', 'Teilnahme per Knopf, automatische Ziehung, Neuauslosung wenn sich niemand meldet.'],
|
||||
[IconBirthday, 'Geburtstage', 'Wer mag, trägt seinen Tag ein — der Bot gratuliert morgens und vergibt eine Rolle für den Tag.'],
|
||||
[IconMagic, 'Willkommens-Karten', 'Neue Mitglieder bekommen ein gerendertes Bild mit Avatar und Mitglieds-Nummer.'],
|
||||
[IconDevlog, 'bot.hl.devlogs'],
|
||||
[IconServer, 'bot.hl.monitor'],
|
||||
[IconLevel, 'bot.hl.level'],
|
||||
[IconRoles, 'bot.hl.roles'],
|
||||
[IconSupport, 'bot.hl.support'],
|
||||
[IconShield, 'bot.hl.mod'],
|
||||
[IconGiveaway, 'bot.hl.giveaway'],
|
||||
[IconBirthday, 'bot.hl.birthday'],
|
||||
[IconMagic, 'bot.hl.welcome'],
|
||||
];
|
||||
|
||||
export default function BotLanding() {
|
||||
const { t } = useT();
|
||||
const [status, setStatus] = useState(null);
|
||||
const [hub, setHub] = useState(null);
|
||||
const [featureCount, setFeatureCount] = useState(null);
|
||||
@@ -40,21 +42,17 @@ export default function BotLanding() {
|
||||
<div className="page-bg-text">BOT</div>
|
||||
<div className="page-header-grid" aria-hidden="true" />
|
||||
<div className="page-header-content">
|
||||
<div className="page-tag">// Selbst gebaut, keine Paywall</div>
|
||||
<div className="page-tag">{t('bot.tag')}</div>
|
||||
<h1 className="page-title">
|
||||
Ein Discord-Bot,<br />der alles macht
|
||||
{t('bot.title1')}<br />{t('bot.title2')}
|
||||
</h1>
|
||||
<p className="page-subtitle">
|
||||
Devlogs, Level, Moderation, Server-Monitoring, Verlosungen, Tickets —
|
||||
was sonst drei Bots mit Abo-Modell erledigen, läuft hier in einem,
|
||||
mit eigenem Webinterface.
|
||||
</p>
|
||||
<p className="page-subtitle">{t('bot.subtitle')}</p>
|
||||
<div className="home-cta">
|
||||
<Link className="btn btn-save with-icon" to="/features">
|
||||
Alle Funktionen <IconArrowRight size={15} />
|
||||
{t('bot.allFeatures')} <IconArrowRight size={15} />
|
||||
</Link>
|
||||
<Link className="btn btn-ghost with-icon" to="/commands">
|
||||
<IconBot /> Befehle ansehen
|
||||
<IconBot /> {t('bot.viewCommands')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,62 +63,56 @@ export default function BotLanding() {
|
||||
{featureCount && (
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">{featureCount}</span>
|
||||
<span className="srv-sum-label">Funktionen, einzeln schaltbar</span>
|
||||
<span className="srv-sum-label">{t('bot.statFeatures')}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">16</span>
|
||||
<span className="srv-sum-label">Slash-Befehle</span>
|
||||
<span className="srv-sum-label">{t('bot.statCommands')}</span>
|
||||
</div>
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">300<span className="srv-sum-of">+</span></span>
|
||||
<span className="srv-sum-label">Spiele im Monitor</span>
|
||||
<span className="srv-sum-label">{t('bot.statGames')}</span>
|
||||
</div>
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">0<span className="srv-sum-of"> €</span></span>
|
||||
<span className="srv-sum-label">Kosten, keine Premium-Stufen</span>
|
||||
<span className="srv-sum-label">{t('bot.statCost')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="settings-title" style={{ marginTop: '2.5rem' }}>// Was er kann</h2>
|
||||
<h2 className="settings-title" style={{ marginTop: '2.5rem' }}>{t('bot.whatItDoes')}</h2>
|
||||
<div className="home-tiles">
|
||||
{HIGHLIGHTS.map(([Icon, title, text]) => (
|
||||
<div className="card home-tile" key={title}>
|
||||
{HIGHLIGHTS.map(([Icon, key]) => (
|
||||
<div className="card home-tile" key={key}>
|
||||
<span className="home-tile-icon"><Icon size={24} /></span>
|
||||
<span className="home-tile-title">{title}</span>
|
||||
<span className="home-tile-desc">{text}</span>
|
||||
<span className="home-tile-title">{t(key)}</span>
|
||||
<span className="home-tile-desc">{t(`${key}.text`)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="roadmap-group" style={{ marginTop: '2.5rem' }}>
|
||||
<h2 className="settings-title">// Für Entwickler</h2>
|
||||
<h2 className="settings-title">{t('bot.forDevs')}</h2>
|
||||
<div className="home-tiles">
|
||||
<div className="card home-tile">
|
||||
<span className="home-tile-icon"><IconKey size={24} /></span>
|
||||
<span className="home-tile-title">API & Single Sign-On</span>
|
||||
<span className="home-tile-desc">
|
||||
Eigene Skripte posten über die API v1 mit Bearer-Schlüsseln und Bereichs-Rechten.
|
||||
Andere Dienste nutzen den Discord-Login des Bots mit und bekommen die Rollen
|
||||
gleich mitgeliefert.
|
||||
</span>
|
||||
<span className="home-tile-title">{t('bot.dev.api')}</span>
|
||||
<span className="home-tile-desc">{t('bot.dev.api.text')}</span>
|
||||
</div>
|
||||
<div className="card home-tile">
|
||||
<span className="home-tile-icon"><IconServer size={24} /></span>
|
||||
<span className="home-tile-title">Läuft überall</span>
|
||||
<span className="home-tile-desc">
|
||||
Node und SQLite in einem Container, ein Volume für die Daten.
|
||||
Nächtliche Sicherungen inklusive — von der Datenbank und allen Repositories.
|
||||
</span>
|
||||
<span className="home-tile-title">{t('bot.dev.host')}</span>
|
||||
<span className="home-tile-desc">{t('bot.dev.host.text')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hub && (
|
||||
<p className="notice" style={{ marginTop: '2rem' }}>
|
||||
Der Bot läuft für die D4RKST3R-Community
|
||||
{status?.members ? ` mit ${status.members} Mitgliedern` : ''} —
|
||||
{' '}<a href={hub} style={{ textDecoration: 'underline' }}>zum Community-Hub</a>.
|
||||
{status?.members
|
||||
? t('bot.runsForWith', status.members)
|
||||
: t('bot.runsFor')} —
|
||||
{' '}<a href={hub} style={{ textDecoration: 'underline' }}>{t('bot.toHub')}</a>.
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user