@@ -150,6 +150,7 @@ async function handleBookmarkSelect(bookmark: BookmarkRead) {
multiline
action-key="createBookmark"
:title="$t('browse.bookmarks.commentModalTitle')"
+ :icon="BookmarksIcon"
:input-label="$t('browse.bookmarks.commentModalInputLabel')"
:rows="3"
:validation-rules="bookmarkFormRules.comment"
diff --git a/Tekst-Web/src/components/browse/ContentHeaderWidgetBar.vue b/Tekst-Web/src/components/browse/ContentHeaderWidgetBar.vue
index 75cab1b1..a8dc6429 100644
--- a/Tekst-Web/src/components/browse/ContentHeaderWidgetBar.vue
+++ b/Tekst-Web/src/components/browse/ContentHeaderWidgetBar.vue
@@ -9,6 +9,7 @@ import type { AnyResourceRead } from '@/api';
import ContentCommentWidget from '@/components/resource/ContentCommentWidget.vue';
import ContentEditWidget from '@/components/resource/ContentEditWidget.vue';
import ResourceExportWidget from '@/components/resource/ResourceExportWidget.vue';
+import CorrectionNoteWidget from '@/components/resource/CorrectionNoteWidget.vue';
withDefaults(
defineProps<{
@@ -48,8 +49,9 @@ const browse = useBrowseStore();
:resource="resource"
/>
-
+
+
diff --git a/Tekst-Web/src/components/editors/WysiwygEditor.vue b/Tekst-Web/src/components/editors/WysiwygEditor.vue
index 0047a158..be6a5603 100644
--- a/Tekst-Web/src/components/editors/WysiwygEditor.vue
+++ b/Tekst-Web/src/components/editors/WysiwygEditor.vue
@@ -213,6 +213,7 @@ function handleAddLinkClick() {
actionKey: 'addLink',
initialValue: editor.value?.getAttributes('link').href,
title: $t('wysiwyg.linkPrompt.title'),
+ icon: LinkIcon,
inputLabel: $t('wysiwyg.linkPrompt.inputLabel'),
validationRules: wysiwygEditorFormRules.linkUrl,
});
@@ -222,6 +223,7 @@ async function handleAddImageClick() {
promptModalRef.value.open({
actionKey: 'addImage',
title: $t('wysiwyg.imagePrompt.title'),
+ icon: ImageIcon,
inputLabel: $t('wysiwyg.imagePrompt.inputLabel'),
disableOkWhenNoValue: true,
validationRules: wysiwygEditorFormRules.imageUrl,
diff --git a/Tekst-Web/src/components/generic/PromptModal.vue b/Tekst-Web/src/components/generic/PromptModal.vue
index 2f764cc9..958ccff4 100644
--- a/Tekst-Web/src/components/generic/PromptModal.vue
+++ b/Tekst-Web/src/components/generic/PromptModal.vue
@@ -2,6 +2,7 @@
import {
NButton,
NInput,
+ NAlert,
NFormItem,
type InputInst,
type FormItemRule,
@@ -9,17 +10,23 @@ import {
type FormItemInst,
} from 'naive-ui';
import ButtonShelf from './ButtonShelf.vue';
-import { ref } from 'vue';
+import { ref, type Component } from 'vue';
import GenericModal from '@/components/generic/GenericModal.vue';
import { $t } from '@/i18n';
import { useMessages } from '@/composables/messages';
+import NInputOsk from '@/components/NInputOsk.vue';
+import { shallowRef } from 'vue';
export interface PromptModalProps {
actionKey?: string;
initialValue?: string;
+ msg?: string;
+ icon?: Component;
inputLabel?: string;
title?: string;
multiline?: boolean;
+ osk?: boolean;
+ font?: string;
placeholder?: string;
rows?: number;
disableOkWhenNoValue?: boolean;
@@ -29,15 +36,19 @@ export interface PromptModalProps {
const props = withDefaults(defineProps(), {
actionKey: undefined,
initialValue: undefined,
+ msg: undefined,
+ icon: undefined,
inputLabel: undefined,
title: undefined,
multiline: false,
+ osk: false,
+ font: undefined,
placeholder: '',
rows: undefined,
disableOkWhenNoValue: false,
validationRules: undefined,
});
-const liveProps = ref(props);
+const liveProps = shallowRef(props);
const emit = defineEmits(['submit', 'afterLeave']);
defineExpose({ open });
@@ -85,6 +96,7 @@ function handleInputReturn(e: KeyboardEvent) {
{
close();
@@ -93,6 +105,9 @@ function handleInputReturn(e: KeyboardEvent) {
"
@after-enter="inputRef?.select()"
>
+
+ {{ liveProps.msg }}
+
+
diff --git a/Tekst-Web/src/components/navigation/DrawerMenu.vue b/Tekst-Web/src/components/navigation/DrawerMenu.vue
index 4b616471..fcee95ed 100644
--- a/Tekst-Web/src/components/navigation/DrawerMenu.vue
+++ b/Tekst-Web/src/components/navigation/DrawerMenu.vue
@@ -14,6 +14,7 @@ import {
} from '@/components/navigation/navMenuOptions';
import { $t } from '@/i18n';
import { useAuthStore } from '@/stores';
+import { usePlatformData } from '@/composables/platformData';
withDefaults(
defineProps<{
@@ -27,6 +28,8 @@ withDefaults(
const show = defineModel('show');
const auth = useAuthStore();
+const { pfData } = usePlatformData();
+
const { menuOptions: mainMenuOptions } = useMainMenuOptions();
const { menuOptions: accountMenuOptions } = useAccountMenuOptions();
const { menuOptions: adminMenuOptions } = useAdminMenuOptions();
@@ -35,7 +38,7 @@ const allMenuOptions = computed(() => [
{
type: 'group',
key: 'general-group',
- label: $t('general.platform'),
+ label: pfData.value?.settings.platformName || $t('general.platform'),
children: mainMenuOptions.value.filter((o) => o.key !== 'info'),
},
...(mainMenuOptions.value.find((o) => o.key === 'info')?.children?.length
diff --git a/Tekst-Web/src/components/navigation/PrimaryNavBar.vue b/Tekst-Web/src/components/navigation/PrimaryNavBar.vue
index adacba33..b6f28672 100644
--- a/Tekst-Web/src/components/navigation/PrimaryNavBar.vue
+++ b/Tekst-Web/src/components/navigation/PrimaryNavBar.vue
@@ -1,25 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ gotoUserProfile(e, correction.userId)"
+ >
+
+
+
+
+ deleteCorrection(e, correction.id)"
+ >
+
+
+
+
+
+
+
+
+
+
+
+ {{ correction.note }}
+
+
+
+
+
diff --git a/Tekst-Web/src/components/resource/CorrectionNoteWidget.vue b/Tekst-Web/src/components/resource/CorrectionNoteWidget.vue
new file mode 100644
index 00000000..8bd27e67
--- /dev/null
+++ b/Tekst-Web/src/components/resource/CorrectionNoteWidget.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+ handleModalSubmit(v)"
+ />
+
diff --git a/Tekst-Web/src/components/resource/ResourceListItem.vue b/Tekst-Web/src/components/resource/ResourceListItem.vue
index 29e7bf97..6e4fd96e 100644
--- a/Tekst-Web/src/components/resource/ResourceListItem.vue
+++ b/Tekst-Web/src/components/resource/ResourceListItem.vue
@@ -8,17 +8,19 @@ import {
NListItem,
NThing,
NButton,
+ NBadge,
type DropdownOption,
} from 'naive-ui';
import { computed } from 'vue';
import ResourceInfoWidget from '@/components/resource/ResourceInfoWidget.vue';
import ResourcePublicationStatus from '@/components/resource/ResourcePublicationStatus.vue';
import TranslationDisplay from '@/components/generic/TranslationDisplay.vue';
-import { useStateStore } from '@/stores';
+import { useResourcesStore, useStateStore } from '@/stores';
import { $t } from '@/i18n';
import ResourceIsVersionInfo from '@/components/resource/ResourceIsVersionInfo.vue';
import UserDisplay from '@/components/user/UserDisplay.vue';
import ResourceExportWidget from '@/components/resource/ResourceExportWidget.vue';
+import ContentContainerHeaderWidget from '@/components/browse/ContentContainerHeaderWidget.vue';
import {
MoreIcon,
@@ -33,8 +35,10 @@ import {
VersionIcon,
DownloadIcon,
UploadIcon,
+ CorrectionNoteIcon,
} from '@/icons';
import { pickTranslation, renderIcon } from '@/utils';
+import { useRouter } from 'vue-router';
const props = defineProps<{
targetResource: AnyResourceRead;
@@ -57,6 +61,8 @@ const emit = defineEmits([
]);
const state = useStateStore();
+const router = useRouter();
+const resources = useResourcesStore();
const isOwner = computed(() => (props.currentUser?.id ?? 'noid') === props.targetResource.ownerId);
const isOwnerOrAdmin = computed(() => isOwner.value || !!props.currentUser?.isSuperuser);
@@ -192,6 +198,13 @@ const actionOptions = computed(() => [
function handleActionSelect(o: DropdownOption & { action?: () => void }) {
o.action?.();
}
+
+function handleCorrectionsClick() {
+ router.push({
+ name: 'resourceCorrections',
+ params: { text: state.text?.slug, id: props.targetResource.id },
+ });
+}
@@ -204,6 +217,17 @@ function handleActionSelect(o: DropdownOption & { action?: () => void }) {
+
+
+
= {
label: [requiredRule(() => $t('models.location.label'), 'blur'), minMaxCharsRule(1, 256, 'blur')],
};
+export const correctionFormRules: Record = {
+ note: [requiredRule(() => $t('models.location.label'), 'blur'), minMaxCharsRule(1, 256, 'blur')],
+};
+
export const systemSegmentFormRules: Record = {
title: [minMaxCharsRule(0, 32, 'blur')],
key: [requiredRule(() => $t('models.segment.key'), 'blur')],
diff --git a/Tekst-Web/src/icons.ts b/Tekst-Web/src/icons.ts
index fd835ef3..f201b6b5 100644
--- a/Tekst-Web/src/icons.ts
+++ b/Tekst-Web/src/icons.ts
@@ -110,8 +110,10 @@ import WarningOutlined from '@vicons/material/WarningOutlined';
import RefreshOutlined from '@vicons/material/RefreshOutlined';
import PlayArrowFilled from '@vicons/material/PlayArrowFilled';
import PauseFilled from '@vicons/material/PauseFilled';
+import PanToolAltOutlined from '@vicons/material/PanToolAltOutlined';
export {
+ PanToolAltOutlined as CorrectionNoteIcon,
PauseFilled as PauseIcon,
PlayArrowFilled as PlayIcon,
WarningOutlined as WarningIcon,
diff --git a/Tekst-Web/src/router.ts b/Tekst-Web/src/router.ts
index 4d8afcc1..0adc8204 100644
--- a/Tekst-Web/src/router.ts
+++ b/Tekst-Web/src/router.ts
@@ -24,6 +24,7 @@ const ResourcesView = () => import('@/views/ResourcesView.vue');
const ResourceSettingsView = () => import('@/views/ResourceSettingsView.vue');
const ResourceCreateView = () => import('@/views/ResourceCreateView.vue');
const ContentsView = () => import('@/views/ContentsView.vue');
+const CorrectionsView = () => import('@/views/CorrectionsView.vue');
const CommunityView = () => import('@/views/CommunityView.vue');
const AccountView = () => import('@/views/account/AccountView.vue');
@@ -182,6 +183,15 @@ const router = createRouter({
restricted: 'user',
},
},
+ {
+ path: '/text/:text?/resources/:id/corrections',
+ name: 'resourceCorrections',
+ component: CorrectionsView,
+ meta: {
+ isTextSpecific: true,
+ restricted: 'user',
+ },
+ },
{
path: '/account',
name: 'account',
diff --git a/Tekst-Web/src/stores/resources.ts b/Tekst-Web/src/stores/resources.ts
index 8124723e..a7001b8c 100644
--- a/Tekst-Web/src/stores/resources.ts
+++ b/Tekst-Web/src/stores/resources.ts
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { computed, ref, watch } from 'vue';
-import { GET, type AnyResourceRead, type ResourceCoverage } from '@/api';
+import { type CorrectionRead, GET, type AnyResourceRead, type ResourceCoverage } from '@/api';
import { useAuthStore, useStateStore } from '@/stores';
import { hashCode } from '@/utils';
@@ -12,6 +12,13 @@ export const useResourcesStore = defineStore('resources', () => {
const resourcesOfText = computed(() =>
resourcesAll.value.filter((r) => r.textId === state.text?.id)
);
+ const corrections = ref>({});
+ const correctionsCount = computed>(() =>
+ Object.fromEntries(resourcesAll.value.map((r) => [r.id, r.corrections || 0]))
+ );
+ const correctionsCountTotal = computed(() =>
+ Object.values(correctionsCount.value).reduce((a, b) => a + b, 0)
+ );
const dataHash = computed(() => hashCode(resourcesAll.value));
const error = ref(false);
@@ -47,9 +54,21 @@ export const useResourcesStore = defineStore('resources', () => {
} else {
error.value = true;
}
+ corrections.value = {};
loading.value = false;
}
+ async function loadCorrections(resourceId: string) {
+ const { data, error } = await GET('/corrections/{resourceId}', {
+ params: { path: { resourceId } },
+ });
+ if (!error) {
+ corrections.value[resourceId] = data.sort((a, b) => Date.parse(b.date) - Date.parse(a.date));
+ } else {
+ corrections.value[resourceId] = [];
+ }
+ }
+
function replace(resource: AnyResourceRead) {
if (resourcesAll.value.find((re) => re.id === resource.id)) {
resourcesAll.value = sortResources(
@@ -115,6 +134,10 @@ export const useResourcesStore = defineStore('resources', () => {
return {
all: resourcesAll,
ofText: resourcesOfText,
+ correctionsCount,
+ correctionsCountTotal,
+ corrections,
+ loadCorrections,
dataHash,
error,
loading,
diff --git a/Tekst-Web/src/views/ContentsView.vue b/Tekst-Web/src/views/ContentsView.vue
index 232e58d5..4c72a3e5 100644
--- a/Tekst-Web/src/views/ContentsView.vue
+++ b/Tekst-Web/src/views/ContentsView.vue
@@ -6,6 +6,10 @@ import {
NFlex,
NForm,
NButton,
+ NCollapseItem,
+ NCollapse,
+ NList,
+ NBadge,
type FormInst,
useDialog,
} from 'naive-ui';
@@ -38,6 +42,7 @@ import { dialogProps } from '@/common';
import LocationSelectModal from '@/components/modals/LocationSelectModal.vue';
import contentComponents from '@/components/content/mappings';
import LocationLabel from '@/components/LocationLabel.vue';
+import CorrectionListItem from '@/components/resource/CorrectionListItem.vue';
import {
EditNoteIcon,
@@ -116,6 +121,12 @@ const loading = computed(
() => resources.loading || loadingDelete.value || loadingSave.value || loadingData.value
);
+const corrections = computed(
+ () =>
+ resources.corrections[resource.value?.id || '']?.filter((c) => c.position === position.value) ||
+ []
+);
+
// go to resource overview if text changes
watch(
() => state.text,
@@ -490,6 +501,25 @@ async function handleNearestChangeClick(mode: 'preceding' | 'subsequent') {
+
+
+
+
+ {{ $t('contents.correctionNotes') }}
+
+
+
+
+
+
+
+
+import IconHeading from '@/components/generic/IconHeading.vue';
+import { ArrowBackIcon, CorrectionNoteIcon, NoContentIcon } from '@/icons';
+import { $t } from '@/i18n';
+import { useResourcesStore, useStateStore } from '@/stores';
+import { computed, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { pickTranslation } from '@/utils';
+import { NButton, NIcon, NList } from 'naive-ui';
+import { RouterLink } from 'vue-router';
+import HugeLabelledIcon from '@/components/generic/HugeLabelledIcon.vue';
+import { onBeforeMount } from 'vue';
+import CorrectionListItem from '@/components/resource/CorrectionListItem.vue';
+
+const state = useStateStore();
+const resources = useResourcesStore();
+const route = useRoute();
+const router = useRouter();
+
+const resourceId = computed(() => route.params.id.toString());
+const resource = computed(() =>
+ route.params.id ? resources.ofText.find((r) => r.id === resourceId.value) : undefined
+);
+const resourceTitle = computed(() => pickTranslation(resource.value?.title, state.locale));
+
+// change route if text changes
+watch(
+ () => state.text,
+ (newText) => {
+ router.push({ name: 'resources', params: { text: newText?.slug } });
+ }
+);
+
+onBeforeMount(async () => {
+ await resources.loadCorrections(route.params.id.toString());
+});
+
+
+
+
+ {{ $t('corrections.heading', { title: resourceTitle }) }}
+
+
+
+
+
+
+
+ {{ $t('resources.backToOverview') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tekst-Web/src/views/ResourcesView.vue b/Tekst-Web/src/views/ResourcesView.vue
index 1cb786d1..bab7a623 100644
--- a/Tekst-Web/src/views/ResourcesView.vue
+++ b/Tekst-Web/src/views/ResourcesView.vue
@@ -19,7 +19,7 @@ import {
GET,
withSelectedFile,
} from '@/api';
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
import { computed } from 'vue';
import { $t } from '@/i18n';
import { useAuthStore, useStateStore } from '@/stores';
@@ -100,7 +100,9 @@ const filteredData = computed(() => filterData(resources.ofText));
const paginatedData = computed(() => {
const start = (pagination.value.page - 1) * pagination.value.pageSize;
const end = start + pagination.value.pageSize;
- return filteredData.value.slice(start, end);
+ return filteredData.value
+ .slice(start, end)
+ .sort((a, b) => (b.corrections || 0) - (a.corrections || 0));
});
async function handleTransferClick(resource: AnyResourceRead) {
@@ -348,6 +350,16 @@ function handleFilterCollapseItemClick(data: { name: string; expanded: boolean }
filters.value = initialFilters();
}
}
+
+onMounted(() => {
+ // inform user in case there are corrections for resources of another text
+ if (
+ !resources.ofText.some((r) => !!r.corrections) &&
+ resources.all.filter((r) => r.textId !== state.text?.id).some((r) => !!r.corrections)
+ ) {
+ message.info($t('resources.msgCorrections'));
+ }
+});
diff --git a/Tekst-Web/src/views/UserView.vue b/Tekst-Web/src/views/UserView.vue
index 159b0751..b414755b 100644
--- a/Tekst-Web/src/views/UserView.vue
+++ b/Tekst-Web/src/views/UserView.vue
@@ -15,7 +15,7 @@ const auth = useAuthStore();
const state = useStateStore();
const userMessages = useUserMessagesStore();
-const username = computed(() => {
+const usernameOrId = computed(() => {
if (route.name) {
if (route.name === 'user' && route.params.username) {
return String(route.params.username);
@@ -25,7 +25,7 @@ const username = computed(() => {
}
return '';
});
-const { user, error } = useProfile(username);
+const { user, error } = useProfile(usernameOrId);
function handleSendUserMessage() {
if (!user.value || !auth.loggedIn) return;
@@ -41,7 +41,7 @@ function handleSendUserMessage() {
}
watch(
- () => username.value,
+ () => usernameOrId.value,
(newUsername) => {
state.setPageTitle(route, { username: newUsername });
},
@@ -93,6 +93,6 @@ watch(
Oops... {{ $t('errors.error') }}!
- {{ $t('account.profileNotFound', { username }) }}
+ {{ $t('account.profileNotFound', { usernameOrId }) }}
diff --git a/Tekst-Web/src/views/account/AccountSettingsView.vue b/Tekst-Web/src/views/account/AccountSettingsView.vue
index 2b538b75..b88bf697 100644
--- a/Tekst-Web/src/views/account/AccountSettingsView.vue
+++ b/Tekst-Web/src/views/account/AccountSettingsView.vue
@@ -50,10 +50,12 @@ const initialUserNotificationTriggersModel = () => ({
resourceProposed: !!auth.user?.userNotificationTriggers?.includes('resourceProposed'),
resourcePublished: !!auth.user?.userNotificationTriggers?.includes('resourcePublished'),
messageReceived: !!auth.user?.userNotificationTriggers?.includes('messageReceived'),
+ newCorrection: !!auth.user?.userNotificationTriggers?.includes('newCorrection'),
});
const initialAdminNotificationTriggersModel = () => ({
userAwaitsActivation: !!auth.user?.adminNotificationTriggers?.includes('userAwaitsActivation'),
+ newCorrection: !!auth.user?.adminNotificationTriggers?.includes('newCorrection'),
});
const initialPublicFieldsModel = () => ({
diff --git a/Tekst-Web/translations/ui/deDE.yml b/Tekst-Web/translations/ui/deDE.yml
index 289c0569..71fceca4 100644
--- a/Tekst-Web/translations/ui/deDE.yml
+++ b/Tekst-Web/translations/ui/deDE.yml
@@ -131,6 +131,7 @@ routes:
login: Anmeldung
register: '@:register.heading'
resources: Ressourcen zu "{text}"
+ resourcesCorrections: Korrekturnotizen
resourceSettings: '@:resources.settings.heading'
user: Profil von {username}
community: Gemeinschaft
@@ -182,6 +183,15 @@ browse:
widgets:
contentEdit:
title: Inhalt bearbeiten
+ correctionNote:
+ title: Korrekturnotiz zu dieser Fundstelle senden
+ heading: Korrekturnotiz senden
+ info: |
+ Sie haben eine kurze Anmerkung oder Korrektur zu diesem Inhalt?
+ Hier können Sie eine Korrektrnotiz verfassen. Die Person,
+ die für diese Ressource verantwortlich ist, wird darüber benachrichtigt!
+ lblNote: Korrekturnotiz
+ msgSuccess: Korrekturnotiz gesendet
deepLTranslate:
title: DeepL-Übersetzung öffnen
infoWidget:
@@ -340,12 +350,14 @@ resources:
Das bedeutet nicht, dass es eine gute Idee ist, dies zu tun. Bitte stellen Sie
sicher, dass jede Ihrer Änderungen im Einverständnis mit dem Besitzer dieser
Ressource geschieht!
+ msgCorrections: Es liegen Korrekturnotizen zu anderen Texten zur Prüfung für Sie vor.
ownedByMe: von mir
ownedByOthers: von anderen
public: '@:models.resource.public'
notPublic: '@:general.not @:models.resource.public'
proposed: '@:models.resource.proposed'
notProposed: '@:general.not @:models.resource.proposed'
+ correctionNotesAction: Korrekturnotizen anzeigen
transferAction: An Benutzer übertragen
settingsAction: Einstellungen
contentsAction: Inhalte
@@ -395,7 +407,7 @@ resources:
msgDeleted: Die Ressource "{title}" wurde gelöscht.
msgCreatedVersion: Eine neue Version der Ressource "{title}" wurde erstellt.
phSearchUsers: Benutzer suchen...
- backToOverview: Zurück zu "Ressourcen"
+ backToOverview: Gehe zur Ressourcen-Übersicht
create:
heading: Neue Ressource zu "{text}"
headingTypeAndLevel: Ressourcen-Typ und Ebene
@@ -492,6 +504,10 @@ resources:
searchFields:
text: Titel / Beschreibung
+corrections:
+ heading: Korrekturnotizen für "{title}"
+ msgDeleted: Korrekturnotiz wurde gelöscht
+
contents:
heading: Ressourcen-Inhalte bearbeiten
lblBtnCompare: Vergleichen
@@ -509,6 +525,7 @@ contents:
msgImportInfo: Der Import wird im Hintergrund verarbeitet. Dies kann eine Weile dauern.
msgNoNearest: Es gibt keine weiteren Fundstellen mit Inhalt in dieser Richtung.
confirmDelete: Sind Sie sicher, dass Sie den Inhalt für diese Fundstelle löschen möchten?
+ correctionNotes: Korrekturnotizen
msgNoOwnContentTitle: Kein eigner Inhalt für diese Fundstelle!
msgNoOwnContentBody: |
Diese Version von "{originalResourceTitle}" hat keinen eignen Inhalt für diese Fundstelle.
@@ -557,10 +574,12 @@ account:
resourceProposed: jemand eine Ressource zur Veröffentlichung vorschlägt (per Plattform-Nachricht)
resourcePublished: eine Ressource veröffentlicht wird (per Plattform-Nachricht)
messageReceived: ich eine Nachricht von einem anderen Benutzer erhalte (per Email)
+ newCorrection: eine neue Korrekturnotiz zu einer meiner Ressourcen erstellt wurde (per Email)
msgSaveSuccess: Einstellungen zu Email-Benachrichtigungen gespeichert.
adminNotificationTriggers:
heading: Benachrichtigungen für Administratoren
userAwaitsActivation: ein Benutzer auf die Aktivierung des Kontos wartet (per Email)
+ newCorrection: eine neue Korrekturnotiz zu einer öffentlichen Ressource erstellt wurde (per Email)
msgSaveSuccess: Einstellungen zu Benutzer-Email-Benachrichtigungen gespeichert.
msgEmailSaveSuccess: '@:models.user.email gespeichert.'
msgEmailChangeWarning: Stellen Sie sicher, dass Sie eine gültige @:models.user.email eingeben, auf die Sie Zugriff haben! Wenn Sie fortfahren, werden Sie abgemeldet und müssen Ihre geänderte @:models.users.email verifizieren, bevor Sie sich wieder anmelden können.
diff --git a/Tekst-Web/translations/ui/enUS.yml b/Tekst-Web/translations/ui/enUS.yml
index aa3ecd67..015e4b5f 100644
--- a/Tekst-Web/translations/ui/enUS.yml
+++ b/Tekst-Web/translations/ui/enUS.yml
@@ -128,6 +128,7 @@ routes:
register: '@:register.heading'
resources: Resources on "{text}"
resourceSettings: '@:resources.settings.heading'
+ resourcesCorrections: Correction notes
user: Profile of {username}
community: Community
accountProfile: '@:account.profileHeading'
@@ -178,6 +179,15 @@ browse:
widgets:
contentEdit:
title: Edit content
+ correctionNote:
+ title: Send correction note for this location
+ heading: Send correction note
+ info: |
+ Do you have a short comment or correction to this content?
+ You can write a correction note here. The person
+ responsible for this resource will be notified!
+ lblNote: Correction note
+ msgSuccess: Sent correction note
deepLTranslate:
title: Open DeepL translation
infoWidget:
@@ -336,12 +346,14 @@ resources:
As an administrator, you are able to modify resources owned by other users.
This doesn't mean it is a good idea to do so. Please make sure that whatever you
do happens in agreement with the owner of this resource!
+ msgCorrections: Correction notes on other texts are available for you to review.
ownedByMe: by me
ownedByOthers: by others
public: '@:models.resource.public'
notPublic: '@:general.not @:models.resource.public'
proposed: '@:models.resource.proposed'
notProposed: '@:general.not @:models.resource.proposed'
+ correctionNotesAction: Show correction notes
transferAction: Transfer to user
settingsAction: Settings
contentsAction: Contents
@@ -384,7 +396,7 @@ resources:
msgDeleted: The resource "{title}" has been deleted.
msgCreatedVersion: A new version of the resource "{title}" has been created.
phSearchUsers: Search for users...
- backToOverview: Back to "Resources"
+ backToOverview: Go to resources overview
create:
heading: New Resource on "{text}"
headingTypeAndLevel: Resource Type and Level
@@ -481,6 +493,10 @@ resources:
searchFields:
text: Title / Description
+corrections:
+ heading: Correction Notes for "{title}"
+ msgDeleted: Correction note has been deleted
+
contents:
heading: Edit Resource Content
lblBtnCompare: Compare
@@ -498,6 +514,7 @@ contents:
msgImportInfo: The import will be processed in the background. This might take a while.
msgNoNearest: There are no more locations holding content in this direction.
confirmDelete: Are you sure you want to delete the content for this location?
+ correctionNotes: Correction Notes
msgNoOwnContentTitle: No own content for this location!
msgNoOwnContentBody: |
This version of "{originalResourceTitle}" has no own content for this location.
@@ -546,10 +563,12 @@ account:
resourceProposed: someone proposes a resource for publication (via platform message)
resourcePublished: a resource is published (via platform message)
messageReceived: I receive a message from another user (via email)
+ newCorrection: a new correction note on one of my resources has been created (via email)
msgSaveSuccess: User notifications settings saved.
adminNotificationTriggers:
heading: Notifications for Administrators
userAwaitsActivation: a user is waiting for account activation (via email)
+ newCorrection: a new correction note on a public resource has been created (via email)
msgSaveSuccess: Administrator notifications settings saved.
msgEmailSaveSuccess: '@:models.user.email saved.'
msgEmailChangeWarning: Make sure you entered a valid email address you have access to! If you proceed, you will be logged out and have to verify your changed email address before you can log in again.