Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
missingEntitlement=MISSING ENTITLEMENT: CONNECTOR_READ

menu.Topology=Topology
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
missingEntitlement=DROIT MANQUANT : CONNECTOR_READ

menu.Topology=Topologie
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
missingEntitlement=ENTITLEMENT MANCANTE: CONNECTOR_READ

menu.Topology=Topologia
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
missingEntitlement=\u6a29\u5229\u4ed8\u4e0e\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093: CONNECTOR_READ

menu.Topology=\u30c8\u30dd\u30ed\u30b8\u30fc
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
# specific language governing permissions and limitations
# under the License.
missingEntitlement=MISSING ENTITLEMENT: CONNECTOR_READ

menu.Topology=Topologia
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# missingEntitlement=Нет прав доступа на просмотр коннектора (CONNECTOR_READ)
missingEntitlement=\u041d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440\u0430 (CONNECTOR_READ)

menu.Topology=\u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044f
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.syncope.client.ui.commons;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.wicket.core.util.resource.locator.IResourceNameIterator;
import org.apache.wicket.resource.IPropertiesFactory;
import org.apache.wicket.resource.loader.ClassStringResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DynamicMenuStringResourceLoader extends ClassStringResourceLoader {

protected static final Logger LOG = LoggerFactory.getLogger(DynamicMenuStringResourceLoader.class);

private final Map<String, Class<?>> keysForPages;

public DynamicMenuStringResourceLoader() {
super(DynamicMenuStringResourceLoader.class);
keysForPages = new HashMap<>();
}

@Override
public String loadStringResource(
final Class<?> clazz,
final String key,
final Locale locale,
final String style,
final String variation) {
if (key == null || !key.startsWith("menu.")) {
return null;
}

final Class<?> pageClass = getPage(key);
if (pageClass == null) {
return null;
}

final String path = pageClass.getName().replace('.', '/');
final IResourceNameIterator resourceNameIterator = newResourceNameIterator(path, locale, style, variation);
final IPropertiesFactory propertiesFactory = getPropertiesFactory();

while (resourceNameIterator.hasNext()) {
final var props = propertiesFactory.load(pageClass, resourceNameIterator.next());
if (props == null) {
continue;
}

final String localeLabel = props.getString(key);
LOG.debug("Found label \"{}\" for key: {}", localeLabel, key);
return localeLabel;
}

return null;
}

private Class<?> getPage(final String key) {
return keysForPages.get(key);
}

public void register(final String key, final Class<?> pageClass) {
keysForPages.put(key, pageClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.apache.syncope.client.console.rest.TaskRestClient;
import org.apache.syncope.client.console.rest.UserRestClient;
import org.apache.syncope.client.console.rest.UserSelfRestClient;
import org.apache.syncope.client.ui.commons.DynamicMenuStringResourceLoader;
import org.apache.syncope.client.ui.commons.MIMETypesLoader;
import org.apache.syncope.client.ui.commons.PreviewUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand Down Expand Up @@ -334,4 +335,10 @@ public UserRestClient userRestClient() {
public UserSelfRestClient userSelfRestClient() {
return new UserSelfRestClient();
}

@ConditionalOnMissingBean
@Bean
public DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader() {
return new DynamicMenuStringResourceLoader();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.apache.syncope.client.console.commons.StatusProvider;
import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
import org.apache.syncope.client.console.wizards.any.UserFormFinalizer;
import org.apache.syncope.client.ui.commons.DynamicMenuStringResourceLoader;
import org.apache.syncope.client.ui.commons.actuate.SyncopeCoreHealthIndicator;
import org.apache.syncope.common.keymaster.client.api.ServiceOps;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
Expand Down Expand Up @@ -87,7 +88,9 @@ public SyncopeWebApplication syncopeWebApplication(
@Qualifier(SyncopeWebApplication.LOGGEDOUT_SESSIONID_CACHE)
final Cache<String, OffsetDateTime> loggedoutSessionIdCache,
@Qualifier(SyncopeWebApplication.DESTROYED_SESSIONID_CACHE)
final Cache<String, OffsetDateTime> destroyedSessionIdCache) {
final Cache<String, OffsetDateTime> destroyedSessionIdCache,
final DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader
) {

return new SyncopeWebApplication(
props,
Expand All @@ -103,7 +106,8 @@ public SyncopeWebApplication syncopeWebApplication(
userFormFinalizers,
resources,
loggedoutSessionIdCache,
destroyedSessionIdCache);
destroyedSessionIdCache,
dynamicMenuStringResourceLoader);
}

@ConditionalOnMissingBean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.syncope.client.console.commons.RealmsUtils;
import org.apache.syncope.client.console.commons.StatusProvider;
import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup;
import org.apache.syncope.client.console.pages.BaseExtPage;
import org.apache.syncope.client.console.pages.BasePage;
import org.apache.syncope.client.console.pages.Dashboard;
import org.apache.syncope.client.console.pages.Login;
Expand All @@ -52,7 +53,9 @@
import org.apache.syncope.client.ui.commons.BaseSession;
import org.apache.syncope.client.ui.commons.BaseWebApplication;
import org.apache.syncope.client.ui.commons.Constants;
import org.apache.syncope.client.ui.commons.DynamicMenuStringResourceLoader;
import org.apache.syncope.client.ui.commons.SyncopeUIRequestCycleListener;
import org.apache.syncope.client.ui.commons.annotations.ExtPage;
import org.apache.syncope.client.ui.commons.annotations.Resource;
import org.apache.syncope.client.ui.commons.themes.AdminLTE;
import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
Expand Down Expand Up @@ -125,6 +128,8 @@ public static SyncopeWebApplication get() {

protected final Cache<String, OffsetDateTime> destroyedSessionIdCache;

protected final DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader;

public SyncopeWebApplication(
final ConsoleProperties props,
final ClassPathScanImplementationLookup lookup,
Expand All @@ -140,7 +145,8 @@ public SyncopeWebApplication(
final List<UserFormFinalizer> userFormFinalizers,
final List<IResource> resources,
final Cache<String, OffsetDateTime> loggedoutSessionIdCache,
final Cache<String, OffsetDateTime> destroyedSessionIdCache) {
final Cache<String, OffsetDateTime> destroyedSessionIdCache,
final DynamicMenuStringResourceLoader dynamicMenuStringResourceLoader) {

this.props = props;
this.lookup = lookup;
Expand All @@ -157,6 +163,7 @@ public SyncopeWebApplication(
this.resources = resources;
this.loggedoutSessionIdCache = loggedoutSessionIdCache;
this.destroyedSessionIdCache = destroyedSessionIdCache;
this.dynamicMenuStringResourceLoader = dynamicMenuStringResourceLoader;
}

protected SyncopeUIRequestCycleListener buildSyncopeUIRequestCycleListener() {
Expand Down Expand Up @@ -240,6 +247,23 @@ protected void init() {

mountPage("/login", getSignInPageClass());

final List<Class<? extends BasePage>> amPageClasses = lookup.getAMPageClasses();
amPageClasses.forEach(claz -> {
dynamicMenuStringResourceLoader.register("menu." + claz.getSimpleName(), claz);
});

final List<Class<? extends BasePage>> idmPageClasses = lookup.getIdMPageClasses();
idmPageClasses.forEach(claz -> {
dynamicMenuStringResourceLoader.register("menu." + claz.getSimpleName(), claz);
});

final List<Class<? extends BaseExtPage>> extPageClasses = lookup.getClasses(BaseExtPage.class);
extPageClasses.stream().filter(claz -> (claz.isAnnotationPresent(ExtPage.class))).forEach(claz -> {
dynamicMenuStringResourceLoader.register("menu." + claz.getSimpleName(), claz);
});

getResourceSettings().getStringResourceLoaders().add(dynamicMenuStringResourceLoader);

for (IResource resource : resources) {
Class<?> resourceClass = AopUtils.getTargetClass(resource);
Resource annotation = resourceClass.getAnnotation(Resource.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ protected void populateItem(final ListItem<Class<? extends BasePage>> item) {
IdMPage ann = item.getModelObject().getAnnotation(IdMPage.class);

BookmarkablePageLink<Page> link = new BookmarkablePageLink<>("idmPage", item.getModelObject());
link.add(new Label("idmPageLabel", ann.label()));
link.add(new Label("idmPageLabel", getString("menu." + ann.label(), null, ann.label())));
if (StringUtils.isNotBlank(ann.listEntitlement())) {
MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.RENDER, ann.listEntitlement());
}
Expand Down Expand Up @@ -226,7 +226,8 @@ protected void populateItem(final ListItem<Class<? extends BasePage>> item) {
AMPage ann = item.getModelObject().getAnnotation(AMPage.class);

BookmarkablePageLink<Page> link = new BookmarkablePageLink<>("amPage", item.getModelObject());
link.add(new Label("amPageLabel", ann.label()));
link.add(new Label("amPageLabel", getString("menu." + ann.label(), null, ann.label())));

if (StringUtils.isNotBlank(ann.listEntitlement())) {
MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.RENDER, ann.listEntitlement());
}
Expand Down Expand Up @@ -521,7 +522,7 @@ protected void populateItem(final ListItem<Class<? extends BaseExtPage>> item) {
ExtPage ann = item.getModelObject().getAnnotation(ExtPage.class);

BookmarkablePageLink<Page> link = new BookmarkablePageLink<>("extPage", item.getModelObject());
link.add(new Label("extPageLabel", ann.label()));
link.add(new Label("extPageLabel", getString("menu." + ann.label(), null, ann.label())));
if (StringUtils.isNotBlank(ann.listEntitlement())) {
MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.RENDER, ann.listEntitlement());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ domains=Domains
nomatch=No matches found
tooLargeFile=File is too large, max upload file size is ${maxUploadSizeB} bytes (${maxUploadSizeMB} MB).
confirmDelegation=Do you really want to switch user?
topology=Topology
engagements=Engagements
confirmProvisionMembers=Do you really want to provision all group members?
confirmDeprovisionMembers=Do you really want to deprovision all group members?
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ confirmDelete=Voulez-vous vraiment supprimer le(s) article(s) s\u00e9lectionn\u0
confirmUnlink=Voulez-vous vraiment supprimer le lien entre le(s) article(s) s\u00e9lectionn\u00e9(s) et la ressource?
confirmUnassign=Souhaitez-vous vraiment supprimer l'affectation entre le(s) article(s) s\u00e9lectionn\u00e9(s) et la ressource?
confirmClone=Voulez-vous vraiment cloner le(s) article(s) s\u00e9lectionn\u00e9(s)?

dropDownChoiceField.nullValid=Faire un choix
DateTimeField$HoursValidator=La valeur horaire doit \u00eatre dans la gamme (1, 12)
error=Erreur
Expand Down Expand Up @@ -66,6 +67,7 @@ audit=Audit
connectors.confirm.reload=Cette demande est potentiellement dangereuse pour le d\u00e9roulement des op\u00e9rations, continuer?
intAttrNameInfo.help=En plus des attributs auto-compl\u00e9t\u00e9s, vous pouvez \u00e9galement faire r\u00e9f\u00e9rence \u00e0 des groupes, des objets ou des appartenances, par exemple:
confirmGlobalLogout=Voulez-vous vraiment effectuer une d\u00e9connexion compl\u00e8te?

implementations=Impl\u00e9mentations
timeout=L'op\u00e9ration prend trop de temps: elle sera ex\u00e9cut\u00e9e en arri\u00e8re-plan. Veuillez v\u00e9rifier plus tard le r\u00e9sultat (les erreurs ne seront pas d\u00e9tect\u00e9es).
security=S\u00e9curit\u00e9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ domains=Domini
nomatch=Nessun risultato trovato
tooLargeFile=File troppo grande, la dimensione massima ammessa \u00e8 ${maxUploadSizeB} bytes (${maxUploadSizeMB} MB).
confirmDelegation=Vuoi davvero cambiare utenza?
topology=Topologia
engagements=Impegni
confirmProvisionMembers=Vuoi davvero procedere con il provisioning di tutti i membri del gruppo?
confirmDeprovisionMembers=Vuoi davvero procedere con il deprovisioning di tutti i membri del gruppo?
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ confirmDelete=\u9078\u629e\u3057\u305f\u30a2\u30a4\u30c6\u30e0\u3092\u524a\u9664
confirmUnlink=\u9078\u629e\u3057\u305f\u30a2\u30a4\u30c6\u30e0\u3068\u30ea\u30bd\u30fc\u30b9\u306e\u9593\u306e\u30ea\u30f3\u30af\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?
confirmUnassign=\u9078\u629e\u3057\u305f\u30a2\u30a4\u30c6\u30e0\u3068\u30ea\u30bd\u30fc\u30b9\u306e\u9593\u306e\u5272\u308a\u5f53\u3066\u3092\u524a\u9664\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?
confirmClone=\u9078\u629e\u3057\u305f\u30a2\u30a4\u30c6\u30e0\u3092\u8907\u88fd\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?

dropDownChoiceField.nullValid=\uff11\u3064\u9078\u629e
DateTimeField$HoursValidator=\u6642\u9593\u306e\u5024\u306f 1\uff5e12 \u306e\u7bc4\u56f2
error=\u30a8\u30e9\u30fc
Expand Down Expand Up @@ -66,6 +67,7 @@ connectors.confirm.reload=\u3053\u306e\u8981\u6c42\u306f\u3001\u5b9f\u884c\u4e2d
intAttrNameInfo.help=\u30aa\u30fc\u30c8\u30b3\u30f3\u30d7\u30ea\u30fc\u30c8\u306e\u5c5e\u6027\u4ee5\u5916\u306b\u3001\u30b0\u30eb\u30fc\u30d7\u3001\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3001\u30e1\u30f3\u30d0\u30fc\u30b7\u30c3\u30d7\u3082\u53c2\u7167\u53ef\u80fd\u3067\u3059 (\u8a72\u5f53\u3059\u308b\u5834\u5408)\u3002\u4f8b\:
confirmGlobalLogout=\u30b0\u30ed\u30fc\u30d0\u30eb\u30ed\u30b0\u30a2\u30a6\u30c8\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b?
implementations=\u5c0e\u5165

timeout=\u64cd\u4f5c\u306b\u9577\u6642\u9593\u304b\u304b\u3063\u3066\u3044\u307e\u3059\: \u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u3067\u5b9f\u884c\u3055\u308c\u307e\u3059\u3002 \u7d50\u679c\u3092\u5f8c\u3067\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044 (\u30a8\u30e9\u30fc\u306f\u5f15\u304d\u8d77\u3053\u3057\u307e\u305b\u3093)\u3002
security=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3
before=\u524d
Expand All @@ -76,7 +78,6 @@ domains=\u30c9\u30e1\u30a4\u30f3
nomatch=No matches found
tooLargeFile=File is too large, max upload file size is ${maxUploadSizeB} bytes (${maxUploadSizeMB} MB).
confirmDelegation=Do you really want to switch user?
topology=Topology
engagements=Engagements
engagements=\u5a5a\u7d04
confirmProvisionMembers=Do you really want to provision all group members?
confirmDeprovisionMembers=Do you really want to deprovision all group members?
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ domains=Dom\u00ednios
nomatch=Nenhuma correspond\u00eancia encontrada
tooLargeFile=File is too large, max upload file size is ${maxUploadSizeB} bytes (${maxUploadSizeMB} MB).
confirmDelegation=Voc\u00ea realmente deseja mudar de usu\u00e1rio?
topology=Topology
engagements=Engagements
confirmProvisionMembers=Voc\u00ea realmente deseja provisionar todos os membros do grupo?
confirmDeprovisionMembers=Voc\u00ea realmente deseja desprovisionar todos os membros do grupo?
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ confirmDelete=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u043
confirmUnlink=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u043c?
confirmUnassign=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0434\u043b\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432?
confirmClone=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b?

dropDownChoiceField.nullValid=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435
DateTimeField$HoursValidator=\u0427\u0430\u0441\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 (1, 12)
error=\u041e\u0448\u0438\u0431\u043a\u0430
Expand Down Expand Up @@ -77,7 +78,6 @@ domains=Domains
nomatch=No matches found
tooLargeFile=File is too large, max upload file size is ${maxUploadSizeB} bytes (${maxUploadSizeMB} MB).
confirmDelegation=Do you really want to switch user?
topology=Topology
engagements=Engagements
engagements=\u043f\u043e\u043c\u043e\u043b\u0432\u043a\u0438
confirmProvisionMembers=Do you really want to provision all group members?
confirmDeprovisionMembers=Do you really want to deprovision all group members?
Loading
Loading