<commit_before>/**
 * @file Language Handler
 * @author <NAME> (a.k.a k3rn31p4nic)
 * @license MIT
 */

/* eslint-disable no-sync */
const fs = require('fs');
const path = require('path');
const Discord = require('discord.js');
const log = require('./logHandler');

const locales = new Discord.Collection();
const languages = fs.readdirSync('./locales/').filter(file => fs.statSync(path.join('./locales/', file)).isDirectory());
const constants = {
  '%bastion%': 'Bastion',
  '%currencyName%': 'Bastion Currency',
  '%_currencyName%': 'Bastion Currencies',
  '%currencySymbol%': 'BC',
  '%bastionSite%': 'https://BastionBot.org',
  '%discordInvLink%': 'https://discord.gg/fzx8fkt'
};

for (let language of languages) {
  log.info(`Loading language: ${language}`);
  const strings = {};
  let stringFiles = fs.readdirSync(`./locales/${language}`);

  for (let stringFile of stringFiles) {
    let file = stringFile.substr(0, stringFile.length - 5);
    log.message(`Loading strings in ${file}`);
    stringFile = require(`../locales/${language}/${stringFile}`);
    strings[file] = stringFile;
  }

  locales.set(language, strings);
  log.info('Done.');
}

/**
 * Used to handle strings of different languages from external files.
 * @module languageHandler
 */
module.exports = class LanguageHandler {
  /**
   * @constructor
   */
  constructor() {
    this.locales = locales;
  }

  /**
   * Returns a list of languages supported by Bastion
   * @function getAvailableLanguages
   * @returns {Array} Array of languages supported by Bastion
   */
  get availableLanguages() {
    return languages;
  }

  /**
   * Returns the error message string for the given key.
   * @function error
   * @param {String} locale The locale of the string
   * @param {String} key The key of the string
   * @param {Boolean} description Whether to return the description or the title
   * @returns {String} The string mapped by the key and namespace
   */
  error(locale, key, description = false, ...vars) {
    if (!this.locales.has(locale)) {
      locale = 'en';
    }

    let namespace, regex = new RegExp(Object.keys(constants).join('|'), 'gi');
    if (description) {
      if (!this.locales.get(locale).errors['descriptions'][key]) {
        return `No string found for '${key}' in error descriptions.`;
      }
      namespace = 'descriptions';
    }
    else {
      if (!this.locales.get(locale).errors['types'][key]) {
        return `No string found for '${key}' in error types.`;
      }
      namespace = 'types';
    }
    return this.locales.get(locale).errors[namespace][key].replace(regex, matched => constants[matched]).substitute(...vars);
  }

  /**
   * Returns the command description string for the given key.
   * @function command
   * @param {String} locale The locale of the string
   * @param {String} module The module that is mapped to the command
   * @param {String} command The command that is mapped to the string
   * @returns {String} The string mapped by the command and module
   */
  command(locale, module, command) {
    if (!this.locales.has(locale)) {
      locale = 'en';
    }

    if (!this.locales.get(locale).modules[module] || !this.locales.get(locale).modules[module][command]) {
      return `No string found for '${command}' command in ${module} module.`;
    }

    return this.locales.get(locale).modules[module][command];
  }
};<commit_msg>Improved language handler * Added Englist as the fallback language for all strings<commit_after>/**
 * @file Language Handler
 * @author <NAME> (a.k.a k3rn31p4nic)
 * @license MIT
 */

/* eslint-disable no-sync */
const fs = require('fs');
const path = require('path');
const Discord = require('discord.js');
const log = require('./logHandler');

const locales = new Discord.Collection();
const languages = fs.readdirSync('./locales/').filter(file => fs.statSync(path.join('./locales/', file)).isDirectory());
const constants = {
  '%bastion%': 'Bastion',
  '%currencyName%': 'Bastion Currency',
  '%_currencyName%': 'Bastion Currencies',
  '%currencySymbol%': 'BC',
  '%bastionSite%': 'https://BastionBot.org',
  '%discordInvLink%': 'https://discord.gg/fzx8fkt'
};

for (let language of languages) {
  log.info(`Loading language: ${language}`);
  const strings = {};
  let stringFiles = fs.readdirSync(`./locales/${language}`);

  for (let stringFile of stringFiles) {
    let file = stringFile.substr(0, stringFile.length - 5);
    log.message(`Loading strings in ${file}`);
    stringFile = require(`../locales/${language}/${stringFile}`);
    strings[file] = stringFile;
  }

  locales.set(language, strings);
  log.info('Done.');
}

/**
 * Used to handle strings of different languages from external files.
 * @module languageHandler
 */
module.exports = class LanguageHandler {
  /**
   * @constructor
   */
  constructor() {
    this.locales = locales;
  }

  /**
   * Returns a list of languages supported by Bastion
   * @function getAvailableLanguages
   * @returns {Array} Array of languages supported by Bastion
   */
  get availableLanguages() {
    return languages;
  }

  /**
   * Returns the error message string for the given key.
   * @function error
   * @param {String} locale The locale of the string
   * @param {String} key The key of the string
   * @param {Boolean} description Whether to return the description or the title
   * @returns {String} The string mapped by the key and namespace
   */
  error(locale, key, description = false, ...vars) {
    if (!this.locales.has(locale)) {
      locale = 'en';
    }

    let namespace, regex = new RegExp(Object.keys(constants).join('|'), 'gi');
    if (description) {
      if (!this.locales.get(locale).errors['descriptions'][key]) {
        if (locale === 'en') {
          return `No string found for '${key}' in error descriptions.`;
        }
        return this.error('en', key, description, ...vars);
      }
      namespace = 'descriptions';
    }
    else {
      if (!this.locales.get(locale).errors['types'][key]) {
        if (locale === 'en') {
          return `No string found for '${key}' in error types.`;
        }
        return this.error('en', key);
      }
      namespace = 'types';
    }
    return this.locales.get(locale).errors[namespace][key].replace(regex, matched => constants[matched]).substitute(...vars);
  }

  /**
   * Returns the command description string for the given key.
   * @function command
   * @param {String} locale The locale of the string
   * @param {String} module The module that is mapped to the command
   * @param {String} command The command that is mapped to the string
   * @returns {String} The string mapped by the command and module
   */
  command(locale, module, command) {
    if (!this.locales.has(locale)) {
      locale = 'en';
    }

    if (!this.locales.get(locale).modules[module] || !this.locales.get(locale).modules[module][command]) {
      if (locale === 'en') {
        return `No string found for '${command}' command in ${module} module.`;
      }
      return command('en', module, command);
    }

    return this.locales.get(locale).modules[module][command];
  }
};
{'fraction_non_alphanumeric': 0.15453905700211118, 'fraction_numerical': 0.0019704433497536944, 'mean_word_length': 3.3702337023370235, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1524336', 'n_tokens_mistral': 2143, 'n_tokens_neox': 2146, 'n_words': 618}