summaryrefslogtreecommitdiff
path: root/internal/web
diff options
context:
space:
mode:
Diffstat (limited to 'internal/web')
-rw-r--r--internal/web/render.go3
-rw-r--r--internal/web/render_test.go16
-rw-r--r--internal/web/server.go12
-rw-r--r--internal/web/server_test.go47
-rw-r--r--internal/web/templates/index.html2
5 files changed, 74 insertions, 6 deletions
diff --git a/internal/web/render.go b/internal/web/render.go
index ca5bb89..208fc59 100644
--- a/internal/web/render.go
+++ b/internal/web/render.go
@@ -19,6 +19,7 @@ import (
"strings"
"github.com/lukaszkasprzak/lectio/internal/bible"
+ "github.com/lukaszkasprzak/lectio/internal/i18n"
"github.com/lukaszkasprzak/lectio/internal/liturgy"
"github.com/lukaszkasprzak/lectio/internal/render"
)
@@ -203,7 +204,7 @@ func buildInterlinearViews(secs []liturgy.Section, versions []string, lectionary
}
if len(sets) == 0 {
- view.Note = "(brak wersetów do zestawienia interlinearnego)"
+ view.Note = i18n.Get(lang).NoInterlinearVerses
views = append(views, view)
continue
}
diff --git a/internal/web/render_test.go b/internal/web/render_test.go
index ea44ed2..494cdcd 100644
--- a/internal/web/render_test.go
+++ b/internal/web/render_test.go
@@ -106,6 +106,22 @@ func TestRenderReadingsInterlinearNoVersifiedNote(t *testing.T) {
if strings.Contains(html, "ilverse") {
t.Errorf("expected no ilverse blocks when nothing resolves: %q", html)
}
+ if !strings.Contains(html, "brak wersetów do zestawienia interlinearnego") {
+ t.Errorf("pl no-verses note missing/wrong: %q", html)
+ }
+}
+
+// TestRenderReadingsInterlinearNoVersifiedNoteLang checks the interlinear
+// "no verses to align" note (finding §1) follows lang, not always Polish.
+func TestRenderReadingsInterlinearNoVersifiedNoteLang(t *testing.T) {
+ secs := []liturgy.Section{{Heading: "Bez odwołania", PartID: "ewangelia"}}
+ html := string(RenderReadings(secs, []string{"wuj"}, "new", "interlinear", "en"))
+ if !strings.Contains(html, "(no verses to align)") {
+ t.Errorf("en no-verses note missing/wrong: %q", html)
+ }
+ if strings.Contains(html, "brak wersetów") {
+ t.Errorf("en output should not carry the Polish no-verses note: %q", html)
+ }
}
// TestRenderReadingsLocalizesEN checks that lang="en" localises both the
diff --git a/internal/web/server.go b/internal/web/server.go
index 3b7102c..4c13576 100644
--- a/internal/web/server.go
+++ b/internal/web/server.go
@@ -188,6 +188,8 @@ type indexData struct {
// set from i18n.Get(cfg.UILanguage) -- index.html references its
// fields (e.g. {{.L.Lectionary}}) instead of hardcoded Polish text.
L i18n.UI
+ // Lang is cfg.UILanguage, rendered into <html lang="...">.
+ Lang string
}
type versionOpt struct {
@@ -245,6 +247,7 @@ func indexHandler(cfg config.Config) http.HandlerFunc {
Mono: queryBool(r, "mono", cfg.WebMono),
Reading: reading,
L: i18n.Get(cfg.UILanguage),
+ Lang: cfg.UILanguage,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
@@ -269,15 +272,16 @@ func readingsHandler(cfg config.Config) http.HandlerFunc {
}
// renderOrError returns RenderReadings' fragment, or (on a readings.Load
-// error) a small escaped error paragraph -- readings.Load errors are
-// expected in normal operation (an unpublished date, no network while
-// online, ...) so the pane should show them, not 500.
+// error, or no sections at all for the date) a small escaped error
+// paragraph, localised via lang -- readings.Load errors are expected in
+// normal operation (an unpublished date, no network while online, ...) so
+// the pane should show them, not 500.
func renderOrError(secs []liturgy.Section, versions []string, lectionary, display, lang string, err error) template.HTML {
if err != nil {
return template.HTML(`<p class="error">` + template.HTMLEscapeString(err.Error()) + `</p>`)
}
if len(secs) == 0 {
- return template.HTML(`<p class="error">brak czytań na ten dzień</p>`)
+ return template.HTML(`<p class="error">` + template.HTMLEscapeString(i18n.Get(lang).NoReadingsDay) + `</p>`)
}
return RenderReadings(secs, versions, lectionary, display, lang)
}
diff --git a/internal/web/server_test.go b/internal/web/server_test.go
index 25d21f4..32ee412 100644
--- a/internal/web/server_test.go
+++ b/internal/web/server_test.go
@@ -227,6 +227,53 @@ func TestServer(t *testing.T) {
})
}
+// TestRenderOrErrorNoSectionsLang checks the "no readings at all for this
+// day" fragment (finding §1) follows lang instead of always being Polish.
+func TestRenderOrErrorNoSectionsLang(t *testing.T) {
+ html := string(renderOrError(nil, nil, "new", "horizontal", "en", nil))
+ if !strings.Contains(html, "no readings for this day") {
+ t.Errorf("en renderOrError(no secs) = %q, want it to contain %q", html, "no readings for this day")
+ }
+ if strings.Contains(html, "czyta") {
+ t.Errorf("en renderOrError(no secs) should not carry Polish wording: %q", html)
+ }
+
+ html = string(renderOrError(nil, nil, "new", "horizontal", "pl", nil))
+ if !strings.Contains(html, "brak czytań na ten dzień") {
+ t.Errorf("pl renderOrError(no secs) = %q, want it to contain %q", html, "brak czytań na ten dzień")
+ }
+}
+
+// TestIndexHTMLLangAttribute checks index.html's <html lang="..."> follows
+// cfg.UILanguage (finding §6) instead of being hardcoded "pl".
+func TestIndexHTMLLangAttribute(t *testing.T) {
+ html, err := os.ReadFile("../liturgy/testdata/2026-07-22.html")
+ if err != nil {
+ t.Fatal(err)
+ }
+ fixtureServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write(html)
+ }))
+ defer fixtureServer.Close()
+ liturgy.SetBaseURL(fixtureServer.URL + "/liturgia/%s/Ewangelia")
+ t.Setenv("XDG_CACHE_HOME", t.TempDir())
+
+ cfg := config.Default()
+ cfg.UILanguage = "en"
+ rec := httptest.NewRecorder()
+ NewServer(cfg).ServeHTTP(rec, httptest.NewRequest("GET", "/?date=2026-07-22&v=wuj", nil))
+ if !strings.Contains(rec.Body.String(), `<html lang="en">`) {
+ t.Errorf(`en index page missing <html lang="en">: %q`, rec.Body.String()[:min(400, rec.Body.Len())])
+ }
+
+ cfg.UILanguage = "pl"
+ rec = httptest.NewRecorder()
+ NewServer(cfg).ServeHTTP(rec, httptest.NewRequest("GET", "/?date=2026-07-22&v=wuj", nil))
+ if !strings.Contains(rec.Body.String(), `<html lang="pl">`) {
+ t.Errorf(`pl index page missing <html lang="pl">: %q`, rec.Body.String()[:min(400, rec.Body.Len())])
+ }
+}
+
// TestChooseListener exercises chooseListener's port-selection logic
// directly (no HTTP serving): port==0 prefers defaultWebPort (1099) and
// falls back to a free OS port when 1099 is taken, and a non-zero port is
diff --git a/internal/web/templates/index.html b/internal/web/templates/index.html
index 8c9fd86..780224f 100644
--- a/internal/web/templates/index.html
+++ b/internal/web/templates/index.html
@@ -11,7 +11,7 @@
included too; they override "date" via hx-vals. The theme <select>
has no server round trip: it swaps the #theme <link>'s href directly. */}}
<!doctype html>
-<html lang="pl">
+<html lang="{{.Lang}}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">