From 4c8eae26787ac1d8d67b0a16496d79704c74e83b Mon Sep 17 00:00:00 2001 From: BastLast Date: Tue, 20 Feb 2024 00:32:18 +0100 Subject: [PATCH 01/12] WIP language command #2273 --- Core/src/commands/admin/LanguageCommand.ts | 13 ++++++ Core/src/core/Constants.ts | 5 --- Discord/src/Constants.ts | 5 --- Discord/src/commands/CommandsManager.ts | 15 ++++--- .../commands/SlashCommandBuilderGenerator.ts | 25 ++++++----- Discord/src/commands/admin/LanguageCommand.ts | 45 +++++++++++++++++++ Discord/src/commands/player/HelpCommand.ts | 3 +- Lang/en/commands.json | 31 +++++++++++++ Lang/en/discordBuilder.json | 8 ++++ Lang/fr/commands.json | 39 ++++++++++++++-- Lang/fr/discordBuilder.json | 12 +++-- Lib/src/Language.ts | 2 +- Lib/src/constants/StringConstants.ts | 19 ++++++++ .../packets/commands/CommandLanguagePacket.ts | 7 +++ Lib/src/utils/TimeUtils.ts | 7 +-- 15 files changed, 194 insertions(+), 42 deletions(-) create mode 100644 Core/src/commands/admin/LanguageCommand.ts create mode 100644 Discord/src/commands/admin/LanguageCommand.ts create mode 100644 Lib/src/packets/commands/CommandLanguagePacket.ts diff --git a/Core/src/commands/admin/LanguageCommand.ts b/Core/src/commands/admin/LanguageCommand.ts new file mode 100644 index 000000000..303c7ce8e --- /dev/null +++ b/Core/src/commands/admin/LanguageCommand.ts @@ -0,0 +1,13 @@ +import {packetHandler} from "../../core/packetHandlers/PacketHandler"; +import {CommandUpdatePacketReq, CommandUpdatePacketRes} from "../../../../Lib/src/packets/commands/CommandUpdatePacket"; +import {WebsocketClient} from "../../../../Lib/src/instances/WebsocketClient"; +import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; + +export default class LanguageCommand { + @packetHandler(CommandUpdatePacketReq) + execute(client: WebsocketClient, packet: CommandUpdatePacketReq, context: PacketContext, response: DraftBotPacket[]): void { + response.push(makePacket(CommandUpdatePacketRes, { + coreVersion: process.env.npm_package_version + })); + } +} \ No newline at end of file diff --git a/Core/src/core/Constants.ts b/Core/src/core/Constants.ts index 3d5a80fce..1979a714c 100644 --- a/Core/src/core/Constants.ts +++ b/Core/src/core/Constants.ts @@ -235,11 +235,6 @@ export abstract class Constants { ] }; - static readonly LANGUAGE = { - FRENCH: "fr", - ENGLISH: "en" - }; - static readonly PET_FOOD = { COMMON_FOOD: "commonFood", CARNIVOROUS_FOOD: "carnivorousFood", diff --git a/Discord/src/Constants.ts b/Discord/src/Constants.ts index 06b929cf2..d218721e8 100644 --- a/Discord/src/Constants.ts +++ b/Discord/src/Constants.ts @@ -54,11 +54,6 @@ export class Constants { ] }; - static readonly LANGUAGE: { FRENCH: Language, ENGLISH: Language } = { - FRENCH: "fr", - ENGLISH: "en" - }; - static readonly MESSAGES = { COLLECTOR_TIME: 120000, COLORS: { diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index 4abc132ea..bff03c0e6 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -32,6 +32,7 @@ import {DiscordWebSocket} from "../bot/Websocket"; import {PacketContext} from "../../../Lib/src/packets/DraftBotPacket"; import {DiscordCache} from "../bot/DiscordCache"; import {BotUtils} from "../utils/BotUtils"; +import { StringConstants } from "../../../Lib/src/constants/StringConstants"; export class CommandsManager { static commands = new Map(); @@ -216,13 +217,13 @@ export class CommandsManager { message.channel.send({ content: ` ${i18n.t("bot:mentionHelp", { - lang: Constants.LANGUAGE.ENGLISH, + lang: StringConstants.LANGUAGE.ENGLISH, commandHelp: BotUtils.commandsMentions.get("help"), commandLanguage: BotUtils.commandsMentions.get("language") })} ${i18n.t("bot:mentionHelp", { - lang: Constants.LANGUAGE.FRENCH, + lang: StringConstants.LANGUAGE.FRENCH, commandHelp: BotUtils.commandsMentions.get("help"), commandLanguage: BotUtils.commandsMentions.get("language") })}` @@ -302,7 +303,7 @@ ${i18n.t("bot:mentionHelp", { attachmentList.push(new AttachmentBuilder(Buffer.from(message.content)).setName(`userMessage-${message.author.id}-${message.id}.txt`)); } const supportAlert = i18n.t("bot:supportAlert", { - lang: Constants.LANGUAGE.FRENCH, + lang: StringConstants.LANGUAGE.FRENCH, username: escapeUsername(message.author.username), id: message.author.id }) + (message.content.length > Constants.DM.MAX_MESSAGE_LENGTH_ALLOWED @@ -336,7 +337,7 @@ ${i18n.t("bot:mentionHelp", { if (!msg!.getFirstReaction()) { return; } - const language = msg!.getFirstReaction()!.emoji.name === Constants.REACTIONS.ENGLISH_FLAG ? Constants.LANGUAGE.ENGLISH : Constants.LANGUAGE.FRENCH; + const language = msg!.getFirstReaction()!.emoji.name === Constants.REACTIONS.ENGLISH_FLAG ? StringConstants.LANGUAGE.ENGLISH : StringConstants.LANGUAGE.FRENCH; message.channel.send({ embeds: [new DraftBotEmbed() .formatAuthor(i18n.t("bot:dmHelpMessageTitle", { @@ -354,7 +355,7 @@ ${i18n.t("bot:mentionHelp", { .formatAuthor(Constants.DM.TITLE_SUPPORT, author) .setDescription(message instanceof DraftbotInteraction ? Constants.DM.INTERACTION_SUPPORT : Constants.DM.MESSAGE_SUPPORT); const draftbotChannel = message.channel as unknown as DraftbotChannel; - draftbotChannel.language = Constants.LANGUAGE.ENGLISH; + draftbotChannel.language = StringConstants.LANGUAGE.ENGLISH; message instanceof Message ? await helpMessage.send(draftbotChannel) : await helpMessage.reply(message); } @@ -370,14 +371,14 @@ ${i18n.t("bot:mentionHelp", { const commandInfo = this.commands.get(interaction.commandName); if (!commandInfo) { - await replyErrorMessage(interaction, Constants.LANGUAGE.ENGLISH, i18n.t("bot:command404", {lang: language})); + await replyErrorMessage(interaction, StringConstants.LANGUAGE.ENGLISH, i18n.t("bot:command404", {lang: language})); console.error(`Command "${interaction.commandName}" is not registered`); return; } const channelAccess = this.hasChannelPermission(interaction.channel); if (!channelAccess[0]) { - await replyErrorMessage(interaction, Constants.LANGUAGE.ENGLISH, i18n.t(channelAccess[1], {lang: language})); + await replyErrorMessage(interaction, StringConstants.LANGUAGE.ENGLISH, i18n.t(channelAccess[1], {lang: language})); return; } diff --git a/Discord/src/commands/SlashCommandBuilderGenerator.ts b/Discord/src/commands/SlashCommandBuilderGenerator.ts index 9b6359553..cb7549872 100644 --- a/Discord/src/commands/SlashCommandBuilderGenerator.ts +++ b/Discord/src/commands/SlashCommandBuilderGenerator.ts @@ -6,6 +6,7 @@ import i18n from "../translations/i18n"; import {Constants} from "../Constants"; import {SlashCommandStringOption} from "discord.js"; import {TopConstants} from "../../../Lib/src/constants/TopConstants"; +import { StringConstants } from "../../../Lib/src/constants/StringConstants"; export class SlashCommandBuilderGenerator { @@ -16,13 +17,13 @@ export class SlashCommandBuilderGenerator { */ static generateBaseCommand(commandSectionName: string): SlashCommandBuilder { return new SlashCommandBuilder() - .setName(i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: Constants.LANGUAGE.ENGLISH })) + .setName(i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: StringConstants.LANGUAGE.ENGLISH })) .setNameLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: StringConstants.LANGUAGE.FRENCH }) }) - .setDescription(i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: Constants.LANGUAGE.ENGLISH })) + .setDescription(i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: StringConstants.LANGUAGE.ENGLISH })) .setDescriptionLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: StringConstants.LANGUAGE.FRENCH }) }); } @@ -33,13 +34,13 @@ export class SlashCommandBuilderGenerator { * @param option Option to populate */ static generateOption(commandSectionName: string, optionSectionName: string, option: T): T { - return option.setName(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: Constants.LANGUAGE.ENGLISH })) + return option.setName(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: StringConstants.LANGUAGE.ENGLISH })) .setNameLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: StringConstants.LANGUAGE.FRENCH }) }) - .setDescription(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: Constants.LANGUAGE.ENGLISH })) + .setDescription(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: StringConstants.LANGUAGE.ENGLISH })) .setDescriptionLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: StringConstants.LANGUAGE.FRENCH }) }); } @@ -57,16 +58,16 @@ export class SlashCommandBuilderGenerator { return SlashCommandBuilderGenerator.generateOption(commandSectionName, optionSectionName, option) .addChoices( { - name: i18n.t("discordBuilder:scopes.global", { lng: Constants.LANGUAGE.ENGLISH }), + name: i18n.t("discordBuilder:scopes.global", { lng: StringConstants.LANGUAGE.ENGLISH }), "name_localizations": { - fr: i18n.t("discordBuilder:scopes.global", { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t("discordBuilder:scopes.global", { lng: StringConstants.LANGUAGE.FRENCH }) }, value: TopConstants.GLOBAL_SCOPE }, { - name: i18n.t("discordBuilder:scopes.server", { lng: Constants.LANGUAGE.ENGLISH }), + name: i18n.t("discordBuilder:scopes.server", { lng: StringConstants.LANGUAGE.ENGLISH }), "name_localizations": { - fr: i18n.t("discordBuilder:scopes.server", { lng: Constants.LANGUAGE.FRENCH }) + fr: i18n.t("discordBuilder:scopes.server", { lng: StringConstants.LANGUAGE.FRENCH }) } , value: TopConstants.SERVER_SCOPE diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts new file mode 100644 index 000000000..f47f21dc9 --- /dev/null +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -0,0 +1,45 @@ +import {ICommand} from "../ICommand"; +import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; +import {ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder} from "discord.js"; +import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; +import i18n from "../../translations/i18n"; +import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; +import { StringConstants } from "../../../../Lib/src/constants/StringConstants"; +/** + * Allow an admin to change the prefix the bot uses in a specific server + */ +async function getPacket(interaction: DraftbotInteraction): Promise { + const selectLanguageMenuId = "languageSelectionMenu"; + + const selectLanguageMenuOptions = Object.keys(StringConstants.LANGUAGE).map((key) => { + const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; + return new StringSelectMenuOptionBuilder() + .setLabel(i18n.t(`commands:language.languages.${languageCode}.name` , {lng: interaction.channel.language})) + .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji` , {lng: interaction.channel.language})) + .setValue(languageCode); + }); + const languageSelectionMenu = new StringSelectMenuBuilder() + .setCustomId(selectLanguageMenuId) + .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.channel.language})) + .addOptions(selectLanguageMenuOptions); + const row = new ActionRowBuilder() + .addComponents(languageSelectionMenu); + await interaction.reply({ + embeds: [new DraftBotEmbed() + .setTitle(i18n.t("commands:language.title", { + lng: interaction.channel.language + })) + .setDescription(i18n.t("commands:language.description", { + lng: interaction.channel.language + }))], + components: [row] + }); + return null; +} + +export const commandInfo: ICommand = { + slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("language"), + getPacket, + requirements: {}, + mainGuildCommand: false +}; diff --git a/Discord/src/commands/player/HelpCommand.ts b/Discord/src/commands/player/HelpCommand.ts index 7d7f1a73e..d26640ff8 100644 --- a/Discord/src/commands/player/HelpCommand.ts +++ b/Discord/src/commands/player/HelpCommand.ts @@ -9,6 +9,7 @@ import {Language} from "../../../../Lib/src/Language"; import {PetConstants} from "../../../../Lib/src/constants/PetConstants"; import {HelpConstants} from "../../constants/HelpConstants"; import {Constants} from "../../Constants"; +import { StringConstants } from "../../../../Lib/src/constants/StringConstants"; /** * Get the list of commands mention from the command data @@ -182,7 +183,7 @@ function generateReplacementObjectForHelpCommand(interaction: DraftbotInteractio */ async function getPacket(interaction: DraftbotInteraction): Promise { const helpMessage = new DraftBotEmbed(); - const command = interaction.options.get(i18n.t("discordBuilder:help.options.commandName.name", {lng: Constants.LANGUAGE.ENGLISH})); + const command = interaction.options.get(i18n.t("discordBuilder:help.options.commandName.name", {lng: StringConstants.LANGUAGE.ENGLISH})); const askedCommand = command ? command.value as string : null; if (!askedCommand) { generateGenericHelpMessage(helpMessage, interaction); diff --git a/Lang/en/commands.json b/Lang/en/commands.json index c48f723d6..1f6126c08 100644 --- a/Lang/en/commands.json +++ b/Lang/en/commands.json @@ -128,6 +128,37 @@ "description": "The latest version of the bot's core is **{{coreVersion}}**. The Discord module's version is **{{discordModuleVersion}}**.\n\nInformations about the changelog can be found here:\nhttps://guide.draftbot.com/v/en/lore/change-logs", "title": ":scroll: Changelog" }, + "language": { + "selectLanguage": "Select a new language", + "description": "Use the menu below to change the language used by the bot on this discord server. This command can only be used by server administrators.", + "title": ":earth_africa: Language selection", + "languages": { + "en": { + "emoji": "🇬🇧", + "name": "English" + }, + "fr": { + "emoji": "🇫🇷", + "name": "French" + }, + "es": { + "emoji": "🇪🇸", + "name": "spanish" + }, + "de": { + "emoji": "🇩🇪", + "name": "German" + }, + "pt": { + "emoji": "🇵🇹", + "name": "Portuguese" + }, + "it": { + "emoji": "🇮🇹", + "name": "Italian" + } + } + }, "help": { "aliasFieldTitle": "Alias", "helpEmbedDescription": ":arrow_forward: If you want more information about a specific command click here: {{helpCommandMention}}, and complete the parameter with a command. :wink:", diff --git a/Lang/en/discordBuilder.json b/Lang/en/discordBuilder.json index 68012e62e..f34345cca 100644 --- a/Lang/en/discordBuilder.json +++ b/Lang/en/discordBuilder.json @@ -82,5 +82,13 @@ "name": "command" } } + }, + "vote": { + "description": "Displays the link to vote for the bot.", + "name": "vote" + }, + "language": { + "description": "Change the language spoken by the bot in the discord server where the command was executed.", + "name": "language" } } \ No newline at end of file diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index 3d2eae15e..f9125b857 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -7,10 +7,6 @@ "description": "Vous pouvez proposer des suggestions et voter pour vos idées préférées via ce lien:\nhttps://feedback.draftbot.com/", "title": ":bulb: Idées" }, - "vote": { - "description": "Voici le lien permettant de soutenir le bot :\nhttps://top.gg/bot/448110812801007618", - "title": ":ballot_box: Voter" - }, "inventory": { "armors_one": "Armure/Bouclier ({{count}}/{{max}}) :", "armors_other": "Armures/Boucliers ({{count}}/{{max}}) :", @@ -128,6 +124,37 @@ "description": "La version actuelle du noyau du bot est la **{{coreVersion}}**. Celle du module Discord est la **{{discordModuleVersion}}**.\n\nToutes les informations concernant les mises à jour sont disponibles ici :\nhttps://guide.draftbot.com/lore/historique-des-mises-a-jour", "title": ":scroll: Mises à jour" }, + "language": { + "selectLanguage": "Sélectionnez une langue", + "description": "Utilisez le menu ci-dessous pour changer la langue utilisée par le bot. Cette commande est réservée aux administrateurs du serveur.", + "title": ":earth_africa: Selection de la langue", + "languages": { + "en": { + "emoji": "🇬🇧", + "name": "Anglais" + }, + "fr": { + "emoji": "🇫🇷", + "name": "Français" + }, + "es": { + "emoji": "🇪🇸", + "name": "Espagnol" + }, + "de": { + "emoji": "🇩🇪", + "name": "Allemand" + }, + "pt": { + "emoji": "🇵🇹", + "name": "Portugais" + }, + "it": { + "emoji": "🇮🇹", + "name": "Italien" + } + } + }, "help": { "aliasFieldTitle": "Alias", "helpEmbedDescription": ":arrow_forward: Si vous voulez plus d'informations sur une commande en particulier, cliquez ici : {{helpCommandMention}}, et donnez la commande qui vous pose problème en paramètre. :wink:", @@ -343,5 +370,9 @@ "monsterRewardsDescription": ":moneybag: Argent gagné : **{{money}}**\n:star: XP gagnée : **{{experience}}**", "monsterRewardGuildXp": "\n:star: XP de guilde gagnée: **{{guildXp}}**", "monsterRewardsGuildPoints": "\n:mirror_ball: Points de guilde gagnés : **{{guildPoints}}**" + }, + "vote": { + "description": "Voici le lien permettant de soutenir le bot :\nhttps://top.gg/bot/448110812801007618", + "title": ":ballot_box: Voter" } } \ No newline at end of file diff --git a/Lang/fr/discordBuilder.json b/Lang/fr/discordBuilder.json index a256c6cb2..646a0a4dc 100644 --- a/Lang/fr/discordBuilder.json +++ b/Lang/fr/discordBuilder.json @@ -3,10 +3,6 @@ "description": "Affiche des informations sur les badges et leur fonctionnement.", "name": "badges" }, - "vote": { - "description": "Afficher le lien permettant de voter pour le bot.", - "name": "vote" - }, "idea": { "description": "Envoyer une suggestion pour améliorer le jeu.", "name": "suggestion" @@ -82,5 +78,13 @@ "name": "commande" } } + }, + "vote": { + "description": "Afficher le lien permettant de voter pour le bot.", + "name": "vote" + }, + "language": { + "description": "Changer la langue du bot dans le serveur discord ou la commande a été exécutée.", + "name": "langage" } } \ No newline at end of file diff --git a/Lib/src/Language.ts b/Lib/src/Language.ts index 887cff3b8..c9ed49678 100644 --- a/Lib/src/Language.ts +++ b/Lib/src/Language.ts @@ -1 +1 @@ -export type Language = "fr" | "en" ; +export type Language = "fr" | "en" | "it" | "es" | "de" | "pt"; diff --git a/Lib/src/constants/StringConstants.ts b/Lib/src/constants/StringConstants.ts index 968fc3dad..d84149585 100644 --- a/Lib/src/constants/StringConstants.ts +++ b/Lib/src/constants/StringConstants.ts @@ -1,3 +1,22 @@ +import {Language} from "../Language"; + export class StringConstants { static readonly PROGRESS_BAR_SIZE = 20; + + static readonly LANGUAGE: { + FRENCH: Language, + ENGLISH: Language, + ITALIAN: Language, + SPANISH: Language, + PORTUGUESE: Language, + GERMAN: Language + } + = { + FRENCH: "fr", + ENGLISH: "en", + ITALIAN: "it", + SPANISH: "es", + PORTUGUESE: "pt", + GERMAN: "de" + }; } \ No newline at end of file diff --git a/Lib/src/packets/commands/CommandLanguagePacket.ts b/Lib/src/packets/commands/CommandLanguagePacket.ts new file mode 100644 index 000000000..01cedd661 --- /dev/null +++ b/Lib/src/packets/commands/CommandLanguagePacket.ts @@ -0,0 +1,7 @@ +export class CommandLanguagePacketReq { + +} + +export class CommandLanguagePacketRes { + +} \ No newline at end of file diff --git a/Lib/src/utils/TimeUtils.ts b/Lib/src/utils/TimeUtils.ts index 726912a51..847adff37 100644 --- a/Lib/src/utils/TimeUtils.ts +++ b/Lib/src/utils/TimeUtils.ts @@ -1,4 +1,5 @@ -import {Constants} from "../../../Core/src/core/Constants"; + +import {StringConstants} from "../constants/StringConstants"; /** * Get the elements to display a remaining time in the given language @@ -11,7 +12,7 @@ function getMinutesDisplayStringConstants(language: string): { hoursDisplay: str secondsDisplay: "s", linkWord: " ", plural: "" - } : language === Constants.LANGUAGE.FRENCH ? { + } : language === StringConstants.LANGUAGE.FRENCH ? { hoursDisplay: "heure", minutesDisplay: "minute", secondsDisplay: "seconde", @@ -206,7 +207,7 @@ export function parseTimeDifferenceFooter(date1: number, date2: number, language let parsed = ""; const days = Math.floor(seconds / (24 * 60 * 60)); if (days > 0) { - parsed += days + (language === Constants.LANGUAGE.FRENCH ? " J " : " D "); + parsed += days + (language === StringConstants.LANGUAGE.FRENCH ? " J " : " D "); seconds -= days * 24 * 60 * 60; } From b5e3f42c8fc5b8074a1bf9452bea7eae0e7fb7fc Mon Sep 17 00:00:00 2001 From: BastLast Date: Wed, 21 Feb 2024 00:08:27 +0100 Subject: [PATCH 02/12] Wip language command 2 #2273 --- Core/src/core/Constants.ts | 34 ------------------- Core/src/core/constants/ServersConstants.ts | 4 +-- .../core/database/game/migrations/019-v5.ts | 4 +-- Discord/src/Constants.ts | 2 -- Discord/src/commands/admin/LanguageCommand.ts | 7 +++- .../commands/{player => admin}/TestCommand.ts | 0 Discord/src/constants/PermissionsConstants.ts | 27 +++++++++++++++ .../handlers/CommandHandlers.ts | 2 ++ Lang/fr/commands.json | 4 +-- .../packets/commands/CommandLanguagePacket.ts | 7 ++-- 10 files changed, 45 insertions(+), 46 deletions(-) rename Discord/src/commands/{player => admin}/TestCommand.ts (100%) create mode 100644 Discord/src/constants/PermissionsConstants.ts diff --git a/Core/src/core/Constants.ts b/Core/src/core/Constants.ts index 1979a714c..26e24b338 100644 --- a/Core/src/core/Constants.ts +++ b/Core/src/core/Constants.ts @@ -54,15 +54,6 @@ export abstract class Constants { ROLE_DURATION: 24 }; - static readonly COMMAND_CATEGORY = { - SERVER: "server", - UTIL: "util", - PLAYER: "player", - MISSION: "mission", - GUILD: "guild", - PET: "pet" - }; - static readonly XP = { BASE_VALUE: 325, COEFFICIENT: 1.041, @@ -269,33 +260,8 @@ export abstract class Constants { ] }; - static readonly ROLES = { - GUILD: { - NONE: "none", - MEMBER: "member", - ELDER: "elder", - CHIEF: "chief" - }, - USER: { - ADMINISTRATOR: "administrator", - BADGE_MANAGER: "manager", - CONTRIBUTORS: "contributors", - BOT_OWNER: "owner" - } - }; - static readonly MINIMAL_PLAYER_SCORE = 100; - static readonly PERMISSION = { - ROLE: { - BOT_OWNER: "owner", // Is the owner of the bot - BADGE_MANAGER: "manager", // Has the badge manager role - SUPPORT: "support", // Has the support role - ADMINISTRATOR: "administrator", // Has the admin permission in a server where the bot is. - CONTRIBUTORS: "contributors", - ALL: "all" - } - }; static readonly MAX_DAILY_POTION_BUYOUTS: number = 5; diff --git a/Core/src/core/constants/ServersConstants.ts b/Core/src/core/constants/ServersConstants.ts index 727b5838c..fb97fce33 100644 --- a/Core/src/core/constants/ServersConstants.ts +++ b/Core/src/core/constants/ServersConstants.ts @@ -1,5 +1,5 @@ -import {Constants} from "../Constants"; +import {StringConstants} from "../../../../Lib/src/constants/StringConstants"; export abstract class ServersConstants { - static readonly DEFAULT_LANGUAGE = Constants.LANGUAGE.ENGLISH; + static readonly DEFAULT_LANGUAGE = StringConstants.LANGUAGE.ENGLISH; } \ No newline at end of file diff --git a/Core/src/core/database/game/migrations/019-v5.ts b/Core/src/core/database/game/migrations/019-v5.ts index 9999c33f8..25d4b0d46 100644 --- a/Core/src/core/database/game/migrations/019-v5.ts +++ b/Core/src/core/database/game/migrations/019-v5.ts @@ -7,8 +7,8 @@ import {parse} from "toml"; import {readFileSync} from "fs"; import {KeycloakUtils} from "../../../../../../Lib/src/keycloak/KeycloakUtils"; import {KeycloakConfig} from "../../../../../../Lib/src/keycloak/KeycloakConfig"; -import {Constants} from "../../../Constants"; import {logsV5NewIds} from "../../logs/migrations/006-v5"; +import {StringConstants} from "../../../../../../Lib/src/constants/StringConstants"; export async function up({context}: { context: QueryInterface }): Promise { const configPath = `${process.cwd()}/config/keycloak.toml`; @@ -29,7 +29,7 @@ clientSecret = "secret" for (let i = 0; i < players.length; ++i) { const player = players[i]; - const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, Constants.LANGUAGE.ENGLISH); + const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, StringConstants.LANGUAGE.ENGLISH); await context.sequelize.query(`UPDATE players SET discordUserId = "${user.id}" WHERE discordUserId = "${player.discordUserId}"`); logsV5NewIds.set(player.discordUserId as string, user.id); } diff --git a/Discord/src/Constants.ts b/Discord/src/Constants.ts index d218721e8..539d65b8c 100644 --- a/Discord/src/Constants.ts +++ b/Discord/src/Constants.ts @@ -1,5 +1,3 @@ -import {Language} from "../../Lib/src/Language"; - export class Constants { static readonly VERSION = import("../package.json").then(json => json.version); diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index f47f21dc9..e0c021941 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -5,6 +5,9 @@ import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; import i18n from "../../translations/i18n"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import { StringConstants } from "../../../../Lib/src/constants/StringConstants"; +import { KeycloakUser } from "../../../../Lib/src/keycloak/KeycloakUser"; +import {PermissionsConstants} from "../../constants/PermissionsConstants"; + /** * Allow an admin to change the prefix the bot uses in a specific server */ @@ -40,6 +43,8 @@ async function getPacket(interaction: DraftbotInteraction): Promise { export const commandInfo: ICommand = { slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("language"), getPacket, - requirements: {}, + requirements: { + userPermission: PermissionsConstants.ROLES.USER.ADMINISTRATOR + }, mainGuildCommand: false }; diff --git a/Discord/src/commands/player/TestCommand.ts b/Discord/src/commands/admin/TestCommand.ts similarity index 100% rename from Discord/src/commands/player/TestCommand.ts rename to Discord/src/commands/admin/TestCommand.ts diff --git a/Discord/src/constants/PermissionsConstants.ts b/Discord/src/constants/PermissionsConstants.ts new file mode 100644 index 000000000..59e881767 --- /dev/null +++ b/Discord/src/constants/PermissionsConstants.ts @@ -0,0 +1,27 @@ +export abstract class PermissionsConstants { + static readonly ROLES = { + GUILD: { + NONE: "none", + MEMBER: "member", + ELDER: "elder", + CHIEF: "chief" + }, + USER: { + ADMINISTRATOR: "administrator", + BADGE_MANAGER: "manager", + CONTRIBUTORS: "contributors", + BOT_OWNER: "owner" + } + }; + + static readonly PERMISSION = { + ROLE: { + BOT_OWNER: "owner", // Is the owner of the bot + BADGE_MANAGER: "manager", // Has the badge manager role + SUPPORT: "support", // Has the support role + ADMINISTRATOR: "administrator", // Has the admin permission in a server where the bot is. + CONTRIBUTORS: "contributors", + ALL: "all" + } + }; +} \ No newline at end of file diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index e2b610a6d..7f8dbb834 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -15,6 +15,8 @@ import {CommandTestPacketRes} from "../../../../Lib/src/packets/commands/Command import {handleCommandTestPacketRes} from "../../commands/player/TestCommand"; import {CommandRarityPacketRes} from "../../../../Lib/src/packets/commands/CommandRarityPacket"; import {handleCommandRarityPacketRes} from "../../commands/player/RarityCommand"; +import {CommandTestPacketRes} from "../../../../Lib/src/packets/commands/CommandTestPacket"; +import {handleCommandTestPacketRes} from "../../commands/admin/TestCommand"; export default class CommandHandlers { @packetHandler(CommandPingPacketRes) diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index f9125b857..cdd8bcb27 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -126,8 +126,8 @@ }, "language": { "selectLanguage": "Sélectionnez une langue", - "description": "Utilisez le menu ci-dessous pour changer la langue utilisée par le bot. Cette commande est réservée aux administrateurs du serveur.", - "title": ":earth_africa: Selection de la langue", + "description": "Utilisez le menu ci-dessous pour changer la langue utilisée par le bot sur ce serveur. Cette commande est réservée aux administrateurs du serveur.", + "title": ":earth_africa: Sélection de la langue", "languages": { "en": { "emoji": "🇬🇧", diff --git a/Lib/src/packets/commands/CommandLanguagePacket.ts b/Lib/src/packets/commands/CommandLanguagePacket.ts index 01cedd661..17e606ff4 100644 --- a/Lib/src/packets/commands/CommandLanguagePacket.ts +++ b/Lib/src/packets/commands/CommandLanguagePacket.ts @@ -1,7 +1,8 @@ -export class CommandLanguagePacketReq { +import {DraftBotPacket} from "../DraftBotPacket"; +export class CommandLanguagePacketReq extends DraftBotPacket { } -export class CommandLanguagePacketRes { - +export class CommandLanguagePacketRes extends DraftBotPacket { + hasPermission!: boolean; } \ No newline at end of file From 6e929df29a1360406e9309f1385713a8b38d46d0 Mon Sep 17 00:00:00 2001 From: BastLast Date: Fri, 23 Feb 2024 01:30:22 +0100 Subject: [PATCH 03/12] WIP language command 3 #2273 --- Discord/src/commands/CommandsManager.ts | 4 +-- Discord/src/commands/admin/LanguageCommand.ts | 31 ++++++++++--------- .../handlers/CommandHandlers.ts | 1 - Lib/src/keycloak/KeycloakUser.ts | 2 +- Lib/src/keycloak/KeycloakUtils.ts | 29 +++++++++++++++++ 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index bff03c0e6..b1545c518 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -274,14 +274,14 @@ ${i18n.t("bot:mentionHelp", { if (!interaction.channel) { replyErrorMessage( interaction, - user.attributes.language, + KeycloakUtils.getUserLanguage(user), i18n.t("bot:noChannelAccess", {lang: user.attributes.language}) ) .finally(() => null); return; } if (!interaction.member) { // If in DM, shouldn't happen - interaction.channel.language = user.attributes.language; + interaction.channel.language = KeycloakUtils.getUserLanguage(user); CommandsManager.handlePrivateMessage(interaction) .finally(() => null); return; diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index e0c021941..14b47fc34 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -4,39 +4,42 @@ import {ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; import i18n from "../../translations/i18n"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; -import { StringConstants } from "../../../../Lib/src/constants/StringConstants"; -import { KeycloakUser } from "../../../../Lib/src/keycloak/KeycloakUser"; +import {StringConstants} from "../../../../Lib/src/constants/StringConstants"; import {PermissionsConstants} from "../../constants/PermissionsConstants"; +import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; +import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; +import {keycloakConfig} from "../../bot/DraftBotShard"; /** * Allow an admin to change the prefix the bot uses in a specific server */ -async function getPacket(interaction: DraftbotInteraction): Promise { +async function getPacket(interaction: DraftbotInteraction, keycloakUser: KeycloakUser): Promise { const selectLanguageMenuId = "languageSelectionMenu"; - - const selectLanguageMenuOptions = Object.keys(StringConstants.LANGUAGE).map((key) => { - const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; - return new StringSelectMenuOptionBuilder() - .setLabel(i18n.t(`commands:language.languages.${languageCode}.name` , {lng: interaction.channel.language})) - .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji` , {lng: interaction.channel.language})) - .setValue(languageCode); - }); + const selectLanguageMenuOptions = Object.keys(StringConstants.LANGUAGE) + .map((key) => { + const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; + return new StringSelectMenuOptionBuilder() + .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) + .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) + .setValue(languageCode); + }); const languageSelectionMenu = new StringSelectMenuBuilder() .setCustomId(selectLanguageMenuId) - .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.channel.language})) + .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) .addOptions(selectLanguageMenuOptions); const row = new ActionRowBuilder() .addComponents(languageSelectionMenu); await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.title", { - lng: interaction.channel.language + lng: KeycloakUtils.getUserLanguage(keycloakUser) })) .setDescription(i18n.t("commands:language.description", { - lng: interaction.channel.language + lng: KeycloakUtils.getUserLanguage(keycloakUser) }))], components: [row] }); + await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, StringConstants.LANGUAGE.ENGLISH); return null; } diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 7f8dbb834..32005e1ce 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -15,7 +15,6 @@ import {CommandTestPacketRes} from "../../../../Lib/src/packets/commands/Command import {handleCommandTestPacketRes} from "../../commands/player/TestCommand"; import {CommandRarityPacketRes} from "../../../../Lib/src/packets/commands/CommandRarityPacket"; import {handleCommandRarityPacketRes} from "../../commands/player/RarityCommand"; -import {CommandTestPacketRes} from "../../../../Lib/src/packets/commands/CommandTestPacket"; import {handleCommandTestPacketRes} from "../../commands/admin/TestCommand"; export default class CommandHandlers { diff --git a/Lib/src/keycloak/KeycloakUser.ts b/Lib/src/keycloak/KeycloakUser.ts index 06ecc7529..82fee4d68 100644 --- a/Lib/src/keycloak/KeycloakUser.ts +++ b/Lib/src/keycloak/KeycloakUser.ts @@ -5,7 +5,7 @@ import {Language} from "../Language"; export interface KeycloakUser { access: { [key: string]: boolean[] }, - attributes: { gameUsername: string, language: Language, discordId?: string }, + attributes: { gameUsername: string, language: [Language], discordId?: [string] }, clientConsents?: KeycloakUserConsent[], clientRoles?: { [key: string]: string[] }, createdTimestamp: number, diff --git a/Lib/src/keycloak/KeycloakUtils.ts b/Lib/src/keycloak/KeycloakUtils.ts index 1526d6604..ea0a19c1f 100644 --- a/Lib/src/keycloak/KeycloakUtils.ts +++ b/Lib/src/keycloak/KeycloakUtils.ts @@ -1,6 +1,7 @@ import {KeycloakConfig} from "./KeycloakConfig"; import {KeycloakUserToRegister} from "./KeycloakUserToRegister"; import {KeycloakUser} from "./KeycloakUser"; +import {Language} from "../Language"; export class KeycloakUtils { private static keycloakToken: string | null = null; @@ -222,4 +223,32 @@ export class KeycloakUtils { return id; } + + public static async updateUserLanguage(keycloakConfig: KeycloakConfig, user: KeycloakUser, newLanguage: Language): Promise { + await this.checkAndQueryToken(keycloakConfig); + + // Update the language attribute + const attributes = user.attributes; + attributes.language = [newLanguage]; + + // Send the update request to Keycloak + const res = await fetch(`${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users/${user.id}`, { + method: "PUT", + headers: { + "Authorization": `Bearer ${this.keycloakToken}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + attributes: attributes + }) + }); + + if (!res.ok) { + throw new Error(`Keycloak update language for user '${user.id}' to '${newLanguage}' error: '${JSON.stringify(await res.json())}'`); + } + } + + public static getUserLanguage(user: KeycloakUser): Language { + return user.attributes.language[0]; + } } \ No newline at end of file From f9c59684b77e3b36244d45c12bfbcc242ab63c65 Mon Sep 17 00:00:00 2001 From: BastLast Date: Wed, 28 Feb 2024 23:23:49 +0100 Subject: [PATCH 04/12] Small refacto error managment of interactions --- Discord/src/commands/player/InventoryCommand.ts | 2 +- Discord/src/utils/ErrorUtils.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Discord/src/commands/player/InventoryCommand.ts b/Discord/src/commands/player/InventoryCommand.ts index 372fd4e71..def44300c 100644 --- a/Discord/src/commands/player/InventoryCommand.ts +++ b/Discord/src/commands/player/InventoryCommand.ts @@ -149,7 +149,7 @@ export async function handleCommandInventoryPacketRes(packet: CommandInventoryPa }); const collector = msg.createMessageComponentCollector({ - filter: i => i.customId === buttonId, + filter: i => i.customId === buttonId, // TODO: rename single letter variable to something clearer time: Constants.MESSAGES.COLLECTOR_TIME }); collector.on("collect", async (i: ButtonInteraction) => { diff --git a/Discord/src/utils/ErrorUtils.ts b/Discord/src/utils/ErrorUtils.ts index 5feb53d18..9b0c9dc97 100644 --- a/Discord/src/utils/ErrorUtils.ts +++ b/Discord/src/utils/ErrorUtils.ts @@ -1,4 +1,4 @@ -import {ButtonInteraction, User} from "discord.js"; +import {ButtonInteraction, StringSelectMenuInteraction, User} from "discord.js"; import {DraftBotErrorEmbed} from "../messages/DraftBotErrorEmbed"; import {Language} from "../../../Lib/src/Language"; import {DraftbotInteraction} from "../messages/DraftbotInteraction"; @@ -42,10 +42,10 @@ export async function sendErrorMessage( export async function sendInteractionNotForYou( user: User, - buttonInteraction: ButtonInteraction, + interaction: ButtonInteraction | StringSelectMenuInteraction, language: Language ): Promise { - await buttonInteraction.reply({ + await interaction.reply({ embeds: [ new DraftBotEmbed() .setDescription(i18n.t("error:interactionNotForYou", { lng: language })) From 36c099d5ab2b4fd9df47073df68997d3a2bf7ce6 Mon Sep 17 00:00:00 2001 From: BastLast Date: Wed, 28 Feb 2024 23:24:47 +0100 Subject: [PATCH 05/12] added default language const and language files --- Discord/src/messages/DraftbotInteraction.ts | 3 + Discord/src/translations/i18n.ts | 67 ++++++++++++++++++++- Lib/src/constants/StringConstants.ts | 17 +++--- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index 13c9109c7..498bef1e8 100644 --- a/Discord/src/messages/DraftbotInteraction.ts +++ b/Discord/src/messages/DraftbotInteraction.ts @@ -10,6 +10,7 @@ import { import {RawInteractionData, RawWebhookData} from "discord.js/typings/rawDataTypes"; import i18n from "../translations/i18n"; import {Language} from "../../../Lib/src/Language"; +import { StringConstants } from "../../../Lib/src/constants/StringConstants"; type DraftbotInteractionWithoutSendCommands = new(client: Client, data: RawInteractionData) => Omit; const DraftbotInteractionWithoutSendCommands: DraftbotInteractionWithoutSendCommands = CommandInteraction as unknown as DraftbotInteractionWithoutSendCommands; @@ -26,6 +27,8 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands // @ts-ignore private _channel: DraftbotChannel; + public userLanguage: Language = StringConstants.DEFAULT_LANGUAGE; + private _replyEdited = false; /** diff --git a/Discord/src/translations/i18n.ts b/Discord/src/translations/i18n.ts index 45703a234..303c2d10f 100644 --- a/Discord/src/translations/i18n.ts +++ b/Discord/src/translations/i18n.ts @@ -1,23 +1,52 @@ import * as i18next from "i18next"; import * as enBot from "../../../Lang/en/bot.json"; import * as frBot from "../../../Lang/fr/bot.json"; +import * as deBot from "../../../Lang/de/bot.json"; +import * as esBot from "../../../Lang/es/bot.json"; +import * as ptBot from "../../../Lang/pt/bot.json"; +import * as itBot from "../../../Lang/it/bot.json"; import * as enCommands from "../../../Lang/en/commands.json"; import * as frCommands from "../../../Lang/fr/commands.json"; +import * as deCommands from "../../../Lang/de/commands.json"; +import * as esCommands from "../../../Lang/es/commands.json"; +import * as ptCommands from "../../../Lang/pt/commands.json"; +import * as itCommands from "../../../Lang/it/commands.json"; +import * as deDiscordBuilder from "../../../Lang/de/discordBuilder.json"; +import * as esDiscordBuilder from "../../../Lang/es/discordBuilder.json"; +import * as ptDiscordBuilder from "../../../Lang/pt/discordBuilder.json"; +import * as itDiscordBuilder from "../../../Lang/it/discordBuilder.json"; import * as enDiscordBuilder from "../../../Lang/en/discordBuilder.json"; import * as frDiscordBuilder from "../../../Lang/fr/discordBuilder.json"; import * as enError from "../../../Lang/en/error.json"; import * as frError from "../../../Lang/fr/error.json"; +import * as deError from "../../../Lang/de/error.json"; +import * as esError from "../../../Lang/es/error.json"; +import * as ptError from "../../../Lang/pt/error.json"; +import * as itError from "../../../Lang/it/error.json"; +import * as deItems from "../../../Lang/de/items.json"; +import * as esItems from "../../../Lang/es/items.json"; +import * as ptItems from "../../../Lang/pt/items.json"; +import * as itItems from "../../../Lang/it/items.json"; import * as enItems from "../../../Lang/en/items.json"; import * as frItems from "../../../Lang/fr/items.json"; import * as enModels from "../../../Lang/en/models.json"; +import * as esModels from "../../../Lang/es/models.json"; import * as frModels from "../../../Lang/fr/models.json"; +import * as ptModels from "../../../Lang/pt/models.json"; +import * as itModels from "../../../Lang/it/models.json"; +import * as deModels from "../../../Lang/de/models.json"; import * as enEvents from "../../../Lang/en/events.json"; import * as frEvents from "../../../Lang/fr/events.json"; +import * as deEvents from "../../../Lang/de/events.json"; +import * as esEvents from "../../../Lang/es/events.json"; +import * as ptEvents from "../../../Lang/pt/events.json"; +import * as itEvents from "../../../Lang/it/events.json"; +import {StringConstants} from "../../../Lib/src/constants/StringConstants"; // Todo load automatically modules i18next.init({ - fallbackLng: "fr", + fallbackLng: StringConstants.DEFAULT_LANGUAGE, resources: { en: { bot: enBot, @@ -36,6 +65,42 @@ i18next.init({ items: frItems, models: frModels, events: frEvents + }, + de: { + bot: deBot, + commands: deCommands, + discordBuilder: deDiscordBuilder, + error: deError, + items: deItems, + models: deModels, + events: deEvents + }, + es: { + bot: esBot, + commands: esCommands, + discordBuilder: esDiscordBuilder, + error: esError, + items: esItems, + models: esModels, + events: esEvents + }, + pt: { + bot: ptBot, + commands: ptCommands, + discordBuilder: ptDiscordBuilder, + error: ptError, + items: ptItems, + models: ptModels, + events: ptEvents + }, + it: { + bot: itBot, + commands: itCommands, + discordBuilder: itDiscordBuilder, + error: itError, + items: itItems, + models: itModels, + events: itEvents } } }).then(); diff --git a/Lib/src/constants/StringConstants.ts b/Lib/src/constants/StringConstants.ts index d84149585..4d37d0229 100644 --- a/Lib/src/constants/StringConstants.ts +++ b/Lib/src/constants/StringConstants.ts @@ -12,11 +12,14 @@ export class StringConstants { GERMAN: Language } = { - FRENCH: "fr", - ENGLISH: "en", - ITALIAN: "it", - SPANISH: "es", - PORTUGUESE: "pt", - GERMAN: "de" - }; + FRENCH: "fr", + ENGLISH: "en", + ITALIAN: "it", + SPANISH: "es", + PORTUGUESE: "pt", + GERMAN: "de" + }; + + static readonly DEFAULT_LANGUAGE: Language = StringConstants.LANGUAGE.FRENCH + } \ No newline at end of file From 8ff349232f458c085dbf737c19d14ba460969447 Mon Sep 17 00:00:00 2001 From: BastLast Date: Wed, 28 Feb 2024 23:25:53 +0100 Subject: [PATCH 06/12] language command WIP 4 #2273 --- Discord/src/commands/admin/LanguageCommand.ts | 26 ++++++++++++++++--- Lib/src/keycloak/KeycloakUtils.ts | 4 +++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index 14b47fc34..1279c2242 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -1,6 +1,11 @@ import {ICommand} from "../ICommand"; import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; -import {ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder} from "discord.js"; +import { + ActionRowBuilder, + StringSelectMenuBuilder, + StringSelectMenuInteraction, + StringSelectMenuOptionBuilder +} from "discord.js"; import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; import i18n from "../../translations/i18n"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; @@ -9,6 +14,8 @@ import {PermissionsConstants} from "../../constants/PermissionsConstants"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../../bot/DraftBotShard"; +import {Constants} from "../../Constants"; +import {sendInteractionNotForYou} from "../../utils/ErrorUtils"; /** * Allow an admin to change the prefix the bot uses in a specific server @@ -29,7 +36,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa .addOptions(selectLanguageMenuOptions); const row = new ActionRowBuilder() .addComponents(languageSelectionMenu); - await interaction.reply({ + const msg = await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.title", { lng: KeycloakUtils.getUserLanguage(keycloakUser) @@ -39,7 +46,20 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa }))], components: [row] }); - await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, StringConstants.LANGUAGE.ENGLISH); + + const collector = msg.createMessageComponentCollector({ + filter: menuInteraction => menuInteraction.customId === selectLanguageMenuId, + time: Constants.MESSAGES.COLLECTOR_TIME + }); + + collector.on("collect", async (menuInteraction: StringSelectMenuInteraction) => { + if (menuInteraction.user.id !== interaction.user.id) { + await sendInteractionNotForYou(menuInteraction.user, menuInteraction, KeycloakUtils.getUserLanguage(keycloakUser)); + return; + } + await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, StringConstants.LANGUAGE.ENGLISH); + }); + return null; } diff --git a/Lib/src/keycloak/KeycloakUtils.ts b/Lib/src/keycloak/KeycloakUtils.ts index ea0a19c1f..34d79b7a2 100644 --- a/Lib/src/keycloak/KeycloakUtils.ts +++ b/Lib/src/keycloak/KeycloakUtils.ts @@ -248,6 +248,10 @@ export class KeycloakUtils { } } + /** + * Get the language of a user from its attributes + * @param user + */ public static getUserLanguage(user: KeycloakUser): Language { return user.attributes.language[0]; } From a68d0e981707384fe4cbd7274e7ed1fb9569ec86 Mon Sep 17 00:00:00 2001 From: BastLast Date: Wed, 28 Feb 2024 23:28:19 +0100 Subject: [PATCH 07/12] userLanguage saved in draftbot interaction --- Discord/src/commands/CommandsManager.ts | 4 +- Discord/src/commands/admin/LanguageCommand.ts | 12 +++--- Discord/src/commands/player/BadgesCommand.ts | 4 +- Discord/src/commands/player/HelpCommand.ts | 40 +++++++++---------- Discord/src/commands/player/IdeaCommand.ts | 4 +- .../src/commands/player/InventoryCommand.ts | 16 ++++---- Discord/src/commands/player/ProfileCommand.ts | 16 ++++---- Discord/src/commands/player/RarityCommand.ts | 4 +- Discord/src/commands/player/ReportCommand.ts | 2 +- Discord/src/commands/player/UpdateCommand.ts | 4 +- Discord/src/commands/player/VoteCommand.ts | 4 +- 11 files changed, 55 insertions(+), 55 deletions(-) diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index b1545c518..eabd54a68 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -281,7 +281,7 @@ ${i18n.t("bot:mentionHelp", { return; } if (!interaction.member) { // If in DM, shouldn't happen - interaction.channel.language = KeycloakUtils.getUserLanguage(user); + interaction.userLanguage = KeycloakUtils.getUserLanguage(user); CommandsManager.handlePrivateMessage(interaction) .finally(() => null); return; @@ -391,7 +391,7 @@ ${i18n.t("bot:mentionHelp", { user: interaction.user.id, channel: interaction.channel.id, interaction: interaction.id, - language: interaction.channel.language + language: interaction.userLanguage } }; DiscordWebSocket.socket!.send(JSON.stringify({ diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index 1279c2242..303950761 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -26,23 +26,23 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa .map((key) => { const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; return new StringSelectMenuOptionBuilder() - .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) - .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) + .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: interaction.userLanguage})) + .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: interaction.userLanguage})) .setValue(languageCode); }); const languageSelectionMenu = new StringSelectMenuBuilder() .setCustomId(selectLanguageMenuId) - .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: KeycloakUtils.getUserLanguage(keycloakUser)})) + .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.userLanguage})) .addOptions(selectLanguageMenuOptions); const row = new ActionRowBuilder() .addComponents(languageSelectionMenu); const msg = await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.title", { - lng: KeycloakUtils.getUserLanguage(keycloakUser) + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:language.description", { - lng: KeycloakUtils.getUserLanguage(keycloakUser) + lng: interaction.userLanguage }))], components: [row] }); @@ -54,7 +54,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa collector.on("collect", async (menuInteraction: StringSelectMenuInteraction) => { if (menuInteraction.user.id !== interaction.user.id) { - await sendInteractionNotForYou(menuInteraction.user, menuInteraction, KeycloakUtils.getUserLanguage(keycloakUser)); + await sendInteractionNotForYou(menuInteraction.user, menuInteraction, interaction.userLanguage); return; } await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, StringConstants.LANGUAGE.ENGLISH); diff --git a/Discord/src/commands/player/BadgesCommand.ts b/Discord/src/commands/player/BadgesCommand.ts index 84224b9a2..fe51c997f 100644 --- a/Discord/src/commands/player/BadgesCommand.ts +++ b/Discord/src/commands/player/BadgesCommand.ts @@ -11,10 +11,10 @@ async function getPacket(interaction: DraftbotInteraction): Promise { await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:badges.title", { - lng: interaction.channel.language + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:badges.description", { - lng: interaction.channel.language + lng: interaction.userLanguage }))] }); return null; diff --git a/Discord/src/commands/player/HelpCommand.ts b/Discord/src/commands/player/HelpCommand.ts index d26640ff8..7f3a13522 100644 --- a/Discord/src/commands/player/HelpCommand.ts +++ b/Discord/src/commands/player/HelpCommand.ts @@ -85,46 +85,46 @@ function generateGenericHelpMessage(helpMessage: DraftBotEmbed, interaction: Dra missionCommands, guildCommands, petCommands - } = getCommandByCategories(interaction.channel.language); + } = getCommandByCategories(interaction.userLanguage); helpMessage.formatAuthor(i18n.t("commands:help.helpEmbedTitle", { - lng: interaction.channel.language, + lng: interaction.userLanguage, pseudo: interaction.user.username }), interaction.user); helpMessage.setDescription( `${i18n.t("commands:help.helpEmbedDescription", { - lng: interaction.channel.language, + lng: interaction.userLanguage, helpCommandMention: BotUtils.commandsMentions.get("help"), interpolation: {escapeValue: false} })}\n\u200b` ); helpMessage.addFields([ { - name: i18n.t("commands:help.serverCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.serverCommands", {lng: interaction.userLanguage}), value: `${serverCommands.sort().join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)}` }, { - name: i18n.t("commands:help.utilCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.utilCommands", {lng: interaction.userLanguage}), value: `${utilCommands.sort().join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)}` }, { - name: i18n.t("commands:help.playerCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.playerCommands", {lng: interaction.userLanguage}), value: `${playerCommands.join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)}` }, { - name: i18n.t("commands:help.missionCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.missionCommands", {lng: interaction.userLanguage}), value: `${missionCommands.join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)}` }, { - name: i18n.t("commands:help.guildCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.guildCommands", {lng: interaction.userLanguage}), value: `${guildCommands.sort().join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)}` }, { - name: i18n.t("commands:help.petCommands", {lng: interaction.channel.language}), + name: i18n.t("commands:help.petCommands", {lng: interaction.userLanguage}), value: `${petCommands.sort().join(HelpConstants.COMMAND_SEPARATOR_FOR_GENERAL_DESCRIPTION)} \n\u200b` }, { - name: i18n.t("commands:help.forMoreHelp", {lng: interaction.channel.language}), - value: i18n.t("commands:help.forMoreHelpValue", {lng: interaction.channel.language}) + name: i18n.t("commands:help.forMoreHelp", {lng: interaction.userLanguage}), + value: i18n.t("commands:help.forMoreHelpValue", {lng: interaction.userLanguage}) } ]); } @@ -162,12 +162,12 @@ function generateReplacementObjectForHelpCommand(interaction: DraftbotInteractio const topGloryCommandMention = BotUtils.commandsMentions.get("top guilds"); const mapCommandMention = BotUtils.commandsMentions.get("map"); const petCommandMention = BotUtils.commandsMentions.get("pet"); - const classesCommandMentionString = classesCommandMention ? classesCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.channel.language}); - const topGloryCommandMentionString = topGloryCommandMention ? topGloryCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.channel.language}); - const mapCommandMentionString = mapCommandMention ? mapCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.channel.language}); - const petCommandMentionString = petCommandMention ? petCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.channel.language}); + const classesCommandMentionString = classesCommandMention ? classesCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.userLanguage}); + const topGloryCommandMentionString = topGloryCommandMention ? topGloryCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.userLanguage}); + const mapCommandMentionString = mapCommandMention ? mapCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.userLanguage}); + const petCommandMentionString = petCommandMention ? petCommandMention : i18n.t("error:commandDoesntExist", {lng: interaction.userLanguage}); return { - lng: interaction.channel.language, + lng: interaction.userLanguage, petSellMinPrice, petSellMaxPrice, classesCommandMention: classesCommandMentionString, @@ -203,23 +203,23 @@ async function getPacket(interaction: DraftbotInteraction): Promise { } const commandMention = BotUtils.commandsMentions.get(HelpConstants.COMMANDS_DATA[command as keyof typeof HelpConstants.COMMANDS_DATA].NAME); - const commandMentionString: string = commandMention ? commandMention : i18n.t("error:commandDoesntExist", {lng: interaction.channel.language}); + const commandMentionString: string = commandMention ? commandMention : i18n.t("error:commandDoesntExist", {lng: interaction.userLanguage}); const replacements = generateReplacementObjectForHelpCommand(interaction); if (command === "FIGHT") { - helpMessage.setImage(i18n.t("commands:help.commands.FIGHT.image", {lng: interaction.channel.language})); + helpMessage.setImage(i18n.t("commands:help.commands.FIGHT.image", {lng: interaction.userLanguage})); } helpMessage.setDescription(i18n.t(`commands:help.commands.${command}.description`, replacements)) .setTitle( i18n.t("commands:help.commandEmbedTitle", { - lng: interaction.channel.language, + lng: interaction.userLanguage, emote: HelpConstants.COMMANDS_DATA[command as keyof typeof HelpConstants.COMMANDS_DATA].EMOTE }) ); helpMessage.addFields({ - name: i18n.t("commands:help.usageFieldTitle", {lng: interaction.channel.language}), + name: i18n.t("commands:help.usageFieldTitle", {lng: interaction.userLanguage}), value: commandMentionString, inline: true }); diff --git a/Discord/src/commands/player/IdeaCommand.ts b/Discord/src/commands/player/IdeaCommand.ts index 233f4c70e..edbd9031e 100644 --- a/Discord/src/commands/player/IdeaCommand.ts +++ b/Discord/src/commands/player/IdeaCommand.ts @@ -8,10 +8,10 @@ async function getPacket(interaction: DraftbotInteraction): Promise { await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:idea.title", { - lng: interaction.channel.language + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:idea.description", { - lng: interaction.channel.language + lng: interaction.userLanguage }))] }); return null; diff --git a/Discord/src/commands/player/InventoryCommand.ts b/Discord/src/commands/player/InventoryCommand.ts index def44300c..d499ad30a 100644 --- a/Discord/src/commands/player/InventoryCommand.ts +++ b/Discord/src/commands/player/InventoryCommand.ts @@ -27,7 +27,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa if (!keycloakId) { await interaction.reply({ embeds: [ - new DraftBotErrorEmbed(interaction.user, interaction, interaction.channel.language, i18n.t("error:playerDoesntExist", {lng: interaction.channel.language})) + new DraftBotErrorEmbed(interaction.user, interaction, interaction.userLanguage, i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage})) ] }); return null; @@ -120,8 +120,8 @@ export async function handleCommandInventoryPacketRes(packet: CommandInventoryPa new DraftBotErrorEmbed( interaction.user, interaction, - interaction.channel.language, - i18n.t("error:playerDoesntExist", {lng: interaction.channel.language}) + interaction.userLanguage, + i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}) ) ] }); @@ -132,16 +132,16 @@ export async function handleCommandInventoryPacketRes(packet: CommandInventoryPa let equippedView = true; const buttonId = "switchItems"; - const equippedButtonLabel = i18n.t("commands:inventory.seeEquippedItems", {lng: interaction.channel.language}); - const backupButtonLabel = i18n.t("commands:inventory.seeBackupItems", {lng: interaction.channel.language}); + const equippedButtonLabel = i18n.t("commands:inventory.seeEquippedItems", {lng: interaction.userLanguage}); + const backupButtonLabel = i18n.t("commands:inventory.seeBackupItems", {lng: interaction.userLanguage}); const switchItemsButton = new ButtonBuilder() .setCustomId(buttonId) .setLabel(backupButtonLabel) .setStyle(ButtonStyle.Primary); - const equippedEmbed = getEquippedEmbed(packet, keycloakUser.attributes.gameUsername, interaction.channel.language); - const backupEmbed = getBackupEmbed(packet, keycloakUser.attributes.gameUsername, interaction.channel.language); + const equippedEmbed = getEquippedEmbed(packet, keycloakUser.attributes.gameUsername, interaction.userLanguage); + const backupEmbed = getBackupEmbed(packet, keycloakUser.attributes.gameUsername, interaction.userLanguage); const msg = await interaction.reply({ embeds: [equippedEmbed], @@ -154,7 +154,7 @@ export async function handleCommandInventoryPacketRes(packet: CommandInventoryPa }); collector.on("collect", async (i: ButtonInteraction) => { if (i.user.id !== context.discord?.user) { - await sendInteractionNotForYou(i.user, i, interaction.channel.language); + await sendInteractionNotForYou(i.user, i, interaction.userLanguage); return; } diff --git a/Discord/src/commands/player/ProfileCommand.ts b/Discord/src/commands/player/ProfileCommand.ts index ffd4b9b67..81b9c12eb 100644 --- a/Discord/src/commands/player/ProfileCommand.ts +++ b/Discord/src/commands/player/ProfileCommand.ts @@ -27,7 +27,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa if (user) { const keycloakId = await KeycloakUtils.getKeycloakIdFromDiscordId(keycloakConfig, user.id, user.displayName); if (!keycloakId) { - await interaction.reply({embeds: [new DraftBotErrorEmbed(interaction.user, interaction, interaction.channel.language, i18n.t("error:playerDoesntExist", { lng: interaction.channel.language }))]}); + await interaction.reply({embeds: [new DraftBotErrorEmbed(interaction.user, interaction, interaction.userLanguage, i18n.t("error:playerDoesntExist", { lng: interaction.userLanguage }))]}); return null; } askedPlayer = { keycloakId }; @@ -43,16 +43,16 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa async function sendMessageAllBadgesTooMuchBadges(gameUsername: string, badges: string[], interaction: DraftbotInteraction): Promise { let content = ""; for (const badgeSentence of badges) { - content += `${i18n.t(`commands:profile.badges.${badgeSentence}`, {lng: interaction.channel.language})}\n`; + content += `${i18n.t(`commands:profile.badges.${badgeSentence}`, {lng: interaction.userLanguage})}\n`; } await interaction.followUp({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:profile.badgeDisplay.title", { - lng: interaction.channel.language, + lng: interaction.userLanguage, pseudo: gameUsername })) .setDescription(content + i18n.t("commands:profile.badgeDisplay.numberBadge", { - lng: interaction.channel.language, + lng: interaction.userLanguage, badge: badges.length }))] }); @@ -222,8 +222,8 @@ export async function handleCommandProfilePacketRes(packet: CommandProfilePacket new DraftBotErrorEmbed( interaction.user, interaction, - interaction.channel.language, - i18n.t("error:playerDoesntExist", {lng: interaction.channel.language}) + interaction.userLanguage, + i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}) ) ] }); @@ -238,12 +238,12 @@ export async function handleCommandProfilePacketRes(packet: CommandProfilePacket new DraftBotEmbed() .setColor(packet.data!.color) .setTitle(i18n.t("commands:profile.title", { - lng: interaction.channel.language, + lng: interaction.userLanguage, effect: titleEffect, pseudo: keycloakUser.attributes.gameUsername, level: packet.data?.level })) - .addFields(generateFields(packet, interaction.channel.language)) + .addFields(generateFields(packet, interaction.userLanguage)) ], fetchReply: true }) as Message; diff --git a/Discord/src/commands/player/RarityCommand.ts b/Discord/src/commands/player/RarityCommand.ts index a4d970bce..c7ff4342d 100644 --- a/Discord/src/commands/player/RarityCommand.ts +++ b/Discord/src/commands/player/RarityCommand.ts @@ -17,7 +17,7 @@ export async function handleCommandRarityPacketRes(packet: CommandRarityPacketRe await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:rarity.title", { - lng: interaction.channel.language + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:rarity.rarities", { common: packet.common, @@ -28,7 +28,7 @@ export async function handleCommandRarityPacketRes(packet: CommandRarityPacketRe epic: packet.epic, legendary: packet.legendary, unique: packet.unique, - lng: interaction.channel.language + lng: interaction.userLanguage }))] }); } diff --git a/Discord/src/commands/player/ReportCommand.ts b/Discord/src/commands/player/ReportCommand.ts index 32576f4cd..11363d5e3 100644 --- a/Discord/src/commands/player/ReportCommand.ts +++ b/Discord/src/commands/player/ReportCommand.ts @@ -97,7 +97,7 @@ export async function createBigEventCollector(packet: ReactionCollectorCreationP buttonCollector.on("collect", async (i: ButtonInteraction) => { if (i.user.id !== context.discord?.user) { - await sendInteractionNotForYou(i.user, i, interaction.channel.language); + await sendInteractionNotForYou(i.user, i, interaction.userLanguage); return; } diff --git a/Discord/src/commands/player/UpdateCommand.ts b/Discord/src/commands/player/UpdateCommand.ts index b31593e56..90df5942a 100644 --- a/Discord/src/commands/player/UpdateCommand.ts +++ b/Discord/src/commands/player/UpdateCommand.ts @@ -20,12 +20,12 @@ export async function handleCommandUpdatePacketRes(packet: CommandUpdatePacketRe await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:update.title", { - lng: interaction.channel.language + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:update.description", { coreVersion: packet.coreVersion, discordModuleVersion: process.env.npm_package_version, - lng: interaction.channel.language + lng: interaction.userLanguage }))] }); } diff --git a/Discord/src/commands/player/VoteCommand.ts b/Discord/src/commands/player/VoteCommand.ts index d8564c2ef..9ca93d5e9 100644 --- a/Discord/src/commands/player/VoteCommand.ts +++ b/Discord/src/commands/player/VoteCommand.ts @@ -11,10 +11,10 @@ async function getPacket(interaction: DraftbotInteraction): Promise { await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:vote.title", { - lng: interaction.channel.language + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:vote.description", { - lng: interaction.channel.language + lng: interaction.userLanguage }))] }); return null; From eafff1315a68f52fc45f439a5e181bab7052e2a3 Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 29 Feb 2024 00:19:55 +0100 Subject: [PATCH 08/12] WIP language command 5 #2273 --- Core/src/core/fights/fighter/MonsterFighter.ts | 1 - Discord/src/commands/CommandsManager.ts | 9 ++++----- Discord/src/commands/admin/LanguageCommand.ts | 4 +++- Discord/src/commands/player/InventoryCommand.ts | 3 +-- Discord/src/commands/player/PingCommand.ts | 2 +- Discord/src/commands/player/ProfileCommand.ts | 3 +-- Discord/src/commands/player/ReportCommand.ts | 2 +- Discord/src/messages/DraftBotErrorEmbed.ts | 4 ++-- Discord/src/packetHandlers/handlers/CommandHandlers.ts | 7 +++---- Discord/src/packetHandlers/handlers/ErrorHandler.ts | 6 +++--- Discord/src/utils/ErrorUtils.ts | 9 +++------ Lib/src/constants/StringConstants.ts | 2 +- 12 files changed, 23 insertions(+), 29 deletions(-) diff --git a/Core/src/core/fights/fighter/MonsterFighter.ts b/Core/src/core/fights/fighter/MonsterFighter.ts index f006a4679..9b6cd4d99 100644 --- a/Core/src/core/fights/fighter/MonsterFighter.ts +++ b/Core/src/core/fights/fighter/MonsterFighter.ts @@ -30,7 +30,6 @@ export class MonsterFighter extends Fighter { this.stats.breath = monster.breath; this.stats.maxBreath = monster.maxBreath; this.stats.breathRegen = monster.breathRegen; - this.emoji = monster.emoji; this.monster = monster; this.status = FighterStatus.NOT_STARTED; } diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index eabd54a68..e7e8f648d 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -271,17 +271,16 @@ ${i18n.t("bot:mentionHelp", { } const user = await KeycloakUtils.getOrRegisterDiscordUser(keycloakConfig, discordInteraction.user.id, discordInteraction.user.displayName, discordInteraction.locale.substring(0, 2)); const interaction: DraftbotInteraction = DraftbotInteraction.cast(discordInteraction); + interaction.userLanguage = KeycloakUtils.getUserLanguage(user); if (!interaction.channel) { replyErrorMessage( interaction, - KeycloakUtils.getUserLanguage(user), i18n.t("bot:noChannelAccess", {lang: user.attributes.language}) ) .finally(() => null); return; } if (!interaction.member) { // If in DM, shouldn't happen - interaction.userLanguage = KeycloakUtils.getUserLanguage(user); CommandsManager.handlePrivateMessage(interaction) .finally(() => null); return; @@ -366,19 +365,19 @@ ${i18n.t("bot:mentionHelp", { * @private */ private static async handleCommand(interaction: DraftbotInteraction, user: KeycloakUser): Promise { - const language = user.attributes.language; + const language = interaction.userLanguage; const commandInfo = this.commands.get(interaction.commandName); if (!commandInfo) { - await replyErrorMessage(interaction, StringConstants.LANGUAGE.ENGLISH, i18n.t("bot:command404", {lang: language})); + await replyErrorMessage(interaction, i18n.t("bot:command404", {lang: language})); console.error(`Command "${interaction.commandName}" is not registered`); return; } const channelAccess = this.hasChannelPermission(interaction.channel); if (!channelAccess[0]) { - await replyErrorMessage(interaction, StringConstants.LANGUAGE.ENGLISH, i18n.t(channelAccess[1], {lang: language})); + await replyErrorMessage(interaction, i18n.t(channelAccess[1], {lang: language})); return; } diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index 303950761..0b3b13284 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -16,6 +16,7 @@ import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../../bot/DraftBotShard"; import {Constants} from "../../Constants"; import {sendInteractionNotForYou} from "../../utils/ErrorUtils"; +import { Language } from "../../../../Lib/src/Language"; /** * Allow an admin to change the prefix the bot uses in a specific server @@ -57,7 +58,8 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa await sendInteractionNotForYou(menuInteraction.user, menuInteraction, interaction.userLanguage); return; } - await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, StringConstants.LANGUAGE.ENGLISH); + await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, menuInteraction.values[0] as Language); + menuInteraction.reply("test") }); return null; diff --git a/Discord/src/commands/player/InventoryCommand.ts b/Discord/src/commands/player/InventoryCommand.ts index d499ad30a..8606f20b1 100644 --- a/Discord/src/commands/player/InventoryCommand.ts +++ b/Discord/src/commands/player/InventoryCommand.ts @@ -27,7 +27,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa if (!keycloakId) { await interaction.reply({ embeds: [ - new DraftBotErrorEmbed(interaction.user, interaction, interaction.userLanguage, i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage})) + new DraftBotErrorEmbed(interaction.user, interaction, i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage})) ] }); return null; @@ -120,7 +120,6 @@ export async function handleCommandInventoryPacketRes(packet: CommandInventoryPa new DraftBotErrorEmbed( interaction.user, interaction, - interaction.userLanguage, i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}) ) ] diff --git a/Discord/src/commands/player/PingCommand.ts b/Discord/src/commands/player/PingCommand.ts index 9edef4d2d..4bd55a2e9 100644 --- a/Discord/src/commands/player/PingCommand.ts +++ b/Discord/src/commands/player/PingCommand.ts @@ -10,7 +10,7 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; */ async function getPacket(interaction: DraftbotInteraction): Promise { const packet = makePacket(CommandPingPacketReq, {time: Date.now()}); - await interaction.reply({content: i18n.t("commands:ping.discord.create")}); + await interaction.reply({content: i18n.t("commands:ping.discord.create", {lng: interaction.userLanguage})}); return packet; } diff --git a/Discord/src/commands/player/ProfileCommand.ts b/Discord/src/commands/player/ProfileCommand.ts index 81b9c12eb..8a87ae1cf 100644 --- a/Discord/src/commands/player/ProfileCommand.ts +++ b/Discord/src/commands/player/ProfileCommand.ts @@ -27,7 +27,7 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa if (user) { const keycloakId = await KeycloakUtils.getKeycloakIdFromDiscordId(keycloakConfig, user.id, user.displayName); if (!keycloakId) { - await interaction.reply({embeds: [new DraftBotErrorEmbed(interaction.user, interaction, interaction.userLanguage, i18n.t("error:playerDoesntExist", { lng: interaction.userLanguage }))]}); + await interaction.reply({embeds: [new DraftBotErrorEmbed(interaction.user, interaction, i18n.t("error:playerDoesntExist", { lng: interaction.userLanguage }))]}); return null; } askedPlayer = { keycloakId }; @@ -222,7 +222,6 @@ export async function handleCommandProfilePacketRes(packet: CommandProfilePacket new DraftBotErrorEmbed( interaction.user, interaction, - interaction.userLanguage, i18n.t("error:playerDoesntExist", {lng: interaction.userLanguage}) ) ] diff --git a/Discord/src/commands/player/ReportCommand.ts b/Discord/src/commands/player/ReportCommand.ts index 11363d5e3..9fd633350 100644 --- a/Discord/src/commands/player/ReportCommand.ts +++ b/Discord/src/commands/player/ReportCommand.ts @@ -59,7 +59,7 @@ export async function createBigEventCollector(packet: ReactionCollectorCreationP } const msg = await interaction?.editReply({ - content: i18n.t("commands:report.doEvent", { lng: interaction?.channel.language, event: eventText, pseudo: user.attributes.gameUsername, interpolation: { escapeValue: false } }), + content: i18n.t("commands:report.doEvent", { lng: interaction?.userLanguage, event: eventText, pseudo: user.attributes.gameUsername, interpolation: { escapeValue: false } }), components: [row] }) as Message; diff --git a/Discord/src/messages/DraftBotErrorEmbed.ts b/Discord/src/messages/DraftBotErrorEmbed.ts index 18076ff42..1a62ec1e3 100644 --- a/Discord/src/messages/DraftBotErrorEmbed.ts +++ b/Discord/src/messages/DraftBotErrorEmbed.ts @@ -8,13 +8,13 @@ import {Language} from "../../../Lib/src/Language"; * Default error embed with the title and description formatted. If you just want the red color, see {@link DraftBotEmbed#setErrorColor} */ export class DraftBotErrorEmbed extends DraftBotEmbed { - constructor(user: User, interaction: DraftbotInteraction, language: Language, reason: string, isCancelling = false, isBlockedError = true) { + constructor(user: User, interaction: DraftbotInteraction, reason: string, isCancelling = false, isBlockedError = true) { super(); this.setErrorColor(); this.setDescription(reason); const isOther = interaction.user !== user; - this.formatAuthor(i18n.t(isCancelling ? "error:titleCanceled" : isOther && isBlockedError ? "error:titleBlocked" : "error:titleDidntWork", { lang: language, pseudo: user.username }), user); + this.formatAuthor(i18n.t(isCancelling ? "error:titleCanceled" : isOther && isBlockedError ? "error:titleBlocked" : "error:titleDidntWork", { lng: interaction.userLanguage, pseudo: user.username }), user); } } \ No newline at end of file diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 32005e1ce..5704119f9 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -10,9 +10,8 @@ import {handleCommandProfilePacketRes} from "../../commands/player/ProfileComman import {CommandInventoryPacketRes} from "../../../../Lib/src/packets/commands/CommandInventoryPacket"; import {handleCommandInventoryPacketRes} from "../../commands/player/InventoryCommand"; import {handleCommandUpdatePacketRes} from "../../commands/player/UpdateCommand"; -import { CommandUpdatePacketRes } from "../../../../Lib/src/packets/commands/CommandUpdatePacket"; +import {CommandUpdatePacketRes} from "../../../../Lib/src/packets/commands/CommandUpdatePacket"; import {CommandTestPacketRes} from "../../../../Lib/src/packets/commands/CommandTestPacket"; -import {handleCommandTestPacketRes} from "../../commands/player/TestCommand"; import {CommandRarityPacketRes} from "../../../../Lib/src/packets/commands/CommandRarityPacket"; import {handleCommandRarityPacketRes} from "../../commands/player/RarityCommand"; import {handleCommandTestPacketRes} from "../../commands/admin/TestCommand"; @@ -23,7 +22,7 @@ export default class CommandHandlers { const interaction = DiscordCache.getInteraction(context.discord!.interaction); await interaction?.editReply({ content: i18n.t("commands:ping.discord.edit", { - lang: interaction?.channel.language, + lng: interaction?.userLanguage, totalLatency: Date.now() - packet.clientTime, discordApiLatency: draftBotClient!.ws.ping, shardId: shardId, @@ -53,7 +52,7 @@ export default class CommandHandlers { } @packetHandler(CommandRarityPacketRes) - rarityRes(socket: WebSocket, packet: CommandRarityPacketRes, context: PacketContext): void { + async rarityRes(socket: WebSocket, packet: CommandRarityPacketRes, context: PacketContext): Promise { handleCommandRarityPacketRes(packet, context).then(); } } \ No newline at end of file diff --git a/Discord/src/packetHandlers/handlers/ErrorHandler.ts b/Discord/src/packetHandlers/handlers/ErrorHandler.ts index 305f8a95a..66e28ec8a 100644 --- a/Discord/src/packetHandlers/handlers/ErrorHandler.ts +++ b/Discord/src/packetHandlers/handlers/ErrorHandler.ts @@ -38,7 +38,7 @@ export default class ErrorHandler { let errorReasons = ""; packet.reasons.forEach(reason => { - errorReasons = errorReasons.concat(`${i18n.t(`error:blockedContext.${reason}`, { lng: interaction?.channel.language })}, `); + errorReasons = errorReasons.concat(`${i18n.t(`error:blockedContext.${reason}`, { lng: interaction?.userLanguage })}, `); }); errorReasons = errorReasons.slice(0, -2); @@ -47,8 +47,8 @@ export default class ErrorHandler { .setTitle(i18n.t("error:titleDidntWork", {lng: interaction?.channel?.language, pseudo: originalUser.attributes.gameUsername })) .setDescription( otherPlayer ? - i18n.t("error:anotherPlayerBlocked", { lng: interaction?.channel.language, username: blockedUser.attributes.gameUsername, reasons: errorReasons }) : - i18n.t("error:playerBlocked", { lng: interaction?.channel.language, reasons: errorReasons }) + i18n.t("error:anotherPlayerBlocked", { lng: interaction?.userLanguage, username: blockedUser.attributes.gameUsername, reasons: errorReasons }) : + i18n.t("error:playerBlocked", { lng: interaction?.userLanguage, reasons: errorReasons }) ); if (interaction?.deferred && !interaction.replyEdited) { diff --git a/Discord/src/utils/ErrorUtils.ts b/Discord/src/utils/ErrorUtils.ts index 9b0c9dc97..b0ffda151 100644 --- a/Discord/src/utils/ErrorUtils.ts +++ b/Discord/src/utils/ErrorUtils.ts @@ -8,12 +8,11 @@ import {DraftBotEmbed} from "../messages/DraftBotEmbed"; /** * Reply to an interaction with a given error * @param interaction - * @param language * @param reason */ -export async function replyErrorMessage(interaction: DraftbotInteraction, language: Language, reason: string): Promise { +export async function replyErrorMessage(interaction: DraftbotInteraction, reason: string): Promise { await interaction.reply({ - embeds: [new DraftBotErrorEmbed(interaction.user, interaction, language, reason)], + embeds: [new DraftBotErrorEmbed(interaction.user, interaction, reason)], ephemeral: true }); } @@ -22,7 +21,6 @@ export async function replyErrorMessage(interaction: DraftbotInteraction, langua * Sends an error message * @param user * @param interaction - * @param language * @param reason * @param isCancelling - true if the error is a cancelling error * @param isBlockedError - set to false if you don't want the "this user is blocked" message when selecting a different user than the one who invoked the command @@ -30,13 +28,12 @@ export async function replyErrorMessage(interaction: DraftbotInteraction, langua export async function sendErrorMessage( user: User, interaction: DraftbotInteraction, - language: Language, reason: string, isCancelling = false, isBlockedError = true ): Promise { await interaction.channel.send({ - embeds: [new DraftBotErrorEmbed(user, interaction, language, reason, isCancelling, isBlockedError)] + embeds: [new DraftBotErrorEmbed(user, interaction, reason, isCancelling, isBlockedError)] }); } diff --git a/Lib/src/constants/StringConstants.ts b/Lib/src/constants/StringConstants.ts index 4d37d0229..89fd0fe7e 100644 --- a/Lib/src/constants/StringConstants.ts +++ b/Lib/src/constants/StringConstants.ts @@ -20,6 +20,6 @@ export class StringConstants { GERMAN: "de" }; - static readonly DEFAULT_LANGUAGE: Language = StringConstants.LANGUAGE.FRENCH + static readonly DEFAULT_LANGUAGE: Language = StringConstants.LANGUAGE.ENGLISH } \ No newline at end of file From 51a9c2d762301df1071a1902dea58efbbaef78fe Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 29 Feb 2024 00:29:46 +0100 Subject: [PATCH 09/12] language command end #2273 --- Discord/src/commands/admin/LanguageCommand.ts | 23 ++++++++++++------- Lang/en/commands.json | 2 ++ Lang/fr/commands.json | 2 ++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index 0b3b13284..4d2aa5f5e 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -16,7 +16,7 @@ import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../../bot/DraftBotShard"; import {Constants} from "../../Constants"; import {sendInteractionNotForYou} from "../../utils/ErrorUtils"; -import { Language } from "../../../../Lib/src/Language"; +import {Language} from "../../../../Lib/src/Language"; /** * Allow an admin to change the prefix the bot uses in a specific server @@ -28,22 +28,22 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; return new StringSelectMenuOptionBuilder() .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: interaction.userLanguage})) - .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: interaction.userLanguage})) + .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: interaction.userLanguage})) .setValue(languageCode); }); const languageSelectionMenu = new StringSelectMenuBuilder() .setCustomId(selectLanguageMenuId) - .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.userLanguage})) + .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.userLanguage})) .addOptions(selectLanguageMenuOptions); const row = new ActionRowBuilder() .addComponents(languageSelectionMenu); const msg = await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.title", { - lng: interaction.userLanguage + lng: interaction.userLanguage })) .setDescription(i18n.t("commands:language.description", { - lng: interaction.userLanguage + lng: interaction.userLanguage }))], components: [row] }); @@ -55,13 +55,20 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa collector.on("collect", async (menuInteraction: StringSelectMenuInteraction) => { if (menuInteraction.user.id !== interaction.user.id) { - await sendInteractionNotForYou(menuInteraction.user, menuInteraction, interaction.userLanguage); + await sendInteractionNotForYou(menuInteraction.user, menuInteraction, interaction.userLanguage); return; } await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, menuInteraction.values[0] as Language); - menuInteraction.reply("test") + await menuInteraction.reply({ + embeds: [new DraftBotEmbed() + .setTitle(i18n.t("commands:language.newLanguageSetTitle", { + lng: menuInteraction.values[0] as Language + })) + .setDescription(i18n.t("commands:language.newLanguageSetDescription", { + lng: menuInteraction.values[0] as Language + }))] + }) }); - return null; } diff --git a/Lang/en/commands.json b/Lang/en/commands.json index 1f6126c08..cf6cf8f8f 100644 --- a/Lang/en/commands.json +++ b/Lang/en/commands.json @@ -131,6 +131,8 @@ "language": { "selectLanguage": "Select a new language", "description": "Use the menu below to change the language used by the bot on this discord server. This command can only be used by server administrators.", + "newLanguageSetTitle": "Language changed", + "newLanguageSetDescription": "DraftBot will now speak in english with you! 🇬🇧", "title": ":earth_africa: Language selection", "languages": { "en": { diff --git a/Lang/fr/commands.json b/Lang/fr/commands.json index cdd8bcb27..155caa991 100644 --- a/Lang/fr/commands.json +++ b/Lang/fr/commands.json @@ -128,6 +128,8 @@ "selectLanguage": "Sélectionnez une langue", "description": "Utilisez le menu ci-dessous pour changer la langue utilisée par le bot sur ce serveur. Cette commande est réservée aux administrateurs du serveur.", "title": ":earth_africa: Sélection de la langue", + "newLanguageSetTitle": "Langue changée", + "newLanguageSetDescription": "DraftBot vous parlera désormais en français ! 🥖", "languages": { "en": { "emoji": "🇬🇧", From 7c0b6aebbd12677fed1237ad94a30e02322a6b48 Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 29 Feb 2024 23:35:18 +0100 Subject: [PATCH 10/12] various fixes language command #2273 small fixes language command #2273 more fixes language command #2273 more fixes language command #2273 fix codacy fix eslint --- Core/src/commands/admin/LanguageCommand.ts | 13 ------- Core/src/core/constants/ServersConstants.ts | 5 --- .../core/database/game/migrations/019-v5.ts | 4 +-- Core/src/core/database/game/models/Server.ts | 4 +-- Discord/src/commands/CommandsManager.ts | 24 ++++++------- .../commands/SlashCommandBuilderGenerator.ts | 27 +++++++------- Discord/src/commands/admin/LanguageCommand.ts | 35 ++++++++++--------- Discord/src/commands/player/HelpCommand.ts | 6 ++-- Discord/src/messages/DraftBotErrorEmbed.ts | 1 - Discord/src/messages/DraftbotInteraction.ts | 13 +++---- .../handlers/CommandHandlers.ts | 2 +- Discord/src/translations/i18n.ts | 4 +-- Lang/en/discordBuilder.json | 4 --- Lib/src/Language.ts | 17 +++++++++ Lib/src/constants/StringConstants.ts | 21 ----------- Lib/src/keycloak/KeycloakUtils.ts | 34 ++++++++++-------- Lib/src/utils/TimeUtils.ts | 7 ++-- 17 files changed, 98 insertions(+), 123 deletions(-) delete mode 100644 Core/src/commands/admin/LanguageCommand.ts delete mode 100644 Core/src/core/constants/ServersConstants.ts diff --git a/Core/src/commands/admin/LanguageCommand.ts b/Core/src/commands/admin/LanguageCommand.ts deleted file mode 100644 index 303c7ce8e..000000000 --- a/Core/src/commands/admin/LanguageCommand.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {packetHandler} from "../../core/packetHandlers/PacketHandler"; -import {CommandUpdatePacketReq, CommandUpdatePacketRes} from "../../../../Lib/src/packets/commands/CommandUpdatePacket"; -import {WebsocketClient} from "../../../../Lib/src/instances/WebsocketClient"; -import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket"; - -export default class LanguageCommand { - @packetHandler(CommandUpdatePacketReq) - execute(client: WebsocketClient, packet: CommandUpdatePacketReq, context: PacketContext, response: DraftBotPacket[]): void { - response.push(makePacket(CommandUpdatePacketRes, { - coreVersion: process.env.npm_package_version - })); - } -} \ No newline at end of file diff --git a/Core/src/core/constants/ServersConstants.ts b/Core/src/core/constants/ServersConstants.ts deleted file mode 100644 index fb97fce33..000000000 --- a/Core/src/core/constants/ServersConstants.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {StringConstants} from "../../../../Lib/src/constants/StringConstants"; - -export abstract class ServersConstants { - static readonly DEFAULT_LANGUAGE = StringConstants.LANGUAGE.ENGLISH; -} \ No newline at end of file diff --git a/Core/src/core/database/game/migrations/019-v5.ts b/Core/src/core/database/game/migrations/019-v5.ts index 25d4b0d46..ed07a51cf 100644 --- a/Core/src/core/database/game/migrations/019-v5.ts +++ b/Core/src/core/database/game/migrations/019-v5.ts @@ -8,7 +8,7 @@ import {readFileSync} from "fs"; import {KeycloakUtils} from "../../../../../../Lib/src/keycloak/KeycloakUtils"; import {KeycloakConfig} from "../../../../../../Lib/src/keycloak/KeycloakConfig"; import {logsV5NewIds} from "../../logs/migrations/006-v5"; -import {StringConstants} from "../../../../../../Lib/src/constants/StringConstants"; +import {LANGUAGE} from "../../../../../../Lib/src/Language"; export async function up({context}: { context: QueryInterface }): Promise { const configPath = `${process.cwd()}/config/keycloak.toml`; @@ -29,7 +29,7 @@ clientSecret = "secret" for (let i = 0; i < players.length; ++i) { const player = players[i]; - const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, StringConstants.LANGUAGE.ENGLISH); + const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, LANGUAGE.ENGLISH); await context.sequelize.query(`UPDATE players SET discordUserId = "${user.id}" WHERE discordUserId = "${player.discordUserId}"`); logsV5NewIds.set(player.discordUserId as string, user.id); } diff --git a/Core/src/core/database/game/models/Server.ts b/Core/src/core/database/game/models/Server.ts index 05ee3b9f1..d1ea1cb52 100644 --- a/Core/src/core/database/game/models/Server.ts +++ b/Core/src/core/database/game/models/Server.ts @@ -1,5 +1,5 @@ import {DataTypes, Model, Sequelize} from "sequelize"; -import {ServersConstants} from "../../../constants/ServersConstants"; +import {LANGUAGE} from "../../../../../../Lib/src/Language"; import moment = require("moment"); export class Server extends Model { @@ -33,7 +33,7 @@ export function initModel(sequelize: Sequelize): void { }, language: { type: DataTypes.STRING(2), // eslint-disable-line new-cap - defaultValue: ServersConstants.DEFAULT_LANGUAGE + defaultValue: LANGUAGE.DEFAULT_LANGUAGE }, discordGuildId: { type: DataTypes.STRING(64) // eslint-disable-line new-cap diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index e7e8f648d..10385927f 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -32,7 +32,7 @@ import {DiscordWebSocket} from "../bot/Websocket"; import {PacketContext} from "../../../Lib/src/packets/DraftBotPacket"; import {DiscordCache} from "../bot/DiscordCache"; import {BotUtils} from "../utils/BotUtils"; -import { StringConstants } from "../../../Lib/src/constants/StringConstants"; +import {LANGUAGE} from "../../../Lib/src/Language"; export class CommandsManager { static commands = new Map(); @@ -217,16 +217,16 @@ export class CommandsManager { message.channel.send({ content: ` ${i18n.t("bot:mentionHelp", { - lang: StringConstants.LANGUAGE.ENGLISH, - commandHelp: BotUtils.commandsMentions.get("help"), - commandLanguage: BotUtils.commandsMentions.get("language") - })} + lang: LANGUAGE.ENGLISH, + commandHelp: BotUtils.commandsMentions.get("help"), + commandLanguage: BotUtils.commandsMentions.get("language") + })} ${i18n.t("bot:mentionHelp", { - lang: StringConstants.LANGUAGE.FRENCH, - commandHelp: BotUtils.commandsMentions.get("help"), - commandLanguage: BotUtils.commandsMentions.get("language") - })}` + lang: LANGUAGE.FRENCH, + commandHelp: BotUtils.commandsMentions.get("help"), + commandLanguage: BotUtils.commandsMentions.get("language") + })}` }).then(); }); } @@ -302,7 +302,7 @@ ${i18n.t("bot:mentionHelp", { attachmentList.push(new AttachmentBuilder(Buffer.from(message.content)).setName(`userMessage-${message.author.id}-${message.id}.txt`)); } const supportAlert = i18n.t("bot:supportAlert", { - lang: StringConstants.LANGUAGE.FRENCH, + lang: LANGUAGE.FRENCH, username: escapeUsername(message.author.username), id: message.author.id }) + (message.content.length > Constants.DM.MAX_MESSAGE_LENGTH_ALLOWED @@ -336,7 +336,7 @@ ${i18n.t("bot:mentionHelp", { if (!msg!.getFirstReaction()) { return; } - const language = msg!.getFirstReaction()!.emoji.name === Constants.REACTIONS.ENGLISH_FLAG ? StringConstants.LANGUAGE.ENGLISH : StringConstants.LANGUAGE.FRENCH; + const language = msg!.getFirstReaction()!.emoji.name === Constants.REACTIONS.ENGLISH_FLAG ? LANGUAGE.ENGLISH : LANGUAGE.FRENCH; message.channel.send({ embeds: [new DraftBotEmbed() .formatAuthor(i18n.t("bot:dmHelpMessageTitle", { @@ -354,7 +354,7 @@ ${i18n.t("bot:mentionHelp", { .formatAuthor(Constants.DM.TITLE_SUPPORT, author) .setDescription(message instanceof DraftbotInteraction ? Constants.DM.INTERACTION_SUPPORT : Constants.DM.MESSAGE_SUPPORT); const draftbotChannel = message.channel as unknown as DraftbotChannel; - draftbotChannel.language = StringConstants.LANGUAGE.ENGLISH; + draftbotChannel.language = LANGUAGE.ENGLISH; message instanceof Message ? await helpMessage.send(draftbotChannel) : await helpMessage.reply(message); } diff --git a/Discord/src/commands/SlashCommandBuilderGenerator.ts b/Discord/src/commands/SlashCommandBuilderGenerator.ts index cb7549872..ec3af8f41 100644 --- a/Discord/src/commands/SlashCommandBuilderGenerator.ts +++ b/Discord/src/commands/SlashCommandBuilderGenerator.ts @@ -3,10 +3,9 @@ */ import {ApplicationCommandOptionBase, SlashCommandBuilder} from "@discordjs/builders"; import i18n from "../translations/i18n"; -import {Constants} from "../Constants"; import {SlashCommandStringOption} from "discord.js"; import {TopConstants} from "../../../Lib/src/constants/TopConstants"; -import { StringConstants } from "../../../Lib/src/constants/StringConstants"; +import {LANGUAGE} from "../../../Lib/src/Language"; export class SlashCommandBuilderGenerator { @@ -17,13 +16,13 @@ export class SlashCommandBuilderGenerator { */ static generateBaseCommand(commandSectionName: string): SlashCommandBuilder { return new SlashCommandBuilder() - .setName(i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: StringConstants.LANGUAGE.ENGLISH })) + .setName(i18n.t(`discordBuilder:${commandSectionName}.name`, {lng: LANGUAGE.ENGLISH})) .setNameLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.name`, { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.name`, {lng: LANGUAGE.FRENCH}) }) - .setDescription(i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: StringConstants.LANGUAGE.ENGLISH })) + .setDescription(i18n.t(`discordBuilder:${commandSectionName}.description`, {lng: LANGUAGE.ENGLISH})) .setDescriptionLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.description`, { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.description`, {lng: LANGUAGE.FRENCH}) }); } @@ -34,13 +33,13 @@ export class SlashCommandBuilderGenerator { * @param option Option to populate */ static generateOption(commandSectionName: string, optionSectionName: string, option: T): T { - return option.setName(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: StringConstants.LANGUAGE.ENGLISH })) + return option.setName(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, {lng: LANGUAGE.ENGLISH})) .setNameLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.name`, {lng: LANGUAGE.FRENCH}) }) - .setDescription(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: StringConstants.LANGUAGE.ENGLISH })) + .setDescription(i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, {lng: LANGUAGE.ENGLISH})) .setDescriptionLocalizations({ - fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t(`discordBuilder:${commandSectionName}.options.${optionSectionName}.description`, {lng: LANGUAGE.FRENCH}) }); } @@ -58,16 +57,16 @@ export class SlashCommandBuilderGenerator { return SlashCommandBuilderGenerator.generateOption(commandSectionName, optionSectionName, option) .addChoices( { - name: i18n.t("discordBuilder:scopes.global", { lng: StringConstants.LANGUAGE.ENGLISH }), + name: i18n.t("discordBuilder:scopes.global", {lng: LANGUAGE.ENGLISH}), "name_localizations": { - fr: i18n.t("discordBuilder:scopes.global", { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t("discordBuilder:scopes.global", {lng: LANGUAGE.FRENCH}) }, value: TopConstants.GLOBAL_SCOPE }, { - name: i18n.t("discordBuilder:scopes.server", { lng: StringConstants.LANGUAGE.ENGLISH }), + name: i18n.t("discordBuilder:scopes.server", {lng: LANGUAGE.ENGLISH}), "name_localizations": { - fr: i18n.t("discordBuilder:scopes.server", { lng: StringConstants.LANGUAGE.FRENCH }) + fr: i18n.t("discordBuilder:scopes.server", {lng: LANGUAGE.FRENCH}) } , value: TopConstants.SERVER_SCOPE diff --git a/Discord/src/commands/admin/LanguageCommand.ts b/Discord/src/commands/admin/LanguageCommand.ts index 4d2aa5f5e..c82c50a76 100644 --- a/Discord/src/commands/admin/LanguageCommand.ts +++ b/Discord/src/commands/admin/LanguageCommand.ts @@ -9,34 +9,34 @@ import { import {DraftbotInteraction} from "../../messages/DraftbotInteraction"; import i18n from "../../translations/i18n"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; -import {StringConstants} from "../../../../Lib/src/constants/StringConstants"; -import {PermissionsConstants} from "../../constants/PermissionsConstants"; import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser"; import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils"; import {keycloakConfig} from "../../bot/DraftBotShard"; import {Constants} from "../../Constants"; import {sendInteractionNotForYou} from "../../utils/ErrorUtils"; -import {Language} from "../../../../Lib/src/Language"; +import {LANGUAGE, Language} from "../../../../Lib/src/Language"; /** - * Allow an admin to change the prefix the bot uses in a specific server + * Change the language used by the bot to interact with the player */ async function getPacket(interaction: DraftbotInteraction, keycloakUser: KeycloakUser): Promise { const selectLanguageMenuId = "languageSelectionMenu"; - const selectLanguageMenuOptions = Object.keys(StringConstants.LANGUAGE) - .map((key) => { - const languageCode = StringConstants.LANGUAGE[key as keyof typeof StringConstants.LANGUAGE]; - return new StringSelectMenuOptionBuilder() - .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: interaction.userLanguage})) - .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: interaction.userLanguage})) - .setValue(languageCode); - }); + + const selectLanguageMenuOptions = LANGUAGE.LANGUAGES + .map((languageCode) => new StringSelectMenuOptionBuilder() + .setLabel(i18n.t(`commands:language.languages.${languageCode}.name`, {lng: interaction.userLanguage})) + .setEmoji(i18n.t(`commands:language.languages.${languageCode}.emoji`, {lng: interaction.userLanguage})) + .setValue(languageCode) + ); + const languageSelectionMenu = new StringSelectMenuBuilder() .setCustomId(selectLanguageMenuId) .setPlaceholder(i18n.t("commands:language.selectLanguage", {lng: interaction.userLanguage})) .addOptions(selectLanguageMenuOptions); + const row = new ActionRowBuilder() .addComponents(languageSelectionMenu); + const msg = await interaction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.title", { @@ -54,18 +54,21 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa }); collector.on("collect", async (menuInteraction: StringSelectMenuInteraction) => { + if (menuInteraction.user.id !== interaction.user.id) { await sendInteractionNotForYou(menuInteraction.user, menuInteraction, interaction.userLanguage); return; } + await KeycloakUtils.updateUserLanguage(keycloakConfig, keycloakUser, menuInteraction.values[0] as Language); + await menuInteraction.reply({ embeds: [new DraftBotEmbed() .setTitle(i18n.t("commands:language.newLanguageSetTitle", { - lng: menuInteraction.values[0] as Language + lng: menuInteraction.values[0] as Language })) .setDescription(i18n.t("commands:language.newLanguageSetDescription", { - lng: menuInteraction.values[0] as Language + lng: menuInteraction.values[0] as Language }))] }) }); @@ -75,8 +78,6 @@ async function getPacket(interaction: DraftbotInteraction, keycloakUser: Keycloa export const commandInfo: ICommand = { slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("language"), getPacket, - requirements: { - userPermission: PermissionsConstants.ROLES.USER.ADMINISTRATOR - }, + requirements: {}, mainGuildCommand: false }; diff --git a/Discord/src/commands/player/HelpCommand.ts b/Discord/src/commands/player/HelpCommand.ts index 7f3a13522..a529d2de3 100644 --- a/Discord/src/commands/player/HelpCommand.ts +++ b/Discord/src/commands/player/HelpCommand.ts @@ -5,11 +5,9 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator"; import {DraftBotEmbed} from "../../messages/DraftBotEmbed"; import {SlashCommandBuilder} from "@discordjs/builders"; import {BotUtils} from "../../utils/BotUtils"; -import {Language} from "../../../../Lib/src/Language"; +import {LANGUAGE, Language} from "../../../../Lib/src/Language"; import {PetConstants} from "../../../../Lib/src/constants/PetConstants"; import {HelpConstants} from "../../constants/HelpConstants"; -import {Constants} from "../../Constants"; -import { StringConstants } from "../../../../Lib/src/constants/StringConstants"; /** * Get the list of commands mention from the command data @@ -183,7 +181,7 @@ function generateReplacementObjectForHelpCommand(interaction: DraftbotInteractio */ async function getPacket(interaction: DraftbotInteraction): Promise { const helpMessage = new DraftBotEmbed(); - const command = interaction.options.get(i18n.t("discordBuilder:help.options.commandName.name", {lng: StringConstants.LANGUAGE.ENGLISH})); + const command = interaction.options.get(i18n.t("discordBuilder:help.options.commandName.name", {lng: LANGUAGE.ENGLISH})); const askedCommand = command ? command.value as string : null; if (!askedCommand) { generateGenericHelpMessage(helpMessage, interaction); diff --git a/Discord/src/messages/DraftBotErrorEmbed.ts b/Discord/src/messages/DraftBotErrorEmbed.ts index 1a62ec1e3..3f45e4cbe 100644 --- a/Discord/src/messages/DraftBotErrorEmbed.ts +++ b/Discord/src/messages/DraftBotErrorEmbed.ts @@ -2,7 +2,6 @@ import {DraftBotEmbed} from "./DraftBotEmbed"; import {User} from "discord.js"; import {DraftbotInteraction} from "./DraftbotInteraction"; import i18n from "../translations/i18n"; -import {Language} from "../../../Lib/src/Language"; /** * Default error embed with the title and description formatted. If you just want the red color, see {@link DraftBotEmbed#setErrorColor} diff --git a/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index 498bef1e8..8ded67832 100644 --- a/Discord/src/messages/DraftbotInteraction.ts +++ b/Discord/src/messages/DraftbotInteraction.ts @@ -2,15 +2,16 @@ import { BaseGuildTextChannel, Client, CommandInteraction, - GuildTextBasedChannel, InteractionEditReplyOptions, + GuildTextBasedChannel, + InteractionEditReplyOptions, InteractionReplyOptions, Message, - MessageCreateOptions, MessagePayload + MessageCreateOptions, + MessagePayload } from "discord.js"; import {RawInteractionData, RawWebhookData} from "discord.js/typings/rawDataTypes"; import i18n from "../translations/i18n"; -import {Language} from "../../../Lib/src/Language"; -import { StringConstants } from "../../../Lib/src/constants/StringConstants"; +import {LANGUAGE, Language} from "../../../Lib/src/Language"; type DraftbotInteractionWithoutSendCommands = new(client: Client, data: RawInteractionData) => Omit; const DraftbotInteractionWithoutSendCommands: DraftbotInteractionWithoutSendCommands = CommandInteraction as unknown as DraftbotInteractionWithoutSendCommands; @@ -27,7 +28,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands // @ts-ignore private _channel: DraftbotChannel; - public userLanguage: Language = StringConstants.DEFAULT_LANGUAGE; + public userLanguage: Language = LANGUAGE.DEFAULT_LANGUAGE; private _replyEdited = false; @@ -102,7 +103,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @private */ private async manageFallback(functionPrototype: ReplyFunctionLike): Promise { - const errorText = i18n.t("bot:noSpeakPermission", { lang: this.channel.language }); + const errorText = i18n.t("bot:noSpeakPermission", {lang: this.channel.language}); try { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/Discord/src/packetHandlers/handlers/CommandHandlers.ts b/Discord/src/packetHandlers/handlers/CommandHandlers.ts index 5704119f9..74fc5b387 100644 --- a/Discord/src/packetHandlers/handlers/CommandHandlers.ts +++ b/Discord/src/packetHandlers/handlers/CommandHandlers.ts @@ -53,6 +53,6 @@ export default class CommandHandlers { @packetHandler(CommandRarityPacketRes) async rarityRes(socket: WebSocket, packet: CommandRarityPacketRes, context: PacketContext): Promise { - handleCommandRarityPacketRes(packet, context).then(); + await handleCommandRarityPacketRes(packet, context); } } \ No newline at end of file diff --git a/Discord/src/translations/i18n.ts b/Discord/src/translations/i18n.ts index 303c2d10f..aff9360c6 100644 --- a/Discord/src/translations/i18n.ts +++ b/Discord/src/translations/i18n.ts @@ -41,12 +41,12 @@ import * as deEvents from "../../../Lang/de/events.json"; import * as esEvents from "../../../Lang/es/events.json"; import * as ptEvents from "../../../Lang/pt/events.json"; import * as itEvents from "../../../Lang/it/events.json"; -import {StringConstants} from "../../../Lib/src/constants/StringConstants"; +import {LANGUAGE} from "../../../Lib/src/Language"; // Todo load automatically modules i18next.init({ - fallbackLng: StringConstants.DEFAULT_LANGUAGE, + fallbackLng: LANGUAGE.DEFAULT_LANGUAGE, resources: { en: { bot: enBot, diff --git a/Lang/en/discordBuilder.json b/Lang/en/discordBuilder.json index f34345cca..63fe67efb 100644 --- a/Lang/en/discordBuilder.json +++ b/Lang/en/discordBuilder.json @@ -3,10 +3,6 @@ "description": "Displays information about badges.", "name": "badges" }, - "vote": { - "description": "Displays the link to vote for the bot.", - "name": "vote" - }, "idea": { "description": "Share with us your idea to improve the game.", "name": "idea" diff --git a/Lib/src/Language.ts b/Lib/src/Language.ts index c9ed49678..8c7f56a20 100644 --- a/Lib/src/Language.ts +++ b/Lib/src/Language.ts @@ -1 +1,18 @@ export type Language = "fr" | "en" | "it" | "es" | "de" | "pt"; + +export class LANGUAGE { + static readonly FRENCH: Language = "fr"; + static readonly ENGLISH: Language = "en"; + static readonly ITALIAN: Language = "it"; + static readonly SPANISH: Language = "es"; + static readonly PORTUGUESE: Language = "pt"; + static readonly GERMAN: Language = "de"; + + static get LANGUAGES(): Language[] { + return Object.values(LANGUAGE); + } + + static get DEFAULT_LANGUAGE(): Language { + return LANGUAGE.ENGLISH; + } +} diff --git a/Lib/src/constants/StringConstants.ts b/Lib/src/constants/StringConstants.ts index 89fd0fe7e..6e3b093b9 100644 --- a/Lib/src/constants/StringConstants.ts +++ b/Lib/src/constants/StringConstants.ts @@ -1,25 +1,4 @@ -import {Language} from "../Language"; - export class StringConstants { static readonly PROGRESS_BAR_SIZE = 20; - static readonly LANGUAGE: { - FRENCH: Language, - ENGLISH: Language, - ITALIAN: Language, - SPANISH: Language, - PORTUGUESE: Language, - GERMAN: Language - } - = { - FRENCH: "fr", - ENGLISH: "en", - ITALIAN: "it", - SPANISH: "es", - PORTUGUESE: "pt", - GERMAN: "de" - }; - - static readonly DEFAULT_LANGUAGE: Language = StringConstants.LANGUAGE.ENGLISH - } \ No newline at end of file diff --git a/Lib/src/keycloak/KeycloakUtils.ts b/Lib/src/keycloak/KeycloakUtils.ts index 34d79b7a2..bb5d6f963 100644 --- a/Lib/src/keycloak/KeycloakUtils.ts +++ b/Lib/src/keycloak/KeycloakUtils.ts @@ -159,13 +159,7 @@ export class KeycloakUtils { public static async getOrRegisterDiscordUser(keycloakConfig: KeycloakConfig, discordId: string, gameUsername: string, language: string): Promise { await this.checkAndQueryToken(keycloakConfig); - const res = await fetch(`${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users?q=discordId:${discordId}`, { - method: "GET", - headers: { - "Authorization": `Bearer ${this.keycloakToken}`, - "Content-Type": "application/json" - } - }); + const res = await this.getUserFromDiscordId(keycloakConfig, discordId); if (!res.ok) { throw new Error(`Keycloak retrieve user with attribute 'discordId:${discordId}', error: '${JSON.stringify(await res.json())}'`); @@ -189,6 +183,22 @@ export class KeycloakUtils { return user; } + /** + * Send a get request to keycloak to retrieve a user from it's discordId + * @param keycloakConfig + * @param discordId + * @private + */ + private static async getUserFromDiscordId(keycloakConfig: KeycloakConfig, discordId: string) : Promise { + return await fetch(`${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users?q=discordId:${discordId}`, { + method: "GET", + headers: { + "Authorization": `Bearer ${this.keycloakToken}`, + "Content-Type": "application/json" + } + }); + } + public static async getKeycloakIdFromDiscordId(keycloakConfig: KeycloakConfig, discordId: string, gameUsername: string | null): Promise { const cachedId = KeycloakUtils.keycloakDiscordToIdMap.get(discordId); if (cachedId) { @@ -197,13 +207,7 @@ export class KeycloakUtils { await this.checkAndQueryToken(keycloakConfig); - const res = await fetch(`${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users?q=discordId:${discordId}`, { - method: "GET", - headers: { - "Authorization": `Bearer ${this.keycloakToken}`, - "Content-Type": "application/json" - } - }); + const res = await this.getUserFromDiscordId(keycloakConfig, discordId); if (!res.ok) { throw new Error(`Keycloak retrieve user with attribute 'discordId:${discordId}', error: '${JSON.stringify(await res.json())}'`); @@ -239,7 +243,7 @@ export class KeycloakUtils { "Content-Type": "application/json" }, body: JSON.stringify({ - attributes: attributes + attributes }) }); diff --git a/Lib/src/utils/TimeUtils.ts b/Lib/src/utils/TimeUtils.ts index 847adff37..588e72407 100644 --- a/Lib/src/utils/TimeUtils.ts +++ b/Lib/src/utils/TimeUtils.ts @@ -1,5 +1,4 @@ - -import {StringConstants} from "../constants/StringConstants"; +import {LANGUAGE} from "../Language"; /** * Get the elements to display a remaining time in the given language @@ -12,7 +11,7 @@ function getMinutesDisplayStringConstants(language: string): { hoursDisplay: str secondsDisplay: "s", linkWord: " ", plural: "" - } : language === StringConstants.LANGUAGE.FRENCH ? { + } : language === LANGUAGE.FRENCH ? { hoursDisplay: "heure", minutesDisplay: "minute", secondsDisplay: "seconde", @@ -207,7 +206,7 @@ export function parseTimeDifferenceFooter(date1: number, date2: number, language let parsed = ""; const days = Math.floor(seconds / (24 * 60 * 60)); if (days > 0) { - parsed += days + (language === StringConstants.LANGUAGE.FRENCH ? " J " : " D "); + parsed += days + (language === LANGUAGE.FRENCH ? " J " : " D "); seconds -= days * 24 * 60 * 60; } From 3361e5cb329effd2c9f0cb4954a7b50eeeb7baa9 Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 29 Feb 2024 23:46:37 +0100 Subject: [PATCH 11/12] unifying lang to lng --- Discord/src/commands/CommandsManager.ts | 16 ++++++++-------- Discord/src/messages/DraftbotInteraction.ts | 2 +- Discord/src/utils/ErrorUtils.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index 10385927f..50e0eefe3 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -217,13 +217,13 @@ export class CommandsManager { message.channel.send({ content: ` ${i18n.t("bot:mentionHelp", { - lang: LANGUAGE.ENGLISH, + lng: LANGUAGE.ENGLISH, commandHelp: BotUtils.commandsMentions.get("help"), commandLanguage: BotUtils.commandsMentions.get("language") })} ${i18n.t("bot:mentionHelp", { - lang: LANGUAGE.FRENCH, + lng: LANGUAGE.FRENCH, commandHelp: BotUtils.commandsMentions.get("help"), commandLanguage: BotUtils.commandsMentions.get("language") })}` @@ -275,7 +275,7 @@ ${i18n.t("bot:mentionHelp", { if (!interaction.channel) { replyErrorMessage( interaction, - i18n.t("bot:noChannelAccess", {lang: user.attributes.language}) + i18n.t("bot:noChannelAccess", {lng: interaction.userLanguage}) ) .finally(() => null); return; @@ -302,7 +302,7 @@ ${i18n.t("bot:mentionHelp", { attachmentList.push(new AttachmentBuilder(Buffer.from(message.content)).setName(`userMessage-${message.author.id}-${message.id}.txt`)); } const supportAlert = i18n.t("bot:supportAlert", { - lang: LANGUAGE.FRENCH, + lng: LANGUAGE.FRENCH, username: escapeUsername(message.author.username), id: message.author.id }) + (message.content.length > Constants.DM.MAX_MESSAGE_LENGTH_ALLOWED @@ -340,11 +340,11 @@ ${i18n.t("bot:mentionHelp", { message.channel.send({ embeds: [new DraftBotEmbed() .formatAuthor(i18n.t("bot:dmHelpMessageTitle", { - lang: language, + lng: language, pseudo: escapeUsername(author.username) }), author) .setDescription(i18n.t("bot:dmHelpMessage", { - lang: language, + lng: language, commandHelp: BotUtils.commandsMentions.get("help"), commandRespawn: BotUtils.commandsMentions.get("respawn") }))] @@ -370,14 +370,14 @@ ${i18n.t("bot:mentionHelp", { const commandInfo = this.commands.get(interaction.commandName); if (!commandInfo) { - await replyErrorMessage(interaction, i18n.t("bot:command404", {lang: language})); + await replyErrorMessage(interaction, i18n.t("bot:command404", {lng: language})); console.error(`Command "${interaction.commandName}" is not registered`); return; } const channelAccess = this.hasChannelPermission(interaction.channel); if (!channelAccess[0]) { - await replyErrorMessage(interaction, i18n.t(channelAccess[1], {lang: language})); + await replyErrorMessage(interaction, i18n.t(channelAccess[1], {lng: language})); return; } diff --git a/Discord/src/messages/DraftbotInteraction.ts b/Discord/src/messages/DraftbotInteraction.ts index 8ded67832..4b31af922 100644 --- a/Discord/src/messages/DraftbotInteraction.ts +++ b/Discord/src/messages/DraftbotInteraction.ts @@ -103,7 +103,7 @@ export class DraftbotInteraction extends DraftbotInteractionWithoutSendCommands * @private */ private async manageFallback(functionPrototype: ReplyFunctionLike): Promise { - const errorText = i18n.t("bot:noSpeakPermission", {lang: this.channel.language}); + const errorText = i18n.t("bot:noSpeakPermission", {lng: this.channel.language}); try { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/Discord/src/utils/ErrorUtils.ts b/Discord/src/utils/ErrorUtils.ts index b0ffda151..11df8cde2 100644 --- a/Discord/src/utils/ErrorUtils.ts +++ b/Discord/src/utils/ErrorUtils.ts @@ -47,7 +47,7 @@ export async function sendInteractionNotForYou( new DraftBotEmbed() .setDescription(i18n.t("error:interactionNotForYou", { lng: language })) .setErrorColor() - .formatAuthor(i18n.t("error:titleDidntWork", { lang: language, pseudo: user.username }), user) + .formatAuthor(i18n.t("error:titleDidntWork", { lng: language, pseudo: user.username }), user) ], ephemeral: true }); From 893747fbc9ad1e164cee7b56f4b0612b68a7c17d Mon Sep 17 00:00:00 2001 From: BastLast Date: Thu, 29 Feb 2024 23:57:55 +0100 Subject: [PATCH 12/12] fix language used for mention of the bot --- Core/src/core/database/game/migrations/019-v5.ts | 2 +- Discord/src/commands/CommandsManager.ts | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Core/src/core/database/game/migrations/019-v5.ts b/Core/src/core/database/game/migrations/019-v5.ts index ed07a51cf..a9a874ee5 100644 --- a/Core/src/core/database/game/migrations/019-v5.ts +++ b/Core/src/core/database/game/migrations/019-v5.ts @@ -29,7 +29,7 @@ clientSecret = "secret" for (let i = 0; i < players.length; ++i) { const player = players[i]; - const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, LANGUAGE.ENGLISH); + const user = await KeycloakUtils.getOrRegisterDiscordUser(config.keycloak, player.discordUserId as string, player.discordUserId as string, LANGUAGE.DEFAULT_LANGUAGE); await context.sequelize.query(`UPDATE players SET discordUserId = "${user.id}" WHERE discordUserId = "${player.discordUserId}"`); logsV5NewIds.set(player.discordUserId as string, user.id); } diff --git a/Discord/src/commands/CommandsManager.ts b/Discord/src/commands/CommandsManager.ts index 50e0eefe3..9b04df77d 100644 --- a/Discord/src/commands/CommandsManager.ts +++ b/Discord/src/commands/CommandsManager.ts @@ -214,18 +214,13 @@ export class CommandsManager { if (this.isAMessageFromMassOrMissPing(message) || !this.shouldSendHelpMessage(message, client)) { return; } + const user = await KeycloakUtils.getOrRegisterDiscordUser(keycloakConfig, message.author.id, message.author.username, LANGUAGE.DEFAULT_LANGUAGE); message.channel.send({ - content: ` -${i18n.t("bot:mentionHelp", { - lng: LANGUAGE.ENGLISH, + content: `${i18n.t("bot:mentionHelp", { + lng: KeycloakUtils.getUserLanguage(user), commandHelp: BotUtils.commandsMentions.get("help"), - commandLanguage: BotUtils.commandsMentions.get("language") - })} - -${i18n.t("bot:mentionHelp", { - lng: LANGUAGE.FRENCH, - commandHelp: BotUtils.commandsMentions.get("help"), - commandLanguage: BotUtils.commandsMentions.get("language") + commandLanguage: BotUtils.commandsMentions.get("language"), + interpolation: {escapeValue: false} })}` }).then(); });