From 2e39517317e4bfa454dbb928e08aaadab218f3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aura=20Rom=C3=A1n?= Date: Mon, 24 Jul 2023 20:50:52 +0200 Subject: [PATCH] refactor: update `i18next` to `v23` typings: `getT` now returns `TFunction` with the correct default namespace typings: `LocalePrefixKey`'s type now doesn't force a `commands/` prefix typings: `LocalePrefixKey` now uses i18next's `nsSeparator` type instead of a hardcoded `:` typings: All functions using `TypedT` now requires `LocalePrefixKey` BREAKING CHANGE: refactor: Removed `resolveKey`, use `getSupportedLanguageT(interaction)(...args)` instead BREAKING CHANGE: refactor: Removed `resolveUserKey`, use `getSupportedUserLanguageT(interaction)(...args)` instead BREAKING CHANGE: typings: Removed `T` type utility function BREAKING CHANGE: typings: Removed `FT` type utility function BREAKING CHANGE: typings: Removed `TypedT` type utility BREAKING CHANGE: typings: Removed `TypedFT` type utility BREAKING CHANGE: typings: Removed `Value` type utility BREAKING CHANGE: typings: Removed `Values` type utility BREAKING CHANGE: typings: Removed `Difference` type utility BREAKING CHANGE: typings: `i18next.TFunction` is not longer augmented, `lng` and `ns` is not longer assumed to exist --- packages/http-framework-i18n/README.md | 2 + packages/http-framework-i18n/src/index.ts | 17 ------ .../http-framework-i18n/src/lib/functions.ts | 10 ---- .../http-framework-i18n/src/lib/registry.ts | 2 +- packages/http-framework-i18n/src/lib/types.ts | 21 ------- packages/http-framework-i18n/src/lib/utils.ts | 56 +++---------------- 6 files changed, 12 insertions(+), 96 deletions(-) delete mode 100644 packages/http-framework-i18n/src/lib/functions.ts delete mode 100644 packages/http-framework-i18n/src/lib/types.ts diff --git a/packages/http-framework-i18n/README.md b/packages/http-framework-i18n/README.md index 7bd537a0..bc74045d 100644 --- a/packages/http-framework-i18n/README.md +++ b/packages/http-framework-i18n/README.md @@ -34,6 +34,8 @@ addFormatters( await init(); ``` +> **Note**: If you want to customize the options, please check [i18next's TypeScript guide](https://www.i18next.com/overview/typescript) to improve the experience. + ### Definition ```typescript diff --git a/packages/http-framework-i18n/src/index.ts b/packages/http-framework-i18n/src/index.ts index 6eb1321e..38dab66d 100644 --- a/packages/http-framework-i18n/src/index.ts +++ b/packages/http-framework-i18n/src/index.ts @@ -1,20 +1,3 @@ export { default as i18next, type InitOptions, type TFunction, type TOptions, type TOptionsBase } from 'i18next'; -export * from './lib/functions.js'; export * from './lib/registry.js'; -export type * from './lib/types.js'; export * from './lib/utils.js'; - -import type { NonNullObject } from '@sapphire/utilities'; -import type { TypedFT, TypedT } from './lib/types.js'; - -declare module 'i18next' { - export interface TFunction { - lng: string; - ns?: string; - - (key: TypedT, options?: TOptionsBase | string): TReturn; - (key: TypedT, defaultValue: TReturn, options?: TOptionsBase | string): TReturn; - (key: TypedFT, options?: TOptions): TReturn; - (key: TypedFT, defaultValue: TReturn, options?: TOptions): TReturn; - } -} diff --git a/packages/http-framework-i18n/src/lib/functions.ts b/packages/http-framework-i18n/src/lib/functions.ts deleted file mode 100644 index aaf77e75..00000000 --- a/packages/http-framework-i18n/src/lib/functions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { NonNullObject } from '@sapphire/utilities'; -import type { TypedFT, TypedT } from './types.js'; - -export function T(k: string): TypedT { - return k as TypedT; -} - -export function FT(k: string): TypedFT { - return k as TypedFT; -} diff --git a/packages/http-framework-i18n/src/lib/registry.ts b/packages/http-framework-i18n/src/lib/registry.ts index af83b76a..3d1428ae 100644 --- a/packages/http-framework-i18n/src/lib/registry.ts +++ b/packages/http-framework-i18n/src/lib/registry.ts @@ -83,7 +83,7 @@ async function loadLocale(directory: string, ns: string) { } const fixedCache = new Collection(); -export function getT(locale: LocaleString): TFunction<'translation', undefined, 'translation'> { +export function getT(locale: LocaleString): TFunction { if (!loadedLocales.has(locale)) throw new ReferenceError(`Invalid language (${locale})`); return fixedCache.ensure(locale, () => getFixedT(locale)); } diff --git a/packages/http-framework-i18n/src/lib/types.ts b/packages/http-framework-i18n/src/lib/types.ts deleted file mode 100644 index a02e7273..00000000 --- a/packages/http-framework-i18n/src/lib/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { NonNullObject } from '@sapphire/utilities'; - -export type TypedT = string & { __type__: TCustom }; - -export type TypedFT = string & { __args__: TArgs; __return__: TReturn }; - -export interface Value { - value: T; -} - -export interface Values { - values: readonly T[]; - count: number; -} - -export interface Difference { - previous: T; - next: T; -} - -export type LocalePrefixKey = `commands/${string}:${string}`; diff --git a/packages/http-framework-i18n/src/lib/utils.ts b/packages/http-framework-i18n/src/lib/utils.ts index dde30df0..c347e9fe 100644 --- a/packages/http-framework-i18n/src/lib/utils.ts +++ b/packages/http-framework-i18n/src/lib/utils.ts @@ -2,11 +2,12 @@ import { Collection } from '@discordjs/collection'; import type { NonNullObject } from '@sapphire/utilities'; import { lazy } from '@sapphire/utilities'; import type { APIInteraction, APIPingInteraction, LocaleString, LocalizationMap } from 'discord-api-types/v10'; -import type { TFunction, TOptions, TOptionsBase } from 'i18next'; +import type { TFunction, TypeOptions } from 'i18next'; import { getT, loadedLocales } from './registry.js'; -import type { LocalePrefixKey, TypedFT, TypedT } from './types.js'; export type Interaction = Pick, 'locale' | 'guild_locale' | 'guild_id'>; +export type LocaleSeparator = TypeOptions['nsSeparator']; +export type LocalePrefixKey = `${string}${LocaleSeparator}${string}`; export function getSupportedUserLanguageName(interaction: Interaction): LocaleString { if (loadedLocales.has(interaction.locale)) return interaction.locale; @@ -31,45 +32,6 @@ export function getSupportedLanguageT(interaction: Interaction): TFunction { return getT(getSupportedLanguageName(interaction)); } -export function resolveUserKey(interaction: Interaction, key: TypedT, options?: TOptionsBase | string): TReturn; -export function resolveUserKey( - interaction: Interaction, - key: TypedT, - defaultValue: TReturn, - options?: TOptionsBase | string -): TReturn; -export function resolveUserKey( - interaction: Interaction, - key: TypedFT, - options?: TOptions -): TReturn; -export function resolveUserKey( - interaction: Interaction, - key: TypedFT, - defaultValue: TReturn, - options?: TOptions -): TReturn; -export function resolveUserKey(interaction: Interaction, ...args: [any, any, any?]) { - return getSupportedUserLanguageT(interaction)(...args); -} - -export function resolveKey(interaction: Interaction, key: TypedT, options?: TOptionsBase | string): TReturn; -export function resolveKey(interaction: Interaction, key: TypedT, defaultValue: TReturn, options?: TOptionsBase | string): TReturn; -export function resolveKey( - interaction: Interaction, - key: TypedFT, - options?: TOptions -): TReturn; -export function resolveKey( - interaction: Interaction, - key: TypedFT, - defaultValue: TReturn, - options?: TOptions -): TReturn; -export function resolveKey(interaction: Interaction, ...args: [any, any, any?]) { - return getSupportedLanguageT(interaction)(...args); -} - const getLocales = lazy(() => new Collection([...loadedLocales].map((locale) => [locale, getT(locale)]))); const getDefaultT = lazy(() => { const defaultT = getLocales().get('en-US'); @@ -83,7 +45,7 @@ const getDefaultT = lazy(() => { * @returns The retrieved data. * @remarks This should be called **strictly** after loading the locales. */ -export function getLocalizedData(key: TypedT): LocalizedData { +export function getLocalizedData(key: LocalePrefixKey): LocalizedData { const locales = getLocales(); const defaultT = getDefaultT(); @@ -99,7 +61,7 @@ export function getLocalizedData(key: TypedT): LocalizedData { * @param key The key to get the localizations from. * @returns The updated builder. */ -export function applyNameLocalizedBuilder(builder: T, key: TypedT) { +export function applyNameLocalizedBuilder(builder: T, key: LocalePrefixKey) { const result = getLocalizedData(key); return builder.setName(result.value).setNameLocalizations(result.localizations); } @@ -110,7 +72,7 @@ export function applyNameLocalizedBuilder(builder: T, * @param key The key to get the localizations from. * @returns The updated builder. */ -export function applyDescriptionLocalizedBuilder(builder: T, key: TypedT) { +export function applyDescriptionLocalizedBuilder(builder: T, key: LocalePrefixKey) { const result = getLocalizedData(key); return builder.setDescription(result.value).setDescriptionLocalizations(result.localizations); } @@ -126,16 +88,16 @@ export function applyDescriptionLocalizedBuilder( builder: T, - ...params: [root: LocalePrefixKey] | [name: TypedT, description: TypedT] + ...params: [root: LocalePrefixKey] | [name: LocalePrefixKey, description: LocalePrefixKey] ): T { - const [localeName, localeDescription] = params.length === 1 ? [`${params[0]}Name` as TypedT, `${params[0]}Description` as TypedT] : params; + const [localeName, localeDescription] = params.length === 1 ? [`${params[0]}Name` as const, `${params[0]}Description` as const] : params; applyNameLocalizedBuilder(builder, localeName); applyDescriptionLocalizedBuilder(builder, localeDescription); return builder; } -export function createSelectMenuChoiceName(key: TypedT, value?: V): createSelectMenuChoiceName.Result { +export function createSelectMenuChoiceName(key: LocalePrefixKey, value?: V): createSelectMenuChoiceName.Result { const result = getLocalizedData(key); return { ...value,