Repository: e-valuation/EvaP

Issue:
Translate evaluation state names in log display
When displaying a logentry for a change of the `state` field of an `evaluation`, the state names should not only be mapped from their integer representation to string values (what we currently do), but also be translated into the display language.

For example, although I am using the site in German, the logs at the end of the evaluation edit site for "Fachspezifisches Englisch (Level 2)" are saying: "State: reviewed → evaluated"


Discussion:

Resolving patch:
diff --git a/evap/evaluation/migrations/0142_alter_evaluation_state.py b/evap/evaluation/migrations/0142_alter_evaluation_state.py
new file mode 100644
--- /dev/null
+++ b/evap/evaluation/migrations/0142_alter_evaluation_state.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2023-11-13 20:59
+
+from django.db import migrations
+import django_fsm
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("evaluation", "0141_userprofile_notes"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="evaluation",
+            name="state",
+            field=django_fsm.FSMIntegerField(default=10, protected=True, verbose_name="state"),
+        ),
+    ]
diff --git a/evap/evaluation/models.py b/evap/evaluation/models.py
--- a/evap/evaluation/models.py
+++ b/evap/evaluation/models.py
@@ -389,7 +389,7 @@ class State:
         REVIEWED = 70
         PUBLISHED = 80
 
-    state = FSMIntegerField(default=State.NEW, protected=True)
+    state = FSMIntegerField(default=State.NEW, protected=True, verbose_name=_("state"))
 
     course = models.ForeignKey(Course, models.PROTECT, verbose_name=_("course"), related_name="evaluations")
 
@@ -779,14 +779,14 @@ def unpublish(self):
         self._participant_count = None
 
     STATE_STR_CONVERSION = {
-        State.NEW: "new",
-        State.PREPARED: "prepared",
-        State.EDITOR_APPROVED: "editor_approved",
-        State.APPROVED: "approved",
-        State.IN_EVALUATION: "in_evaluation",
-        State.EVALUATED: "evaluated",
-        State.REVIEWED: "reviewed",
-        State.PUBLISHED: "published",
+        State.NEW: _("new"),
+        State.PREPARED: _("prepared"),
+        State.EDITOR_APPROVED: _("editor_approved"),
+        State.APPROVED: _("approved"),
+        State.IN_EVALUATION: _("in_evaluation"),
+        State.EVALUATED: _("evaluated"),
+        State.REVIEWED: _("reviewed"),
+        State.PUBLISHED: _("published"),
     }
 
     @classmethod
@@ -994,7 +994,7 @@ def unlogged_fields(self):
 
     @classmethod
     def transform_log_action(cls, field_action):
-        if field_action.label == "State":
+        if field_action.label.lower() == Evaluation.state.field.verbose_name.lower():
             return FieldAction(
                 field_action.label, field_action.type, [cls.state_to_str(state) for state in field_action.items]
             )


Test patch:
diff --git a/evap/staff/tests/test_views.py b/evap/staff/tests/test_views.py
--- a/evap/staff/tests/test_views.py
+++ b/evap/staff/tests/test_views.py
@@ -2176,6 +2176,17 @@ def test_questionnaire_with_answers_warning(self):
             '<label class="form-check-label badge bg-danger" for="id_contributions-1-questionnaires_0">', page
         )
 
+    @patch.dict(Evaluation.STATE_STR_CONVERSION, {Evaluation.State.PREPARED: "mock-translated-prepared"})
+    def test_state_change_log_translated(self):
+        page = self.app.get(self.url, user=self.manager)
+        self.assertNotIn("mock-translated-prepared", page)
+
+        self.evaluation.ready_for_editors()
+        self.evaluation.save()
+
+        page = self.app.get(self.url, user=self.manager)
+        self.assertIn("mock-translated-prepared", page)
+
 
 class TestEvaluationDeleteView(WebTestStaffMode):
     csrf_checks = False