Add giveaway, ticket, self-role, starboard, and suggestion features to the bot
- Introduced new models in the Prisma schema for giveaways, tickets, self-role panels, starboard configurations, and suggestions, enhancing the bot's functionality. - Implemented job handling for self-role expiration and ticket management, improving user experience. - Updated command localization to support new features in both German and English. - Enhanced the job processing system to include dedicated workers for managing tickets and self-role expirations. - Documented the new features and their setup processes in PHASE-TRACKING.md for clarity on implementation steps.
This commit is contained in:
@@ -5,6 +5,7 @@ export * from './command-locales.js';
|
||||
export * from './discord-localization.js';
|
||||
export * from './phase2.js';
|
||||
export * from './phase3.js';
|
||||
export * from './phase4.js';
|
||||
|
||||
export const LocaleSchema = z.enum(['de', 'en']);
|
||||
export type Locale = z.infer<typeof LocaleSchema>;
|
||||
@@ -238,7 +239,204 @@ const de: Dictionary = {
|
||||
'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'
|
||||
'fun.dog.title': 'Random Dog',
|
||||
'starboard.notConfigured': 'Starboard ist noch nicht konfiguriert. Nutze `/starboard setup`.',
|
||||
'starboard.invalidChannel': 'Der Starboard-Kanal ist ungültig.',
|
||||
'starboard.setupDone': 'Starboard konfiguriert.',
|
||||
'starboard.noContent': '*Kein Textinhalt*',
|
||||
'starboard.field.stars': 'Sterne',
|
||||
'starboard.field.source': 'Quelle',
|
||||
'starboard.jumpLink': 'Zur Nachricht',
|
||||
'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.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.)',
|
||||
'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.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.'
|
||||
};
|
||||
const en: Dictionary = {
|
||||
'generic.noPermission': 'You do not have permission for this action.',
|
||||
@@ -439,7 +637,204 @@ const en: Dictionary = {
|
||||
'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'
|
||||
'fun.dog.title': 'Random Dog',
|
||||
'starboard.notConfigured': 'Starboard is not configured yet. Use `/starboard setup`.',
|
||||
'starboard.invalidChannel': 'The starboard channel is invalid.',
|
||||
'starboard.setupDone': 'Starboard configured.',
|
||||
'starboard.noContent': '*No text content*',
|
||||
'starboard.field.stars': 'Stars',
|
||||
'starboard.field.source': 'Source',
|
||||
'starboard.jumpLink': 'Jump to message',
|
||||
'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.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)',
|
||||
'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.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.'
|
||||
};
|
||||
|
||||
const locales: Record<Locale, Dictionary> = { de, en };
|
||||
|
||||
Reference in New Issue
Block a user