i18n need to be passed as props if we want to be able to ovewrite

This commit is contained in:
Joseph Garrone 2024-06-09 11:20:45 +02:00
parent 2015882688
commit 7a040935e9
57 changed files with 310 additions and 246 deletions

View File

@ -1,7 +1,8 @@
import { lazy, Suspense } from "react"; import { lazy, Suspense } from "react";
import { assert, type Equals } from "tsafe/assert"; import { assert, type Equals } from "tsafe/assert";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "./KcContext"; import type { KcContext } from "keycloakify/account/KcContext";
import { I18n } from "keycloakify/account/i18n";
const Password = lazy(() => import("keycloakify/account/pages/Password")); const Password = lazy(() => import("keycloakify/account/pages/Password"));
const Account = lazy(() => import("keycloakify/account/pages/Account")); const Account = lazy(() => import("keycloakify/account/pages/Account"));
@ -11,7 +12,7 @@ const Applications = lazy(() => import("keycloakify/account/pages/Applications")
const Log = lazy(() => import("keycloakify/account/pages/Log")); const Log = lazy(() => import("keycloakify/account/pages/Log"));
const FederatedIdentity = lazy(() => import("keycloakify/account/pages/FederatedIdentity")); const FederatedIdentity = lazy(() => import("keycloakify/account/pages/FederatedIdentity"));
export default function Fallback(props: PageProps<KcContext>) { export default function Fallback(props: PageProps<KcContext, I18n>) {
const { kcContext, ...rest } = props; const { kcContext, ...rest } = props;
return ( return (

View File

@ -5,15 +5,15 @@ import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags"; import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
import { useSetClassName } from "keycloakify/tools/useSetClassName"; import { useSetClassName } from "keycloakify/tools/useSetClassName";
import type { TemplateProps } from "keycloakify/account/TemplateProps"; import type { TemplateProps } from "keycloakify/account/TemplateProps";
import type { I18n } from "./i18n";
import type { KcContext } from "./KcContext"; import type { KcContext } from "./KcContext";
import { useI18n } from "./i18n";
export default function Template(props: TemplateProps<KcContext>) { export default function Template(props: TemplateProps<KcContext, I18n>) {
const { kcContext, doUseDefaultCss, active, classes, children } = props; const { kcContext, i18n, doUseDefaultCss, active, classes, children } = props;
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes }); const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
const { msg, msgStr, getChangeLocalUrl, labelBySupportedLanguageTag, currentLanguageTag } = useI18n({ kcContext }); const { msg, msgStr, getChangeLocalUrl, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
const { locale, url, features, realm, message, referrer } = kcContext; const { locale, url, features, realm, message, referrer } = kcContext;

View File

@ -1,12 +1,13 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import type { KcContext } from "./KcContext";
export type TemplateProps<KcContext extends KcContext.Common> = { export type TemplateProps<KcContext, I18n> = {
kcContext: KcContext; kcContext: KcContext;
i18n: I18n;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
active: string;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;
children: ReactNode; children: ReactNode;
active: string;
}; };
export type ClassKey = export type ClassKey =

View File

@ -130,7 +130,7 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
extraMessages: extraMessages[partialI18n.currentLanguageTag] extraMessages: extraMessages[partialI18n.currentLanguageTag]
}); });
const isCurrentLanguageFallbackLanguage = partialI18n.currentLanguageTag !== fallbackLanguageTag; const isCurrentLanguageFallbackLanguage = partialI18n.currentLanguageTag === fallbackLanguageTag;
const result: Result = { const result: Result = {
i18n: { i18n: {
@ -175,7 +175,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
const { getI18n } = createGetI18n(extraMessages); const { getI18n } = createGetI18n(extraMessages);
function useI18n(params: { kcContext: KcContextLike }): I18n { function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
const { kcContext } = params; const { kcContext } = params;
const { i18n, prI18n_currentLanguage } = getI18n({ kcContext }); const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
@ -198,7 +198,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
}; };
}, []); }, []);
return i18n_toReturn; return { i18n: i18n_toReturn };
} }
return { useI18n, ofTypeI18n: Reflect<I18n>() }; return { useI18n, ofTypeI18n: Reflect<I18n>() };

View File

@ -1,10 +1,5 @@
export type { MessageKey } from "./i18n"; import type { GenericI18n, MessageKey, KcContextLike } from "./i18n";
import { createUseI18n } from "./i18n"; export type { MessageKey, KcContextLike };
export { createUseI18n }; export type I18n = GenericI18n<MessageKey>;
export { createUseI18n } from "./i18n";
export { fallbackLanguageTag } from "./i18n"; export { fallbackLanguageTag } from "./i18n";
const { useI18n, ofTypeI18n } = createUseI18n({});
export type I18n = typeof ofTypeI18n;
export { useI18n };

View File

@ -2,10 +2,10 @@ import { clsx } from "keycloakify/tools/clsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Account(props: PageProps<Extract<KcContext, { pageId: "account.ftl" }>>) { export default function Account(props: PageProps<Extract<KcContext, { pageId: "account.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template } = props; const { kcContext, i18n, doUseDefaultCss, Template } = props;
const classes = { const classes = {
...props.classes, ...props.classes,
@ -19,10 +19,10 @@ export default function Account(props: PageProps<Extract<KcContext, { pageId: "a
const { url, realm, messagesPerField, stateChecker, account, referrer } = kcContext; const { url, realm, messagesPerField, stateChecker, account, referrer } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="account"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="account">
<div className="row"> <div className="row">
<div className="col-md-10"> <div className="col-md-10">
<h2>{msg("editAccountHtmlTitle")}</h2> <h2>{msg("editAccountHtmlTitle")}</h2>

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Applications(props: PageProps<Extract<KcContext, { pageId: "applications.ftl" }>>) { export default function Applications(props: PageProps<Extract<KcContext, { pageId: "applications.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, classes, Template } = props; const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -17,10 +17,10 @@ export default function Applications(props: PageProps<Extract<KcContext, { pageI
stateChecker stateChecker
} = kcContext; } = kcContext;
const { msg, advancedMsg } = useI18n({ kcContext }); const { msg, advancedMsg } = i18n;
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="applications"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="applications">
<div className="row"> <div className="row">
<div className="col-md-10"> <div className="col-md-10">
<h2>{msg("applicationsHtmlTitle")}</h2> <h2>{msg("applicationsHtmlTitle")}</h2>

View File

@ -1,14 +1,14 @@
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function FederatedIdentity(props: PageProps<Extract<KcContext, { pageId: "federatedIdentity.ftl" }>>) { export default function FederatedIdentity(props: PageProps<Extract<KcContext, { pageId: "federatedIdentity.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, classes, Template } = props; const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
const { url, federatedIdentity, stateChecker } = kcContext; const { url, federatedIdentity, stateChecker } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="federatedIdentity"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="federatedIdentity">
<div className="main-layout social"> <div className="main-layout social">
<div className="row"> <div className="row">
<div className="col-md-10"> <div className="col-md-10">

View File

@ -2,10 +2,10 @@ import type { Key } from "react";
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Log(props: PageProps<Extract<KcContext, { pageId: "log.ftl" }>>) { export default function Log(props: PageProps<Extract<KcContext, { pageId: "log.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, classes, Template } = props; const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -14,10 +14,10 @@ export default function Log(props: PageProps<Extract<KcContext, { pageId: "log.f
const { log } = kcContext; const { log } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="log"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="log">
<div className={kcClsx("kcContentWrapperClass")}> <div className={kcClsx("kcContentWrapperClass")}>
<div className="col-md-10"> <div className="col-md-10">
<h2>{msg("accountLogHtmlTitle")}</h2> <h2>{msg("accountLogHtmlTitle")}</h2>

View File

@ -1,10 +1,10 @@
import type { TemplateProps, ClassKey } from "keycloakify/account/TemplateProps"; import { type TemplateProps, type ClassKey } from "keycloakify/account/TemplateProps";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import type { KcContext } from "../KcContext";
export type PageProps<NarrowedKcContext = KcContext> = { export type PageProps<NarrowedKcContext, I18n> = {
Template: LazyOrNot<(props: TemplateProps<any>) => JSX.Element | null>; Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>;
kcContext: NarrowedKcContext; kcContext: NarrowedKcContext;
i18n: I18n;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;
}; };

View File

@ -3,10 +3,10 @@ import { clsx } from "keycloakify/tools/clsx";
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Password(props: PageProps<Extract<KcContext, { pageId: "password.ftl" }>>) { export default function Password(props: PageProps<Extract<KcContext, { pageId: "password.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template } = props; const { kcContext, i18n, doUseDefaultCss, Template } = props;
const classes = { const classes = {
...props.classes, ...props.classes,
@ -20,7 +20,7 @@ export default function Password(props: PageProps<Extract<KcContext, { pageId: "
const { url, password, account, stateChecker } = kcContext; const { url, password, account, stateChecker } = kcContext;
const { msgStr, msg } = useI18n({ kcContext }); const { msgStr, msg } = i18n;
const [currentPassword, setCurrentPassword] = useState(""); const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState(""); const [newPassword, setNewPassword] = useState("");
@ -77,6 +77,7 @@ export default function Password(props: PageProps<Extract<KcContext, { pageId: "
return kcContext.message; return kcContext.message;
})() })()
}, },
i18n,
doUseDefaultCss, doUseDefaultCss,
classes classes
}} }}

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "sessions.ftl" }>>) { export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "sessions.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,9 +13,9 @@ export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "
const { url, stateChecker, sessions } = kcContext; const { url, stateChecker, sessions } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="sessions"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="sessions">
<div className={kcClsx("kcContentWrapperClass")}> <div className={kcClsx("kcContentWrapperClass")}>
<div className="col-md-10"> <div className="col-md-10">
<h2>{msg("sessionsHtmlTitle")}</h2> <h2>{msg("sessionsHtmlTitle")}</h2>

View File

@ -2,10 +2,10 @@ import { clsx } from "keycloakify/tools/clsx";
import { getKcClsx } from "keycloakify/account/lib/kcClsx"; import { getKcClsx } from "keycloakify/account/lib/kcClsx";
import type { PageProps } from "keycloakify/account/pages/PageProps"; import type { PageProps } from "keycloakify/account/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>>) { export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -14,7 +14,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
const { totp, mode, url, messagesPerField, stateChecker } = kcContext; const { totp, mode, url, messagesPerField, stateChecker } = kcContext;
const { msg, msgStr, advancedMsg } = useI18n({ kcContext }); const { msg, msgStr, advancedMsg } = i18n;
const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = { const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = {
HmacSHA1: "SHA1", HmacSHA1: "SHA1",
@ -23,7 +23,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
}; };
return ( return (
<Template {...{ kcContext, doUseDefaultCss, classes }} active="totp"> <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="totp">
<> <>
<div className="row"> <div className="row">
<div className="col-md-10"> <div className="col-md-10">

View File

@ -2,7 +2,8 @@ import { lazy, Suspense } from "react";
import { assert, type Equals } from "tsafe/assert"; import { assert, type Equals } from "tsafe/assert";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "./KcContext"; import type { I18n } from "keycloakify/login/i18n";
import type { KcContext } from "keycloakify/login/KcContext";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
const Login = lazy(() => import("keycloakify/login/pages/Login")); const Login = lazy(() => import("keycloakify/login/pages/Login"));
@ -40,7 +41,7 @@ const LoginResetOtp = lazy(() => import("keycloakify/login/pages/LoginResetOtp")
const LoginX509Info = lazy(() => import("keycloakify/login/pages/LoginX509Info")); const LoginX509Info = lazy(() => import("keycloakify/login/pages/LoginX509Info"));
const WebauthnError = lazy(() => import("keycloakify/login/pages/WebauthnError")); const WebauthnError = lazy(() => import("keycloakify/login/pages/WebauthnError"));
type FallbackProps = PageProps<KcContext> & { type FallbackProps = PageProps<KcContext, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };

View File

@ -6,10 +6,10 @@ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags"; import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags"; import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
import { useSetClassName } from "keycloakify/tools/useSetClassName"; import { useSetClassName } from "keycloakify/tools/useSetClassName";
import type { I18n } from "./i18n";
import type { KcContext } from "./KcContext"; import type { KcContext } from "./KcContext";
import { useI18n } from "./i18n";
export default function Template(props: TemplateProps<KcContext>) { export default function Template(props: TemplateProps<KcContext, I18n>) {
const { const {
displayInfo = false, displayInfo = false,
displayMessage = true, displayMessage = true,
@ -21,6 +21,7 @@ export default function Template(props: TemplateProps<KcContext>) {
documentTitle, documentTitle,
bodyClassName, bodyClassName,
kcContext, kcContext,
i18n,
doUseDefaultCss, doUseDefaultCss,
classes, classes,
children children
@ -28,7 +29,7 @@ export default function Template(props: TemplateProps<KcContext>) {
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes }); const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
const { msg, msgStr, getChangeLocalUrl, labelBySupportedLanguageTag, currentLanguageTag } = useI18n({ kcContext }); const { msg, msgStr, getChangeLocalUrl, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
const { realm, locale, auth, url, message, isAppInitiatedAction, authenticationSession, scripts } = kcContext; const { realm, locale, auth, url, message, isAppInitiatedAction, authenticationSession, scripts } = kcContext;

View File

@ -1,10 +1,11 @@
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import type { KcContext } from "./KcContext";
export type TemplateProps<KcContext extends KcContext.Common> = { export type TemplateProps<KcContext, I18n> = {
kcContext: KcContext; kcContext: KcContext;
i18n: I18n;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;
children: ReactNode;
displayInfo?: boolean; displayInfo?: boolean;
displayMessage?: boolean; displayMessage?: boolean;
@ -16,8 +17,6 @@ export type TemplateProps<KcContext extends KcContext.Common> = {
infoNode?: ReactNode; infoNode?: ReactNode;
documentTitle?: string; documentTitle?: string;
bodyClassName?: string; bodyClassName?: string;
children: ReactNode;
}; };
export type ClassKey = export type ClassKey =

View File

@ -9,10 +9,11 @@ import {
type FormFieldError type FormFieldError
} from "keycloakify/login/lib/useUserProfileForm"; } from "keycloakify/login/lib/useUserProfileForm";
import type { Attribute } from "keycloakify/login/KcContext"; import type { Attribute } from "keycloakify/login/KcContext";
import { useI18n, type I18n } from "./i18n"; import type { I18n } from "./i18n";
export type UserProfileFormFieldsProps = { export type UserProfileFormFieldsProps = {
kcContext: KcContextLike; kcContext: KcContextLike;
i18n: I18n;
kcClsx: KcClsx; kcClsx: KcClsx;
onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void; onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
@ -30,15 +31,16 @@ type BeforeAfterFieldProps = {
}; };
export default function UserProfileFormFields(props: UserProfileFormFieldsProps) { export default function UserProfileFormFields(props: UserProfileFormFieldsProps) {
const { kcContext, kcClsx, onIsFormSubmittableValueChange, doMakeUserConfirmPassword, BeforeField, AfterField } = props; const { kcContext, i18n, kcClsx, onIsFormSubmittableValueChange, doMakeUserConfirmPassword, BeforeField, AfterField } = props;
const { advancedMsg } = useI18n({ kcContext }); const { advancedMsg } = i18n;
const { const {
formState: { formFieldStates, isFormSubmittable }, formState: { formFieldStates, isFormSubmittable },
dispatchFormAction dispatchFormAction
} = useUserProfileForm({ } = useUserProfileForm({
kcContext, kcContext,
i18n,
doMakeUserConfirmPassword doMakeUserConfirmPassword
}); });
@ -46,8 +48,6 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps)
onIsFormSubmittableValueChange(isFormSubmittable); onIsFormSubmittableValueChange(isFormSubmittable);
}, [isFormSubmittable]); }, [isFormSubmittable]);
const i18n = useI18n({ kcContext });
const groupNameRef = { current: "" }; const groupNameRef = { current: "" };
return ( return (

View File

@ -177,7 +177,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
const { getI18n } = createGetI18n(extraMessages); const { getI18n } = createGetI18n(extraMessages);
function useI18n(params: { kcContext: KcContextLike }): I18n { function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
const { kcContext } = params; const { kcContext } = params;
const { i18n, prI18n_currentLanguage } = getI18n({ kcContext }); const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
@ -200,7 +200,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
}; };
}, []); }, []);
return i18n_toReturn; return { i18n: i18n_toReturn };
} }
return { useI18n, ofTypeI18n: Reflect<I18n>() }; return { useI18n, ofTypeI18n: Reflect<I18n>() };

View File

@ -1,10 +1,5 @@
export type { MessageKey, KcContextLike } from "./i18n"; import type { GenericI18n, MessageKey, KcContextLike } from "./i18n";
import { createUseI18n } from "./i18n"; export type { MessageKey, KcContextLike };
export { createUseI18n }; export type I18n = GenericI18n<MessageKey>;
export { createUseI18n } from "./i18n";
export { fallbackLanguageTag } from "./i18n"; export { fallbackLanguageTag } from "./i18n";
const { useI18n, ofTypeI18n } = createUseI18n({});
export type I18n = typeof ofTypeI18n;
export { useI18n };

View File

@ -11,7 +11,7 @@ import type { PasswordPolicies, Attribute, Validators } from "keycloakify/login/
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import type { MessageKey } from "keycloakify/login/i18n"; import type { MessageKey } from "keycloakify/login/i18n";
import { KcContextLike as KcContextLike_i18n } from "keycloakify/login/i18n"; import { KcContextLike as KcContextLike_i18n } from "keycloakify/login/i18n";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export type FormFieldError = { export type FormFieldError = {
errorMessage: JSX.Element; errorMessage: JSX.Element;
@ -83,6 +83,7 @@ assert<Extract<KcContext.Register, { pageId: "register.ftl" }> extends KcContext
export type ParamsOfUseUserProfileForm = { export type ParamsOfUseUserProfileForm = {
kcContext: KcContextLike; kcContext: KcContextLike;
i18n: I18n;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };
@ -105,7 +106,7 @@ namespace internal {
} }
export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm { export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm {
const { kcContext, doMakeUserConfirmPassword } = params; const { kcContext, i18n, doMakeUserConfirmPassword } = params;
const { insertScriptTags } = useInsertScriptTags({ const { insertScriptTags } = useInsertScriptTags({
componentOrHookName: "useUserProfileForm", componentOrHookName: "useUserProfileForm",
@ -122,7 +123,8 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
}, []); }, []);
const { getErrors } = useGetErrors({ const { getErrors } = useGetErrors({
kcContext kcContext,
i18n
}); });
const initialState = useMemo((): internal.State => { const initialState = useMemo((): internal.State => {
@ -523,12 +525,12 @@ type KcContextLike_useGetErrors = KcContextLike_i18n & {
assert<KcContextLike extends KcContextLike_useGetErrors ? true : false>(); assert<KcContextLike extends KcContextLike_useGetErrors ? true : false>();
function useGetErrors(params: { kcContext: KcContextLike_useGetErrors }) { function useGetErrors(params: { kcContext: KcContextLike_useGetErrors; i18n: I18n }) {
const { kcContext } = params; const { kcContext, i18n } = params;
const { messagesPerField, passwordPolicies } = kcContext; const { messagesPerField, passwordPolicies } = kcContext;
const { msg, msgStr, advancedMsg, advancedMsgStr } = useI18n({ kcContext }); const { msg, msgStr, advancedMsg, advancedMsgStr } = i18n;
const getErrors = useConstCallback( const getErrors = useConstCallback(
(params: { (params: {

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Code(props: PageProps<Extract<KcContext, { pageId: "code.ftl" }>>) { export default function Code(props: PageProps<Extract<KcContext, { pageId: "code.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,11 +13,12 @@ export default function Code(props: PageProps<Extract<KcContext, { pageId: "code
const { code } = kcContext; const { code } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
headerNode={code.success ? msg("codeSuccessTitle") : msg("codeErrorTitle", code.error)} headerNode={code.success ? msg("codeSuccessTitle") : msg("codeErrorTitle", code.error)}

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function DeleteAccountConfirm(props: PageProps<Extract<KcContext, { pageId: "delete-account-confirm.ftl" }>>) { export default function DeleteAccountConfirm(props: PageProps<Extract<KcContext, { pageId: "delete-account-confirm.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,10 +13,10 @@ export default function DeleteAccountConfirm(props: PageProps<Extract<KcContext,
const { url, triggered_from_aia } = kcContext; const { url, triggered_from_aia } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("deleteAccountConfirm")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("deleteAccountConfirm")}>
<form action={url.loginAction} className="form-vertical" method="post"> <form action={url.loginAction} className="form-vertical" method="post">
<div className="alert alert-warning" style={{ marginTop: "0", marginBottom: "30px" }}> <div className="alert alert-warning" style={{ marginTop: "0", marginBottom: "30px" }}>
<span className="pficon pficon-warning-triangle-o"></span> <span className="pficon pficon-warning-triangle-o"></span>

View File

@ -1,12 +1,12 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function DeleteCredential(props: PageProps<Extract<KcContext, { pageId: "delete-credential.ftl" }>>) { export default function DeleteCredential(props: PageProps<Extract<KcContext, { pageId: "delete-credential.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msgStr, msg } = useI18n({ kcContext }); const { msgStr, msg } = i18n;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -18,6 +18,7 @@ export default function DeleteCredential(props: PageProps<Extract<KcContext, { p
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={false} displayMessage={false}

View File

@ -1,16 +1,23 @@
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Error(props: PageProps<Extract<KcContext, { pageId: "error.ftl" }>>) { export default function Error(props: PageProps<Extract<KcContext, { pageId: "error.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { message, client, skipLink } = kcContext; const { message, client, skipLink } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} displayMessage={false} headerNode={msg("errorTitle")}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
displayMessage={false}
headerNode={msg("errorTitle")}
>
<div id="kc-error-message"> <div id="kc-error-message">
<p className="instruction">{message.summary}</p> <p className="instruction">{message.summary}</p>
{!skipLink && client !== undefined && client.baseUrl !== undefined && ( {!skipLink && client !== undefined && client.baseUrl !== undefined && (

View File

@ -1,14 +1,14 @@
import { useEffect } from "react"; import { useEffect } from "react";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function FrontchannelLogout(props: PageProps<Extract<KcContext, { pageId: "frontchannel-logout.ftl" }>>) { export default function FrontchannelLogout(props: PageProps<Extract<KcContext, { pageId: "frontchannel-logout.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { logout } = kcContext; const { logout } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
useEffect(() => { useEffect(() => {
if (logout.logoutRedirectUri) { if (logout.logoutRedirectUri) {
@ -19,6 +19,7 @@ export default function FrontchannelLogout(props: PageProps<Extract<KcContext, {
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
documentTitle={msgStr("frontchannel-logout.title")} documentTitle={msgStr("frontchannel-logout.title")}

View File

@ -4,22 +4,22 @@ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
type IdpReviewUserProfileProps = PageProps<Extract<KcContext, { pageId: "idp-review-user-profile.ftl" }>> & { type IdpReviewUserProfileProps = PageProps<Extract<KcContext, { pageId: "idp-review-user-profile.ftl" }>, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };
export default function IdpReviewUserProfile(props: IdpReviewUserProfileProps) { export default function IdpReviewUserProfile(props: IdpReviewUserProfileProps) {
const { kcContext, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
classes classes
}); });
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const { url, messagesPerField } = kcContext; const { url, messagesPerField } = kcContext;
@ -28,6 +28,7 @@ export default function IdpReviewUserProfile(props: IdpReviewUserProfileProps) {
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={messagesPerField.exists("global")} displayMessage={messagesPerField.exists("global")}
@ -37,6 +38,7 @@ export default function IdpReviewUserProfile(props: IdpReviewUserProfileProps) {
<form id="kc-idp-review-profile-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post"> <form id="kc-idp-review-profile-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
<UserProfileFormFields <UserProfileFormFields
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
onIsFormSubmittableValueChange={setIsFomSubmittable} onIsFormSubmittableValueChange={setIsFomSubmittable}
kcClsx={kcClsx} kcClsx={kcClsx}
doMakeUserConfirmPassword={doMakeUserConfirmPassword} doMakeUserConfirmPassword={doMakeUserConfirmPassword}

View File

@ -1,12 +1,12 @@
import { assert } from "keycloakify/tools/assert"; import { assert } from "keycloakify/tools/assert";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Info(props: PageProps<Extract<KcContext, { pageId: "info.ftl" }>>) { export default function Info(props: PageProps<Extract<KcContext, { pageId: "info.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msgStr, msg } = useI18n({ kcContext }); const { msgStr, msg } = i18n;
assert( assert(
kcContext.message !== undefined, kcContext.message !== undefined,
@ -18,6 +18,7 @@ export default function Info(props: PageProps<Extract<KcContext, { pageId: "info
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={false} displayMessage={false}

View File

@ -4,10 +4,10 @@ import { clsx } from "keycloakify/tools/clsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Login(props: PageProps<Extract<KcContext, { pageId: "login.ftl" }>>) { export default function Login(props: PageProps<Extract<KcContext, { pageId: "login.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -16,7 +16,6 @@ export default function Login(props: PageProps<Extract<KcContext, { pageId: "log
const { social, realm, url, usernameHidden, login, auth, registrationDisabled, messagesPerField } = kcContext; const { social, realm, url, usernameHidden, login, auth, registrationDisabled, messagesPerField } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
@ -24,6 +23,7 @@ export default function Login(props: PageProps<Extract<KcContext, { pageId: "log
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("username", "password")} displayMessage={!messagesPerField.existsError("username", "password")}

View File

@ -1,10 +1,10 @@
import { getKcClsx, KcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx, KcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pageId: "login-config-totp.ftl" }>>) { export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pageId: "login-config-totp.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,12 +13,10 @@ export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pa
const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext; const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr, advancedMsg } = i18n; const { msg, msgStr, advancedMsg } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("loginTotpTitle")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("loginTotpTitle")}>
<> <>
<ol id="kc-totp-settings"> <ol id="kc-totp-settings">
<li> <li>

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginIdpLinkConfirm(props: PageProps<Extract<KcContext, { pageId: "login-idp-link-confirm.ftl" }>>) { export default function LoginIdpLinkConfirm(props: PageProps<Extract<KcContext, { pageId: "login-idp-link-confirm.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,10 +13,10 @@ export default function LoginIdpLinkConfirm(props: PageProps<Extract<KcContext,
const { url, idpAlias } = kcContext; const { url, idpAlias } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("confirmLinkIdpTitle")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("confirmLinkIdpTitle")}>
<form id="kc-register-form" action={url.loginAction} method="post"> <form id="kc-register-form" action={url.loginAction} method="post">
<div className={kcClsx("kcFormGroupClass")}> <div className={kcClsx("kcFormGroupClass")}>
<button <button

View File

@ -1,16 +1,22 @@
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginIdpLinkEmail(props: PageProps<Extract<KcContext, { pageId: "login-idp-link-email.ftl" }>>) { export default function LoginIdpLinkEmail(props: PageProps<Extract<KcContext, { pageId: "login-idp-link-email.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { url, realm, brokerContext, idpAlias } = kcContext; const { url, realm, brokerContext, idpAlias } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("emailLinkIdpTitle", idpAlias)}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
headerNode={msg("emailLinkIdpTitle", idpAlias)}
>
<p id="instruction1" className="instruction"> <p id="instruction1" className="instruction">
{msg("emailLinkIdp1", idpAlias, brokerContext.username, realm.displayName)} {msg("emailLinkIdp1", idpAlias, brokerContext.username, realm.displayName)}
</p> </p>

View File

@ -1,15 +1,15 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import { PageProps } from "keycloakify/login/pages/PageProps"; import { PageProps } from "keycloakify/login/pages/PageProps";
import { KcContext } from "../KcContext"; import { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginOauth2DeviceVerifyUserCode( export default function LoginOauth2DeviceVerifyUserCode(
props: PageProps<Extract<KcContext, { pageId: "login-oauth2-device-verify-user-code.ftl" }>> props: PageProps<Extract<KcContext, { pageId: "login-oauth2-device-verify-user-code.ftl" }>, I18n>
) { ) {
const { kcContext, doUseDefaultCss, classes, Template } = props; const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
const { url } = kcContext; const { url } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -17,7 +17,13 @@ export default function LoginOauth2DeviceVerifyUserCode(
}); });
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("oauth2DeviceVerificationTitle")}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
headerNode={msg("oauth2DeviceVerificationTitle")}
>
<form <form
id="kc-user-verify-device-user-code-form" id="kc-user-verify-device-user-code-form"
className={kcClsx("kcFormClass")} className={kcClsx("kcFormClass")}

View File

@ -1,13 +1,13 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import { PageProps } from "keycloakify/login/pages/PageProps"; import { PageProps } from "keycloakify/login/pages/PageProps";
import { KcContext } from "../KcContext"; import { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginOauthGrant(props: PageProps<Extract<KcContext, { pageId: "login-oauth-grant.ftl" }>>) { export default function LoginOauthGrant(props: PageProps<Extract<KcContext, { pageId: "login-oauth-grant.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, classes, Template } = props; const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
const { url, oauth, client } = kcContext; const { url, oauth, client } = kcContext;
const { msg, msgStr, advancedMsg, advancedMsgStr } = useI18n({ kcContext }); const { msg, msgStr, advancedMsg, advancedMsgStr } = i18n;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -17,6 +17,7 @@ export default function LoginOauthGrant(props: PageProps<Extract<KcContext, { pa
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
bodyClassName="oauth" bodyClassName="oauth"

View File

@ -2,10 +2,10 @@ import { Fragment } from "react";
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "login-otp.ftl" }>>) { export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "login-otp.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -14,11 +14,12 @@ export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "
const { otpLogin, url, messagesPerField } = kcContext; const { otpLogin, url, messagesPerField } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("totp")} displayMessage={!messagesPerField.existsError("totp")}

View File

@ -1,16 +1,16 @@
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginPageExpired(props: PageProps<Extract<KcContext, { pageId: "login-page-expired.ftl" }>>) { export default function LoginPageExpired(props: PageProps<Extract<KcContext, { pageId: "login-page-expired.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { url } = kcContext; const { url } = kcContext;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("pageExpiredTitle")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("pageExpiredTitle")}>
<p id="instruction1" className="instruction"> <p id="instruction1" className="instruction">
{msg("pageExpiredMsg1")} {msg("pageExpiredMsg1")}
<a id="loginRestartLink" href={url.loginRestartFlowUrl}> <a id="loginRestartLink" href={url.loginRestartFlowUrl}>

View File

@ -4,10 +4,10 @@ import { assert } from "tsafe/assert";
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginPassword(props: PageProps<Extract<KcContext, { pageId: "login-password.ftl" }>>) { export default function LoginPassword(props: PageProps<Extract<KcContext, { pageId: "login-password.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -16,7 +16,6 @@ export default function LoginPassword(props: PageProps<Extract<KcContext, { page
const { realm, url, messagesPerField } = kcContext; const { realm, url, messagesPerField } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
@ -24,6 +23,7 @@ export default function LoginPassword(props: PageProps<Extract<KcContext, { page
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}

View File

@ -4,10 +4,10 @@ import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags"; import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-config.ftl" }>>) { export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-config.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -16,7 +16,6 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
const { recoveryAuthnCodesConfigBean, isAppInitiatedAction } = kcContext; const { recoveryAuthnCodesConfigBean, isAppInitiatedAction } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { insertScriptTags } = useInsertScriptTags({ const { insertScriptTags } = useInsertScriptTags({
@ -145,7 +144,13 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
}, []); }, []);
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("recovery-code-config-header")}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
headerNode={msg("recovery-code-config-header")}
>
<div className={clsx("pf-c-alert", "pf-m-warning", "pf-m-inline", kcClsx("kcRecoveryCodesWarning"))} aria-label="Warning alert"> <div className={clsx("pf-c-alert", "pf-m-warning", "pf-m-inline", kcClsx("kcRecoveryCodesWarning"))} aria-label="Warning alert">
<div className="pf-c-alert__icon"> <div className="pf-c-alert__icon">
<i className="pficon-warning-triangle-o" aria-hidden="true" /> <i className="pficon-warning-triangle-o" aria-hidden="true" />

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginRecoveryAuthnCodeInput(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-input.ftl" }>>) { export default function LoginRecoveryAuthnCodeInput(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-input.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,11 +13,12 @@ export default function LoginRecoveryAuthnCodeInput(props: PageProps<Extract<KcC
const { url, messagesPerField, recoveryAuthnCodesInputBean } = kcContext; const { url, messagesPerField, recoveryAuthnCodesInputBean } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
headerNode={msg("auth-recovery-code-header")} headerNode={msg("auth-recovery-code-header")}

View File

@ -2,10 +2,10 @@ import { Fragment } from "react";
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginResetOtp(props: PageProps<Extract<KcContext, { pageId: "login-reset-otp.ftl" }>>) { export default function LoginResetOtp(props: PageProps<Extract<KcContext, { pageId: "login-reset-otp.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -14,11 +14,12 @@ export default function LoginResetOtp(props: PageProps<Extract<KcContext, { page
const { url, messagesPerField, configuredOtpCredentials } = kcContext; const { url, messagesPerField, configuredOtpCredentials } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("totp")} displayMessage={!messagesPerField.existsError("totp")}

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginResetPassword(props: PageProps<Extract<KcContext, { pageId: "login-reset-password.ftl" }>>) { export default function LoginResetPassword(props: PageProps<Extract<KcContext, { pageId: "login-reset-password.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,11 +13,12 @@ export default function LoginResetPassword(props: PageProps<Extract<KcContext, {
const { url, realm, auth, messagesPerField } = kcContext; const { url, realm, auth, messagesPerField } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayInfo displayInfo

View File

@ -3,17 +3,16 @@ import { assert } from "tsafe/assert";
import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginUpdatePassword(props: PageProps<Extract<KcContext, { pageId: "login-update-password.ftl" }>>) { export default function LoginUpdatePassword(props: PageProps<Extract<KcContext, { pageId: "login-update-password.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
classes classes
}); });
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { url, messagesPerField, isAppInitiatedAction } = kcContext; const { url, messagesPerField, isAppInitiatedAction } = kcContext;
@ -21,6 +20,7 @@ export default function LoginUpdatePassword(props: PageProps<Extract<KcContext,
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("password", "password-confirm")} displayMessage={!messagesPerField.existsError("password", "password-confirm")}

View File

@ -4,15 +4,15 @@ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
type LoginUpdateProfileProps = PageProps<Extract<KcContext, { pageId: "login-update-profile.ftl" }>> & { type LoginUpdateProfileProps = PageProps<Extract<KcContext, { pageId: "login-update-profile.ftl" }>, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };
export default function LoginUpdateProfile(props: LoginUpdateProfileProps) { export default function LoginUpdateProfile(props: LoginUpdateProfileProps) {
const { kcContext, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -21,13 +21,14 @@ export default function LoginUpdateProfile(props: LoginUpdateProfileProps) {
const { url, isAppInitiatedAction } = kcContext; const { url, isAppInitiatedAction } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const [isFormSubmittable, setIsFormSubmittable] = useState(false); const [isFormSubmittable, setIsFormSubmittable] = useState(false);
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayRequiredFields displayRequiredFields
@ -36,6 +37,7 @@ export default function LoginUpdateProfile(props: LoginUpdateProfileProps) {
<form id="kc-update-profile-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post"> <form id="kc-update-profile-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
<UserProfileFormFields <UserProfileFormFields
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
kcClsx={kcClsx} kcClsx={kcClsx}
onIsFormSubmittableValueChange={setIsFormSubmittable} onIsFormSubmittableValueChange={setIsFormSubmittable}
doMakeUserConfirmPassword={doMakeUserConfirmPassword} doMakeUserConfirmPassword={doMakeUserConfirmPassword}

View File

@ -3,10 +3,10 @@ import { clsx } from "keycloakify/tools/clsx";
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginUsername(props: PageProps<Extract<KcContext, { pageId: "login-username.ftl" }>>) { export default function LoginUsername(props: PageProps<Extract<KcContext, { pageId: "login-username.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -15,13 +15,14 @@ export default function LoginUsername(props: PageProps<Extract<KcContext, { page
const { social, realm, url, usernameHidden, login, registrationDisabled, messagesPerField } = kcContext; const { social, realm, url, usernameHidden, login, registrationDisabled, messagesPerField } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("username")} displayMessage={!messagesPerField.existsError("username")}

View File

@ -1,17 +1,18 @@
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginVerifyEmail(props: PageProps<Extract<KcContext, { pageId: "login-verify-email.ftl" }>>) { export default function LoginVerifyEmail(props: PageProps<Extract<KcContext, { pageId: "login-verify-email.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
const { url, user } = kcContext; const { url, user } = kcContext;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayInfo displayInfo

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LoginX509Info(props: PageProps<Extract<KcContext, { pageId: "login-x509-info.ftl" }>>) { export default function LoginX509Info(props: PageProps<Extract<KcContext, { pageId: "login-x509-info.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,10 +13,10 @@ export default function LoginX509Info(props: PageProps<Extract<KcContext, { page
const { url, x509 } = kcContext; const { url, x509 } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("doLogIn")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("doLogIn")}>
<form id="kc-x509-login-info" className={kcClsx("kcFormClass")} action={url.loginAction} method="post"> <form id="kc-x509-login-info" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
<div className={kcClsx("kcFormGroupClass")}> <div className={kcClsx("kcFormGroupClass")}>
<div className={kcClsx("kcLabelWrapperClass")}> <div className={kcClsx("kcLabelWrapperClass")}>

View File

@ -1,10 +1,10 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function LogoutConfirm(props: PageProps<Extract<KcContext, { pageId: "logout-confirm.ftl" }>>) { export default function LogoutConfirm(props: PageProps<Extract<KcContext, { pageId: "logout-confirm.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -13,10 +13,10 @@ export default function LogoutConfirm(props: PageProps<Extract<KcContext, { page
const { url, client, logoutConfirm } = kcContext; const { url, client, logoutConfirm } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("logoutConfirmTitle")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("logoutConfirmTitle")}>
<div id="kc-logout-confirm" className="content-area"> <div id="kc-logout-confirm" className="content-area">
<p className="instruction">{msg("logoutConfirmHeader")}</p> <p className="instruction">{msg("logoutConfirmHeader")}</p>
<form className="form-actions" action={url.logoutConfirmAction} method="POST"> <form className="form-actions" action={url.logoutConfirmAction} method="POST">

View File

@ -1,10 +1,10 @@
import { type TemplateProps, type ClassKey } from "keycloakify/login/TemplateProps"; import { type TemplateProps, type ClassKey } from "keycloakify/login/TemplateProps";
import type { LazyOrNot } from "keycloakify/tools/LazyOrNot"; import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
import type { KcContext } from "keycloakify/account/KcContext";
export type PageProps<NarowedKcContext = KcContext> = { export type PageProps<NarrowedKcContext, I18n> = {
Template: LazyOrNot<(props: TemplateProps<any>) => JSX.Element | null>; Template: LazyOrNot<(props: TemplateProps<any, any>) => JSX.Element | null>;
kcContext: NarowedKcContext; kcContext: NarrowedKcContext;
i18n: I18n;
doUseDefaultCss: boolean; doUseDefaultCss: boolean;
classes?: Partial<Record<ClassKey, string>>; classes?: Partial<Record<ClassKey, string>>;
}; };

View File

@ -6,15 +6,15 @@ import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
type RegisterProps = PageProps<Extract<KcContext, { pageId: "register.ftl" }>> & { type RegisterProps = PageProps<Extract<KcContext, { pageId: "register.ftl" }>, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };
export default function Register(props: RegisterProps) { export default function Register(props: RegisterProps) {
const { kcContext, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -23,16 +23,23 @@ export default function Register(props: RegisterProps) {
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey, termsAcceptanceRequired } = kcContext; const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey, termsAcceptanceRequired } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const [isFormSubmittable, setIsFormSubmittable] = useState(false); const [isFormSubmittable, setIsFormSubmittable] = useState(false);
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("registerTitle")} displayRequiredFields> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
headerNode={msg("registerTitle")}
displayRequiredFields
>
<form id="kc-register-form" className={kcClsx("kcFormClass")} action={url.registrationAction} method="post"> <form id="kc-register-form" className={kcClsx("kcFormClass")} action={url.registrationAction} method="post">
<UserProfileFormFields <UserProfileFormFields
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
kcClsx={kcClsx} kcClsx={kcClsx}
onIsFormSubmittableValueChange={setIsFormSubmittable} onIsFormSubmittableValueChange={setIsFormSubmittable}
doMakeUserConfirmPassword={doMakeUserConfirmPassword} doMakeUserConfirmPassword={doMakeUserConfirmPassword}

View File

@ -1,12 +1,12 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function SamlPostForm(props: PageProps<Extract<KcContext, { pageId: "saml-post-form.ftl" }>>) { export default function SamlPostForm(props: PageProps<Extract<KcContext, { pageId: "saml-post-form.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msgStr, msg } = useI18n({ kcContext }); const { msgStr, msg } = i18n;
const { samlPost } = kcContext; const { samlPost } = kcContext;
@ -26,7 +26,7 @@ export default function SamlPostForm(props: PageProps<Extract<KcContext, { pageI
htmlFormElement.submit(); htmlFormElement.submit();
}, [htmlFormElement]); }, [htmlFormElement]);
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("saml.post-form.title")}> <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={msg("saml.post-form.title")}>
<p>{msg("saml.post-form.message")}</p> <p>{msg("saml.post-form.message")}</p>
<form name="saml-post-binding" method="post" action={samlPost.url} ref={setHtmlFormElement}> <form name="saml-post-binding" method="post" action={samlPost.url} ref={setHtmlFormElement}>
{samlPost.SAMLRequest && <input type="hidden" name="SAMLRequest" value={samlPost.SAMLRequest} />} {samlPost.SAMLRequest && <input type="hidden" name="SAMLRequest" value={samlPost.SAMLRequest} />}

View File

@ -1,18 +1,19 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function SelectAuthenticator(props: PageProps<Extract<KcContext, { pageId: "select-authenticator.ftl" }>>) { export default function SelectAuthenticator(props: PageProps<Extract<KcContext, { pageId: "select-authenticator.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { url, auth } = kcContext; const { url, auth } = kcContext;
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes }); const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
const { msg } = useI18n({ kcContext }); const { msg } = i18n;
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayInfo={false} displayInfo={false}

View File

@ -3,17 +3,17 @@ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import { useTermsMarkdown } from "keycloakify/login/lib/useDownloadTerms"; import { useTermsMarkdown } from "keycloakify/login/lib/useDownloadTerms";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function Terms(props: PageProps<Extract<KcContext, { pageId: "terms.ftl" }>>) { export default function Terms(props: PageProps<Extract<KcContext, { pageId: "terms.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
classes classes
}); });
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const { locale, url } = kcContext; const { locale, url } = kcContext;
@ -24,7 +24,14 @@ export default function Terms(props: PageProps<Extract<KcContext, { pageId: "ter
} }
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} displayMessage={false} headerNode={msg("termsTitle")}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
displayMessage={false}
headerNode={msg("termsTitle")}
>
<div id="kc-terms-text" lang={termsLanguageTag !== locale?.currentLanguageTag ? termsLanguageTag : undefined}> <div id="kc-terms-text" lang={termsLanguageTag !== locale?.currentLanguageTag ? termsLanguageTag : undefined}>
<Markdown>{termsMarkdown}</Markdown> <Markdown>{termsMarkdown}</Markdown>
</div> </div>

View File

@ -4,22 +4,21 @@ import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields"; import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
type UpdateEmailProps = PageProps<Extract<KcContext, { pageId: "update-email.ftl" }>> & { type UpdateEmailProps = PageProps<Extract<KcContext, { pageId: "update-email.ftl" }>, I18n> & {
UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>; UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
doMakeUserConfirmPassword: boolean; doMakeUserConfirmPassword: boolean;
}; };
export default function UpdateEmail(props: UpdateEmailProps) { export default function UpdateEmail(props: UpdateEmailProps) {
const { kcContext, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes, UserProfileFormFields, doMakeUserConfirmPassword } = props;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
classes classes
}); });
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const [isFormSubmittable, setIsFormSubmittable] = useState(false); const [isFormSubmittable, setIsFormSubmittable] = useState(false);
@ -29,6 +28,7 @@ export default function UpdateEmail(props: UpdateEmailProps) {
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={messagesPerField.exists("global")} displayMessage={messagesPerField.exists("global")}
@ -38,6 +38,7 @@ export default function UpdateEmail(props: UpdateEmailProps) {
<form id="kc-update-email-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post"> <form id="kc-update-email-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
<UserProfileFormFields <UserProfileFormFields
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
kcClsx={kcClsx} kcClsx={kcClsx}
onIsFormSubmittableValueChange={setIsFormSubmittable} onIsFormSubmittableValueChange={setIsFormSubmittable}
doMakeUserConfirmPassword={doMakeUserConfirmPassword} doMakeUserConfirmPassword={doMakeUserConfirmPassword}

View File

@ -5,10 +5,10 @@ import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext, { pageId: "webauthn-authenticate.ftl" }>>) { export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext, { pageId: "webauthn-authenticate.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes }); const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
@ -26,7 +26,7 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
shouldDisplayAuthenticators shouldDisplayAuthenticators
} = kcContext; } = kcContext;
const { msg, msgStr, advancedMsg } = useI18n({ kcContext }); const { msg, msgStr, advancedMsg } = i18n;
const { insertScriptTags } = useInsertScriptTags({ const { insertScriptTags } = useInsertScriptTags({
componentOrHookName: "WebauthnAuthenticate", componentOrHookName: "WebauthnAuthenticate",
@ -137,6 +137,7 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
displayMessage={!messagesPerField.existsError("username")} displayMessage={!messagesPerField.existsError("username")}

View File

@ -1,14 +1,14 @@
import { getKcClsx } from "keycloakify/login/lib/kcClsx"; import { getKcClsx } from "keycloakify/login/lib/kcClsx";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n } from "../i18n"; import type { I18n } from "../i18n";
export default function WebauthnError(props: PageProps<Extract<KcContext, { pageId: "webauthn-error.ftl" }>>) { export default function WebauthnError(props: PageProps<Extract<KcContext, { pageId: "webauthn-error.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { url, isAppInitiatedAction } = kcContext; const { url, isAppInitiatedAction } = kcContext;
const { msg, msgStr } = useI18n({ kcContext }); const { msg, msgStr } = i18n;
const { kcClsx } = getKcClsx({ const { kcClsx } = getKcClsx({
doUseDefaultCss, doUseDefaultCss,
@ -16,7 +16,14 @@ export default function WebauthnError(props: PageProps<Extract<KcContext, { page
}); });
return ( return (
<Template kcContext={kcContext} doUseDefaultCss={doUseDefaultCss} classes={classes} displayMessage headerNode={msg("webauthn-error-title")}> <Template
kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss}
classes={classes}
displayMessage
headerNode={msg("webauthn-error-title")}
>
<form id="kc-error-credential-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post"> <form id="kc-error-credential-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
<input type="hidden" id="executionValue" name="authenticationExecution" /> <input type="hidden" id="executionValue" name="authenticationExecution" />
<input type="hidden" id="isSetRetry" name="isSetRetry" /> <input type="hidden" id="isSetRetry" name="isSetRetry" />

View File

@ -4,10 +4,10 @@ import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags"; import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
import type { PageProps } from "keycloakify/login/pages/PageProps"; import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext"; import type { KcContext } from "../KcContext";
import { useI18n, type I18n } from "../i18n"; import type { I18n } from "../i18n";
export default function WebauthnRegister(props: PageProps<Extract<KcContext, { pageId: "webauthn-register.ftl" }>>) { export default function WebauthnRegister(props: PageProps<Extract<KcContext, { pageId: "webauthn-register.ftl" }>, I18n>) {
const { kcContext, doUseDefaultCss, Template, classes } = props; const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes }); const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
@ -29,7 +29,6 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
isAppInitiatedAction isAppInitiatedAction
} = kcContext; } = kcContext;
const i18n = useI18n({ kcContext });
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { insertScriptTags } = useInsertScriptTags({ const { insertScriptTags } = useInsertScriptTags({
@ -207,6 +206,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
return ( return (
<Template <Template
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
doUseDefaultCss={doUseDefaultCss} doUseDefaultCss={doUseDefaultCss}
classes={classes} classes={classes}
headerNode={ headerNode={

View File

@ -1,10 +1,13 @@
import React from "react"; import React from "react";
import Fallback from "../../dist/account/Fallback"; import Fallback from "../../dist/account/Fallback";
import { useI18n } from "./i18n";
import type { KcContext } from "./KcContext"; import type { KcContext } from "./KcContext";
import Template from "../../dist/account/Template"; import Template from "../../dist/account/Template";
export default function KcApp(props: { kcContext: KcContext }) { export default function KcApp(props: { kcContext: KcContext }) {
const { kcContext } = props; const { kcContext } = props;
return <Fallback kcContext={kcContext} Template={Template} doUseDefaultCss={true} />; const { i18n } = useI18n({ kcContext });
return <Fallback kcContext={kcContext} i18n={i18n} Template={Template} doUseDefaultCss={true} />;
} }

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import Fallback from "../../dist/login/Fallback"; import Fallback from "../../dist/login/Fallback";
import type { KcContext } from "./KcContext"; import type { KcContext } from "./KcContext";
import { useI18n } from "./i18n";
import { useDownloadTerms } from "../../dist/login/lib/useDownloadTerms"; import { useDownloadTerms } from "../../dist/login/lib/useDownloadTerms";
import Template from "../../dist/login/Template"; import Template from "../../dist/login/Template";
import UserProfileFormFields from "../../dist/login/UserProfileFormFields"; import UserProfileFormFields from "../../dist/login/UserProfileFormFields";
@ -8,6 +9,8 @@ import UserProfileFormFields from "../../dist/login/UserProfileFormFields";
export default function KcApp(props: { kcContext: KcContext }) { export default function KcApp(props: { kcContext: KcContext }) {
const { kcContext } = props; const { kcContext } = props;
const { i18n } = useI18n({ kcContext });
useDownloadTerms({ useDownloadTerms({
kcContext, kcContext,
downloadTermsMarkdown: async ({ currentLanguageTag }) => { downloadTermsMarkdown: async ({ currentLanguageTag }) => {
@ -36,6 +39,7 @@ export default function KcApp(props: { kcContext: KcContext }) {
return ( return (
<Fallback <Fallback
kcContext={kcContext} kcContext={kcContext}
i18n={i18n}
Template={Template} Template={Template}
doUseDefaultCss={true} doUseDefaultCss={true}
UserProfileFormFields={UserProfileFormFields} UserProfileFormFields={UserProfileFormFields}