From 47da79eefcb9427f20172cf366087c3db7d2874c Mon Sep 17 00:00:00 2001 From: Mylloon Date: Fri, 22 Jul 2022 01:50:30 +0200 Subject: [PATCH] Add comments --- src/commands/loader.ts | 2 +- src/commands/misc/ping.ts | 2 +- src/events/loader.ts | 2 +- src/index.ts | 2 +- src/utils/client.ts | 11 ++++---- src/utils/locales.ts | 59 +++++++++++++++++++++++++++------------ src/utils/misc.ts | 14 +++++++--- 7 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/commands/loader.ts b/src/commands/loader.ts index aa639f5..c606616 100644 --- a/src/commands/loader.ts +++ b/src/commands/loader.ts @@ -3,7 +3,7 @@ import { Routes } from 'discord-api-types/v9'; import { Client } from 'discord.js'; import { readdir } from 'fs/promises'; -/** Load all the commands */ +/** Load all the commands. */ export default async (client: Client) => { const rest = new REST({ version: '9' }).setToken(client.token ?? ''); diff --git a/src/commands/misc/ping.ts b/src/commands/misc/ping.ts index 169c199..26b586e 100644 --- a/src/commands/misc/ping.ts +++ b/src/commands/misc/ping.ts @@ -7,7 +7,7 @@ export default { data: (client: Client) => { const filename = getFilename(__filename); return new SlashCommandBuilder() - .setName(filename) + .setName(filename.toLowerCase()) .setDescription(client.locales.get(client.config.default_lang)?.get(`c_${filename}_desc`) ?? '?') .setNameLocalizations(getLocalizations(client, `c_${filename}_name`)) .setDescriptionLocalizations(getLocalizations(client, `c_${filename}_desc`)); diff --git a/src/events/loader.ts b/src/events/loader.ts index 15f2da0..b33cb65 100644 --- a/src/events/loader.ts +++ b/src/events/loader.ts @@ -1,7 +1,7 @@ import { Client } from 'discord.js'; import { readdir } from 'fs/promises'; -/** Load all the events */ +/** Load all the events. */ export default async (client: Client) => { const events_categories = (await readdir(__dirname)) .filter(element => !element.endsWith('.js') && !element.endsWith('.ts')); diff --git a/src/index.ts b/src/index.ts index 1457e74..7b85203 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import loadCommands from './commands/loader'; import { logStart } from './utils/misc'; -/** Run the bot */ +/** Run the bot. */ const run = async () => { console.log('Starting Botanique...'); diff --git a/src/utils/client.ts b/src/utils/client.ts index b3e159e..4ec27d7 100644 --- a/src/utils/client.ts +++ b/src/utils/client.ts @@ -3,15 +3,16 @@ import { readFileSync } from 'fs'; import { SlashCommandBuilder } from '@discordjs/builders'; import { loadLocales } from './locales'; -const { version } = JSON.parse(readFileSync('./package.json').toString()); - declare module 'discord.js' { // eslint-disable-next-line no-shadow export interface Client { /** Store the configuration */ config: { + /** Bot version */ version: string, + /** Bot token from env variable */ token_discord: string | undefined, + /** Default lang used */ default_lang: string }, /** Store all the slash commands */ @@ -27,7 +28,7 @@ declare module 'discord.js' { } } -/** Creation of the client and definition of its properties */ +/** Creation of the client and definition of its properties. */ export default async () => { const client: Client = new Client({ intents: [ @@ -36,14 +37,14 @@ export default async () => { }); client.config = { - version: version, + version: JSON.parse(readFileSync('./package.json').toString()).version, token_discord: process.env.TOKEN_DISCORD, default_lang: 'en-US', }; client.commands = new Collection(); - console.log('Localizations progression :'); + console.log('Translations progression :'); client.locales = await loadLocales(client.config.default_lang); return client; diff --git a/src/utils/locales.ts b/src/utils/locales.ts index 52818a7..c82f291 100644 --- a/src/utils/locales.ts +++ b/src/utils/locales.ts @@ -3,33 +3,38 @@ import { readdir } from 'fs/promises'; import { removeExtension } from './misc'; /** - * Load the localizations files into memory + * Load the localizations files into memory. + * + * Show percentage of translations. * @param default_lang default lang * @returns Map of map with all the localizations */ export const loadLocales = async (default_lang: string) => { + // Get files from locales/ directory const old_path = __dirname.split('/'); old_path.pop(); - const files = await readdir(`${old_path.join('/')}/locales`); + // Read JSON files content and load it into the memory const locales = new Map>(); await Promise.all( files.map(async lang => { + // Import file const content: { [key: string]: string } = await import( `../locales/${lang}` ); + // Add it to the memory locales.set( removeExtension(lang), - new Map( - Object.keys(content) - .filter(str => str !== 'default') - .map(str => { - return [str, content[str]]; - }), + new Map(Object.keys(content) + // Ignore the default key + .filter(str => str !== 'default') + .map(str => { + return [str, content[str]]; + }), ) ); }) @@ -43,7 +48,7 @@ export const loadLocales = async (default_lang: string) => { /** * Builds a dictionary, if a translation is not available, - * we fallback to en-US. + * we fallback to default lang. * @param client Client * @param text Name of string to fetch * @returns the dictionary @@ -51,12 +56,16 @@ export const loadLocales = async (default_lang: string) => { export const getLocalizations = (client: Client, text: string) => { const data: Record = {}; + // Load all the localizations client.locales.forEach((locale, lang) => { + // Fetch the text and fallback to default lang if needed + // See getLocale for more info on why we *can* fallback const str = locale.get(text) ?? client.locales.get(client.config.default_lang)?.get(text); + // Store it if defined if (str !== undefined) { - data[lang] = str.toLowerCase(); + data[lang] = str; } }); @@ -65,15 +74,22 @@ export const getLocalizations = (client: Client, text: string) => { /** * Return the locale data for a lang, - * fallback to default language when a string isn't available + * fallback to default language when a string isn't available. * @param client Client * @param lang Lang to fetch * @returns the map with the desired languaged clogged with the default one */ export const getLocale = (client: Client, lang: string) => { + // Load default lang const default_locales = client.locales.get(client.config.default_lang); + // Load desired lang const desired_locales = client.locales.get(lang); + // Get text and fallback to default lang if needed + // + // We can fallback to the default one without any problem + // because we make sure that the default language always contains + // the desired text, and that the other languages are only translations const locales = new Map(); default_locales?.forEach((_, key) => { locales.set(key, desired_locales?.get(key) ?? default_locales.get(key)); @@ -83,15 +99,15 @@ export const getLocale = (client: Client, lang: string) => { }; /** - * Show percentage of translation progression + * Show percentage of translation progression. * * Raise an error if the default lang isn't - * the lang with most text + * the lang with most text. * @param locales Locales loaded * @param default_lang default lang * @returns void */ -export const checkLocales = +const checkLocales = async (locales: Map>, default_lang: string) => { // Associate each lang with the number of locale it has let locales_size = new Map(); @@ -108,6 +124,10 @@ async (locales: Map>, default_lang: string) => { const [max_size] = locales_size.values(); const default_lang_size = locales_size.get(default_lang) ?? 0; if (max_size > default_lang_size) { + // Throw error because in this case we are sure than the security + // explained in getLocale isn't true. + // However, it is possible that this condition is true + // and the security is poor, but it's better than nothing. throw new Error( `The default locale (${default_lang} = ${default_lang_size}) isn't complete ` + `(${max_size_name} = ${max_size}).` @@ -122,26 +142,29 @@ async (locales: Map>, default_lang: string) => { const bar_size = 4; locales_size.forEach((size, lang) => { const percentage = (size / max_size) * 100; + // Colored bar part const blocks = ' '.repeat(percentage / bar_size); + // Blank bar part const blank = ' '.repeat((100 - percentage) / bar_size); const color = () => { switch (true) { case percentage <= 25: - // red + // Red return '\x1b[41m'; case percentage <= 50: - // mangeta + // Mangeta return '\x1b[45m'; case percentage <= 75: - // cyan + // Cyan return '\x1b[46m'; case percentage <= 100: - // green + // Green return '\x1b[42m'; default: return ''; } }; + console.log(`${lang} | ${color()}${blocks}\x1b[0m${blank} | ${percentage}%`); }); }; diff --git a/src/utils/misc.ts b/src/utils/misc.ts index ef4bbee..0f76dd4 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -1,5 +1,5 @@ /** - * Log module status + * Log module status. * @param {string} name Module name * @param {boolean} status Module status * @returns String @@ -9,18 +9,24 @@ export const logStart = (name: string, status: boolean) => { }; /** - * Filename without path and extension + * Filename without path and extension. * @param path __filename * @returns string */ export const getFilename = (path: string) => { const path_list = path.split('/'); - return path_list[path_list.length - 1].split('.')[0]; + // Check if filename exist + const filename_with_ext = path_list.pop(); + if (filename_with_ext === undefined) { + throw new Error(`Filename error: don't exist in ${path}`); + } + + return removeExtension(filename_with_ext); }; /** - * Remove extension from a filename + * Remove extension from a filename. * @param filename string of the filename with an extension * @returns string of the filename without an extension */