Fix language menu select in templates
This commit is contained in:
parent
3a8f1a0ed1
commit
e962b37948
@ -15,7 +15,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
|||||||
|
|
||||||
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
||||||
|
|
||||||
const { msg, msgStr, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
|
const { msg, msgStr, getChangeLocalUrl, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
|
||||||
|
|
||||||
const { locale, url, features, realm, message, referrer } = kcContext;
|
const { locale, url, features, realm, message, referrer } = kcContext;
|
||||||
|
|
||||||
@ -81,10 +81,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
|||||||
<ul>
|
<ul>
|
||||||
{locale.supported.map(({ languageTag }) => (
|
{locale.supported.map(({ languageTag }) => (
|
||||||
<li key={languageTag} className="kc-dropdown-item">
|
<li key={languageTag} className="kc-dropdown-item">
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
<a href={getChangeLocalUrl(languageTag)}>{labelBySupportedLanguageTag[languageTag]}</a>
|
||||||
<a href="#" onClick={() => changeLocale(languageTag)}>
|
|
||||||
{labelBySupportedLanguageTag[languageTag]}
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -28,11 +28,10 @@ export type GenericI18n<MessageKey extends string> = {
|
|||||||
*/
|
*/
|
||||||
currentLanguageTag: string;
|
currentLanguageTag: string;
|
||||||
/**
|
/**
|
||||||
* To call when the user switch language.
|
* Redirect to this url to change the language.
|
||||||
* This will cause the page to be reloaded,
|
* After reload currentLanguageTag === newLanguageTag
|
||||||
* on next load currentLanguageTag === newLanguageTag
|
|
||||||
*/
|
*/
|
||||||
changeLocale: (newLanguageTag: string) => never;
|
getChangeLocalUrl: (newLanguageTag: string) => string;
|
||||||
/**
|
/**
|
||||||
* e.g. "en" => "English", "fr" => "Français", ...
|
* e.g. "en" => "English", "fr" => "Français", ...
|
||||||
*
|
*
|
||||||
@ -104,7 +103,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
} as any
|
} as any
|
||||||
}),
|
}),
|
||||||
currentLanguageTag,
|
currentLanguageTag,
|
||||||
"changeLocale": newLanguageTag => {
|
"getChangeLocalUrl": newLanguageTag => {
|
||||||
const { locale } = kcContext;
|
const { locale } = kcContext;
|
||||||
|
|
||||||
assert(locale !== undefined, "Internationalization not enabled");
|
assert(locale !== undefined, "Internationalization not enabled");
|
||||||
@ -113,9 +112,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
|
|
||||||
assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
|
assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
|
||||||
|
|
||||||
window.location.href = targetSupportedLocale.url;
|
return targetSupportedLocale.url;
|
||||||
|
|
||||||
assert(false, "never");
|
|
||||||
},
|
},
|
||||||
"labelBySupportedLanguageTag": Object.fromEntries(
|
"labelBySupportedLanguageTag": Object.fromEntries(
|
||||||
(kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
|
(kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
|
||||||
|
@ -32,7 +32,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
|||||||
|
|
||||||
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
||||||
|
|
||||||
const { msg, msgStr, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
|
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;
|
||||||
|
|
||||||
@ -126,31 +126,17 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
|||||||
|
|
||||||
<div className={getClassName("kcFormCardClass")}>
|
<div className={getClassName("kcFormCardClass")}>
|
||||||
<header className={getClassName("kcFormHeaderClass")}>
|
<header className={getClassName("kcFormHeaderClass")}>
|
||||||
{realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && (
|
{realm.internationalizationEnabled && (assert(locale !== undefined), locale.supported.length > 1) && (
|
||||||
<div className={getClassName("kcLocaleMainClass")} id="kc-locale">
|
<div className={getClassName("kcLocaleMainClass")} id="kc-locale">
|
||||||
<div id="kc-locale-wrapper" className={getClassName("kcLocaleWrapperClass")}>
|
<div id="kc-locale-wrapper" className={getClassName("kcLocaleWrapperClass")}>
|
||||||
<div id="kc-locale-dropdown" className={clsx("menu-button-links", getClassName("kcLocaleDropDownClass"))}>
|
<div id="kc-locale-dropdown" className={clsx("menu-button-links", getClassName("kcLocaleDropDownClass"))}>
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
||||||
<a href="#" id="kc-current-locale-link">
|
|
||||||
{labelBySupportedLanguageTag[currentLanguageTag]}
|
|
||||||
</a>
|
|
||||||
<ul>
|
|
||||||
{locale.supported.map(({ languageTag }) => (
|
|
||||||
<li key={languageTag} className="kc-dropdown-item">
|
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
||||||
<a href="#" onClick={() => changeLocale(languageTag)}>
|
|
||||||
{labelBySupportedLanguageTag[languageTag]}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
id="kc-current-locale-link"
|
id="kc-current-locale-link"
|
||||||
aria-label={msgStr("languages" as any)}
|
aria-label={msgStr("languages" as any)}
|
||||||
aria-haspopup={true}
|
aria-haspopup="true"
|
||||||
aria-expanded={false}
|
aria-expanded="false"
|
||||||
aria-controls="language-switch1"
|
aria-controls="language-switch1"
|
||||||
>
|
>
|
||||||
{labelBySupportedLanguageTag[currentLanguageTag]}
|
{labelBySupportedLanguageTag[currentLanguageTag]}
|
||||||
@ -165,13 +151,11 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
|||||||
>
|
>
|
||||||
{locale.supported.map(({ languageTag }, i) => (
|
{locale.supported.map(({ languageTag }, i) => (
|
||||||
<li key={languageTag} className={getClassName("kcLocaleListItemClass")} role="none">
|
<li key={languageTag} className={getClassName("kcLocaleListItemClass")} role="none">
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
||||||
<a
|
<a
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
id={`language-${i}`}
|
id={`language-${i + 1}`}
|
||||||
className={getClassName("kcLocaleItemClass")}
|
className={getClassName("kcLocaleItemClass")}
|
||||||
href="#"
|
href={getChangeLocalUrl(languageTag)}
|
||||||
onClick={() => changeLocale(languageTag)}
|
|
||||||
>
|
>
|
||||||
{labelBySupportedLanguageTag[languageTag]}
|
{labelBySupportedLanguageTag[languageTag]}
|
||||||
</a>
|
</a>
|
||||||
|
@ -28,11 +28,10 @@ export type GenericI18n<MessageKey extends string> = {
|
|||||||
*/
|
*/
|
||||||
currentLanguageTag: string;
|
currentLanguageTag: string;
|
||||||
/**
|
/**
|
||||||
* To call when the user switch language.
|
* Redirect to this url to change the language.
|
||||||
* This will cause the page to be reloaded,
|
* After reload currentLanguageTag === newLanguageTag
|
||||||
* on next load currentLanguageTag === newLanguageTag
|
|
||||||
*/
|
*/
|
||||||
changeLocale: (newLanguageTag: string) => never;
|
getChangeLocalUrl: (newLanguageTag: string) => string;
|
||||||
/**
|
/**
|
||||||
* e.g. "en" => "English", "fr" => "Français", ...
|
* e.g. "en" => "English", "fr" => "Français", ...
|
||||||
*
|
*
|
||||||
@ -104,7 +103,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
} as any
|
} as any
|
||||||
}),
|
}),
|
||||||
currentLanguageTag,
|
currentLanguageTag,
|
||||||
"changeLocale": newLanguageTag => {
|
"getChangeLocalUrl": newLanguageTag => {
|
||||||
const { locale } = kcContext;
|
const { locale } = kcContext;
|
||||||
|
|
||||||
assert(locale !== undefined, "Internationalization not enabled");
|
assert(locale !== undefined, "Internationalization not enabled");
|
||||||
@ -113,9 +112,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
|
|
||||||
assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
|
assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
|
||||||
|
|
||||||
window.location.href = targetSupportedLocale.url;
|
return targetSupportedLocale.url;
|
||||||
|
|
||||||
assert(false, "never");
|
|
||||||
},
|
},
|
||||||
"labelBySupportedLanguageTag": Object.fromEntries(
|
"labelBySupportedLanguageTag": Object.fromEntries(
|
||||||
(kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
|
(kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
|
||||||
|
169
src/login/template.ftl
Normal file
169
src/login/template.ftl
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true displayRequiredFields=false>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="${properties.kcHtmlClass!}"<#if realm.internationalizationEnabled> lang="${locale.currentLanguageTag}"</#if>>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="robots" content="noindex, nofollow">
|
||||||
|
|
||||||
|
<#if properties.meta?has_content>
|
||||||
|
<#list properties.meta?split(' ') as meta>
|
||||||
|
<meta name="${meta?split('==')[0]}" content="${meta?split('==')[1]}"/>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<title>${msg("loginTitle",(realm.displayName!''))}</title>
|
||||||
|
<link rel="icon" href="${url.resourcesPath}/img/favicon.ico" />
|
||||||
|
<#if properties.stylesCommon?has_content>
|
||||||
|
<#list properties.stylesCommon?split(' ') as style>
|
||||||
|
<link href="${url.resourcesCommonPath}/${style}" rel="stylesheet" />
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if properties.styles?has_content>
|
||||||
|
<#list properties.styles?split(' ') as style>
|
||||||
|
<link href="${url.resourcesPath}/${style}" rel="stylesheet" />
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if properties.scripts?has_content>
|
||||||
|
<#list properties.scripts?split(' ') as script>
|
||||||
|
<script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<script src="${url.resourcesPath}/js/menu-button-links.js" type="module"></script>
|
||||||
|
<#if scripts??>
|
||||||
|
<#list scripts as script>
|
||||||
|
<script src="${script}" type="text/javascript"></script>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#if authenticationSession??>
|
||||||
|
<script type="module">
|
||||||
|
import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";
|
||||||
|
|
||||||
|
checkCookiesAndSetTimer(
|
||||||
|
"${authenticationSession.authSessionId}",
|
||||||
|
"${authenticationSession.tabId}",
|
||||||
|
"${url.ssoLoginInOtherTabsUrl?no_esc}"
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</#if>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="${properties.kcBodyClass!}">
|
||||||
|
<div class="${properties.kcLoginClass!}">
|
||||||
|
<div id="kc-header" class="${properties.kcHeaderClass!}">
|
||||||
|
<div id="kc-header-wrapper"
|
||||||
|
class="${properties.kcHeaderWrapperClass!}">${kcSanitize(msg("loginTitleHtml",(realm.displayNameHtml!'')))?no_esc}</div>
|
||||||
|
</div>
|
||||||
|
<div class="${properties.kcFormCardClass!}">
|
||||||
|
<header class="${properties.kcFormHeaderClass!}">
|
||||||
|
<#if realm.internationalizationEnabled && locale.supported?size gt 1>
|
||||||
|
<div class="${properties.kcLocaleMainClass!}" id="kc-locale">
|
||||||
|
<div id="kc-locale-wrapper" class="${properties.kcLocaleWrapperClass!}">
|
||||||
|
<div id="kc-locale-dropdown" class="menu-button-links ${properties.kcLocaleDropDownClass!}">
|
||||||
|
<button tabindex="1" id="kc-current-locale-link" aria-label="${msg("languages")}" aria-haspopup="true"
|
||||||
|
aria-expanded="false" aria-controls="language-switch1">${locale.current}</button>
|
||||||
|
<ul role="menu" tabindex="-1" aria-labelledby="kc-current-locale-link" aria-activedescendant="" id="language-switch1" class="${properties.kcLocaleListClass!}">
|
||||||
|
<#assign i = 1>
|
||||||
|
<#list locale.supported as l>
|
||||||
|
<li class="${properties.kcLocaleListItemClass!}" role="none">
|
||||||
|
<a role="menuitem" id="language-${i}" class="${properties.kcLocaleItemClass!}" href="${l.url}">${l.label}</a>
|
||||||
|
</li>
|
||||||
|
<#assign i++>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
<#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())>
|
||||||
|
<#if displayRequiredFields>
|
||||||
|
<div class="${properties.kcContentWrapperClass!}">
|
||||||
|
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||||
|
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<h1 id="kc-page-title"><#nested "header"></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<#else>
|
||||||
|
<h1 id="kc-page-title"><#nested "header"></h1>
|
||||||
|
</#if>
|
||||||
|
<#else>
|
||||||
|
<#if displayRequiredFields>
|
||||||
|
<div class="${properties.kcContentWrapperClass!}">
|
||||||
|
<div class="${properties.kcLabelWrapperClass!} subtitle">
|
||||||
|
<span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<#nested "show-username">
|
||||||
|
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||||
|
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||||
|
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||||
|
<div class="kc-login-tooltip">
|
||||||
|
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||||
|
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<#else>
|
||||||
|
<#nested "show-username">
|
||||||
|
<div id="kc-username" class="${properties.kcFormGroupClass!}">
|
||||||
|
<label id="kc-attempted-username">${auth.attemptedUsername}</label>
|
||||||
|
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}">
|
||||||
|
<div class="kc-login-tooltip">
|
||||||
|
<i class="${properties.kcResetFlowIcon!}"></i>
|
||||||
|
<span class="kc-tooltip-text">${msg("restartLoginTooltip")}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</header>
|
||||||
|
<div id="kc-content">
|
||||||
|
<div id="kc-content-wrapper">
|
||||||
|
|
||||||
|
<#-- App-initiated actions should not see warning messages about the need to complete the action -->
|
||||||
|
<#-- during login. -->
|
||||||
|
<#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)>
|
||||||
|
<div class="alert-${message.type} ${properties.kcAlertClass!} pf-m-<#if message.type = 'error'>danger<#else>${message.type}</#if>">
|
||||||
|
<div class="pf-c-alert__icon">
|
||||||
|
<#if message.type = 'success'><span class="${properties.kcFeedbackSuccessIcon!}"></span></#if>
|
||||||
|
<#if message.type = 'warning'><span class="${properties.kcFeedbackWarningIcon!}"></span></#if>
|
||||||
|
<#if message.type = 'error'><span class="${properties.kcFeedbackErrorIcon!}"></span></#if>
|
||||||
|
<#if message.type = 'info'><span class="${properties.kcFeedbackInfoIcon!}"></span></#if>
|
||||||
|
</div>
|
||||||
|
<span class="${properties.kcAlertTitleClass!}">${kcSanitize(message.summary)?no_esc}</span>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#nested "form">
|
||||||
|
|
||||||
|
<#if auth?has_content && auth.showTryAnotherWayLink()>
|
||||||
|
<form id="kc-select-try-another-way-form" action="${url.loginAction}" method="post">
|
||||||
|
<div class="${properties.kcFormGroupClass!}">
|
||||||
|
<input type="hidden" name="tryAnotherWay" value="on"/>
|
||||||
|
<a href="#" id="try-another-way"
|
||||||
|
onclick="document.forms['kc-select-try-another-way-form'].submit();return false;">${msg("doTryAnotherWay")}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#nested "socialProviders">
|
||||||
|
|
||||||
|
<#if displayInfo>
|
||||||
|
<div id="kc-info" class="${properties.kcSignUpClass!}">
|
||||||
|
<div id="kc-info-wrapper" class="${properties.kcInfoAreaWrapperClass!}">
|
||||||
|
<#nested "info">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</#macro>
|
Loading…
x
Reference in New Issue
Block a user