th_biedermann
Occasional Collector

Mehrsprachigkeit externe DB Fallback Sprache

Hallo zusammen

Ich stehe vor dem Problem, dass ich eine nicht FS Datenbank habe, mit verschiedenen Sprachen DE; EN; FR.
Es sind nicht immer alle Felder in allen Sprachen gefüllt. CZ wird z.B. in EN abgefüllt.

Wie kann ich nun eine Fallbacksprache definieren z.B. EN und zuweisen, so dass wenn z.B. FS cz/cs/ ausgewählt ist, die EN Version gezogen wird.

snap099.png

Danke für einen Tipp und Grüsse

Thomas

0 Kudos
15 Replies

Guten Morgen Holger

Zuerst einmal bedeutet dies, dass die URLs sich nach der ersten Generierung nicht mehr verändern werden, solange Du die nicht zurücksetzt (Im SiteStore das Kontextmenü auf der Seiten/dem Ordner aufrufen und dort Extras/Gespeicherte URLs zurücksetzen aufrufen).

-> Das habe ich bereits mehrmals gemacht 😉

Beim Erzeugen der URL wird aber festgestellt, dass es für die "Variable für Text in der Sitemap" (Karteikarte Daten) keinen Wert in den Sprachen gibt, für die es keine Spalte gibt (da wird, wenn ich mich nicht irre, die Datenbankspalte genommen und um das Sprachkürzel erweitert).

snap118.jpg

 

Nach dem Zurücksetzen der URLs musst Du also per Skript neue URLs definieren und in die Registry schreiben (siehe Api-Hinweis in meiner Antwort von heute morgen). Einfach über die Entities iterieren und für jede die gewünschte URL (erzeugt aus der Überschrift der passenden Sprache) für die jeweilige Projekt-Sprache in dem gewünschten Templatesatz (bekommt man über das Project) für die Seitenreferenz, die die Detailseiten erzeugt, setzen. ACHTUNG: Du musst darauf achten, dass die URLs sich pro Sprache und pro Templatesatz unterscheiden. Doppelte URLs sind nicht erlaubt und auch nicht gewünscht.

Hier hackt es nun bei mir. Wie und wo kann ich über die Entities iterieren. Es ist eine Datenquelle. Wie komme ich an diese Informationen ran. Ehrlich gesagt kenne ich mich hier nicht so aus.

Hättest du ein kleines Beispiel für diesen Script.

Vielen Lieben DANK und Grüsse

Thomas

0 Kudos

Hallo Thomas,

ich wollte das sowieso schon immer mal ausprobieren 🙂
Hier ein entsprechendes Skript, dass bei mir lokal funktioniert.
Da musst Du natürlich die Namen der Knoten/Eingabekomponente entsprechend anpassen.

Außerdem habe ich den String nur sehr rudimentär über die replaceAll bereinigt. Da muss wahrscheinlich noch bedeutend mehr ersetzt werden, damit die URL "gültig und lesbar" ist 😉

//!Beanshell
import de.espirit.firstspirit.agency.StoreElementAgent;
import de.espirit.firstspirit.agency.StoreAgent;
import de.espirit.firstspirit.access.store.contentstore.Content2;
import de.espirit.firstspirit.access.store.sitestore.PageRef;
import de.espirit.firstspirit.access.store.Store.Type;
import de.espirit.firstspirit.access.store.globalstore.URLProperties;

templateset = context.project.templateSets.get(0);
languages = context.project.languages;
storeAgent = context.requestSpecialist(StoreAgent.TYPE);
urlProperties = storeAgent.getStore(Type.GLOBALSTORE).getChildren(URLProperties.class).getFirst();
storeElementAgent  = context.requestSpecialist(StoreElementAgent.TYPE);
content2 = storeElementAgent.loadStoreElement("talente",Content2.UID_TYPE,false);
datasets = content2.getDatasets();
pageref = storeElementAgent.loadStoreElement("steigerbare_talente_detailseiten",PageRef.UID_TYPE,false);
urlPrefix = "/Regeln/Talentsystem/steigerbareTalente/";
urlSuffix = ".html";
urlProperties.setLock(true);
for(dataset:datasets) {
	for(language:languages) {
		url = urlPrefix + dataset.formData.get(null,"Name").get().replaceAll(" ","-").replaceAll("&","+") + urlSuffix;
		urlProperties.setStoredUrl(url,pageref,language,templateset,dataset.entity);
	}
}
urlProperties.save("urls adapted to dataset content for pageref talente");
urlProperties.setLock(false);
/*
for(dataset:datasets) {
	for(language:languages) {
		context.logInfo("URL: " + urlProperties.getStoredUrl(pageref,language,templateset,dataset.entity));
	}
}
*/

Der auskommentierte Block unten dient nur zur Kontrolle. Wenn man den einkommentiert, werden die angepassten URLs auf der Konsole des SiteArchitect ausgegeben, damit man prüfen kann, ob alles so aussieht wie erwartet.

Die URL muss natürlich in das Projekt passen. Ich habe zwei Variablen urlPrefix und urlSuffix hinzugefügt, mit denen man das "drumherum" definieren kann. Wenn Du die URLs für mehr als einen Ausgabekanal anpassen willst, sollte das Suffix zum jeweiligen Ausgabekanal passen (z.B. .html, .json, .xml, .pdf, ...)

Auch fehlt noch die Sprachabhängigkeit. Du willst ja für mehrere Sprachen identische Inhalte setzen. Die URLs müssen aber eindeutig sein - doppelte sind nicht erlaubt. Irgendetwas musst Du in die URL reinbasteln (z.B das Sprachkürzel als zusätzliches Verzeichnis im Präfix)

Ich hoffe, dass Du das Problem mit Hilfe dieses Skriptbeispiels lösen kannst.

Viele Grüße
Holger

P.S. Wenn man die URLs einmal gesetzt hat, können die danach auch redaktionell bearbeitet werden (in den globalen Einstellungen unter URL Einstellungen. Wenn man das machen will, muss man natürlich vor dem automatischen Setzen prüfen, ob es bereits eine entsprechende URL gibt und wenn ja, diese NICHT überschreiben...

0 Kudos

Hallo Holger

Vielen vielen DANK für den Code Schnipsel.

Eine Frage habe ich noch. Was meinst du mit "talente". Was ist das genau für ein StoreElement.

content2 = storeElementAgent.loadStoreElement("talente",Content2.UID_TYPE,false);

Grüsse. Thomas

0 Kudos

Hallo Thomas,

sorry, ich hatte den Testcode ohne Anpassungen übernommen, da die Zeit knapp wurde. Normalerweise nenne ich die entsprechenden Stellen sinnvoll um, damit sich aus dem Namen ergibt, was es ist.
Der Test stammt aus meinem privatem Projekt, dass ich vor langer Zeit mal aufgesetzt habe (mit einer FirstSpirit Version kleiner 1). 

"talente" ist die UID der entsprechenden Datenquelle, über die die Datensätze angezeigt werden. Die hole ich mir, um über die Datensätze iterieren zu können. Die entsprechenden datasets wandele ich später dann ja in Entities um, um die SEO URLs setzen zu können.

"steigerbare_talente_detailseiten" ist die Seitenreferenz, über die die Detailseiten der Datensätze ausgegeben werden und für die die SEO URLs definiert werden sollen.

"Name" ist der Name der Eingabekomponente (heutzutage mit Coding Conventions wäre das dann "cs_name")

Viele Grüße
Holger

 

0 Kudos

Hoi Holger

Wir sind weiter gekommen 😉

Jetzt habe ich noch folgenden Fehler:

Warum weiss ich nicht, der soll ja nicht in die DB schreiben. Was er auch nicht darf, da die DB keine FS - DB ist sondern "Schema aus Datenbank erzeugen"

 

INFO  23.09.2022 15:26:09.136 (de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl): starting task 'jobUrlCreator' - schedule entry '[DEV-ADMIN] Career - CH' (id=596480)
INFO  23.09.2022 15:26:09.144 (de.espirit.firstspirit.store.access.AccessStoreBuilder): GLOBALSTORE(false) loaded in 0ms
INFO  23.09.2022 15:26:09.145 (de.espirit.firstspirit.store.access.AccessStoreBuilder): CONTENTSTORE(false) loaded in 0ms
INFO  23.09.2022 15:26:09.145 (de.espirit.firstspirit.store.access.AccessStoreBuilder): TEMPLATESTORE(false) loaded in 0ms
INFO  23.09.2022 15:26:09.154 (de.espirit.firstspirit.store.access.AccessStoreBuilder): SITESTORE(false) loaded in 0ms
ERROR 23.09.2022 15:26:09.155{dNR=} (de.espirit.firstspirit.server.scheduler.ScriptTaskExecutor): error during script execution : de.espirit.firstspirit.access.script.ExecutionException: Method Invocation urlProperties.setLock : at Line: 19 : in file: inline evaluation of: ``__execute() { //!Beanshell import de.espirit.firstspirit.agency.StoreElementAgen . . . '' : urlProperties .setLock ( true ) 

Called from method: __execute
Target exception: java.lang.SecurityException: read only store
 at line 19
de.espirit.firstspirit.access.script.ExecutionException: Method Invocation urlProperties.setLock : at Line: 19 : in file: inline evaluation of: ``__execute() { //!Beanshell import de.espirit.firstspirit.agency.StoreElementAgen . . . '' : urlProperties .setLock ( true ) 

Called from method: __execute
Target exception: java.lang.SecurityException: read only store
 at line 19
	at de.espirit.firstspirit.server.script.BeanshellScriptEngine$BeanshellExecutable.execute(BeanshellScriptEngine.java:109)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.lambda$execute$1(PermissionsScriptEngine.java:83)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.execute(PermissionsScriptEngine.java:88)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.execute(PermissionsScriptEngine.java:83)
	at de.espirit.firstspirit.common.ScriptUtil.execute(ScriptUtil.java:109)
	at de.espirit.firstspirit.server.scheduler.ScriptTaskExecutor.run(ScriptTaskExecutor.java:162)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:2709)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:2692)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.call(ScheduleManagerImpl.java:2621)
	at de.espirit.firstspirit.server.ExecutionManagerImpl$ExtendedCallable.call(ExecutionManagerImpl.java:629)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at de.espirit.common.util.BoundedExecutorService$RunnableWrapper.run(BoundedExecutorService.java:491)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
	at de.espirit.common.util.SuspendableThread.run(SuspendableThread.java:58)
Caused by: java.lang.SecurityException: read only store
	at de.espirit.firstspirit.store.access.ReadOnlySecurityManager.checkAccess(ReadOnlySecurityManager.java:29)
	at de.espirit.firstspirit.store.access.AbstractStoreElement.checkAccess(AbstractStoreElement.java:1480)
	at de.espirit.firstspirit.store.access.DefaultStoreElement.setLock(DefaultStoreElement.java:463)
	at de.espirit.firstspirit.store.access.DefaultStoreElement.setLock(DefaultStoreElement.java:455)
	at de.espirit.firstspirit.store.access.AbstractStoreElement.setLock(AbstractStoreElement.java:1176)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at bsh.Reflect.invokeMethod(Reflect.java:185)
	at bsh.Reflect.invokeObjectMethod(Reflect.java:118)
	at bsh.Name.invokeMethod(Name.java:858)
	at bsh.BSHMethodInvocation.eval(BSHMethodInvocation.java:75)
	at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:102)
	at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:47)
	at bsh.BSHBlock.evalBlock(BSHBlock.java:130)
	at bsh.BSHBlock.eval(BSHBlock.java:80)
	at bsh.BshMethod.invokeImpl(BshMethod.java:371)
	at bsh.BshMethod.invoke(BshMethod.java:267)
	at bsh.BshMethod.invoke(BshMethod.java:170)
	at bsh.PreparsedScript.invoke(PreparsedScript.java:66)
	at de.espirit.firstspirit.server.script.BeanshellScriptEngine$BeanshellExecutable.execute(BeanshellScriptEngine.java:100)
	... 18 more
INFO  23.09.2022 15:26:09.155 (de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl): finished task 'jobUrlCreator' - schedule entry '[DEV-ADMIN] Career - CH' (id=596480)

 

 

Fehler ohne die Zeile:

/*urlProperties.setLock(true);*/

 

INFO  23.09.2022 15:31:07.555 (de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl): starting task 'jobUrlCreator' - schedule entry '[DEV-ADMIN] Career - CH' (id=596480)
INFO  23.09.2022 15:31:07.561 (de.espirit.firstspirit.store.access.AccessStoreBuilder): GLOBALSTORE(false) loaded in 0ms
INFO  23.09.2022 15:31:07.561 (de.espirit.firstspirit.store.access.AccessStoreBuilder): CONTENTSTORE(false) loaded in 0ms
INFO  23.09.2022 15:31:07.562 (de.espirit.firstspirit.store.access.AccessStoreBuilder): TEMPLATESTORE(false) loaded in 0ms
INFO  23.09.2022 15:31:07.574 (de.espirit.firstspirit.store.access.AccessStoreBuilder): SITESTORE(false) loaded in 0ms
ERROR 23.09.2022 15:31:07.583 (de.espirit.firstspirit.impl.access.ScriptContextImpl): url = /offene-stellen/Key-Account-Quality-Manager-–-Automotive-(m/w).html
ERROR 23.09.2022 15:31:07.584 (de.espirit.firstspirit.impl.access.ScriptContextImpl): pageref = <PAGEREF editor="1" htmlname="job_detail" id="586008" pageref="586005" releaseRevision="211146" releasedby="1" revision="211146" uniquedescription="job_detail">
	<LANG displayname="job_detail" language="DE"/>
	<PAGE_LANG_SPEC language="DE" showinpagegrp="1" showinsitemap="1"/>
	<PAGE_LANG_SPEC language="EN" showinpagegrp="1" showinsitemap="1"/>
	<CONTENTPARAMETER count="1" query="596898" sitemapvar="Marke" source="SFS_INSERATE_ERECRUITING_MULTILANG" templateid="384">
		<PARAM class="java.lang.String" name="OrgId" value="2969"/>
		<PARAM class="java.lang.String" name="Stellentyp" value="ext"/>
		<PARAM class="java.lang.String" name="Mandant" value="HAUFE"/>
	</CONTENTPARAMETER>
</PAGEREF>

ERROR 23.09.2022 15:31:07.584 (de.espirit.firstspirit.impl.access.ScriptContextImpl): language = DE
ERROR 23.09.2022 15:31:07.584 (de.espirit.firstspirit.impl.access.ScriptContextImpl): templateset = de.espirit.firstspirit.server.templatemanagement.TemplateSetImpl@7b3c7954{id=559267, name=html, presentationChannel=HTML}
ERROR 23.09.2022 15:31:07.584 (de.espirit.firstspirit.impl.access.ScriptContextImpl): dataset.entity = de.espirit.or.impl.EntityImpl@81452aa0{SFS_INSERATE_ERECRUITING_MULTILANG,PERSISTENT,STELLENID=901736}
ERROR 23.09.2022 15:31:07.585{dNR=} (de.espirit.firstspirit.server.scheduler.ScriptTaskExecutor): error during script execution : de.espirit.firstspirit.access.script.ExecutionException: Method Invocation urlProperties.setStoredUrl : at Line: 30 : in file: inline evaluation of: ``__execute() { //!Beanshell import de.espirit.firstspirit.agency.StoreElementAgen . . . '' : urlProperties .setStoredUrl ( url , pageref , language , templateset , dataset .entity ) 

Target exception: java.lang.IllegalStateException: not locked
 at line 30
de.espirit.firstspirit.access.script.ExecutionException: Method Invocation urlProperties.setStoredUrl : at Line: 30 : in file: inline evaluation of: ``__execute() { //!Beanshell import de.espirit.firstspirit.agency.StoreElementAgen . . . '' : urlProperties .setStoredUrl ( url , pageref , language , templateset , dataset .entity ) 

Target exception: java.lang.IllegalStateException: not locked
 at line 30
	at de.espirit.firstspirit.server.script.BeanshellScriptEngine$BeanshellExecutable.execute(BeanshellScriptEngine.java:109)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.lambda$execute$1(PermissionsScriptEngine.java:83)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.execute(PermissionsScriptEngine.java:88)
	at de.espirit.firstspirit.server.script.PermissionsScriptEngine$PermissionsExecutable.execute(PermissionsScriptEngine.java:83)
	at de.espirit.firstspirit.common.ScriptUtil.execute(ScriptUtil.java:109)
	at de.espirit.firstspirit.server.scheduler.ScriptTaskExecutor.run(ScriptTaskExecutor.java:162)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:2709)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:2692)
	at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.call(ScheduleManagerImpl.java:2621)
	at de.espirit.firstspirit.server.ExecutionManagerImpl$ExtendedCallable.call(ExecutionManagerImpl.java:629)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at de.espirit.common.util.BoundedExecutorService$RunnableWrapper.run(BoundedExecutorService.java:491)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
	at de.espirit.common.util.SuspendableThread.run(SuspendableThread.java:58)
Caused by: java.lang.IllegalStateException: not locked
	at de.espirit.firstspirit.store.access.globalstore.URLPropertiesImpl.checkIsLocked(URLPropertiesImpl.java:257)
	at de.espirit.firstspirit.store.access.globalstore.URLPropertiesImpl.setUrl(URLPropertiesImpl.java:263)
	at de.espirit.firstspirit.store.access.globalstore.URLPropertiesImpl.setStoredUrl(URLPropertiesImpl.java:92)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at bsh.Reflect.invokeMethod(Reflect.java:185)
	at bsh.Reflect.invokeObjectMethod(Reflect.java:118)
	at bsh.Name.invokeMethod(Name.java:858)
	at bsh.BSHMethodInvocation.eval(BSHMethodInvocation.java:75)
	at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:102)
	at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:47)
	at bsh.BSHBlock.evalBlock(BSHBlock.java:130)
	at bsh.BSHBlock.eval(BSHBlock.java:80)
	at bsh.BSHBlock.eval(BSHBlock.java:46)
	at bsh.BSHEnhancedForStatement.eval(BSHEnhancedForStatement.java:80)
	at bsh.BSHBlock.evalBlock(BSHBlock.java:130)
	at bsh.BSHBlock.eval(BSHBlock.java:80)
	at bsh.BSHBlock.eval(BSHBlock.java:46)
	at bsh.BSHEnhancedForStatement.eval(BSHEnhancedForStatement.java:80)
	at bsh.BSHBlock.evalBlock(BSHBlock.java:130)
	at bsh.BSHBlock.eval(BSHBlock.java:80)
	at bsh.BshMethod.invokeImpl(BshMethod.java:371)
	at bsh.BshMethod.invoke(BshMethod.java:267)
	at bsh.BshMethod.invoke(BshMethod.java:170)
	at bsh.PreparsedScript.invoke(PreparsedScript.java:66)
	at de.espirit.firstspirit.server.script.BeanshellScriptEngine$BeanshellExecutable.execute(BeanshellScriptEngine.java:100)
	... 18 more
INFO  23.09.2022 15:31:07.585 (de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl): finished task 'jobUrlCreator' - schedule entry '[DEV-ADMIN] Career - CH' (id=596480)

 

 

 Ich wünsche dir ein schönes Weekend und Danke noch einmal für deine Hilfe.

Thomas

0 Kudos

Guten Morgen Thomas,

da Du das Skript in einem Auftrag ausführst (wobei es dann empfehlenswert ist zu prüfen, ob die entsprechende URL bereits gesetzt ist, damit die nicht jedesmal überschrieben werden), vermute ich mal, dass Du in dem Skript wahrscheinlich keine Verbindungseinstellungen gesetzt (über dem Quelltext des Skriptes der Button Eigenschaften->Eigene Verbindung und dann die Zugangsdaten von einem [technischen] Benutzer eintragen, der die URL Einstellungen bearbeiten darf).

Dafür spricht auch "java.lang.SecurityException: read only store", da man ohne diese Einstellung eine "Read-Only" Verbindung bekommt.

Viele Grüße
Holger

0 Kudos