From e621ff4d933bbf45d086f5d79a622f36fc184d01 Mon Sep 17 00:00:00 2001
From: Klaus-Dieter Quibeldey-Cirkel <klaus.quibeldey-cirkel@mni.thm.de>
Date: Sat, 2 Oct 2021 09:40:37 +0200
Subject: [PATCH] User statistics

---
 .../room-name-settings.component.html         |  4 +++
 .../create-comment.component.html             |  1 +
 .../create-comment.component.ts               |  3 +-
 .../comment-list/comment-list.component.html  |  3 +-
 .../comment-list/comment-list.component.ts    | 10 ++++++
 .../shared/comment/comment.component.html     | 33 +++++++++----------
 .../shared/comment/comment.component.scss     | 27 ++++++++++++---
 .../shared/comment/comment.component.ts       |  3 +-
 .../write-comment.component.html              | 22 ++++++++++++-
 .../write-comment.component.scss              | 10 ++++++
 .../write-comment/write-comment.component.ts  | 17 ++++++++--
 src/app/models/comment.ts                     |  3 ++
 src/app/services/http/comment.service.ts      |  2 +-
 src/app/services/util/room-data.service.ts    |  5 +--
 src/assets/i18n/creator/de.json               | 16 ++++++---
 src/assets/i18n/creator/en.json               | 14 +++++---
 src/assets/i18n/home/de.json                  |  6 ++--
 src/assets/i18n/home/en.json                  |  2 +-
 src/assets/i18n/participant/de.json           | 14 +++++---
 src/assets/i18n/participant/en.json           | 14 +++++---
 20 files changed, 156 insertions(+), 53 deletions(-)

diff --git a/src/app/components/creator/_dialogs/room-name-settings/room-name-settings.component.html b/src/app/components/creator/_dialogs/room-name-settings/room-name-settings.component.html
index 69cc54228..ea4d850ee 100644
--- a/src/app/components/creator/_dialogs/room-name-settings/room-name-settings.component.html
+++ b/src/app/components/creator/_dialogs/room-name-settings/room-name-settings.component.html
@@ -26,3 +26,7 @@
   [cancelButtonClickAction]="buildCloseDialogActionCallback()"
   [confirmButtonClickAction]="buildConfirmDialogActionCallback()"
 ></app-dialog-action-buttons>
+
+<div class="visually-hidden">
+  <div id="room-name">{{ 'room-page.a11y-room-name' | translate }}</div>
+</div>
diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html
index 25933dfdb..1c18a3975 100644
--- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.html
+++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.html
@@ -1,5 +1,6 @@
 <ars-row ars-flex-box>
   <app-write-comment [confirmLabel]="'send'"
+                     [isQuestionerNameEnabled]="true"
                      [onSubmit]="this.closeDialog.bind(this)"
                      [onClose]="this.onNoClick.bind(this)"
                      [isSpinning]="isSendingToSpacy"
diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
index ae82095d8..20b6adde4 100644
--- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
+++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
@@ -43,13 +43,14 @@ export class CreateCommentComponent implements OnInit {
     this.dialogRef.close();
   }
 
-  closeDialog(body: string, text: string, tag: string) {
+  closeDialog(body: string, text: string, tag: string, name: string) {
     const comment = new Comment();
     comment.roomId = localStorage.getItem(`roomId`);
     comment.body = body;
     comment.creatorId = this.user.id;
     comment.createdFromLecturer = this.user.role > 0;
     comment.tag = tag;
+    comment.questionerName = name;
     this.isSendingToSpacy = true;
     this.openSpacyDialog(comment, text);
   }
diff --git a/src/app/components/shared/comment-list/comment-list.component.html b/src/app/components/shared/comment-list/comment-list.component.html
index e3969fc56..c4a24b2ab 100644
--- a/src/app/components/shared/comment-list/comment-list.component.html
+++ b/src/app/components/shared/comment-list/comment-list.component.html
@@ -267,13 +267,14 @@
 <div *ngIf="!isLoading">
   <app-comment *ngFor="let current of hideCommentsList ? filteredComments : commentsFilteredByTime; let i = index"
                [appScrollIntoView]="current.id === focusCommentId"
-               [usesJoyride]="i === 0"
+               [usesJoyride]="i === 0 && isJoyrideActive"
                [comment]="current"
                [parseVote]="getVote(current)"
                [userRole]="userRole"
                [moderator]="false"
                [user]="user"
                [disabled]="!commentsEnabled"
+               [commentsWrittenByUser]="commentsWrittenByUsers.get(current.creatorId).size"
                (clickedOnTag)="clickedOnTag($event)"
                (clickedUserNumber)="clickedUserNumber($event)"
                (clickedOnKeyword)="clickedOnKeyword($event)"
diff --git a/src/app/components/shared/comment-list/comment-list.component.ts b/src/app/components/shared/comment-list/comment-list.component.ts
index 123708a47..2a746b20e 100644
--- a/src/app/components/shared/comment-list/comment-list.component.ts
+++ b/src/app/components/shared/comment-list/comment-list.component.ts
@@ -105,6 +105,7 @@ export class CommentListComponent implements OnInit, OnDestroy {
   isJoyrideActive = false;
   focusCommentId = '';
   activeUsers = 0;
+  commentsWrittenByUsers: Map<string, Set<string>> = new Map<string, Set<string>>();
   private _subscriptionEventServiceTagConfig = null;
   private _subscriptionEventServiceRoomData = null;
   private _subscriptionRoomService = null;
@@ -557,6 +558,15 @@ export class CommentListComponent implements OnInit, OnDestroy {
   }
 
   setComments(comments: Comment[]) {
+    this.commentsWrittenByUsers.clear();
+    for (const comment of this.comments) {
+      let set = this.commentsWrittenByUsers.get(comment.creatorId);
+      if (!set) {
+        set = new Set<string>();
+        this.commentsWrittenByUsers.set(comment.creatorId, set);
+      }
+      set.add(comment.id);
+    }
     this.commentsFilteredByTime = comments;
     this.titleService.attachTitle('(' + this.commentsFilteredByTime.length + ')');
   }
diff --git a/src/app/components/shared/comment/comment.component.html b/src/app/components/shared/comment/comment.component.html
index 66274a4ca..9324990e3 100644
--- a/src/app/components/shared/comment/comment.component.html
+++ b/src/app/components/shared/comment/comment.component.html
@@ -330,8 +330,8 @@
           &nbsp;{{comment.tag}}
         </span>
       </div>
-      <div class="user-number joyrideActive"
-           *ngIf="usesJoyride"
+      <div class="user-number"
+           [ngClass]="{'joyrideActive': usesJoyride, 'pin-active': commentsWrittenByUser > 1}"
            [joyrideStep]="'commentUserNumber'"
            [stepPosition]="'right'"
            appJoyrideTemplate
@@ -339,19 +339,11 @@
            matTooltip="{{ 'comment-page.user-number' | translate }}"
            (click)="this.clickedUserNumber.emit(comment.userNumber)">
         <mat-icon class="user-icon">person_pin_circle</mat-icon>
-        <strong>
-          {{comment.userNumber}}
-        </strong>
-      </div>
-      <div class="user-number"
-           *ngIf="!usesJoyride"
-           fxLayoutAlign="center center"
-           matTooltip="{{ 'comment-page.user-number' | translate }}"
-           (click)="this.clickedUserNumber.emit(comment.userNumber)">
-        <mat-icon class="user-icon">person_pin_circle</mat-icon>
-        <strong>
-          {{comment.userNumber}}
-        </strong>
+        <span *ngIf="commentsWrittenByUser > 1"
+              matBadge="{{commentsWrittenByUser}}"
+              matBadgeSize="small"
+              matBadgeOverlap="false">
+        </span>
       </div>
       <div fxLayoutAlign="center center"
            matTooltip="{{ 'comment-page.keywords-per-question' | translate }}"
@@ -360,10 +352,8 @@
            class="comment-keywords">
         <mat-icon svgIcon="hashtag" class="keyword-icon"></mat-icon>
         <span matBadge="{{comment.keywordsFromQuestioner.length}}" matBadgeSize="small" matBadgeOverlap="false">
-          {{ this.selectedKeyword === '' ? ('comment-page.keywords' | translate) : this.selectedKeyword}}
         </span>
         <mat-menu #keywordsMenu>
-
           <mat-list dense class="keywords-list">
             <mat-list-item
               *ngFor="let keyword of sortKeywords(comment.keywordsFromQuestioner); let odd = odd; let even = even"
@@ -376,6 +366,15 @@
       </div>
 
       <span class="fill-remaining-space"></span>
+      <div fxLayoutAlign="center center"
+           matTooltip="{{ 'comment-page.questioner-name' | translate }}"
+           *ngIf="comment.questionerName"
+           class="questioner-name">
+        <mat-icon>account_circle</mat-icon>
+        <span>
+          &nbsp;{{comment.questionerName}}
+        </span>
+      </div>
       <button mat-icon-button
               class="moderate-button"
               *ngIf="(isCreator || isModerator) && !inAnswerView"
diff --git a/src/app/components/shared/comment/comment.component.scss b/src/app/components/shared/comment/comment.component.scss
index 8dfd10262..5fb2990b5 100644
--- a/src/app/components/shared/comment/comment.component.scss
+++ b/src/app/components/shared/comment/comment.component.scss
@@ -191,9 +191,13 @@ mat-card-content > :first-child {
 .comment-keywords {
   cursor: pointer;
   color: var(--on-surface);
-  margin-left: 10px;
+  margin-right: 25px;
 }
 
+.questioner-name {
+  color: var(--secondary);
+  margin-right: 6px;
+}
 
 ::ng-deep .mat-menu-panel {
   min-height: 56px !important;
@@ -219,16 +223,30 @@ mat-card-content > :first-child {
 }
 
 .keyword-icon {
-  height: 18px !important;
+  margin-right: 2px;
+
+  + span {
+    transform: scale(1.2);
+  }
 }
 
 .mat-badge-content {
-  background: #fb9a1c;
+  background: var(--secondary);
+  color: var(--on-secondary);
 }
 
 .user-number {
   cursor: pointer;
   color: var(--on-surface);
+  margin-right: 7px;
+}
+
+.user-number.pin-active {
+  margin-right: 25px;
+
+  > span {
+    transform: scale(1.2);
+  }
 }
 
 .user-number.joyrideActive {
@@ -241,7 +259,8 @@ mat-card-content > :first-child {
 
 
 .user-icon {
-  margin-right: 5px;
+  margin-right: 2px;
+  transform: scale(1.3);
 }
 
 .voteUp {
diff --git a/src/app/components/shared/comment/comment.component.ts b/src/app/components/shared/comment/comment.component.ts
index 2cb0ddc08..a1838d4a8 100644
--- a/src/app/components/shared/comment/comment.component.ts
+++ b/src/app/components/shared/comment/comment.component.ts
@@ -44,6 +44,7 @@ export class CommentComponent implements OnInit, AfterViewInit {
   @Input() user: User;
   @Input() disabled = false;
   @Input() usesJoyride = false;
+  @Input() commentsWrittenByUser = 1;
   @Output() clickedOnTag = new EventEmitter<string>();
   @Output() clickedOnKeyword = new EventEmitter<string>();
   @Output() clickedUserNumber = new EventEmitter<number>();
@@ -63,9 +64,7 @@ export class CommentComponent implements OnInit, AfterViewInit {
   roleString: string;
   isExpanded = false;
   isExpandable = false;
-  selectedKeyword = '';
   filterProfanityForModerators = false;
-  createdBy;
 
   constructor(protected authenticationService: AuthenticationService,
     private route: ActivatedRoute,
diff --git a/src/app/components/shared/write-comment/write-comment.component.html b/src/app/components/shared/write-comment/write-comment.component.html
index 6caa97191..d1abcac23 100644
--- a/src/app/components/shared/write-comment/write-comment.component.html
+++ b/src/app/components/shared/write-comment/write-comment.component.html
@@ -50,7 +50,23 @@
                        [isEditor]="true"
                        [maxTextCharacters]="maxTextCharacters"
                        [maxDataCharacters]="maxDataCharacters"
-                       [placeHolderText]="placeholder"></app-view-comment-data>
+                       [placeHolderText]="placeholder">
+</app-view-comment-data>
+<mat-form-field class="questioner-name-input" *ngIf="isQuestionerNameEnabled && enabled">
+  <input (focus)="eventService.makeFocusOnInputTrue()"
+         (blur)="eventService.makeFocusOnInputFalse()"
+         matInput
+         [formControl]="questionerNameFormControl"
+         name="questioner-name"
+         maxlength="20"
+         aria-labelledby="questioner-name"/>
+  <mat-placeholder class="placeholder">{{ 'write-comment.questioner-name' | translate }}</mat-placeholder>
+  <mat-hint align="end"><span aria-hidden="true">{{ questionerNameFormControl.value.length }} / 20</span></mat-hint>
+  <mat-error *ngIf="questionerNameFormControl.hasError('minlength') ||
+                    questionerNameFormControl.hasError('maxlength')">
+    {{ 'write-comment.name-length-error' | translate }}
+  </mat-error>
+</mat-form-field>
 <ars-row ars-flex-box *ngIf="enabled" class="spellcheck">
   <ars-col>
     <button
@@ -77,3 +93,7 @@
     ></app-dialog-action-buttons>
   </ars-col>
 </ars-row>
+
+<div class="visually-hidden">
+  <div id="questioner-name">{{ 'write-comment.a11y-questioner-name' | translate }}</div>
+</div>
diff --git a/src/app/components/shared/write-comment/write-comment.component.scss b/src/app/components/shared/write-comment/write-comment.component.scss
index cdbad1813..62b32e611 100644
--- a/src/app/components/shared/write-comment/write-comment.component.scss
+++ b/src/app/components/shared/write-comment/write-comment.component.scss
@@ -1,3 +1,13 @@
+.questioner-name-input {
+  width: 100%;
+  max-width: 260px;
+  margin-top: -5px;
+
+  @media screen and (max-width: 500px) {
+    max-width: unset;
+  }
+}
+
 button {
   min-width: 80px;
 }
diff --git a/src/app/components/shared/write-comment/write-comment.component.ts b/src/app/components/shared/write-comment/write-comment.component.ts
index c9d7b8d94..3ae455018 100644
--- a/src/app/components/shared/write-comment/write-comment.component.ts
+++ b/src/app/components/shared/write-comment/write-comment.component.ts
@@ -9,6 +9,7 @@ import { ViewCommentDataComponent } from '../view-comment-data/view-comment-data
 import { DeepLService, SourceLang, TargetLang } from '../../../services/http/deep-l.service';
 import { DeepLDialogComponent } from '../_dialogs/deep-ldialog/deep-ldialog.component';
 import { MatDialog } from '@angular/material/dialog';
+import { FormControl, Validators } from '@angular/forms';
 
 @Component({
   selector: 'app-write-comment',
@@ -22,7 +23,7 @@ export class WriteCommentComponent implements OnInit {
   @Input() isModerator = false;
   @Input() tags: string[];
   @Input() onClose: () => any;
-  @Input() onSubmit: (commentData: string, commentText: string, selectedTag: string) => any;
+  @Input() onSubmit: (commentData: string, commentText: string, selectedTag: string, name?: string) => any;
   @Input() isSpinning = false;
   @Input() disableCancelButton = false;
   @Input() confirmLabel = 'save';
@@ -32,6 +33,7 @@ export class WriteCommentComponent implements OnInit {
   @Input() isCommentAnswer = false;
   @Input() placeholder = 'comment-page.enter-comment';
   @Input() i18nSection = 'comment-page';
+  @Input() isQuestionerNameEnabled = false;
   comment: Comment;
   selectedTag: string;
   maxTextCharacters = 500;
@@ -42,6 +44,9 @@ export class WriteCommentComponent implements OnInit {
   isSpellchecking = false;
   hasSpellcheckConfidence = true;
   newLang = 'auto';
+  questionerNameFormControl = new FormControl('', [
+    Validators.minLength(2), Validators.maxLength(20)
+  ]);
 
   constructor(private notification: NotificationService,
               private languageService: LanguageService,
@@ -77,9 +82,15 @@ export class WriteCommentComponent implements OnInit {
       return undefined;
     }
     return () => {
+      let allowed = true;
+      if (this.isQuestionerNameEnabled) {
+        this.questionerNameFormControl.setValue((this.questionerNameFormControl.value || '').trim());
+        allowed = !this.questionerNameFormControl.hasError('minlength') &&
+          !this.questionerNameFormControl.hasError('maxlength');
+      }
       if (ViewCommentDataComponent.checkInputData(this.commentData.currentData, this.commentData.currentText,
-        this.translateService, this.notification, this.maxTextCharacters, this.maxDataCharacters)) {
-        this.onSubmit(this.commentData.currentData, this.commentData.currentText, this.selectedTag);
+        this.translateService, this.notification, this.maxTextCharacters, this.maxDataCharacters) && allowed) {
+        this.onSubmit(this.commentData.currentData, this.commentData.currentText, this.selectedTag, this.questionerNameFormControl.value);
       }
     };
   }
diff --git a/src/app/models/comment.ts b/src/app/models/comment.ts
index 18b77b83d..26c3ba2d7 100644
--- a/src/app/models/comment.ts
+++ b/src/app/models/comment.ts
@@ -26,6 +26,7 @@ export class Comment {
   upvotes: number;
   downvotes: number;
   language: Language;
+  questionerName: string;
   createdBy;
 
   constructor(roomId: string = '',
@@ -48,6 +49,7 @@ export class Comment {
               upvotes = 0,
               downvotes = 0,
               language = Language.auto,
+              questionerName: string = null,
               createdBy?: any) {
     this.id = '';
     this.roomId = roomId;
@@ -72,6 +74,7 @@ export class Comment {
     this.downvotes = downvotes;
     this.language = language;
     this.createdBy = createdBy;
+    this.questionerName = questionerName;
   }
 
   static mapModelToLanguage(model: Model): Language {
diff --git a/src/app/services/http/comment.service.ts b/src/app/services/http/comment.service.ts
index 7f82202e3..0de32cdb2 100644
--- a/src/app/services/http/comment.service.ts
+++ b/src/app/services/http/comment.service.ts
@@ -87,7 +87,7 @@ export class CommentService extends BaseHttpService {
         read: comment.read, creationTimestamp: comment.timestamp, tag: comment.tag,
         keywordsFromSpacy: JSON.stringify(comment.keywordsFromSpacy),
         keywordsFromQuestioner: JSON.stringify(comment.keywordsFromQuestioner),
-        language: comment.language
+        language: comment.language, questionerName: comment.questionerName
       }, httpOptions).pipe(
       tap(_ => ''),
       catchError(this.handleError<Comment>('addComment'))
diff --git a/src/app/services/util/room-data.service.ts b/src/app/services/util/room-data.service.ts
index c1802e7b8..12e7f984c 100644
--- a/src/app/services/util/room-data.service.ts
+++ b/src/app/services/util/room-data.service.ts
@@ -184,11 +184,11 @@ export class RoomDataService {
   }
 
   getUnFilteredBody(id: string): string {
-    return this._savedCommentsBeforeFilter.get(id)[0];
+    return this._savedCommentsBeforeFilter.get(id).body;
   }
 
   getFilteredBody(id: string): string {
-    return this._savedCommentsAfterFilter.get(id)[0];
+    return this._savedCommentsAfterFilter.get(id).body;
   }
 
   getCensoredInformation(comment: Comment): CommentFilterData {
@@ -314,6 +314,7 @@ export class RoomDataService {
     c.userNumber = this.commentService.hashCode(c.creatorId);
     c.keywordsFromQuestioner = JSON.parse(payload.keywordsFromQuestioner);
     c.language = payload.language;
+    c.questionerName = payload.questionerName;
     this._fastCommentAccess[c.id] = c;
     this._currentComments.push(c);
     this.triggerUpdate(UpdateType.commentStream, {
diff --git a/src/assets/i18n/creator/de.json b/src/assets/i18n/creator/de.json
index 42b35de38..9da0fe888 100644
--- a/src/assets/i18n/creator/de.json
+++ b/src/assets/i18n/creator/de.json
@@ -170,9 +170,9 @@
     "send-description": "Frage abschicken",
     "tag": "Tag",
     "tag-reset": "Zurücksetzen",
-    "tag-to-filter": "Klick auf die Fragekategorie, um Fragen dieser Kategorie zu filtern.",
-    "user-number": "Klick auf die Nummer, um die Fragen dieses anonymen Fragenstellers zu filtern.",
-    "keywords-per-question": "Klick auf die Keywords, um die Keywords anzuzeigen die für die Frage hinterlegt wurden.",
+    "tag-to-filter": "Klick auf die Fragenkategorie, um Fragen dieser Kategorie zu filtern.",
+    "user-number": "Klick auf das Pin-Icon, um alle Fragen dieses Fragenstellers zu filtern.",
+    "keywords-per-question": "Klick auf das #-Zeichen, um die  Stichwörter anzuzeigen, die der Fragensteller bestimmt oder aus einer KI-generierten Liste ausgewählt hat.",
     "keywords": "Stichwörter",
     "vote-down": "Frage abwerten",
     "vote-up": "Frage aufwerten",
@@ -195,7 +195,8 @@
     "show-comment-with-filter": "Vulgäre Wörter ausixen",
     "show-comment-without-filter": "Vulgäre Wörter anzeigen",
     "upvote": "positiv:",
-    "downvote": "negativ:"
+    "downvote": "negativ:",
+    "questioner-name": "Selbst vergebener Name"
   },
   "content": {
     "abort": "Abbrechen",
@@ -354,7 +355,7 @@
     "settings-direct-send": "Alle Fragen veröffentlichen",
     "settings-direct-send-description": "Jede Frage wird sofort veröffentlicht. Schalte diese Option ab, wenn du jede Frage einzeln freigeben willst.",
     "sure": "Bist du sicher?",
-    "tag-new": "Neue Fragekategorie:",
+    "tag-new": "Neue Fragenkategorie:",
     "tag-error": "Muss zwischen 3 und 30 Zeichen lang sein",
     "tags": "Kategorien",
     "threshold": "Schwellenwert der Freigabe",
@@ -591,5 +592,10 @@
     "bad-spelled" : "Zu schlechte Rechtschreibung",
     "failed" : "Fehler aufgetreten",
     "inline-header": "Laufende Stichwort-Aktualisierungen"
+  },
+  "write-comment": {
+    "questioner-name": "Dein Name, wenn du willst ...",
+    "a11y-questioner-name": "Hier kannst du, wenn du willst, deinen Namen eingeben. Dieser ist für alle an diesem Kommentar sichtbar.",
+    "name-length-error": "Der Name muss zwischen 2 und 20 Zeichen lang sein."
   }
 }
diff --git a/src/assets/i18n/creator/en.json b/src/assets/i18n/creator/en.json
index 2a3d3e1ce..0c8a58091 100644
--- a/src/assets/i18n/creator/en.json
+++ b/src/assets/i18n/creator/en.json
@@ -171,9 +171,9 @@
     "send-description": "Send question",
     "tag": "Tag",
     "tag-reset": "Reset",
-    "tag-to-filter": "Click on the question category to filter questions in that category.",
-    "user-number": "Click on the number to filter the questions from this anonymous questioner.",
-    "keywords-per-question": "Click to display the keywords that have been entered for the question.",
+    "tag-to-filter": "Click on the question category to filter all questions in that category.",
+    "user-number": "Click on the pin icon to filter all questions from this questioner.",
+    "keywords-per-question": "Click on the # sign to display the keywords that the questioner has determined or selected from an AI-generated list.",
     "keywords": "Keywords",
     "vote-down": "Vote down",
     "vote-up": "Vote up",
@@ -196,7 +196,8 @@
     "show-comment-with-filter": "Hide vulgar words",
     "show-comment-without-filter": "Show vulgar words",
     "upvote": "upvotes:",
-    "downvote": "downvotes:"
+    "downvote": "downvotes:",
+    "questioner-name": "Self assigned name"
   },
   "content": {
     "abort": "Abort",
@@ -589,5 +590,10 @@
     "bad-spelled": "Spelling too bad",
     "failed": "Error occurred",
     "inline-header": "Ongoing keyword updates"
+  },
+  "write-comment": {
+    "questioner-name": "Your name, if you want ...",
+    "a11y-questioner-name": "Here you can enter your name if you want. This is visible for everyone at this comment.",
+    "name-length-error": "The name must be between 2 and 20 characters."
   }
 }
diff --git a/src/assets/i18n/home/de.json b/src/assets/i18n/home/de.json
index 4facef220..c650fd029 100644
--- a/src/assets/i18n/home/de.json
+++ b/src/assets/i18n/home/de.json
@@ -105,7 +105,7 @@
     "bonustoken": "Bonus-Archiv",
     "edit-moderator": "Moderatoren",
     "edit-session-description": "Begrüßungstext",
-    "edit-tags": "Fragen-Kategorien",
+    "edit-tags": "Fragenkategorien",
     "profanity-filter": "Vulgäre Wörter ausixen",
     "export-questions": "Fragen speichern",
     "delete-questions": "Fragen löschen",
@@ -119,7 +119,7 @@
     "questionwall": "Präsentation",
     "tag-cloud": "Themenwolke",
     "fullscreen": "Vollbild & Textgröße",
-    "motd": "News & FAQ",
+    "motd": "News",
     "tag-cloud-config": "Aussehen & Animation",
     "tag-cloud-administration": "Einstellungen & Suche",
     "questions-blocked": "Neue Fragen deaktiviert ",
@@ -388,7 +388,7 @@
     "inline-header": "Laufende Stichwort-Aktualisierungen"
   },
   "topic-cloud-filter": {
-    "info-no-keywords": "Es gibt keine Stichwörter. Die Themenwolke wird leer sein. Eine KI-basierte Textanalyse kann Stichwörter nachträglich erzeugen. Analyse starten?",
+    "info-no-keywords": "Eine KI-basierte Textanalyse kann Stichwörter nachträglich erzeugen. Analyse starten?",
     "label-refresh-keywords-start": "Starten"
   }
 }
diff --git a/src/assets/i18n/home/en.json b/src/assets/i18n/home/en.json
index d736f132f..4274fa190 100644
--- a/src/assets/i18n/home/en.json
+++ b/src/assets/i18n/home/en.json
@@ -390,7 +390,7 @@
     "inline-header": "Running keyword updates"
   },
   "topic-cloud-filter": {
-    "info-no-keywords": "There are no keywords. The topic cloud will be empty. An AI-based text analysis can generate keywords afterwards. Start analysis?",
+    "info-no-keywords": "An AI-based text analysis can generate keywords afterwards. Start analysis?",
     "label-refresh-keywords-start": "Start"
   }
 }
diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json
index d95b0400d..90318bb76 100644
--- a/src/assets/i18n/participant/de.json
+++ b/src/assets/i18n/participant/de.json
@@ -149,9 +149,9 @@
     "send-description": "Frage abschicken",
     "tag": "Tag",
     "tag-reset": "Zurücksetzen",
-    "tag-to-filter": "Klick auf die Fragekategorie, um alle Fragen dieser Kategorie zu filtern.",
-    "user-number": "Klick auf die Nummer, um alle Fragen dieses Fragenstellers zu filtern.",
-    "keywords-per-question": "Klick auf ein Stichwort, um alle Fragen mit diesem Stichwort zu filtern.",
+    "tag-to-filter": "Klick auf die Fragenkategorie, um alle Fragen dieser Kategorie zu filtern.",
+    "user-number": "Klick auf das Pin-Icon, um alle Fragen dieses Fragenstellers zu filtern.",
+    "keywords-per-question": "Klick auf das #-Zeichen, um die  Stichwörter anzuzeigen, die der Fragensteller bestimmt oder aus einer KI-generierten Liste ausgewählt hat.",
     "keywords": "Stichwörter",
     "vote-down": "Frage abwerten",
     "vote-up": "Frage aufwerten",
@@ -162,7 +162,8 @@
     "sure": "Bist du sicher?",
     "grammar-check": "Text prüfen",
     "upvote": "positiv:",
-    "downvote": "negativ:"
+    "downvote": "negativ:",
+    "questioner-name": "Selbst vergebener Name"
   },
   "deepl": {
     "header": "Text prüfen",
@@ -473,5 +474,10 @@
     "cancel": "Schließen",
     "cancel-description": "Schließe die Einführung und gehe zurück zur Anmeldung.",
     "title": "Einführung"
+  },
+  "write-comment": {
+    "questioner-name": "Dein Name, wenn du willst ...",
+    "a11y-questioner-name": "Hier kannst du, wenn du willst, deinen Namen eingeben. Dieser ist für alle an diesem Kommentar sichtbar.",
+    "name-length-error": "Der Name muss zwischen 2 und 20 Zeichen lang sein."
   }
 }
diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json
index 876f4dcee..323491b8e 100644
--- a/src/assets/i18n/participant/en.json
+++ b/src/assets/i18n/participant/en.json
@@ -158,9 +158,9 @@
     "send-description": "Send question",
     "tag": "Tag",
     "tag-reset": "Reset",
-    "tag-to-filter": "Click on the question category to filter questions in that category.",
-    "user-number": "Click on the number to filter the questions from this anonymous questioner.",
-    "keywords-per-question": "Click to display the keywords that have been entered for the question.",
+    "tag-to-filter": "Click on the question category to filter all questions in that category.",
+    "user-number": "Click on the pin icon to filter all questions from this questioner.",
+    "keywords-per-question": "Click on the # sign to display the keywords that the questioner has determined or selected from an AI-generated list.",
     "keywords": "Keywords",
     "vote-down": "Vote down",
     "vote-up": "Vote up",
@@ -171,7 +171,8 @@
     "delete": "Delete question",
     "grammar-check": "Check text",
     "upvote": "upvotes:",
-    "downvote": "downvotes:"
+    "downvote": "downvotes:",
+    "questioner-name": "Self assigned name"
   },
   "deepl": {
     "header": "Check text",
@@ -479,5 +480,10 @@
     "cancel": "Close",
     "cancel-description": "Close introduction.",
     "title": "Introduction"
+  },
+  "write-comment": {
+    "questioner-name": "Your name, if you want ...",
+    "a11y-questioner-name": "Here you can enter your name if you want. This is visible for everyone at this comment.",
+    "name-length-error": "The name must be between 2 and 20 characters."
   }
 }
-- 
GitLab