Skip to content

Commit

Permalink
feat: improved translation command
Browse files Browse the repository at this point in the history
  • Loading branch information
virtual-designer committed Feb 21, 2023
1 parent 95a7007 commit 09cda31
Show file tree
Hide file tree
Showing 3 changed files with 275 additions and 50 deletions.
4 changes: 2 additions & 2 deletions deploy-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ let commands = [
// UTILS
new SlashCommandBuilder().setName('translate').setDescription('Translates the input text. Powered by Google Translate.')
.addStringOption(option => option.setName('text').setDescription("The text to translate").setRequired(true))
.addStringOption(option => option.setName("from").setDescription("Specify the language of the input text, defaults to automatic detection."))
.addStringOption(option => option.setName("to").setDescription("Specify the language to translate the input text, defaults to English."))
.addStringOption(option => option.setName("from").setDescription("Specify the language of the input text, defaults to automatic detection.").setAutocomplete(true))
.addStringOption(option => option.setName("to").setDescription("Specify the language to translate the input text, defaults to English.").setAutocomplete(true))
.addBooleanOption(option => option.setName("ephemeral").setDescription("Specify if the response should be ephemeral or not, defaults to false.")),

new SlashCommandBuilder().setName('snippet').setDescription('Snippets are instant custom messages')
Expand Down
186 changes: 186 additions & 0 deletions resources/languages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
{
"aa": "Afar",
"ab": "Abkhazian",
"ae": "Avestan",
"af": "Afrikaans",
"ak": "Akan",
"am": "Amharic",
"an": "Aragonese",
"ar": "Arabic",
"as": "Assamese",
"av": "Avaric",
"ay": "Aymara",
"az": "Azerbaijani",
"ba": "Bashkir",
"be": "Belarusian",
"bg": "Bulgarian",
"bh": "Bihari languages",
"bi": "Bislama",
"bm": "Bambara",
"bn": "Bengali",
"bo": "Tibetan",
"br": "Breton",
"bs": "Bosnian",
"ca": "Catalan; Valencian",
"ce": "Chechen",
"ch": "Chamorro",
"co": "Corsican",
"cr": "Cree",
"cs": "Czech",
"cu": "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic",
"cv": "Chuvash",
"cy": "Welsh",
"da": "Danish",
"de": "German",
"dv": "Divehi; Dhivehi; Maldivian",
"dz": "Dzongkha",
"ee": "Ewe",
"el": "Greek, Modern (1453-)",
"en": "English",
"eo": "Esperanto",
"es": "Spanish; Castilian",
"et": "Estonian",
"eu": "Basque",
"fa": "Persian",
"ff": "Fulah",
"fi": "Finnish",
"fj": "Fijian",
"fo": "Faroese",
"fr": "French",
"fy": "Western Frisian",
"ga": "Irish",
"gd": "Gaelic; Scomttish Gaelic",
"gl": "Galician",
"gn": "Guarani",
"gu": "Gujarati",
"gv": "Manx",
"ha": "Hausa",
"he": "Hebrew",
"hi": "Hindi",
"ho": "Hiri Motu",
"hr": "Croatian",
"ht": "Haitian; Haitian Creole",
"hu": "Hungarian",
"hy": "Armenian",
"hz": "Herero",
"ia": "Interlingua (International Auxiliary Language Association)",
"id": "Indonesian",
"ie": "Interlingue; Occidental",
"ig": "Igbo",
"ii": "Sichuan Yi; Nuosu",
"ik": "Inupiaq",
"io": "Ido",
"is": "Icelandic",
"it": "Italian",
"iu": "Inuktitut",
"ja": "Japanese",
"jv": "Javanese",
"ka": "Georgian",
"kg": "Kongo",
"ki": "Kikuyu; Gikuyu",
"kj": "Kuanyama; Kwanyama",
"kk": "Kazakh",
"kl": "Kalaallisut; Greenlandic",
"km": "Central Khmer",
"kn": "Kannada",
"ko": "Korean",
"kr": "Kanuri",
"ks": "Kashmiri",
"ku": "Kurdish",
"kv": "Komi",
"kw": "Cornish",
"ky": "Kirghiz; Kyrgyz",
"la": "Latin",
"lb": "Luxembourgish; Letzeburgesch",
"lg": "Ganda",
"li": "Limburgan; Limburger; Limburgish",
"ln": "Lingala",
"lo": "Lao",
"lt": "Lithuanian",
"lu": "Luba-Katanga",
"lv": "Latvian",
"mg": "Malagasy",
"mh": "Marshallese",
"mi": "Maori",
"mk": "Macedonian",
"ml": "Malayalam",
"mn": "Mongolian",
"mr": "Marathi",
"ms": "Malay",
"mt": "Maltese",
"my": "Burmese",
"na": "Nauru",
"nb": "Bokmål, Norwegian; Norwegian Bokmål",
"nd": "Ndebele, North; North Ndebele",
"ne": "Nepali",
"ng": "Ndonga",
"nl": "Dutch; Flemish",
"nn": "Norwegian Nynorsk; Nynorsk, Norwegian",
"no": "Norwegian",
"nr": "Ndebele, South; South Ndebele",
"nv": "Navajo; Navaho",
"ny": "Chichewa; Chewa; Nyanja",
"oc": "Occitan (post 1500)",
"oj": "Ojibwa",
"om": "Oromo",
"or": "Oriya",
"os": "Ossetian; Ossetic",
"pa": "Panjabi; Punjabi",
"pi": "Pali",
"pl": "Polish",
"ps": "Pushto; Pashto",
"pt": "Portuguese",
"qu": "Quechua",
"rm": "Romansh",
"rn": "Rundi",
"ro": "Romanian; Moldavian; Moldovan",
"ru": "Russian",
"rw": "Kinyarwanda",
"sa": "Sanskrit",
"sc": "Sardinian",
"sd": "Sindhi",
"se": "Northern Sami",
"sg": "Sango",
"si": "Sinhala; Sinhalese",
"sk": "Slovak",
"sl": "Slovenian",
"sm": "Samoan",
"sn": "Shona",
"so": "Somali",
"sq": "Albanian",
"sr": "Serbian",
"ss": "Swati",
"st": "Sotho, Southern",
"su": "Sundanese",
"sv": "Swedish",
"sw": "Swahili",
"ta": "Tamil",
"te": "Telugu",
"tg": "Tajik",
"th": "Thai",
"ti": "Tigrinya",
"tk": "Turkmen",
"tl": "Tagalog",
"tn": "Tswana",
"to": "Tonga (Tonga Islands)",
"tr": "Turkish",
"ts": "Tsonga",
"tt": "Tatar",
"tw": "Twi",
"ty": "Tahitian",
"ug": "Uighur; Uyghur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"ve": "Venda",
"vi": "Vietnamese",
"vo": "Volapük",
"wa": "Walloon",
"wo": "Wolof",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang; Chuang",
"zh": "Chinese",
"zu": "Zulu"
}
135 changes: 87 additions & 48 deletions src/commands/utils/TranslateCommand.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,99 @@
/**
* This file is part of SudoBot.
*
* Copyright (C) 2021-2022 OSN Inc.
*
* SudoBot is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SudoBot is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
*/
* This file is part of SudoBot.
*
* Copyright (C) 2021-2022 OSN Inc.
*
* SudoBot is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SudoBot is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with SudoBot. If not, see <https://www.gnu.org/licenses/>.
*/

import { CommandInteraction, ContextMenuInteraction, Message, MessageContextMenuInteraction, Modal, User } from 'discord.js';
import BaseCommand from '../../utils/structures/BaseCommand';
import DiscordClient from '../../client/Client';
import CommandOptions from '../../types/CommandOptions';
import InteractionOptions from '../../types/InteractionOptions';
import { emoji } from '../../utils/Emoji';
import MessageEmbed from '../../client/MessageEmbed';
import {
ApplicationCommandOptionChoiceData,
AutocompleteInteraction,
CacheType,
CommandInteraction,
Message,
MessageContextMenuInteraction,
User,
} from "discord.js";
import BaseCommand from "../../utils/structures/BaseCommand";
import DiscordClient from "../../client/Client";
import CommandOptions from "../../types/CommandOptions";
import InteractionOptions from "../../types/InteractionOptions";
import { emoji } from "../../utils/Emoji";
import MessageEmbed from "../../client/MessageEmbed";
import AutoCompleteOptions from "../../types/AutoCompleteOptions";
import { readFileSync } from "fs";
import path from "path";

export default class TranslateCommand extends BaseCommand {
supportsInteractions: boolean = true;
supportsContextMenu = true;
languages: Record<string, string> = {};

constructor() {
super('translate', 'settings', ['tr', 'trnsl', 't', "Translate to English"]);
super("translate", "settings", ["tr", "trnsl", "t", "Translate to English"]);
this.languages = JSON.parse(readFileSync(path.resolve(__dirname, "..", "..", "..", "resources", "languages.json")).toString());
}

async run(client: DiscordClient, message: Message | CommandInteraction | MessageContextMenuInteraction, options: CommandOptions | InteractionOptions) {
async autoComplete(client: DiscordClient, interaction: AutocompleteInteraction<CacheType>, options: AutoCompleteOptions): Promise<void> {
const focused = interaction.options.getFocused();
const matches: ApplicationCommandOptionChoiceData[] = [];

for (const code in this.languages) {
if (matches.length >= 24) {
break;
}

if (code === focused || this.languages[code].includes(focused)) {
matches.push({
name: this.languages[code],
value: code,
});
}
}

interaction.respond(matches).catch(console.error);
}

async run(
client: DiscordClient,
message: Message | CommandInteraction | MessageContextMenuInteraction,
options: CommandOptions | InteractionOptions
) {
if (!options.isInteraction && options.args[0] === undefined) {
await message.reply(`${emoji('error')} You must specify the text to translate.`);
await message.reply(`${emoji("error")} You must specify the text to translate.`);
return;
}

if (message instanceof MessageContextMenuInteraction && (!message.targetMessage.content || message.targetMessage.content.trim() === '')) {
await message.reply(`${emoji('error')} The message does not have any text content. Note that embeds cannot be translated.`);
if (message instanceof MessageContextMenuInteraction && (!message.targetMessage.content || message.targetMessage.content.trim() === "")) {
await message.reply(`${emoji("error")} The message does not have any text content. Note that embeds cannot be translated.`);
return;
}

if (!(message instanceof Message))
await message.deferReply({
ephemeral: message instanceof CommandInteraction ? message.options.getBoolean('ephemeral') ?? false : false
ephemeral: message instanceof CommandInteraction ? message.options.getBoolean("ephemeral") ?? false : false,
});

const from = message instanceof CommandInteraction ? message.options.getString('from') ?? 'auto' : 'auto';
const to = message instanceof CommandInteraction ? message.options.getString('to') ?? 'en' : 'en';
const text = message instanceof Message ? message.content.slice(client.config.props[message.guildId!].prefix.length).trim().slice(options.cmdName.length).trim() : (
message instanceof CommandInteraction ? message.options.getString('text', true) : message.targetMessage.content
);
const from = message instanceof CommandInteraction ? message.options.getString("from") ?? "auto" : "auto";
const to = message instanceof CommandInteraction ? message.options.getString("to") ?? "en" : "en";
const text =
message instanceof Message
? message.content.slice(client.config.props[message.guildId!].prefix.length).trim().slice(options.cmdName.length).trim()
: message instanceof CommandInteraction
? message.options.getString("text", true)
: message.targetMessage.content;

const { error, translation, response } = await client.translator.translate(text, from, to);

Expand All @@ -63,15 +103,14 @@ export default class TranslateCommand extends BaseCommand {
new MessageEmbed({
color: 0xf14a60,
author: {
name: "Translation Failed"
name: "Translation Failed",
},
description: `${emoji('error')} Couldn't translate that due to an internal error.`,
description: `${emoji("error")} Couldn't translate that due to an internal error.`,
footer: {
text: "Powered by Google Translate",
}
})
.setTimestamp()
]
},
}).setTimestamp(),
],
});

return;
Expand All @@ -83,15 +122,15 @@ export default class TranslateCommand extends BaseCommand {
color: 0x007bff,
author: {
name: message instanceof MessageContextMenuInteraction ? (message.targetMessage.author as User).tag : "Translation",
iconURL: message instanceof MessageContextMenuInteraction ? (message.targetMessage.author as User).displayAvatarURL() : undefined,
iconURL:
message instanceof MessageContextMenuInteraction ? (message.targetMessage.author as User).displayAvatarURL() : undefined,
},
description: translation,
footer: {
text: `Translated from ${response!.data.src} to ${to} • Powered by Google Translate`,
}
})
.setTimestamp()
]
text: `Translated from ${this.languages[response!.data.src]} to ${this.languages[to]} • Powered by Google Translate`,
},
}).setTimestamp(),
],
});
}
}
}

1 comment on commit 09cda31

@vercel
Copy link

@vercel vercel bot commented on 09cda31 Feb 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.