import type { $OmitArrayKeys, $PreservedValue, $Dictionary, $SpecialObject } from './helpers.js'; import type { TypeOptions, Namespace, FlatNamespace, DefaultNamespace, TOptions, } from './options.js'; type $IsResourcesDefined = [keyof _Resources] extends [never] ? false : true; type $ValueIfResourcesDefined = $IsResourcesDefined extends true ? Value : Fallback; type $FirstNamespace = Ns extends readonly any[] ? Ns[0] : Ns; // Type Options type _ReturnObjects = TypeOptions['returnObjects']; type _ReturnNull = TypeOptions['returnNull']; type _KeySeparator = TypeOptions['keySeparator']; type _NsSeparator = TypeOptions['nsSeparator']; type _PluralSeparator = TypeOptions['pluralSeparator']; type _ContextSeparator = TypeOptions['contextSeparator']; type _FallbackNamespace = TypeOptions['fallbackNS']; type _Resources = TypeOptions['resources']; type _JSONFormat = TypeOptions['jsonFormat']; type _InterpolationPrefix = TypeOptions['interpolationPrefix']; type _InterpolationSuffix = TypeOptions['interpolationSuffix']; type Resources = $ValueIfResourcesDefined<_Resources, $Dictionary>; type PluralSuffix = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'; type WithOrWithoutPlural = _JSONFormat extends 'v4' ? Key extends `${infer KeyWithoutOrdinalPlural}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}` ? KeyWithoutOrdinalPlural | Key : Key extends `${infer KeyWithoutPlural}${_PluralSeparator}${PluralSuffix}` ? KeyWithoutPlural | Key : Key : Key; type JoinKeys = `${K1 & string}${_KeySeparator}${K2 & string}`; type AppendNamespace = `${Ns & string}${_NsSeparator}${Keys & string}`; /****************************************************** * Build all keys and key prefixes based on Resources * ******************************************************/ type KeysBuilderWithReturnObjects = Key extends keyof Res ? Res[Key] extends $Dictionary ? | JoinKeys>> | JoinKeys> : never : never; type KeysBuilderWithoutReturnObjects> = Key extends keyof Res ? Res[Key] extends $Dictionary ? JoinKeys> : Key : never; type KeysBuilder = $IsResourcesDefined extends true ? WithReturnObjects extends true ? keyof Res | KeysBuilderWithReturnObjects : KeysBuilderWithoutReturnObjects : string; type KeysWithReturnObjects = { [Ns in FlatNamespace]: WithOrWithoutPlural>; }; type KeysWithoutReturnObjects = { [Ns in FlatNamespace]: WithOrWithoutPlural>; }; type ResourceKeys = WithReturnObjects extends true ? KeysWithReturnObjects : KeysWithoutReturnObjects; /************************************************************************ * Parse t function keys based on the namespace, options and key prefix * ************************************************************************/ export type KeysByTOptions = TOpt['returnObjects'] extends true ? ResourceKeys : ResourceKeys; export type NsByTOptions = TOpt['ns'] extends Namespace ? TOpt['ns'] : Ns; type ParseKeysByKeyPrefix = KPrefix extends string ? Keys extends `${KPrefix}${_KeySeparator}${infer Key}` ? Key : never : Keys; type ParseKeysByNamespaces = Ns extends readonly (infer UnionNsps)[] ? UnionNsps extends keyof Keys ? AppendNamespace : never : never; type ParseKeysByFallbackNs = _FallbackNamespace extends false ? never : _FallbackNamespace extends (infer UnionFallbackNs extends string)[] ? Keys[UnionFallbackNs] : Keys[_FallbackNamespace & string]; type FilterKeysByContext = TOpt['context'] extends string ? Keys extends `${infer Prefix}${_ContextSeparator}${TOpt['context']}${infer Suffix}` ? `${Prefix}${Suffix}` : never : Keys; export type ParseKeys< Ns extends Namespace = DefaultNamespace, TOpt extends TOptions = {}, KPrefix = undefined, Keys extends $Dictionary = KeysByTOptions, ActualNS extends Namespace = NsByTOptions, > = $IsResourcesDefined extends true ? FilterKeysByContext< | ParseKeysByKeyPrefix], KPrefix> | ParseKeysByNamespaces | ParseKeysByFallbackNs, TOpt > : string; /********************************************************* * Parse t function return type and interpolation values * *********************************************************/ type ParseInterpolationValues = Ret extends `${string}${_InterpolationPrefix}${infer Value}${_InterpolationSuffix}${infer Rest}` ? | (Value extends `${infer ActualValue},${string}` ? ActualValue : Value) | ParseInterpolationValues : never; type InterpolationMap = Record< $PreservedValue, string>, unknown >; type ParseTReturnPlural< Res, Key, KeyWithPlural = `${Key & string}${_PluralSeparator}${PluralSuffix}`, KeyWithOrdinalPlural = `${Key & string}${_PluralSeparator}ordinal${_PluralSeparator}${PluralSuffix}`, > = Res[(KeyWithOrdinalPlural | KeyWithPlural | Key) & keyof Res]; type ParseTReturn = Key extends `${infer K1}${_KeySeparator}${infer RestKey}` ? ParseTReturn : ParseTReturnPlural; type TReturnOptionalNull = _ReturnNull extends true ? null : never; type TReturnOptionalObjects = _ReturnObjects extends true ? $SpecialObject | string : TOpt['returnObjects'] extends true ? $SpecialObject : string; type DefaultTReturn = TReturnOptionalObjects | TReturnOptionalNull; export type KeyWithContext = TOpt['context'] extends string ? `${Key & string}${_ContextSeparator}${TOpt['context']}` : Key; export type TFunctionReturn< Ns extends Namespace, Key, TOpt extends TOptions, ActualNS extends Namespace = NsByTOptions, ActualKey = KeyWithContext, > = $IsResourcesDefined extends true ? ActualKey extends `${infer Nsp}${_NsSeparator}${infer RestKey}` ? ParseTReturn : ParseTReturn]> : DefaultTReturn; export type TFunctionDetailedResult = { /** * The plain used key */ usedKey: string; /** * The translation result. */ res: T; /** * The key with context / plural */ exactUsedKey: string; /** * The used language for this translation. */ usedLng: string; /** * The used namespace for this translation. */ usedNS: string; /** * The parameters used for interpolation. */ usedParams: InterpolationMap & { count?: TOpt['count'] }; }; type TFunctionReturnOptionalDetails = TOpt['returnDetails'] extends true ? TFunctionDetailedResult : Ret; type AppendKeyPrefix = KPrefix extends string ? `${KPrefix}${_KeySeparator}${Key & string}` : Key; /************************** * T function declaration * **************************/ export interface TFunction { $TFunctionBrand: $IsResourcesDefined extends true ? `${$FirstNamespace}` : never; < Key extends ParseKeys | TemplateStringsArray, TOpt extends TOptions, Ret extends TFunctionReturn, TOpt>, >( ...args: | [key: Key | Key[], options?: TOpt & InterpolationMap] | [key: string | string[], options: TOpt & $Dictionary & { defaultValue: string }] | [key: string | string[], defaultValue: string, options?: TOpt & $Dictionary] ): TFunctionReturnOptionalDetails; } export type KeyPrefix = ResourceKeys[$FirstNamespace] | undefined;