@intl-t/core
Version:
A Fully-Typed Node-Based i18n Translation Library
112 lines (111 loc) • 8.15 kB
TypeScript
import type { TranslationNode, invalidKeys } from "@intl-t/core/translation";
import type { State, GlobalPathSeparator } from "@intl-t/global";
import type { Locale } from "@intl-t/locales";
import type { ReactChunk } from "@intl-t/react";
export type { TranslationNode, Locale, State };
export type { TranslationProps, ReactNode, TranslationFC, TranslationNodeFC } from "@intl-t/react";
export type Base = string | number;
export type Key = string | number | symbol;
export type Value = Base | null | undefined | boolean | Base[] | Date | ReactChunk;
export type Values = Record<Key, Value>;
export type Stringable = string | number | boolean | null | undefined;
export type InvalidKey = (typeof invalidKeys)[number];
export type Node = Base | readonly Node[] | readonly [Node, ...Node[]] | ({
[key: Key]: Node;
} & {
values?: Values;
base?: Base;
});
export type Keep<T> = T extends Base ? Base : T extends [infer F, ...infer R] ? [Keep<F>, ...isArray<Keep<R>>] : {
[K in keyof T]: T[K] extends object ? Keep<T[K]> : T[K] | Base;
};
export type ResolveNode<T> = T extends Promisable<infer N> | (() => Promisable<infer N>) ? Default<N> : Default<T>;
export type ResolveTree<T extends Record<string, any>> = {
[L in keyof T]: ResolveNode<T[L]>;
};
export type Display<N> = N extends `${infer A}{${string}}${infer B}` ? `${A}${string}${Display<B>}` : N;
export type Content<N> = N extends Base ? Display<N> : N extends {
base: infer B;
} ? Display<B> : Base;
export type Children<N> = N extends object ? N extends readonly any[] | any[] ? Exclude<keyof N, keyof (readonly any[]) | keyof any[]> : Exclude<keyof N, InvalidKey> : never;
type VFSO<V extends string, C extends string = string, T extends any = Value> = {
[K in V]: T;
} & VFS1<C>;
type VFSR<S extends string, C extends string> = VFSO<S extends `/${infer V}` | `${infer V} ${string}` ? V : S, C, ReactChunk>;
type VFS2<S extends string> = S extends `${infer V},${string}` ? V : S;
type VFS1<S extends string> = S extends `${string}{{${infer V}}}${infer C}` ? VFSO<VFS2<V>, C> : S extends `${string}{${infer V}}${infer C}` ? VFSO<VFS2<V>, C> : S extends `${string}<${infer V}>${infer C}` ? VFSR<V, C> : {};
export type VariablesFromString<S extends string> = VFS1<S>;
export type Override<T, U> = T & U extends never ? Omit<T, keyof U> & U : T & U;
export type VariablesFromNode<N> = "values" extends keyof N ? N["values"] : N extends string ? VariablesFromString<N> : {};
export type Variables<N, V = Values> = Override<V, VariablesFromNode<N>>;
export type LastKey<R extends Key[]> = R extends [...Key[], infer K] ? K : Key;
export type Join<K extends Key[], S extends string> = K extends [infer F extends Stringable, ...infer R] ? R extends [Key, ...Key[]] ? `${F}${S}${Join<R, S>}` : `${F}` : string;
export type Default<T> = T extends {
default: infer D;
} ? D : T;
export type Promisable<T> = T | Promise<T>;
export type Awaitable<T> = T & Promise<T>;
export type valueof<O extends object> = O extends Record<any, infer V> ? V : never;
export type ArrayToString<A extends Key[], S extends string = "."> = A extends [infer F extends Stringable, ...infer R] ? `${F}${R extends [Key, ...any[]] ? `${S}${ArrayToString<R, S>}` : ""}` : "";
export type StringToArray<S extends string, D extends string = "."> = S extends `${infer T}${D}${infer U}` ? [T, ...StringToArray<U, D>] : [S];
export type isArray<A = any[]> = A extends any[] ? A : never;
export type SearchWays<N, A extends any[] = [], C extends keyof N = Children<N>> = symbol | C extends symbol ? A : valueof<{
[K in C]: SearchWays<N[K], [...A, K]> | [...A, K];
}>;
export type KeysFromNode<N, S extends string = GlobalPathSeparator> = ArrayToString<isArray<SearchWays<N>>, S>;
export type TranslationKeys<T, S extends string = GlobalPathSeparator> = T extends {
node: infer N;
} ? KeysFromNode<N, S> : KeysFromNode<T, S>;
export type FollowWay<N, W extends Key[]> = W extends [infer F, ...infer R extends Key[]] ? F extends keyof N ? FollowWay<N[F], R> : ArrayToString<W> : N;
export type FollowWayWithValues<N, W extends Key[], VV = Values, V = Variables<N, VV>> = W extends [
infer F extends keyof N,
...infer R extends Key[]
] ? N[F] extends Node ? FollowWayWithValues<N[F], R, V> : V : V;
export type Translation<S extends TranslationSettings = TranslationSettings, N = S["tree"][S["allowedLocale"]], V = S["variables"], L extends S["allowedLocale"] = S["allowedLocale"], R extends Key[] = []> = {
<const VV extends Values>(variables?: Override<Partial<Variables<N, V>>, VV>): Translation<S, N, Override<V, VV>, L, R>;
<LL extends S["allowedLocale"], const VV extends Values = Values>(locale: `${LL}${"" & {}}`, variables?: Override<Partial<Variables<N, V>>, VV>): Translation<S, FollowWay<S["tree"][LL], R>, Override<V, VV>, LL, R>;
<D extends ArrayToString<isArray<SearchWays<N>>, S["ps"]> | (string & {}), const VV extends Values = Values>(path?: D, variables?: Override<Partial<FollowWayWithValues<N, StringToArray<D, S["ps"]>, V>>, VV>): Translation<S, FollowWay<N, StringToArray<D, S["ps"]>>, FollowWayWithValues<N, StringToArray<D, S["ps"]>, any, Override<Variables<N, V>, VV>>, L, [
...R,
...StringToArray<D, S["ps"]>
]>;
<A extends isArray<SearchWays<N>>, A_ extends string[] = A, const VV extends Values = Values>(path?: A | A_, variables?: Override<Partial<FollowWayWithValues<N, A_, V>>, VV>): Translation<S, FollowWay<N, A_>, FollowWayWithValues<N, A_, any, Override<Variables<N, V>, VV>>, L, [...R, ...A_]>;
<A extends isArray<SearchWays<N>>, A_ extends string[] = A, const VV extends Values = Values>(...path: A | A_ | [...(A | A_), Override<Partial<FollowWayWithValues<N, A_, V>>, VV>?] | TemplateStringsArray[]): Translation<S, FollowWay<N, A_>, FollowWayWithValues<N, A_, any, Override<Variables<N, V>, VV>>, L, [...R, ...A_]>;
new <const T extends TranslationData>(data: T): TranslationDataAdapter<T>;
} & TranslationNode<S, N, V & Values, L, R> & {
[C in Children<N>]: Translation<S, N[C], Variables<N, V>, L, [...R, C]>;
} & {
[LL in S["allowedLocale"]]: Translation<S, FollowWay<S["tree"][LL], R>, V, LL, R>;
} & (N extends any[] | readonly any[] ? Translation<S, FollowWay<S["tree"][L], [...R, Children<N>]>, V, L, [...R, Children<N>]>[] : Content<N>);
export type { Translation as TranslationType };
export interface TranslationSettings<AllowedLocale extends Locale = string, MainLocale extends AllowedLocale = AllowedLocale, Tree = unknown, Variables extends Values = Values, PathSeparator extends string = string, N = Node> extends State<AllowedLocale> {
locales: (Partial<Tree> & {
[Locale in AllowedLocale]?: Keep<N> | (() => Promisable<Keep<N>>);
}) | ((locale: Locale) => Promisable<Tree>);
mainLocale: MainLocale;
defaultLocale: MainLocale;
currentLocale: AllowedLocale;
allowedLocales: AllowedLocale[] & [MainLocale, ...AllowedLocale[]];
allowedLocale: AllowedLocale;
pathSeparator: PathSeparator;
variables: Variables;
tree: Tree extends Record<AllowedLocale, any> ? ResolveTree<Tree> : Record<AllowedLocale, Default<Tree>>;
ps: PathSeparator;
settings: this;
preventDynamic: boolean;
preload: boolean;
hydrate: boolean;
t?: any;
setLocale: (locale: Locale) => Locale | void;
getLocale: (locale: Locale) => Promisable<Node>;
}
export interface TranslationData<S extends TranslationSettings = TranslationSettings, N = S["tree"], V = S["variables"], L extends S["allowedLocale"] = S["mainLocale"], R extends Key[] = Key[]> {
settings: S;
node?: N;
variables?: V;
locale?: L;
path?: R;
key?: LastKey<R>;
parent?: TranslationNode;
preload?: boolean;
}
export type TranslationDataAdapter<T extends TranslationData = TranslationData> = Translation<undefined extends T["settings"] ? TranslationSettings : T["settings"], undefined extends T["node"] ? T["settings"]["tree"] : T["node"], undefined extends T["variables"] ? NonNullable<T["settings"]["variables"]> : NonNullable<T["variables"]>, undefined extends T["locale"] ? NonNullable<T["settings"]["mainLocale"]> : NonNullable<T["locale"]>>;