Skip to content

Commit

Permalink
Add Lang singleton, update help command to use localized command info
Browse files Browse the repository at this point in the history
  • Loading branch information
zajrik committed Jun 12, 2017
1 parent 0446f63 commit e0514dc
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 24 deletions.
12 changes: 11 additions & 1 deletion src/client/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { StorageProviderConstructor } from '../types/StorageProviderConstructor'
import { BaseCommandName } from '../types/BaseCommandName';
import { Logger, logger } from '../util/logger/Logger';
import { ListenerUtil } from '../util/ListenerUtil';
import { Lang } from '../localization/Lang';

const { on, once, registerListeners } = ListenerUtil;

Expand All @@ -49,6 +50,7 @@ export class Client extends Discord.Client
public readonly name: string;
public readonly commandsDir: string;
public readonly owner: string | string[];
public readonly defaultLang: string;
public readonly statusText: string;
public readonly readyText: string;
public readonly unknownCommandError: boolean;
Expand Down Expand Up @@ -102,6 +104,12 @@ export class Client extends Discord.Client
*/
this.commandsDir = path.resolve(options.commandsDir) || null;

/**
* Default language to use for localization
* @type {string}
*/
this.defaultLang = options.defaultLang || 'en_us';

/**
* Status text for the client
* @type {string}
Expand Down Expand Up @@ -212,11 +220,13 @@ export class Client extends Discord.Client
if (!this.commandsDir && !this.passive) throw new Error('A directory from which to load commands must be provided via commandsDir');
if (!(this.owner instanceof Array)) throw new TypeError('Client config `owner` field must be an array of user ID strings.');

Lang.createInstance(this);

// Load commands
if (!this.passive)
{
this.loadCommand('all');
this._commandLoader.loadLocalizations();
Lang.loadCommandLocalizations();
}

registerListeners(this);
Expand Down
2 changes: 0 additions & 2 deletions src/command/Command.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { PermissionResolvable, Permissions, Message } from 'discord.js';
import { Client } from '../client/Client';
import { MiddlewareFunction } from '../types/MiddlewareFunction';
import { LocalizedCommandInfo } from '../types/LocalizedCommandInfo';
import { CommandInfo } from '../types/CommandInfo';
import { RateLimiter } from './RateLimiter';
import { ArgOpts } from '../types/ArgOpts';
Expand Down Expand Up @@ -30,7 +29,6 @@ export class Command<T extends Client = Client>
public overloads: string;

public _classloc: string;
public translation?: { [name: string]: LocalizedCommandInfo };
public readonly _rateLimiter: RateLimiter;
public readonly _middleware: MiddlewareFunction[];

Expand Down
16 changes: 0 additions & 16 deletions src/command/CommandLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,6 @@ export class CommandLoader<T extends Client>
return true;
}

/**
* Load any command localizations and assign them to commands
*/
public loadLocalizations(): void
{
for (const command of this._client.commands.values())
{
let localizationFile: string = glob.sync(`${this._client.commandsDir}/**/${command.name}.lang.json`)[0];
if (!localizationFile) continue;
let localizations: { [name: string]: LocalizedCommandInfo };
try { localizations = require(localizationFile); }
catch (err) { continue; }
command.translation = localizations;
}
}

/**
* Get the Command class from an attempted Command class import
*/
Expand Down
17 changes: 13 additions & 4 deletions src/command/base/Help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { LocalizedCommandInfo } from '../../types/LocalizedCommandInfo';
import { Message } from '../../types/Message';
import { Util } from '../../util/Util';
import { Command } from '../Command';
import { Lang } from '../../localization/Lang';
import { Collection, RichEmbed } from 'discord.js';

export default class extends Command
Expand All @@ -20,6 +22,11 @@ export default class extends Command
if (this.client.selfbot) message.delete();
const dm: boolean = message.channel.type !== 'text';
const mentionName: string = `@${this.client.user.tag}`;
const lang: string = dm ? this.client.defaultLang
: await message.guild.storage.settings.get('lang');

const cInfo: (command: Command) => LocalizedCommandInfo =
(command: Command) => Lang.getCommandInfo(command, lang);

let command: Command;
let output: string = '';
Expand All @@ -37,7 +44,7 @@ export default class extends Command

const widest: number = usableCommands.map(c => c.name.length).reduce((a, b) => Math.max(a, b));
let commandList: string = usableCommands.map(c =>
`${Util.padRight(c.name, widest + 1)}${c.guildOnly ? '*' : ' '}: ${c.desc}`).sort().join('\n');
`${Util.padRight(c.name, widest + 1)}${c.guildOnly ? '*' : ' '}: ${cInfo(c).desc}`).sort().join('\n');

output = preText + commandList + postText;
if (output.length >= 1024)
Expand All @@ -63,14 +70,16 @@ export default class extends Command

if (!command) output = `A command by that name could not be found or you do\n`
+ `not have permission to view it.`;
else output = '```ldif\n'

const info: LocalizedCommandInfo = cInfo(command);
if (command) output = '```ldif\n'
+ (command.guildOnly ? '[Server Only]\n' : '')
+ (command.ownerOnly ? '[Owner Only]\n' : '')
+ `Command: ${command.name}\n`
+ `Description: ${command.desc}\n`
+ `Description: ${info.desc}\n`
+ (command.aliases.length > 0 ? `Aliases: ${command.aliases.join(', ')}\n` : '')
+ `Usage: ${command.usage}\n`
+ (command.info ? `\n${command.info}` : '')
+ (info.info ? `\n${info.info}` : '')
+ '\n```';
}

Expand Down
84 changes: 84 additions & 0 deletions src/localization/Lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { LocalizedCommandInfo } from '../types/LocalizedCommandInfo';
import { Command } from '../command/Command';
import { Client } from '../client/Client';
import * as glob from 'glob';

/**
* Class for loading localization files and fetching localized values
*/
export class Lang
{
private static _instance: Lang;
private client: Client;
private commandInfo: { [command: string]: { [lang: string]: LocalizedCommandInfo } };
private constructor(client: Client)
{
if (Lang._instance)
throw new Error('Cannot create multiple instances of Logger singleton');

this.client = client;
this.commandInfo = {};
}

/**
* Create the singleton instance
*/
public static createInstance(client: Client): void
{
if (!Lang._instance) Lang._instance = new Lang(client);
}

/**
* Load any command localizations and assign them to commands
*/
public static loadCommandLocalizations(): void
{
if (!Lang._instance) return;

for (const command of Lang._instance.client.commands.values())
{
let localizationFile: string =
glob.sync(`${Lang._instance.client.commandsDir}/**/${command.name}.lang.json`)[0];
if (!localizationFile) continue;
let localizations: { [name: string]: LocalizedCommandInfo };
try { localizations = require(localizationFile); }
catch (err) { continue; }
Lang._instance.commandInfo[command.name] = localizations;
}
}

/**
* Get all available localization languages
* TODO: Extend this to scan language string files after
* adding support for those
*/
public static getLangs(): string[]
{
let langs: Set<string> = new Set();
for (const commandName of Object.keys(Lang._instance.commandInfo))
for (const lang of Object.keys(Lang._instance.commandInfo[commandName]))
langs.add(lang);

return Array.from(langs);
}

/**
* Get localized command info, defaulting to the info
* given in the Command's constructor
*/
public static getCommandInfo(command: Command, lang: string): LocalizedCommandInfo
{
let desc: string, info: string;
if (!Lang._instance.commandInfo[command.name]
|| (Lang._instance.commandInfo[command.name]
&& !Lang._instance.commandInfo[command.name][lang]))
return { desc, info } = command;

desc = Lang._instance.commandInfo[command.name][lang].desc;
info = Lang._instance.commandInfo[command.name][lang].info;
if (!desc) desc = command.desc;
if (!info) info = command.info;

return { desc, info };
}
}
2 changes: 2 additions & 0 deletions src/types/YAMDBFOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @property {string[]} [owner=[]] Can also be a single string<br>See: {@link Client#owner}
* @property {string} [provider] See: {@link Client#provider}
* @property {string} [commandsDir] See: {@link Client#commandsDir}
* @property {string} [defaultLang] See: {@link Client#defaultLang}
* @property {string} [statusText=null] See: {@link Client#statusText}
* @property {string} [readyText='Client ready!'] See: {@link Client#readyText}
* @property {boolean} [unknownCommandError=true] See: {@link Client#unknownCommandError}
Expand All @@ -28,6 +29,7 @@ export type YAMDBFOptions = {
owner?: string | string[];
provider?: StorageProviderConstructor;
commandsDir?: string;
defaultLang?: string;
statusText?: string;
readyText?: string;
unknownCommandError?: boolean;
Expand Down
5 changes: 5 additions & 0 deletions test/commands/base/eval.lang.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"al_bhed": {
"desc": "Ajymiyda bnujetat Javascript luta"
}
}
6 changes: 6 additions & 0 deletions test/commands/base/help.lang.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"al_bhed": {
"desc": "Bnujetac ehvunsydeuh uh pud lussyhtc",
"info": "Femm DM pud lussyht ramb ehvunsydeuh du dra ican du gaab lmiddan tufh eh kiemt lryhhamc"
}
}
3 changes: 2 additions & 1 deletion test/test_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ class Test extends Client
token: config.token,
owner: config.owner,
commandsDir: './commands',
defaultLang: 'al_bhed',
pause: true,
logLevel: LogLevel.DEBUG,
disableBase: Util.baseCommandNames
.filter(n => n !== 'help')
.filter(n => n !== 'help' && n !== 'eval')
});
}

Expand Down

0 comments on commit e0514dc

Please sign in to comment.