diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-23 21:51:40 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-23 21:51:40 +0200 |
| commit | 4c776396115c8120c3e1cb8fda993449fcdcd326 (patch) | |
| tree | 0144fb325663dde063057a5ec568c59d4cbe79da /internal/i18n | |
| parent | bfa8df7b36ccbd44703e0705d51a2ed553a23164 (diff) | |
| download | lectio-4c776396115c8120c3e1cb8fda993449fcdcd326.tar.gz lectio-4c776396115c8120c3e1cb8fda993449fcdcd326.zip | |
i18n: ui_language config (default en) for UI chrome across cli/tui/web; version labels localised
Diffstat (limited to 'internal/i18n')
| -rw-r--r-- | internal/i18n/i18n.go | 114 | ||||
| -rw-r--r-- | internal/i18n/i18n_test.go | 145 |
2 files changed, 259 insertions, 0 deletions
diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go new file mode 100644 index 0000000..a5cb77b --- /dev/null +++ b/internal/i18n/i18n.go @@ -0,0 +1,114 @@ +// Package i18n holds lectio's UI-chrome string tables (English and Polish) +// for the ui_language config setting. It localises the chrome only -- +// version-column labels, the TUI keybar/messages, the CLI banner words, the +// web control labels, and the modern-lectionary section-heading label words +// -- never the scripture verse text or citation, which stay source-language. +package i18n + +// UI is one language's complete set of chrome strings. +type UI struct { + // Version names each bible version for column headers / prose, keyed by + // version code (pl, wuj, vul, grb, drb). + Version map[string]string + + // PartLabel names each modern-lectionary section's heading label word, + // keyed by liturgy.Section.PartID (pierwsze_czytanie, psalm, + // drugie_czytanie, aklamacja, ewangelia). The pl entries are the exact + // prefixes niedziela.pl's scraped headings carry, used by + // render.LocalizeHeading to recognise and swap the label word while + // keeping the citation untouched. + PartLabel map[string]string + + // TUI keybar and status messages. + FooterKeys, Loading, NoReadingsFor, ErrorPrefix, ErrorHint string + + // CLI banner label words: the banner is "<word> — <date>". + BannerGospel, BannerReadings string + + // Web control labels. + Lectionary, OptModern, OptTraditional string + Parts, OptGospel, OptAll string + Layout, OptHorizontal, OptColumns string + OptInterlinear, Theme, Mono string +} + +// Get returns lang's chrome string set, falling back to English for +// anything other than "pl". +func Get(lang string) UI { + if lang == "pl" { + return plUI + } + return enUI +} + +var enUI = UI{ + Version: map[string]string{ + "pl": "Polish (niedziela.pl)", + "wuj": "Wujek (Polish)", + "vul": "Vulgate (Latin)", + "grb": "Greek", + "drb": "Douay-Rheims (English)", + }, + PartLabel: map[string]string{ + "pierwsze_czytanie": "1st reading", + "psalm": "Psalm", + "drugie_czytanie": "2nd reading", + "aklamacja": "Acclamation", + "ewangelia": "Gospel", + }, + FooterKeys: "tab/⇧tab version ←/→ day j/k scroll space/b page g/G top/bottom r refresh q quit", + Loading: "loading…", + NoReadingsFor: "no readings for ", + ErrorPrefix: "error: ", + ErrorHint: "change date (←/→) or refresh (r)", + BannerGospel: "Gospel", + BannerReadings: "Readings", + Lectionary: "lectionary", + OptModern: "modern", + OptTraditional: "traditional", + Parts: "parts", + OptGospel: "Gospel", + OptAll: "all parts", + Layout: "layout", + OptHorizontal: "horizontal", + OptColumns: "columns", + OptInterlinear: "interlinear", + Theme: "theme", + Mono: "mono", +} + +var plUI = UI{ + Version: map[string]string{ + "pl": "Polski (niedziela.pl)", + "wuj": "Wujek (pol.)", + "vul": "Wulgata (lac.)", + "grb": "Grecki", + "drb": "Douay-Rheims (ang.)", + }, + PartLabel: map[string]string{ + "pierwsze_czytanie": "1. czytanie", + "psalm": "Psalm", + "drugie_czytanie": "2. czytanie", + "aklamacja": "Aklamacja", + "ewangelia": "Ewangelia", + }, + FooterKeys: "tab/⇧tab wersja ←/→ dzień j/k przewiń spacja/b strona g/G góra/dół r odśwież q wyjście", + Loading: "ładowanie…", + NoReadingsFor: "brak czytań na ", + ErrorPrefix: "błąd: ", + ErrorHint: "zmień datę (←/→) lub odśwież (r)", + BannerGospel: "Ewangelia", + BannerReadings: "Czytania", + Lectionary: "lekcjonarz", + OptModern: "nowy", + OptTraditional: "tradycyjny", + Parts: "zakres", + OptGospel: "Ewangelia", + OptAll: "wszystkie części", + Layout: "układ", + OptHorizontal: "poziomo", + OptColumns: "kolumny", + OptInterlinear: "interlinearnie", + Theme: "motyw", + Mono: "mono", +} diff --git a/internal/i18n/i18n_test.go b/internal/i18n/i18n_test.go new file mode 100644 index 0000000..8c6f137 --- /dev/null +++ b/internal/i18n/i18n_test.go @@ -0,0 +1,145 @@ +package i18n + +import "testing" + +func TestGetTheme(t *testing.T) { + if got := Get("pl").Theme; got != "motyw" { + t.Errorf(`Get("pl").Theme = %q, want "motyw"`, got) + } + if got := Get("en").Theme; got != "theme" { + t.Errorf(`Get("en").Theme = %q, want "theme"`, got) + } +} + +func TestGetUnknownFallsBackToEnglish(t *testing.T) { + en := Get("en") + if got := Get("xx"); got.Theme != en.Theme || got.BannerGospel != en.BannerGospel { + t.Errorf(`Get("xx") = %+v, want the English set %+v`, got, en) + } + if got := Get(""); got.Theme != en.Theme || got.BannerGospel != en.BannerGospel { + t.Errorf(`Get("") = %+v, want the English set %+v`, got, en) + } +} + +func TestVersionLabels(t *testing.T) { + cases := []struct { + lang, code, want string + }{ + {"en", "pl", "Polish (niedziela.pl)"}, + {"pl", "pl", "Polski (niedziela.pl)"}, + {"en", "wuj", "Wujek (Polish)"}, + {"pl", "wuj", "Wujek (pol.)"}, + {"en", "vul", "Vulgate (Latin)"}, + {"pl", "vul", "Wulgata (lac.)"}, + {"en", "grb", "Greek"}, + {"pl", "grb", "Grecki"}, + {"en", "drb", "Douay-Rheims (English)"}, + {"pl", "drb", "Douay-Rheims (ang.)"}, + } + for _, c := range cases { + if got := Get(c.lang).Version[c.code]; got != c.want { + t.Errorf("Get(%q).Version[%q] = %q, want %q", c.lang, c.code, got, c.want) + } + } +} + +func TestTUIStrings(t *testing.T) { + en := Get("en") + pl := Get("pl") + + if en.FooterKeys != "tab/⇧tab version ←/→ day j/k scroll space/b page g/G top/bottom r refresh q quit" { + t.Errorf("en.FooterKeys = %q", en.FooterKeys) + } + if pl.FooterKeys != "tab/⇧tab wersja ←/→ dzień j/k przewiń spacja/b strona g/G góra/dół r odśwież q wyjście" { + t.Errorf("pl.FooterKeys = %q", pl.FooterKeys) + } + if en.Loading != "loading…" || pl.Loading != "ładowanie…" { + t.Errorf("Loading en=%q pl=%q", en.Loading, pl.Loading) + } + if en.NoReadingsFor != "no readings for " || pl.NoReadingsFor != "brak czytań na " { + t.Errorf("NoReadingsFor en=%q pl=%q", en.NoReadingsFor, pl.NoReadingsFor) + } + if en.ErrorPrefix != "error: " || pl.ErrorPrefix != "błąd: " { + t.Errorf("ErrorPrefix en=%q pl=%q", en.ErrorPrefix, pl.ErrorPrefix) + } + if en.ErrorHint != "change date (←/→) or refresh (r)" || pl.ErrorHint != "zmień datę (←/→) lub odśwież (r)" { + t.Errorf("ErrorHint en=%q pl=%q", en.ErrorHint, pl.ErrorHint) + } +} + +func TestBannerWords(t *testing.T) { + en := Get("en") + pl := Get("pl") + if en.BannerGospel != "Gospel" || pl.BannerGospel != "Ewangelia" { + t.Errorf("BannerGospel en=%q pl=%q", en.BannerGospel, pl.BannerGospel) + } + if en.BannerReadings != "Readings" || pl.BannerReadings != "Czytania" { + t.Errorf("BannerReadings en=%q pl=%q", en.BannerReadings, pl.BannerReadings) + } +} + +func TestWebControlLabels(t *testing.T) { + en := Get("en") + pl := Get("pl") + + cases := []struct { + name, en, pl string + }{ + {"Lectionary", en.Lectionary, pl.Lectionary}, + {"OptModern", en.OptModern, pl.OptModern}, + {"OptTraditional", en.OptTraditional, pl.OptTraditional}, + {"Parts", en.Parts, pl.Parts}, + {"OptGospel", en.OptGospel, pl.OptGospel}, + {"OptAll", en.OptAll, pl.OptAll}, + {"Layout", en.Layout, pl.Layout}, + {"OptHorizontal", en.OptHorizontal, pl.OptHorizontal}, + {"OptColumns", en.OptColumns, pl.OptColumns}, + {"OptInterlinear", en.OptInterlinear, pl.OptInterlinear}, + {"Theme", en.Theme, pl.Theme}, + {"Mono", en.Mono, pl.Mono}, + } + want := map[string][2]string{ + "Lectionary": {"lectionary", "lekcjonarz"}, + "OptModern": {"modern", "nowy"}, + "OptTraditional": {"traditional", "tradycyjny"}, + "Parts": {"parts", "zakres"}, + "OptGospel": {"Gospel", "Ewangelia"}, + "OptAll": {"all parts", "wszystkie części"}, + "Layout": {"layout", "układ"}, + "OptHorizontal": {"horizontal", "poziomo"}, + "OptColumns": {"columns", "kolumny"}, + "OptInterlinear": {"interlinear", "interlinearnie"}, + "Theme": {"theme", "motyw"}, + "Mono": {"mono", "mono"}, + } + for _, c := range cases { + w := want[c.name] + if c.en != w[0] { + t.Errorf("en.%s = %q, want %q", c.name, c.en, w[0]) + } + if c.pl != w[1] { + t.Errorf("pl.%s = %q, want %q", c.name, c.pl, w[1]) + } + } +} + +func TestModernPartLabels(t *testing.T) { + en := Get("en") + pl := Get("pl") + + want := map[string][2]string{ + "pierwsze_czytanie": {"1. czytanie", "1st reading"}, + "psalm": {"Psalm", "Psalm"}, + "drugie_czytanie": {"2. czytanie", "2nd reading"}, + "aklamacja": {"Aklamacja", "Acclamation"}, + "ewangelia": {"Ewangelia", "Gospel"}, + } + for partID, w := range want { + if got := pl.PartLabel[partID]; got != w[0] { + t.Errorf("pl.PartLabel[%q] = %q, want %q", partID, got, w[0]) + } + if got := en.PartLabel[partID]; got != w[1] { + t.Errorf("en.PartLabel[%q] = %q, want %q", partID, got, w[1]) + } + } +} |
