1247 lines
72 KiB
TypeScript
1247 lines
72 KiB
TypeScript
import { z } from 'zod';
|
||
|
||
export * from './audit.js';
|
||
export * from './command-locales.js';
|
||
export * from './discord-localization.js';
|
||
export * from './phase2.js';
|
||
export * from './phase3.js';
|
||
export * from './phase4.js';
|
||
export * from './phase5.js';
|
||
export * from './phase6.js';
|
||
export * from './dashboard.js';
|
||
export * from './owner.js';
|
||
export * from './public.js';
|
||
export * from './premium.js';
|
||
export * from './components-v2.js';
|
||
|
||
export const LocaleSchema = z.enum(['de', 'en']);
|
||
export type Locale = z.infer<typeof LocaleSchema>;
|
||
|
||
export const GuildSettingsSchema = z.object({
|
||
guildId: z.string(),
|
||
locale: LocaleSchema.default('de'),
|
||
timezone: z.string().default('Europe/Berlin'),
|
||
moderationEnabled: z.boolean().default(true)
|
||
});
|
||
|
||
export const ModerationActionSchema = z.enum([
|
||
'BAN',
|
||
'UNBAN',
|
||
'KICK',
|
||
'TIMEOUT',
|
||
'UN_TIMEOUT',
|
||
'WARN_ADD',
|
||
'WARN_REMOVE',
|
||
'WARN_CLEAR',
|
||
'PURGE',
|
||
'LOCK',
|
||
'UNLOCK',
|
||
'SLOWMODE',
|
||
'NICK_SET',
|
||
'NICK_RESET',
|
||
'CASE_EDIT',
|
||
'CASE_DELETE',
|
||
'MODNOTE_ADD'
|
||
]);
|
||
|
||
export type ModerationAction = z.infer<typeof ModerationActionSchema>;
|
||
|
||
type Dictionary = Record<string, string>;
|
||
const de: Dictionary = {
|
||
'generic.noPermission': 'Du hast keine Berechtigung für diese Aktion.',
|
||
'generic.guildOnly': 'Dieser Command kann nur auf einem Server verwendet werden.',
|
||
'generic.botMissingPermission': 'Dem Bot fehlt die erforderliche Berechtigung ({permission}).',
|
||
'generic.invalidRegex': 'Ungültiges Regex-Muster.',
|
||
'generic.error': 'Es ist ein Fehler aufgetreten.',
|
||
'generic.maintenance': 'Nexumi ist derzeit im Wartungsmodus. Bitte versuche es später erneut.',
|
||
'generic.unknownCommand': 'Unbekannter Befehl.',
|
||
'generic.commandDisabled': 'Dieser Befehl ist auf diesem Server deaktiviert.',
|
||
'generic.commandChannelBlocked': 'Dieser Befehl ist in diesem Kanal nicht erlaubt.',
|
||
'generic.commandRoleBlocked': 'Du darfst diesen Befehl mit deinen Rollen nicht nutzen.',
|
||
'generic.commandCooldown': 'Bitte warte noch {seconds} Sekunden, bevor du diesen Befehl erneut nutzt.',
|
||
'generic.moduleDisabled': 'Dieses Modul ist auf diesem Server deaktiviert.',
|
||
'generic.userBlacklisted': 'Du darfst Nexumi derzeit nicht nutzen.',
|
||
'generic.guildBlacklisted': 'Dieser Server darf Nexumi derzeit nicht nutzen.',
|
||
'core.help.title': 'Nexumi Hilfe',
|
||
'core.help.subtitle': 'Commands nach Modul. Optional: `/help module:<name>`.',
|
||
'core.help.moduleLine': '**{module}**: {commands}',
|
||
'core.help.unknownModule': 'Unbekanntes Modul. Verfügbar: {modules}',
|
||
'core.help.footer': 'Mehr Infos: /info · Dashboard: {webui}',
|
||
'core.info.title': 'Nexumi',
|
||
'core.info.version': 'Version',
|
||
'core.info.uptime': 'Uptime',
|
||
'core.info.shard': 'Shard',
|
||
'core.info.guilds': 'Server (dieser Shard)',
|
||
'core.info.latency': 'API-Latenz',
|
||
'core.info.links': 'Links',
|
||
'core.info.link.dashboard': 'Dashboard',
|
||
'core.info.link.invite': 'Einladen',
|
||
'core.info.link.support': 'Support',
|
||
'core.info.link.status': 'Status',
|
||
'core.invite.title': 'Nexumi einladen',
|
||
'core.invite.body': 'Lade Nexumi mit diesem Link auf deinen Server ein:',
|
||
'core.support.title': 'Support',
|
||
'core.support.body': 'Tritt unserem Support-Server bei:',
|
||
'core.support.missing': 'Kein Support-Server konfiguriert. Bitte SUPPORT_SERVER_URL setzen.',
|
||
'core.module.core': 'Basis',
|
||
'core.module.moderation': 'Moderation',
|
||
'core.module.automod': 'Auto-Moderation',
|
||
'core.module.welcome': 'Willkommen',
|
||
'core.module.verification': 'Verifizierung',
|
||
'core.module.leveling': 'Leveling',
|
||
'core.module.economy': 'Economy',
|
||
'core.module.utility': 'Utility',
|
||
'core.module.fun': 'Fun',
|
||
'core.module.giveaways': 'Giveaways',
|
||
'core.module.tickets': 'Tickets',
|
||
'core.module.selfroles': 'Self-Roles',
|
||
'core.module.tags': 'Tags',
|
||
'core.module.starboard': 'Starboard',
|
||
'core.module.suggestions': 'Vorschläge',
|
||
'core.module.birthdays': 'Geburtstage',
|
||
'core.module.tempvoice': 'Temp-Voice',
|
||
'core.module.stats': 'Statistiken',
|
||
'core.module.feeds': 'Feeds',
|
||
'core.module.scheduler': 'Scheduler',
|
||
'core.module.guildbackup': 'Backup',
|
||
'gdpr.privacy.title': 'Datenschutz',
|
||
'gdpr.privacy.body':
|
||
'Nexumi speichert Discord-IDs und modulbezogene Daten (z. B. Verwarnungen, XP, Economy), soweit für den Betrieb nötig.',
|
||
'gdpr.privacy.link': 'Vollständige Datenschutzerklärung: {url}',
|
||
'gdpr.privacy.deleteHint': 'Persönliche Daten löschen: `/gdpr delete confirm:true`',
|
||
'gdpr.delete.needConfirm': 'Setze `confirm` auf `true`, um die Löschung zu bestätigen.',
|
||
'gdpr.delete.doneTitle': 'Daten gelöscht',
|
||
'gdpr.delete.doneBody':
|
||
'Gelöscht/anonymisiert: {warnings} Verwarnungen, {levels} Level-Einträge, {economy} Economy-Einträge, {cases} Cases anonymisiert.',
|
||
'moderation.success': 'Aktion erfolgreich ausgeführt.',
|
||
'moderation.success.case': 'Aktion erfolgreich ausgeführt (Fall #{caseNumber}).',
|
||
'moderation.duration.invalid': 'Ungültige Dauer. Nutze z. B. 30m, 12h oder 7d.',
|
||
'moderation.duration.invalidTimeout':
|
||
'Ungültige Timeout-Dauer. Nutze z. B. 30m oder 1d (max. 28 Tage).',
|
||
'moderation.hierarchy.self': 'Du kannst diese Aktion nicht auf dich selbst anwenden.',
|
||
'moderation.hierarchy.owner': 'Der Server-Owner kann nicht moderiert werden.',
|
||
'moderation.hierarchy.moderator':
|
||
'Du kannst keine Mitglieder moderieren, die gleich oder höher in der Rollenhierarchie stehen.',
|
||
'moderation.hierarchy.bot':
|
||
'Der Bot kann dieses Mitglied wegen der Rollenhierarchie oder fehlender Rechte nicht moderieren.',
|
||
'moderation.hierarchy.notMember': 'Dieses Mitglied ist nicht auf dem Server.',
|
||
'moderation.reason.none': 'Kein Grund angegeben',
|
||
'moderation.warning.created': 'Verwarnung erstellt: {warningId}',
|
||
'moderation.warning.none': 'Keine Verwarnungen vorhanden.',
|
||
'moderation.warning.defaultReason': 'Kein Grund',
|
||
'moderation.warning.notFound': 'Verwarnung nicht gefunden.',
|
||
'moderation.purge.done': '{deletedCount} Nachrichten gelöscht (Fall #{caseNumber}).',
|
||
'moderation.note.none': 'Keine Notizen vorhanden.',
|
||
'moderation.case.notFound': 'Fall nicht gefunden.',
|
||
'moderation.escalation.durationRequired':
|
||
'Für TIMEOUT-Eskalation ist eine Dauer erforderlich.',
|
||
'moderation.escalation.noneConfigured': 'Keine Eskalationsregeln konfiguriert.',
|
||
'moderation.escalation.saved':
|
||
'Eskalationsregel gespeichert: {warnCount} Verwarnungen => {action}{duration}.',
|
||
'moderation.escalation.removed':
|
||
'Eskalationsregel für {warnCount} Verwarnungen entfernt.',
|
||
'moderation.escalation.defaultReason': 'Auto-Eskalation bei {warnCount} Verwarnungen',
|
||
'moderation.escalation.skippedDuration':
|
||
'Eskalationsregel für {warnCount} Verwarnungen übersprungen (fehlende Dauer).',
|
||
'moderation.escalation.skippedPermission':
|
||
'Eskalationsregel für {warnCount} Verwarnungen übersprungen (fehlende Bot-Rechte).',
|
||
'moderation.escalation.appliedTimeout': 'Auto-Eskalation angewendet: Timeout ({durationMs} ms).',
|
||
'moderation.escalation.appliedKick': 'Auto-Eskalation angewendet: Kick.',
|
||
'moderation.escalation.appliedBan': 'Auto-Eskalation angewendet: Ban.',
|
||
'moderation.confirm.button.confirm': 'Bestätigen',
|
||
'moderation.confirm.button.cancel': 'Abbrechen',
|
||
'moderation.confirm.permanent': 'dauerhaft',
|
||
'moderation.confirm.ban':
|
||
'Ban bestätigen für <@{userId}>?\nGrund: {reason}\nDauer: {duration}',
|
||
'moderation.confirm.purge': '{amount} Nachrichten löschen? Diese Aktion kann nicht rückgängig gemacht werden.',
|
||
'moderation.confirm.caseDelete': 'Fall #{caseNumber} wirklich löschen?',
|
||
'moderation.confirm.expired': 'Bestätigung abgelaufen. Bitte den Befehl erneut ausführen.',
|
||
'moderation.confirm.cancelled': 'Aktion abgebrochen.',
|
||
'moderation.confirm.unauthorized': 'Nur der ausführende Moderator kann diese Bestätigung nutzen.',
|
||
'automod.status.header':
|
||
'**AutoMod enabled:** {enabled}\n**Anti-raid:** {antiRaid}\n**Anti-nuke:** {antiNuke}\n**Lockdown:** {lockdown}',
|
||
'automod.status.ruleLine': '- {type} → {action}',
|
||
'automod.status.noRules': 'Keine aktiven Regeln.',
|
||
'automod.status.yes': 'ja',
|
||
'automod.status.no': 'nein',
|
||
'welcome.notConfigured': 'Willkommensnachricht ist noch nicht konfiguriert.',
|
||
'welcome.invalidChannel': 'Der konfigurierte Willkommenskanal ist ungültig.',
|
||
'welcome.testSent': 'Test-Willkommensnachricht gesendet.',
|
||
'verification.disabled': 'Verifizierung ist deaktiviert.',
|
||
'verification.success': 'Du wurdest erfolgreich verifiziert.',
|
||
'verification.setupDone': 'Verifizierung konfiguriert.',
|
||
'verification.notConfigured': 'Verifizierung ist noch nicht eingerichtet. Nutze `/verify setup`.',
|
||
'verification.invalidChannel': 'Der Verifizierungskanal ist ungültig.',
|
||
'verification.panelPosted': 'Verifizierungs-Panel gepostet.',
|
||
'verification.panelMissingPermission':
|
||
'Dem Bot fehlen Rechte in diesem Kanal (Kanal sehen, Nachrichten senden, Embeds).',
|
||
'verification.panel.title': 'Verifizierung',
|
||
'verification.panel.description':
|
||
'Klicke auf den Button unten, um dich zu verifizieren und Zugang zum Server zu erhalten.',
|
||
'verification.panel.button': 'Verifizieren',
|
||
'verification.panel.buttonCaptcha': 'Verifizieren (Captcha)',
|
||
'verification.captchaLink': 'Öffne diesen Link zur Captcha-Verifizierung: {url}',
|
||
'verification.error.not_configured': 'Verifizierung ist nicht konfiguriert.',
|
||
'verification.error.member_not_found': 'Mitglied nicht gefunden.',
|
||
'verification.error.account_too_young': 'Dein Account ist zu jung für die Verifizierung.',
|
||
'verification.error.missing_permissions': 'Dem Bot fehlen Berechtigungen.',
|
||
'verification.error.invalid_role': 'Die Verifizierungsrolle ist ungültig.',
|
||
'verification.error.alt_detected':
|
||
'Verifizierung abgelehnt: möglicher Zweitaccount erkannt.',
|
||
'verification.error.generic': 'Verifizierung fehlgeschlagen.',
|
||
'verification.captcha.success': 'Captcha bestanden. Du wurdest verifiziert.',
|
||
'verification.captcha.invalid': 'Captcha ungültig oder abgelaufen.',
|
||
'verification.captcha.title': 'Nexumi Verifizierung',
|
||
'leveling.disabled': 'Leveling ist auf diesem Server deaktiviert.',
|
||
'leveling.rank.title': 'Rangkarte',
|
||
'leveling.leaderboard.title': 'Leaderboard',
|
||
'leveling.leaderboard.empty': 'Noch keine XP-Daten vorhanden.',
|
||
'leveling.leaderboard.entry': '{rank}. {user} — Level {level} ({xp} XP)',
|
||
'leveling.leaderboard.footer': 'Top {count} Mitglieder',
|
||
'leveling.levelUp.default': 'Glückwunsch {user}, du hast Level {level} erreicht!',
|
||
'leveling.xp.give.success': '{amount} XP an {user} vergeben. Neues Level: {level}.',
|
||
'leveling.xp.remove.success': '{amount} XP von {user} entfernt. Neues Level: {level}.',
|
||
'leveling.xp.reset.success': 'XP von {user} zurückgesetzt.',
|
||
'leveling.xp.invalidAmount': 'Der Betrag muss größer als 0 sein.',
|
||
'leveling.user.notFound': 'Nutzer nicht auf diesem Server gefunden.',
|
||
'economy.error.disabled': 'Das Economy-Modul ist auf diesem Server deaktiviert.',
|
||
'economy.error.insufficient': 'Du hast nicht genug Geld.',
|
||
'economy.error.cooldown': 'Cooldown aktiv. Versuche es in {seconds} Sekunden erneut.',
|
||
'economy.error.invalid_amount': 'Ungültiger Betrag.',
|
||
'economy.error.self_transfer': 'Du kannst dir nicht selbst Geld senden.',
|
||
'economy.error.not_found': 'Eintrag nicht gefunden.',
|
||
'economy.error.out_of_stock': 'Dieser Artikel ist ausverkauft.',
|
||
'economy.error.role_assign_failed': 'Kauf erfolgreich, aber die Rolle konnte nicht vergeben werden.',
|
||
'economy.error.game_in_progress': 'Du hast bereits ein laufendes Blackjack-Spiel.',
|
||
'economy.balance.result': 'Kontostand von {user}: {amount}',
|
||
'economy.daily.success': 'Tägliche Belohnung: {amount}. Neuer Kontostand: {balance}',
|
||
'economy.weekly.success': 'Wöchentliche Belohnung: {amount}. Neuer Kontostand: {balance}',
|
||
'economy.work.success': 'Du hast {amount} verdient. Neuer Kontostand: {balance}',
|
||
'economy.pay.success': 'Du hast {amount} an {user} gesendet. Dein Kontostand: {balance}',
|
||
'economy.gamble.win': 'Gewonnen! +{amount}. Kontostand: {balance}',
|
||
'economy.gamble.lose': 'Verloren! -{amount}. Kontostand: {balance}',
|
||
'economy.slots.win': '{reels}\nGewinn: {payout}. Kontostand: {balance}',
|
||
'economy.slots.lose': '{reels}\nKein Gewinn. Kontostand: {balance}',
|
||
'economy.coinflip.win': '{result} – du hattest {choice} gewählt. Gewonnen! +{amount}. Kontostand: {balance}',
|
||
'economy.coinflip.lose': '{result} – du hattest {choice} gewählt. Verloren! -{amount}. Kontostand: {balance}',
|
||
'economy.choice.heads': 'Kopf',
|
||
'economy.choice.tails': 'Zahl',
|
||
'economy.shop.empty': 'Der Shop ist leer.',
|
||
'economy.shop.noDescription': 'Keine Beschreibung',
|
||
'economy.shop.itemLine': '**{name}** (`{id}`) – {price} | Bestand: {stock}\n{description}',
|
||
'economy.shop.purchased': 'Du hast **{name}** gekauft. Kontostand: {balance}',
|
||
'economy.inventory.empty': 'Dein Inventar ist leer.',
|
||
'economy.inventory.itemLine': '- {name} × {quantity}',
|
||
'economy.leaderboard.empty': 'Noch keine Einträge auf der Bestenliste.',
|
||
'economy.leaderboard.line': '{rank}. {user} – {amount}',
|
||
'economy.admin.give': '{amount} an {user} vergeben. Neuer Kontostand: {balance}',
|
||
'economy.admin.remove': '{amount} von {user} entfernt. Neuer Kontostand: {balance}',
|
||
'economy.admin.reset': 'Economy-Daten von {user} zurückgesetzt.',
|
||
'economy.blackjack.title': 'Blackjack',
|
||
'economy.blackjack.hand': 'Einsatz: {bet}\n\n**Du:** {playerHand} ({playerTotal})\n**Dealer:** {dealerHand} ({dealerTotal})',
|
||
'economy.blackjack.button.hit': 'Hit',
|
||
'economy.blackjack.button.stand': 'Stand',
|
||
'economy.blackjack.outcome.win': 'Du gewinnst {bet}!',
|
||
'economy.blackjack.outcome.lose': 'Du verlierst deinen Einsatz.',
|
||
'economy.blackjack.outcome.push': 'Unentschieden – Einsatz zurück.',
|
||
'economy.blackjack.outcome.blackjack': 'Blackjack! Du gewinnst {bet}!',
|
||
'economy.blackjack.expired': 'Dieses Blackjack-Spiel ist abgelaufen oder existiert nicht mehr.',
|
||
'economy.blackjack.notOwner': 'Nur der Spieler kann diese Buttons nutzen.',
|
||
'utility.error.invalid_when': 'Ungültiger Zeitpunkt. Nutze z. B. 30m oder ein ISO-Datum in der Zukunft.',
|
||
'utility.error.invalid_datetime': 'Ungültiges Datum/Uhrzeit.',
|
||
'utility.error.invalid_poll_options': 'Es werden 2–5 Optionen benötigt (kommagetrennt).',
|
||
'utility.error.channel_not_found': 'Kanal nicht gefunden.',
|
||
'utility.error.role_not_found': 'Rolle nicht gefunden.',
|
||
'utility.error.poll_not_found': 'Umfrage nicht gefunden.',
|
||
'utility.error.reminder_channel_unavailable': 'Erinnerungskanal nicht erreichbar.',
|
||
'utility.poll.created': 'Umfrage erstellt.',
|
||
'utility.poll.closed': 'Diese Umfrage ist geschlossen.',
|
||
'utility.poll.notFound': 'Umfrage nicht gefunden.',
|
||
'utility.poll.invalidOption': 'Ungültige Option.',
|
||
'utility.poll.alreadyVoted': 'Du hast bereits abgestimmt.',
|
||
'utility.poll.voted': 'Stimme für **{option}** gezählt.',
|
||
'utility.poll.votes': 'Stimmen',
|
||
'utility.poll.endsAt': 'Endet {time}',
|
||
'utility.poll.multiSelect': 'Mehrfachauswahl',
|
||
'utility.poll.multiSelectHint': 'Du kannst mehrere Optionen wählen.',
|
||
'utility.remindme.created': 'Erinnerung erstellt (ID: `{id}`).',
|
||
'utility.reminders.none': 'Keine Erinnerungen.',
|
||
'utility.reminders.line': '`{id}` — {time}: {content}',
|
||
'utility.reminders.deleted': 'Erinnerung gelöscht.',
|
||
'utility.reminders.notFound': 'Erinnerung nicht gefunden.',
|
||
'utility.afk.set': 'AFK gesetzt. Grund: {reason}',
|
||
'utility.afk.welcomeBack': 'Willkommen zurück! Du warst AFK: {reason}',
|
||
'utility.afk.mention': '{user} ist AFK: {reason}',
|
||
'utility.avatar.title': 'Avatar von {user}',
|
||
'utility.banner.title': 'Banner von {user}',
|
||
'utility.banner.none': 'Kein Banner gesetzt.',
|
||
'utility.emoji.noSource': 'Anhang oder URL erforderlich.',
|
||
'utility.emoji.added': 'Emoji {emoji} hinzugefügt.',
|
||
'utility.emoji.removed': 'Emoji entfernt.',
|
||
'utility.emoji.notFound': 'Emoji nicht gefunden.',
|
||
'utility.emoji.messageNotFound': 'Nachricht nicht gefunden.',
|
||
'utility.emoji.noEmojiInMessage': 'Kein Custom-Emoji in der Nachricht.',
|
||
'utility.emoji.stolen': 'Emoji {emoji} gestohlen.',
|
||
'utility.sticker.noSource': 'Anhang oder URL erforderlich.',
|
||
'utility.sticker.added': 'Sticker **{name}** hinzugefügt.',
|
||
'utility.embed.sent': 'Embed gesendet.',
|
||
'utility.embed.invalidColor': 'Ungültige Farbe. Nutze z. B. 6366F1.',
|
||
'utility.snipe.none': 'Nichts zum Anzeigen.',
|
||
'utility.snipe.disabled': 'Snipe ist auf diesem Server deaktiviert (Datenschutz).',
|
||
'utility.snipe.privacy':
|
||
'Datenschutz: Snipe speichert gelöschte/bearbeitete Nachrichten kurzzeitig (1 h) in Redis.',
|
||
'utility.snipe.deletedAt': 'Gelöschte Nachricht von {user}',
|
||
'utility.snipe.editedAt': 'Bearbeitete Nachricht von {user}',
|
||
'utility.translate.noContent': 'Kein übersetzbare Textinhalt.',
|
||
'utility.translate.failed': 'Übersetzung fehlgeschlagen.',
|
||
'utility.translate.result': '**Übersetzung:** {text}',
|
||
'fun.8ball.result': '**Frage:** {question}\n**Antwort:** {answer}',
|
||
'fun.dice.result': 'Würfel ({sides} Seiten): {rolls}',
|
||
'fun.flip.result': 'Die Münze zeigt: **{result}**',
|
||
'fun.rps.win': 'Du wähltest **{player}**, ich **{bot}**. Du gewinnst!',
|
||
'fun.rps.lose': 'Du wähltest **{player}**, ich **{bot}**. Du verlierst!',
|
||
'fun.rps.draw': 'Beide wählten **{player}**. Unentschieden!',
|
||
'fun.rps.choice.rock': 'Stein',
|
||
'fun.rps.choice.paper': 'Papier',
|
||
'fun.rps.choice.scissors': 'Schere',
|
||
'fun.choose.result': 'Ich wähle: **{choice}**',
|
||
'fun.choose.tooFew': 'Gib mindestens zwei Optionen an (kommagetrennt).',
|
||
'fun.trivia.title': 'Trivia',
|
||
'fun.trivia.question': '**{question}**\n\n{options}',
|
||
'fun.trivia.footer': 'Nur {user} kann antworten.',
|
||
'fun.trivia.correct': '✅ Richtig!',
|
||
'fun.trivia.incorrect': '❌ Falsch!',
|
||
'fun.trivia.notOwner': 'Nur der Initiator kann diese Frage beantworten.',
|
||
'fun.tictactoe.title': 'Tic-Tac-Toe',
|
||
'fun.tictactoe.board': '❌: {x} | ⭕: {o}\n\n{board}',
|
||
'fun.tictactoe.challenge': '{challenger} fordert {opponent} zu Tic-Tac-Toe heraus!',
|
||
'fun.tictactoe.turn': 'Am Zug: {user}',
|
||
'fun.tictactoe.won': '{user} gewinnt!',
|
||
'fun.tictactoe.draw': 'Unentschieden!',
|
||
'fun.tictactoe.invalidMove': 'Ungültiger Zug.',
|
||
'fun.connect4.title': 'Connect 4',
|
||
'fun.connect4.board': '🔴: {red} | 🟡: {yellow}\n\n{board}',
|
||
'fun.connect4.challenge': '{challenger} fordert {opponent} zu Connect 4 heraus!',
|
||
'fun.connect4.turn': 'Am Zug: {user}',
|
||
'fun.connect4.won': '{user} gewinnt!',
|
||
'fun.connect4.draw': 'Unentschieden!',
|
||
'fun.connect4.invalidMove': 'Diese Spalte ist voll.',
|
||
'fun.hangman.title': 'Hangman',
|
||
'fun.hangman.progress': 'Wort: {word}\nFehler: {wrong}/{max}\nGeraten: {guessed}',
|
||
'fun.hangman.won': 'Gewonnen! Das Wort war **{word}**.',
|
||
'fun.hangman.lost': 'Verloren! Das Wort war **{word}**.',
|
||
'fun.common.notParticipant': 'Du bist nicht an diesem Spiel beteiligt.',
|
||
'fun.common.expired': 'Dieses Spiel ist abgelaufen oder existiert nicht mehr.',
|
||
'fun.common.selfChallenge': 'Du kannst dich nicht selbst herausfordern.',
|
||
'fun.common.botChallenge': 'Du kannst keinen Bot herausfordern.',
|
||
'fun.media.disabled': 'Medien-Commands sind auf diesem Server deaktiviert.',
|
||
'fun.media.fetchFailed': 'Bild konnte nicht geladen werden. Versuche es später erneut.',
|
||
'fun.cat.title': 'Random Cat',
|
||
'fun.dog.title': 'Random Dog',
|
||
'starboard.notConfigured': 'Starboard ist noch nicht konfiguriert. Nutze `/starboard setup`.',
|
||
'starboard.invalidChannel':
|
||
'Der Starboard-Kanal ist ungültig oder dem Bot fehlen Rechte (Ansehen, Senden, Embeds).',
|
||
'starboard.setupDone': 'Starboard konfiguriert und aktiviert.',
|
||
'starboard.noContent': '*Kein Textinhalt*',
|
||
'starboard.field.stars': 'Sterne',
|
||
'starboard.field.source': 'Quelle',
|
||
'starboard.jumpLink': 'Zur Nachricht',
|
||
'starboard.statusLine':
|
||
'Starboard aktiv → Kanal {channel}, Emoji {emoji}, Schwelle {threshold}, Self-Star: {selfStar}',
|
||
'starboard.selfStarOn': 'erlaubt',
|
||
'starboard.selfStarOff': 'verboten',
|
||
'suggestion.created': 'Vorschlag eingereicht (ID: `{id}`).',
|
||
'suggestion.setupDone': 'Vorschlagssystem konfiguriert.',
|
||
'suggestion.staffUpdated': 'Vorschlag aktualisiert ({status}).',
|
||
'suggestion.votedUp': 'Upvote gezählt.',
|
||
'suggestion.votedDown': 'Downvote gezählt.',
|
||
'suggestion.threadName': 'Diskussion #{id}',
|
||
'suggestion.error.not_configured': 'Vorschläge sind nicht konfiguriert. Nutze `/suggestion setup`.',
|
||
'suggestion.error.invalid_channel': 'Der konfigurierte Kanal ist ungültig.',
|
||
'suggestion.error.not_found': 'Vorschlag nicht gefunden.',
|
||
'suggestion.error.not_open': 'Dieser Vorschlag ist nicht mehr offen.',
|
||
'suggestion.error.already_voted': 'Du hast bereits so abgestimmt.',
|
||
'suggestion.embed.title': 'Vorschlag #{id}',
|
||
'suggestion.embed.status': 'Status',
|
||
'suggestion.embed.votes': 'Stimmen',
|
||
'suggestion.embed.author': 'Von {author}',
|
||
'suggestion.embed.staffReason': 'Team-Begründung',
|
||
'suggestion.status.open': 'Offen',
|
||
'suggestion.status.approved': 'Angenommen',
|
||
'suggestion.status.denied': 'Abgelehnt',
|
||
'suggestion.status.considered': 'In Prüfung',
|
||
'suggestion.status.implemented': 'Umgesetzt',
|
||
'suggestion.dm.statusUpdate': 'Dein Vorschlag wurde aktualisiert: **{status}**\nBegründung: {reason}',
|
||
'giveaway.embed.title': 'Giveaway',
|
||
'giveaway.embed.prize': 'Preis',
|
||
'giveaway.embed.winners': 'Gewinner',
|
||
'giveaway.embed.entrants': 'Teilnehmer',
|
||
'giveaway.embed.host': 'Host',
|
||
'giveaway.embed.requirements': 'Anforderungen',
|
||
'giveaway.embed.active': 'Klicke auf **Join**, um teilzunehmen!',
|
||
'giveaway.embed.paused': '⏸️ Dieses Giveaway ist pausiert.',
|
||
'giveaway.embed.ended': 'Beendet',
|
||
'giveaway.embed.endedWinners': 'Gewinner: {winners}',
|
||
'giveaway.embed.endedNoWinners': 'Keine gültigen Teilnehmer.',
|
||
'giveaway.embed.endsAt': 'Endet {time}',
|
||
'giveaway.button.join': 'Teilnehmen',
|
||
'giveaway.requirement.role': 'Rolle: {role}',
|
||
'giveaway.requirement.level': 'Mindest-Level: {level}',
|
||
'giveaway.requirement.memberDays': 'Server-Mitglied seit mindestens {days} Tagen',
|
||
'giveaway.started': 'Giveaway gestartet (ID: `{id}`).',
|
||
'giveaway.ended': 'Giveaway beendet.',
|
||
'giveaway.rerolled': 'Neue Gewinner: {winners}',
|
||
'giveaway.deleted': 'Giveaway gelöscht.',
|
||
'giveaway.paused': 'Giveaway pausiert.',
|
||
'giveaway.resumed': 'Giveaway fortgesetzt.',
|
||
'giveaway.joined': 'Du nimmst am Giveaway teil!',
|
||
'giveaway.list.header': '**Aktive Giveaways**',
|
||
'giveaway.list.empty': 'Keine aktiven Giveaways.',
|
||
'giveaway.list.entrants': 'Teilnehmer',
|
||
'giveaway.dm.won': 'Glückwunsch! Du hast **{prize}** auf **{guild}** gewonnen!',
|
||
'giveaway.error.not_found': 'Giveaway nicht gefunden oder bereits beendet.',
|
||
'giveaway.error.already_ended': 'Dieses Giveaway ist bereits beendet.',
|
||
'giveaway.error.not_ended': 'Giveaway ist noch nicht beendet.',
|
||
'giveaway.error.paused': 'Dieses Giveaway ist pausiert.',
|
||
'giveaway.error.already_joined': 'Du nimmst bereits teil.',
|
||
'giveaway.error.member_not_found': 'Mitglied nicht gefunden.',
|
||
'giveaway.error.missing_role': 'Dir fehlt die erforderliche Rolle.',
|
||
'giveaway.error.insufficient_level': 'Dein Level ist zu niedrig.',
|
||
'giveaway.error.insufficient_member_days': 'Du bist noch nicht lange genug auf dem Server.',
|
||
'giveaway.error.invalid_duration': 'Ungültige Dauer. Nutze z. B. 1h, 2d.',
|
||
'giveaway.error.duration_too_short': 'Die Dauer muss mindestens 1 Minute betragen.',
|
||
'giveaway.error.invalid_channel': 'Ungültiger Kanal.',
|
||
'ticket.panel.defaultDescription': 'Wähle eine Kategorie, um ein Ticket zu öffnen.',
|
||
'ticket.panel.created': 'Ticket-Panel erstellt.',
|
||
'ticket.category.created': 'Kategorie **{name}** erstellt.',
|
||
'ticket.created': 'Dein Ticket wurde erstellt: {channel}',
|
||
'ticket.opened': '{user} hat ein Ticket geöffnet.',
|
||
'ticket.subjectLine': 'Betreff: {subject}',
|
||
'ticket.claimed': '{user} hat dieses Ticket übernommen.',
|
||
'ticket.userAdded': '{user} wurde zum Ticket hinzugefügt.',
|
||
'ticket.userRemoved': '{user} wurde aus dem Ticket entfernt.',
|
||
'ticket.renamed': 'Ticket umbenannt in **{name}**.',
|
||
'ticket.prioritySet': 'Priorität gesetzt: **{priority}**',
|
||
'ticket.closed': 'Ticket geschlossen von {user}.',
|
||
'ticket.closedWithReason': 'Ticket geschlossen von {user}.\nGrund: {reason}',
|
||
'ticket.close.success': 'Ticket geschlossen.',
|
||
'ticket.claim.success': 'Ticket übernommen.',
|
||
'ticket.add.success': '{user} hinzugefügt.',
|
||
'ticket.remove.success': '{user} entfernt.',
|
||
'ticket.rename.success': 'Ticket umbenannt in **{name}**.',
|
||
'ticket.priority.success': 'Priorität: **{priority}**',
|
||
'ticket.transcriptDm': 'Hier ist dein Ticket-Transkript.',
|
||
'ticket.ratePrompt': 'Wie zufrieden warst du mit dem Support? (1–5)',
|
||
'ticket.rated': 'Danke für deine Bewertung: {rating}/5',
|
||
'ticket.autoCloseReason': 'Automatisch wegen Inaktivität geschlossen',
|
||
'ticket.modal.subject': 'Betreff',
|
||
'ticket.log.closed': 'Ticket geschlossen',
|
||
'ticket.log.opener': 'Ersteller',
|
||
'ticket.log.closedBy': 'Geschlossen von',
|
||
'ticket.priority.LOW': 'Niedrig',
|
||
'ticket.priority.NORMAL': 'Normal',
|
||
'ticket.priority.HIGH': 'Hoch',
|
||
'ticket.priority.URGENT': 'Dringend',
|
||
'ticket.error.disabled': 'Das Ticket-System ist deaktiviert.',
|
||
'ticket.error.category_not_found': 'Kategorie nicht gefunden.',
|
||
'ticket.error.no_categories': 'Keine Ticket-Kategorien vorhanden.',
|
||
'ticket.error.not_in_ticket': 'Dieser Befehl kann nur in einem Ticket-Kanal genutzt werden.',
|
||
'ticket.error.not_staff': 'Du hast keine Berechtigung für diese Ticket-Aktion.',
|
||
'ticket.error.already_open': 'Du hast bereits ein offenes Ticket.',
|
||
'ticket.error.closed': 'Dieses Ticket ist bereits geschlossen.',
|
||
'ticket.error.already_claimed': 'Du hast dieses Ticket bereits übernommen.',
|
||
'ticket.error.cannot_remove_opener': 'Der Ticket-Ersteller kann nicht entfernt werden.',
|
||
'ticket.error.no_channel': 'Ticket-Kanal nicht gefunden.',
|
||
'ticket.error.invalid_name': 'Ungültiger Name.',
|
||
'ticket.error.invalid_channel': 'Ungültiger Kanal.',
|
||
'ticket.error.no_parent_channel': 'Kein Elternkanal für Thread-Tickets konfiguriert.',
|
||
'ticket.error.invalid_parent_channel': 'Der konfigurierte Elternkanal ist ungültig.',
|
||
'ticket.error.not_found': 'Ticket nicht gefunden.',
|
||
'ticket.error.already_rated': 'Du hast dieses Ticket bereits bewertet.',
|
||
'birthdays.error.invalidDate': 'Ungültiges Datum. Prüfe Tag, Monat und optionales Jahr.',
|
||
'birthdays.error.invalidTimezone': 'Ungültige Zeitzone. Nutze z. B. Europe/Berlin.',
|
||
'birthdays.setup.done': 'Geburtstags-Modul konfiguriert.',
|
||
'birthdays.set.success': 'Geburtstag gespeichert: {day}.{month}.{year}',
|
||
'birthdays.remove.none': 'Du hast keinen Geburtstag eingetragen.',
|
||
'birthdays.remove.success': 'Dein Geburtstag wurde entfernt.',
|
||
'birthdays.list.empty': 'Noch keine Geburtstage eingetragen.',
|
||
'birthdays.list.header': '**Geburtstage (sortiert nach nächstem Datum):**',
|
||
'birthdays.next.header': '**Nächste Geburtstage:**',
|
||
'birthdays.list.line': '{rank}. {user} — {date} (in {days} T.)',
|
||
'stats.notConfigured': 'Server-Statistiken sind noch nicht eingerichtet. Nutze `/stats setup`.',
|
||
'stats.setup.done': 'Statistik-Kanäle konfiguriert und aktualisiert.',
|
||
'stats.refresh.done': 'Statistik-Kanäle wurden aktualisiert.',
|
||
'stats.error.invalidSetup': 'Ungültige Eingabe für die Statistik-Konfiguration.',
|
||
'invites.view.empty': '{user} hat noch keine Invite-Statistiken.',
|
||
'invites.view.result':
|
||
'**Invite-Statistik für {user}**\nJoins: {joins} | Leaves: {leaves} | Fakes: {fakes} | Netto: {net}',
|
||
'invites.leaderboard.empty': 'Noch keine Invite-Daten vorhanden.',
|
||
'invites.leaderboard.header': '**Top Einlader:**',
|
||
'invites.leaderboard.line':
|
||
'{rank}. {user} — Joins: {joins}, Leaves: {leaves}, Fakes: {fakes}, Netto: {net}',
|
||
'tempvoice.error.disabled': 'Temp-Voice ist auf diesem Server deaktiviert.',
|
||
'tempvoice.error.invalidCategory': 'Ungültige Kategorie.',
|
||
'tempvoice.error.notOwner': 'Du bist nicht der Besitzer dieses Temp-Voice-Kanals.',
|
||
'tempvoice.error.notInChannel': 'Du musst in einem Temp-Voice-Kanal sein.',
|
||
'tempvoice.error.notFound': 'Temp-Voice-Kanal nicht gefunden.',
|
||
'tempvoice.error.invalidName': 'Ungültiger Kanalname.',
|
||
'tempvoice.error.invalidLimit': 'Limit muss zwischen 0 und 99 liegen.',
|
||
'tempvoice.setup.done': 'Temp-Voice konfiguriert.',
|
||
'tempvoice.rename.success': 'Kanal umbenannt in **{name}**.',
|
||
'tempvoice.limit.success': 'Nutzerlimit auf **{limit}** gesetzt (0 = unbegrenzt).',
|
||
'tempvoice.lock.success': 'Kanal gesperrt (Connect für @everyone entfernt).',
|
||
'tempvoice.hide.success': 'Kanal versteckt (ViewChannel für @everyone entfernt).',
|
||
'tempvoice.kick.self': 'Du kannst dich nicht selbst kicken.',
|
||
'tempvoice.kick.notInChannel': 'Dieser Nutzer ist nicht in deinem Kanal.',
|
||
'tempvoice.kick.success': '{user} wurde aus dem Kanal entfernt.',
|
||
'tempvoice.transfer.self': 'Du kannst den Kanal nicht an dich selbst übertragen.',
|
||
'tempvoice.transfer.notInChannel': 'Der neue Besitzer muss in deinem Kanal sein.',
|
||
'tempvoice.transfer.success': 'Kanal an {user} übertragen.',
|
||
'tempvoice.claim.ownerPresent': 'Der Besitzer ist noch im Kanal.',
|
||
'tempvoice.claim.success': 'Du bist jetzt Besitzer dieses Kanals.',
|
||
'tempvoice.panel.title': 'Temp-Voice Steuerung',
|
||
'tempvoice.panel.description': 'Verwalte **{channel}** mit den Buttons oder `/voice`-Commands.',
|
||
'tempvoice.panel.sent': 'Control-Panel wurde in den Voice-Kanal-Chat gesendet.',
|
||
'tempvoice.button.rename': 'Umbenennen',
|
||
'tempvoice.button.limit': 'Limit',
|
||
'tempvoice.button.lock': 'Sperren',
|
||
'tempvoice.button.hide': 'Verstecken',
|
||
'tempvoice.button.kick': 'Kicken',
|
||
'tempvoice.button.transfer': 'Übertragen',
|
||
'tempvoice.button.claim': 'Übernehmen',
|
||
'selfroles.panel.defaultDescription': 'Wähle unten deine Rollen aus.',
|
||
'selfroles.panel.rolesField': 'Rollen',
|
||
'selfroles.panel.temporaryFooter': 'Rollen sind temporär und laufen automatisch ab.',
|
||
'selfroles.panel.created': 'Self-Role-Panel erstellt (ID: `{id}`).',
|
||
'selfroles.panel.updated': 'Self-Role-Panel aktualisiert (ID: `{id}`).',
|
||
'selfroles.panel.deleted': 'Self-Role-Panel gelöscht.',
|
||
'selfroles.role.added': 'Rolle hinzugefügt.',
|
||
'selfroles.role.removed': 'Rolle entfernt.',
|
||
'selfroles.role.verified': 'Rolle vergeben.',
|
||
'selfroles.role.unchanged': 'Du hast diese Rolle bereits.',
|
||
'selfroles.error.not_found': 'Self-Role-Panel nicht gefunden.',
|
||
'selfroles.error.invalid_roles': 'Ungültiges Rollen-Format. Nutze roleId:label:emoji.',
|
||
'selfroles.error.too_many_roles': 'Maximal 25 Rollen pro Panel.',
|
||
'selfroles.error.invalid_channel': 'Ungültiger Kanal.',
|
||
'selfroles.error.invalid_duration': 'Ungültige Dauer. Nutze z. B. 1h, 2d.',
|
||
'selfroles.error.duration_too_short': 'Die Dauer muss mindestens 1 Minute betragen.',
|
||
'selfroles.error.duration_required': 'Für temporäre Panels ist eine Dauer erforderlich.',
|
||
'selfroles.error.reaction_emoji_required': 'Reaktions-Modus erfordert Emojis für alle Rollen.',
|
||
'selfroles.error.member_not_found': 'Mitglied nicht gefunden.',
|
||
'selfroles.error.role_not_in_panel': 'Diese Rolle gehört nicht zu diesem Panel.',
|
||
'selfroles.error.role_not_found': 'Rolle nicht gefunden.',
|
||
'selfroles.error.role_hierarchy': 'Die Rolle liegt über der höchsten Bot-Rolle.',
|
||
'selfroles.error.role_managed': 'Integrierte Rollen können nicht vergeben werden.',
|
||
'selfroles.error.bot_missing_permissions': 'Dem Bot fehlt die Berechtigung Rollen zu verwalten.',
|
||
'tag.created': 'Tag `{name}` erstellt.',
|
||
'tag.updated': 'Tag `{name}` aktualisiert.',
|
||
'tag.deleted': 'Tag gelöscht.',
|
||
'tag.list.header': '**Tags**',
|
||
'tag.list.empty': 'Keine Tags vorhanden.',
|
||
'tag.list.uses': 'Aufrufe',
|
||
'tag.info.name': 'Name: `{name}`',
|
||
'tag.info.type': 'Typ: {type}',
|
||
'tag.info.uses': 'Aufrufe: {count}',
|
||
'tag.info.trigger': 'Trigger: `{word}`',
|
||
'tag.info.noTrigger': 'Kein Auto-Responder.',
|
||
'tag.info.roles': 'Rollen: {roles}',
|
||
'tag.info.allRoles': 'Rollen: alle',
|
||
'tag.info.channels': 'Kanäle: {channels}',
|
||
'tag.info.allChannels': 'Kanäle: alle',
|
||
'tag.error.not_found': 'Tag nicht gefunden.',
|
||
'tag.error.not_allowed': 'Du darfst diesen Tag hier nicht nutzen.',
|
||
'tag.error.invalid_name': 'Ungültiger Tag-Name (1–32 Zeichen, a-z, 0-9, _, -).',
|
||
'tag.error.content_required': 'Text-Tags benötigen Inhalt.',
|
||
'tag.error.embed_required': 'Embed-Tags benötigen Titel oder Beschreibung.',
|
||
'tag.error.premium_limit': 'Tag-Limit für diese Premium-Stufe erreicht.',
|
||
'tag.error.premium_feature': 'Tags sind für diese Premium-Stufe deaktiviert.',
|
||
'guildbackup.description': 'Server-Backups erstellen und wiederherstellen',
|
||
'guildbackup.created': 'Backup **{name}** erstellt (ID: `{id}`).',
|
||
'guildbackup.deleted': 'Backup `{id}` gelöscht.',
|
||
'guildbackup.list.header': '**Server-Backups**',
|
||
'guildbackup.list.empty': 'Keine Backups vorhanden.',
|
||
'guildbackup.list.line': '• `{id}` — **{name}** ({date})',
|
||
'guildbackup.info.id': 'ID: `{id}`',
|
||
'guildbackup.info.name': 'Name: **{name}**',
|
||
'guildbackup.info.created': 'Erstellt: {date}',
|
||
'guildbackup.info.createdBy': 'Erstellt von: <@{userId}>',
|
||
'guildbackup.info.roles': 'Rollen: {count}',
|
||
'guildbackup.info.channels': 'Kanäle: {count}',
|
||
'guildbackup.info.limitations':
|
||
'Hinweis: Backups enthalten keine Nachrichten. Beim Restore werden IDs nicht übernommen; fehlende Rollen/Kanäle werden nach Name ergänzt, bestehende nicht gelöscht.',
|
||
'guildbackup.confirm.delete': 'Backup `{id}` wirklich löschen?',
|
||
'guildbackup.confirm.restore.step1':
|
||
'Backup `{id}` wiederherstellen? Es werden fehlende Rollen/Kanäle ergänzt und Overwrites best-effort angewendet. Bestehende Kanäle werden **nicht** gelöscht.',
|
||
'guildbackup.confirm.restore.step2':
|
||
'**Letzte Bestätigung:** Backup `{id}` jetzt wiederherstellen? Diese Aktion kann nicht rückgängig gemacht werden.',
|
||
'guildbackup.confirm.button.confirm': 'Bestätigen',
|
||
'guildbackup.confirm.button.cancel': 'Abbrechen',
|
||
'guildbackup.confirm.expired': 'Diese Bestätigung ist abgelaufen.',
|
||
'guildbackup.confirm.unauthorized': 'Nur der auslösende Nutzer kann das bestätigen.',
|
||
'guildbackup.confirm.cancelled': 'Abgebrochen.',
|
||
'guildbackup.restore.done':
|
||
'Backup `{id}` wiederhergestellt. Rollen: {rolesCreated} neu, {rolesSkipped} übersprungen. Kanäle: {channelsCreated} neu, {channelsUpdated} aktualisiert. Overwrites: {overwritesApplied}.',
|
||
'guildbackup.restore.queued':
|
||
'Großes Backup `{id}` — Restore wurde in die Warteschlange gestellt und läuft im Hintergrund.',
|
||
'guildbackup.error.not_found': 'Backup nicht gefunden.',
|
||
'guildbackup.error.invalid_payload': 'Backup-Daten sind ungültig oder veraltet.',
|
||
'guildbackup.error.invalid_name': 'Ungültiger Backup-Name (1–100 Zeichen).',
|
||
'guildbackup.error.owner_only': 'Nur der Server-Owner kann Backups wiederherstellen.',
|
||
'guildbackup.error.bot_missing_permissions':
|
||
'Dem Bot fehlen Manage Roles oder Manage Channels für einen Restore.',
|
||
'guildbackup.error.premium_limit': 'Backup-Limit für diese Premium-Stufe erreicht.',
|
||
'guildbackup.error.premium_feature': 'Backups sind für diese Premium-Stufe deaktiviert.',
|
||
'feeds.added': 'Feed `{id}` ({type}) hinzugefügt.',
|
||
'feeds.removed': 'Feed `{id}` entfernt.',
|
||
'feeds.list.header': '**Social Feeds**',
|
||
'feeds.list.empty': 'Keine Feeds konfiguriert.',
|
||
'feeds.list.line': '`{id}` — {type}: {source} → {channel}',
|
||
'feeds.test.posted': 'Test erfolgreich: {count} Nachricht(en) gesendet.',
|
||
'feeds.test.noItems': 'Keine neuen Einträge gefunden.',
|
||
'feeds.test.failed': 'Abruf fehlgeschlagen: {reason}',
|
||
'feeds.test.skipped': 'Feed-Test übersprungen.',
|
||
'feeds.test.twitchSkipped':
|
||
'Twitch-Feed übersprungen: TWITCH_CLIENT_ID und TWITCH_CLIENT_SECRET fehlen in der Bot-Konfiguration.',
|
||
'feeds.error.not_found': 'Feed nicht gefunden.',
|
||
'feeds.error.premium_limit': 'Feed-Limit für diese Premium-Stufe erreicht.',
|
||
'feeds.error.premium_feature': 'Feeds sind für diese Premium-Stufe deaktiviert.',
|
||
'scheduler.created': 'Geplante Nachricht erstellt (ID: `{id}`). {timing}',
|
||
'scheduler.created.at': 'Sendung: {time}',
|
||
'scheduler.created.cron': 'Wiederholung: `{cron}`',
|
||
'scheduler.deleted': 'Geplante Nachricht gelöscht.',
|
||
'scheduler.announce.sent': 'Ankündigung gesendet.',
|
||
'scheduler.list.header': '**Geplante Nachrichten**',
|
||
'scheduler.list.empty': 'Keine geplanten Nachrichten.',
|
||
'scheduler.list.line': '`{id}` — {channel} — {timing} — {preview}',
|
||
'scheduler.list.cron': 'Cron `{cron}`',
|
||
'scheduler.list.embedPreview': '[Embed]',
|
||
'scheduler.list.componentsPreview': '[Components V2]',
|
||
'scheduler.error.missing_schedule_time': 'Gib `when` oder `cron` an.',
|
||
'scheduler.error.invalid_when': 'Ungültige Zeit. Nutze z. B. 1h, 2d oder ein ISO-Datum.',
|
||
'scheduler.error.invalid_cron': 'Ungültiger Cron-Ausdruck (5–6 Felder).',
|
||
'scheduler.error.invalid_channel': 'Ungültiger Kanal.',
|
||
'scheduler.error.channel_unavailable': 'Der Bot kann in diesem Kanal nicht senden.',
|
||
'scheduler.error.not_found': 'Geplante Nachricht nicht gefunden.',
|
||
'scheduler.error.content_required': 'Inhalt oder Embed-Titel/Beschreibung erforderlich.',
|
||
'componentsV2.error.notFound': 'Diese Komponenten-Nachricht ist nicht mehr verfügbar.',
|
||
'componentsV2.error.actionMissing': 'Für diese Interaktion ist keine Aktion konfiguriert.',
|
||
'componentsV2.error.botMissingManageRoles': 'Dem Bot fehlt die Berechtigung Rollen zu verwalten.',
|
||
'componentsV2.error.roleNotFound': 'Rolle nicht gefunden.',
|
||
'componentsV2.error.roleManaged': 'Integrierte Rollen können nicht vergeben werden.',
|
||
'componentsV2.error.roleHierarchy': 'Die Rolle liegt über der höchsten Bot-Rolle.',
|
||
'componentsV2.error.noRolesSelected': 'Keine Rollen ausgewählt.',
|
||
'componentsV2.role.assigned': 'Rolle vergeben.',
|
||
'componentsV2.role.removed': 'Rolle entfernt.',
|
||
'componentsV2.role.assignedSelected': 'Ausgewählte Rollen vergeben.',
|
||
'utility.embed.components.sent': 'Components-V2-Nachricht gesendet.',
|
||
'utility.embed.components.dashboardHint':
|
||
'Für den vollen Builder inkl. Interaktionen: {url}',
|
||
'utility.embed.components.missingText': 'Text ist erforderlich.',
|
||
'tag.error.components_required': 'Components-V2-Tags benötigen Komponenten.'
|
||
};
|
||
const en: Dictionary = {
|
||
'generic.noPermission': 'You do not have permission for this action.',
|
||
'generic.guildOnly': 'This command can only be used in a server.',
|
||
'generic.botMissingPermission': 'Bot lacks required permission ({permission}).',
|
||
'generic.invalidRegex': 'Invalid regex pattern.',
|
||
'generic.error': 'An error occurred.',
|
||
'generic.maintenance': 'Nexumi is currently in maintenance mode. Please try again later.',
|
||
'generic.unknownCommand': 'Unknown command.',
|
||
'generic.commandDisabled': 'This command is disabled on this server.',
|
||
'generic.commandChannelBlocked': 'This command is not allowed in this channel.',
|
||
'generic.commandRoleBlocked': 'You are not allowed to use this command with your roles.',
|
||
'generic.commandCooldown': 'Please wait {seconds} more seconds before using this command again.',
|
||
'generic.moduleDisabled': 'This module is disabled on this server.',
|
||
'generic.userBlacklisted': 'You are not allowed to use Nexumi right now.',
|
||
'generic.guildBlacklisted': 'This server is not allowed to use Nexumi right now.',
|
||
'core.help.title': 'Nexumi Help',
|
||
'core.help.subtitle': 'Commands by module. Optional: `/help module:<name>`.',
|
||
'core.help.moduleLine': '**{module}**: {commands}',
|
||
'core.help.unknownModule': 'Unknown module. Available: {modules}',
|
||
'core.help.footer': 'More: /info · Dashboard: {webui}',
|
||
'core.info.title': 'Nexumi',
|
||
'core.info.version': 'Version',
|
||
'core.info.uptime': 'Uptime',
|
||
'core.info.shard': 'Shard',
|
||
'core.info.guilds': 'Servers (this shard)',
|
||
'core.info.latency': 'API latency',
|
||
'core.info.links': 'Links',
|
||
'core.info.link.dashboard': 'Dashboard',
|
||
'core.info.link.invite': 'Invite',
|
||
'core.info.link.support': 'Support',
|
||
'core.info.link.status': 'Status',
|
||
'core.invite.title': 'Invite Nexumi',
|
||
'core.invite.body': 'Invite Nexumi to your server with this link:',
|
||
'core.support.title': 'Support',
|
||
'core.support.body': 'Join our support server:',
|
||
'core.support.missing': 'No support server configured. Set SUPPORT_SERVER_URL.',
|
||
'core.module.core': 'Core',
|
||
'core.module.moderation': 'Moderation',
|
||
'core.module.automod': 'Auto-Moderation',
|
||
'core.module.welcome': 'Welcome',
|
||
'core.module.verification': 'Verification',
|
||
'core.module.leveling': 'Leveling',
|
||
'core.module.economy': 'Economy',
|
||
'core.module.utility': 'Utility',
|
||
'core.module.fun': 'Fun',
|
||
'core.module.giveaways': 'Giveaways',
|
||
'core.module.tickets': 'Tickets',
|
||
'core.module.selfroles': 'Self-Roles',
|
||
'core.module.tags': 'Tags',
|
||
'core.module.starboard': 'Starboard',
|
||
'core.module.suggestions': 'Suggestions',
|
||
'core.module.birthdays': 'Birthdays',
|
||
'core.module.tempvoice': 'Temp Voice',
|
||
'core.module.stats': 'Stats',
|
||
'core.module.feeds': 'Feeds',
|
||
'core.module.scheduler': 'Scheduler',
|
||
'core.module.guildbackup': 'Backup',
|
||
'gdpr.privacy.title': 'Privacy',
|
||
'gdpr.privacy.body':
|
||
'Nexumi stores Discord IDs and module-related data (e.g. warnings, XP, economy) as needed to operate.',
|
||
'gdpr.privacy.link': 'Full privacy policy: {url}',
|
||
'gdpr.privacy.deleteHint': 'Delete personal data: `/gdpr delete confirm:true`',
|
||
'gdpr.delete.needConfirm': 'Set `confirm` to `true` to confirm deletion.',
|
||
'gdpr.delete.doneTitle': 'Data deleted',
|
||
'gdpr.delete.doneBody':
|
||
'Deleted/anonymized: {warnings} warnings, {levels} level rows, {economy} economy rows, {cases} cases anonymized.',
|
||
'moderation.success': 'Action executed successfully.',
|
||
'moderation.success.case': 'Action executed successfully (case #{caseNumber}).',
|
||
'moderation.duration.invalid': 'Invalid duration. Use e.g. 30m, 12h, or 7d.',
|
||
'moderation.duration.invalidTimeout':
|
||
'Invalid timeout duration. Use e.g. 30m or 1d (max 28 days).',
|
||
'moderation.hierarchy.self': 'You cannot apply this action to yourself.',
|
||
'moderation.hierarchy.owner': 'The server owner cannot be moderated.',
|
||
'moderation.hierarchy.moderator':
|
||
'You cannot moderate members with equal or higher roles.',
|
||
'moderation.hierarchy.bot':
|
||
'The bot cannot moderate this member due to role hierarchy or missing permissions.',
|
||
'moderation.hierarchy.notMember': 'That member is not on this server.',
|
||
'moderation.reason.none': 'No reason provided',
|
||
'moderation.warning.created': 'Warning created: {warningId}',
|
||
'moderation.warning.none': 'No warnings.',
|
||
'moderation.warning.defaultReason': 'No reason',
|
||
'moderation.warning.notFound': 'Warning not found.',
|
||
'moderation.purge.done': 'Deleted {deletedCount} messages (case #{caseNumber}).',
|
||
'moderation.note.none': 'No notes.',
|
||
'moderation.case.notFound': 'Case not found.',
|
||
'moderation.escalation.durationRequired': 'Duration is required for TIMEOUT escalation.',
|
||
'moderation.escalation.noneConfigured': 'No escalation rules configured.',
|
||
'moderation.escalation.saved':
|
||
'Escalation rule saved: {warnCount} warnings => {action}{duration}.',
|
||
'moderation.escalation.removed': 'Escalation rule removed for {warnCount} warnings.',
|
||
'moderation.escalation.defaultReason': 'Auto escalation at {warnCount} warnings',
|
||
'moderation.escalation.skippedDuration':
|
||
'Escalation rule for {warnCount} warns skipped (missing duration).',
|
||
'moderation.escalation.skippedPermission':
|
||
'Escalation rule for {warnCount} warns skipped (missing bot permissions).',
|
||
'moderation.escalation.appliedTimeout': 'Auto escalation applied: timeout ({durationMs} ms).',
|
||
'moderation.escalation.appliedKick': 'Auto escalation applied: kick.',
|
||
'moderation.escalation.appliedBan': 'Auto escalation applied: ban.',
|
||
'moderation.confirm.button.confirm': 'Confirm',
|
||
'moderation.confirm.button.cancel': 'Cancel',
|
||
'moderation.confirm.permanent': 'permanent',
|
||
'moderation.confirm.ban':
|
||
'Confirm ban for <@{userId}>?\nReason: {reason}\nDuration: {duration}',
|
||
'moderation.confirm.purge':
|
||
'Delete {amount} messages? This action cannot be undone.',
|
||
'moderation.confirm.caseDelete': 'Really delete case #{caseNumber}?',
|
||
'moderation.confirm.expired': 'Confirmation expired. Please run the command again.',
|
||
'moderation.confirm.cancelled': 'Action cancelled.',
|
||
'moderation.confirm.unauthorized': 'Only the moderator who started this action can confirm it.',
|
||
'automod.status.header':
|
||
'**AutoMod enabled:** {enabled}\n**Anti-raid:** {antiRaid}\n**Anti-nuke:** {antiNuke}\n**Lockdown:** {lockdown}',
|
||
'automod.status.ruleLine': '- {type} → {action}',
|
||
'automod.status.noRules': 'No active rules.',
|
||
'automod.status.yes': 'yes',
|
||
'automod.status.no': 'no',
|
||
'welcome.notConfigured': 'Welcome message is not configured yet.',
|
||
'welcome.invalidChannel': 'The configured welcome channel is invalid.',
|
||
'welcome.testSent': 'Test welcome message sent.',
|
||
'verification.disabled': 'Verification is disabled.',
|
||
'verification.success': 'You have been verified successfully.',
|
||
'verification.setupDone': 'Verification configured.',
|
||
'verification.notConfigured': 'Verification is not set up yet. Use `/verify setup`.',
|
||
'verification.invalidChannel': 'The verification channel is invalid.',
|
||
'verification.panelPosted': 'Verification panel posted.',
|
||
'verification.panelMissingPermission':
|
||
'The bot lacks permissions in that channel (View Channel, Send Messages, Embed Links).',
|
||
'verification.panel.title': 'Verification',
|
||
'verification.panel.description':
|
||
'Click the button below to verify and gain access to the server.',
|
||
'verification.panel.button': 'Verify',
|
||
'verification.panel.buttonCaptcha': 'Verify (Captcha)',
|
||
'verification.captchaLink': 'Open this link to complete captcha verification: {url}',
|
||
'verification.error.not_configured': 'Verification is not configured.',
|
||
'verification.error.member_not_found': 'Member not found.',
|
||
'verification.error.account_too_young': 'Your account is too young to verify.',
|
||
'verification.error.missing_permissions': 'Bot lacks permissions.',
|
||
'verification.error.invalid_role': 'Verification role is invalid.',
|
||
'verification.error.alt_detected':
|
||
'Verification denied: possible alternate account detected.',
|
||
'verification.error.generic': 'Verification failed.',
|
||
'verification.captcha.success': 'Captcha passed. You have been verified.',
|
||
'verification.captcha.invalid': 'Captcha invalid or expired.',
|
||
'verification.captcha.title': 'Nexumi Verification',
|
||
'leveling.disabled': 'Leveling is disabled on this server.',
|
||
'leveling.rank.title': 'Rank card',
|
||
'leveling.leaderboard.title': 'Leaderboard',
|
||
'leveling.leaderboard.empty': 'No XP data yet.',
|
||
'leveling.leaderboard.entry': '{rank}. {user} — Level {level} ({xp} XP)',
|
||
'leveling.leaderboard.footer': 'Top {count} members',
|
||
'leveling.levelUp.default': 'Congratulations {user}, you reached level {level}!',
|
||
'leveling.xp.give.success': 'Gave {amount} XP to {user}. New level: {level}.',
|
||
'leveling.xp.remove.success': 'Removed {amount} XP from {user}. New level: {level}.',
|
||
'leveling.xp.reset.success': 'Reset XP for {user}.',
|
||
'leveling.xp.invalidAmount': 'Amount must be greater than 0.',
|
||
'leveling.user.notFound': 'User not found on this server.',
|
||
'economy.error.disabled': 'The economy module is disabled on this server.',
|
||
'economy.error.insufficient': 'You do not have enough money.',
|
||
'economy.error.cooldown': 'Cooldown active. Try again in {seconds} seconds.',
|
||
'economy.error.invalid_amount': 'Invalid amount.',
|
||
'economy.error.self_transfer': 'You cannot send money to yourself.',
|
||
'economy.error.not_found': 'Entry not found.',
|
||
'economy.error.out_of_stock': 'This item is out of stock.',
|
||
'economy.error.role_assign_failed': 'Purchase succeeded, but the role could not be assigned.',
|
||
'economy.error.game_in_progress': 'You already have an active blackjack game.',
|
||
'economy.balance.result': 'Balance of {user}: {amount}',
|
||
'economy.daily.success': 'Daily reward: {amount}. New balance: {balance}',
|
||
'economy.weekly.success': 'Weekly reward: {amount}. New balance: {balance}',
|
||
'economy.work.success': 'You earned {amount}. New balance: {balance}',
|
||
'economy.pay.success': 'You sent {amount} to {user}. Your balance: {balance}',
|
||
'economy.gamble.win': 'You won! +{amount}. Balance: {balance}',
|
||
'economy.gamble.lose': 'You lost! -{amount}. Balance: {balance}',
|
||
'economy.slots.win': '{reels}\nWinnings: {payout}. Balance: {balance}',
|
||
'economy.slots.lose': '{reels}\nNo win. Balance: {balance}',
|
||
'economy.coinflip.win': '{result} – you picked {choice}. You won! +{amount}. Balance: {balance}',
|
||
'economy.coinflip.lose': '{result} – you picked {choice}. You lost! -{amount}. Balance: {balance}',
|
||
'economy.choice.heads': 'Heads',
|
||
'economy.choice.tails': 'Tails',
|
||
'economy.shop.empty': 'The shop is empty.',
|
||
'economy.shop.noDescription': 'No description',
|
||
'economy.shop.itemLine': '**{name}** (`{id}`) – {price} | Stock: {stock}\n{description}',
|
||
'economy.shop.purchased': 'You purchased **{name}**. Balance: {balance}',
|
||
'economy.inventory.empty': 'Your inventory is empty.',
|
||
'economy.inventory.itemLine': '- {name} × {quantity}',
|
||
'economy.leaderboard.empty': 'No leaderboard entries yet.',
|
||
'economy.leaderboard.line': '{rank}. {user} – {amount}',
|
||
'economy.admin.give': 'Gave {amount} to {user}. New balance: {balance}',
|
||
'economy.admin.remove': 'Removed {amount} from {user}. New balance: {balance}',
|
||
'economy.admin.reset': 'Reset economy data for {user}.',
|
||
'economy.blackjack.title': 'Blackjack',
|
||
'economy.blackjack.hand': 'Bet: {bet}\n\n**You:** {playerHand} ({playerTotal})\n**Dealer:** {dealerHand} ({dealerTotal})',
|
||
'economy.blackjack.button.hit': 'Hit',
|
||
'economy.blackjack.button.stand': 'Stand',
|
||
'economy.blackjack.outcome.win': 'You win {bet}!',
|
||
'economy.blackjack.outcome.lose': 'You lose your bet.',
|
||
'economy.blackjack.outcome.push': 'Push – bet returned.',
|
||
'economy.blackjack.outcome.blackjack': 'Blackjack! You win {bet}!',
|
||
'economy.blackjack.expired': 'This blackjack game expired or no longer exists.',
|
||
'economy.blackjack.notOwner': 'Only the player can use these buttons.',
|
||
'utility.error.invalid_when': 'Invalid time. Use e.g. 30m or a future ISO datetime.',
|
||
'utility.error.invalid_datetime': 'Invalid date/time.',
|
||
'utility.error.invalid_poll_options': 'Provide 2–5 comma-separated options.',
|
||
'utility.error.channel_not_found': 'Channel not found.',
|
||
'utility.error.role_not_found': 'Role not found.',
|
||
'utility.error.poll_not_found': 'Poll not found.',
|
||
'utility.error.reminder_channel_unavailable': 'Reminder channel unavailable.',
|
||
'utility.poll.created': 'Poll created.',
|
||
'utility.poll.closed': 'This poll is closed.',
|
||
'utility.poll.notFound': 'Poll not found.',
|
||
'utility.poll.invalidOption': 'Invalid option.',
|
||
'utility.poll.alreadyVoted': 'You already voted.',
|
||
'utility.poll.voted': 'Vote counted for **{option}**.',
|
||
'utility.poll.votes': 'votes',
|
||
'utility.poll.endsAt': 'Ends {time}',
|
||
'utility.poll.multiSelect': 'Multi-select',
|
||
'utility.poll.multiSelectHint': 'You may select multiple options.',
|
||
'utility.remindme.created': 'Reminder created (ID: `{id}`).',
|
||
'utility.reminders.none': 'No reminders.',
|
||
'utility.reminders.line': '`{id}` — {time}: {content}',
|
||
'utility.reminders.deleted': 'Reminder deleted.',
|
||
'utility.reminders.notFound': 'Reminder not found.',
|
||
'utility.afk.set': 'AFK set. Reason: {reason}',
|
||
'utility.afk.welcomeBack': 'Welcome back! You were AFK: {reason}',
|
||
'utility.afk.mention': '{user} is AFK: {reason}',
|
||
'utility.avatar.title': 'Avatar of {user}',
|
||
'utility.banner.title': 'Banner of {user}',
|
||
'utility.banner.none': 'No banner set.',
|
||
'utility.emoji.noSource': 'Attachment or URL required.',
|
||
'utility.emoji.added': 'Added emoji {emoji}.',
|
||
'utility.emoji.removed': 'Emoji removed.',
|
||
'utility.emoji.notFound': 'Emoji not found.',
|
||
'utility.emoji.messageNotFound': 'Message not found.',
|
||
'utility.emoji.noEmojiInMessage': 'No custom emoji in message.',
|
||
'utility.emoji.stolen': 'Stole emoji {emoji}.',
|
||
'utility.sticker.noSource': 'Attachment or URL required.',
|
||
'utility.sticker.added': 'Added sticker **{name}**.',
|
||
'utility.embed.sent': 'Embed sent.',
|
||
'utility.embed.invalidColor': 'Invalid color. Use e.g. 6366F1.',
|
||
'utility.snipe.none': 'Nothing to show.',
|
||
'utility.snipe.disabled': 'Snipe is disabled on this server (privacy).',
|
||
'utility.snipe.privacy':
|
||
'Privacy: Snipe stores deleted/edited messages briefly (1 h) in Redis.',
|
||
'utility.snipe.deletedAt': 'Deleted message by {user}',
|
||
'utility.snipe.editedAt': 'Edited message by {user}',
|
||
'utility.translate.noContent': 'No translatable text content.',
|
||
'utility.translate.failed': 'Translation failed.',
|
||
'utility.translate.result': '**Translation:** {text}',
|
||
'fun.8ball.result': '**Question:** {question}\n**Answer:** {answer}',
|
||
'fun.dice.result': 'Dice ({sides} sides): {rolls}',
|
||
'fun.flip.result': 'The coin shows: **{result}**',
|
||
'fun.rps.win': 'You picked **{player}**, I picked **{bot}**. You win!',
|
||
'fun.rps.lose': 'You picked **{player}**, I picked **{bot}**. You lose!',
|
||
'fun.rps.draw': 'Both picked **{player}**. Draw!',
|
||
'fun.rps.choice.rock': 'Rock',
|
||
'fun.rps.choice.paper': 'Paper',
|
||
'fun.rps.choice.scissors': 'Scissors',
|
||
'fun.choose.result': 'I choose: **{choice}**',
|
||
'fun.choose.tooFew': 'Provide at least two comma-separated options.',
|
||
'fun.trivia.title': 'Trivia',
|
||
'fun.trivia.question': '**{question}**\n\n{options}',
|
||
'fun.trivia.footer': 'Only {user} can answer.',
|
||
'fun.trivia.correct': '✅ Correct!',
|
||
'fun.trivia.incorrect': '❌ Wrong!',
|
||
'fun.trivia.notOwner': 'Only the initiator can answer this question.',
|
||
'fun.tictactoe.title': 'Tic-Tac-Toe',
|
||
'fun.tictactoe.board': '❌: {x} | ⭕: {o}\n\n{board}',
|
||
'fun.tictactoe.challenge': '{challenger} challenges {opponent} to Tic-Tac-Toe!',
|
||
'fun.tictactoe.turn': 'Turn: {user}',
|
||
'fun.tictactoe.won': '{user} wins!',
|
||
'fun.tictactoe.draw': 'Draw!',
|
||
'fun.tictactoe.invalidMove': 'Invalid move.',
|
||
'fun.connect4.title': 'Connect 4',
|
||
'fun.connect4.board': '🔴: {red} | 🟡: {yellow}\n\n{board}',
|
||
'fun.connect4.challenge': '{challenger} challenges {opponent} to Connect 4!',
|
||
'fun.connect4.turn': 'Turn: {user}',
|
||
'fun.connect4.won': '{user} wins!',
|
||
'fun.connect4.draw': 'Draw!',
|
||
'fun.connect4.invalidMove': 'This column is full.',
|
||
'fun.hangman.title': 'Hangman',
|
||
'fun.hangman.progress': 'Word: {word}\nWrong: {wrong}/{max}\nGuessed: {guessed}',
|
||
'fun.hangman.won': 'You won! The word was **{word}**.',
|
||
'fun.hangman.lost': 'You lost! The word was **{word}**.',
|
||
'fun.common.notParticipant': 'You are not a participant in this game.',
|
||
'fun.common.expired': 'This game expired or no longer exists.',
|
||
'fun.common.selfChallenge': 'You cannot challenge yourself.',
|
||
'fun.common.botChallenge': 'You cannot challenge a bot.',
|
||
'fun.media.disabled': 'Media commands are disabled on this server.',
|
||
'fun.media.fetchFailed': 'Could not load image. Try again later.',
|
||
'fun.cat.title': 'Random Cat',
|
||
'fun.dog.title': 'Random Dog',
|
||
'starboard.notConfigured': 'Starboard is not configured yet. Use `/starboard setup`.',
|
||
'starboard.invalidChannel':
|
||
'The starboard channel is invalid or the bot lacks permissions (View, Send, Embed Links).',
|
||
'starboard.setupDone': 'Starboard configured and enabled.',
|
||
'starboard.noContent': '*No text content*',
|
||
'starboard.field.stars': 'Stars',
|
||
'starboard.field.source': 'Source',
|
||
'starboard.jumpLink': 'Jump to message',
|
||
'starboard.statusLine':
|
||
'Starboard active → channel {channel}, emoji {emoji}, threshold {threshold}, self-star: {selfStar}',
|
||
'starboard.selfStarOn': 'allowed',
|
||
'starboard.selfStarOff': 'denied',
|
||
'suggestion.created': 'Suggestion submitted (ID: `{id}`).',
|
||
'suggestion.setupDone': 'Suggestion system configured.',
|
||
'suggestion.staffUpdated': 'Suggestion updated ({status}).',
|
||
'suggestion.votedUp': 'Upvote recorded.',
|
||
'suggestion.votedDown': 'Downvote recorded.',
|
||
'suggestion.threadName': 'Discussion #{id}',
|
||
'suggestion.error.not_configured': 'Suggestions are not configured. Use `/suggestion setup`.',
|
||
'suggestion.error.invalid_channel': 'The configured channel is invalid.',
|
||
'suggestion.error.not_found': 'Suggestion not found.',
|
||
'suggestion.error.not_open': 'This suggestion is no longer open.',
|
||
'suggestion.error.already_voted': 'You already voted this way.',
|
||
'suggestion.embed.title': 'Suggestion #{id}',
|
||
'suggestion.embed.status': 'Status',
|
||
'suggestion.embed.votes': 'Votes',
|
||
'suggestion.embed.author': 'By {author}',
|
||
'suggestion.embed.staffReason': 'Staff reason',
|
||
'suggestion.status.open': 'Open',
|
||
'suggestion.status.approved': 'Approved',
|
||
'suggestion.status.denied': 'Denied',
|
||
'suggestion.status.considered': 'Under consideration',
|
||
'suggestion.status.implemented': 'Implemented',
|
||
'suggestion.dm.statusUpdate': 'Your suggestion was updated: **{status}**\nReason: {reason}',
|
||
'giveaway.embed.title': 'Giveaway',
|
||
'giveaway.embed.prize': 'Prize',
|
||
'giveaway.embed.winners': 'Winners',
|
||
'giveaway.embed.entrants': 'Entrants',
|
||
'giveaway.embed.host': 'Host',
|
||
'giveaway.embed.requirements': 'Requirements',
|
||
'giveaway.embed.active': 'Click **Join** to enter!',
|
||
'giveaway.embed.paused': '⏸️ This giveaway is paused.',
|
||
'giveaway.embed.ended': 'Ended',
|
||
'giveaway.embed.endedWinners': 'Winners: {winners}',
|
||
'giveaway.embed.endedNoWinners': 'No valid entrants.',
|
||
'giveaway.embed.endsAt': 'Ends {time}',
|
||
'giveaway.button.join': 'Join',
|
||
'giveaway.requirement.role': 'Role: {role}',
|
||
'giveaway.requirement.level': 'Minimum level: {level}',
|
||
'giveaway.requirement.memberDays': 'Member for at least {days} days',
|
||
'giveaway.started': 'Giveaway started (ID: `{id}`).',
|
||
'giveaway.ended': 'Giveaway ended.',
|
||
'giveaway.rerolled': 'New winners: {winners}',
|
||
'giveaway.deleted': 'Giveaway deleted.',
|
||
'giveaway.paused': 'Giveaway paused.',
|
||
'giveaway.resumed': 'Giveaway resumed.',
|
||
'giveaway.joined': 'You entered the giveaway!',
|
||
'giveaway.list.header': '**Active giveaways**',
|
||
'giveaway.list.empty': 'No active giveaways.',
|
||
'giveaway.list.entrants': 'entrants',
|
||
'giveaway.dm.won': 'Congratulations! You won **{prize}** on **{guild}**!',
|
||
'giveaway.error.not_found': 'Giveaway not found or already ended.',
|
||
'giveaway.error.already_ended': 'This giveaway has already ended.',
|
||
'giveaway.error.not_ended': 'Giveaway has not ended yet.',
|
||
'giveaway.error.paused': 'This giveaway is paused.',
|
||
'giveaway.error.already_joined': 'You already entered.',
|
||
'giveaway.error.member_not_found': 'Member not found.',
|
||
'giveaway.error.missing_role': 'You are missing the required role.',
|
||
'giveaway.error.insufficient_level': 'Your level is too low.',
|
||
'giveaway.error.insufficient_member_days': 'You have not been on the server long enough.',
|
||
'giveaway.error.invalid_duration': 'Invalid duration. Use e.g. 1h, 2d.',
|
||
'giveaway.error.duration_too_short': 'Duration must be at least 1 minute.',
|
||
'giveaway.error.invalid_channel': 'Invalid channel.',
|
||
'ticket.panel.defaultDescription': 'Select a category to open a ticket.',
|
||
'ticket.panel.created': 'Ticket panel created.',
|
||
'ticket.category.created': 'Category **{name}** created.',
|
||
'ticket.created': 'Your ticket was created: {channel}',
|
||
'ticket.opened': '{user} opened a ticket.',
|
||
'ticket.subjectLine': 'Subject: {subject}',
|
||
'ticket.claimed': '{user} claimed this ticket.',
|
||
'ticket.userAdded': '{user} was added to the ticket.',
|
||
'ticket.userRemoved': '{user} was removed from the ticket.',
|
||
'ticket.renamed': 'Ticket renamed to **{name}**.',
|
||
'ticket.prioritySet': 'Priority set to **{priority}**',
|
||
'ticket.closed': 'Ticket closed by {user}.',
|
||
'ticket.closedWithReason': 'Ticket closed by {user}.\nReason: {reason}',
|
||
'ticket.close.success': 'Ticket closed.',
|
||
'ticket.claim.success': 'Ticket claimed.',
|
||
'ticket.add.success': 'Added {user}.',
|
||
'ticket.remove.success': 'Removed {user}.',
|
||
'ticket.rename.success': 'Ticket renamed to **{name}**.',
|
||
'ticket.priority.success': 'Priority: **{priority}**',
|
||
'ticket.transcriptDm': 'Here is your ticket transcript.',
|
||
'ticket.ratePrompt': 'How satisfied were you with support? (1–5)',
|
||
'ticket.rated': 'Thanks for your rating: {rating}/5',
|
||
'ticket.autoCloseReason': 'Auto-closed due to inactivity',
|
||
'ticket.modal.subject': 'Subject',
|
||
'ticket.log.closed': 'Ticket closed',
|
||
'ticket.log.opener': 'Opener',
|
||
'ticket.log.closedBy': 'Closed by',
|
||
'ticket.priority.LOW': 'Low',
|
||
'ticket.priority.NORMAL': 'Normal',
|
||
'ticket.priority.HIGH': 'High',
|
||
'ticket.priority.URGENT': 'Urgent',
|
||
'ticket.error.disabled': 'The ticket system is disabled.',
|
||
'ticket.error.category_not_found': 'Category not found.',
|
||
'ticket.error.no_categories': 'No ticket categories configured.',
|
||
'ticket.error.not_in_ticket': 'This command can only be used inside a ticket channel.',
|
||
'ticket.error.not_staff': 'You do not have permission for this ticket action.',
|
||
'ticket.error.already_open': 'You already have an open ticket.',
|
||
'ticket.error.closed': 'This ticket is already closed.',
|
||
'ticket.error.already_claimed': 'You already claimed this ticket.',
|
||
'ticket.error.cannot_remove_opener': 'The ticket opener cannot be removed.',
|
||
'ticket.error.no_channel': 'Ticket channel not found.',
|
||
'ticket.error.invalid_name': 'Invalid name.',
|
||
'ticket.error.invalid_channel': 'Invalid channel.',
|
||
'ticket.error.no_parent_channel': 'No parent channel configured for thread tickets.',
|
||
'ticket.error.invalid_parent_channel': 'The configured parent channel is invalid.',
|
||
'ticket.error.not_found': 'Ticket not found.',
|
||
'ticket.error.already_rated': 'You already rated this ticket.',
|
||
'birthdays.error.invalidDate': 'Invalid date. Check day, month, and optional year.',
|
||
'birthdays.error.invalidTimezone': 'Invalid timezone. Use e.g. Europe/Berlin.',
|
||
'birthdays.setup.done': 'Birthday module configured.',
|
||
'birthdays.set.success': 'Birthday saved: {day}/{month}/{year}',
|
||
'birthdays.remove.none': 'You have not set a birthday.',
|
||
'birthdays.remove.success': 'Your birthday was removed.',
|
||
'birthdays.list.empty': 'No birthdays registered yet.',
|
||
'birthdays.list.header': '**Birthdays (sorted by next date):**',
|
||
'birthdays.next.header': '**Upcoming birthdays:**',
|
||
'birthdays.list.line': '{rank}. {user} — {date} (in {days} d)',
|
||
'stats.notConfigured': 'Server statistics are not configured yet. Use `/stats setup`.',
|
||
'stats.setup.done': 'Stats channels configured and updated.',
|
||
'stats.refresh.done': 'Stats channels have been refreshed.',
|
||
'stats.error.invalidSetup': 'Invalid input for stats configuration.',
|
||
'invites.view.empty': '{user} has no invite statistics yet.',
|
||
'invites.view.result':
|
||
'**Invite stats for {user}**\nJoins: {joins} | Leaves: {leaves} | Fakes: {fakes} | Net: {net}',
|
||
'invites.leaderboard.empty': 'No invite data available yet.',
|
||
'invites.leaderboard.header': '**Top inviters:**',
|
||
'invites.leaderboard.line':
|
||
'{rank}. {user} — Joins: {joins}, Leaves: {leaves}, Fakes: {fakes}, Net: {net}',
|
||
'tempvoice.error.disabled': 'Temp voice is disabled on this server.',
|
||
'tempvoice.error.invalidCategory': 'Invalid category.',
|
||
'tempvoice.error.notOwner': 'You are not the owner of this temp voice channel.',
|
||
'tempvoice.error.notInChannel': 'You must be in a temp voice channel.',
|
||
'tempvoice.error.notFound': 'Temp voice channel not found.',
|
||
'tempvoice.error.invalidName': 'Invalid channel name.',
|
||
'tempvoice.error.invalidLimit': 'Limit must be between 0 and 99.',
|
||
'tempvoice.setup.done': 'Temp voice configured.',
|
||
'tempvoice.rename.success': 'Channel renamed to **{name}**.',
|
||
'tempvoice.limit.success': 'User limit set to **{limit}** (0 = unlimited).',
|
||
'tempvoice.lock.success': 'Channel locked (Connect denied for @everyone).',
|
||
'tempvoice.hide.success': 'Channel hidden (ViewChannel denied for @everyone).',
|
||
'tempvoice.kick.self': 'You cannot kick yourself.',
|
||
'tempvoice.kick.notInChannel': 'That user is not in your channel.',
|
||
'tempvoice.kick.success': 'Removed {user} from the channel.',
|
||
'tempvoice.transfer.self': 'You cannot transfer the channel to yourself.',
|
||
'tempvoice.transfer.notInChannel': 'The new owner must be in your channel.',
|
||
'tempvoice.transfer.success': 'Channel transferred to {user}.',
|
||
'tempvoice.claim.ownerPresent': 'The owner is still in the channel.',
|
||
'tempvoice.claim.success': 'You are now the owner of this channel.',
|
||
'tempvoice.panel.title': 'Temp Voice Control',
|
||
'tempvoice.panel.description': 'Manage **{channel}** with the buttons below or `/voice` commands.',
|
||
'tempvoice.panel.sent': 'Control panel posted in the voice channel chat.',
|
||
'tempvoice.button.rename': 'Rename',
|
||
'tempvoice.button.limit': 'Limit',
|
||
'tempvoice.button.lock': 'Lock',
|
||
'tempvoice.button.hide': 'Hide',
|
||
'tempvoice.button.kick': 'Kick',
|
||
'tempvoice.button.transfer': 'Transfer',
|
||
'tempvoice.button.claim': 'Claim',
|
||
'selfroles.panel.defaultDescription': 'Choose your roles below.',
|
||
'selfroles.panel.rolesField': 'Roles',
|
||
'selfroles.panel.temporaryFooter': 'Roles are temporary and expire automatically.',
|
||
'selfroles.panel.created': 'Self-role panel created (ID: `{id}`).',
|
||
'selfroles.panel.updated': 'Self-role panel updated (ID: `{id}`).',
|
||
'selfroles.panel.deleted': 'Self-role panel deleted.',
|
||
'selfroles.role.added': 'Role added.',
|
||
'selfroles.role.removed': 'Role removed.',
|
||
'selfroles.role.verified': 'Role granted.',
|
||
'selfroles.role.unchanged': 'You already have this role.',
|
||
'selfroles.error.not_found': 'Self-role panel not found.',
|
||
'selfroles.error.invalid_roles': 'Invalid roles format. Use roleId:label:emoji.',
|
||
'selfroles.error.too_many_roles': 'Maximum 25 roles per panel.',
|
||
'selfroles.error.invalid_channel': 'Invalid channel.',
|
||
'selfroles.error.invalid_duration': 'Invalid duration. Use e.g. 1h, 2d.',
|
||
'selfroles.error.duration_too_short': 'Duration must be at least 1 minute.',
|
||
'selfroles.error.duration_required': 'Temporary panels require a duration.',
|
||
'selfroles.error.reaction_emoji_required': 'Reaction mode requires emojis for all roles.',
|
||
'selfroles.error.member_not_found': 'Member not found.',
|
||
'selfroles.error.role_not_in_panel': 'This role is not part of this panel.',
|
||
'selfroles.error.role_not_found': 'Role not found.',
|
||
'selfroles.error.role_hierarchy': 'The role is above the bot\'s highest role.',
|
||
'selfroles.error.role_managed': 'Managed roles cannot be assigned.',
|
||
'selfroles.error.bot_missing_permissions': 'The bot lacks Manage Roles permission.',
|
||
'tag.created': 'Tag `{name}` created.',
|
||
'tag.updated': 'Tag `{name}` updated.',
|
||
'tag.deleted': 'Tag deleted.',
|
||
'tag.list.header': '**Tags**',
|
||
'tag.list.empty': 'No tags configured.',
|
||
'tag.list.uses': 'uses',
|
||
'tag.info.name': 'Name: `{name}`',
|
||
'tag.info.type': 'Type: {type}',
|
||
'tag.info.uses': 'Uses: {count}',
|
||
'tag.info.trigger': 'Trigger: `{word}`',
|
||
'tag.info.noTrigger': 'No auto-responder.',
|
||
'tag.info.roles': 'Roles: {roles}',
|
||
'tag.info.allRoles': 'Roles: all',
|
||
'tag.info.channels': 'Channels: {channels}',
|
||
'tag.info.allChannels': 'Channels: all',
|
||
'tag.error.not_found': 'Tag not found.',
|
||
'tag.error.not_allowed': 'You are not allowed to use this tag here.',
|
||
'tag.error.invalid_name': 'Invalid tag name (1–32 chars, a-z, 0-9, _, -).',
|
||
'tag.error.content_required': 'Text tags require content.',
|
||
'tag.error.embed_required': 'Embed tags require a title or description.',
|
||
'tag.error.premium_limit': 'Tag limit reached for this premium tier.',
|
||
'tag.error.premium_feature': 'Tags are disabled for this premium tier.',
|
||
'guildbackup.description': 'Create and restore server backups',
|
||
'guildbackup.created': 'Created backup **{name}** (ID: `{id}`).',
|
||
'guildbackup.deleted': 'Deleted backup `{id}`.',
|
||
'guildbackup.list.header': '**Server backups**',
|
||
'guildbackup.list.empty': 'No backups found.',
|
||
'guildbackup.list.line': '• `{id}` — **{name}** ({date})',
|
||
'guildbackup.info.id': 'ID: `{id}`',
|
||
'guildbackup.info.name': 'Name: **{name}**',
|
||
'guildbackup.info.created': 'Created: {date}',
|
||
'guildbackup.info.createdBy': 'Created by: <@{userId}>',
|
||
'guildbackup.info.roles': 'Roles: {count}',
|
||
'guildbackup.info.channels': 'Channels: {count}',
|
||
'guildbackup.info.limitations':
|
||
'Note: Backups do not include messages. Restore cannot preserve IDs; missing roles/channels are added by name, existing channels are not deleted.',
|
||
'guildbackup.confirm.delete': 'Really delete backup `{id}`?',
|
||
'guildbackup.confirm.restore.step1':
|
||
'Restore backup `{id}`? Missing roles/channels will be added and overwrites applied best-effort. Existing channels will **not** be deleted.',
|
||
'guildbackup.confirm.restore.step2':
|
||
'**Final confirmation:** Restore backup `{id}` now? This cannot be undone.',
|
||
'guildbackup.confirm.button.confirm': 'Confirm',
|
||
'guildbackup.confirm.button.cancel': 'Cancel',
|
||
'guildbackup.confirm.expired': 'This confirmation has expired.',
|
||
'guildbackup.confirm.unauthorized': 'Only the user who started this action can confirm.',
|
||
'guildbackup.confirm.cancelled': 'Cancelled.',
|
||
'guildbackup.restore.done':
|
||
'Restored backup `{id}`. Roles: {rolesCreated} created, {rolesSkipped} skipped. Channels: {channelsCreated} created, {channelsUpdated} updated. Overwrites: {overwritesApplied}.',
|
||
'guildbackup.restore.queued':
|
||
'Large backup `{id}` — restore queued and will run in the background.',
|
||
'guildbackup.error.not_found': 'Backup not found.',
|
||
'guildbackup.error.invalid_payload': 'Backup data is invalid or outdated.',
|
||
'guildbackup.error.invalid_name': 'Invalid backup name (1–100 characters).',
|
||
'guildbackup.error.owner_only': 'Only the server owner can restore backups.',
|
||
'guildbackup.error.bot_missing_permissions':
|
||
'The bot is missing Manage Roles or Manage Channels for a restore.',
|
||
'guildbackup.error.premium_limit': 'Backup limit reached for this premium tier.',
|
||
'guildbackup.error.premium_feature': 'Backups are disabled for this premium tier.',
|
||
'feeds.added': 'Added feed `{id}` ({type}).',
|
||
'feeds.removed': 'Removed feed `{id}`.',
|
||
'feeds.list.header': '**Social Feeds**',
|
||
'feeds.list.empty': 'No feeds configured.',
|
||
'feeds.list.line': '`{id}` — {type}: {source} → {channel}',
|
||
'feeds.test.posted': 'Test successful: sent {count} message(s).',
|
||
'feeds.test.noItems': 'No new items found.',
|
||
'feeds.test.failed': 'Fetch failed: {reason}',
|
||
'feeds.test.skipped': 'Feed test skipped.',
|
||
'feeds.test.twitchSkipped':
|
||
'Twitch feed skipped: TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET are missing in the bot configuration.',
|
||
'feeds.error.not_found': 'Feed not found.',
|
||
'feeds.error.premium_limit': 'Feed limit reached for this premium tier.',
|
||
'feeds.error.premium_feature': 'Feeds are disabled for this premium tier.',
|
||
'scheduler.created': 'Scheduled message created (ID: `{id}`). {timing}',
|
||
'scheduler.created.at': 'Sends at: {time}',
|
||
'scheduler.created.cron': 'Repeats: `{cron}`',
|
||
'scheduler.deleted': 'Scheduled message deleted.',
|
||
'scheduler.announce.sent': 'Announcement sent.',
|
||
'scheduler.list.header': '**Scheduled messages**',
|
||
'scheduler.list.empty': 'No scheduled messages.',
|
||
'scheduler.list.line': '`{id}` — {channel} — {timing} — {preview}',
|
||
'scheduler.list.cron': 'Cron `{cron}`',
|
||
'scheduler.list.embedPreview': '[Embed]',
|
||
'scheduler.list.componentsPreview': '[Components V2]',
|
||
'scheduler.error.missing_schedule_time': 'Provide `when` or `cron`.',
|
||
'scheduler.error.invalid_when': 'Invalid time. Use e.g. 1h, 2d, or an ISO date.',
|
||
'scheduler.error.invalid_cron': 'Invalid cron expression (5–6 fields).',
|
||
'scheduler.error.invalid_channel': 'Invalid channel.',
|
||
'scheduler.error.channel_unavailable': 'The bot cannot send messages in that channel.',
|
||
'scheduler.error.not_found': 'Scheduled message not found.',
|
||
'scheduler.error.content_required': 'Content or embed title/description is required.',
|
||
'componentsV2.error.notFound': 'This component message is no longer available.',
|
||
'componentsV2.error.actionMissing': 'No action is configured for this interaction.',
|
||
'componentsV2.error.botMissingManageRoles': 'The bot lacks Manage Roles permission.',
|
||
'componentsV2.error.roleNotFound': 'Role not found.',
|
||
'componentsV2.error.roleManaged': 'Managed roles cannot be assigned.',
|
||
'componentsV2.error.roleHierarchy': 'The role is above the bot\'s highest role.',
|
||
'componentsV2.error.noRolesSelected': 'No roles selected.',
|
||
'componentsV2.role.assigned': 'Role assigned.',
|
||
'componentsV2.role.removed': 'Role removed.',
|
||
'componentsV2.role.assignedSelected': 'Selected roles assigned.',
|
||
'utility.embed.components.sent': 'Components V2 message sent.',
|
||
'utility.embed.components.dashboardHint':
|
||
'For the full builder including interactions: {url}',
|
||
'utility.embed.components.missingText': 'Text is required.',
|
||
'tag.error.components_required': 'Components V2 tags require components.'
|
||
};
|
||
|
||
const locales: Record<Locale, Dictionary> = { de, en };
|
||
|
||
export function t(locale: Locale, key: string): string {
|
||
return locales[locale][key] ?? key;
|
||
}
|
||
|
||
export function tf(locale: Locale, key: string, vars: Record<string, string | number>): string {
|
||
const base = t(locale, key);
|
||
return Object.entries(vars).reduce(
|
||
(acc, [name, value]) => acc.replaceAll(`{${name}}`, String(value)),
|
||
base
|
||
);
|
||
}
|