@sapphire/plugin-i18next 8.0.1-next.e18dc27 → 8.0.1-next.f67c68a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
  var i18next__default = /*#__PURE__*/_interopDefault(i18next);
11
11
 
12
12
  // src/index.ts
13
- var version = "8.0.1-next.e18dc27";
13
+ var version = "8.0.1-next.f67c68a";
14
14
 
15
15
  Object.defineProperty(exports, "i18next", {
16
16
  enumerable: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAyBO,IAAM,OAAkB,GAAA","file":"index.cjs","sourcesContent":["import type { InternationalizationHandler } from './lib/InternationalizationHandler';\nimport type { InternationalizationClientOptions } from './lib/types';\n\nexport { default as i18next, type TFunction, type TOptions } from 'i18next';\nexport * from './lib/InternationalizationHandler';\nexport * from './lib/functions';\nexport * from './lib/types';\n\ndeclare module '@sapphire/pieces' {\n\tinterface Container {\n\t\ti18n: InternationalizationHandler;\n\t}\n}\n\ndeclare module 'discord.js' {\n\texport interface ClientOptions extends InternationalizationClientOptions {}\n}\n\n/**\n * The [@sapphire/plugin-i18next](https://github.com/sapphiredev/plugins/blob/main/packages/i18next) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '8.0.1-next.e18dc27';\n"]}
1
+ {"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAyBO,IAAM,OAAA,GAAkB","file":"index.cjs","sourcesContent":["import type { InternationalizationHandler } from './lib/InternationalizationHandler';\nimport type { InternationalizationClientOptions } from './lib/types';\n\nexport { default as i18next, type TFunction, type TOptions } from 'i18next';\nexport * from './lib/InternationalizationHandler';\nexport * from './lib/functions';\nexport * from './lib/types';\n\ndeclare module '@sapphire/pieces' {\n\tinterface Container {\n\t\ti18n: InternationalizationHandler;\n\t}\n}\n\ndeclare module 'discord.js' {\n\texport interface ClientOptions extends InternationalizationClientOptions {}\n}\n\n/**\n * The [@sapphire/plugin-i18next](https://github.com/sapphiredev/plugins/blob/main/packages/i18next) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '8.0.1-next.f67c68a';\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":["container","URL","fileURLToPath","join","getRootData","isFunction","i18next","Backend","opendir","Result"],"mappings":"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","file":"InternationalizationHandler.cjs","sourcesContent":["import { Result } from '@sapphire/framework';\nimport { container, getRootData } from '@sapphire/pieces';\nimport { isFunction, type Awaitable } from '@sapphire/utilities';\nimport { Backend, type PathResolvable } from '@skyra/i18next-backend';\nimport i18next, {\n\ttype AppendKeyPrefix,\n\ttype DefaultNamespace,\n\ttype InterpolationMap,\n\ttype Namespace,\n\ttype ParseKeys,\n\ttype TFunction,\n\ttype TFunctionProcessReturnValue,\n\ttype TFunctionReturn,\n\ttype TFunctionReturnOptionalDetails,\n\ttype TOptions\n} from 'i18next';\nimport type { PathLike } from 'node:fs';\nimport { opendir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { URL, fileURLToPath } from 'node:url';\nimport type { $Dictionary, $NoInfer, $SpecialObject, InternationalizationContext, InternationalizationOptions } from './types';\n\n/**\n * A generalized class for handling `i18next` JSON files and their discovery.\n * @since 1.0.0\n */\nexport class InternationalizationHandler {\n\t/**\n\t * Describes whether {@link InternationalizationHandler.init} has been run and languages are loaded in {@link InternationalizationHandler.languages}.\n\t * @since 1.0.0\n\t */\n\tpublic languagesLoaded = false;\n\n\t/**\n\t * A `Set` of initially loaded namespaces.\n\t * @since 1.2.0\n\t */\n\tpublic namespaces = new Set<string>();\n\n\t/**\n\t * A `Map` of `i18next` language functions keyed by their language code.\n\t * @since 1.0.0\n\t */\n\tpublic readonly languages = new Map<string, TFunction>();\n\n\t/**\n\t * The options InternationalizationHandler was initialized with in the client.\n\t * @since 1.0.0\n\t */\n\tpublic readonly options: InternationalizationOptions;\n\n\t/**\n\t * The director passed to `@skyra/i18next-backend`.\n\t * Also used in {@link InternationalizationHandler.walkLanguageDirectory}.\n\t * @since 1.2.0\n\t */\n\tpublic readonly languagesDirectory: string;\n\n\t/**\n\t * The backend options for `@skyra/i18next-backend` used by `i18next`.\n\t * @since 1.0.0\n\t */\n\tprotected readonly backendOptions: Backend.Options;\n\n\t/**\n\t * @param options The options that `i18next`, `@skyra/i18next-backend`, and {@link InternationalizationHandler} should use.\n\t * @since 1.0.0\n\t * @constructor\n\t */\n\tpublic constructor(options?: InternationalizationOptions) {\n\t\tthis.options = options ?? { i18next: { ignoreJSONStructure: false } };\n\n\t\tconst baseUserDirectory =\n\t\t\tcontainer.client?.options?.baseUserDirectory instanceof URL\n\t\t\t\t? fileURLToPath(container.client?.options?.baseUserDirectory)\n\t\t\t\t: container.client?.options?.baseUserDirectory;\n\n\t\tthis.languagesDirectory = this.options.defaultLanguageDirectory ?? join(baseUserDirectory ?? getRootData().root, 'languages');\n\n\t\tconst languagePaths = new Set<PathResolvable>([\n\t\t\tjoin(this.languagesDirectory, '{{lng}}', '{{ns}}.json'), //\n\t\t\t...(options?.backend?.paths ?? [])\n\t\t]);\n\n\t\tthis.backendOptions = {\n\t\t\tpaths: [...languagePaths],\n\t\t\t...this.options.backend\n\t\t};\n\n\t\tif (isFunction(this.options.fetchLanguage)) {\n\t\t\tthis.fetchLanguage = this.options.fetchLanguage;\n\t\t}\n\t}\n\n\t/**\n\t * The method to be overridden by the developer.\n\t *\n\t * @note In the event that fetchLanguage is not defined or returns null / undefined, the defaulting from {@link fetchLanguage} will be used.\n\t * @since 2.0.0\n\t * @return A string for the desired language or null for no match.\n\t * @see {@link fetchLanguage}\n\t * @example\n\t * ```typescript\n\t * // Always use the same language (no per-guild configuration):\n\t * container.i18n.fetchLanguage = () => 'en-US';\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an SQL database:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getOne('SELECT language FROM public.guild WHERE id = $1', [context.guild.id]);\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an ORM:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getRepository(GuildEntity).findOne({ id: context.guild.id });\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language on a per channel basis, e.g. per user or guild channel (ORM example but same principles apply):\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const channel = await driver.getRepository(ChannelEntity).findOne({ id: context.channel.id });\n\t * return channel?.language ?? 'en-US';\n\t * };\n\t * ```\n\t */\n\tpublic fetchLanguage: (context: InternationalizationContext) => Awaitable<string | null> = () => null;\n\n\t/**\n\t * Initializes the handler by loading in the namespaces, passing the data to i18next, and filling in the {@link InternationalizationHandler#languages}.\n\t * @since 1.0.0\n\t */\n\tpublic async init() {\n\t\tconst { namespaces, languages } = await this.walkRootDirectory(this.languagesDirectory);\n\t\tconst userOptions = isFunction(this.options.i18next) ? this.options.i18next(namespaces, languages) : this.options.i18next;\n\t\tconst ignoreJSONStructure = userOptions?.ignoreJSONStructure ?? false;\n\t\tconst skipOnVariables = userOptions?.interpolation?.skipOnVariables ?? false;\n\n\t\ti18next.use(Backend);\n\t\tawait i18next.init({\n\t\t\tbackend: this.backendOptions,\n\t\t\tfallbackLng: this.options.defaultName ?? 'en-US',\n\t\t\tinitImmediate: false,\n\t\t\tinterpolation: {\n\t\t\t\tescapeValue: false,\n\t\t\t\t...userOptions?.interpolation,\n\t\t\t\tskipOnVariables\n\t\t\t},\n\t\t\tload: 'all',\n\t\t\tdefaultNS: 'default',\n\t\t\tns: namespaces,\n\t\t\tpreload: languages,\n\t\t\t...userOptions,\n\t\t\tignoreJSONStructure\n\t\t});\n\n\t\tthis.namespaces = new Set(namespaces);\n\t\tfor (const item of languages) {\n\t\t\tthis.languages.set(item, i18next.getFixedT(item));\n\t\t}\n\t\tthis.languagesLoaded = true;\n\n\t\tconst formatter = i18next.services.formatter!;\n\t\tconst formatters = this.options.formatters ?? [];\n\t\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\t\tfor (const { name, format, cached } of formatters) {\n\t\t\tif (cached) formatter.addCached(name, format);\n\t\t\telse formatter.add(name, format);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a raw TFunction from the passed locale.\n\t * @param locale The language to be used.\n\t * @since 1.0.0\n\t */\n\tpublic getT(locale: string) {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst t = this.languages.get(locale);\n\t\tif (t) return t;\n\t\tthrow new ReferenceError('Invalid language provided');\n\t}\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: Key | Key[], options?: ActualOptions): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param defaultValue The default value to use if the key is not found.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(\n\t\tlocale: string,\n\t\tkey: string | string[],\n\t\tdefaultValue: string | undefined,\n\t\toptions?: TOpt & $Dictionary\n\t): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t *\n\t * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n\t * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n\t * for the documentation on those parameters.\n\t *\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,\n\t\tDefaultValue extends string = never\n\t>(\n\t\tlocale: string,\n\t\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t\t| [key: string | string[], defaultValue: DefaultValue | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt> {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst language = this.languages.get(locale);\n\t\tif (!language) throw new ReferenceError('Invalid language provided');\n\n\t\tconst defaultValue =\n\t\t\ttypeof defaultValueOrOptions === 'string'\n\t\t\t\t? defaultValueOrOptions\n\t\t\t\t: this.options.defaultMissingKey\n\t\t\t\t\t? language(this.options.defaultMissingKey, { replace: { key } })\n\t\t\t\t\t: '';\n\n\t\treturn language<Key, TOpt, Ret, ActualOptions, DefaultValue>(key, {\n\t\t\tdefaultValue,\n\t\t\t...((optionsOrUndefined ?? {}) as TOpt)\n\t\t} as TOpt & $Dictionary & { defaultValue: DefaultValue });\n\t}\n\n\t/**\n\t * @param directory The directory that should be walked.\n\t * @since 3.0.0\n\t */\n\tpublic async walkRootDirectory(directory: PathLike) {\n\t\tconst languages = new Set<string>();\n\t\tconst namespaces = new Set<string>();\n\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\t// If the entry is not a directory, skip:\n\t\t\tif (!entry.isDirectory()) continue;\n\n\t\t\t// Load the directory:\n\t\t\tlanguages.add(entry.name);\n\n\t\t\tfor await (const namespace of this.walkLocaleDirectory(join(dir.path, entry.name), '')) {\n\t\t\t\tnamespaces.add(namespace);\n\t\t\t}\n\t\t}\n\n\t\treturn { namespaces: [...namespaces], languages: [...languages] };\n\t}\n\n\tpublic async reloadResources() {\n\t\tconst result = await Result.fromAsync(async () => {\n\t\t\tlet languages = this.options.hmr?.languages;\n\t\t\tlet namespaces = this.options.hmr?.namespaces;\n\t\t\tif (!languages || !namespaces) {\n\t\t\t\tconst languageDirectoryResult = await this.walkRootDirectory(this.languagesDirectory);\n\t\t\t\tlanguages ??= languageDirectoryResult.languages;\n\t\t\t\tnamespaces ??= languageDirectoryResult.namespaces;\n\t\t\t}\n\n\t\t\tawait i18next.reloadResources(languages, namespaces);\n\t\t\tcontainer.logger.info('[i18next-Plugin] Reloaded language resources.');\n\t\t});\n\n\t\tresult.inspectErr((error) => container.logger.error('[i18next-Plugin]: Failed to reload language resources.', error));\n\t}\n\n\t/**\n\t * @description Skips any files that don't end with `.json`.\n\t * @param directory The directory that should be walked.\n\t * @param ns The current namespace.\n\t * @since 3.0.0\n\t */\n\tprivate async *walkLocaleDirectory(directory: string, ns: string): AsyncGenerator<string> {\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tyield* this.walkLocaleDirectory(join(dir.path, entry.name), `${ns}${entry.name}/`);\n\t\t\t} else if (entry.isFile() && entry.name.endsWith('.json')) {\n\t\t\t\tyield `${ns}${entry.name.slice(0, -5)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":["container","URL","fileURLToPath","join","getRootData","isFunction","i18next","Backend","opendir","Result"],"mappings":"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","file":"InternationalizationHandler.cjs","sourcesContent":["import { Result } from '@sapphire/framework';\nimport { container, getRootData } from '@sapphire/pieces';\nimport { isFunction, type Awaitable } from '@sapphire/utilities';\nimport { Backend, type PathResolvable } from '@skyra/i18next-backend';\nimport i18next, {\n\ttype AppendKeyPrefix,\n\ttype DefaultNamespace,\n\ttype InterpolationMap,\n\ttype Namespace,\n\ttype ParseKeys,\n\ttype TFunction,\n\ttype TFunctionProcessReturnValue,\n\ttype TFunctionReturn,\n\ttype TFunctionReturnOptionalDetails,\n\ttype TOptions\n} from 'i18next';\nimport type { PathLike } from 'node:fs';\nimport { opendir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { URL, fileURLToPath } from 'node:url';\nimport type { $Dictionary, $NoInfer, $SpecialObject, InternationalizationContext, InternationalizationOptions } from './types';\n\n/**\n * A generalized class for handling `i18next` JSON files and their discovery.\n * @since 1.0.0\n */\nexport class InternationalizationHandler {\n\t/**\n\t * Describes whether {@link InternationalizationHandler.init} has been run and languages are loaded in {@link InternationalizationHandler.languages}.\n\t * @since 1.0.0\n\t */\n\tpublic languagesLoaded = false;\n\n\t/**\n\t * A `Set` of initially loaded namespaces.\n\t * @since 1.2.0\n\t */\n\tpublic namespaces = new Set<string>();\n\n\t/**\n\t * A `Map` of `i18next` language functions keyed by their language code.\n\t * @since 1.0.0\n\t */\n\tpublic readonly languages = new Map<string, TFunction>();\n\n\t/**\n\t * The options InternationalizationHandler was initialized with in the client.\n\t * @since 1.0.0\n\t */\n\tpublic readonly options: InternationalizationOptions;\n\n\t/**\n\t * The director passed to `@skyra/i18next-backend`.\n\t * Also used in {@link InternationalizationHandler.walkLanguageDirectory}.\n\t * @since 1.2.0\n\t */\n\tpublic readonly languagesDirectory: string;\n\n\t/**\n\t * The backend options for `@skyra/i18next-backend` used by `i18next`.\n\t * @since 1.0.0\n\t */\n\tprotected readonly backendOptions: Backend.Options;\n\n\t/**\n\t * @param options The options that `i18next`, `@skyra/i18next-backend`, and {@link InternationalizationHandler} should use.\n\t * @since 1.0.0\n\t * @constructor\n\t */\n\tpublic constructor(options?: InternationalizationOptions) {\n\t\tthis.options = options ?? { i18next: { ignoreJSONStructure: false } };\n\n\t\tconst baseUserDirectory =\n\t\t\tcontainer.client?.options?.baseUserDirectory instanceof URL\n\t\t\t\t? fileURLToPath(container.client?.options?.baseUserDirectory)\n\t\t\t\t: container.client?.options?.baseUserDirectory;\n\n\t\tthis.languagesDirectory = this.options.defaultLanguageDirectory ?? join(baseUserDirectory ?? getRootData().root, 'languages');\n\n\t\tconst languagePaths = new Set<PathResolvable>([\n\t\t\tjoin(this.languagesDirectory, '{{lng}}', '{{ns}}.json'), //\n\t\t\t...(options?.backend?.paths ?? [])\n\t\t]);\n\n\t\tthis.backendOptions = {\n\t\t\tpaths: [...languagePaths],\n\t\t\t...this.options.backend\n\t\t};\n\n\t\tif (isFunction(this.options.fetchLanguage)) {\n\t\t\tthis.fetchLanguage = this.options.fetchLanguage;\n\t\t}\n\t}\n\n\t/**\n\t * The method to be overridden by the developer.\n\t *\n\t * @note In the event that fetchLanguage is not defined or returns null / undefined, the defaulting from {@link fetchLanguage} will be used.\n\t * @since 2.0.0\n\t * @return A string for the desired language or null for no match.\n\t * @see {@link fetchLanguage}\n\t * @example\n\t * ```typescript\n\t * // Always use the same language (no per-guild configuration):\n\t * container.i18n.fetchLanguage = () => 'en-US';\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an SQL database:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getOne('SELECT language FROM public.guild WHERE id = $1', [context.guild.id]);\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an ORM:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getRepository(GuildEntity).findOne({ id: context.guild.id });\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language on a per channel basis, e.g. per user or guild channel (ORM example but same principles apply):\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const channel = await driver.getRepository(ChannelEntity).findOne({ id: context.channel.id });\n\t * return channel?.language ?? 'en-US';\n\t * };\n\t * ```\n\t */\n\tpublic fetchLanguage: (context: InternationalizationContext) => Awaitable<string | null> = () => null;\n\n\t/**\n\t * Initializes the handler by loading in the namespaces, passing the data to i18next, and filling in the {@link InternationalizationHandler#languages}.\n\t * @since 1.0.0\n\t */\n\tpublic async init() {\n\t\tconst { namespaces, languages } = await this.walkRootDirectory(this.languagesDirectory);\n\t\tconst userOptions = isFunction(this.options.i18next) ? this.options.i18next(namespaces, languages) : this.options.i18next;\n\t\tconst ignoreJSONStructure = userOptions?.ignoreJSONStructure ?? false;\n\t\tconst skipOnVariables = userOptions?.interpolation?.skipOnVariables ?? false;\n\n\t\ti18next.use(Backend);\n\t\tawait i18next.init({\n\t\t\tbackend: this.backendOptions,\n\t\t\tfallbackLng: this.options.defaultName ?? 'en-US',\n\t\t\tinitImmediate: false,\n\t\t\tinterpolation: {\n\t\t\t\tescapeValue: false,\n\t\t\t\t...userOptions?.interpolation,\n\t\t\t\tskipOnVariables\n\t\t\t},\n\t\t\tload: 'all',\n\t\t\tdefaultNS: 'default',\n\t\t\tns: namespaces,\n\t\t\tpreload: languages,\n\t\t\t...userOptions,\n\t\t\tignoreJSONStructure\n\t\t});\n\n\t\tthis.namespaces = new Set(namespaces);\n\t\tfor (const item of languages) {\n\t\t\tthis.languages.set(item, i18next.getFixedT(item));\n\t\t}\n\t\tthis.languagesLoaded = true;\n\n\t\tconst formatter = i18next.services.formatter!;\n\t\tconst formatters = this.options.formatters ?? [];\n\t\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\t\tfor (const { name, format, cached } of formatters) {\n\t\t\tif (cached) formatter.addCached(name, format);\n\t\t\telse formatter.add(name, format);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a raw TFunction from the passed locale.\n\t * @param locale The language to be used.\n\t * @since 1.0.0\n\t */\n\tpublic getT(locale: string) {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst t = this.languages.get(locale);\n\t\tif (t) return t;\n\t\tthrow new ReferenceError('Invalid language provided');\n\t}\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: Key | Key[], options?: ActualOptions): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param defaultValue The default value to use if the key is not found.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(\n\t\tlocale: string,\n\t\tkey: string | string[],\n\t\tdefaultValue: string | undefined,\n\t\toptions?: TOpt & $Dictionary\n\t): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t *\n\t * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n\t * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n\t * for the documentation on those parameters.\n\t *\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,\n\t\tDefaultValue extends string = never\n\t>(\n\t\tlocale: string,\n\t\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t\t| [key: string | string[], defaultValue: DefaultValue | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt> {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst language = this.languages.get(locale);\n\t\tif (!language) throw new ReferenceError('Invalid language provided');\n\n\t\tconst defaultValue =\n\t\t\ttypeof defaultValueOrOptions === 'string'\n\t\t\t\t? defaultValueOrOptions\n\t\t\t\t: this.options.defaultMissingKey\n\t\t\t\t\t? language(this.options.defaultMissingKey, { replace: { key } })\n\t\t\t\t\t: '';\n\n\t\treturn language<Key, TOpt, Ret, ActualOptions, DefaultValue>(key, {\n\t\t\tdefaultValue,\n\t\t\t...((optionsOrUndefined ?? {}) as TOpt)\n\t\t} as TOpt & $Dictionary & { defaultValue: DefaultValue });\n\t}\n\n\t/**\n\t * @param directory The directory that should be walked.\n\t * @since 3.0.0\n\t */\n\tpublic async walkRootDirectory(directory: PathLike) {\n\t\tconst languages = new Set<string>();\n\t\tconst namespaces = new Set<string>();\n\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\t// If the entry is not a directory, skip:\n\t\t\tif (!entry.isDirectory()) continue;\n\n\t\t\t// Load the directory:\n\t\t\tlanguages.add(entry.name);\n\n\t\t\tfor await (const namespace of this.walkLocaleDirectory(join(dir.path, entry.name), '')) {\n\t\t\t\tnamespaces.add(namespace);\n\t\t\t}\n\t\t}\n\n\t\treturn { namespaces: [...namespaces], languages: [...languages] };\n\t}\n\n\tpublic async reloadResources() {\n\t\tconst result = await Result.fromAsync(async () => {\n\t\t\tlet languages = this.options.hmr?.languages;\n\t\t\tlet namespaces = this.options.hmr?.namespaces;\n\t\t\tif (!languages || !namespaces) {\n\t\t\t\tconst languageDirectoryResult = await this.walkRootDirectory(this.languagesDirectory);\n\t\t\t\tlanguages ??= languageDirectoryResult.languages;\n\t\t\t\tnamespaces ??= languageDirectoryResult.namespaces;\n\t\t\t}\n\n\t\t\tawait i18next.reloadResources(languages, namespaces);\n\t\t\tcontainer.logger.info('[i18next-Plugin] Reloaded language resources.');\n\t\t});\n\n\t\tresult.inspectErr((error) => container.logger.error('[i18next-Plugin]: Failed to reload language resources.', error));\n\t}\n\n\t/**\n\t * @description Skips any files that don't end with `.json`.\n\t * @param directory The directory that should be walked.\n\t * @param ns The current namespace.\n\t * @since 3.0.0\n\t */\n\tprivate async *walkLocaleDirectory(directory: string, ns: string): AsyncGenerator<string> {\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tyield* this.walkLocaleDirectory(join(dir.path, entry.name), `${ns}${entry.name}/`);\n\t\t\t} else if (entry.isFile() && entry.name.endsWith('.json')) {\n\t\t\t\tyield `${ns}${entry.name.slice(0, -5)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/functions.ts"],"names":["BaseInteraction","Message","Guild","ChannelType","container","Locale","lazy"],"mappings":"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","file":"functions.cjs","sourcesContent":["import { container } from '@sapphire/pieces';\nimport { lazy } from '@sapphire/utilities';\nimport { BaseInteraction, ChannelType, Guild, Locale, Message, type APIApplicationCommandOptionChoice, type LocaleString } from 'discord.js';\nimport type {\n\tAppendKeyPrefix,\n\tDefaultNamespace,\n\tInterpolationMap,\n\tNamespace,\n\tParseKeys,\n\tTFunctionReturn,\n\tTFunctionReturnOptionalDetails,\n\tTOptions\n} from 'i18next';\nimport type {\n\t$Dictionary,\n\t$SpecialObject,\n\tBuilderWithDescription,\n\tBuilderWithName,\n\tBuilderWithNameAndDescription,\n\tInternationalizationContext,\n\tLocalizedData,\n\tTarget\n} from './types';\n\n/**\n * Retrieves the language name for a specific target, using {@link InternationalizationHandler.fetchLanguage}.\n * If {@link InternationalizationHandler.fetchLanguage} is not defined or this function returns a nullish value,\n * then there will be a series of fallback attempts in the following descending order:\n * 1. Returns {@link Guild.preferredLocale}.\n * 2. Returns {@link InternationalizationOptions.defaultName} if no guild was provided.\n * 3. Returns `'en-US'` if nothing else was found.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @see {@link resolveLanguage}\n * @returns The name of the language key.\n */\nexport function fetchLanguage(target: Target): Promise<string> {\n\t// Handle Interactions:\n\tif (target instanceof BaseInteraction) {\n\t\treturn resolveLanguage({\n\t\t\tuser: target.user,\n\t\t\tchannel: target.channel,\n\t\t\tguild: target.guild,\n\t\t\tinteractionGuildLocale: target.guildLocale,\n\t\t\tinteractionLocale: target.locale\n\t\t});\n\t}\n\n\t// Handle Message:\n\tif (target instanceof Message) {\n\t\treturn resolveLanguage({ user: target.author, channel: target.channel, guild: target.guild });\n\t}\n\n\t// Handle Guild:\n\tif (target instanceof Guild) {\n\t\treturn resolveLanguage({ user: null, channel: null, guild: target });\n\t}\n\n\t// Handle DMChannel and GroupDMChannel:\n\tif (target.type === ChannelType.DM || target.type === ChannelType.GroupDM) {\n\t\treturn resolveLanguage({ user: null, channel: target, guild: null });\n\t}\n\n\t// Handle any other channel:\n\treturn resolveLanguage({ user: null, channel: target, guild: target.guild });\n}\n\n/**\n * Retrieves the language-assigned function from i18next designated to a target's preferred language code.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @returns The language function from i18next.\n */\nexport async function fetchT(target: Target) {\n\treturn container.i18n.getT(await fetchLanguage(target));\n}\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The options to be passed to TFunction.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: Key | Key[], options?: ActualOptions): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param defaultValue The default value to use if the key is not found.\n * @param options The interpolation options.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], defaultValue: string, options?: TOpt & $Dictionary): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n *\n * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n * for the documentation on those parameters.\n *\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(\n\ttarget: Target,\n\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t| [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]\n): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>> {\n\tconst parsedOptions = typeof defaultValueOrOptions === 'string' ? optionsOrUndefined : defaultValueOrOptions;\n\tconst language = typeof parsedOptions?.lng === 'string' ? parsedOptions.lng : await fetchLanguage(target);\n\n\tif (typeof defaultValueOrOptions === 'string') {\n\t\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, defaultValueOrOptions, optionsOrUndefined);\n\t}\n\n\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, undefined, defaultValueOrOptions);\n}\n\n/**\n * @internal\n */\nasync function resolveLanguage(context: InternationalizationContext): Promise<string> {\n\tconst lang = await container.i18n.fetchLanguage(context);\n\treturn lang ?? context.guild?.preferredLocale ?? container.i18n.options.defaultName ?? 'en-US';\n}\n\nconst supportedLanguages = new Set(Object.values(Locale)) as ReadonlySet<LocaleString>;\n\nfunction isSupportedDiscordLocale(language: string): language is LocaleString {\n\treturn supportedLanguages.has(language as LocaleString);\n}\n\nconst getLocales = lazy(() => {\n\tconst locales = new Map(container.i18n.languages);\n\n\tfor (const [locale] of locales) {\n\t\tif (!isSupportedDiscordLocale(locale)) {\n\t\t\tprocess.emitWarning('Unsupported Discord locale', {\n\t\t\t\tcode: 'UNSUPPORTED_LOCALE',\n\t\t\t\tdetail: `'${locale}' needs to be one of: ${[...locales.keys()]}`\n\t\t\t});\n\n\t\t\tlocales.delete(locale);\n\t\t}\n\n\t\tcontinue;\n\t}\n\n\treturn locales;\n});\n\nconst getDefaultT = lazy(() => {\n\tconst defaultLocale = container.i18n.options.defaultName ?? 'en-US';\n\n\tif (!isSupportedDiscordLocale(defaultLocale)) {\n\t\tthrow new TypeError(`Unsupported Discord locale found:\\n'${defaultLocale}' is not within the list of ${[...supportedLanguages]}`);\n\t}\n\n\tconst defaultT = getLocales().get(defaultLocale);\n\n\tif (defaultT) {\n\t\treturn defaultT;\n\t}\n\n\tthrow new TypeError(`Could not find ${defaultLocale}`);\n});\n\n/**\n * Gets the value and the localizations from a language key.\n * @param key The key to get the localizations from.\n * @returns The retrieved data.\n * @remarks This should be called **strictly** after loading the locales.\n */\nexport function getLocalizedData<const TOpt extends TOptions = TOptions, Ns extends Namespace = DefaultNamespace, KPrefix = undefined>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>\n): LocalizedData {\n\tconst locales = getLocales();\n\tconst defaultT = getDefaultT();\n\n\treturn {\n\t\tvalue: defaultT(key),\n\t\tlocalizations: Object.fromEntries(Array.from(locales, ([locale, t]) => [locale, t(key)]))\n\t};\n}\n\n/**\n * Applies the localized names on the builder, calling `setName` and `setNameLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyNameLocalizedBuilder<\n\tT extends BuilderWithName,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setName(result.value).setNameLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized descriptions on the builder, calling `setDescription` and `setDescriptionLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyDescriptionLocalizedBuilder<\n\tT extends BuilderWithDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setDescription(result.value).setDescriptionLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized names and descriptions on the builder, calling {@link applyNameLocalizedBuilder} and\n * {@link applyDescriptionLocalizedBuilder}.\n *\n * @param builder The builder to apply the localizations to.\n *\n * @param params The root key or the key for the name and description keys.\n * This needs to be either 1 or 2 parameters.\n * See examples below for more information.\n *\n * @returns The updated builder. You can chain subsequent builder methods on this.\n *\n * @remarks If only 2 parameters were passed, then this function will automatically append `Name` and `Description`\n * to the root-key (wherein `root-key` is second parameter in the function, after `builder`)\n * passed through the second parameter.\n *\n * For example given `applyLocalizedBuilder(builder, 'userinfo')` the localized options will use the i18next keys\n * `userinfoName` and `userinfoDescription`.\n *\n * In the following example we provide all parameters and add a User Option\n * `applyLocalizedBuilder` needs either\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:userinfo', 'commands/descriptions:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'commands/options:userinfo-name', 'commands/options:userinfo-description').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n *\n * In the following example we provide single root keys which means `Name` and `Description` get appended as mentioned above.\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'options:userinfo').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n */\nexport function applyLocalizedBuilder<\n\tT extends BuilderWithNameAndDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, ...params: [root: string] | [name: ParseKeys<Ns, TOpt, KPrefix>, description: ParseKeys<Ns, TOpt, KPrefix>]): T {\n\ttype LocalKeysType = ParseKeys<Ns, TOpt, KPrefix>;\n\n\tconst [localeName, localeDescription] =\n\t\tparams.length === 1 ? [`${params[0]}Name` as LocalKeysType, `${params[0]}Description` as LocalKeysType] : params;\n\n\tapplyNameLocalizedBuilder(builder, localeName);\n\tapplyDescriptionLocalizedBuilder(builder, localeDescription);\n\n\treturn builder;\n}\n\n/**\n * Constructs an object that can be passed into `setChoices` for String or Number option with localized names.\n *\n * @param key The i18next key for the name of the select option name.\n * @param options The additional Select Menu options. This should _at least_ include the `value` key.\n * @returns An object with anything provided through {@link createLocalizedChoice.options} with `name` and `name_localizations` added.\n *\n * @example\n * ```typescript\n * export class TypeCommand extends Command {\n * public override registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand((builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:type').addStringOption((option) =>\n * applyLocalizedBuilder(option, 'commands/options:type')\n * .setRequired(true)\n * .setChoices(\n * createLocalizedChoice('selects/pokemon:type-grass', { value: 'grass' }),\n * createLocalizedChoice('selects/pokemon:type-water', { value: 'water' }),\n * createLocalizedChoice('selects/pokemon:type-fire', { value: 'fire' }),\n * createLocalizedChoice('selects/pokemon:type-electric', { value: 'electric' })\n * )\n * )\n * );\n * }\n * }\n * ```\n */\nexport function createLocalizedChoice<\n\tValueType = string | number,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>,\n\toptions: Omit<APIApplicationCommandOptionChoice<ValueType>, 'name' | 'name_localizations'>\n): APIApplicationCommandOptionChoice<ValueType> {\n\tconst result = getLocalizedData(key);\n\n\treturn {\n\t\t...options,\n\t\tname: result.value,\n\t\tname_localizations: result.localizations\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/functions.ts"],"names":["BaseInteraction","Message","Guild","ChannelType","container","Locale","lazy"],"mappings":"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","file":"functions.cjs","sourcesContent":["import { container } from '@sapphire/pieces';\nimport { lazy } from '@sapphire/utilities';\nimport { BaseInteraction, ChannelType, Guild, Locale, Message, type APIApplicationCommandOptionChoice, type LocaleString } from 'discord.js';\nimport type {\n\tAppendKeyPrefix,\n\tDefaultNamespace,\n\tInterpolationMap,\n\tNamespace,\n\tParseKeys,\n\tTFunctionReturn,\n\tTFunctionReturnOptionalDetails,\n\tTOptions\n} from 'i18next';\nimport type {\n\t$Dictionary,\n\t$SpecialObject,\n\tBuilderWithDescription,\n\tBuilderWithName,\n\tBuilderWithNameAndDescription,\n\tInternationalizationContext,\n\tLocalizedData,\n\tTarget\n} from './types';\n\n/**\n * Retrieves the language name for a specific target, using {@link InternationalizationHandler.fetchLanguage}.\n * If {@link InternationalizationHandler.fetchLanguage} is not defined or this function returns a nullish value,\n * then there will be a series of fallback attempts in the following descending order:\n * 1. Returns {@link Guild.preferredLocale}.\n * 2. Returns {@link InternationalizationOptions.defaultName} if no guild was provided.\n * 3. Returns `'en-US'` if nothing else was found.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @see {@link resolveLanguage}\n * @returns The name of the language key.\n */\nexport function fetchLanguage(target: Target): Promise<string> {\n\t// Handle Interactions:\n\tif (target instanceof BaseInteraction) {\n\t\treturn resolveLanguage({\n\t\t\tuser: target.user,\n\t\t\tchannel: target.channel,\n\t\t\tguild: target.guild,\n\t\t\tinteractionGuildLocale: target.guildLocale,\n\t\t\tinteractionLocale: target.locale\n\t\t});\n\t}\n\n\t// Handle Message:\n\tif (target instanceof Message) {\n\t\treturn resolveLanguage({ user: target.author, channel: target.channel, guild: target.guild });\n\t}\n\n\t// Handle Guild:\n\tif (target instanceof Guild) {\n\t\treturn resolveLanguage({ user: null, channel: null, guild: target });\n\t}\n\n\t// Handle DMChannel and GroupDMChannel:\n\tif (target.type === ChannelType.DM || target.type === ChannelType.GroupDM) {\n\t\treturn resolveLanguage({ user: null, channel: target, guild: null });\n\t}\n\n\t// Handle any other channel:\n\treturn resolveLanguage({ user: null, channel: target, guild: target.guild });\n}\n\n/**\n * Retrieves the language-assigned function from i18next designated to a target's preferred language code.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @returns The language function from i18next.\n */\nexport async function fetchT(target: Target) {\n\treturn container.i18n.getT(await fetchLanguage(target));\n}\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The options to be passed to TFunction.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: Key | Key[], options?: ActualOptions): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param defaultValue The default value to use if the key is not found.\n * @param options The interpolation options.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], defaultValue: string, options?: TOpt & $Dictionary): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n *\n * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n * for the documentation on those parameters.\n *\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(\n\ttarget: Target,\n\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t| [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]\n): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>> {\n\tconst parsedOptions = typeof defaultValueOrOptions === 'string' ? optionsOrUndefined : defaultValueOrOptions;\n\tconst language = typeof parsedOptions?.lng === 'string' ? parsedOptions.lng : await fetchLanguage(target);\n\n\tif (typeof defaultValueOrOptions === 'string') {\n\t\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, defaultValueOrOptions, optionsOrUndefined);\n\t}\n\n\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, undefined, defaultValueOrOptions);\n}\n\n/**\n * @internal\n */\nasync function resolveLanguage(context: InternationalizationContext): Promise<string> {\n\tconst lang = await container.i18n.fetchLanguage(context);\n\treturn lang ?? context.guild?.preferredLocale ?? container.i18n.options.defaultName ?? 'en-US';\n}\n\nconst supportedLanguages = new Set(Object.values(Locale)) as ReadonlySet<LocaleString>;\n\nfunction isSupportedDiscordLocale(language: string): language is LocaleString {\n\treturn supportedLanguages.has(language as LocaleString);\n}\n\nconst getLocales = lazy(() => {\n\tconst locales = new Map(container.i18n.languages);\n\n\tfor (const [locale] of locales) {\n\t\tif (!isSupportedDiscordLocale(locale)) {\n\t\t\tprocess.emitWarning('Unsupported Discord locale', {\n\t\t\t\tcode: 'UNSUPPORTED_LOCALE',\n\t\t\t\tdetail: `'${locale}' needs to be one of: ${[...locales.keys()]}`\n\t\t\t});\n\n\t\t\tlocales.delete(locale);\n\t\t}\n\n\t\tcontinue;\n\t}\n\n\treturn locales;\n});\n\nconst getDefaultT = lazy(() => {\n\tconst defaultLocale = container.i18n.options.defaultName ?? 'en-US';\n\n\tif (!isSupportedDiscordLocale(defaultLocale)) {\n\t\tthrow new TypeError(`Unsupported Discord locale found:\\n'${defaultLocale}' is not within the list of ${[...supportedLanguages]}`);\n\t}\n\n\tconst defaultT = getLocales().get(defaultLocale);\n\n\tif (defaultT) {\n\t\treturn defaultT;\n\t}\n\n\tthrow new TypeError(`Could not find ${defaultLocale}`);\n});\n\n/**\n * Gets the value and the localizations from a language key.\n * @param key The key to get the localizations from.\n * @returns The retrieved data.\n * @remarks This should be called **strictly** after loading the locales.\n */\nexport function getLocalizedData<const TOpt extends TOptions = TOptions, Ns extends Namespace = DefaultNamespace, KPrefix = undefined>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>\n): LocalizedData {\n\tconst locales = getLocales();\n\tconst defaultT = getDefaultT();\n\n\treturn {\n\t\tvalue: defaultT(key),\n\t\tlocalizations: Object.fromEntries(Array.from(locales, ([locale, t]) => [locale, t(key)]))\n\t};\n}\n\n/**\n * Applies the localized names on the builder, calling `setName` and `setNameLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyNameLocalizedBuilder<\n\tT extends BuilderWithName,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setName(result.value).setNameLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized descriptions on the builder, calling `setDescription` and `setDescriptionLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyDescriptionLocalizedBuilder<\n\tT extends BuilderWithDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setDescription(result.value).setDescriptionLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized names and descriptions on the builder, calling {@link applyNameLocalizedBuilder} and\n * {@link applyDescriptionLocalizedBuilder}.\n *\n * @param builder The builder to apply the localizations to.\n *\n * @param params The root key or the key for the name and description keys.\n * This needs to be either 1 or 2 parameters.\n * See examples below for more information.\n *\n * @returns The updated builder. You can chain subsequent builder methods on this.\n *\n * @remarks If only 2 parameters were passed, then this function will automatically append `Name` and `Description`\n * to the root-key (wherein `root-key` is second parameter in the function, after `builder`)\n * passed through the second parameter.\n *\n * For example given `applyLocalizedBuilder(builder, 'userinfo')` the localized options will use the i18next keys\n * `userinfoName` and `userinfoDescription`.\n *\n * In the following example we provide all parameters and add a User Option\n * `applyLocalizedBuilder` needs either\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:userinfo', 'commands/descriptions:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'commands/options:userinfo-name', 'commands/options:userinfo-description').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n *\n * In the following example we provide single root keys which means `Name` and `Description` get appended as mentioned above.\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'options:userinfo').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n */\nexport function applyLocalizedBuilder<\n\tT extends BuilderWithNameAndDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, ...params: [root: string] | [name: ParseKeys<Ns, TOpt, KPrefix>, description: ParseKeys<Ns, TOpt, KPrefix>]): T {\n\ttype LocalKeysType = ParseKeys<Ns, TOpt, KPrefix>;\n\n\tconst [localeName, localeDescription] =\n\t\tparams.length === 1 ? [`${params[0]}Name` as LocalKeysType, `${params[0]}Description` as LocalKeysType] : params;\n\n\tapplyNameLocalizedBuilder(builder, localeName);\n\tapplyDescriptionLocalizedBuilder(builder, localeDescription);\n\n\treturn builder;\n}\n\n/**\n * Constructs an object that can be passed into `setChoices` for String or Number option with localized names.\n *\n * @param key The i18next key for the name of the select option name.\n * @param options The additional Select Menu options. This should _at least_ include the `value` key.\n * @returns An object with anything provided through {@link createLocalizedChoice.options} with `name` and `name_localizations` added.\n *\n * @example\n * ```typescript\n * export class TypeCommand extends Command {\n * public override registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand((builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:type').addStringOption((option) =>\n * applyLocalizedBuilder(option, 'commands/options:type')\n * .setRequired(true)\n * .setChoices(\n * createLocalizedChoice('selects/pokemon:type-grass', { value: 'grass' }),\n * createLocalizedChoice('selects/pokemon:type-water', { value: 'water' }),\n * createLocalizedChoice('selects/pokemon:type-fire', { value: 'fire' }),\n * createLocalizedChoice('selects/pokemon:type-electric', { value: 'electric' })\n * )\n * )\n * );\n * }\n * }\n * ```\n */\nexport function createLocalizedChoice<\n\tValueType = string | number,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>,\n\toptions: Omit<APIApplicationCommandOptionChoice<ValueType>, 'name' | 'name_localizations'>\n): APIApplicationCommandOptionChoice<ValueType> {\n\tconst result = getLocalizedData(key);\n\n\treturn {\n\t\t...options,\n\t\tname: result.value,\n\t\tname_localizations: result.localizations\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/register.ts"],"names":["Plugin","preGenericsInitialization","container","InternationalizationHandler","preLogin","postLogin","watch","SapphireClient"],"mappings":";;;;;;;;AAOO,IAAM,cAAA,GAAN,MAAM,cAAA,SAAsBA,gBAAO,CAAA;AAAA,EACzC,QAAeC,mCAAyB,CAAA,CAAwB,OAA8B,EAAA;AAC7F,IAAAC,mBAAA,CAAU,IAAO,GAAA,IAAIC,qCAA4B,CAAA,OAAA,CAAQ,IAAI,CAAA;AAAA;AAC9D,EAEA,cAAqBC,kBAAQ,CAAuC,GAAA;AACnE,IAAM,MAAAF,mBAAA,CAAU,KAAK,IAAK,EAAA;AAAA;AAC3B,EAEA,QAAeG,mBAAS,CAA8B,GAAA;AACrD,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA,GAAA,EAAK,OAAS,EAAA;AACpC,MAAUH,mBAAA,CAAA,MAAA,CAAO,KAAK,gEAAgE,CAAA;AAEtF,MAAMI,cAAA,CAAAJ,mBAAA,CAAU,IAAK,CAAA,kBAAA,EAAoB,IAAK,CAAA,OAAA,CAAQ,KAAK,GAAI,CAAA,OAAA,IAAW,EAAE,CAC1E,CAAA,EAAA,CAAG,UAAU,MAAMA,mBAAA,CAAU,IAAK,CAAA,eAAA,EAAiB,CAAA,CACnD,EAAG,CAAA,QAAA,EAAU,MAAMA,mBAAA,CAAU,IAAK,CAAA,eAAA,EAAiB,CAAA;AAAA;AACtD;AAEF,CAAA;AAlB0C,MAAA,CAAA,cAAA,EAAA,eAAA,CAAA;AAAnC,IAAM,aAAN,GAAA;AAoBPK,wBAAA,CAAe,OAAQ,CAAA,8BAAA,CAA+B,aAAc,CAAAN,mCAAyB,GAAG,mCAAmC,CAAA;AACnIM,wBAAA,CAAe,OAAQ,CAAA,oBAAA,CAAqB,aAAc,CAAAH,kBAAQ,GAAG,kBAAkB,CAAA;AACvFG,wBAAA,CAAe,OAAQ,CAAA,qBAAA,CAAsB,aAAc,CAAAF,mBAAS,GAAG,mBAAmB,CAAA","file":"register.cjs","sourcesContent":["import './index';\n\nimport { Plugin, SapphireClient, container, postLogin, preGenericsInitialization, preLogin } from '@sapphire/framework';\nimport { watch } from 'chokidar';\nimport type { ClientOptions } from 'discord.js';\nimport { InternationalizationHandler } from './index';\n\nexport class I18nextPlugin extends Plugin {\n\tpublic static [preGenericsInitialization](this: SapphireClient, options: ClientOptions): void {\n\t\tcontainer.i18n = new InternationalizationHandler(options.i18n);\n\t}\n\n\tpublic static async [preLogin](this: SapphireClient): Promise<void> {\n\t\tawait container.i18n.init();\n\t}\n\n\tpublic static [postLogin](this: SapphireClient): void {\n\t\tif (this.options.i18n?.hmr?.enabled) {\n\t\t\tcontainer.logger.info('[i18next-Plugin]: HMR enabled. Watching for languages changes.');\n\n\t\t\twatch(container.i18n.languagesDirectory, this.options.i18n.hmr.options ?? {})\n\t\t\t\t.on('change', () => container.i18n.reloadResources())\n\t\t\t\t.on('unlink', () => container.i18n.reloadResources());\n\t\t}\n\t}\n}\n\nSapphireClient.plugins.registerPostInitializationHook(I18nextPlugin[preGenericsInitialization], 'I18next-PreGenericsInitialization');\nSapphireClient.plugins.registerPreLoginHook(I18nextPlugin[preLogin], 'I18next-PreLogin');\nSapphireClient.plugins.registerPostLoginHook(I18nextPlugin[postLogin], 'I18next-PostLogin');\n"]}
1
+ {"version":3,"sources":["../../src/register.ts"],"names":["Plugin","preGenericsInitialization","container","InternationalizationHandler","preLogin","postLogin","watch","SapphireClient"],"mappings":";;;;;;;;AAOO,IAAM,cAAA,GAAN,MAAM,cAAA,SAAsBA,gBAAA,CAAO;AAAA,EACzC,QAAeC,mCAAyB,CAAA,CAAwB,OAAA,EAA8B;AAC7F,IAAAC,mBAAA,CAAU,IAAA,GAAO,IAAIC,qCAAA,CAA4B,OAAA,CAAQ,IAAI,CAAA;AAAA,EAC9D;AAAA,EAEA,cAAqBC,kBAAQ,CAAA,GAAuC;AACnE,IAAA,MAAMF,mBAAA,CAAU,KAAK,IAAA,EAAK;AAAA,EAC3B;AAAA,EAEA,QAAeG,mBAAS,CAAA,GAA8B;AACrD,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,GAAA,EAAK,OAAA,EAAS;AACpC,MAAAH,mBAAA,CAAU,MAAA,CAAO,KAAK,gEAAgE,CAAA;AAEtF,MAAAI,cAAA,CAAMJ,mBAAA,CAAU,IAAA,CAAK,kBAAA,EAAoB,IAAA,CAAK,OAAA,CAAQ,KAAK,GAAA,CAAI,OAAA,IAAW,EAAE,CAAA,CAC1E,EAAA,CAAG,UAAU,MAAMA,mBAAA,CAAU,IAAA,CAAK,eAAA,EAAiB,CAAA,CACnD,EAAA,CAAG,QAAA,EAAU,MAAMA,mBAAA,CAAU,IAAA,CAAK,eAAA,EAAiB,CAAA;AAAA,IACtD;AAAA,EACD;AACD,CAAA;AAlB0C,MAAA,CAAA,cAAA,EAAA,eAAA,CAAA;AAAnC,IAAM,aAAA,GAAN;AAoBPK,wBAAA,CAAe,OAAA,CAAQ,8BAAA,CAA+B,aAAA,CAAcN,mCAAyB,GAAG,mCAAmC,CAAA;AACnIM,wBAAA,CAAe,OAAA,CAAQ,oBAAA,CAAqB,aAAA,CAAcH,kBAAQ,GAAG,kBAAkB,CAAA;AACvFG,wBAAA,CAAe,OAAA,CAAQ,qBAAA,CAAsB,aAAA,CAAcF,mBAAS,GAAG,mBAAmB,CAAA","file":"register.cjs","sourcesContent":["import './index';\n\nimport { Plugin, SapphireClient, container, postLogin, preGenericsInitialization, preLogin } from '@sapphire/framework';\nimport { watch } from 'chokidar';\nimport type { ClientOptions } from 'discord.js';\nimport { InternationalizationHandler } from './index';\n\nexport class I18nextPlugin extends Plugin {\n\tpublic static [preGenericsInitialization](this: SapphireClient, options: ClientOptions): void {\n\t\tcontainer.i18n = new InternationalizationHandler(options.i18n);\n\t}\n\n\tpublic static async [preLogin](this: SapphireClient): Promise<void> {\n\t\tawait container.i18n.init();\n\t}\n\n\tpublic static [postLogin](this: SapphireClient): void {\n\t\tif (this.options.i18n?.hmr?.enabled) {\n\t\t\tcontainer.logger.info('[i18next-Plugin]: HMR enabled. Watching for languages changes.');\n\n\t\t\twatch(container.i18n.languagesDirectory, this.options.i18n.hmr.options ?? {})\n\t\t\t\t.on('change', () => container.i18n.reloadResources())\n\t\t\t\t.on('unlink', () => container.i18n.reloadResources());\n\t\t}\n\t}\n}\n\nSapphireClient.plugins.registerPostInitializationHook(I18nextPlugin[preGenericsInitialization], 'I18next-PreGenericsInitialization');\nSapphireClient.plugins.registerPreLoginHook(I18nextPlugin[preLogin], 'I18next-PreLogin');\nSapphireClient.plugins.registerPostLoginHook(I18nextPlugin[postLogin], 'I18next-PostLogin');\n"]}
@@ -4,7 +4,7 @@ export * from './lib/InternationalizationHandler.mjs';
4
4
  export * from './lib/functions.mjs';
5
5
  export * from './lib/types.mjs';
6
6
 
7
- var version = "8.0.1-next.e18dc27";
7
+ var version = "8.0.1-next.f67c68a";
8
8
 
9
9
  export { version };
10
10
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;AAyBO,IAAM,OAAkB,GAAA","file":"index.mjs","sourcesContent":["import type { InternationalizationHandler } from './lib/InternationalizationHandler';\nimport type { InternationalizationClientOptions } from './lib/types';\n\nexport { default as i18next, type TFunction, type TOptions } from 'i18next';\nexport * from './lib/InternationalizationHandler';\nexport * from './lib/functions';\nexport * from './lib/types';\n\ndeclare module '@sapphire/pieces' {\n\tinterface Container {\n\t\ti18n: InternationalizationHandler;\n\t}\n}\n\ndeclare module 'discord.js' {\n\texport interface ClientOptions extends InternationalizationClientOptions {}\n}\n\n/**\n * The [@sapphire/plugin-i18next](https://github.com/sapphiredev/plugins/blob/main/packages/i18next) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '8.0.1-next.e18dc27';\n"]}
1
+ {"version":3,"sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;AAyBO,IAAM,OAAA,GAAkB","file":"index.mjs","sourcesContent":["import type { InternationalizationHandler } from './lib/InternationalizationHandler';\nimport type { InternationalizationClientOptions } from './lib/types';\n\nexport { default as i18next, type TFunction, type TOptions } from 'i18next';\nexport * from './lib/InternationalizationHandler';\nexport * from './lib/functions';\nexport * from './lib/types';\n\ndeclare module '@sapphire/pieces' {\n\tinterface Container {\n\t\ti18n: InternationalizationHandler;\n\t}\n}\n\ndeclare module 'discord.js' {\n\texport interface ClientOptions extends InternationalizationClientOptions {}\n}\n\n/**\n * The [@sapphire/plugin-i18next](https://github.com/sapphiredev/plugins/blob/main/packages/i18next) version that you are currently using.\n * An example use of this is showing it of in a bot information command.\n *\n * Note to Sapphire developers: This needs to explicitly be `string` so it is not typed as the string that gets replaced by esbuild\n */\n// eslint-disable-next-line @typescript-eslint/no-inferrable-types\nexport const version: string = '8.0.1-next.f67c68a';\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":[],"mappings":"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","file":"InternationalizationHandler.mjs","sourcesContent":["import { Result } from '@sapphire/framework';\nimport { container, getRootData } from '@sapphire/pieces';\nimport { isFunction, type Awaitable } from '@sapphire/utilities';\nimport { Backend, type PathResolvable } from '@skyra/i18next-backend';\nimport i18next, {\n\ttype AppendKeyPrefix,\n\ttype DefaultNamespace,\n\ttype InterpolationMap,\n\ttype Namespace,\n\ttype ParseKeys,\n\ttype TFunction,\n\ttype TFunctionProcessReturnValue,\n\ttype TFunctionReturn,\n\ttype TFunctionReturnOptionalDetails,\n\ttype TOptions\n} from 'i18next';\nimport type { PathLike } from 'node:fs';\nimport { opendir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { URL, fileURLToPath } from 'node:url';\nimport type { $Dictionary, $NoInfer, $SpecialObject, InternationalizationContext, InternationalizationOptions } from './types';\n\n/**\n * A generalized class for handling `i18next` JSON files and their discovery.\n * @since 1.0.0\n */\nexport class InternationalizationHandler {\n\t/**\n\t * Describes whether {@link InternationalizationHandler.init} has been run and languages are loaded in {@link InternationalizationHandler.languages}.\n\t * @since 1.0.0\n\t */\n\tpublic languagesLoaded = false;\n\n\t/**\n\t * A `Set` of initially loaded namespaces.\n\t * @since 1.2.0\n\t */\n\tpublic namespaces = new Set<string>();\n\n\t/**\n\t * A `Map` of `i18next` language functions keyed by their language code.\n\t * @since 1.0.0\n\t */\n\tpublic readonly languages = new Map<string, TFunction>();\n\n\t/**\n\t * The options InternationalizationHandler was initialized with in the client.\n\t * @since 1.0.0\n\t */\n\tpublic readonly options: InternationalizationOptions;\n\n\t/**\n\t * The director passed to `@skyra/i18next-backend`.\n\t * Also used in {@link InternationalizationHandler.walkLanguageDirectory}.\n\t * @since 1.2.0\n\t */\n\tpublic readonly languagesDirectory: string;\n\n\t/**\n\t * The backend options for `@skyra/i18next-backend` used by `i18next`.\n\t * @since 1.0.0\n\t */\n\tprotected readonly backendOptions: Backend.Options;\n\n\t/**\n\t * @param options The options that `i18next`, `@skyra/i18next-backend`, and {@link InternationalizationHandler} should use.\n\t * @since 1.0.0\n\t * @constructor\n\t */\n\tpublic constructor(options?: InternationalizationOptions) {\n\t\tthis.options = options ?? { i18next: { ignoreJSONStructure: false } };\n\n\t\tconst baseUserDirectory =\n\t\t\tcontainer.client?.options?.baseUserDirectory instanceof URL\n\t\t\t\t? fileURLToPath(container.client?.options?.baseUserDirectory)\n\t\t\t\t: container.client?.options?.baseUserDirectory;\n\n\t\tthis.languagesDirectory = this.options.defaultLanguageDirectory ?? join(baseUserDirectory ?? getRootData().root, 'languages');\n\n\t\tconst languagePaths = new Set<PathResolvable>([\n\t\t\tjoin(this.languagesDirectory, '{{lng}}', '{{ns}}.json'), //\n\t\t\t...(options?.backend?.paths ?? [])\n\t\t]);\n\n\t\tthis.backendOptions = {\n\t\t\tpaths: [...languagePaths],\n\t\t\t...this.options.backend\n\t\t};\n\n\t\tif (isFunction(this.options.fetchLanguage)) {\n\t\t\tthis.fetchLanguage = this.options.fetchLanguage;\n\t\t}\n\t}\n\n\t/**\n\t * The method to be overridden by the developer.\n\t *\n\t * @note In the event that fetchLanguage is not defined or returns null / undefined, the defaulting from {@link fetchLanguage} will be used.\n\t * @since 2.0.0\n\t * @return A string for the desired language or null for no match.\n\t * @see {@link fetchLanguage}\n\t * @example\n\t * ```typescript\n\t * // Always use the same language (no per-guild configuration):\n\t * container.i18n.fetchLanguage = () => 'en-US';\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an SQL database:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getOne('SELECT language FROM public.guild WHERE id = $1', [context.guild.id]);\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an ORM:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getRepository(GuildEntity).findOne({ id: context.guild.id });\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language on a per channel basis, e.g. per user or guild channel (ORM example but same principles apply):\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const channel = await driver.getRepository(ChannelEntity).findOne({ id: context.channel.id });\n\t * return channel?.language ?? 'en-US';\n\t * };\n\t * ```\n\t */\n\tpublic fetchLanguage: (context: InternationalizationContext) => Awaitable<string | null> = () => null;\n\n\t/**\n\t * Initializes the handler by loading in the namespaces, passing the data to i18next, and filling in the {@link InternationalizationHandler#languages}.\n\t * @since 1.0.0\n\t */\n\tpublic async init() {\n\t\tconst { namespaces, languages } = await this.walkRootDirectory(this.languagesDirectory);\n\t\tconst userOptions = isFunction(this.options.i18next) ? this.options.i18next(namespaces, languages) : this.options.i18next;\n\t\tconst ignoreJSONStructure = userOptions?.ignoreJSONStructure ?? false;\n\t\tconst skipOnVariables = userOptions?.interpolation?.skipOnVariables ?? false;\n\n\t\ti18next.use(Backend);\n\t\tawait i18next.init({\n\t\t\tbackend: this.backendOptions,\n\t\t\tfallbackLng: this.options.defaultName ?? 'en-US',\n\t\t\tinitImmediate: false,\n\t\t\tinterpolation: {\n\t\t\t\tescapeValue: false,\n\t\t\t\t...userOptions?.interpolation,\n\t\t\t\tskipOnVariables\n\t\t\t},\n\t\t\tload: 'all',\n\t\t\tdefaultNS: 'default',\n\t\t\tns: namespaces,\n\t\t\tpreload: languages,\n\t\t\t...userOptions,\n\t\t\tignoreJSONStructure\n\t\t});\n\n\t\tthis.namespaces = new Set(namespaces);\n\t\tfor (const item of languages) {\n\t\t\tthis.languages.set(item, i18next.getFixedT(item));\n\t\t}\n\t\tthis.languagesLoaded = true;\n\n\t\tconst formatter = i18next.services.formatter!;\n\t\tconst formatters = this.options.formatters ?? [];\n\t\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\t\tfor (const { name, format, cached } of formatters) {\n\t\t\tif (cached) formatter.addCached(name, format);\n\t\t\telse formatter.add(name, format);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a raw TFunction from the passed locale.\n\t * @param locale The language to be used.\n\t * @since 1.0.0\n\t */\n\tpublic getT(locale: string) {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst t = this.languages.get(locale);\n\t\tif (t) return t;\n\t\tthrow new ReferenceError('Invalid language provided');\n\t}\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: Key | Key[], options?: ActualOptions): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param defaultValue The default value to use if the key is not found.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(\n\t\tlocale: string,\n\t\tkey: string | string[],\n\t\tdefaultValue: string | undefined,\n\t\toptions?: TOpt & $Dictionary\n\t): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t *\n\t * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n\t * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n\t * for the documentation on those parameters.\n\t *\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,\n\t\tDefaultValue extends string = never\n\t>(\n\t\tlocale: string,\n\t\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t\t| [key: string | string[], defaultValue: DefaultValue | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt> {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst language = this.languages.get(locale);\n\t\tif (!language) throw new ReferenceError('Invalid language provided');\n\n\t\tconst defaultValue =\n\t\t\ttypeof defaultValueOrOptions === 'string'\n\t\t\t\t? defaultValueOrOptions\n\t\t\t\t: this.options.defaultMissingKey\n\t\t\t\t\t? language(this.options.defaultMissingKey, { replace: { key } })\n\t\t\t\t\t: '';\n\n\t\treturn language<Key, TOpt, Ret, ActualOptions, DefaultValue>(key, {\n\t\t\tdefaultValue,\n\t\t\t...((optionsOrUndefined ?? {}) as TOpt)\n\t\t} as TOpt & $Dictionary & { defaultValue: DefaultValue });\n\t}\n\n\t/**\n\t * @param directory The directory that should be walked.\n\t * @since 3.0.0\n\t */\n\tpublic async walkRootDirectory(directory: PathLike) {\n\t\tconst languages = new Set<string>();\n\t\tconst namespaces = new Set<string>();\n\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\t// If the entry is not a directory, skip:\n\t\t\tif (!entry.isDirectory()) continue;\n\n\t\t\t// Load the directory:\n\t\t\tlanguages.add(entry.name);\n\n\t\t\tfor await (const namespace of this.walkLocaleDirectory(join(dir.path, entry.name), '')) {\n\t\t\t\tnamespaces.add(namespace);\n\t\t\t}\n\t\t}\n\n\t\treturn { namespaces: [...namespaces], languages: [...languages] };\n\t}\n\n\tpublic async reloadResources() {\n\t\tconst result = await Result.fromAsync(async () => {\n\t\t\tlet languages = this.options.hmr?.languages;\n\t\t\tlet namespaces = this.options.hmr?.namespaces;\n\t\t\tif (!languages || !namespaces) {\n\t\t\t\tconst languageDirectoryResult = await this.walkRootDirectory(this.languagesDirectory);\n\t\t\t\tlanguages ??= languageDirectoryResult.languages;\n\t\t\t\tnamespaces ??= languageDirectoryResult.namespaces;\n\t\t\t}\n\n\t\t\tawait i18next.reloadResources(languages, namespaces);\n\t\t\tcontainer.logger.info('[i18next-Plugin] Reloaded language resources.');\n\t\t});\n\n\t\tresult.inspectErr((error) => container.logger.error('[i18next-Plugin]: Failed to reload language resources.', error));\n\t}\n\n\t/**\n\t * @description Skips any files that don't end with `.json`.\n\t * @param directory The directory that should be walked.\n\t * @param ns The current namespace.\n\t * @since 3.0.0\n\t */\n\tprivate async *walkLocaleDirectory(directory: string, ns: string): AsyncGenerator<string> {\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tyield* this.walkLocaleDirectory(join(dir.path, entry.name), `${ns}${entry.name}/`);\n\t\t\t} else if (entry.isFile() && entry.name.endsWith('.json')) {\n\t\t\t\tyield `${ns}${entry.name.slice(0, -5)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":[],"mappings":"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","file":"InternationalizationHandler.mjs","sourcesContent":["import { Result } from '@sapphire/framework';\nimport { container, getRootData } from '@sapphire/pieces';\nimport { isFunction, type Awaitable } from '@sapphire/utilities';\nimport { Backend, type PathResolvable } from '@skyra/i18next-backend';\nimport i18next, {\n\ttype AppendKeyPrefix,\n\ttype DefaultNamespace,\n\ttype InterpolationMap,\n\ttype Namespace,\n\ttype ParseKeys,\n\ttype TFunction,\n\ttype TFunctionProcessReturnValue,\n\ttype TFunctionReturn,\n\ttype TFunctionReturnOptionalDetails,\n\ttype TOptions\n} from 'i18next';\nimport type { PathLike } from 'node:fs';\nimport { opendir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { URL, fileURLToPath } from 'node:url';\nimport type { $Dictionary, $NoInfer, $SpecialObject, InternationalizationContext, InternationalizationOptions } from './types';\n\n/**\n * A generalized class for handling `i18next` JSON files and their discovery.\n * @since 1.0.0\n */\nexport class InternationalizationHandler {\n\t/**\n\t * Describes whether {@link InternationalizationHandler.init} has been run and languages are loaded in {@link InternationalizationHandler.languages}.\n\t * @since 1.0.0\n\t */\n\tpublic languagesLoaded = false;\n\n\t/**\n\t * A `Set` of initially loaded namespaces.\n\t * @since 1.2.0\n\t */\n\tpublic namespaces = new Set<string>();\n\n\t/**\n\t * A `Map` of `i18next` language functions keyed by their language code.\n\t * @since 1.0.0\n\t */\n\tpublic readonly languages = new Map<string, TFunction>();\n\n\t/**\n\t * The options InternationalizationHandler was initialized with in the client.\n\t * @since 1.0.0\n\t */\n\tpublic readonly options: InternationalizationOptions;\n\n\t/**\n\t * The director passed to `@skyra/i18next-backend`.\n\t * Also used in {@link InternationalizationHandler.walkLanguageDirectory}.\n\t * @since 1.2.0\n\t */\n\tpublic readonly languagesDirectory: string;\n\n\t/**\n\t * The backend options for `@skyra/i18next-backend` used by `i18next`.\n\t * @since 1.0.0\n\t */\n\tprotected readonly backendOptions: Backend.Options;\n\n\t/**\n\t * @param options The options that `i18next`, `@skyra/i18next-backend`, and {@link InternationalizationHandler} should use.\n\t * @since 1.0.0\n\t * @constructor\n\t */\n\tpublic constructor(options?: InternationalizationOptions) {\n\t\tthis.options = options ?? { i18next: { ignoreJSONStructure: false } };\n\n\t\tconst baseUserDirectory =\n\t\t\tcontainer.client?.options?.baseUserDirectory instanceof URL\n\t\t\t\t? fileURLToPath(container.client?.options?.baseUserDirectory)\n\t\t\t\t: container.client?.options?.baseUserDirectory;\n\n\t\tthis.languagesDirectory = this.options.defaultLanguageDirectory ?? join(baseUserDirectory ?? getRootData().root, 'languages');\n\n\t\tconst languagePaths = new Set<PathResolvable>([\n\t\t\tjoin(this.languagesDirectory, '{{lng}}', '{{ns}}.json'), //\n\t\t\t...(options?.backend?.paths ?? [])\n\t\t]);\n\n\t\tthis.backendOptions = {\n\t\t\tpaths: [...languagePaths],\n\t\t\t...this.options.backend\n\t\t};\n\n\t\tif (isFunction(this.options.fetchLanguage)) {\n\t\t\tthis.fetchLanguage = this.options.fetchLanguage;\n\t\t}\n\t}\n\n\t/**\n\t * The method to be overridden by the developer.\n\t *\n\t * @note In the event that fetchLanguage is not defined or returns null / undefined, the defaulting from {@link fetchLanguage} will be used.\n\t * @since 2.0.0\n\t * @return A string for the desired language or null for no match.\n\t * @see {@link fetchLanguage}\n\t * @example\n\t * ```typescript\n\t * // Always use the same language (no per-guild configuration):\n\t * container.i18n.fetchLanguage = () => 'en-US';\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an SQL database:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getOne('SELECT language FROM public.guild WHERE id = $1', [context.guild.id]);\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language from an ORM:\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const guild = await driver.getRepository(GuildEntity).findOne({ id: context.guild.id });\n\t * return guild?.language ?? 'en-US';\n\t * };\n\t * ```\n\t * @example\n\t * ```typescript\n\t * // Retrieving the language on a per channel basis, e.g. per user or guild channel (ORM example but same principles apply):\n\t * container.i18n.fetchLanguage = async (context) => {\n\t * const channel = await driver.getRepository(ChannelEntity).findOne({ id: context.channel.id });\n\t * return channel?.language ?? 'en-US';\n\t * };\n\t * ```\n\t */\n\tpublic fetchLanguage: (context: InternationalizationContext) => Awaitable<string | null> = () => null;\n\n\t/**\n\t * Initializes the handler by loading in the namespaces, passing the data to i18next, and filling in the {@link InternationalizationHandler#languages}.\n\t * @since 1.0.0\n\t */\n\tpublic async init() {\n\t\tconst { namespaces, languages } = await this.walkRootDirectory(this.languagesDirectory);\n\t\tconst userOptions = isFunction(this.options.i18next) ? this.options.i18next(namespaces, languages) : this.options.i18next;\n\t\tconst ignoreJSONStructure = userOptions?.ignoreJSONStructure ?? false;\n\t\tconst skipOnVariables = userOptions?.interpolation?.skipOnVariables ?? false;\n\n\t\ti18next.use(Backend);\n\t\tawait i18next.init({\n\t\t\tbackend: this.backendOptions,\n\t\t\tfallbackLng: this.options.defaultName ?? 'en-US',\n\t\t\tinitImmediate: false,\n\t\t\tinterpolation: {\n\t\t\t\tescapeValue: false,\n\t\t\t\t...userOptions?.interpolation,\n\t\t\t\tskipOnVariables\n\t\t\t},\n\t\t\tload: 'all',\n\t\t\tdefaultNS: 'default',\n\t\t\tns: namespaces,\n\t\t\tpreload: languages,\n\t\t\t...userOptions,\n\t\t\tignoreJSONStructure\n\t\t});\n\n\t\tthis.namespaces = new Set(namespaces);\n\t\tfor (const item of languages) {\n\t\t\tthis.languages.set(item, i18next.getFixedT(item));\n\t\t}\n\t\tthis.languagesLoaded = true;\n\n\t\tconst formatter = i18next.services.formatter!;\n\t\tconst formatters = this.options.formatters ?? [];\n\t\t// eslint-disable-next-line @typescript-eslint/unbound-method\n\t\tfor (const { name, format, cached } of formatters) {\n\t\t\tif (cached) formatter.addCached(name, format);\n\t\t\telse formatter.add(name, format);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieve a raw TFunction from the passed locale.\n\t * @param locale The language to be used.\n\t * @since 1.0.0\n\t */\n\tpublic getT(locale: string) {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst t = this.languages.get(locale);\n\t\tif (t) return t;\n\t\tthrow new ReferenceError('Invalid language provided');\n\t}\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: Key | Key[], options?: ActualOptions): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(locale: string, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t * @param key The key or keys to retrieve the content from.\n\t * @param defaultValue The default value to use if the key is not found.\n\t * @param options The interpolation options.\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n\t>(\n\t\tlocale: string,\n\t\tkey: string | string[],\n\t\tdefaultValue: string | undefined,\n\t\toptions?: TOpt & $Dictionary\n\t): TFunctionReturnOptionalDetails<Ret, TOpt>;\n\n\t/**\n\t * Localizes a content given one or more keys and i18next options.\n\t * @since 2.0.0\n\t * @param locale The language to be used.\n\t *\n\t * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n\t * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n\t * for the documentation on those parameters.\n\t *\n\t * @see {@link https://www.i18next.com/overview/api#t}\n\t * @returns The localized content.\n\t */\n\tpublic format<\n\t\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\t\tconst TOpt extends TOptions = TOptions,\n\t\tNs extends Namespace = DefaultNamespace,\n\t\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\t\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>,\n\t\tDefaultValue extends string = never\n\t>(\n\t\tlocale: string,\n\t\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t\t| [key: string | string[], defaultValue: DefaultValue | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<TFunctionProcessReturnValue<$NoInfer<Ret>, DefaultValue>, TOpt> {\n\t\tif (!this.languagesLoaded) throw new Error('Cannot call this method until InternationalizationHandler#init has been called');\n\n\t\tconst language = this.languages.get(locale);\n\t\tif (!language) throw new ReferenceError('Invalid language provided');\n\n\t\tconst defaultValue =\n\t\t\ttypeof defaultValueOrOptions === 'string'\n\t\t\t\t? defaultValueOrOptions\n\t\t\t\t: this.options.defaultMissingKey\n\t\t\t\t\t? language(this.options.defaultMissingKey, { replace: { key } })\n\t\t\t\t\t: '';\n\n\t\treturn language<Key, TOpt, Ret, ActualOptions, DefaultValue>(key, {\n\t\t\tdefaultValue,\n\t\t\t...((optionsOrUndefined ?? {}) as TOpt)\n\t\t} as TOpt & $Dictionary & { defaultValue: DefaultValue });\n\t}\n\n\t/**\n\t * @param directory The directory that should be walked.\n\t * @since 3.0.0\n\t */\n\tpublic async walkRootDirectory(directory: PathLike) {\n\t\tconst languages = new Set<string>();\n\t\tconst namespaces = new Set<string>();\n\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\t// If the entry is not a directory, skip:\n\t\t\tif (!entry.isDirectory()) continue;\n\n\t\t\t// Load the directory:\n\t\t\tlanguages.add(entry.name);\n\n\t\t\tfor await (const namespace of this.walkLocaleDirectory(join(dir.path, entry.name), '')) {\n\t\t\t\tnamespaces.add(namespace);\n\t\t\t}\n\t\t}\n\n\t\treturn { namespaces: [...namespaces], languages: [...languages] };\n\t}\n\n\tpublic async reloadResources() {\n\t\tconst result = await Result.fromAsync(async () => {\n\t\t\tlet languages = this.options.hmr?.languages;\n\t\t\tlet namespaces = this.options.hmr?.namespaces;\n\t\t\tif (!languages || !namespaces) {\n\t\t\t\tconst languageDirectoryResult = await this.walkRootDirectory(this.languagesDirectory);\n\t\t\t\tlanguages ??= languageDirectoryResult.languages;\n\t\t\t\tnamespaces ??= languageDirectoryResult.namespaces;\n\t\t\t}\n\n\t\t\tawait i18next.reloadResources(languages, namespaces);\n\t\t\tcontainer.logger.info('[i18next-Plugin] Reloaded language resources.');\n\t\t});\n\n\t\tresult.inspectErr((error) => container.logger.error('[i18next-Plugin]: Failed to reload language resources.', error));\n\t}\n\n\t/**\n\t * @description Skips any files that don't end with `.json`.\n\t * @param directory The directory that should be walked.\n\t * @param ns The current namespace.\n\t * @since 3.0.0\n\t */\n\tprivate async *walkLocaleDirectory(directory: string, ns: string): AsyncGenerator<string> {\n\t\tconst dir = await opendir(directory);\n\t\tfor await (const entry of dir) {\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tyield* this.walkLocaleDirectory(join(dir.path, entry.name), `${ns}${entry.name}/`);\n\t\t\t} else if (entry.isFile() && entry.name.endsWith('.json')) {\n\t\t\t\tyield `${ns}${entry.name.slice(0, -5)}`;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/functions.ts"],"names":[],"mappings":"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","file":"functions.mjs","sourcesContent":["import { container } from '@sapphire/pieces';\nimport { lazy } from '@sapphire/utilities';\nimport { BaseInteraction, ChannelType, Guild, Locale, Message, type APIApplicationCommandOptionChoice, type LocaleString } from 'discord.js';\nimport type {\n\tAppendKeyPrefix,\n\tDefaultNamespace,\n\tInterpolationMap,\n\tNamespace,\n\tParseKeys,\n\tTFunctionReturn,\n\tTFunctionReturnOptionalDetails,\n\tTOptions\n} from 'i18next';\nimport type {\n\t$Dictionary,\n\t$SpecialObject,\n\tBuilderWithDescription,\n\tBuilderWithName,\n\tBuilderWithNameAndDescription,\n\tInternationalizationContext,\n\tLocalizedData,\n\tTarget\n} from './types';\n\n/**\n * Retrieves the language name for a specific target, using {@link InternationalizationHandler.fetchLanguage}.\n * If {@link InternationalizationHandler.fetchLanguage} is not defined or this function returns a nullish value,\n * then there will be a series of fallback attempts in the following descending order:\n * 1. Returns {@link Guild.preferredLocale}.\n * 2. Returns {@link InternationalizationOptions.defaultName} if no guild was provided.\n * 3. Returns `'en-US'` if nothing else was found.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @see {@link resolveLanguage}\n * @returns The name of the language key.\n */\nexport function fetchLanguage(target: Target): Promise<string> {\n\t// Handle Interactions:\n\tif (target instanceof BaseInteraction) {\n\t\treturn resolveLanguage({\n\t\t\tuser: target.user,\n\t\t\tchannel: target.channel,\n\t\t\tguild: target.guild,\n\t\t\tinteractionGuildLocale: target.guildLocale,\n\t\t\tinteractionLocale: target.locale\n\t\t});\n\t}\n\n\t// Handle Message:\n\tif (target instanceof Message) {\n\t\treturn resolveLanguage({ user: target.author, channel: target.channel, guild: target.guild });\n\t}\n\n\t// Handle Guild:\n\tif (target instanceof Guild) {\n\t\treturn resolveLanguage({ user: null, channel: null, guild: target });\n\t}\n\n\t// Handle DMChannel and GroupDMChannel:\n\tif (target.type === ChannelType.DM || target.type === ChannelType.GroupDM) {\n\t\treturn resolveLanguage({ user: null, channel: target, guild: null });\n\t}\n\n\t// Handle any other channel:\n\treturn resolveLanguage({ user: null, channel: target, guild: target.guild });\n}\n\n/**\n * Retrieves the language-assigned function from i18next designated to a target's preferred language code.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @returns The language function from i18next.\n */\nexport async function fetchT(target: Target) {\n\treturn container.i18n.getT(await fetchLanguage(target));\n}\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The options to be passed to TFunction.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: Key | Key[], options?: ActualOptions): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param defaultValue The default value to use if the key is not found.\n * @param options The interpolation options.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], defaultValue: string, options?: TOpt & $Dictionary): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n *\n * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n * for the documentation on those parameters.\n *\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(\n\ttarget: Target,\n\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t| [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]\n): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>> {\n\tconst parsedOptions = typeof defaultValueOrOptions === 'string' ? optionsOrUndefined : defaultValueOrOptions;\n\tconst language = typeof parsedOptions?.lng === 'string' ? parsedOptions.lng : await fetchLanguage(target);\n\n\tif (typeof defaultValueOrOptions === 'string') {\n\t\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, defaultValueOrOptions, optionsOrUndefined);\n\t}\n\n\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, undefined, defaultValueOrOptions);\n}\n\n/**\n * @internal\n */\nasync function resolveLanguage(context: InternationalizationContext): Promise<string> {\n\tconst lang = await container.i18n.fetchLanguage(context);\n\treturn lang ?? context.guild?.preferredLocale ?? container.i18n.options.defaultName ?? 'en-US';\n}\n\nconst supportedLanguages = new Set(Object.values(Locale)) as ReadonlySet<LocaleString>;\n\nfunction isSupportedDiscordLocale(language: string): language is LocaleString {\n\treturn supportedLanguages.has(language as LocaleString);\n}\n\nconst getLocales = lazy(() => {\n\tconst locales = new Map(container.i18n.languages);\n\n\tfor (const [locale] of locales) {\n\t\tif (!isSupportedDiscordLocale(locale)) {\n\t\t\tprocess.emitWarning('Unsupported Discord locale', {\n\t\t\t\tcode: 'UNSUPPORTED_LOCALE',\n\t\t\t\tdetail: `'${locale}' needs to be one of: ${[...locales.keys()]}`\n\t\t\t});\n\n\t\t\tlocales.delete(locale);\n\t\t}\n\n\t\tcontinue;\n\t}\n\n\treturn locales;\n});\n\nconst getDefaultT = lazy(() => {\n\tconst defaultLocale = container.i18n.options.defaultName ?? 'en-US';\n\n\tif (!isSupportedDiscordLocale(defaultLocale)) {\n\t\tthrow new TypeError(`Unsupported Discord locale found:\\n'${defaultLocale}' is not within the list of ${[...supportedLanguages]}`);\n\t}\n\n\tconst defaultT = getLocales().get(defaultLocale);\n\n\tif (defaultT) {\n\t\treturn defaultT;\n\t}\n\n\tthrow new TypeError(`Could not find ${defaultLocale}`);\n});\n\n/**\n * Gets the value and the localizations from a language key.\n * @param key The key to get the localizations from.\n * @returns The retrieved data.\n * @remarks This should be called **strictly** after loading the locales.\n */\nexport function getLocalizedData<const TOpt extends TOptions = TOptions, Ns extends Namespace = DefaultNamespace, KPrefix = undefined>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>\n): LocalizedData {\n\tconst locales = getLocales();\n\tconst defaultT = getDefaultT();\n\n\treturn {\n\t\tvalue: defaultT(key),\n\t\tlocalizations: Object.fromEntries(Array.from(locales, ([locale, t]) => [locale, t(key)]))\n\t};\n}\n\n/**\n * Applies the localized names on the builder, calling `setName` and `setNameLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyNameLocalizedBuilder<\n\tT extends BuilderWithName,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setName(result.value).setNameLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized descriptions on the builder, calling `setDescription` and `setDescriptionLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyDescriptionLocalizedBuilder<\n\tT extends BuilderWithDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setDescription(result.value).setDescriptionLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized names and descriptions on the builder, calling {@link applyNameLocalizedBuilder} and\n * {@link applyDescriptionLocalizedBuilder}.\n *\n * @param builder The builder to apply the localizations to.\n *\n * @param params The root key or the key for the name and description keys.\n * This needs to be either 1 or 2 parameters.\n * See examples below for more information.\n *\n * @returns The updated builder. You can chain subsequent builder methods on this.\n *\n * @remarks If only 2 parameters were passed, then this function will automatically append `Name` and `Description`\n * to the root-key (wherein `root-key` is second parameter in the function, after `builder`)\n * passed through the second parameter.\n *\n * For example given `applyLocalizedBuilder(builder, 'userinfo')` the localized options will use the i18next keys\n * `userinfoName` and `userinfoDescription`.\n *\n * In the following example we provide all parameters and add a User Option\n * `applyLocalizedBuilder` needs either\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:userinfo', 'commands/descriptions:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'commands/options:userinfo-name', 'commands/options:userinfo-description').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n *\n * In the following example we provide single root keys which means `Name` and `Description` get appended as mentioned above.\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'options:userinfo').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n */\nexport function applyLocalizedBuilder<\n\tT extends BuilderWithNameAndDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, ...params: [root: string] | [name: ParseKeys<Ns, TOpt, KPrefix>, description: ParseKeys<Ns, TOpt, KPrefix>]): T {\n\ttype LocalKeysType = ParseKeys<Ns, TOpt, KPrefix>;\n\n\tconst [localeName, localeDescription] =\n\t\tparams.length === 1 ? [`${params[0]}Name` as LocalKeysType, `${params[0]}Description` as LocalKeysType] : params;\n\n\tapplyNameLocalizedBuilder(builder, localeName);\n\tapplyDescriptionLocalizedBuilder(builder, localeDescription);\n\n\treturn builder;\n}\n\n/**\n * Constructs an object that can be passed into `setChoices` for String or Number option with localized names.\n *\n * @param key The i18next key for the name of the select option name.\n * @param options The additional Select Menu options. This should _at least_ include the `value` key.\n * @returns An object with anything provided through {@link createLocalizedChoice.options} with `name` and `name_localizations` added.\n *\n * @example\n * ```typescript\n * export class TypeCommand extends Command {\n * public override registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand((builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:type').addStringOption((option) =>\n * applyLocalizedBuilder(option, 'commands/options:type')\n * .setRequired(true)\n * .setChoices(\n * createLocalizedChoice('selects/pokemon:type-grass', { value: 'grass' }),\n * createLocalizedChoice('selects/pokemon:type-water', { value: 'water' }),\n * createLocalizedChoice('selects/pokemon:type-fire', { value: 'fire' }),\n * createLocalizedChoice('selects/pokemon:type-electric', { value: 'electric' })\n * )\n * )\n * );\n * }\n * }\n * ```\n */\nexport function createLocalizedChoice<\n\tValueType = string | number,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>,\n\toptions: Omit<APIApplicationCommandOptionChoice<ValueType>, 'name' | 'name_localizations'>\n): APIApplicationCommandOptionChoice<ValueType> {\n\tconst result = getLocalizedData(key);\n\n\treturn {\n\t\t...options,\n\t\tname: result.value,\n\t\tname_localizations: result.localizations\n\t};\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/functions.ts"],"names":[],"mappings":"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","file":"functions.mjs","sourcesContent":["import { container } from '@sapphire/pieces';\nimport { lazy } from '@sapphire/utilities';\nimport { BaseInteraction, ChannelType, Guild, Locale, Message, type APIApplicationCommandOptionChoice, type LocaleString } from 'discord.js';\nimport type {\n\tAppendKeyPrefix,\n\tDefaultNamespace,\n\tInterpolationMap,\n\tNamespace,\n\tParseKeys,\n\tTFunctionReturn,\n\tTFunctionReturnOptionalDetails,\n\tTOptions\n} from 'i18next';\nimport type {\n\t$Dictionary,\n\t$SpecialObject,\n\tBuilderWithDescription,\n\tBuilderWithName,\n\tBuilderWithNameAndDescription,\n\tInternationalizationContext,\n\tLocalizedData,\n\tTarget\n} from './types';\n\n/**\n * Retrieves the language name for a specific target, using {@link InternationalizationHandler.fetchLanguage}.\n * If {@link InternationalizationHandler.fetchLanguage} is not defined or this function returns a nullish value,\n * then there will be a series of fallback attempts in the following descending order:\n * 1. Returns {@link Guild.preferredLocale}.\n * 2. Returns {@link InternationalizationOptions.defaultName} if no guild was provided.\n * 3. Returns `'en-US'` if nothing else was found.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @see {@link resolveLanguage}\n * @returns The name of the language key.\n */\nexport function fetchLanguage(target: Target): Promise<string> {\n\t// Handle Interactions:\n\tif (target instanceof BaseInteraction) {\n\t\treturn resolveLanguage({\n\t\t\tuser: target.user,\n\t\t\tchannel: target.channel,\n\t\t\tguild: target.guild,\n\t\t\tinteractionGuildLocale: target.guildLocale,\n\t\t\tinteractionLocale: target.locale\n\t\t});\n\t}\n\n\t// Handle Message:\n\tif (target instanceof Message) {\n\t\treturn resolveLanguage({ user: target.author, channel: target.channel, guild: target.guild });\n\t}\n\n\t// Handle Guild:\n\tif (target instanceof Guild) {\n\t\treturn resolveLanguage({ user: null, channel: null, guild: target });\n\t}\n\n\t// Handle DMChannel and GroupDMChannel:\n\tif (target.type === ChannelType.DM || target.type === ChannelType.GroupDM) {\n\t\treturn resolveLanguage({ user: null, channel: target, guild: null });\n\t}\n\n\t// Handle any other channel:\n\treturn resolveLanguage({ user: null, channel: target, guild: target.guild });\n}\n\n/**\n * Retrieves the language-assigned function from i18next designated to a target's preferred language code.\n * @since 2.0.0\n * @param target The target to fetch the language from.\n * @returns The language function from i18next.\n */\nexport async function fetchT(target: Target) {\n\treturn container.i18n.getT(await fetchLanguage(target));\n}\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The options to be passed to TFunction.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: Key | Key[], options?: ActualOptions): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param options The interpolation options as well as a `defaultValue` for the key and any key/value pairs.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n * @param key The i18next key.\n * @param defaultValue The default value to use if the key is not found.\n * @param options The interpolation options.\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(target: Target, key: string | string[], defaultValue: string, options?: TOpt & $Dictionary): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>>;\n\n/**\n * Resolves a key and its parameters.\n * @since 2.0.0\n * @param target The target to fetch the language key from.\n *\n * @remark This function also has additional parameters for `key`, `defaultValue`, and `options`, however\n * TSDoc does not let us document those while matching proper implementation. See the overloads for this method\n * for the documentation on those parameters.\n *\n * @returns The data that `key` held, processed by i18next.\n */\nexport async function resolveKey<\n\tconst Key extends ParseKeys<Ns, TOpt, undefined>,\n\tconst TOpt extends TOptions = TOptions,\n\tRet extends TFunctionReturn<Ns, AppendKeyPrefix<Key, undefined>, TOpt> = TOpt['returnObjects'] extends true ? $SpecialObject : string,\n\tNs extends Namespace = DefaultNamespace,\n\tconst ActualOptions extends TOpt & InterpolationMap<Ret> = TOpt & InterpolationMap<Ret>\n>(\n\ttarget: Target,\n\t...[key, defaultValueOrOptions, optionsOrUndefined]:\n\t\t| [key: Key | Key[], options?: ActualOptions]\n\t\t| [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }]\n\t\t| [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary]\n): Promise<TFunctionReturnOptionalDetails<Ret, TOpt>> {\n\tconst parsedOptions = typeof defaultValueOrOptions === 'string' ? optionsOrUndefined : defaultValueOrOptions;\n\tconst language = typeof parsedOptions?.lng === 'string' ? parsedOptions.lng : await fetchLanguage(target);\n\n\tif (typeof defaultValueOrOptions === 'string') {\n\t\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, defaultValueOrOptions, optionsOrUndefined);\n\t}\n\n\treturn container.i18n.format<Key, TOpt, Ns, Ret, ActualOptions>(language, key, undefined, defaultValueOrOptions);\n}\n\n/**\n * @internal\n */\nasync function resolveLanguage(context: InternationalizationContext): Promise<string> {\n\tconst lang = await container.i18n.fetchLanguage(context);\n\treturn lang ?? context.guild?.preferredLocale ?? container.i18n.options.defaultName ?? 'en-US';\n}\n\nconst supportedLanguages = new Set(Object.values(Locale)) as ReadonlySet<LocaleString>;\n\nfunction isSupportedDiscordLocale(language: string): language is LocaleString {\n\treturn supportedLanguages.has(language as LocaleString);\n}\n\nconst getLocales = lazy(() => {\n\tconst locales = new Map(container.i18n.languages);\n\n\tfor (const [locale] of locales) {\n\t\tif (!isSupportedDiscordLocale(locale)) {\n\t\t\tprocess.emitWarning('Unsupported Discord locale', {\n\t\t\t\tcode: 'UNSUPPORTED_LOCALE',\n\t\t\t\tdetail: `'${locale}' needs to be one of: ${[...locales.keys()]}`\n\t\t\t});\n\n\t\t\tlocales.delete(locale);\n\t\t}\n\n\t\tcontinue;\n\t}\n\n\treturn locales;\n});\n\nconst getDefaultT = lazy(() => {\n\tconst defaultLocale = container.i18n.options.defaultName ?? 'en-US';\n\n\tif (!isSupportedDiscordLocale(defaultLocale)) {\n\t\tthrow new TypeError(`Unsupported Discord locale found:\\n'${defaultLocale}' is not within the list of ${[...supportedLanguages]}`);\n\t}\n\n\tconst defaultT = getLocales().get(defaultLocale);\n\n\tif (defaultT) {\n\t\treturn defaultT;\n\t}\n\n\tthrow new TypeError(`Could not find ${defaultLocale}`);\n});\n\n/**\n * Gets the value and the localizations from a language key.\n * @param key The key to get the localizations from.\n * @returns The retrieved data.\n * @remarks This should be called **strictly** after loading the locales.\n */\nexport function getLocalizedData<const TOpt extends TOptions = TOptions, Ns extends Namespace = DefaultNamespace, KPrefix = undefined>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>\n): LocalizedData {\n\tconst locales = getLocales();\n\tconst defaultT = getDefaultT();\n\n\treturn {\n\t\tvalue: defaultT(key),\n\t\tlocalizations: Object.fromEntries(Array.from(locales, ([locale, t]) => [locale, t(key)]))\n\t};\n}\n\n/**\n * Applies the localized names on the builder, calling `setName` and `setNameLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyNameLocalizedBuilder<\n\tT extends BuilderWithName,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setName(result.value).setNameLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized descriptions on the builder, calling `setDescription` and `setDescriptionLocalizations`.\n * @param builder The builder to apply the localizations to.\n * @param key The key to get the localizations from.\n * @returns The updated builder.\n */\nexport function applyDescriptionLocalizedBuilder<\n\tT extends BuilderWithDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, key: ParseKeys<Ns, TOpt, KPrefix>) {\n\tconst result = getLocalizedData(key);\n\treturn builder.setDescription(result.value).setDescriptionLocalizations(result.localizations);\n}\n\n/**\n * Applies the localized names and descriptions on the builder, calling {@link applyNameLocalizedBuilder} and\n * {@link applyDescriptionLocalizedBuilder}.\n *\n * @param builder The builder to apply the localizations to.\n *\n * @param params The root key or the key for the name and description keys.\n * This needs to be either 1 or 2 parameters.\n * See examples below for more information.\n *\n * @returns The updated builder. You can chain subsequent builder methods on this.\n *\n * @remarks If only 2 parameters were passed, then this function will automatically append `Name` and `Description`\n * to the root-key (wherein `root-key` is second parameter in the function, after `builder`)\n * passed through the second parameter.\n *\n * For example given `applyLocalizedBuilder(builder, 'userinfo')` the localized options will use the i18next keys\n * `userinfoName` and `userinfoDescription`.\n *\n * In the following example we provide all parameters and add a User Option\n * `applyLocalizedBuilder` needs either\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:userinfo', 'commands/descriptions:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'commands/options:userinfo-name', 'commands/options:userinfo-description').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n *\n * In the following example we provide single root keys which means `Name` and `Description` get appended as mentioned above.\n * @example\n * ```typescript\n * class UserInfoCommand extends Command {\n * public registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand(\n * (builder) =>\n * applyLocalizedBuilder(builder, 'commands:userinfo')\n * .addUserOption(\n * (input) => applyLocalizedBuilder(input, 'options:userinfo').setRequired(true)\n * )\n * );\n * }\n * }\n * ```\n */\nexport function applyLocalizedBuilder<\n\tT extends BuilderWithNameAndDescription,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(builder: T, ...params: [root: string] | [name: ParseKeys<Ns, TOpt, KPrefix>, description: ParseKeys<Ns, TOpt, KPrefix>]): T {\n\ttype LocalKeysType = ParseKeys<Ns, TOpt, KPrefix>;\n\n\tconst [localeName, localeDescription] =\n\t\tparams.length === 1 ? [`${params[0]}Name` as LocalKeysType, `${params[0]}Description` as LocalKeysType] : params;\n\n\tapplyNameLocalizedBuilder(builder, localeName);\n\tapplyDescriptionLocalizedBuilder(builder, localeDescription);\n\n\treturn builder;\n}\n\n/**\n * Constructs an object that can be passed into `setChoices` for String or Number option with localized names.\n *\n * @param key The i18next key for the name of the select option name.\n * @param options The additional Select Menu options. This should _at least_ include the `value` key.\n * @returns An object with anything provided through {@link createLocalizedChoice.options} with `name` and `name_localizations` added.\n *\n * @example\n * ```typescript\n * export class TypeCommand extends Command {\n * public override registerApplicationCommands(registry: ChatInputCommand.Registry) {\n * registry.registerChatInputCommand((builder) =>\n * applyLocalizedBuilder(builder, 'commands/names:type').addStringOption((option) =>\n * applyLocalizedBuilder(option, 'commands/options:type')\n * .setRequired(true)\n * .setChoices(\n * createLocalizedChoice('selects/pokemon:type-grass', { value: 'grass' }),\n * createLocalizedChoice('selects/pokemon:type-water', { value: 'water' }),\n * createLocalizedChoice('selects/pokemon:type-fire', { value: 'fire' }),\n * createLocalizedChoice('selects/pokemon:type-electric', { value: 'electric' })\n * )\n * )\n * );\n * }\n * }\n * ```\n */\nexport function createLocalizedChoice<\n\tValueType = string | number,\n\tconst TOpt extends TOptions = TOptions,\n\tNs extends Namespace = DefaultNamespace,\n\tKPrefix = undefined\n>(\n\tkey: ParseKeys<Ns, TOpt, KPrefix>,\n\toptions: Omit<APIApplicationCommandOptionChoice<ValueType>, 'name' | 'name_localizations'>\n): APIApplicationCommandOptionChoice<ValueType> {\n\tconst result = getLocalizedData(key);\n\n\treturn {\n\t\t...options,\n\t\tname: result.value,\n\t\tname_localizations: result.localizations\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;;AAOO,IAAM,cAAA,GAAN,MAAM,cAAA,SAAsB,MAAO,CAAA;AAAA,EACzC,QAAe,yBAAyB,CAAA,CAAwB,OAA8B,EAAA;AAC7F,IAAA,SAAA,CAAU,IAAO,GAAA,IAAI,2BAA4B,CAAA,OAAA,CAAQ,IAAI,CAAA;AAAA;AAC9D,EAEA,cAAqB,QAAQ,CAAuC,GAAA;AACnE,IAAM,MAAA,SAAA,CAAU,KAAK,IAAK,EAAA;AAAA;AAC3B,EAEA,QAAe,SAAS,CAA8B,GAAA;AACrD,IAAA,IAAI,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA,GAAA,EAAK,OAAS,EAAA;AACpC,MAAU,SAAA,CAAA,MAAA,CAAO,KAAK,gEAAgE,CAAA;AAEtF,MAAM,KAAA,CAAA,SAAA,CAAU,IAAK,CAAA,kBAAA,EAAoB,IAAK,CAAA,OAAA,CAAQ,KAAK,GAAI,CAAA,OAAA,IAAW,EAAE,CAC1E,CAAA,EAAA,CAAG,UAAU,MAAM,SAAA,CAAU,IAAK,CAAA,eAAA,EAAiB,CAAA,CACnD,EAAG,CAAA,QAAA,EAAU,MAAM,SAAA,CAAU,IAAK,CAAA,eAAA,EAAiB,CAAA;AAAA;AACtD;AAEF,CAAA;AAlB0C,MAAA,CAAA,cAAA,EAAA,eAAA,CAAA;AAAnC,IAAM,aAAN,GAAA;AAoBP,cAAA,CAAe,OAAQ,CAAA,8BAAA,CAA+B,aAAc,CAAA,yBAAyB,GAAG,mCAAmC,CAAA;AACnI,cAAA,CAAe,OAAQ,CAAA,oBAAA,CAAqB,aAAc,CAAA,QAAQ,GAAG,kBAAkB,CAAA;AACvF,cAAA,CAAe,OAAQ,CAAA,qBAAA,CAAsB,aAAc,CAAA,SAAS,GAAG,mBAAmB,CAAA","file":"register.mjs","sourcesContent":["import './index';\n\nimport { Plugin, SapphireClient, container, postLogin, preGenericsInitialization, preLogin } from '@sapphire/framework';\nimport { watch } from 'chokidar';\nimport type { ClientOptions } from 'discord.js';\nimport { InternationalizationHandler } from './index';\n\nexport class I18nextPlugin extends Plugin {\n\tpublic static [preGenericsInitialization](this: SapphireClient, options: ClientOptions): void {\n\t\tcontainer.i18n = new InternationalizationHandler(options.i18n);\n\t}\n\n\tpublic static async [preLogin](this: SapphireClient): Promise<void> {\n\t\tawait container.i18n.init();\n\t}\n\n\tpublic static [postLogin](this: SapphireClient): void {\n\t\tif (this.options.i18n?.hmr?.enabled) {\n\t\t\tcontainer.logger.info('[i18next-Plugin]: HMR enabled. Watching for languages changes.');\n\n\t\t\twatch(container.i18n.languagesDirectory, this.options.i18n.hmr.options ?? {})\n\t\t\t\t.on('change', () => container.i18n.reloadResources())\n\t\t\t\t.on('unlink', () => container.i18n.reloadResources());\n\t\t}\n\t}\n}\n\nSapphireClient.plugins.registerPostInitializationHook(I18nextPlugin[preGenericsInitialization], 'I18next-PreGenericsInitialization');\nSapphireClient.plugins.registerPreLoginHook(I18nextPlugin[preLogin], 'I18next-PreLogin');\nSapphireClient.plugins.registerPostLoginHook(I18nextPlugin[postLogin], 'I18next-PostLogin');\n"]}
1
+ {"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;;AAOO,IAAM,cAAA,GAAN,MAAM,cAAA,SAAsB,MAAA,CAAO;AAAA,EACzC,QAAe,yBAAyB,CAAA,CAAwB,OAAA,EAA8B;AAC7F,IAAA,SAAA,CAAU,IAAA,GAAO,IAAI,2BAAA,CAA4B,OAAA,CAAQ,IAAI,CAAA;AAAA,EAC9D;AAAA,EAEA,cAAqB,QAAQ,CAAA,GAAuC;AACnE,IAAA,MAAM,SAAA,CAAU,KAAK,IAAA,EAAK;AAAA,EAC3B;AAAA,EAEA,QAAe,SAAS,CAAA,GAA8B;AACrD,IAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,GAAA,EAAK,OAAA,EAAS;AACpC,MAAA,SAAA,CAAU,MAAA,CAAO,KAAK,gEAAgE,CAAA;AAEtF,MAAA,KAAA,CAAM,SAAA,CAAU,IAAA,CAAK,kBAAA,EAAoB,IAAA,CAAK,OAAA,CAAQ,KAAK,GAAA,CAAI,OAAA,IAAW,EAAE,CAAA,CAC1E,EAAA,CAAG,UAAU,MAAM,SAAA,CAAU,IAAA,CAAK,eAAA,EAAiB,CAAA,CACnD,EAAA,CAAG,QAAA,EAAU,MAAM,SAAA,CAAU,IAAA,CAAK,eAAA,EAAiB,CAAA;AAAA,IACtD;AAAA,EACD;AACD,CAAA;AAlB0C,MAAA,CAAA,cAAA,EAAA,eAAA,CAAA;AAAnC,IAAM,aAAA,GAAN;AAoBP,cAAA,CAAe,OAAA,CAAQ,8BAAA,CAA+B,aAAA,CAAc,yBAAyB,GAAG,mCAAmC,CAAA;AACnI,cAAA,CAAe,OAAA,CAAQ,oBAAA,CAAqB,aAAA,CAAc,QAAQ,GAAG,kBAAkB,CAAA;AACvF,cAAA,CAAe,OAAA,CAAQ,qBAAA,CAAsB,aAAA,CAAc,SAAS,GAAG,mBAAmB,CAAA","file":"register.mjs","sourcesContent":["import './index';\n\nimport { Plugin, SapphireClient, container, postLogin, preGenericsInitialization, preLogin } from '@sapphire/framework';\nimport { watch } from 'chokidar';\nimport type { ClientOptions } from 'discord.js';\nimport { InternationalizationHandler } from './index';\n\nexport class I18nextPlugin extends Plugin {\n\tpublic static [preGenericsInitialization](this: SapphireClient, options: ClientOptions): void {\n\t\tcontainer.i18n = new InternationalizationHandler(options.i18n);\n\t}\n\n\tpublic static async [preLogin](this: SapphireClient): Promise<void> {\n\t\tawait container.i18n.init();\n\t}\n\n\tpublic static [postLogin](this: SapphireClient): void {\n\t\tif (this.options.i18n?.hmr?.enabled) {\n\t\t\tcontainer.logger.info('[i18next-Plugin]: HMR enabled. Watching for languages changes.');\n\n\t\t\twatch(container.i18n.languagesDirectory, this.options.i18n.hmr.options ?? {})\n\t\t\t\t.on('change', () => container.i18n.reloadResources())\n\t\t\t\t.on('unlink', () => container.i18n.reloadResources());\n\t\t}\n\t}\n}\n\nSapphireClient.plugins.registerPostInitializationHook(I18nextPlugin[preGenericsInitialization], 'I18next-PreGenericsInitialization');\nSapphireClient.plugins.registerPreLoginHook(I18nextPlugin[preLogin], 'I18next-PreLogin');\nSapphireClient.plugins.registerPostLoginHook(I18nextPlugin[postLogin], 'I18next-PostLogin');\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapphire/plugin-i18next",
3
- "version": "8.0.1-next.e18dc27",
3
+ "version": "8.0.1-next.f67c68a",
4
4
  "description": "Plugin for @sapphire/framework to support i18next.",
5
5
  "author": "@sapphire",
6
6
  "license": "MIT",
@@ -53,7 +53,7 @@
53
53
  "@sapphire/utilities": "^3.18.2",
54
54
  "@skyra/i18next-backend": "^2.0.6",
55
55
  "chokidar": "^4.0.3",
56
- "i18next": "^25.2.1"
56
+ "i18next": "^25.6.0"
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",
@@ -88,9 +88,9 @@
88
88
  "devDependencies": {
89
89
  "@favware/cliff-jumper": "^6.0.0",
90
90
  "@favware/rollup-type-bundler": "^4.0.0",
91
- "concurrently": "^9.1.2",
91
+ "concurrently": "^9.2.1",
92
92
  "tsup": "^8.5.0",
93
- "tsx": "^4.19.4",
93
+ "tsx": "^4.20.6",
94
94
  "typedoc": "^0.26.11",
95
95
  "typedoc-json-parser": "^10.2.0",
96
96
  "typescript": "~5.4.5"