From c3d076baaf2510d4b31c85661f94dd613f6a7c0a Mon Sep 17 00:00:00 2001 From: kevinlul <6320810+kevinlul@users.noreply.github.com> Date: Sun, 3 Nov 2024 23:31:00 -0500 Subject: [PATCH] Draft /locale-user command based on /locale (incomplete) #432 --- src/commands/index.ts | 4 +- src/commands/locale-user.ts | 93 +++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/commands/locale-user.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index 9fe9405..5443562 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -7,6 +7,7 @@ import { HelpCommand } from "./help"; import { IdCommand } from "./id"; import { LinkCommand } from "./link"; import { LocaleCommand } from "./locale"; +import { LocaleUserCommand } from "./locale-user"; import { MetagameCommand } from "./metagame"; import { PingCommand } from "./ping"; import { PriceCommand } from "./price"; @@ -34,7 +35,7 @@ export const productionCommandClasses = [ RushDuelCommand, MetagameCommand ]; -export const previewCommandClasses = [QueryCommand]; +export const previewCommandClasses = [QueryCommand, LocaleUserCommand]; export const classes = [ ...productionCommandClasses, @@ -48,6 +49,7 @@ export { IdCommand, LinkCommand, LocaleCommand, + LocaleUserCommand, MetagameCommand, PingCommand, PriceCommand, diff --git a/src/commands/locale-user.ts b/src/commands/locale-user.ts new file mode 100644 index 0000000..cfa42ab --- /dev/null +++ b/src/commands/locale-user.ts @@ -0,0 +1,93 @@ +import { SlashCommandBuilder, SlashCommandStringOption, SlashCommandSubcommandBuilder } from "@discordjs/builders"; +import { + ApplicationIntegrationType, + InteractionContextType, + RESTPostAPIApplicationCommandsJSONBody +} from "discord-api-types/v10"; +import { ChatInputCommandInteraction } from "discord.js"; +import { inject, injectable } from "tsyringe"; +import { c, t, useLocale } from "ttag"; +import { Command } from "../Command"; +import { LOCALE_CHOICES, Locale, LocaleProvider, buildLocalisedChoice, buildLocalisedCommand } from "../locale"; +import { Logger, getLogger } from "../logger"; +import { Metrics } from "../metrics"; +import { replyLatency } from "../utils"; + +@injectable() +export class LocaleUserCommand extends Command { + #logger = getLogger("command:locale-user"); + #locales: LocaleProvider; + + constructor(metrics: Metrics, @inject("LocaleProvider") locales: LocaleProvider) { + super(metrics); + this.#locales = locales; + } + + static override get meta(): RESTPostAPIApplicationCommandsJSONBody { + const builder = buildLocalisedCommand( + new SlashCommandBuilder() + .setIntegrationTypes(ApplicationIntegrationType.UserInstall) + .setContexts(InteractionContextType.BotDM, InteractionContextType.PrivateChannel), + () => c("command-name").t`locale-user`, + () => c("command-description").t`Check or set user-installed Bastion's locale.` + ); + const getSubcommand = buildLocalisedCommand( + new SlashCommandSubcommandBuilder(), + () => c("command-option").t`get`, + () => c("command-option-description").t`Check your user-installed Bastion's locale.` + ); + const setSubcommand = buildLocalisedCommand( + new SlashCommandSubcommandBuilder(), + () => c("command-option").t`set`, + () => c("command-option-description").t`Configure your user-installed Bastion's locale.` + ); + const localeOption = buildLocalisedCommand( + new SlashCommandStringOption().setRequired(true), + () => c("command-option").t`locale`, + () => c("command-option-description").t`The new default language to use for user-installed Bastion.` + ).addChoices( + buildLocalisedChoice("default", () => c("command-option-choice").t`Discord default`), + ...LOCALE_CHOICES + ); + setSubcommand.addStringOption(localeOption); + builder.addSubcommand(getSubcommand).addSubcommand(setSubcommand); + return builder.toJSON(); + } + + protected override get logger(): Logger { + return this.#logger; + } + + private async useLocaleAfterWrite(interaction: ChatInputCommandInteraction): Promise { + const effectiveLocale = await this.#locales.get(interaction); + useLocale(effectiveLocale); + } + + protected override async execute(interaction: ChatInputCommandInteraction): Promise { + let content = ""; + if (interaction.options.getSubcommand() === "get") { + const effectiveLocale = await this.#locales.get(interaction); + const override = await this.#locales.channel(interaction.channelId); + useLocale(effectiveLocale); + if (override) { + content += t`Locale override for this direct message: ${override}`; + content += "\n"; + } + content += t`Your Discord locale: ${interaction.locale}`; + } else { + // subcommand set + const locale = interaction.options.getString("locale", true) as Locale | "default"; + if (locale !== "default") { + await this.#locales.setForChannel(interaction.channelId, locale); + await this.useLocaleAfterWrite(interaction); + content = t`Locale for this direct message overridden with ${locale}. Your Discord setting is ${interaction.locale}.`; + } else { + await this.#locales.setForChannel(interaction.channelId, null); + await this.useLocaleAfterWrite(interaction); + content = t`Locale for this direct message reset to Discord default. Your Discord setting is ${interaction.locale}.`; + } + } + const reply = await interaction.reply({ content, fetchReply: true }); + return replyLatency(reply, interaction); + } +}