Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 2x 2x 10x 10x 10x 10x 7x 7x 2x 13x 13x 2x 11x 6x 7x 4x | import { type I18n, type LocaleLang, type TFunction, type TFunctionArgs } from "@embra/i18n";
import { useValue } from "@embra/reactivity/react";
import { type FC, type PropsWithChildren, createContext, createElement, useContext, useMemo } from "react";
interface Ctx {
t: TFunction;
i18n: I18n;
}
const I18nContext = /* @__PURE__ */ createContext<Ctx | null>(null);
export interface I18nProviderProps {
i18n: I18n;
}
/**
* Provides the I18n instance to the rest of the app.
*
* @example
* ```tsx
* <I18nProvider i18n={i18n}>
* <App />
* </I18nProvider>
*/
export const I18nProvider: FC<PropsWithChildren<I18nProviderProps>> = ({ i18n, children }) => {
const currentT = useValue(i18n.t$);
const depT = useContext(I18nContext)?.t;
return createElement(I18nContext.Provider, {
value: useMemo(
() => ({
t: depT
? (keyPath: string, args?: TFunctionArgs): string => {
const result = currentT(keyPath, args);
return result === keyPath ? depT(keyPath, args) : result;
}
: currentT,
i18n,
}),
[currentT, depT],
),
children,
});
};
interface UseI18nCtx {
(): Ctx;
(optional?: false): Ctx;
(optional?: boolean): Ctx | null;
}
const useI18nCtx: UseI18nCtx = (optional => {
const ctx = useContext(I18nContext);
if (!ctx && !optional) {
throw new Error("I18nProvider not found");
}
return ctx;
}) as UseI18nCtx;
export interface UseTranslate {
(): TFunction;
(optional?: false): TFunction;
(optional?: boolean): TFunction | undefined;
}
/**
* @returns A {@link TFunction} that translates the key from the nearest {@link I18nProvider} and fallbacks outwards.
* If no {@link I18nProvider} found, throws an error unless `optional` is true.
*/
export const useTranslate: UseTranslate = (optional => useI18nCtx(optional)?.t) as UseTranslate;
export interface UseI18n {
(): I18n;
(optional?: false): I18n;
(optional?: boolean): I18n | undefined;
}
/**
* @returns The {@link I18n} instance from the nearest {@link I18nProvider}.
* If no {@link I18nProvider} found, throws an error unless `optional` is true.
*/
export const useI18n: UseI18n = (optional => useI18nCtx(optional)?.i18n) as UseI18n;
export interface UseLang {
(): LocaleLang;
(optional?: false): LocaleLang;
(optional?: boolean): LocaleLang | undefined;
}
/**
* @returns The {@link LocaleLang} from the nearest {@link I18nProvider}.
* If no {@link I18nProvider} found, throws an error unless `optional` is true.
*/
export const useLang: UseLang = (optional => useValue(useI18n(optional)?.lang$)) as UseLang;
|