diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml deleted file mode 100644 index 7f44b74..0000000 --- a/.github/workflows/changelog.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Generate Changelog - -on: - schedule: - - cron: "0 3 * * *" - workflow_dispatch: - -jobs: - changelog: - name: Generate changelog - runs-on: ubuntu-latest - permissions: - contents: write - - steps: - - name: Checkout main - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: main - - - name: Generate changelog - uses: orhun/git-cliff-action@v4 - with: - config: cliff.toml - args: --verbose - output_file: CHANGELOG.md - env: - GITHUB_REPO: ${{ github.repository }} - - - name: Checkout or create changelog branch - run: | - git fetch origin - git checkout -B changelog origin/changelog || git checkout -B changelog - git checkout main -- CHANGELOG.md - - - name: Commit changelog - run: | - git config user.name 'github-actions[bot]' - git config user.email 'github-actions[bot]@users.noreply.github.com' - git add CHANGELOG.md - git diff --cached --quiet && exit 0 - git commit -m "Update changelog from main" - git push origin changelog --force diff --git a/examples/basic_client/index.js b/examples/basic_client/index.js index f62745f..4df8075 100644 --- a/examples/basic_client/index.js +++ b/examples/basic_client/index.js @@ -1,12 +1,31 @@ +const i18next = require("i18next"); const arox = require("../../dist/index"); +const backend = require("i18next-fs-backend"); +const path = require("node:path"); +const { LogLevel } = require("../../dist/utils/logger/ILogger"); + +const myinstance = i18next.createInstance({ + supportedLngs: ["en-US", "tr"], + fallbackLng: "en-US", + defaultNS: "translation", + ns: ["translation", "test"], + backend: { + loadPath: path.join(__dirname, "locales/{{lng}}/{{ns}}.json"), + }, + interpolation: { + escapeValue: false, + }, +}); +myinstance.use(backend); const client = new arox.Client({ intents: 37376, prefix: { enabled: true, prefix: "a!" }, logger: { - depth: 0, + level: LogLevel.Trace, }, autoRegisterCommands: false, + i18n: myinstance, }); arox.setClient(client); @@ -20,12 +39,16 @@ arox.clearClient(); command .onMessage(function (ctx) { - const { message } = ctx; - void message.reply("Çalışıyom ulan şurda rahat bırak beni"); + const { message, t, author } = ctx; + void message.reply( + t("test:hello", { user: author?.username ?? "Unknown" }) + ); }) .onInteraction(function (ctx) { - const { interaction } = ctx; - void interaction.reply("Çalışıyom ulan şurda rahat bırak beni"); + const { interaction, t, author } = ctx; + void interaction.reply( + t("test:hello", { user: author?.username ?? "Unknown" }) + ); }); async function init() { diff --git a/examples/basic_client/locales/en-US/test.json b/examples/basic_client/locales/en-US/test.json new file mode 100644 index 0000000..f66301f --- /dev/null +++ b/examples/basic_client/locales/en-US/test.json @@ -0,0 +1,3 @@ +{ + "hello": "Hello {{user}}" +} diff --git a/package-lock.json b/package-lock.json index d01e2cc..9a17d14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,14 @@ "@swc/helpers": "^0.5.18", "colorette": "^2.0.20", "fast-glob": "^3.3.3", + "i18next": "^25.8.0", + "i18next-fs-backend": "^2.6.1", "lodash": "^4.17.21" }, "devDependencies": { "@swc/cli": "^0.7.10", "@types/lodash": "^4.17.23", - "@types/node": "^25.0.8", + "@types/node": "^25.0.9", "husky": "^9.1.7", "libnpmpack": "^9.0.12", "oxfmt": "^0.24.0", @@ -30,6 +32,15 @@ "discord.js": ">=14.25.1" } }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@borewit/text-codec": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", @@ -1754,9 +1765,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.0.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz", - "integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==", + "version": "25.0.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz", + "integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -2831,6 +2842,43 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/i18next": { + "version": "25.8.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.0.tgz", + "integrity": "sha512-urrg4HMFFMQZ2bbKRK7IZ8/CTE7D8H4JRlAwqA2ZwDRFfdd0K/4cdbNNLgfn9mo+I/h9wJu61qJzH7jCFAhUZQ==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-fs-backend": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.6.1.tgz", + "integrity": "sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ==", + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3083,9 +3131,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.snakecase": { @@ -4334,9 +4382,9 @@ } }, "node_modules/tar": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.3.tgz", - "integrity": "sha512-ENg5JUHUm2rDD7IvKNFGzyElLXNjachNLp6RaGf4+JOgxXHkqA+gq81ZAMCUmtMtqBsoU62lcp6S27g1LCYGGQ==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.6.tgz", + "integrity": "sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4479,7 +4527,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 4160ea0..2ea4a66 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "imports": { - "#types/*": "./types/*" + "#types/*": "./types/*", + "#utils": "./src/utils/index.ts", + "#structures": "./src/structures/index.ts", + "#ctx": "./src/context.ts" }, "scripts": { "prepare": "node scripts/prepareHusky.js", @@ -38,12 +41,14 @@ "@swc/helpers": "^0.5.18", "colorette": "^2.0.20", "fast-glob": "^3.3.3", + "i18next": "^25.8.0", + "i18next-fs-backend": "^2.6.1", "lodash": "^4.17.21" }, "devDependencies": { "@swc/cli": "^0.7.10", "@types/lodash": "^4.17.23", - "@types/node": "^25.0.8", + "@types/node": "^25.0.9", "husky": "^9.1.7", "libnpmpack": "^9.0.12", "oxfmt": "^0.24.0", diff --git a/src/context.ts b/src/context.ts index d4eaf63..3994d7b 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,4 +1,4 @@ -import { Client } from "./structures/Client"; +import { Client } from "#structures"; // Birden fazla client olursa hata çıkartabilir ama aklıma gelen tek şey bu export let currentClient: Client | null = null; diff --git a/src/events/interaction.ts b/src/events/interaction.ts index 0f6832b..9ca5710 100644 --- a/src/events/interaction.ts +++ b/src/events/interaction.ts @@ -1,6 +1,5 @@ -import { Events } from "discord.js"; -import { EventBuilder } from "../structures/Event"; -import { Context } from "../structures/Context"; +import { Events, MessageFlags } from "discord.js"; +import { EventBuilder, Context } from "#structures"; new EventBuilder(Events.InteractionCreate, false).onExecute( async function (context, interaction) { @@ -10,13 +9,17 @@ new EventBuilder(Events.InteractionCreate, false).onExecute( if (!command || !command.supportsSlash) { await interaction.reply({ content: "Command not found or disabled.", - ephemeral: true, + flags: MessageFlags.Ephemeral, }); return; } try { const ctx = new Context(context.client, { interaction }); + ctx.locale = interaction.locale; + context.logger.debug( + `${ctx.author?.tag ?? "Unknown"} used ${command.name}(interaction)` + ); if (command._onInteraction) await command._onInteraction(ctx.toJSON()); } catch (error) { context.client.logger.error( @@ -26,12 +29,12 @@ new EventBuilder(Events.InteractionCreate, false).onExecute( if (interaction.replied || interaction.deferred) { await interaction.followUp({ content: "There was an error while executing this command!", - ephemeral: true, + flags: MessageFlags.Ephemeral, }); } else { await interaction.reply({ content: "There was an error while executing this command!", - ephemeral: true, + flags: MessageFlags.Ephemeral, }); } } diff --git a/src/events/message.ts b/src/events/message.ts index 7b92263..39c78e2 100644 --- a/src/events/message.ts +++ b/src/events/message.ts @@ -1,7 +1,6 @@ import { Events } from "discord.js"; -import { EventBuilder } from "../structures/Event"; -import { Context } from "../structures/Context"; -import { deleteMessage } from "../utils/util"; +import { EventBuilder, Context } from "#structures"; +import { deleteMessageAfterSent } from "#utils"; new EventBuilder( Events.MessageCreate, @@ -31,7 +30,7 @@ new EventBuilder( content: "Command not found or disabled.", allowedMentions: { repliedUser: false }, }) - .then(deleteMessage); + .then(deleteMessageAfterSent); return; } diff --git a/src/events/ready.ts b/src/events/ready.ts index 06317f5..f1f8504 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,5 +1,5 @@ import { Events } from "discord.js"; -import { EventBuilder } from "../structures/Event"; +import { EventBuilder } from "#structures"; new EventBuilder(Events.ClientReady).onExecute(async function (context) { if (context.client.options.autoRegisterCommands) { diff --git a/src/index.ts b/src/index.ts index 1e433b9..4a8c0e9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,5 @@ -export * from "./structures/Client"; -export * from "./structures/Command"; -export * from "./structures/Context"; -export * from "./structures/Event"; -export * from "./structures/Argument"; +export * from "#structures"; export * from "./utils/logger/Logger"; -export * from "./context"; +export * from "#ctx"; + export const version = "[VI]{{version}}[/VI]"; diff --git a/src/structures/Argument.ts b/src/structures/builder/Argument.ts similarity index 72% rename from src/structures/Argument.ts rename to src/structures/builder/Argument.ts index 991aa20..bf1c28c 100644 --- a/src/structures/Argument.ts +++ b/src/structures/builder/Argument.ts @@ -25,6 +25,16 @@ export class Argument { } public toJSON(): ApplicationCommandOptionData { + const choicesAllowedTypes = [ + ApplicationCommandOptionType.String, + ApplicationCommandOptionType.Integer, + ApplicationCommandOptionType.Number, + ]; + if (this.choices && !choicesAllowedTypes.includes(this.type)) { + throw new Error( + `Choices are not allowed for option type ${ApplicationCommandOptionType[this.type]} (${this.type})` + ); + } return { name: this.name, description: this.description, diff --git a/src/structures/Command.ts b/src/structures/builder/Command.ts similarity index 80% rename from src/structures/Command.ts rename to src/structures/builder/Command.ts index 27a42ed..cd2ca3d 100644 --- a/src/structures/Command.ts +++ b/src/structures/builder/Command.ts @@ -3,12 +3,16 @@ import { ChatInputCommandInteraction, Message, } from "discord.js"; -import { Context } from "./Context"; -import { Client } from "./Client"; +import { Context, Client } from "#structures"; import { Argument } from "./Argument"; -import { currentClient } from "../context"; +import { currentClient } from "#ctx"; import { MaybePromise } from "#types/extra.js"; -import { Logger } from "../utils/logger/Logger"; +import { Logger } from "#utils"; + +type MessageContext = NonNullable["toJSON"]>>; +type InteractionContext = NonNullable< + ReturnType["toJSON"]> +>; export interface CommandOptions { name: string; @@ -29,12 +33,8 @@ export class CommandBuilder { public readonly options: ApplicationCommandOptionData[]; private _supportsSlash: boolean; private _supportsPrefix: boolean; - public _onMessage?: ( - ctx: NonNullable["toJSON"]>> - ) => MaybePromise; - public _onInteraction?: ( - ctx: NonNullable["toJSON"]>> - ) => MaybePromise; + public _onMessage?: (ctx: MessageContext) => MaybePromise; + public _onInteraction?: (ctx: InteractionContext) => MaybePromise; public get supportsSlash() { return this._supportsSlash && this._onInteraction; @@ -99,22 +99,12 @@ export class CommandBuilder { this.logger.debug(`Loaded Command ${this.name}`); } - onMessage( - func: ( - ctx: NonNullable["toJSON"]>> - ) => MaybePromise - ) { + onMessage(func: (ctx: MessageContext) => MaybePromise) { this._onMessage = func; return this; } - onInteraction( - func: ( - ctx: NonNullable< - ReturnType["toJSON"]> - > - ) => MaybePromise - ) { + onInteraction(func: (ctx: InteractionContext) => MaybePromise) { this._onInteraction = func; return this; } diff --git a/src/structures/Context.ts b/src/structures/builder/Context.ts similarity index 59% rename from src/structures/Context.ts rename to src/structures/builder/Context.ts index d7484de..9dba783 100644 --- a/src/structures/Context.ts +++ b/src/structures/builder/Context.ts @@ -1,5 +1,5 @@ -import { Message, User, ChatInputCommandInteraction } from "discord.js"; -import { Client } from "../structures/Client"; +import { Message, User, ChatInputCommandInteraction, Locale } from "discord.js"; +import { Client } from "#structures"; type ContextPayload = T extends ChatInputCommandInteraction @@ -7,12 +7,14 @@ type ContextPayload = : { message: T; args?: string[] }; export class Context { - public readonly client: Client; public readonly args: string[]; public readonly data: T; + public locale?: `${Locale}`; - constructor(client: Client, payload: ContextPayload) { - this.client = client; + constructor( + public readonly client: Client, + payload: ContextPayload + ) { this.args = payload.args ?? []; if ("interaction" in payload) { @@ -40,22 +42,40 @@ export class Context { return null; } - toJSON() { + public t(key: string, args?: Record): string { + if (!this.client.i18n) { + throw new Error("i18n is not initialized"); + } + let locale = + this.locale ?? + (Array.isArray(this.client.i18n.options.fallbackLng) + ? this.client.i18n.options.fallbackLng[0] + : this.client.i18n.options.fallbackLng) ?? + "en"; + + const t = this.client.i18n.getFixedT(locale); + + return t(key, args) as string; + } + + public toJSON() { const { data, args, author } = this; if (this.isInteraction()) { return { kind: "interaction" as const, interaction: data, - author: author, + author, + t: this.t.bind(this), }; } return { kind: "message" as const, message: data as Message, - args: args, - author: author, + args, + author, + t: (this as Context).t.bind(this), }; } } diff --git a/src/structures/Event.ts b/src/structures/builder/Event.ts similarity index 91% rename from src/structures/Event.ts rename to src/structures/builder/Event.ts index af5aa98..7dfd4c1 100644 --- a/src/structures/Event.ts +++ b/src/structures/builder/Event.ts @@ -1,8 +1,8 @@ import { ClientEvents } from "discord.js"; import { MaybePromise } from "#types/extra.js"; -import { currentClient } from "../context"; -import { Client } from "./Client"; -import { Logger } from "../utils/logger/Logger"; +import { currentClient } from "#ctx"; +import { Client } from "#structures"; +import { Logger } from "#utils"; type EventArgs = ClientEvents[K]; type EventHandler = ( @@ -41,8 +41,6 @@ export class EventBuilder { this.handler = _handler; this.register(); } - - this.logger.debug(`Loaded Event ${String(this.name)}`); } private register(): void { @@ -55,6 +53,7 @@ export class EventBuilder { } this.bound = true; + this.logger.debug(`Loaded Event ${String(this.name)}`); } public onExecute(func: EventHandler) { diff --git a/src/structures/builder/index.ts b/src/structures/builder/index.ts new file mode 100644 index 0000000..81fad25 --- /dev/null +++ b/src/structures/builder/index.ts @@ -0,0 +1,4 @@ +export * from "./Argument"; +export * from "./Command"; +export * from "./Context"; +export * from "./Event"; diff --git a/src/structures/Client.ts b/src/structures/core/Client.ts similarity index 72% rename from src/structures/Client.ts rename to src/structures/core/Client.ts index c7ef552..0da8eb9 100644 --- a/src/structures/Client.ts +++ b/src/structures/core/Client.ts @@ -5,20 +5,23 @@ import { Routes, IntentsBitField, } from "discord.js"; -import { CommandBuilder } from "./Command"; +import { CommandBuilder } from "#structures"; import path from "path"; -import { getFiles, getProjectRoot } from "../utils/Files"; +import { + getFiles, + getProjectRoot, + getPrefix, + I18nLoggerAdapter, + Logger, +} from "#utils"; import { FrameworkOptions } from "#types/client.js"; import { merge } from "lodash"; -import { clearClient, setClient } from "../context"; -import { getPrefix } from "../utils/util"; -import { Logger } from "../utils/logger/Logger"; +import { clearClient, setClient } from "#ctx"; +import { i18n } from "i18next"; +import { existsSync } from "fs"; const defaultOpts: Omit = { - paths: { - events: "events", - commands: "commands", - }, + includePaths: ["events", "commands"], autoRegisterCommands: true, }; @@ -29,6 +32,7 @@ export class Client< public commands: Collection; public aliases: Collection>; public readonly prefix: string | false; + public i18n: i18n | undefined; declare public options: Omit & { intents: IntentsBitField; @@ -40,11 +44,9 @@ export class Client< this.commands = new Collection(); this.aliases = new Collection(); this.prefix = getPrefix(this.options.prefix ?? { enabled: false }); - - if (this.options.paths?.events) { - this.loadFiles( - path.join(getProjectRoot(), this.options.paths?.events) - ).catch((error) => this.logger.error("Error loading events:", error)); + if (this.options.i18n) { + this.i18n = this.options.i18n; + this.i18n.use(new I18nLoggerAdapter(this.logger)); } setClient(this); @@ -56,10 +58,23 @@ export class Client< clearClient(); } } + override async login(token?: string) { + if (this.options.includePaths) { + for (const p of this.options.includePaths) { + this.loadDir(path.join(getProjectRoot(), p)).catch((error) => + this.logger.error("Error loading events:", error) + ); + } + } + if (this.i18n && !this.i18n.isInitialized) { + await this.i18n.init(); + } + return super.login(token); + } - async loadFiles(dir: string) { - if (!require("fs").existsSync(dir)) { - this.logger.warn(`Directory not found: ${dir}`); + async loadDir(dir: string) { + if (!existsSync(dir)) { + this.logger.debug(`Directory not found: ${dir}`); return; } const files = getFiles(dir); diff --git a/src/structures/core/index.ts b/src/structures/core/index.ts new file mode 100644 index 0000000..ccf222b --- /dev/null +++ b/src/structures/core/index.ts @@ -0,0 +1 @@ +export * from "./Client"; diff --git a/src/structures/index.ts b/src/structures/index.ts new file mode 100644 index 0000000..4c8e81f --- /dev/null +++ b/src/structures/index.ts @@ -0,0 +1,2 @@ +export * from "./core"; +export * from "./builder"; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..a6f4449 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,3 @@ +export * from "./util"; +export * from "./Files"; +export * from "./logger/Logger"; diff --git a/src/utils/logger/Logger.ts b/src/utils/logger/Logger.ts index 037f4ad..a21c640 100644 --- a/src/utils/logger/Logger.ts +++ b/src/utils/logger/Logger.ts @@ -6,6 +6,7 @@ import type { Color } from "colorette"; import { Timestamp } from "@sapphire/timestamp"; import type { ILogger } from "./ILogger"; import { LogLevel } from "./ILogger"; +import { LoggerModule } from "i18next"; export class Logger implements ILogger { public level: LogLevel; @@ -390,3 +391,19 @@ export enum LoggerStyleBackground { CyanBright = "bgCyanBright", WhiteBright = "bgWhiteBright", } + +export class I18nLoggerAdapter implements LoggerModule { + public readonly type = "logger"; + constructor(private readonly logger: Logger) {} + log(...args: unknown[]): void { + this.logger.debug("[i18next]", ...args); + } + + warn(...args: unknown[]): void { + this.logger.warn("[i18next]", ...args); + } + + error(...args: unknown[]): void { + this.logger.error("[i18next]", ...args); + } +} diff --git a/src/utils/util.ts b/src/utils/util.ts index 99b31b3..5b52c0d 100644 --- a/src/utils/util.ts +++ b/src/utils/util.ts @@ -1,7 +1,7 @@ import { PrefixOptions } from "#types/client.js"; import { InteractionResponse, Message } from "discord.js"; -export function deleteMessage( +export function deleteMessageAfterSent( message: Message | InteractionResponse, time = 15_000 ) { @@ -12,6 +12,7 @@ export function deleteMessage( }, time); }); } + export function getPrefix(opts: PrefixOptions): string | false { if (typeof opts === "string") { return opts; diff --git a/types/client.d.ts b/types/client.d.ts index 4e1055d..6f49dac 100644 --- a/types/client.d.ts +++ b/types/client.d.ts @@ -1,9 +1,11 @@ import { ClientOptions } from "discord.js"; import { LoggerOptions } from "../src/utils/logger/Logger"; +import { i18n } from "i18next"; export interface FrameworkPaths { events?: string; commands?: string; + locales?: string; } export type PrefixOptions = @@ -14,6 +16,7 @@ export type PrefixOptions = export interface FrameworkOptions extends ClientOptions { logger?: LoggerOptions; prefix?: PrefixOptions; - paths?: FrameworkPaths; autoRegisterCommands?: boolean; + includePaths: string[]; + i18n?: i18n; }