From 4c776396115c8120c3e1cb8fda993449fcdcd326 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 23 Jul 2026 21:51:40 +0200 Subject: i18n: ui_language config (default en) for UI chrome across cli/tui/web; version labels localised --- internal/web/render.go | 31 ++++++++++++++++++------------- internal/web/render_test.go | 30 ++++++++++++++++++++++++------ internal/web/server.go | 14 ++++++++++---- internal/web/server_test.go | 11 ++++++++--- internal/web/templates/index.html | 24 ++++++++++++------------ 5 files changed, 72 insertions(+), 38 deletions(-) (limited to 'internal/web') diff --git a/internal/web/render.go b/internal/web/render.go index 63c1da4..ca5bb89 100644 --- a/internal/web/render.go +++ b/internal/web/render.go @@ -95,15 +95,17 @@ type ilLineView struct { // In every mode, heading, citation (subtitle), verse-number and refrain // text are wrapped in class="heading|citation|vnum|refrain|version-label" // spans so theme CSS can restyle them; verse/paragraph text is escaped by -// html/template. -func RenderReadings(secs []liturgy.Section, versions []string, lectionary, display string) template.HTML { +// html/template. lang localises the version-column labels and each section +// heading's part-label word (render.LocalizeHeading, brief §3b); the +// citation/verse text is never touched. +func RenderReadings(secs []liturgy.Section, versions []string, lectionary, display, lang string) template.HTML { switch display { case "vertical": - return renderTemplate("readings-vertical.html", buildColumnViews(secs, versions, lectionary)) + return renderTemplate("readings-vertical.html", buildColumnViews(secs, versions, lectionary, lang)) case "interlinear": - return renderTemplate("readings-interlinear.html", buildInterlinearViews(secs, versions, lectionary)) + return renderTemplate("readings-interlinear.html", buildInterlinearViews(secs, versions, lectionary, lang)) default: - return renderTemplate("readings.html", buildColumnViews(secs, versions, lectionary)) + return renderTemplate("readings.html", buildColumnViews(secs, versions, lectionary, lang)) } } @@ -122,15 +124,17 @@ func renderTemplate(name string, data any) template.HTML { // buildColumnViews gathers each section's per-version columns via // render.GatherVersion -- the shared data both the "horizontal" // (readings.html) and "vertical" (readings-vertical.html) templates range -// over; only the surrounding markup differs between the two layouts. -func buildColumnViews(secs []liturgy.Section, versions []string, lectionary string) []sectionView { +// over; only the surrounding markup differs between the two layouts. lang +// localises the column labels and the heading's part-label word (see +// RenderReadings). +func buildColumnViews(secs []liturgy.Section, versions []string, lectionary, lang string) []sectionView { views := make([]sectionView, 0, len(secs)) for _, sec := range secs { isPsalm := sec.PartID == "psalm" cols := make([]columnView, 0, len(versions)) for _, v := range versions { - label, blocks := render.GatherVersion(v, sec, lectionary) + label, blocks := render.GatherVersion(v, sec, lectionary, lang) bviews := make([]blockView, 0, len(blocks)) for bi, b := range blocks { @@ -148,7 +152,7 @@ func buildColumnViews(secs []liturgy.Section, versions []string, lectionary stri } views = append(views, sectionView{ - Heading: sec.Heading, + Heading: render.LocalizeHeading(sec.Heading, sec.PartID, lang), Subtitle: sec.Subtitle, PartID: sec.PartID, Columns: cols, @@ -175,8 +179,9 @@ func interlinearVersions(versions []string) []string { // that version's order (stable, no duplicates). A version that comes back // unversified (a bible lookup miss) is simply skipped -- the remaining // versions still render. A section where nothing could be interleaved gets -// a short escaped Note instead of an empty Verses list. -func buildInterlinearViews(secs []liturgy.Section, versions []string, lectionary string) []ilSectionView { +// a short escaped Note instead of an empty Verses list. lang localises the +// per-version labels and the heading's part-label word (see RenderReadings). +func buildInterlinearViews(secs []liturgy.Section, versions []string, lectionary, lang string) []ilSectionView { mapped := interlinearVersions(versions) type verseSet struct { @@ -186,11 +191,11 @@ func buildInterlinearViews(secs []liturgy.Section, versions []string, lectionary views := make([]ilSectionView, 0, len(secs)) for _, sec := range secs { - view := ilSectionView{Heading: sec.Heading, Subtitle: sec.Subtitle, PartID: sec.PartID} + view := ilSectionView{Heading: render.LocalizeHeading(sec.Heading, sec.PartID, lang), Subtitle: sec.Subtitle, PartID: sec.PartID} var sets []verseSet for _, v := range mapped { - label, verses, versified := render.GatherVerses(v, sec, lectionary) + label, verses, versified := render.GatherVerses(v, sec, lectionary, lang) if !versified { continue } diff --git a/internal/web/render_test.go b/internal/web/render_test.go index 0e64168..ea44ed2 100644 --- a/internal/web/render_test.go +++ b/internal/web/render_test.go @@ -11,7 +11,7 @@ import ( func TestRenderReadings(t *testing.T) { secs := []liturgy.Section{{Heading: "Ewangelia (J 20, 1. 11-18)", PartID: "ewangelia"}} - html := string(RenderReadings(secs, []string{"wuj"}, "new", "horizontal")) + html := string(RenderReadings(secs, []string{"wuj"}, "new", "horizontal", "pl")) if !strings.Contains(html, "Ewangelia") || !strings.Contains(html, "class=") { t.Errorf("reading pane missing heading/classes: %q", html[:min(200, len(html))]) } @@ -45,7 +45,7 @@ func TestRenderReadingsEscapesScriptText(t *testing.T) { PartID: "pierwsze_czytanie", Paragraphs: [][]string{{""}}, }} - html := string(RenderReadings(secs, []string{"pl"}, "new", "horizontal")) + html := string(RenderReadings(secs, []string{"pl"}, "new", "horizontal", "pl")) if strings.Contains(html, "") { t.Errorf("raw