You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
399 lines
11 KiB
399 lines
11 KiB
3 years ago
|
import i18next, {
|
||
|
ReactOptions,
|
||
|
i18n,
|
||
|
ThirdPartyModule,
|
||
|
Resource,
|
||
|
TOptions,
|
||
|
StringMap,
|
||
|
TFunctionResult,
|
||
|
} from 'i18next';
|
||
|
import * as React from 'react';
|
||
|
|
||
|
type Subtract<T extends K, K> = Omit<T, keyof K>;
|
||
|
|
||
|
/**
|
||
|
* Due to a limitation/bug on typescript 4.1 (https://github.com/microsoft/TypeScript/issues/41406), we added
|
||
|
* "extends infer A ? A : never" in a few places to suppress the error "Type instantiation is excessively deep and possibly infinite."
|
||
|
* on cases where users have more than 22 namespaces. Once the issue is fixed, we can remove all instances of the workaround used.
|
||
|
*
|
||
|
* Reference of the bug reported: https://github.com/i18next/react-i18next/issues/1222
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* This interface can be augmented by users to add types to `react-i18next` default resources.
|
||
|
*
|
||
|
* @deprecated use the `resources` key of `CustomTypeOptions` instead
|
||
|
*/
|
||
|
export interface Resources {}
|
||
|
/**
|
||
|
* This interface can be augmented by users to add types to `react-i18next`. It accepts a `defaultNS`, `resources`, `returnNull` and `returnEmptyString` properties.
|
||
|
*
|
||
|
* Usage:
|
||
|
* ```ts
|
||
|
* // react-i18next.d.ts
|
||
|
* import 'react-i18next';
|
||
|
* declare module 'react-i18next' {
|
||
|
* interface CustomTypeOptions {
|
||
|
* defaultNS: 'custom';
|
||
|
* returnNull: false;
|
||
|
* returnEmptyString: false;
|
||
|
* nsSeparator: ':';
|
||
|
* keySeparator: '.';
|
||
|
* jsonFormat: 'v4';
|
||
|
* allowObjectInHTMLChildren: false;
|
||
|
* resources: {
|
||
|
* custom: {
|
||
|
* foo: 'foo';
|
||
|
* };
|
||
|
* };
|
||
|
* }
|
||
|
* }
|
||
|
* ```
|
||
|
*/
|
||
|
export interface CustomTypeOptions {}
|
||
|
|
||
|
type MergeBy<T, K> = Omit<T, keyof K> & K;
|
||
|
|
||
|
type TypeOptions = MergeBy<
|
||
|
{
|
||
|
returnNull: true;
|
||
|
returnEmptyString: true;
|
||
|
keySeparator: '.';
|
||
|
nsSeparator: ':';
|
||
|
defaultNS: 'translation';
|
||
|
jsonFormat: 'v4';
|
||
|
resources: Resources;
|
||
|
allowObjectInHTMLChildren: false;
|
||
|
},
|
||
|
CustomTypeOptions
|
||
|
>;
|
||
|
|
||
|
type DefaultResources = TypeOptions['resources'];
|
||
|
type DefaultNamespace<T = TypeOptions['defaultNS']> = T extends Fallback<string> ? T : string;
|
||
|
|
||
|
type Fallback<F, T = keyof DefaultResources> = [T] extends [never] ? F : T;
|
||
|
|
||
|
export type Namespace<F = Fallback<string>> = F | F[];
|
||
|
|
||
|
export function setDefaults(options: ReactOptions): void;
|
||
|
export function getDefaults(): ReactOptions;
|
||
|
export function setI18n(instance: i18n): void;
|
||
|
export function getI18n(): i18n;
|
||
|
export const initReactI18next: ThirdPartyModule;
|
||
|
export function composeInitialProps(ForComponent: any): (ctx: unknown) => Promise<any>;
|
||
|
export function getInitialProps(): {
|
||
|
initialI18nStore: {
|
||
|
[ns: string]: {};
|
||
|
};
|
||
|
initialLanguage: string;
|
||
|
};
|
||
|
|
||
|
export interface ReportNamespaces {
|
||
|
addUsedNamespaces(namespaces: Namespace[]): void;
|
||
|
getUsedNamespaces(): string[];
|
||
|
}
|
||
|
|
||
|
declare module 'i18next' {
|
||
|
interface i18n {
|
||
|
reportNamespaces: ReportNamespaces;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type ObjectOrNever = TypeOptions['allowObjectInHTMLChildren'] extends true
|
||
|
? Record<string, unknown>
|
||
|
: never;
|
||
|
|
||
|
type ReactI18NextChild = React.ReactNode | ObjectOrNever;
|
||
|
|
||
|
declare module 'react' {
|
||
|
interface HTMLAttributes<T> {
|
||
|
children?: ReactI18NextChild | Iterable<ReactI18NextChild>;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type PluralSuffix = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
|
||
|
|
||
|
type WithOrWithoutPlural<K> = TypeOptions['jsonFormat'] extends 'v4'
|
||
|
? K extends `${infer B}_${PluralSuffix}`
|
||
|
? B | K
|
||
|
: K
|
||
|
: K;
|
||
|
|
||
|
// Normalize single namespace
|
||
|
export type KeysWithSeparator<K1, K2, S extends string = TypeOptions['keySeparator']> = `${K1 &
|
||
|
string}${S}${K2 & string}`;
|
||
|
type KeysWithSeparator2<K1, K2> = KeysWithSeparator<K1, Exclude<K2, keyof any[]>>;
|
||
|
type Normalize2<T, K = keyof T> = K extends keyof T
|
||
|
? T[K] extends Record<string, any>
|
||
|
? T[K] extends readonly any[]
|
||
|
?
|
||
|
| KeysWithSeparator2<K, WithOrWithoutPlural<keyof T[K]>>
|
||
|
| KeysWithSeparator2<K, Normalize2<T[K]>>
|
||
|
:
|
||
|
| KeysWithSeparator<K, WithOrWithoutPlural<keyof T[K]>>
|
||
|
| KeysWithSeparator<K, Normalize2<T[K]>>
|
||
|
: never
|
||
|
: never;
|
||
|
type Normalize<T> = WithOrWithoutPlural<keyof T> | Normalize2<T>;
|
||
|
|
||
|
// Normalize multiple namespaces
|
||
|
type KeyWithNSSeparator<N, K, S extends string = TypeOptions['nsSeparator']> = `${N &
|
||
|
string}${S}${K & string}`;
|
||
|
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
|
||
|
? I
|
||
|
: never;
|
||
|
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R
|
||
|
? R
|
||
|
: never;
|
||
|
type NormalizeMulti<T, U extends keyof T, L = LastOf<U>> = L extends U
|
||
|
? KeyWithNSSeparator<L, Normalize<T[L]>> | NormalizeMulti<T, Exclude<U, L>>
|
||
|
: never;
|
||
|
|
||
|
interface CustomTypeParameters {
|
||
|
returnNull?: boolean;
|
||
|
returnEmptyString?: boolean;
|
||
|
}
|
||
|
|
||
|
type TypeOptionsFallback<TranslationValue, Option, MatchingValue> = Option extends false
|
||
|
? TranslationValue extends MatchingValue
|
||
|
? string
|
||
|
: TranslationValue
|
||
|
: TranslationValue;
|
||
|
|
||
|
/**
|
||
|
* Checks if user has enabled `returnEmptyString` and `returnNull` options to retrieve correct values.
|
||
|
*/
|
||
|
export type NormalizeByTypeOptions<
|
||
|
TranslationValue,
|
||
|
Options extends CustomTypeParameters = TypeOptions,
|
||
|
R = TypeOptionsFallback<TranslationValue, Options['returnEmptyString'], ''>
|
||
|
> = TypeOptionsFallback<R, Options['returnNull'], null>;
|
||
|
|
||
|
type StringIfPlural<T> = TypeOptions['jsonFormat'] extends 'v4'
|
||
|
? T extends `${string}_${PluralSuffix}`
|
||
|
? string
|
||
|
: never
|
||
|
: never;
|
||
|
|
||
|
type NormalizeReturn<
|
||
|
T,
|
||
|
V,
|
||
|
S extends string | false = TypeOptions['keySeparator']
|
||
|
> = V extends keyof T
|
||
|
? NormalizeByTypeOptions<T[V]>
|
||
|
: S extends false
|
||
|
? V
|
||
|
: V extends `${infer K}${S}${infer R}`
|
||
|
? K extends keyof T
|
||
|
? NormalizeReturn<T[K], R>
|
||
|
: never
|
||
|
: StringIfPlural<keyof T>;
|
||
|
|
||
|
type NormalizeMultiReturn<T, V> = V extends `${infer N}:${infer R}`
|
||
|
? N extends keyof T
|
||
|
? NormalizeReturn<T[N], R>
|
||
|
: never
|
||
|
: never;
|
||
|
|
||
|
type NormalizeWithKeyPrefix<
|
||
|
T,
|
||
|
K,
|
||
|
S extends string = TypeOptions['keySeparator']
|
||
|
> = K extends `${infer K1}${S}${infer K2}`
|
||
|
? K1 extends keyof T
|
||
|
? NormalizeWithKeyPrefix<T[K1], K2>
|
||
|
: never
|
||
|
: K extends keyof T
|
||
|
? T[K] extends string
|
||
|
? never
|
||
|
: Normalize<T[K]>
|
||
|
: never;
|
||
|
|
||
|
type KeyPrefix<N extends Namespace> =
|
||
|
| (N extends keyof DefaultResources ? Normalize<DefaultResources[N]> : string)
|
||
|
| undefined;
|
||
|
|
||
|
export type TFuncKey<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix = undefined,
|
||
|
T = DefaultResources
|
||
|
> = N extends (keyof T)[] | Readonly<(keyof T)[]>
|
||
|
? NormalizeMulti<T, N[number]>
|
||
|
: N extends keyof T
|
||
|
? TKPrefix extends undefined
|
||
|
? Normalize<T[N]>
|
||
|
: NormalizeWithKeyPrefix<T[N], TKPrefix>
|
||
|
: string;
|
||
|
|
||
|
export type TFuncReturn<
|
||
|
N,
|
||
|
TKeys,
|
||
|
TDefaultResult,
|
||
|
TKPrefix = undefined,
|
||
|
T = DefaultResources
|
||
|
> = N extends (keyof T)[]
|
||
|
? NormalizeMultiReturn<T, TKeys>
|
||
|
: N extends keyof T
|
||
|
? TKPrefix extends undefined
|
||
|
? NormalizeReturn<T[N], TKeys>
|
||
|
: NormalizeReturn<T[N], KeysWithSeparator<TKPrefix, TKeys>>
|
||
|
: Fallback<TDefaultResult>;
|
||
|
|
||
|
export interface TFunction<N extends Namespace = DefaultNamespace, TKPrefix = undefined> {
|
||
|
<
|
||
|
TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
|
||
|
TDefaultResult extends TFunctionResult | React.ReactNode = string,
|
||
|
TInterpolationMap extends object = StringMap
|
||
|
>(
|
||
|
key: TKeys | TKeys[],
|
||
|
options?: TOptions<TInterpolationMap> | string,
|
||
|
): TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>;
|
||
|
<
|
||
|
TKeys extends TFuncKey<N, TKPrefix> | TemplateStringsArray extends infer A ? A : never,
|
||
|
TDefaultResult extends TFunctionResult | React.ReactNode = string,
|
||
|
TInterpolationMap extends object = StringMap
|
||
|
>(
|
||
|
key: TKeys | TKeys[],
|
||
|
defaultValue?: string,
|
||
|
options?: TOptions<TInterpolationMap> | string,
|
||
|
): TFuncReturn<N, TKeys, TDefaultResult, TKPrefix>;
|
||
|
}
|
||
|
|
||
|
type TransChild = React.ReactNode | Record<string, unknown>;
|
||
|
export type TransProps<
|
||
|
K extends TFuncKey<N, TKPrefix> extends infer A ? A : never,
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix = undefined,
|
||
|
E = React.HTMLProps<HTMLDivElement>
|
||
|
> = E & {
|
||
|
children?: TransChild | TransChild[];
|
||
|
components?: readonly React.ReactElement[] | { readonly [tagName: string]: React.ReactElement };
|
||
|
count?: number;
|
||
|
context?: string;
|
||
|
defaults?: string;
|
||
|
i18n?: i18n;
|
||
|
i18nKey?: K | K[];
|
||
|
ns?: N;
|
||
|
parent?: string | React.ComponentType<any> | null; // used in React.createElement if not null
|
||
|
tOptions?: {};
|
||
|
values?: {};
|
||
|
shouldUnescape?: boolean;
|
||
|
t?: TFunction<N, TKPrefix>;
|
||
|
};
|
||
|
|
||
|
export function Trans<
|
||
|
K extends TFuncKey<N, TKPrefix> extends infer A ? A : never,
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined,
|
||
|
E = React.HTMLProps<HTMLDivElement>
|
||
|
>(props: TransProps<K, N, TKPrefix, E>): React.ReactElement;
|
||
|
|
||
|
export function useSSR(initialI18nStore: Resource, initialLanguage: string): void;
|
||
|
|
||
|
export interface UseTranslationOptions<TKPrefix = undefined> {
|
||
|
i18n?: i18n;
|
||
|
useSuspense?: boolean;
|
||
|
keyPrefix?: TKPrefix;
|
||
|
bindI18n?: string | false;
|
||
|
nsMode?: 'fallback' | 'default';
|
||
|
}
|
||
|
|
||
|
export type UseTranslationResponse<N extends Namespace, TKPrefix = undefined> = [
|
||
|
TFunction<N, TKPrefix>,
|
||
|
i18n,
|
||
|
boolean,
|
||
|
] & {
|
||
|
t: TFunction<N, TKPrefix>;
|
||
|
i18n: i18n;
|
||
|
ready: boolean;
|
||
|
};
|
||
|
|
||
|
export function useTranslation<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined
|
||
|
>(
|
||
|
ns?: N | Readonly<N>,
|
||
|
options?: UseTranslationOptions<TKPrefix>,
|
||
|
): UseTranslationResponse<N, TKPrefix>;
|
||
|
|
||
|
// Need to see usage to improve this
|
||
|
export function withSSR(): <Props>(
|
||
|
WrappedComponent: React.ComponentType<Props>,
|
||
|
) => {
|
||
|
({
|
||
|
initialI18nStore,
|
||
|
initialLanguage,
|
||
|
...rest
|
||
|
}: {
|
||
|
initialI18nStore: Resource;
|
||
|
initialLanguage: string;
|
||
|
} & Props): React.FunctionComponentElement<Props>;
|
||
|
getInitialProps: (ctx: unknown) => Promise<any>;
|
||
|
};
|
||
|
|
||
|
export interface WithTranslation<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined
|
||
|
> {
|
||
|
t: TFunction<N, TKPrefix>;
|
||
|
i18n: i18n;
|
||
|
tReady: boolean;
|
||
|
}
|
||
|
|
||
|
export interface WithTranslationProps {
|
||
|
i18n?: i18n;
|
||
|
useSuspense?: boolean;
|
||
|
}
|
||
|
|
||
|
export function withTranslation<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined
|
||
|
>(
|
||
|
ns?: N,
|
||
|
options?: {
|
||
|
withRef?: boolean;
|
||
|
keyPrefix?: TKPrefix;
|
||
|
},
|
||
|
): <
|
||
|
C extends React.ComponentType<React.ComponentProps<any> & WithTranslationProps>,
|
||
|
ResolvedProps = JSX.LibraryManagedAttributes<
|
||
|
C,
|
||
|
Subtract<React.ComponentProps<C>, WithTranslationProps>
|
||
|
>
|
||
|
>(
|
||
|
component: C,
|
||
|
) => React.ComponentType<Omit<ResolvedProps, keyof WithTranslation<N>> & WithTranslationProps>;
|
||
|
|
||
|
export interface I18nextProviderProps {
|
||
|
children?: React.ReactNode;
|
||
|
i18n: i18n;
|
||
|
defaultNS?: string;
|
||
|
}
|
||
|
|
||
|
export const I18nextProvider: React.FunctionComponent<I18nextProviderProps>;
|
||
|
export const I18nContext: React.Context<{ i18n: i18n }>;
|
||
|
|
||
|
export interface TranslationProps<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined
|
||
|
> {
|
||
|
children: (
|
||
|
t: TFunction<N, TKPrefix>,
|
||
|
options: {
|
||
|
i18n: i18n;
|
||
|
lng: string;
|
||
|
},
|
||
|
ready: boolean,
|
||
|
) => React.ReactNode;
|
||
|
ns?: N;
|
||
|
i18n?: i18n;
|
||
|
useSuspense?: boolean;
|
||
|
keyPrefix?: TKPrefix;
|
||
|
nsMode?: 'fallback' | 'default';
|
||
|
}
|
||
|
|
||
|
export function Translation<
|
||
|
N extends Namespace = DefaultNamespace,
|
||
|
TKPrefix extends KeyPrefix<N> = undefined
|
||
|
>(props: TranslationProps<N, TKPrefix>): any;
|