diff --git a/frontend/src/client/fristenrechner.ts b/frontend/src/client/fristenrechner.ts index f39c27e..8ae63ce 100644 --- a/frontend/src/client/fristenrechner.ts +++ b/frontend/src/client/fristenrechner.ts @@ -480,6 +480,7 @@ interface EventDeadlineResult { durationUnit: string; timing: string; notes?: string; + notesEN?: string; ruleCodes: string[]; dueDate: string; originalDueDate: string; @@ -630,8 +631,9 @@ function renderEventResults(data: EventCalculateResponse) { const composite = d.isComposite && d.compositeNote ? `
${escHtml(t("deadlines.event.composite.label"))} ${escHtml(d.compositeNote)}
` : ""; - const notes = d.notes - ? `
${escHtml(d.notes)}
` + const noteText = getLang() === "en" ? (d.notesEN || d.notes) : d.notes; + const notes = noteText + ? `
${escHtml(noteText)}
` : ""; return `
  • diff --git a/internal/db/migrations/035_event_deadlines_title_de_backfill.down.sql b/internal/db/migrations/035_event_deadlines_title_de_backfill.down.sql new file mode 100644 index 0000000..337d489 --- /dev/null +++ b/internal/db/migrations/035_event_deadlines_title_de_backfill.down.sql @@ -0,0 +1,4 @@ +-- Reverses 035_event_deadlines_title_de_backfill. Resets title_de back to +-- the empty default so a re-run of the up-migration backfills cleanly. + +UPDATE paliad.event_deadlines SET title_de = '' WHERE title_de <> ''; diff --git a/internal/db/migrations/035_event_deadlines_title_de_backfill.up.sql b/internal/db/migrations/035_event_deadlines_title_de_backfill.up.sql new file mode 100644 index 0000000..9ad14f3 --- /dev/null +++ b/internal/db/migrations/035_event_deadlines_title_de_backfill.up.sql @@ -0,0 +1,90 @@ +-- t-paliad-116 A: backfill paliad.event_deadlines.title_de for the +-- "Was kommt nach…" Fristenrechner mode. +-- +-- 028 imported 70 deadlines from youpc data.deadlines with English `title` +-- populated and `title_de` defaulted to '' (NOT NULL). The DTO's +-- deadlineTitle() helper already prefers title_de when locale=de and +-- falls back to title when title_de is empty — so populating title_de +-- here is a pure data fix with no code changes for this leak. +-- +-- Translations follow UPC RoP DE terminology (Klageerwiderung, Replik, +-- Duplik, Erwiderung, Berufungsschrift, Berufungsbegründung, +-- Anschlussberufungsschrift, Verletzungswiderklage, Nichtigkeitswiderklage, +-- Mängelbeseitigung, etc.) and stay consistent with the trigger_events +-- backfill from migration 033 so the picker label and the deadline row +-- read the same German. + +UPDATE paliad.event_deadlines SET title_de = CASE id + WHEN 1 THEN 'Vorgängige Einrede' + WHEN 2 THEN 'Klageerwiderung' + WHEN 3 THEN 'Erwiderung auf die Nichtigkeitswiderklage und Replik auf die Klageerwiderung' + WHEN 4 THEN 'Replik auf die Klageerwiderung' + WHEN 5 THEN 'Duplik zur Replik auf die Klageerwiderung' + WHEN 6 THEN 'Antrag auf Patentänderung' + WHEN 7 THEN 'Replik auf die Erwiderung zur Widerklage, Duplik zur Replik auf die Klageerwiderung, Erwiderung auf den Patentänderungsantrag' + WHEN 8 THEN 'Duplik zur Replik, Replik auf die Erwiderung zum Patentänderungsantrag' + WHEN 9 THEN 'Erwiderung auf den Antrag auf Patentänderung' + WHEN 10 THEN 'Replik auf die Erwiderung zum Patentänderungsantrag' + WHEN 11 THEN 'Duplik zur Replik auf die Erwiderung zum Patentänderungsantrag' + WHEN 12 THEN 'Einreichung von Übersetzungen von Schriftstücken' + WHEN 13 THEN 'Erwiderung auf die Nichtigkeitsklage' + WHEN 14 THEN 'Replik auf die Erwiderung zur Nichtigkeitsklage, Erwiderung auf den Patentänderungsantrag, Erwiderung auf die Verletzungswiderklage' + WHEN 15 THEN 'Duplik zur Replik auf die Erwiderung zur Nichtigkeitsklage' + WHEN 16 THEN 'Erwiderung auf die Verletzungswiderklage' + WHEN 17 THEN 'Replik auf die Erwiderung zur Verletzungswiderklage' + WHEN 18 THEN 'Duplik zur Replik auf die Erwiderung zur Verletzungswiderklage, Duplik zur Replik auf die Erwiderung zum Patentänderungsantrag' + WHEN 19 THEN 'Erwiderung auf die negative Feststellungsklage' + WHEN 20 THEN 'Replik auf die Erwiderung zur negativen Feststellungsklage' + WHEN 21 THEN 'Duplik zur Replik auf die Erwiderung zur negativen Feststellungsklage' + WHEN 22 THEN 'Antrag auf Aufhebung oder Änderung einer Entscheidung des Amtes' + WHEN 23 THEN 'Antrag auf Simultanübersetzung' + WHEN 24 THEN 'Antrag auf Folgemaßnahmen aus einer rechtskräftigen Validitätsentscheidung' + WHEN 25 THEN 'Erwiderung auf den Antrag auf Schadensersatzbemessung' + WHEN 26 THEN 'Replik auf die Erwiderung zum Antrag auf Schadensersatzbemessung' + WHEN 27 THEN 'Duplik zur Replik auf die Erwiderung zum Antrag auf Schadensersatzbemessung' + WHEN 28 THEN 'Erwiderung auf den Antrag auf Rechnungslegung' + WHEN 29 THEN 'Replik auf die Erwiderung zum Antrag auf Rechnungslegung' + WHEN 30 THEN 'Duplik zur Replik auf die Erwiderung zum Antrag auf Rechnungslegung' + WHEN 31 THEN 'Berufungsschrift gegen eine in Regel 220.1(a) und (b) genannte Entscheidung' + WHEN 32 THEN 'Berufungsschrift gegen eine in Regel 220.1(c) genannte Anordnung oder eine in Regel 220.2 oder 221.3 genannte Entscheidung' + WHEN 33 THEN 'Berufungsbegründung gegen eine in Regel 220.1(a) und (b) genannte Entscheidung' + WHEN 34 THEN 'Berufungsbegründung gegen eine in Regel 220.1(c) genannte Anordnung oder eine in Regel 220.2 oder 221.3 genannte Entscheidung' + WHEN 35 THEN 'Anfechtung einer Entscheidung über die Verwerfung der Berufung als unzulässig' + WHEN 36 THEN 'Berufungserwiderung (auf die Berufung nach Regel 224.2(a))' + WHEN 37 THEN 'Berufungserwiderung (auf die Berufung nach Regel 224.2(b))' + WHEN 38 THEN 'Anschlussberufungsschrift (zur Berufung nach Regel 224.2(a))' + WHEN 39 THEN 'Anschlussberufungsschrift (zur Berufung nach Regel 224.2(b))' + WHEN 40 THEN 'Erwiderung auf eine Anschlussberufungsschrift (zur Berufung nach Regel 224.2(a))' + WHEN 41 THEN 'Erwiderung auf eine Anschlussberufungsschrift (zur Berufung nach Regel 224.2(b))' + WHEN 42 THEN 'Antrag auf Wiederaufnahme (schwerwiegender Verfahrensmangel)' + WHEN 43 THEN 'Antrag auf Wiederaufnahme (Straftat)' + WHEN 44 THEN 'Antrag auf Überprüfung einer verfahrensleitenden Anordnung' + WHEN 45 THEN 'Mängelbeseitigung / Zahlung' + WHEN 46 THEN 'Mängelbeseitigung / Einreichung schriftlicher Stellungnahme' + WHEN 47 THEN 'Mängelbeseitigung / Zahlung' + WHEN 48 THEN 'Mängelbeseitigung / Zahlung' + WHEN 49 THEN 'Antrag auf Überprüfung der Beweissicherungsanordnung' + WHEN 50 THEN 'Beginn des Hauptsacheverfahrens' + WHEN 51 THEN 'Mängelbeseitigung / Zahlung' + WHEN 52 THEN 'Beginn des Hauptsacheverfahrens' + WHEN 53 THEN 'Berufung (Anordnungen & mit Zulassung)' + WHEN 54 THEN 'Antrag auf Ermessensüberprüfung' + WHEN 55 THEN 'Antrag auf Berufungszulassung gegen Kostenentscheidungen' + WHEN 56 THEN 'Mängelbeseitigung / Zahlung' + WHEN 57 THEN 'Mängelbeseitigung / Zahlung' + WHEN 58 THEN 'Antrag auf Verweisung an die Zentralkammer' + WHEN 59 THEN 'Antrag auf Aufhebung einer Entscheidung des EPA, mit der ein Antrag auf einheitliche Wirkung zurückgewiesen wurde' + WHEN 60 THEN 'Mitteilung über Beauftragung eines Dolmetschers auf Kosten der Partei' + WHEN 61 THEN 'Verletzungswiderklage' + WHEN 62 THEN 'Antrag auf Patentänderung' + WHEN 63 THEN 'Nichtigkeitswiderklage' + WHEN 64 THEN 'Antrag auf Kostenentscheidung' + WHEN 65 THEN 'Berufungsschrift gegen eine in Regel 220.1(a) und (b) genannte Entscheidung' + WHEN 66 THEN 'Berufungsbegründung gegen eine in Regel 220.1(a) und (b) genannte Entscheidung' + WHEN 67 THEN 'Erneuerung der Schutzschrift' + WHEN 68 THEN 'Berichtigung von Entscheidungen und Anordnungen' + WHEN 69 THEN 'Klärung von Übersetzungsfragen' + WHEN 70 THEN 'Antrag auf Vertraulichkeit gegenüber der Öffentlichkeit' + ELSE title_de +END +WHERE id BETWEEN 1 AND 70; diff --git a/internal/db/migrations/036_event_deadlines_notes_en.down.sql b/internal/db/migrations/036_event_deadlines_notes_en.down.sql new file mode 100644 index 0000000..0d3be59 --- /dev/null +++ b/internal/db/migrations/036_event_deadlines_notes_en.down.sql @@ -0,0 +1,13 @@ +-- Reverses 036_event_deadlines_notes_en. Restores the original English +-- notes for rows 50/52/70 from notes_en, then drops the column. + +UPDATE paliad.event_deadlines SET notes = CASE id + WHEN 50 THEN 'Or 20 Working days, whichever is longer' + WHEN 52 THEN 'Or 20 Working days, whichever is longer' + WHEN 70 THEN 'The 262.2 application can also be filed for opponent submissions to protect confidential information disclosed by the opponent.' + ELSE notes +END +WHERE id IN (50, 52, 70); + +ALTER TABLE paliad.event_deadlines + DROP COLUMN IF EXISTS notes_en; diff --git a/internal/db/migrations/036_event_deadlines_notes_en.up.sql b/internal/db/migrations/036_event_deadlines_notes_en.up.sql new file mode 100644 index 0000000..00e4d11 --- /dev/null +++ b/internal/db/migrations/036_event_deadlines_notes_en.up.sql @@ -0,0 +1,44 @@ +-- t-paliad-116 B: paliad.event_deadlines.notes_en column + DE/EN swap +-- for the three rows that ship English text in the (DE-named) notes +-- column. +-- +-- The DTO has long emitted `notes` directly into the EN render, so the +-- pattern matches t-112 mig 032 for deadline_rules: add a parallel +-- notes_en column, render path prefers _en when locale=EN and falls +-- back to notes (DE) when NULL. +-- +-- Three rows currently leak English into the DE locale (ids 50, 52, 70): +-- 50, 52: "Or 20 Working days, whichever is longer" +-- 70: "The 262.2 application can also be filed for opponent +-- submissions to protect confidential information disclosed +-- by the opponent." +-- For those rows we (1) copy the existing English string verbatim into +-- notes_en, and (2) overwrite notes with the proper DE translation so +-- the DE locale stops leaking. + +ALTER TABLE paliad.event_deadlines + ADD COLUMN IF NOT EXISTS notes_en text; + +COMMENT ON COLUMN paliad.event_deadlines.notes_en IS + 'English translation of notes. Render path prefers this column when ' + 'the active locale is EN; falls back to notes (DE) when NULL.'; + +-- Step 1: preserve current English text in notes_en for the three rows +-- that have it. +UPDATE paliad.event_deadlines SET notes_en = CASE id + WHEN 50 THEN 'Or 20 Working days, whichever is longer' + WHEN 52 THEN 'Or 20 Working days, whichever is longer' + WHEN 70 THEN 'The 262.2 application can also be filed for opponent submissions to protect confidential information disclosed by the opponent.' + ELSE notes_en +END +WHERE id IN (50, 52, 70); + +-- Step 2: replace the leaking English text in the DE-named notes column +-- with proper DE translations. +UPDATE paliad.event_deadlines SET notes = CASE id + WHEN 50 THEN 'Oder 20 Werktage, je nachdem, was länger ist' + WHEN 52 THEN 'Oder 20 Werktage, je nachdem, was länger ist' + WHEN 70 THEN 'Der Antrag nach Regel 262.2 kann auch für Schriftsätze der einsprechenden Partei gestellt werden, um vertrauliche Informationen zu schützen, die von der einsprechenden Partei offengelegt wurden.' + ELSE notes +END +WHERE id IN (50, 52, 70); diff --git a/internal/services/event_deadline_service.go b/internal/services/event_deadline_service.go index 052452f..64c8271 100644 --- a/internal/services/event_deadline_service.go +++ b/internal/services/event_deadline_service.go @@ -53,8 +53,8 @@ func (s *EventDeadlineService) ListTriggerEvents(ctx context.Context) ([]Trigger } // EventDeadlineResult is one computed deadline returned to the UI. -// Bilingual title + the rule codes attached to the deadline + the -// computed due date (after weekend/holiday rollover). +// Bilingual title + bilingual notes + the rule codes attached to the +// deadline + the computed due date (after weekend/holiday rollover). type EventDeadlineResult struct { ID int64 `json:"id"` Title string `json:"title"` @@ -63,6 +63,7 @@ type EventDeadlineResult struct { DurationUnit string `json:"durationUnit"` Timing string `json:"timing"` Notes string `json:"notes,omitempty"` + NotesEN string `json:"notesEN,omitempty"` RuleCodes []string `json:"ruleCodes"` DueDate string `json:"dueDate"` // YYYY-MM-DD, after holiday/weekend adjust OriginalDueDate string `json:"originalDueDate"` // YYYY-MM-DD, before adjust @@ -103,7 +104,7 @@ func (s *EventDeadlineService) Calculate(ctx context.Context, triggerEventID int var rows []eventDeadlineRow err = s.db.SelectContext(ctx, &rows, ` SELECT id, title, title_de, duration_value, duration_unit, timing, - notes, alt_duration_value, alt_duration_unit, combine_op + notes, notes_en, alt_duration_value, alt_duration_unit, combine_op FROM paliad.event_deadlines WHERE trigger_event_id = $1 AND is_active = true ORDER BY id`, triggerEventID) @@ -167,6 +168,10 @@ func (s *EventDeadlineService) Calculate(ctx context.Context, triggerEventID int } } + notesEN := "" + if r.NotesEN != nil { + notesEN = *r.NotesEN + } results = append(results, EventDeadlineResult{ ID: r.ID, Title: r.Title, @@ -175,6 +180,7 @@ func (s *EventDeadlineService) Calculate(ctx context.Context, triggerEventID int DurationUnit: r.DurationUnit, Timing: r.Timing, Notes: r.Notes, + NotesEN: notesEN, RuleCodes: codes[r.ID], DueDate: picked.Format("2006-01-02"), OriginalDueDate: original.Format("2006-01-02"), @@ -259,6 +265,7 @@ type eventDeadlineRow struct { DurationUnit string `db:"duration_unit"` Timing string `db:"timing"` Notes string `db:"notes"` + NotesEN *string `db:"notes_en"` AltDurationValue *int `db:"alt_duration_value"` AltDurationUnit *string `db:"alt_duration_unit"` CombineOp *string `db:"combine_op"`