import { MessageEmbed } from 'discord.js'; /* TYPES */ type basicObject = {[keys: string]: string}; type URL = string; type bigString = string | string[]; interface embedData { content?: string, embeds: MessageEmbed[] } interface embedField { name: string, value: bigString, inline?: boolean } interface authorData { name: string, url?: string, icon?: string } interface footerData { text: string, icon?: string } interface embedObj { embed: true, content?: string, title?: string, description?: bigString, url?: URL, color?: string, footer?: string | footerData, thumbnail?: URL, image?: URL, author?: string | authorData, fields?: embedField[], timestamp?: boolean | string | number } type LangObj = { [keys:string]: LangObj | embedObj | string } type LangObjWhole = { [langid:string]: LangObj } /* UTIL FUNCS */ function template(str: string, args: basicObject): string { return str.replace(/{\w+}/g, str => { const key = str.substring(1, str.length-1); if (key in args) return args[key]; return key; }); } function bigString(str: bigString): string { if (typeof str === 'object') return str.join('\n'); return str; } function resolveColor(color: string): [number, number, number] { color = color.replace(/[^0-9a-f]/gi, ''); const colorNum: [number, number, number] = [0, 0, 0]; if (color.length === 3 || color.length === 6) { const colorSpl = /([0-9a-f]{1,2})([0-9a-f]{1,2})([0-9a-f]{1,2})/.exec(color); if (!colorSpl) return colorNum; for (let i = 0; i < colorSpl.length && i < colorNum.length; i++) colorNum[i] = parseInt(colorSpl[i], 16); } return colorNum; } function embedObjStr(embedData: embedObj, fallback = ''): string { if (embedData.content !== undefined) return bigString(embedData.content); if (embedData.description !== undefined) return bigString(embedData.description); return fallback; } function embedObjEmbed(embedObj: embedObj, args: basicObject = {}): MessageEmbed { const embed = new MessageEmbed(), { author, color, description, fields, footer, image, thumbnail, timestamp, title, url } = embedObj; if (author !== undefined) { let authorFix: authorData; if (typeof author === 'string') authorFix = { name: template(author, args) }; else { const {name, icon, url} = author; authorFix = { name: template(name, args) }; if (icon !== undefined) authorFix.icon = template(icon, args); if (url !== undefined) authorFix.url = template(url, args); } embed.setAuthor(authorFix); } if (footer !== undefined) { let footerFix: footerData; if (typeof footer === 'string') footerFix = { text: template(footer, args) }; else { const {text, icon} = footer; footerFix = { text: template(text, args) }; if (icon !== undefined) footerFix.icon = template(icon, args); } embed.setFooter(footerFix); } if (color !== undefined) embed.setColor(resolveColor(template(color, args))); if (description !== undefined) embed.setDescription(template(bigString(description), args)); if (image !== undefined) embed.setImage(template(image, args)); if (thumbnail !== undefined) embed.setThumbnail(template(thumbnail, args)); if (title !== undefined) embed.setTitle(template(title, args)); if (url !== undefined) embed.setURL(template(url, args)); if (timestamp === true) embed.setTimestamp(); else if (typeof timestamp === 'string') embed.setTimestamp(new Date(template(timestamp, args))); else if (timestamp !== false) embed.setTimestamp(timestamp); fields?.forEach(field => { embed.addField(template(field.name, args), template(bigString(field.value), args), field.inline); }); return embed; } /* LANG */ const LANG: LangObjWhole = { en: { main: { login: 'Logged in as {user}' }, discord: { botRestart: 'The bot has just restarted, anybody previously in the queue has been reset', create: 'A queue for teams of {teamsize} has been created', close: 'Queue has been closed', join: 'Joined the queue', leave: 'Left the queue' }, api: { player: { embed: true, title: '{name} ({id})', url: 'https://uniteapi.dev/p/{nameEncoded}', timestamp: true, thumbnail: '{avatar}', description: [ 'Level {level}', '{rank} {elo}', '', '**Battles** {battles}', '**Wins** {wins}', '**Win Rate** {winrate}' ] } }, error: { main: { missingToken: 'Missing Discord Token, please enter the bot token into the token file' }, discord: { noQueue: 'There is not an active queue in this channel, type `/open` to create one', noChannel: 'Unable to find channel {channelId} for teams of {teamsize}', noCreate: 'There is already an active queue in this channel for teams of {teamsize}', inQueue: 'You are already in the queue', notInQueue: 'You aren\'t in the queue', notMod: 'Member is not a moderator' }, general: { noMember: 'Unable to retrieve guild member information, please try again', noChannel: 'Unable to retrieve text channel information, please try again' }, api: { noUser: 'Unable to find user' } } } }; /* MAIN */ let LANGID = 'en'; if (!(LANGID in LANG)) throw 'language id does not exist'; export function setLang(langid: string) { if (langid in LANG) LANGID = langid; else throw 'language id does not exist'; } /** * reads language json (just strings) * @param id ex: discord.error.noActiveQueue * @returns language value, defaults to `id` parameter */ export function get(id: string, args: basicObject = {}): string { const keySpl = id.split('.').map(k => k.trim()).filter(k => k); let finding = LANG[LANGID]; for (const key of keySpl) { if (key in finding) { const found = finding[key]; if (typeof found === 'string') return template(found, args); if (found.embed === true) return embedObjStr(found as embedObj, id); finding = found as LangObj; } else break; } return id; } /** * reads language json as an object (could be embed or just string) * @param id ex: discord.error.noActiveQueue * @returns language value, defaults to `id` parameter */ export function getEmbed(id: string, args: basicObject = {}): embedData { const embedData: embedData = { embeds: [] }; const keySpl = id.split('.').map(k => k.trim()).filter(k => k); let finding = LANG[LANGID]; for (const key of keySpl) { if (key in finding) { const found = finding[key]; if (typeof found === 'string') { embedData.content = template(found, args); break; } if (found.embed === true) { const embedObj = found as embedObj, {content} = embedObj, embed = embedObjEmbed(embedObj, args), embedData: embedData = { embeds: [embed] }; if (content !== undefined) embedData.content = content; return embedData; } finding = found as LangObj; } else break; } return embedData; }