1
votes

I am making Discord bot with Node.js (using Discord.js API), and I've encountered some strange behaviour when running one of my commands ($$server). The thing is that I am using my custom made translation engine for the bot (it is in fact part of the bot itself) and the issue seems to originate from complete nonsense. First of all, I won't include all the code for simplicity. If you want to see how the bot actually works from entire code, go to GitHub repository, where I have uploaded most recent updates. I stripped out unused and non-important code to save some space.

Now, for the issue: The thing is that the same code (excluding my debugging code) works different for different Discord voice channel regions. All regions work pretty much the same, except for the four American regions (US West, East, Central, South). I've look into the region ids, they are correctly interpretted. The thing is, when I set one of the US regions, the first translation it could find (embed footer) suddenly stops working. I tried also setting up debugging code (simple console.log() function), and the thing is this. In server.js, it literally does nothing else than print out the actual Discord voice region. Doesn't affect the function at all. However, in functions.js, the presence of debugging code (just prints out content of the regex output, nothing else) makes the code suddenly stop working at the problematic line (highlighted by comment in functions.js) by all means, not just with US regions set up.

This is content of functions.js (unnecessary code was stripped out):

/*****************************************
 * Joker Discord Bot
 * Made by CZghost/Polda18, 2019
 * ALPHA v0.0.1
 * 
 * File: functions.js
 *****************************************/

const { Permissions } = require("discord.js");
const locales = require("./locales.js");
const literals = require("./literals.js");

const colors = require("colors");

module.exports = {
    // ...

    // Resolve locale string
    resolveLocale: (localeString, localeCode) => {
        localeString = localeString.toLowerCase().trim();

        // Anything else than #locale{<content>} isn't a locale string
        if(!localeString.startsWith('#locale{') || !localeString.endsWith('}')) return localeString;

        if(!literals.locales.includes(localeCode)) return null;     // Could not recognise locale code

        if(Object.prototype.hasOwnProperty.call(literals.locales_map, localeCode))
            localeCode = literals.locales_map[localeCode];          // No country code encountered, map to default country

        // Check a locale string for any matches
        const regex = /#locale\{([a-zA-Z0-9_:]+)\}/g;

        // Debug <-- If this is present, the command doesn't work at all, this is where it gets stuck
        console.log(regex.exec(localeString));

        // Get the content of the brackets and split by colon
        let content = regex.exec(localeString)[1].split(':');    // Problematic line - works or not, depends on the region settings - sounds strange, right?

        // Get the available locales for this locale string
        let availableLocales = content.reduce((o, i) => {
            try {
                return o[i];        // Decompile string to an object reference
            } catch(e) {
                console.error(`Cannot find locale string \`${localeString}\` for language \`${localeCode}\`. Perhaps missing?`);
                console.error(e);
                return undefined;   // If reached an unreachable end, return undefined (safe reference)
            }
        }, locales.locale_strings);

        if(!availableLocales || availableLocales.constructor !== Object) return null;       // Reached an unreachable reference

        // Locale string for this locale code not found => use default locale code
        if(!Object.prototype.hasOwnProperty.call(availableLocales, localeCode)) return availableLocales[locales.default_locale];

        // Get and return the correct locale string
        return availableLocales[localeCode];
    },

    // ...
}

This is content of server.js:

/*****************************************
 * Joker Discord Bot
 * Made by CZghost/Polda18, 2019
 * ALPHA v0.0.1
 * 
 * File: commands/info/server.js
 *****************************************/

const { RichEmbed } = require("discord.js");
const { stripIndents } = require("common-tags");

const { formatDate, createError, resolveLocale } = require("../../functions.js");
const literals = require("../../literals.js");

module.exports = {
    name: 'serverinfo',
    aliases: [ 'server', 'sinfo' ],
    category: 'info',
    help: {
        description: '#locale{help:command:serverinfo:description}',
        args: []
    },
    run: async (client, message, args) => {
        // Check if a locale is set for this guild and fetch that settings
        const server_id = message.guild.id;
        const localeCode = (Object.prototype.hasOwnProperty.call(client.settings.guilds, server_id))
            ? client.settings.guilds[server_id].locale
            : client.settings.guilds.default.locale
            || client.settings.guilds.default.locale;

        // Debug <-- prints out the actual region id to console
        console.log(`\`${message.guild.region}\``);

        const embed = new RichEmbed()
            .setFooter(resolveLocale("#locale{commands:serverinfo:query:footer}", localeCode)   // This is where it gets stuck
                .replace(/\[author\]/g, message.author.tag.replace(/\$/g, '$$$$')), message.author.displayAvatarURL)
            .setTitle(resolveLocale("#locale{commands:serverinfo:query:title}", localeCode))
            .setAuthor(message.guild.name, message.guild.iconURL)
            .setThumbnail(message.guild.iconURL)
            .setColor(literals.region_colors[message.guild.region])

            .addField(resolveLocale("#locale{commands:serverinfo:query:basic_info:caption}", localeCode),
            stripIndents`
                **\\> ${
                    resolveLocale("#locale{commands:serverinfo:query:basic_info:description:id}", localeCode)
                }:** ${server_id}
                **\\> ${
                    resolveLocale("#locale{commands:serverinfo:query:basic_info:description:system_channel}", localeCode)
                }:** ${message.guild.systemChannel}
                **\\> ${
                    resolveLocale("#locale{commands:serverinfo:query:basic_info:description:member_count}", localeCode)
                }:** ${message.guild.memberCount}
                **\\> ${
                    resolveLocale("#locale{commands:serverinfo:query:basic_info:description:region}", localeCode)
                }:** ${literals.region_flags[message.guild.region]} ${resolveLocale(`#locale{regions:${message.guild.region}}`, localeCode)}
            `.trim())

        embed.setTimestamp();

        await message.channel.send(embed);
    }
}

For clarify, this is an actual content of locales.js, which is used for the translations:

/*****************************************
 * Joker Discord Bot
 * Made by CZghost/Polda18, 2019
 * ALPHA v0.0.1
 * 
 * File: locales.js
 * Description:
 * This file contains locale settings
 * for supported languages using ISO 639-1
 * language codes with country locale code
 * 
 * Please send me a feature request for
 * adding another locale code
 *****************************************/

const { stripIndents } = require("common-tags");

// Translations
module.exports = {
    default_locale: 'en-US',
    supported_locales: {
        partially: [],
        completely: [
            'en-US',
            'cs-CZ'
        ]
    },
    locale_strings: {
        regions: {
            'brazil': {
                'en-US': 'Brazil',
                'cs-CZ': 'Brazílie'
            },
            'eu-central': {
                'en-US': 'Central Europe',
                'cs-CZ': 'Střední Evropa'
            },
            'europe': {
                'en-US': 'Europe',
                'cs-CZ': 'Evropa'
            },
            'hongkong': {
                'en-US': 'Hong Kong',
                'cs-CZ': 'Hong Kong'
            },
            'india': {
                'en-US': 'India',
                'cs-CZ': 'Indie'
            },
            'japan': {
                'en-US': 'Japan',
                'cs-CZ': 'Japonsko'
            },
            'russia': {
                'en-US': 'Russia',
                'cs-CZ': 'Rusko'
            },
            'singapore': {
                'en-US': 'Singapore',
                'cs-CZ': 'Singapur'
            },
            'southafrica': {
                'en-US': 'South Africa',
                'cs-CZ': 'Jižní Afrika'
            },
            'sydney': {
                'en-US': 'Sydney',
                'cs-CZ': 'Sydney'
            },
            'us-central': {
                'en-US': 'U.S. Central',
                'cs-CZ': 'Střed USA'
            },
            'us-east': {
                'en-US': 'U.S. East',
                'cs-CZ': 'Východ USA'
            },
            'us-south': {
                'en-US': 'U.S. South',
                'cs-CZ': 'Jih USA'
            },
            'us-west': {
                'en-US': 'U.S. West',
                'cs-CZ': 'Západ USA'
            }
        },
        // ...
        commands: {
            // ...
            serverinfo: {
                query: {
                    footer: {
                        'en-US': 'Queried by [author]',
                        'cs-CZ': 'Vyžádal/-a si [author]'
                    },
                    title: {
                        'en-US': 'Server info',
                        'cs-CZ': 'Informace o serveru'
                    },
                    basic_info: {
                        caption: {
                            'en-US': 'Basic info',
                            'cs-CZ': 'Základní informace'
                        },
                        description: {
                            id: {
                                'en-US': 'Server ID',
                                'cs-CZ': 'ID serveru'
                            },
                            system_channel: {
                                'en-US': 'System channel',
                                'cs-CZ': 'Systémový kanál'
                            },
                            member_count: {
                                'en-US': 'Member count',
                                'cs-CZ': 'Počet členů'
                            },
                            region: {
                                'en-US': 'Region',
                                'cs-CZ': 'Region'
                            }
                        }
                    }
                }
            },
            // ...
        },
        help: {
            // ...
            command: {
                // ...
                serverinfo: {
                    description: {
                        'en-US': 'Returns server information',
                        'cs-CZ': 'Vrátí informace o serveru'
                    }
                }
            }
        }
    }
}

This is the console output:

C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot>node .     
Template locale file found, ignoring
.----------------------------.
|          Commands          |
|----------------------------|
|  Command  |  Load status   |
|-----------|----------------|
| ping.js   | Okay |
| server.js | Okay |
| whois.js  | Okay |
'----------------------------'
.---------------------------------.
|             Events              |
|---------------------------------|
|     Event      |  Load status   |
|----------------|----------------|
| error.js       | Okay |
| guildCreate.js | Okay |
| guildDelete.js | Okay |
| message.js     | Okay |
| ready.js       | Okay |
'---------------------------------'
Bot logged in as `Joker#0156`, user ID: `484988029841440808`
`us-central`
[
  '#locale{commands:serverinfo:query:footer}',
  'commands:serverinfo:query:footer',
  index: 0,
  input: '#locale{commands:serverinfo:query:footer}',
  groups: undefined
]
(node:36692) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '1' of null
    at resolveLocale (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\functions.js:196:47)
    at Object.run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\commands\info\server.js:35:24)
    at run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\events\message.js:59:30)
    at Client.emit (events.js:223:5)
    at MessageCreateHandler.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\handlers\MessageCreate.js:9:34)
    at WebSocketPacketManager.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\WebSocketPacketManager.js:105:65)
    at WebSocketConnection.onPacket (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:333:35)
    at WebSocketConnection.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:296:17)
    at WebSocket.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\ws\lib\event-target.js:120:16)
    at WebSocket.emit (events.js:223:5)
(node:36692) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:36692) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
`sydney`
[
  '#locale{commands:serverinfo:query:footer}',
  'commands:serverinfo:query:footer',
  index: 0,
  input: '#locale{commands:serverinfo:query:footer}',
  groups: undefined
]
(node:36692) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '1' of null
    at resolveLocale (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\functions.js:196:47)
    at Object.run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\commands\info\server.js:35:24)
    at run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\events\message.js:59:30)
    at Client.emit (events.js:223:5)
    at MessageCreateHandler.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\handlers\MessageCreate.js:9:34)
    at WebSocketPacketManager.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\WebSocketPacketManager.js:105:65)
    at WebSocketConnection.onPacket (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:333:35)
    at WebSocketConnection.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:296:17)
    at WebSocket.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\ws\lib\event-target.js:120:16)
    at WebSocket.emit (events.js:223:5)
(node:36692) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
^C
C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot>node .
Template locale file found, ignoring
.----------------------------.
|          Commands          |
|----------------------------|
|  Command  |  Load status   |
|-----------|----------------|
| ping.js   | Okay |
| server.js | Okay |
| whois.js  | Okay |
'----------------------------'
.---------------------------------.
|             Events              |
|---------------------------------|
|     Event      |  Load status   |
|----------------|----------------|
| error.js       | Okay |
| guildCreate.js | Okay |
| guildDelete.js | Okay |
| message.js     | Okay |
| ready.js       | Okay |
'---------------------------------'
Bot logged in as `Joker#0156`, user ID: `484988029841440808`
`sydney`
^C
C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot>node .
Template locale file found, ignoring
.----------------------------.
|          Commands          |
|----------------------------|
|  Command  |  Load status   |
|-----------|----------------|
| ping.js   | Okay |
| server.js | Okay |
| whois.js  | Okay |
'----------------------------'
.---------------------------------.
|             Events              |
|---------------------------------|
|     Event      |  Load status   |
|----------------|----------------|
| error.js       | Okay |
| guildCreate.js | Okay |
| guildDelete.js | Okay |
| message.js     | Okay |
| ready.js       | Okay |
'---------------------------------'
Bot logged in as `Joker#0156`, user ID: `484988029841440808`
`sydney`
[
  '#locale{commands:serverinfo:query:footer}',
  'commands:serverinfo:query:footer',
  index: 0,
  input: '#locale{commands:serverinfo:query:footer}',
  groups: undefined
]
(node:43844) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '1' of null
    at resolveLocale (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\functions.js:196:47)
    at Object.run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\commands\info\server.js:35:24)
    at run (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\events\message.js:59:30)
    at Client.emit (events.js:223:5)
    at MessageCreateHandler.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\handlers\MessageCreate.js:9:34)
    at WebSocketPacketManager.handle (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\packets\WebSocketPacketManager.js:105:65)
    at WebSocketConnection.onPacket (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:333:35)
    at WebSocketConnection.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\discord.js\src\client\websocket\WebSocketConnection.js:296:17)
    at WebSocket.onMessage (C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot\node_modules\ws\lib\event-target.js:120:16)
    at WebSocket.emit (events.js:223:5)
(node:43844) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a 
catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:43844) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
^C
C:\Users\Marek Poláček\Documents\GitHub\Joker-Discord-Chat-Bot>

And for complete sake, this is how the bot responds on the server: Discord bot is going crazy

1

1 Answers

0
votes

Okay, it turns out I didn't expect to have hyphens in the locale codes, and I forgot about them. Didn't include them in the regex :D Yeah, that's dumb.

So the only solution for this was include the hyphen in the regex expression.