mhenke
I'm new here

Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Mittels folgendem Schnippels finde ich alle Felder in Datenbank-Templates die zwar mehrsprachig sind aber bei denen nicht für alle existierenden Sprachen ein Feld existiert.

Es werden also zum Beispiel bei einem zweisprachigen Projekt das vor kurzem eine neue Sprache hinzugefügt hat alle mehrsprachigen Felder gelistet da bei diesen das Feld für die neue Sprache fehlt.

TemplateStoreRoot templateStore = (TemplateStoreRoot) storeAgent.getStore(Store.Type.TEMPLATESTORE);

Schemes schemes = templateStore.getSchemes();

for (Schema s : schemes.getChildren(Schema.class)) {

          for (TableTemplate t : s.getChildren(TableTemplate.class)) {

                    TableTemplate.Mapping[] mappings = t.getMappings();

                    for (TableTemplate.Mapping m : mappings) {

                              if (!m.isLanguageDependent()) {

                                        continue;

                              }

                              for (Language l : context.getProject().getLanguages()) {

                                        Attribute a = m.getDBAttribute(l.getAbbreviation());

                                        if (a == null) {

                                                  System.out.println(t.getName() +"," + m.getName()+ "," + l.getName());

                                        }

                              }

                    }

          }

}

Ich würde nun gerne an der Stelle des println die fehlenden Felder hinzufügen und auch gleich mappen.

Hat da jemand Hinweise, Ideen oder Ähnliches?

Viele Grüße,

Michael

Labels (1)
Tags (2)
1 Solution

Accepted Solutions
mhenke
I'm new here

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Den Trick mit der XML kenne ich. Allerdings würde ich die Felder gerne automatisch anlegen.

Die Tabellenspalte habe ich nun soweit anlegen können. Mir fehlt aber noch das Mapping.

Die Klasse TableTemplate.Mapping hat eine Methode getDBAttribute aber keine um mein neu erstelltes SimpleAttribute zu setzen.

Wie gehe ich denn vor um das Mapping anzulegen ?

EDIT: Ich habe es hingekriegt. Falls einer das gleiche Problem hat hier der Quelltext:

public class CreateFieldsNewLanguage {

          private ClientScriptContext context;

          private Language masterLang;

          private static final Pattern reName = Pattern.compile("^([^_]+)_.{2}$");

          private String getOriginalDatabaseFieldName(TableTemplate.Mapping mapping) throws Exception {

                    Attribute master = mapping.getDBAttribute(masterLang.getAbbreviation());

                    if (master == null) {

                              throw new Exception("Field " + mapping.getName() + " does not have master language mapping");

                    }

                    Matcher m = reName.matcher(master.getName());

                    if (!m.matches()) {

                              throw new Exception("Field " + mapping.getName() + " has DB field " + master.getName() + " which does not conform to naming convention of $name_$abbreviationoflangunage");

                    }

                    return m.group(1);

          }

          private void addMissingFields(TableTemplate t, EntityType type) throws Exception {

                    try {

                              t.setLock(true, false);

                              TableTemplate.Mapping[] mappings = t.getMappings();

                              for (TableTemplate.Mapping mapping : mappings) {

                                        if (!mapping.isLanguageDependent()) {

                                                  continue;

                                        }

                                        for (Language l : context.getProject().getLanguages()) {

                                                  Attribute a = mapping.getDBAttribute(l.getAbbreviation());

                                                  if (a != null) {

                                                            continue;

                                                  }

                                                  String dbname;

                                                  try {

                                                            dbname = getOriginalDatabaseFieldName(mapping);

                                                  } catch(Exception e) {

                                                            context.logError(e.getMessage());

                                                            continue;

                                                  }

                                                  String masterName = dbname + "_" + masterLang.getAbbreviation();

                                                  if (!type.isSimpleAttribute(masterName)) {

                                                            context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " is missing but not simple attribute (composed not supported)");

                                                            continue;

                                                  }

                                                  String newName = dbname + "_" + l.getAbbreviation();

                                                  if (!type.containsAttribute(newName)) {

                                                            context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> creating " + newName);

                                                            SimpleAttribute ma = (SimpleAttribute) type.getAttribute(masterName);

                                                            SimpleAttribute na = type.createSimpleAttribute(newName, ma.getType());

                                                            Column col = ma.getColumn().clone();

                                                            col.setName(newName);

                                                            na.setColumn(col);

                                                  }

                                                  context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> mapping " + newName);

                                                  mapping.setAttributeReference(new String[]{newName}, l.getAbbreviation(), true);

                                        }

                              }

                              t.setMappings(mappings);

                              t.save("", false);

                    } finally {

                              t.setLock(false, false);

                    }

          }

          public void run(ClientScriptContext context) throws Exception {

                    this.context = context;

                    this.masterLang = context.getProject().getMasterLanguage();

                    TemplateStoreRoot templateStore = context.getUserService().getStore(Store.Type.TEMPLATESTORE, false);

                    Schemes schemes = templateStore.getSchemes();

                    for (Schema s : schemes.getChildren(Schema.class)) {

                              if(s.isReadOnly()) {

                                        continue;

                              }

                              try {

                                        s.setLock(true, false);

                                        Session osess = s.getSession(false);

                                        de.espirit.or.schema.Schema os = osess.getSchema();

                                        for (TableTemplate t : s.getChildren(TableTemplate.class)) {

                                                  addMissingFields(t, os.getEntityType(t.getEntityType().getName()));

                                        }

                                        osess.syncSchemaWithDB(os, false);

                                        s.setOrSchema(os);

                                        s.save("", false);

                              } finally {

                                        s.setLock(false, false);

                              }

                    }

          }

}

Benutzung ist:

new CreateFieldsNewLanguage().run(context);

Falls jemand Verbesserungsvorschlage und/oder Kritik hat bitte melden.

View solution in original post

0 Kudos
8 Replies
marro
Crownpeak employee
Crownpeak employee

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Hallo Michael,

ich fürchte, da gibt es keinen einfachen Weg über die API. Zumindest fällt mir keiner ein.

Eine ähnliche Frage findest Du in Sprachabhängige Spalten nach Hinzufügen einer Sprache. Dort verweise ich auf ein Blogposting, in dem ein alternativer Weg beschrieben wird.

Viele Grüße

Donato

mhenke
I'm new here

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Den Trick mit der XML kenne ich. Allerdings würde ich die Felder gerne automatisch anlegen.

Die Tabellenspalte habe ich nun soweit anlegen können. Mir fehlt aber noch das Mapping.

Die Klasse TableTemplate.Mapping hat eine Methode getDBAttribute aber keine um mein neu erstelltes SimpleAttribute zu setzen.

Wie gehe ich denn vor um das Mapping anzulegen ?

EDIT: Ich habe es hingekriegt. Falls einer das gleiche Problem hat hier der Quelltext:

public class CreateFieldsNewLanguage {

          private ClientScriptContext context;

          private Language masterLang;

          private static final Pattern reName = Pattern.compile("^([^_]+)_.{2}$");

          private String getOriginalDatabaseFieldName(TableTemplate.Mapping mapping) throws Exception {

                    Attribute master = mapping.getDBAttribute(masterLang.getAbbreviation());

                    if (master == null) {

                              throw new Exception("Field " + mapping.getName() + " does not have master language mapping");

                    }

                    Matcher m = reName.matcher(master.getName());

                    if (!m.matches()) {

                              throw new Exception("Field " + mapping.getName() + " has DB field " + master.getName() + " which does not conform to naming convention of $name_$abbreviationoflangunage");

                    }

                    return m.group(1);

          }

          private void addMissingFields(TableTemplate t, EntityType type) throws Exception {

                    try {

                              t.setLock(true, false);

                              TableTemplate.Mapping[] mappings = t.getMappings();

                              for (TableTemplate.Mapping mapping : mappings) {

                                        if (!mapping.isLanguageDependent()) {

                                                  continue;

                                        }

                                        for (Language l : context.getProject().getLanguages()) {

                                                  Attribute a = mapping.getDBAttribute(l.getAbbreviation());

                                                  if (a != null) {

                                                            continue;

                                                  }

                                                  String dbname;

                                                  try {

                                                            dbname = getOriginalDatabaseFieldName(mapping);

                                                  } catch(Exception e) {

                                                            context.logError(e.getMessage());

                                                            continue;

                                                  }

                                                  String masterName = dbname + "_" + masterLang.getAbbreviation();

                                                  if (!type.isSimpleAttribute(masterName)) {

                                                            context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " is missing but not simple attribute (composed not supported)");

                                                            continue;

                                                  }

                                                  String newName = dbname + "_" + l.getAbbreviation();

                                                  if (!type.containsAttribute(newName)) {

                                                            context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> creating " + newName);

                                                            SimpleAttribute ma = (SimpleAttribute) type.getAttribute(masterName);

                                                            SimpleAttribute na = type.createSimpleAttribute(newName, ma.getType());

                                                            Column col = ma.getColumn().clone();

                                                            col.setName(newName);

                                                            na.setColumn(col);

                                                  }

                                                  context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> mapping " + newName);

                                                  mapping.setAttributeReference(new String[]{newName}, l.getAbbreviation(), true);

                                        }

                              }

                              t.setMappings(mappings);

                              t.save("", false);

                    } finally {

                              t.setLock(false, false);

                    }

          }

          public void run(ClientScriptContext context) throws Exception {

                    this.context = context;

                    this.masterLang = context.getProject().getMasterLanguage();

                    TemplateStoreRoot templateStore = context.getUserService().getStore(Store.Type.TEMPLATESTORE, false);

                    Schemes schemes = templateStore.getSchemes();

                    for (Schema s : schemes.getChildren(Schema.class)) {

                              if(s.isReadOnly()) {

                                        continue;

                              }

                              try {

                                        s.setLock(true, false);

                                        Session osess = s.getSession(false);

                                        de.espirit.or.schema.Schema os = osess.getSchema();

                                        for (TableTemplate t : s.getChildren(TableTemplate.class)) {

                                                  addMissingFields(t, os.getEntityType(t.getEntityType().getName()));

                                        }

                                        osess.syncSchemaWithDB(os, false);

                                        s.setOrSchema(os);

                                        s.save("", false);

                              } finally {

                                        s.setLock(false, false);

                              }

                    }

          }

}

Benutzung ist:

new CreateFieldsNewLanguage().run(context);

Falls jemand Verbesserungsvorschlage und/oder Kritik hat bitte melden.

0 Kudos
jessica_aust
Crownpeak employee
Crownpeak employee

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Hallo zusammen,

im Rahmen eines Kundenprojekts haben wir dieses Skript eingesetzt.

Folgendes muss angepasst werden:

  • Es müssen hier die Imports entsprechend angepasst werden.
  • Weiterhin hat die Reihenfolge, wie das Skript die Sprachen anlegt Schwierigkeiten bereitet. Im Skript werden erst die Tabellenvorlagen erweitert und dann erfolgt die Erweiterung des Schemas. Die korrekte Reihenfolge ist erst das Schema und dann die Tabellenvorlagen (inkl. Mapping) zu erweitern. Wir haben ganz pragmatisch das Skript zweimal ausgeführt und jeweils die relevanten Stellen auskommentiert, so dass wir die korrekte Reihenfolge eingehalten haben.
  • Das Mapping bei sprachunabhängigen Feldern hat gefehlt, das haben wir nachträglich ergänzt
0 Kudos
bIT_sosswald
Returning Responder

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Hi Jessica,

postet das angepasste Script doch, oder noch besser, packt es auf Github (wenn der ursprüngliche Urheber damit einverstanden ist) 🙂

Ein Solches Feature fehlt in FS sowieso schon immer und jeder baut es sich irgendwie selbst.

Grüße

Sandro

0 Kudos
jessica_aust
Crownpeak employee
Crownpeak employee

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Hallo Sandra,

ich lad es einfach hier hoch. wir haben das Skript bzw. die Skripte nicht "schön" gemacht, sondern nur, dass es funktioniert.

Wichtig ist dabei die Skripte in der folgenden Reihenfolge auszuführen:

1. add_language_schema

2. add_table

1) ADD_LANGUAGE_SCHEMA

import de.espirit.firstspirit.access.Language;

import de.espirit.firstspirit.access.store.Store;

import de.espirit.firstspirit.access.store.templatestore.Schema;

import de.espirit.firstspirit.access.store.templatestore.Schemes;

import de.espirit.firstspirit.access.store.templatestore.TableTemplate;

import de.espirit.firstspirit.access.store.templatestore.TemplateStoreRoot;

import de.espirit.firstspirit.access.store.templatestore.TableTemplate.Mapping;

import de.espirit.or.Session;

import de.espirit.or.schema.Attribute;

import de.espirit.or.schema.Column;

import de.espirit.or.schema.EntityType;

import de.espirit.or.schema.SimpleAttribute;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

private Language masterLang;

private static final Pattern reName = Pattern.compile("^(.+)_[a-zA-Z]{2}$");

private String getOriginalDatabaseFieldName(TableTemplate.Mapping mapping) throws Exception {

    Attribute master = mapping.getDBAttribute(context.getProject().getMasterLanguage().getAbbreviation());

    if (master == null) {

        throw new Exception("Field " + mapping.getName() + " does not have master language mapping");

    }

    Matcher m = reName.matcher(master.getName());

    if (!m.matches()) {

        throw new Exception("Field " + mapping.getName() + " has DB field " + master.getName() + " which does not conform to naming convention of $name_$abbreviationoflangunage");

    }

    return m.group(1);

}

private void addMissingFields(TableTemplate t, EntityType type, Session osess, de.espirit.or.schema.Schema os, Schema s) throws Exception {

    try {

        t.setLock(true, false);

        context.logInfo("Locking '" + t.getUid() + "'");

        mappings = t.getMappings();

        for (TableTemplate.Mapping mapping: mappings) {

            if (!mapping.isLanguageDependent()) {

                context.logInfo("Mapping '" + mapping.getName() + "' of '" + t.getUid() + "' is not language dependent! -> skipping");

                Attribute master = mapping.getDBAttribute(context.getProject().getMasterLanguage().getAbbreviation());

                if (master == null) {

                    context.logError("Field " + mapping.getName() + " does not have master language mapping");

                    continue;

                }

                String masterName = master.getName();

                for (Language l: context.getProject().getLanguages()) {

                    if (mapping.getDBAttribute(l.getAbbreviation()) == null) {

                        mapping.setAttributeReference(new String[] {

                            masterName

                        }, l.getAbbreviation(), false);

                        context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " -> mapping " + masterName + " [lang. independent]");

                    }

                }

                continue;

            }

            for (Language l: context.getProject().getLanguages()) {

                Attribute a = mapping.getDBAttribute(l.getAbbreviation());

                if (a != null) {

                    continue;

                }

                String dbname;

                try {

                    dbname = getOriginalDatabaseFieldName(mapping);

                } catch (Exception e) {

                    context.logError(e.getMessage());

                    continue;

                }

                String masterName = dbname + "_" + context.getProject().getMasterLanguage().getAbbreviation();

                if (!type.isSimpleAttribute(masterName)) {

                    context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " is missing but not simple attribute (composed not supported)");

                    continue;

                }

                String newName = dbname + "_" + l.getAbbreviation();

                if (!type.containsAttribute(newName)) {

                    context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> creating " + newName + " [attribute not in entity]");

                    SimpleAttribute ma = (SimpleAttribute) type.getAttribute(masterName);

                    SimpleAttribute na = type.createSimpleAttribute(newName, ma.getType());

                    Column col = ma.getColumn().clone();

                    col.setName(newName);

                    na.setColumn(col);

                }

                context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> mapping " + newName);

                mapping.setAttributeReference(new String[] {

                    newName

                }, l.getAbbreviation(), true);

            }

        }

        t.setMappings(mappings);

        //t.save("", false);

    } finally {

        context.logInfo("Unlocking '" + t.getUid() + "'");

        t.setLock(false, false);

    }

}

public void run(context) throws Exception {

    this.masterLang = context.getProject().getMasterLanguage();

    TemplateStoreRoot templateStore = (TemplateStoreRoot) context.getUserService().getStore(Store.Type.TEMPLATESTORE, false);

    Schemes schemes = templateStore.getSchemes();

    for (Schema s: schemes.getChildren(Schema.class)) {

        context.logInfo("- - - - - - - - - - - - ");

        context.logInfo("Schema: '" + s.getUid() + "'");

        if (s.isReadOnly()) {

            continue;

        }

        try {

            context.logInfo("Locking '" + s.getUid() + "'");

            s.setLock(true, false);

            Session osess = s.getSession(false);

            de.espirit.or.schema.Schema os = osess.getSchema();

            for (TableTemplate t: s.getChildren(TableTemplate.class)) {

                addMissingFields(t, os.getEntityType(t.getEntityType().getName()), osess, os, s);

            }

            osess.syncSchemaWithDB(os, false);

            s.setOrSchema(os);

            s.save("", false);

        } finally {

            context.logInfo("Unlocking '" + s.getUid() + "'");

            s.setLock(false, false);

            s.refresh();

            s.setLock(true, false);

            s.save("", false);

            s.setLock(false, false);

        }

        context.logInfo("- - - - - - - - - - - - ");

        context.logInfo(" ");

    }

}

run(context);

2) ADD_LANGUAGE_TABLE

import de.espirit.firstspirit.access.Language;

import de.espirit.firstspirit.access.store.Store;

import de.espirit.firstspirit.access.store.templatestore.Schema;

import de.espirit.firstspirit.access.store.templatestore.Schemes;

import de.espirit.firstspirit.access.store.templatestore.TableTemplate;

import de.espirit.firstspirit.access.store.templatestore.TemplateStoreRoot;

import de.espirit.firstspirit.access.store.templatestore.TableTemplate.Mapping;

import de.espirit.or.Session;

import de.espirit.or.schema.Attribute;

import de.espirit.or.schema.Column;

import de.espirit.or.schema.EntityType;

import de.espirit.or.schema.SimpleAttribute;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

private Language masterLang;

private static final Pattern reName = Pattern.compile("^(.+)_[a-zA-Z]{2}$");

private String getOriginalDatabaseFieldName(TableTemplate.Mapping mapping) throws Exception {

    Attribute master = mapping.getDBAttribute(context.getProject().getMasterLanguage().getAbbreviation());

    if (master == null) {

        throw new Exception("Field " + mapping.getName() + " does not have master language mapping");

    }

    Matcher m = reName.matcher(master.getName());

    if (!m.matches()) {

        throw new Exception("Field " + mapping.getName() + " has DB field " + master.getName() + " which does not conform to naming convention of $name_$abbreviationoflangunage");

    }

    return m.group(1);

}

private void addMissingFields(TableTemplate t, EntityType type, Session osess, de.espirit.or.schema.Schema os, Schema s) throws Exception {

    try {

        t.setLock(true, false);

        context.logInfo("Locking '" + t.getUid() + "'");

        mappings = t.getMappings();

        for (TableTemplate.Mapping mapping: mappings) {

            if (!mapping.isLanguageDependent()) {

                context.logInfo("Mapping '" + mapping.getName() + "' of '" + t.getUid() + "' is not language dependent! -> skipping");

                Attribute master = mapping.getDBAttribute(context.getProject().getMasterLanguage().getAbbreviation());

                if (master == null) {

                    context.logError("Field " + mapping.getName() + " does not have master language mapping");

                    continue;

                }

                String masterName = master.getName();

                for (Language l: context.getProject().getLanguages()) {

                    if (mapping.getDBAttribute(l.getAbbreviation()) == null) {

                        mapping.setAttributeReference(new String[] {

                            masterName

                        }, l.getAbbreviation(), false);

                        context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " -> mapping " + masterName + " [lang. independent]");

                    }

                }

                continue;

            }

            for (Language l: context.getProject().getLanguages()) {

                Attribute a = mapping.getDBAttribute(l.getAbbreviation());

                if (a != null) {

                    continue;

                }

                String dbname;

                try {

                    dbname = getOriginalDatabaseFieldName(mapping);

                } catch (Exception e) {

                    context.logError(e.getMessage());

                    continue;

                }

                String masterName = dbname + "_" + context.getProject().getMasterLanguage().getAbbreviation();

                if (!type.isSimpleAttribute(masterName)) {

                    context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + " is missing but not simple attribute (composed not supported)");

                    continue;

                }

                String newName = dbname + "_" + l.getAbbreviation();

                if (!type.containsAttribute(newName)) {

                    context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> creating " + newName + " [attribute not in entity]");

                    SimpleAttribute ma = (SimpleAttribute) type.getAttribute(masterName);

                    SimpleAttribute na = type.createSimpleAttribute(newName, ma.getType());

                    Column col = ma.getColumn().clone();

                    col.setName(newName);

                    na.setColumn(col);

                }

                context.logInfo(t.getName() + "," + mapping.getName() + "," + l.getName() + "-> mapping " + newName);

                mapping.setAttributeReference(new String[] {

                    newName

                }, l.getAbbreviation(), true);

            }

        }

        t.setMappings(mappings);

        t.save("", false);

    } finally {

        context.logInfo("Unlocking '" + t.getUid() + "'");

        t.setLock(false, false);

    }

}

public void run(context) throws Exception {

    this.masterLang = context.getProject().getMasterLanguage();

    TemplateStoreRoot templateStore = (TemplateStoreRoot) context.getUserService().getStore(Store.Type.TEMPLATESTORE, false);

    Schemes schemes = templateStore.getSchemes();

    for (Schema s: schemes.getChildren(Schema.class)) {

        context.logInfo("- - - - - - - - - - - - ");

        context.logInfo("Schema: '" + s.getUid() + "'");

        if (s.isReadOnly()) {

            continue;

        }

        try {

            context.logInfo("Locking '" + s.getUid() + "'");

            s.setLock(true, false);

            Session osess = s.getSession(false);

            de.espirit.or.schema.Schema os = osess.getSchema();

            for (TableTemplate t: s.getChildren(TableTemplate.class)) {

                addMissingFields(t, os.getEntityType(t.getEntityType().getName()), osess, os, s);

            }

            osess.syncSchemaWithDB(os, false);

            s.setOrSchema(os);

            //s.save("", false);

        } finally {

            context.logInfo("Unlocking '" + s.getUid() + "'");

            s.setLock(false, false);

            s.refresh();

            s.setLock(true, false);

            //s.save("", false);

            s.setLock(false, false);

        }

        context.logInfo("- - - - - - - - - - - - ");

        context.logInfo(" ");

    }

}

run(context);

jessica_aust
Crownpeak employee
Crownpeak employee

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

SandrO meinte ich! Sorry!

bIT_sosswald
Returning Responder

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Bin ich gewohnt 😉

0 Kudos
lobanova
Elite Observer

Re: Mittels Script bei mehrsprachigen Feldern Datenbankfelder für alle Sprachen anlegen

Jump to solution

Hallo Jessica.

Die beigefügten Skripte unterscheiden sich aber von einander nicht viel. Oder verstehe ich was falsch?

Viele Grüße,

Olga

0 Kudos