From c8c41cd79588926d048c6ace2f28f241b1d56ca8 Mon Sep 17 00:00:00 2001 From: uhensler <none@none> Date: Thu, 4 Jan 2018 14:23:08 +0100 Subject: [PATCH] OO-3116: Same order and grouping in bulk metadata change like in regular metadata change --- .../ui/QuestionItemSummaryController.java | 2 +- .../qpool/ui/_i18n/LocalStrings_de.properties | 2 - .../qpool/ui/_i18n/LocalStrings_en.properties | 2 - .../qpool/ui/_i18n/LocalStrings_fr.properties | 2 - .../qpool/ui/_i18n/LocalStrings_it.properties | 2 - .../qpool/ui/_i18n/LocalStrings_pl.properties | 2 - .../ui/_i18n/LocalStrings_pt_BR.properties | 2 - .../ui/_i18n/LocalStrings_zh_CN.properties | 2 - .../MetadataBulkChangeController.java | 143 ++++++------------ .../ui/metadata/_content/bulk_change.html | 6 - 10 files changed, 50 insertions(+), 115 deletions(-) diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java index 94ac9f67376..31f991a1e2d 100644 --- a/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java +++ b/src/main/java/org/olat/modules/qpool/ui/QuestionItemSummaryController.java @@ -59,8 +59,8 @@ public class QuestionItemSummaryController extends FormBasicController { setFormTitle("metadatas"); subjectEl = uifactory.addStaticTextElement("general.topic", "", formLayout); - keywordsEl = uifactory.addStaticTextElement("general.keywords", "", formLayout); studyFieldEl = uifactory.addStaticTextElement("classification.taxonomy.level", "", formLayout); + keywordsEl = uifactory.addStaticTextElement("general.keywords", "", formLayout); usageEl = uifactory.addStaticTextElement("question.usage", "", formLayout); difficultyEl = uifactory.addStaticTextElement("question.difficulty", "", formLayout); stdevDifficultyEl = uifactory.addStaticTextElement("question.stdevDifficulty", "", formLayout); diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties index 8d45f3e3203..9b35fbd8b74 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties @@ -38,7 +38,6 @@ delete.pool.confirm=Wollen Sie wirklich den Pool "{0}" l\u00F6schen? details=Detailansicht edit.pool=Pool editieren editable=Editierbar -educational=Didaktik educational.context=Level educational.learningTime=Durchschnittliche Bearbeitungszeit educational.learningTime.day=d @@ -90,7 +89,6 @@ item.type.numerical=Numerische Eingabe item.type.sc=Single-Choice item.type.unkown=Unbekannt item.type.upload=Datei hochladen -lifecycle=Lebenszyklus lifecycle.status=Status lifecycle.status.draft=Draft lifecycle.status.endOfLife=End of life diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties index 450f57b5e9a..304b706e313 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties @@ -38,7 +38,6 @@ delete.pool.confirm=Do you really want to delete the pool "{0}"? details=Details edit.pool=Edit pool editable=Editable -educational=Educational educational.context=Level educational.learningTime=Typical learning time educational.learningTime.day=d @@ -90,7 +89,6 @@ item.type.numerical=Numerical input item.type.sc=Single-Choice item.type.unkown=Unkown item.type.upload=Upload file -lifecycle=Lifecycle lifecycle.status=Status lifecycle.status.draft=Draft lifecycle.status.endOfLife=End of life diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_fr.properties index 7b0e581d7c0..8d575893f58 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_fr.properties @@ -37,7 +37,6 @@ delete.pool.confirm=Voulez-vous vraiment effacer le pool "{0}"? details=D\u00E9tails edit.pool=Editer le pool editable=Modifiable -educational=Didactique educational.context=Niveau educational.learningTime=Temps d'apprentissage typique educational.learningTime.day=j @@ -87,7 +86,6 @@ item.type.numerical=Entr\u00E9e num\u00E9rique item.type.sc=Choix unique item.type.unkown=Inconnu item.type.upload=T\u00E9l\u00E9verser un fichier -lifecycle=Lifecycle lifecycle.status=Statut lifecycle.status.draft=Ebauche lifecycle.status.finalVersion=Final diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_it.properties index b02b1cbc230..e7b31bb8d9a 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_it.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_it.properties @@ -35,7 +35,6 @@ delete.pool.confirm=Vuoi veramente eliminare il pool "{0}"? details=Dettagli edit.pool=Modificare il pool editable=Modificabile -educational=Didattico educational.context=Livello educational.learningTime=Tempo tipico di apprendimento educational.learningTime.day=g @@ -80,7 +79,6 @@ item.type.mc=Scelta multipla item.type.numerical=Immissione numerica item.type.sc=Scelta singola item.type.unkown=Sconosciuto -lifecycle=Ciclo di vita lifecycle.status=Stato lifecycle.status.draft=Bozza lifecycle.status.finalVersion=Finale diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pl.properties index 2a25b6ed7e9..6cf67fee381 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pl.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pl.properties @@ -18,7 +18,6 @@ delete.pool=Usu\u0144 pul\u0119 details=Szczeg\u00F3\u0142y edit.pool=Edytuj editable=Edytowalne -educational=Edukacyjne educational.context=Poziom educational.learningTime=Przewidziany czas educational.learningTime.day=d @@ -55,7 +54,6 @@ item.type.kprim=KPrim item.type.mc=Wielokrotny wyb\u00F3r item.type.sc=Pojedynczy wyb\u00F3r item.type.unkown=Nieznane -lifecycle=Cykl \u017Cycia lifecycle.status=Status lifecycle.status.finalVersion=Ostateczne lifecycle.status.review=Przegl\u0105d diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pt_BR.properties index 7d407f1ace0..4b9e59adbbe 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pt_BR.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_pt_BR.properties @@ -38,7 +38,6 @@ delete.pool.confirm=Voc\u00EA realmente deseja excluir o reservat\u00F3rio "{0}" details=Detalhes edit.pool=Editar reservat\u00F3rio editable=Edit\u00E1vel -educational=Educacional educational.context=N\u00EDvel educational.learningTime=Tempo de aprendizagem t\u00EDpico educational.learningTime.day=d @@ -88,7 +87,6 @@ item.type.numerical=Entrada num\u00E9rica item.type.sc=Escolha \u00FAnica item.type.unkown=Desconhecido item.type.upload=Enviar arquivo -lifecycle=Vida \u00FAtil lifecycle.status=Status lifecycle.status.draft=Rascunho lifecycle.status.finalVersion=Final diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_zh_CN.properties index 38c0977b9b1..42836979ba3 100644 --- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_zh_CN.properties +++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_zh_CN.properties @@ -28,7 +28,6 @@ delete.pool.confirm=\u60A8\u786E\u5B9A\u8981\u5220\u9664\u8FD9\u4E2A\u6C60{0}\u5 details=\u67E5\u770B\u7EC6\u8282 edit.pool=\u7F16\u8F91\u6C60 editable=\u7F16\u8F91\u680F -educational=\u6559\u5B66 educational.context=\u7EA7\u522B educational.learningTime=\u5E73\u5747\u5904\u7406\u65F6\u95F4 educational.learningTime.day=d @@ -73,7 +72,6 @@ item.type.mc=\u591A\u9009 item.type.numerical=\u6570\u503C\u8F93\u5165 item.type.sc=\u5355\u9009 item.type.unkown=\u672A\u77E5 -lifecycle=\u751F\u547D\u5468\u671F lifecycle.status=\u72B6\u6001 lifecycle.status.draft=\u8349\u7A3F lifecycle.status.finalVersion=\u6700\u7EC8 diff --git a/src/main/java/org/olat/modules/qpool/ui/metadata/MetadataBulkChangeController.java b/src/main/java/org/olat/modules/qpool/ui/metadata/MetadataBulkChangeController.java index 66b264f21d2..ff37f348298 100644 --- a/src/main/java/org/olat/modules/qpool/ui/metadata/MetadataBulkChangeController.java +++ b/src/main/java/org/olat/modules/qpool/ui/metadata/MetadataBulkChangeController.java @@ -67,33 +67,24 @@ import org.springframework.beans.factory.annotation.Autowired; * */ public class MetadataBulkChangeController extends FormBasicController { - + private static final String[] EMPTY_VALUES = new String[]{ "" }; - //general private TextElement topicEl, keywordsEl, coverageEl, addInfosEl, languageEl; private SingleSelection taxonomyLevelEl; - //educational private SingleSelection contextEl; private FormLayoutContainer learningTimeContainer; private IntegerElement learningTimeDayElement, learningTimeHourElement, learningTimeMinuteElement, learningTimeSecondElement; - //question private SingleSelection typeEl, assessmentTypeEl; private TextElement difficultyEl, stdevDifficultyEl, differentiationEl, numAnswerAltEl; - //lifecycle private TextElement versionEl; private SingleSelection statusEl; - //technical - private TextElement editorEl, editorVersionEl; - private SingleSelection formatEl; - //rights private KeyValues licenseKeys; private SingleSelection copyrightEl; private TextElement descriptionEl; private FormLayoutContainer rightsWrapperCont; - private Map<MultipleSelectionElement,FormLayoutContainer> checkboxContainer - = new HashMap<>(); + private Map<MultipleSelectionElement, FormLayoutContainer> checkboxContainer = new HashMap<>(); private final List<MultipleSelectionElement> checkboxSwitch = new ArrayList<>(); private List<QuestionItem> updatedItems; @@ -120,9 +111,7 @@ public class MetadataBulkChangeController extends FormBasicController { setFormDescription("bulk.change.description"); initGeneralForm(formLayout); - initEducationalForm(formLayout); initQuestionForm(formLayout); - initLifecycleForm(formLayout); initTechnicalForm(formLayout); initRightsForm(formLayout); @@ -140,32 +129,50 @@ public class MetadataBulkChangeController extends FormBasicController { topicEl = uifactory.addTextElement("general.topic", "general.topic", 1000, null, generalCont); decorate(topicEl, generalCont); + + qpoolTaxonomyTreeBuilder.loadTaxonomyLevelsSelection(getIdentity(), false); + taxonomyLevelEl = uifactory.addDropdownSingleselect("classification.taxonomic.path", generalCont, + qpoolTaxonomyTreeBuilder.getSelectableKeys(), qpoolTaxonomyTreeBuilder.getSelectableValues(), null); + decorate(taxonomyLevelEl, generalCont); + + KeyValues contexts = MetaUIFactory.getContextKeyValues(getTranslator(), qpoolService); + contextEl = uifactory.addDropdownSingleselect("educational.context", "educational.context", generalCont, + contexts.getKeys(), contexts.getValues(), null); + decorate(contextEl, generalCont); + keywordsEl = uifactory.addTextElement("general.keywords", "general.keywords", 1000, null, generalCont); decorate(keywordsEl, generalCont); - coverageEl = uifactory.addTextElement("general.coverage", "general.coverage", 1000, null, generalCont); - decorate(coverageEl, generalCont); + addInfosEl = uifactory.addTextElement("general.additional.informations", "general.additional.informations.long", 256, "", generalCont); decorate(addInfosEl, generalCont); + + coverageEl = uifactory.addTextElement("general.coverage", "general.coverage", 1000, null, generalCont); + decorate(coverageEl, generalCont); + languageEl = uifactory.addTextElement("general.language", "general.language", 10, "", generalCont); decorate(languageEl, generalCont); - qpoolTaxonomyTreeBuilder.loadTaxonomyLevelsSelection(getIdentity(), false); - taxonomyLevelEl = uifactory.addDropdownSingleselect("classification.taxonomic.path", generalCont, - qpoolTaxonomyTreeBuilder.getSelectableKeys(), qpoolTaxonomyTreeBuilder.getSelectableValues(), null); - decorate(taxonomyLevelEl, generalCont); + KeyValues types = MetaUIFactory.getAssessmentTypes(getTranslator()); + assessmentTypeEl = uifactory.addDropdownSingleselect("question.assessmentType", "question.assessmentType", generalCont, + types.getKeys(), types.getValues(), null); + decorate(assessmentTypeEl, generalCont); } - private void initEducationalForm(FormItemContainer formLayout) { - FormLayoutContainer eduCont = FormLayoutContainer.createDefaultFormLayout("educational", getTranslator()); - eduCont.setRootForm(mainForm); - formLayout.add(eduCont); + private void initQuestionForm(FormItemContainer formLayout) { + FormLayoutContainer questionCont = FormLayoutContainer.createDefaultFormLayout("question", getTranslator()); + questionCont.setRootForm(mainForm); + formLayout.add(questionCont); + + KeyValues typeKeys = getQItemTypeKeyValues(getTranslator(), qpoolService); + typeEl = uifactory.addDropdownSingleselect("question.type", "question.type", questionCont, typeKeys.getKeys(), typeKeys.getValues(), null); + decorate(typeEl, questionCont); String page = velocity_root + "/learning_time.html"; learningTimeContainer = FormLayoutContainer.createCustomFormLayout("educational.learningTime", getTranslator(), page); learningTimeContainer.setRootForm(mainForm); - eduCont.add(learningTimeContainer); - decorate(learningTimeContainer, eduCont); + questionCont.add(learningTimeContainer); + decorate(learningTimeContainer, questionCont); learningTimeDayElement = uifactory.addIntegerElement("learningTime.day", "", 0, learningTimeContainer); learningTimeDayElement.setDisplaySize(3); @@ -175,21 +182,6 @@ public class MetadataBulkChangeController extends FormBasicController { learningTimeMinuteElement.setDisplaySize(3); learningTimeSecondElement = uifactory.addIntegerElement("learningTime.second", "", 0, learningTimeContainer); learningTimeSecondElement.setDisplaySize(3); - - KeyValues contexts = MetaUIFactory.getContextKeyValues(getTranslator(), qpoolService); - contextEl = uifactory.addDropdownSingleselect("educational.context", "educational.context", eduCont, - contexts.getKeys(), contexts.getValues(), null); - decorate(contextEl, eduCont); - } - - private void initQuestionForm(FormItemContainer formLayout) { - FormLayoutContainer questionCont = FormLayoutContainer.createDefaultFormLayout("question", getTranslator()); - questionCont.setRootForm(mainForm); - formLayout.add(questionCont); - - KeyValues typeKeys = getQItemTypeKeyValues(getTranslator(), qpoolService); - typeEl = uifactory.addDropdownSingleselect("question.type", "question.type", questionCont, typeKeys.getKeys(), typeKeys.getValues(), null); - decorate(typeEl, questionCont); difficultyEl = uifactory.addTextElement("question.difficulty", "question.difficulty", 10, null, questionCont); difficultyEl.setExampleKey("question.difficulty.example", null); @@ -209,25 +201,7 @@ public class MetadataBulkChangeController extends FormBasicController { numAnswerAltEl = uifactory.addTextElement("question.numOfAnswerAlternatives", "question.numOfAnswerAlternatives", 10, null, questionCont); numAnswerAltEl.setDisplaySize(4); decorate(numAnswerAltEl, questionCont); - - KeyValues types = MetaUIFactory.getAssessmentTypes(getTranslator()); - assessmentTypeEl = uifactory.addDropdownSingleselect("question.assessmentType", "question.assessmentType", questionCont, - types.getKeys(), types.getValues(), null); - decorate(assessmentTypeEl, questionCont); - } - - private void initLifecycleForm(FormItemContainer formLayout) { - FormLayoutContainer lifecycleCont = FormLayoutContainer.createDefaultFormLayout("lifecycle", getTranslator()); - lifecycleCont.setRootForm(mainForm); - formLayout.add(lifecycleCont); - - versionEl = uifactory.addTextElement("lifecycle.version", "lifecycle.version", 50, null, lifecycleCont); - decorate(versionEl, lifecycleCont); - - KeyValues status = MetaUIFactory.getStatus(getTranslator()); - statusEl = uifactory.addDropdownSingleselect("lifecycle.status", "lifecycle.status", lifecycleCont, - status.getKeys(), status.getValues(), null); - decorate(statusEl, lifecycleCont); + } private void initTechnicalForm(FormItemContainer formLayout) { @@ -235,14 +209,13 @@ public class MetadataBulkChangeController extends FormBasicController { technicalCont.setRootForm(mainForm); formLayout.add(technicalCont); - editorEl = uifactory.addTextElement("technical.editor", "technical.editor", 50, null, technicalCont); - decorate(editorEl, technicalCont); - editorVersionEl = uifactory.addTextElement("technical.editorVersion", "technical.editorVersion", 50, null, technicalCont); - decorate(editorVersionEl, technicalCont); - KeyValues formats = MetaUIFactory.getFormats(); - formatEl = uifactory.addDropdownSingleselect("technical.format", "technical.format", technicalCont, - formats.getKeys(), formats.getValues(), null); - decorate(formatEl, technicalCont); + versionEl = uifactory.addTextElement("lifecycle.version", "lifecycle.version", 50, null, technicalCont); + decorate(versionEl, technicalCont); + + KeyValues status = MetaUIFactory.getStatus(getTranslator()); + statusEl = uifactory.addDropdownSingleselect("lifecycle.status", "lifecycle.status", technicalCont, + status.getKeys(), status.getValues(), null); + decorate(statusEl, technicalCont); ; } private void initRightsForm(FormItemContainer formLayout) { @@ -312,20 +285,15 @@ public class MetadataBulkChangeController extends FormBasicController { allOk &= validateElementLogic(addInfosEl, addInfosEl.getMaxLength(), false, isEnabled(addInfosEl)); allOk &= validateElementLogic(languageEl, languageEl.getMaxLength(), true, isEnabled(languageEl)); - //educational + //question allOk &= validateBigDecimal(difficultyEl, 0.0d, 1.0d, true); allOk &= validateBigDecimal(stdevDifficultyEl, 0.0d, 1.0d, true); allOk &= validateBigDecimal(differentiationEl, -1.0d, 1.0d, true); - //lifecycle + //technical allOk &= validateElementLogic(versionEl, versionEl.getMaxLength(), true, isEnabled(versionEl)); allOk &= validateSelection(statusEl, isEnabled(statusEl)); - //technical - allOk &= validateElementLogic(editorEl, editorEl.getMaxLength(), true, isEnabled(editorEl)); - allOk &= validateElementLogic(editorVersionEl, editorVersionEl.getMaxLength(), true, isEnabled(editorVersionEl)); - allOk &= validateSelection(formatEl, isEnabled(formatEl)); - //rights allOk &= validateRights(copyrightEl, descriptionEl, licenseKeys, isEnabled(rightsWrapperCont)); @@ -344,9 +312,7 @@ public class MetadataBulkChangeController extends FormBasicController { if(fullItem instanceof QuestionItemImpl) { QuestionItemImpl itemImpl = (QuestionItemImpl)fullItem; formOKGeneral(itemImpl); - formOKEducational(itemImpl); formOKQuestion(itemImpl); - formOKLifecycle(itemImpl); formOKTechnical(itemImpl); if(isEnabled(rightsWrapperCont)) { RightsMetadataEditController.formOKRights(itemImpl, copyrightEl, descriptionEl, licenseKeys, qpoolService); @@ -376,7 +342,12 @@ public class MetadataBulkChangeController extends FormBasicController { } } - private void formOKEducational(QuestionItemImpl itemImpl) { + private void formOKQuestion(QuestionItemImpl itemImpl) { + if(isEnabled(typeEl) && typeEl.isOneSelected()) { + String typeKey = typeEl.getSelectedKey(); + itemImpl.setType(qpoolService.getItemType(typeKey)); + } + if(isEnabled(contextEl)) { if(contextEl.isOneSelected()) { QEducationalContext context = qpoolService.getEducationlContextByLevel(contextEl.getSelectedKey()); @@ -394,13 +365,6 @@ public class MetadataBulkChangeController extends FormBasicController { String timeStr = MetadataConverterHelper.convertDuration(day, hour, minute, seconds); itemImpl.setEducationalLearningTime(timeStr); } - } - - private void formOKQuestion(QuestionItemImpl itemImpl) { - if(isEnabled(typeEl) && typeEl.isOneSelected()) { - String typeKey = typeEl.getSelectedKey(); - itemImpl.setType(qpoolService.getItemType(typeKey)); - } if(isEnabled(difficultyEl)) itemImpl.setDifficulty(toBigDecimal(difficultyEl.getValue())); @@ -416,22 +380,13 @@ public class MetadataBulkChangeController extends FormBasicController { } } - private void formOKLifecycle(QuestionItemImpl itemImpl) { + private void formOKTechnical(QuestionItemImpl itemImpl) { if(isEnabled(statusEl) && statusEl.isOneSelected()) itemImpl.setStatus(statusEl.getSelectedKey()); if(isEnabled(versionEl)) itemImpl.setItemVersion(versionEl.getValue()); } - private void formOKTechnical(QuestionItemImpl itemImpl) { - if(isEnabled(editorEl)) - itemImpl.setEditor(editorEl.getValue()); - if(isEnabled(editorVersionEl)) - itemImpl.setEditorVersion(editorVersionEl.getValue()); - if(isEnabled(formatEl) && formatEl.isOneSelected()) - itemImpl.setFormat(formatEl.getSelectedKey()); - } - @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); diff --git a/src/main/java/org/olat/modules/qpool/ui/metadata/_content/bulk_change.html b/src/main/java/org/olat/modules/qpool/ui/metadata/_content/bulk_change.html index 0063db30afe..413fccfdb15 100644 --- a/src/main/java/org/olat/modules/qpool/ui/metadata/_content/bulk_change.html +++ b/src/main/java/org/olat/modules/qpool/ui/metadata/_content/bulk_change.html @@ -2,15 +2,9 @@ $r.contextHelpWithWrapper("Data Management#qb_change_md")<br/> <fieldset><legend>$r.translate("general")</legend> $r.render("general") </fieldset> -<fieldset><legend>$r.translate("educational")</legend> - $r.render("educational") -</fieldset> <fieldset><legend>$r.translate("question")</legend> $r.render("question") </fieldset> -<fieldset><legend>$r.translate("lifecycle")</legend> - $r.render("lifecycle") -</fieldset> <fieldset><legend>$r.translate("technical")</legend> $r.render("technical") </fieldset> -- GitLab