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/tui/tui.go | 22 +++++++++++--------- internal/tui/tui_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 10 deletions(-) (limited to 'internal/tui') diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 1e3b948..bcfb3c1 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -13,6 +13,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/lukaszkasprzak/lectio/internal/config" + "github.com/lukaszkasprzak/lectio/internal/i18n" "github.com/lukaszkasprzak/lectio/internal/liturgy" "github.com/lukaszkasprzak/lectio/internal/readings" "github.com/lukaszkasprzak/lectio/internal/render" @@ -42,8 +43,6 @@ type errMsg struct { err error } -const footerKeys = "tab/⇧tab wersja ←/→ dzień j/k przewiń spacja/b strona g/G góra/dół r odśwież q wyjście" - // New builds the initial model: cfg.Offline drops "pl" from the version // list (render.OfflineVersions), the active version starts at // cfg.DefaultVersion (falling back to the first version if not found, or @@ -256,7 +255,7 @@ func (m Model) View() string { } header := headerStyle.Width(w).Render(m.headerText()) - footer := footerStyle.Width(w).Render(footerKeys) + footer := footerStyle.Width(w).Render(i18n.Get(m.cfg.UILanguage).FooterKeys) bodyLines := m.bodyLines(innerW) @@ -276,7 +275,7 @@ func (m Model) View() string { func (m Model) headerText() string { label := m.version() if len(m.sections) > 0 { - if l, _ := render.GatherVersion(m.version(), m.sections[0], m.cfg.Lectionary); l != "" { + if l, _ := render.GatherVersion(m.version(), m.sections[0], m.cfg.Lectionary, m.cfg.UILanguage); l != "" { label = l } } @@ -287,17 +286,19 @@ func (m Model) headerText() string { // through: a loading/error/empty notice, or each section's heading + // render.GatherVersion blocks for the active version. func (m Model) bodyLines(w int) []string { + ui := i18n.Get(m.cfg.UILanguage) + switch { case m.err != nil: return []string{ - errStyle.Render("błąd: " + m.err.Error()), + errStyle.Render(ui.ErrorPrefix + m.err.Error()), "", - citationStyle.Render("zmień datę (←/→) lub odśwież (r)"), + citationStyle.Render(ui.ErrorHint), } case m.loading: - return []string{citationStyle.Render("ładowanie…")} + return []string{citationStyle.Render(ui.Loading)} case len(m.sections) == 0: - return []string{citationStyle.Render("brak czytań na " + m.date)} + return []string{citationStyle.Render(ui.NoReadingsFor + m.date)} } ver := m.version() @@ -306,13 +307,14 @@ func (m Model) bodyLines(w int) []string { if i > 0 { lines = append(lines, "") } - lines = append(lines, headingStyle.Render(sec.Heading)) + heading := render.LocalizeHeading(sec.Heading, sec.PartID, m.cfg.UILanguage) + lines = append(lines, headingStyle.Render(heading)) if sec.Subtitle != "" { lines = append(lines, citationStyle.Render(sec.Subtitle)) } lines = append(lines, "") - _, blocks := render.GatherVersion(ver, sec, m.cfg.Lectionary) + _, blocks := render.GatherVersion(ver, sec, m.cfg.Lectionary, m.cfg.UILanguage) isPsalm := sec.PartID == "psalm" for bi, b := range blocks { refrain := isPsalm && bi == 0 diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go index 2aa7b84..baa5c05 100644 --- a/internal/tui/tui_test.go +++ b/internal/tui/tui_test.go @@ -1,9 +1,11 @@ package tui import ( + "strings" "testing" "github.com/lukaszkasprzak/lectio/internal/config" + "github.com/lukaszkasprzak/lectio/internal/liturgy" ) func TestVersionCycle(t *testing.T) { @@ -29,3 +31,55 @@ func TestOfflineDropsPL(t *testing.T) { } } } + +// TestBodyLinesLocalisesMessages checks that the loading/no-readings/error +// messages follow cfg.UILanguage. +func TestBodyLinesLocalisesMessages(t *testing.T) { + en := Model{cfg: config.Config{UILanguage: "en"}, loading: true} + if lines := en.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "loading") { + t.Errorf("en loading bodyLines = %v, want it to contain %q", lines, "loading") + } + + pl := Model{cfg: config.Config{UILanguage: "pl"}, loading: true} + if lines := pl.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "ładowanie") { + t.Errorf("pl loading bodyLines = %v, want it to contain %q", lines, "ładowanie") + } + + enEmpty := Model{cfg: config.Config{UILanguage: "en"}, date: "2026-07-22"} + if lines := enEmpty.bodyLines(80); len(lines) == 0 || !strings.Contains(lines[0], "no readings for") { + t.Errorf("en no-readings bodyLines = %v, want it to contain %q", lines, "no readings for") + } +} + +// TestBodyLinesLocalisesHeading checks that a modern-lectionary section +// heading's label word follows cfg.UILanguage while the citation stays +// exactly as scraped (render.LocalizeHeading, brief §3b). +func TestBodyLinesLocalisesHeading(t *testing.T) { + sec := liturgy.Section{Heading: "Ewangelia (J 20, 1. 11-18)", PartID: "ewangelia"} + + en := Model{cfg: config.Config{UILanguage: "en", Lectionary: "new"}, sections: []liturgy.Section{sec}} + body := strings.Join(en.bodyLines(80), "\n") + if !strings.Contains(body, "Gospel (J 20, 1. 11-18)") { + t.Errorf("en bodyLines missing localised heading: %q", body) + } + + pl := Model{cfg: config.Config{UILanguage: "pl", Lectionary: "new"}, sections: []liturgy.Section{sec}} + body = strings.Join(pl.bodyLines(80), "\n") + if !strings.Contains(body, "Ewangelia (J 20, 1. 11-18)") { + t.Errorf("pl bodyLines missing unchanged heading: %q", body) + } +} + +// TestFooterKeysLocalised checks the footer keybar text follows +// cfg.UILanguage. +func TestFooterKeysLocalised(t *testing.T) { + en := Model{cfg: config.Config{UILanguage: "en"}, date: "2026-07-22"} + if out := en.View(); !strings.Contains(out, "q quit") { + t.Errorf("en View() footer missing %q: %q", "q quit", out) + } + + pl := Model{cfg: config.Config{UILanguage: "pl"}, date: "2026-07-22"} + if out := pl.View(); !strings.Contains(out, "q wyjście") { + t.Errorf("pl View() footer missing %q: %q", "q wyjście", out) + } +} -- cgit v1.3