@sapphire/plugin-i18next 7.1.3-next.fc6b7cf.0 → 7.1.3-next.fc8e636
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.
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/lib/InternationalizationHandler.cjs +8 -18
- package/dist/cjs/lib/InternationalizationHandler.cjs.map +1 -1
- package/dist/cjs/register.cjs +1 -2
- package/dist/cjs/register.cjs.map +1 -1
- package/dist/esm/{chunk-6QB3UK4Q.mjs → chunk-2JTKI4GS.mjs} +2 -5
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/lib/InternationalizationHandler.mjs +8 -15
- package/dist/esm/lib/InternationalizationHandler.mjs.map +1 -1
- package/dist/esm/lib/functions.mjs +1 -1
- package/dist/esm/register.mjs +2 -3
- package/dist/esm/register.mjs.map +1 -1
- package/package.json +7 -7
- /package/dist/esm/{chunk-6QB3UK4Q.mjs.map → chunk-2JTKI4GS.mjs.map} +0 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -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 = "7.1.3-next.
|
|
13
|
+
var version = "7.1.3-next.fc8e636";
|
|
14
14
|
|
|
15
15
|
Object.defineProperty(exports, "i18next", {
|
|
16
16
|
enumerable: true,
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":["default"],"mappings":";AAGA,SAAoB,WAAXA,gBAAyD;AAClE,cAAc;AACd,cAAc;AACd,cAAc;AAmBP,IAAM,UAAkB","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 = '7.1.3-next.
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"names":["default"],"mappings":";AAGA,SAAoB,WAAXA,gBAAyD;AAClE,cAAc;AACd,cAAc;AACd,cAAc;AAmBP,IAAM,UAAkB","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 = '7.1.3-next.fc8e636';\n"]}
|
|
@@ -16,10 +16,7 @@ var i18next__default = /*#__PURE__*/_interopDefault(i18next);
|
|
|
16
16
|
var __defProp = Object.defineProperty;
|
|
17
17
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
18
18
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
19
|
-
var __publicField = (obj, key, value) =>
|
|
20
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
21
|
-
return value;
|
|
22
|
-
};
|
|
19
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
23
20
|
var _InternationalizationHandler = class _InternationalizationHandler {
|
|
24
21
|
/**
|
|
25
22
|
* @param options The options that `i18next`, `@skyra/i18next-backend`, and {@link InternationalizationHandler} should use.
|
|
@@ -146,10 +143,8 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
146
143
|
const formatter = i18next__default.default.services.formatter;
|
|
147
144
|
const formatters = this.options.formatters ?? [];
|
|
148
145
|
for (const { name, format, cached } of formatters) {
|
|
149
|
-
if (cached)
|
|
150
|
-
|
|
151
|
-
else
|
|
152
|
-
formatter.add(name, format);
|
|
146
|
+
if (cached) formatter.addCached(name, format);
|
|
147
|
+
else formatter.add(name, format);
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
/**
|
|
@@ -158,11 +153,9 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
158
153
|
* @since 1.0.0
|
|
159
154
|
*/
|
|
160
155
|
getT(locale) {
|
|
161
|
-
if (!this.languagesLoaded)
|
|
162
|
-
throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
156
|
+
if (!this.languagesLoaded) throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
163
157
|
const t = this.languages.get(locale);
|
|
164
|
-
if (t)
|
|
165
|
-
return t;
|
|
158
|
+
if (t) return t;
|
|
166
159
|
throw new ReferenceError("Invalid language provided");
|
|
167
160
|
}
|
|
168
161
|
/**
|
|
@@ -178,11 +171,9 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
178
171
|
* @returns The localized content.
|
|
179
172
|
*/
|
|
180
173
|
format(locale, ...[key, defaultValueOrOptions, optionsOrUndefined]) {
|
|
181
|
-
if (!this.languagesLoaded)
|
|
182
|
-
throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
174
|
+
if (!this.languagesLoaded) throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
183
175
|
const language = this.languages.get(locale);
|
|
184
|
-
if (!language)
|
|
185
|
-
throw new ReferenceError("Invalid language provided");
|
|
176
|
+
if (!language) throw new ReferenceError("Invalid language provided");
|
|
186
177
|
const defaultValue = typeof defaultValueOrOptions === "string" ? defaultValueOrOptions : this.options.defaultMissingKey ? language(this.options.defaultMissingKey, { replace: { key } }) : "";
|
|
187
178
|
return language(key, { defaultValue, ...optionsOrUndefined ?? {} });
|
|
188
179
|
}
|
|
@@ -195,8 +186,7 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
195
186
|
const namespaces = /* @__PURE__ */ new Set();
|
|
196
187
|
const dir = await promises.opendir(directory);
|
|
197
188
|
for await (const entry of dir) {
|
|
198
|
-
if (!entry.isDirectory())
|
|
199
|
-
continue;
|
|
189
|
+
if (!entry.isDirectory()) continue;
|
|
200
190
|
languages.add(entry.name);
|
|
201
191
|
for await (const namespace of this.walkLocaleDirectory(path.join(dir.path, entry.name), "")) {
|
|
202
192
|
namespaces.add(namespace);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":[],"mappings":"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","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 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, $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\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>(\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: string | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<Ret, 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>(key, { defaultValue, ...((optionsOrUndefined ?? {}) as TOpt) });\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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","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 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, $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\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>(\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: string | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<Ret, 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>(key, { defaultValue, ...((optionsOrUndefined ?? {}) as TOpt) });\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"]}
|
package/dist/cjs/register.cjs
CHANGED
|
@@ -17,8 +17,7 @@ var _I18nextPlugin = class _I18nextPlugin extends framework.Plugin {
|
|
|
17
17
|
if (this.options.i18n?.hmr?.enabled) {
|
|
18
18
|
framework.container.logger.info("[i18next-Plugin]: HMR enabled. Watching for languages changes.");
|
|
19
19
|
const hmr = chokidar.watch(framework.container.i18n.languagesDirectory, this.options.i18n.hmr.options);
|
|
20
|
-
for (const event of ["change", "unlink"])
|
|
21
|
-
hmr.on(event, () => framework.container.i18n.reloadResources());
|
|
20
|
+
for (const event of ["change", "unlink"]) hmr.on(event, () => framework.container.i18n.reloadResources());
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;AAAA,OAAO;AAEP,SAAS,QAAQ,gBAAgB,WAAW,WAAW,2BAA2B,gBAAgB;AAClG,SAAS,aAAa;AAEtB,SAAS,mCAAmC;AAErC,IAAM,iBAAN,MAAM,uBAAsB,OAAO;AAAA,EACzC,QAAe,yBAAyB,EAAwB,SAA8B;AAC7F,cAAU,OAAO,IAAI,4BAA4B,QAAQ,IAAI;AAAA,EAC9D;AAAA,EAEA,cAAqB,QAAQ,IAAuC;AACnE,UAAM,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,QAAe,SAAS,IAA8B;AACrD,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS;AACpC,gBAAU,OAAO,KAAK,gEAAgE;AACtF,YAAM,MAAM,MAAM,UAAU,KAAK,oBAAoB,KAAK,QAAQ,KAAK,IAAI,OAAO;AAElF,iBAAW,SAAS,CAAC,UAAU,QAAQ
|
|
1
|
+
{"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;AAAA,OAAO;AAEP,SAAS,QAAQ,gBAAgB,WAAW,WAAW,2BAA2B,gBAAgB;AAClG,SAAS,aAAa;AAEtB,SAAS,mCAAmC;AAErC,IAAM,iBAAN,MAAM,uBAAsB,OAAO;AAAA,EACzC,QAAe,yBAAyB,EAAwB,SAA8B;AAC7F,cAAU,OAAO,IAAI,4BAA4B,QAAQ,IAAI;AAAA,EAC9D;AAAA,EAEA,cAAqB,QAAQ,IAAuC;AACnE,UAAM,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,QAAe,SAAS,IAA8B;AACrD,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS;AACpC,gBAAU,OAAO,KAAK,gEAAgE;AACtF,YAAM,MAAM,MAAM,UAAU,KAAK,oBAAoB,KAAK,QAAQ,KAAK,IAAI,OAAO;AAElF,iBAAW,SAAS,CAAC,UAAU,QAAQ,EAAG,KAAI,GAAG,OAAO,MAAM,UAAU,KAAK,gBAAgB,CAAC;AAAA,IAC/F;AAAA,EACD;AACD;AAjB0C;AAAnC,IAAM,gBAAN;AAmBP,eAAe,QAAQ,+BAA+B,cAAc,yBAAyB,GAAG,mCAAmC;AACnI,eAAe,QAAQ,qBAAqB,cAAc,QAAQ,GAAG,kBAAkB;AACvF,eAAe,QAAQ,sBAAsB,cAAc,SAAS,GAAG,mBAAmB","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\t\t\tconst hmr = watch(container.i18n.languagesDirectory, this.options.i18n.hmr.options);\n\n\t\t\tfor (const event of ['change', 'unlink']) hmr.on(event, () => 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,11 +1,8 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
-
var __publicField = (obj, key, value) =>
|
|
5
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
-
return value;
|
|
7
|
-
};
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
5
|
|
|
9
6
|
export { __name, __publicField };
|
|
10
7
|
//# sourceMappingURL=out.js.map
|
|
11
|
-
//# sourceMappingURL=chunk-
|
|
8
|
+
//# sourceMappingURL=chunk-2JTKI4GS.mjs.map
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import './chunk-
|
|
1
|
+
import './chunk-2JTKI4GS.mjs';
|
|
2
2
|
export { default as i18next } from 'i18next';
|
|
3
3
|
export * from './lib/InternationalizationHandler.mjs';
|
|
4
4
|
export * from './lib/functions.mjs';
|
|
5
5
|
export * from './lib/types.mjs';
|
|
6
6
|
|
|
7
|
-
var version = "7.1.3-next.
|
|
7
|
+
var version = "7.1.3-next.fc8e636";
|
|
8
8
|
|
|
9
9
|
export { version };
|
|
10
10
|
//# sourceMappingURL=out.js.map
|
package/dist/esm/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":["default"],"mappings":";;;AAGA,SAAoB,WAAXA,gBAAyD;AAClE,cAAc;AACd,cAAc;AACd,cAAc;AAmBP,IAAM,UAAkB","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 = '7.1.3-next.
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"names":["default"],"mappings":";;;AAGA,SAAoB,WAAXA,gBAAyD;AAClE,cAAc;AACd,cAAc;AACd,cAAc;AAmBP,IAAM,UAAkB","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 = '7.1.3-next.fc8e636';\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __name, __publicField } from '../chunk-
|
|
1
|
+
import { __name, __publicField } from '../chunk-2JTKI4GS.mjs';
|
|
2
2
|
import { Result } from '@sapphire/framework';
|
|
3
3
|
import { container, getRootData } from '@sapphire/pieces';
|
|
4
4
|
import { isFunction } from '@sapphire/utilities';
|
|
@@ -134,10 +134,8 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
134
134
|
const formatter = i18next.services.formatter;
|
|
135
135
|
const formatters = this.options.formatters ?? [];
|
|
136
136
|
for (const { name, format, cached } of formatters) {
|
|
137
|
-
if (cached)
|
|
138
|
-
|
|
139
|
-
else
|
|
140
|
-
formatter.add(name, format);
|
|
137
|
+
if (cached) formatter.addCached(name, format);
|
|
138
|
+
else formatter.add(name, format);
|
|
141
139
|
}
|
|
142
140
|
}
|
|
143
141
|
/**
|
|
@@ -146,11 +144,9 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
146
144
|
* @since 1.0.0
|
|
147
145
|
*/
|
|
148
146
|
getT(locale) {
|
|
149
|
-
if (!this.languagesLoaded)
|
|
150
|
-
throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
147
|
+
if (!this.languagesLoaded) throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
151
148
|
const t = this.languages.get(locale);
|
|
152
|
-
if (t)
|
|
153
|
-
return t;
|
|
149
|
+
if (t) return t;
|
|
154
150
|
throw new ReferenceError("Invalid language provided");
|
|
155
151
|
}
|
|
156
152
|
/**
|
|
@@ -166,11 +162,9 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
166
162
|
* @returns The localized content.
|
|
167
163
|
*/
|
|
168
164
|
format(locale, ...[key, defaultValueOrOptions, optionsOrUndefined]) {
|
|
169
|
-
if (!this.languagesLoaded)
|
|
170
|
-
throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
165
|
+
if (!this.languagesLoaded) throw new Error("Cannot call this method until InternationalizationHandler#init has been called");
|
|
171
166
|
const language = this.languages.get(locale);
|
|
172
|
-
if (!language)
|
|
173
|
-
throw new ReferenceError("Invalid language provided");
|
|
167
|
+
if (!language) throw new ReferenceError("Invalid language provided");
|
|
174
168
|
const defaultValue = typeof defaultValueOrOptions === "string" ? defaultValueOrOptions : this.options.defaultMissingKey ? language(this.options.defaultMissingKey, { replace: { key } }) : "";
|
|
175
169
|
return language(key, { defaultValue, ...optionsOrUndefined ?? {} });
|
|
176
170
|
}
|
|
@@ -183,8 +177,7 @@ var _InternationalizationHandler = class _InternationalizationHandler {
|
|
|
183
177
|
const namespaces = /* @__PURE__ */ new Set();
|
|
184
178
|
const dir = await opendir(directory);
|
|
185
179
|
for await (const entry of dir) {
|
|
186
|
-
if (!entry.isDirectory())
|
|
187
|
-
continue;
|
|
180
|
+
if (!entry.isDirectory()) continue;
|
|
188
181
|
languages.add(entry.name);
|
|
189
182
|
for await (const namespace of this.walkLocaleDirectory(join(dir.path, entry.name), "")) {
|
|
190
183
|
namespaces.add(namespace);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/InternationalizationHandler.ts"],"names":[],"mappings":"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","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 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, $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\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>(\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: string | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<Ret, 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>(key, { defaultValue, ...((optionsOrUndefined ?? {}) as TOpt) });\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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","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 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, $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\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>(\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: string | undefined, options?: TOpt & $Dictionary]\n\t): TFunctionReturnOptionalDetails<Ret, 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>(key, { defaultValue, ...((optionsOrUndefined ?? {}) as TOpt) });\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,4 +1,4 @@
|
|
|
1
|
-
import { __name } from '../chunk-
|
|
1
|
+
import { __name } from '../chunk-2JTKI4GS.mjs';
|
|
2
2
|
import { container } from '@sapphire/pieces';
|
|
3
3
|
import { lazy } from '@sapphire/utilities';
|
|
4
4
|
import { Locale, BaseInteraction, Message, Guild, ChannelType } from 'discord.js';
|
package/dist/esm/register.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __name } from './chunk-
|
|
1
|
+
import { __name } from './chunk-2JTKI4GS.mjs';
|
|
2
2
|
import { InternationalizationHandler } from './index.mjs';
|
|
3
3
|
import { SapphireClient, preGenericsInitialization, preLogin, postLogin, Plugin, container } from '@sapphire/framework';
|
|
4
4
|
import { watch } from 'chokidar';
|
|
@@ -14,8 +14,7 @@ var _I18nextPlugin = class _I18nextPlugin extends Plugin {
|
|
|
14
14
|
if (this.options.i18n?.hmr?.enabled) {
|
|
15
15
|
container.logger.info("[i18next-Plugin]: HMR enabled. Watching for languages changes.");
|
|
16
16
|
const hmr = watch(container.i18n.languagesDirectory, this.options.i18n.hmr.options);
|
|
17
|
-
for (const event of ["change", "unlink"])
|
|
18
|
-
hmr.on(event, () => container.i18n.reloadResources());
|
|
17
|
+
for (const event of ["change", "unlink"]) hmr.on(event, () => container.i18n.reloadResources());
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;;AAAA,OAAO;AAEP,SAAS,QAAQ,gBAAgB,WAAW,WAAW,2BAA2B,gBAAgB;AAClG,SAAS,aAAa;AAEtB,SAAS,mCAAmC;AAErC,IAAM,iBAAN,MAAM,uBAAsB,OAAO;AAAA,EACzC,QAAe,yBAAyB,EAAwB,SAA8B;AAC7F,cAAU,OAAO,IAAI,4BAA4B,QAAQ,IAAI;AAAA,EAC9D;AAAA,EAEA,cAAqB,QAAQ,IAAuC;AACnE,UAAM,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,QAAe,SAAS,IAA8B;AACrD,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS;AACpC,gBAAU,OAAO,KAAK,gEAAgE;AACtF,YAAM,MAAM,MAAM,UAAU,KAAK,oBAAoB,KAAK,QAAQ,KAAK,IAAI,OAAO;AAElF,iBAAW,SAAS,CAAC,UAAU,QAAQ
|
|
1
|
+
{"version":3,"sources":["../../src/register.ts"],"names":[],"mappings":";;;;;AAAA,OAAO;AAEP,SAAS,QAAQ,gBAAgB,WAAW,WAAW,2BAA2B,gBAAgB;AAClG,SAAS,aAAa;AAEtB,SAAS,mCAAmC;AAErC,IAAM,iBAAN,MAAM,uBAAsB,OAAO;AAAA,EACzC,QAAe,yBAAyB,EAAwB,SAA8B;AAC7F,cAAU,OAAO,IAAI,4BAA4B,QAAQ,IAAI;AAAA,EAC9D;AAAA,EAEA,cAAqB,QAAQ,IAAuC;AACnE,UAAM,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,QAAe,SAAS,IAA8B;AACrD,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS;AACpC,gBAAU,OAAO,KAAK,gEAAgE;AACtF,YAAM,MAAM,MAAM,UAAU,KAAK,oBAAoB,KAAK,QAAQ,KAAK,IAAI,OAAO;AAElF,iBAAW,SAAS,CAAC,UAAU,QAAQ,EAAG,KAAI,GAAG,OAAO,MAAM,UAAU,KAAK,gBAAgB,CAAC;AAAA,IAC/F;AAAA,EACD;AACD;AAjB0C;AAAnC,IAAM,gBAAN;AAmBP,eAAe,QAAQ,+BAA+B,cAAc,yBAAyB,GAAG,mCAAmC;AACnI,eAAe,QAAQ,qBAAqB,cAAc,QAAQ,GAAG,kBAAkB;AACvF,eAAe,QAAQ,sBAAsB,cAAc,SAAS,GAAG,mBAAmB","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\t\t\tconst hmr = watch(container.i18n.languagesDirectory, this.options.i18n.hmr.options);\n\n\t\t\tfor (const event of ['change', 'unlink']) hmr.on(event, () => 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": "7.1.3-next.
|
|
3
|
+
"version": "7.1.3-next.fc8e636",
|
|
4
4
|
"description": "Plugin for @sapphire/framework to support i18next.",
|
|
5
5
|
"author": "@sapphire",
|
|
6
6
|
"license": "MIT",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"check-update": "cliff-jumper --dry-run"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@sapphire/utilities": "^3.
|
|
53
|
+
"@sapphire/utilities": "^3.16.2",
|
|
54
54
|
"@skyra/i18next-backend": "^2.0.5",
|
|
55
55
|
"chokidar": "^3.6.0",
|
|
56
|
-
"i18next": "^23.11.
|
|
56
|
+
"i18next": "^23.11.5"
|
|
57
57
|
},
|
|
58
58
|
"repository": {
|
|
59
59
|
"type": "git",
|
|
@@ -86,13 +86,13 @@
|
|
|
86
86
|
"access": "public"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@favware/cliff-jumper": "^
|
|
89
|
+
"@favware/cliff-jumper": "^4.0.2",
|
|
90
90
|
"@favware/rollup-type-bundler": "^3.3.0",
|
|
91
91
|
"concurrently": "^8.2.2",
|
|
92
|
-
"tsup": "^8.0
|
|
93
|
-
"tsx": "^4.
|
|
92
|
+
"tsup": "^8.1.0",
|
|
93
|
+
"tsx": "^4.16.2",
|
|
94
94
|
"typedoc": "^0.25.13",
|
|
95
95
|
"typedoc-json-parser": "^10.0.0",
|
|
96
|
-
"typescript": "
|
|
96
|
+
"typescript": "~5.4.5"
|
|
97
97
|
}
|
|
98
98
|
}
|
|
File without changes
|