KEYCLOAK-7123: l10n dropdowns (#5170)
* KEYCLOAK-7196: Add kc_locale to keycloak.js * KEYCLOAK-7123: Localization dropdowns * Update keycloak-service to latest keycloak.js
This commit is contained in:
parent
fe2ae6ec68
commit
35154db50f
8 changed files with 577 additions and 534 deletions
|
@ -89,9 +89,7 @@ public class AccountConsole {
|
||||||
|
|
||||||
map.put("authUrl", session.getContext().getContextPath());
|
map.put("authUrl", session.getContext().getContextPath());
|
||||||
map.put("baseUrl", session.getContext().getContextPath() + "/realms/" + realm.getName() + "/account");
|
map.put("baseUrl", session.getContext().getContextPath() + "/realms/" + realm.getName() + "/account");
|
||||||
map.put("realm", realm.getName());
|
map.put("realm", realm);
|
||||||
map.put("isRegistrationEmailAsUsername", realm.isRegistrationEmailAsUsername());
|
|
||||||
map.put("isEditUserNameAllowed", realm.isEditUsernameAllowed());
|
|
||||||
map.put("resourceUrl", Urls.themeRoot(baseUri).getPath() + "/account/" + theme.getName());
|
map.put("resourceUrl", Urls.themeRoot(baseUri).getPath() + "/account/" + theme.getName());
|
||||||
map.put("resourceVersion", Version.RESOURCES_VERSION);
|
map.put("resourceVersion", Version.RESOURCES_VERSION);
|
||||||
|
|
||||||
|
@ -108,7 +106,7 @@ public class AccountConsole {
|
||||||
Properties messages = theme.getMessages(locale);
|
Properties messages = theme.getMessages(locale);
|
||||||
map.put("msg", new MessageFormatterMethod(locale, messages));
|
map.put("msg", new MessageFormatterMethod(locale, messages));
|
||||||
map.put("msgJSON", messagesToJsonString(messages));
|
map.put("msgJSON", messagesToJsonString(messages));
|
||||||
|
map.put("supportedLocales", supportedLocales(messages));
|
||||||
map.put("properties", theme.getProperties());
|
map.put("properties", theme.getProperties());
|
||||||
|
|
||||||
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
|
||||||
|
@ -119,6 +117,15 @@ public class AccountConsole {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> supportedLocales(Properties messages) throws IOException {
|
||||||
|
Map<String, String> supportedLocales = new HashMap<>();
|
||||||
|
for (String l : realm.getSupportedLocales()) {
|
||||||
|
String label = messages.getProperty("locale_" + l, l);
|
||||||
|
supportedLocales.put(l, label);
|
||||||
|
}
|
||||||
|
return supportedLocales;
|
||||||
|
}
|
||||||
|
|
||||||
private String messagesToJsonString(Properties props) {
|
private String messagesToJsonString(Properties props) {
|
||||||
if (props == null) return "";
|
if (props == null) return "";
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ doLogOutAllSessions=Log out all sessions
|
||||||
doRemove=Remove
|
doRemove=Remove
|
||||||
doAdd=Add
|
doAdd=Add
|
||||||
doSignOut=Sign Out
|
doSignOut=Sign Out
|
||||||
|
doLogIn=Log In
|
||||||
|
|
||||||
editAccountHtmlTitle=Edit Account
|
editAccountHtmlTitle=Edit Account
|
||||||
personalInfoHtmlTitle=Personal Info
|
personalInfoHtmlTitle=Personal Info
|
||||||
|
@ -210,18 +211,18 @@ permissionRequestion=Permission Requestion
|
||||||
permission=Permission
|
permission=Permission
|
||||||
shares=share(s)
|
shares=share(s)
|
||||||
|
|
||||||
locale_ca=Catal\u00E0
|
locale_ca=Catal\u00e0
|
||||||
locale_de=Deutsch
|
locale_de=Deutsch
|
||||||
locale_en=English
|
locale_en=English
|
||||||
locale_es=Espa\u00F1ol
|
locale_es=Espa\u00f1ol
|
||||||
locale_fr=Fran\u00e7ais
|
locale_fr=Fran\u00e7ais
|
||||||
locale_it=Italian
|
locale_it=Italian
|
||||||
locale_ja=\u65E5\u672C\u8A9E
|
locale_ja=\u65e5\u672c\u8a9e
|
||||||
locale_nl=Nederlands
|
locale_nl=Nederlands
|
||||||
locale_no=Norsk
|
locale_no=Norsk
|
||||||
locale_lt=Lietuvi\u0173
|
locale_lt=Lietuvi\u0173
|
||||||
locale_pt-BR=Portugu\u00EAs (Brasil)
|
locale_pt-BR=Portugu\u00eas (Brasil)
|
||||||
locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
|
locale_ru=\u0420\u0443\u0441\u0441\u043a\u0438\u0439
|
||||||
locale_sk=Sloven\u010Dina
|
locale_sk=Sloven\u010dina
|
||||||
locale_sv=Svenska
|
locale_sv=Svenska
|
||||||
locale_zh-CN=\u4e2d\u6587\u7b80\u4f53
|
locale_zh-CN=\u4e2d\u6587\u7b80\u4f53
|
||||||
|
|
|
@ -6,10 +6,16 @@
|
||||||
<script>
|
<script>
|
||||||
var authUrl = '${authUrl}';
|
var authUrl = '${authUrl}';
|
||||||
var baseUrl = '${baseUrl}';
|
var baseUrl = '${baseUrl}';
|
||||||
var realm = '${realm}';
|
var realm = '${realm.name}';
|
||||||
var resourceUrl = '${resourceUrl}';
|
var resourceUrl = '${resourceUrl}';
|
||||||
var isRegistrationEmailAsUsername = ${isRegistrationEmailAsUsername?c};
|
var isRegistrationEmailAsUsername = ${realm.registrationEmailAsUsername?c};
|
||||||
var isEditUserNameAllowed = ${isEditUserNameAllowed?c};
|
var isEditUserNameAllowed = ${realm.editUsernameAllowed?c};
|
||||||
|
var isInternationalizationEnabled = ${realm.internationalizationEnabled?c};
|
||||||
|
|
||||||
|
var availableLocales = [];
|
||||||
|
<#list supportedLocales as locale, label>
|
||||||
|
availableLocales.push({locale : '${locale}', label : '${label}'});
|
||||||
|
</#list>
|
||||||
|
|
||||||
<#if referrer??>
|
<#if referrer??>
|
||||||
var referrer = '${referrer}';
|
var referrer = '${referrer}';
|
||||||
|
@ -67,7 +73,7 @@
|
||||||
<script src="${authUrl}/js/keycloak.js"></script>
|
<script src="${authUrl}/js/keycloak.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var keycloak = Keycloak('${authUrl}/realms/${realm}/account/keycloak.json');
|
var keycloak = Keycloak('${authUrl}/realms/${realm.name}/account/keycloak.json');
|
||||||
keycloak.init({onLoad: 'check-sso'}).success(function(authenticated) {
|
keycloak.init({onLoad: 'check-sso'}).success(function(authenticated) {
|
||||||
var loadjs = function (url,loadListener) {
|
var loadjs = function (url,loadListener) {
|
||||||
const script = document.createElement("script");
|
const script = document.createElement("script");
|
||||||
|
@ -128,27 +134,15 @@
|
||||||
we are unable to localize the button's message. Not sure what to do about that yet.
|
we are unable to localize the button's message. Not sure what to do about that yet.
|
||||||
-->
|
-->
|
||||||
<ul class="nav navbar-nav navbar-right navbar-iconic">
|
<ul class="nav navbar-nav navbar-right navbar-iconic">
|
||||||
<li><button id="signInButton" style="visibility:hidden" onclick="keycloak.login();" class="btn btn-primary btn-lg btn-sign" type="button">Log In</button></li>
|
<li><button id="signInButton" style="visibility:hidden" onclick="keycloak.login();" class="btn btn-primary btn-lg btn-sign" type="button">${msg("doLogIn")}</button></li>
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#0" class="dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a href="#0" class="dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
${msg("locale_en")} <span class="caret"></span>
|
${msg("locale_" + locale)} <span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
<li><a href="#">${msg("locale_ca")}</a></li>
|
<#list supportedLocales as locale, label>
|
||||||
<li><a href="#">${msg("locale_de")}</a></li>
|
<li><a href="${baseUrl}/?kc_locale=${locale}">${label}</a></li>
|
||||||
<li><a href="#">${msg("locale_en")}</a></li>
|
</#list>
|
||||||
<li><a href="#">${msg("locale_es")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_fr")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_it")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_ja")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_nl")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_no")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_lt")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_pt-BR")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_ru")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_sk")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_sv")}</a></li>
|
|
||||||
<li><a href="#">${msg("locale_zh-CN")}</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* MIT License
|
* MIT License
|
||||||
*
|
*
|
||||||
* Copyright 2017 Andy Hanson
|
* Copyright 2017 Brett Epps <https://github.com/eppsilon>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||||
* associated documentation files (the "Software"), to deal in the Software without restriction, including
|
* associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||||
|
@ -29,7 +29,7 @@ export = Keycloak;
|
||||||
declare function Keycloak(config?: string|{}): Keycloak.KeycloakInstance;
|
declare function Keycloak(config?: string|{}): Keycloak.KeycloakInstance;
|
||||||
|
|
||||||
declare namespace Keycloak {
|
declare namespace Keycloak {
|
||||||
type KeycloakAdapterName = 'cordova'|'default';
|
type KeycloakAdapterName = 'cordova'|'default' | any;
|
||||||
type KeycloakOnLoad = 'login-required'|'check-sso';
|
type KeycloakOnLoad = 'login-required'|'check-sso';
|
||||||
type KeycloakResponseMode = 'query'|'fragment';
|
type KeycloakResponseMode = 'query'|'fragment';
|
||||||
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
|
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
|
||||||
|
@ -39,6 +39,15 @@ declare namespace Keycloak {
|
||||||
/**
|
/**
|
||||||
* @private Undocumented.
|
* @private Undocumented.
|
||||||
*/
|
*/
|
||||||
|
useNonce?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to use different adapter:
|
||||||
|
*
|
||||||
|
* - {string} default - using browser api for redirects
|
||||||
|
* - {string} cordova - using cordova plugins
|
||||||
|
* - {function} - allows to provide custom function as adapter.
|
||||||
|
*/
|
||||||
adapter?: KeycloakAdapterName;
|
adapter?: KeycloakAdapterName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +87,7 @@ declare namespace Keycloak {
|
||||||
* Set the interval to check login state (in seconds).
|
* Set the interval to check login state (in seconds).
|
||||||
* @default 5
|
* @default 5
|
||||||
*/
|
*/
|
||||||
checkLoginIframeInterval?: boolean;
|
checkLoginIframeInterval?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the OpenID Connect response mode to send to Keycloak upon login.
|
* Set the OpenID Connect response mode to send to Keycloak upon login.
|
||||||
|
@ -141,9 +150,17 @@ declare namespace Keycloak {
|
||||||
idpHint?: string;
|
idpHint?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the desired locale for the UI.
|
* Sets the 'ui_locales' query param in compliance with section 3.1.2.1
|
||||||
|
* of the OIDC 1.0 specification.
|
||||||
*/
|
*/
|
||||||
locale?: string;
|
locale?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the desired Keycloak locale for the UI. This differs from
|
||||||
|
* the locale param in that it tells the Keycloak server to set a cookie and update
|
||||||
|
* the user's profile to a new preferred locale.
|
||||||
|
*/
|
||||||
|
kcLocale?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeycloakPromiseCallback<T> = (result: T) => void;
|
type KeycloakPromiseCallback<T> = (result: T) => void;
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
adapter = loadAdapter('cordova');
|
adapter = loadAdapter('cordova');
|
||||||
} else if (initOptions && initOptions.adapter === 'default') {
|
} else if (initOptions && initOptions.adapter === 'default') {
|
||||||
adapter = loadAdapter();
|
adapter = loadAdapter();
|
||||||
|
} else if (initOptions && typeof initOptions.adapter === "object") {
|
||||||
|
adapter = initOptions.adapter;
|
||||||
} else {
|
} else {
|
||||||
if (window.Cordova || window.cordova) {
|
if (window.Cordova || window.cordova) {
|
||||||
adapter = loadAdapter('cordova');
|
adapter = loadAdapter('cordova');
|
||||||
|
@ -281,6 +283,10 @@
|
||||||
url += '&ui_locales=' + encodeURIComponent(options.locale);
|
url += '&ui_locales=' + encodeURIComponent(options.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options && options.kcLocale) {
|
||||||
|
url += '&kc_locale=' + encodeURIComponent(options.kcLocale);
|
||||||
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,6 +470,10 @@
|
||||||
} else {
|
} else {
|
||||||
console.warn('[KEYCLOAK] Failed to refresh token');
|
console.warn('[KEYCLOAK] Failed to refresh token');
|
||||||
|
|
||||||
|
if (req.status == 400) {
|
||||||
|
kc.clearToken();
|
||||||
|
}
|
||||||
|
|
||||||
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
kc.onAuthRefreshError && kc.onAuthRefreshError();
|
||||||
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
|
||||||
p.setError(true);
|
p.setError(true);
|
||||||
|
|
|
@ -28,6 +28,12 @@
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
|
||||||
<li><a href="#" (click)="logout()">{{'doSignOut' | translate}}</a></li>
|
<li><a href="#" (click)="logout()">{{'doSignOut' | translate}}</a></li>
|
||||||
|
<li class="dropdown-submenu pull-left">
|
||||||
|
<a class="test" tabindex="-1" href="#">Change language</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li *ngFor="let locale of availableLocales" (click)="changeLocale(locale.locale)"><a tabindex="-1" href="#">{{ locale.label }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -24,6 +24,7 @@ declare const resourceUrl: string;
|
||||||
declare const baseUrl: string;
|
declare const baseUrl: string;
|
||||||
declare const referrer: string;
|
declare const referrer: string;
|
||||||
declare const referrer_uri: string;
|
declare const referrer_uri: string;
|
||||||
|
declare const availableLocales: Array<Object>;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-top-nav',
|
selector: 'app-top-nav',
|
||||||
|
@ -34,10 +35,13 @@ export class TopNavComponent implements OnInit {
|
||||||
@Input() showSideNav: String;
|
@Input() showSideNav: String;
|
||||||
|
|
||||||
public resourceUrl: string = resourceUrl;
|
public resourceUrl: string = resourceUrl;
|
||||||
|
public availableLocales: Array<Object> = availableLocales;
|
||||||
|
|
||||||
private referrer: Referrer;
|
private referrer: Referrer;
|
||||||
|
|
||||||
constructor(private keycloakService: KeycloakService, translateUtil: TranslateUtil, private respSvc: ResponsivenessService) {
|
constructor(private keycloakService: KeycloakService,
|
||||||
|
translateUtil: TranslateUtil,
|
||||||
|
private respSvc: ResponsivenessService) {
|
||||||
this.referrer = new Referrer(translateUtil);
|
this.referrer = new Referrer(translateUtil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,4 +56,8 @@ export class TopNavComponent implements OnInit {
|
||||||
this.keycloakService.logout(baseUrl);
|
this.keycloakService.logout(baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private changeLocale(newLocale: string) {
|
||||||
|
this.keycloakService.login({kcLocale: newLocale });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue