improve i18n, implement "add text block" dialog

This commit is contained in:
Mira Weller
2026-04-28 19:23:35 +02:00
parent bdc720f5a2
commit 3a1a6b988e
5 changed files with 103 additions and 37 deletions

View File

@@ -23,6 +23,8 @@
{% endblocktrans %}
</p>
{{ request.event.settings.locales|json_script:"event_locales" }}
<div id="questionnaires-editor">
<!-- Vue app mount point -->
</div>

View File

@@ -1,5 +1,8 @@
<script setup lang="ts">
import { ref, useId, defineProps } from 'vue';
import {get_event_locales} from "./api";
const locales = get_event_locales();
const props = defineProps(['value', 'id']);
@@ -8,7 +11,6 @@ if (!props.value) props.value = {};
<template>
<div class="i18n-form-group" :id="id">
<textarea cols="40" rows="2" lang="en" dir="ltr" class="form-control" title="Englisch" :id="`${id}_0`" placeholder="Englisch" v-model="value.en"></textarea>
<textarea cols="40" rows="2" lang="de" dir="ltr" class="form-control" title="Deutsch" :id="`${id}_1`" placeholder="Deutsch" v-model="value.de"></textarea>
<textarea v-for="locale in locales" cols="40" rows="2" :lang="locale" dir="ltr" class="form-control" title="Englisch" :id="`${id}_${locale}`" :placeholder="locale" v-model="value[locale]"></textarea>
</div>
</template>

View File

@@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import { i18n_any, QUESTION_TYPE, QUESTION_TYPE_LABEL, SYSTEM_DATAFIELDS } from './helper';
import NativeDialog from './NativeDialog.vue';
import I18nTextField from './I18nTextField.vue';
@@ -6,12 +6,13 @@ import { useId, ref } from 'vue'
const id = useId();
const props = defineProps(['question', 'datafields', 'editable'])
const emit = defineEmits(['removeSelf']);
const gettext = (window as any).gettext;
const df = typeof props.question.question === 'number' ?
props.datafields.find(el => el.id === props.question.question) :
typeof props.question.question === 'string' ?
SYSTEM_DATAFIELDS[props.question.question] :
{};
null;
if (!props.question.label) props.question.label = {};
if (!props.question.help_text) props.question.help_text = {};
@@ -25,28 +26,35 @@ const editor = ref();
<button class="btn btn-default"><i class="fa fa-arrows"></i></button>
<button class="btn btn-default" @click="editor.show()"><i class="fa fa-edit"></i></button>
</div></div>
<label class="col-md-3 control-label" :for="id" v-if="df.type !== QUESTION_TYPE.BOOLEAN">
{{ i18n_any(question.label) }}
</label>
<div v-else class="col-md-3 control-label label-empty"></div>
<div class="col-md-9">
<input :id="id" type="text" v-if="df.type === QUESTION_TYPE.STRING" class="form-control">
<textarea :id="id" v-if="df.type === QUESTION_TYPE.TEXT" class="form-control"></textarea>
<div class="checkbox" v-if="df.type === QUESTION_TYPE.BOOLEAN">
<label :for="id">
<input :id="id" type="checkbox"> {{ i18n_any(question.label) }}
</label>
</div>
<input :id="id" type="number" v-if="df.type === QUESTION_TYPE.NUMBER" class="form-control">
<input :id="id" type="file" v-if="df.type === QUESTION_TYPE.FILE" class="form-control">
<select :id="id"
v-if="df.type === QUESTION_TYPE.CHOICE || df.type === QUESTION_TYPE.CHOICE_MULTIPLE"
:multiple="df.type === QUESTION_TYPE.CHOICE_MULTIPLE" class="form-control">
<option></option>
<option v-for="opt in question.options">{{ i18n_any(opt.answer) }}</option>
</select>
<div class="help-block">{{ i18n_any(question.help_text) }}</div>
</div>
<template v-if="df">
<label class="col-md-3 control-label" :for="id" v-if="df.type !== QUESTION_TYPE.BOOLEAN">
{{ i18n_any(question.label) }}
</label>
<div v-else class="col-md-3 control-label label-empty"></div>
<div class="col-md-9">
<input :id="id" type="text" v-if="df.type === QUESTION_TYPE.STRING" class="form-control">
<textarea :id="id" v-if="df.type === QUESTION_TYPE.TEXT" class="form-control"></textarea>
<div class="checkbox" v-if="df.type === QUESTION_TYPE.BOOLEAN">
<label :for="id">
<input :id="id" type="checkbox"> {{ i18n_any(question.label) }}
</label>
</div>
<input :id="id" type="number" v-if="df.type === QUESTION_TYPE.NUMBER" class="form-control">
<input :id="id" type="file" v-if="df.type === QUESTION_TYPE.FILE" class="form-control">
<select :id="id"
v-if="df.type === QUESTION_TYPE.CHOICE || df.type === QUESTION_TYPE.CHOICE_MULTIPLE"
:multiple="df.type === QUESTION_TYPE.CHOICE_MULTIPLE" class="form-control">
<option></option>
<option v-for="opt in question.options">{{ i18n_any(opt.answer) }}</option>
</select>
<div class="help-block">{{ i18n_any(question.help_text) }}</div>
</div>
</template>
<div v-else class="col-md-12">
<h3>{{ i18n_any(question.label) }}</h3>
<p>{{ i18n_any(question.help_text) }}</p>
</div>
</div>
@@ -55,7 +63,7 @@ const editor = ref();
title="Edit question">
<div class="form-group">
<label class="col-md-3 control-label">
Question
{{ gettext('Question') }}
</label>
<div class="col-md-9">
<I18nTextField :value="question.label"/>
@@ -63,7 +71,7 @@ const editor = ref();
</div>
<div class="form-group">
<label class="col-md-3 control-label">
Help text
{{ gettext('Help text') }}
</label>
<div class="col-md-9">
<I18nTextField :value="question.help_text"/>

View File

@@ -4,6 +4,14 @@ import Question from "./Question.vue";
import {i18n_any, QUESTION_TYPE, QUESTION_TYPE_LABEL} from "./helper";
import I18nTextField from "./I18nTextField.vue";
import NativeDialog from "./NativeDialog.vue";
const dlgEditor = ref();
const dlgAddExisting = ref();
const dlgAddTextblock = ref();
const newTextblockTitle = ref();
const newTextblockText = ref();
const id = useId();
const props = defineProps(['questionnaire', 'datafields', 'selected_product', 'items'])
const gettext = (window as any).gettext
@@ -29,12 +37,27 @@ function addExistingDatafield(field) {
dlgAddExisting.value.close();
}
function showAddTextblockDialog() {
newTextblockTitle.value = {};
newTextblockText.value = {};
dlgAddTextblock.value.show();
}
function addTextblock() {
props.questionnaire.children.push({
question: null,
required: false,
label: newTextblockTitle.value,
help_text: newTextblockText.value,
dependency_question: null,
dependency_values: [],
});
dlgAddTextblock.value.close();
}
const isHidden = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) === -1);
const isEditable = computed(() => props.selected_product && props.questionnaire.items.indexOf(props.selected_product) !== -1);
const dlgEditor = ref();
const dlgAddExisting = ref();
</script>
@@ -62,10 +85,9 @@ const dlgAddExisting = ref();
</div>
<p v-if="true">
<button class="btn btn-default" @click="dlgAddExisting.show()"><i class="fa fa-plus"></i> Bestehendes Datenfeld hinzufügen</button>
<button class="btn btn-default" @click="newDatafield()"><i class="fa fa-plus"></i> Neues Datenfeld</button>
<button class="btn btn-default" @click="addSubtitle()"><i class="fa fa-plus"></i> Zwischenüberschrift</button>
<button class="btn btn-default" @click="addTextBlock()"><i class="fa fa-plus"></i> Text</button>
<button class="btn btn-default" @click="dlgAddExisting.show()"><i class="fa fa-plus"></i> {{ gettext('Existing data field') }}</button>
<button class="btn btn-default" @click="newDatafield()"><i class="fa fa-plus"></i> {{ gettext('New data field') }}</button>
<button class="btn btn-default" @click="showAddTextblockDialog()"><i class="fa fa-plus"></i> {{ gettext('Text') }}</button>
</p>
</div>
</details>
@@ -94,7 +116,7 @@ const dlgAddExisting = ref();
</div>
</div>
<button @click="dlgEditor.close()" class="btn btn-primary pull-right"><span class="fa fa-check"></span> {{ gettext('Save and close') }}</button>
<button class="btn btn-default">Delete</button>
<button class="btn btn-default">{{ gettext('Delete') }}</button>
</NativeDialog>
<NativeDialog ref="dlgAddExisting" class="modal-card"
@@ -104,7 +126,31 @@ const dlgAddExisting = ref();
<a href="javascript:" @click="addExistingDatafield(field)" v-for="field in datafields" class="list-group-item">{{ field.internal_name }}</a>
</div>
<button @click="dlgAddExisting.close()" class="btn btn-default pull-right">Cancel</button>
<button @click="dlgAddExisting.close()" class="btn btn-default pull-right">{{ gettext('Cancel') }}</button>
</NativeDialog>
<NativeDialog ref="dlgAddTextblock" class="modal-card"
:title="gettext('Add sub heading')">
<div class="form-group">
<label class="col-md-3 control-label">
{{ gettext('Title') }}
</label>
<div class="col-md-9">
<I18nTextField :value="newTextblockTitle"/>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
{{ gettext('Text') }}
</label>
<div class="col-md-9">
<I18nTextField :value="newTextblockText"/>
</div>
</div>
<button @click="addTextblock()" class="btn btn-default pull-right">{{ gettext('OK') }}</button>
<button @click="dlgAddTextblock.close()" class="btn btn-default pull-right">{{ gettext('Cancel') }}</button>
</NativeDialog>
</Teleport>
</template>

View File

@@ -12,3 +12,11 @@ export async function get_questionnaires() {
export async function get_items() {
return await (await fetch(`/api/v1/organizers/${organizer_slug}/events/${event_slug}/items/`)).json();
}
function get_json_script_value(id) {
return JSON.parse(document.getElementById(id).innerText);
}
export function get_event_locales() {
return get_json_script_value('event_locales');
}