diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-23 22:08:56 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-23 22:08:56 +0200 |
| commit | 390f8cb146c69d8d3a0e6e0d76ea3546f30a7611 (patch) | |
| tree | 99510b1fe2d80bfc1ab26473a53def3318bed256 /internal/render | |
| parent | 4c776396115c8120c3e1cb8fda993449fcdcd326 (diff) | |
| download | lectio-390f8cb146c69d8d3a0e6e0d76ea3546f30a7611.tar.gz lectio-390f8cb146c69d8d3a0e6e0d76ea3546f30a7611.zip | |
i18n: fix consistency-review gaps in ui_language (en/pl chrome)
Closes six findings from review of the ui_language feature so English
mode carries no leftover Polish UI text:
- Web: interlinear "no verses" note and the empty-day error fragment now
route through i18n instead of being unconditionally Polish.
- render.GatherVersion/GatherVerses/resolveRef's four lookup/citation-
failure blocks are now lang-aware (resolveRef gained a lang param).
- i18n.ErrorPrefix/NoReadingsFor lost a stray extra trailing space,
restoring the pre-i18n single-space TUI concatenation.
- render.LocalizeHeading now matches a heading's actual leading label
text against all known modern pl labels, rather than trusting the
label keyed by sec.PartID -- fixes split-feast days where PartID is
"drugie_czytanie" but the heading still reads "1. czytanie ...".
- cli bannerFor is lang-specific again (pl "na", en "for"), restoring
pl's exact pre-i18n wording instead of "--" for both languages.
- index.html's <html lang> now follows cfg.UILanguage instead of being
hardcoded "pl".
gofmt/vet clean, go test ./... green, all three binaries build, no new
go.mod deps. Consistency grep across cli/tui/web/render's live source
turns up only two non-displayed identifiers (a PartID slug list and a
pre-existing incipit-stripping constant on the pl scripture text itself).
Diffstat (limited to 'internal/render')
| -rw-r--r-- | internal/render/render.go | 62 | ||||
| -rw-r--r-- | internal/render/render_test.go | 56 |
2 files changed, 97 insertions, 21 deletions
diff --git a/internal/render/render.go b/internal/render/render.go index c5a2ab0..6bccc65 100644 --- a/internal/render/render.go +++ b/internal/render/render.go @@ -24,28 +24,45 @@ func versionLabel(version, lang string) string { return version } +// modernPartOrder is the fixed, deterministic order LocalizeHeading tries +// the known modern (niedziela.pl) pl part labels in -- a plain slice rather +// than ranging over i18n.UI.PartLabel (a map, so Go randomises its +// iteration order). None of the five labels is a prefix of another, so the +// order never changes which one matches, only determinism. +var modernPartOrder = []string{"pierwsze_czytanie", "drugie_czytanie", "psalm", "aklamacja", "ewangelia"} + // LocalizeHeading swaps a modern (niedziela.pl) section heading's leading // label word for its lang translation, keeping the rest of the heading (the // parenthetical citation, exactly as scraped) untouched: e.g. -// "Ewangelia (J 20, 1. 11-18)" with partID "ewangelia" and lang "en" becomes -// "Gospel (J 20, 1. 11-18)". It only ever localises the label word, never -// the citation or the verse text. +// "Ewangelia (J 20, 1. 11-18)" with lang "en" becomes "Gospel (J 20, 1. +// 11-18)". It only ever localises the label word, never the citation or the +// verse text. +// +// It matches against heading's own leading text, not partID: a split +// (two-reading) feast day scrapes PartID="drugie_czytanie" onto a heading +// that niedziela.pl still literally titles "1. czytanie ..." (its own +// numbering quirk carries over from the undivided day), so looking up the +// Polish label by partID and checking heading's prefix against only that +// one label misses it. Instead every known pl label (modernPartOrder) is +// tried against heading in turn; partID itself is unused -- kept in the +// signature for callers, which all have it in hand already (sec.PartID). // -// It is a safe no-op (returns heading unchanged) unless all of: lang is -// "en", partID names a known modern-lectionary part (see -// internal/i18n.UI.PartLabel), and heading actually starts with that part's -// Polish label -- which excludes traditional (missalemeum) headings, already -// in the requested language, and anything unrecognised. +// It is a safe no-op (returns heading unchanged) unless lang is "en" and +// heading actually starts with one of the known pl labels -- which excludes +// traditional (missalemeum) headings, already in the requested language, +// and anything unrecognised. func LocalizeHeading(heading, partID, lang string) string { if lang != "en" { return heading } - plLabel, ok := i18n.Get("pl").PartLabel[partID] - if !ok || !strings.HasPrefix(heading, plLabel) { - return heading + plUI, enUI := i18n.Get("pl"), i18n.Get("en") + for _, id := range modernPartOrder { + plLabel := plUI.PartLabel[id] + if strings.HasPrefix(heading, plLabel) { + return enUI.PartLabel[id] + heading[len(plLabel):] + } } - enLabel := i18n.Get(lang).PartLabel[partID] - return enLabel + heading[len(plLabel):] + return heading } // versionSystem maps a bible version to the Psalter system bible.ToEnglishRef @@ -83,14 +100,14 @@ func GatherVersion(version string, sec liturgy.Section, lectionary, lang string) return label, gatherPL(sec) } - ref, err := resolveRef(version, sec, lectionary) + ref, err := resolveRef(version, sec, lectionary, lang) if err != nil { return label, []string{err.Error()} } verses, missing := bible.Lookup(version, ref) if len(verses) == 0 { - return label, []string{fmt.Sprintf("(brak w „%s”)", version)} + return label, []string{fmt.Sprintf(i18n.Get(lang).NoVersion, version)} } blocks = make([]string, 0, len(verses)) @@ -98,7 +115,7 @@ func GatherVersion(version string, sec liturgy.Section, lectionary, lang string) blocks = append(blocks, fmt.Sprintf("%d:%d %s", v.Chapter, v.Verse, v.Text)) } if len(missing) > 0 { - blocks = append(blocks, fmt.Sprintf("(brak w „%s”: %s)", version, strings.Join(missing, ", "))) + blocks = append(blocks, fmt.Sprintf(i18n.Get(lang).NoVersionPartial, version, strings.Join(missing, ", "))) } return label, blocks } @@ -108,8 +125,11 @@ func GatherVersion(version string, sec liturgy.Section, lectionary, lang string) // converted to English/kjv-style via bible.ToEnglishRef when // lectionary=="new" (a "traditional" citation is already English-style and // used as-is). Shared by GatherVersion and GatherVerses so both apply the -// exact same resolution. -func resolveRef(version string, sec liturgy.Section, lectionary string) (string, error) { +// exact same resolution. lang selects the wording of the two failure +// messages it can return (see internal/i18n.UI.NoReference/NoReferenceErr); +// it never affects which reference is resolved. +func resolveRef(version string, sec liturgy.Section, lectionary, lang string) (string, error) { + ui := i18n.Get(lang) citation := sec.Citation if citation == "" { if c, err := liturgy.ExtractCitation(sec.Heading); err == nil { @@ -117,7 +137,7 @@ func resolveRef(version string, sec liturgy.Section, lectionary string) (string, } } if citation == "" { - return "", fmt.Errorf("(brak odwołania)") + return "", fmt.Errorf("%s", ui.NoReference) } if lectionary != "new" { @@ -125,7 +145,7 @@ func resolveRef(version string, sec liturgy.Section, lectionary string) (string, } ref, err := bible.ToEnglishRef(citation, system(version)) if err != nil { - return "", fmt.Errorf("(brak odwołania: %w)", err) + return "", fmt.Errorf(ui.NoReferenceErr, err) } return ref, nil } @@ -141,7 +161,7 @@ func GatherVerses(version string, sec liturgy.Section, lectionary, lang string) return label, nil, false } - ref, err := resolveRef(version, sec, lectionary) + ref, err := resolveRef(version, sec, lectionary, lang) if err != nil { return label, nil, false } diff --git a/internal/render/render_test.go b/internal/render/render_test.go index b016d6b..affaaf8 100644 --- a/internal/render/render_test.go +++ b/internal/render/render_test.go @@ -76,6 +76,56 @@ func TestCompareLabelLang(t *testing.T) { } } +// TestGatherVersionNoVersionLang checks that the "(not in %s)" block +// (bible.Lookup finding nothing at all) follows lang -- pl reproduces the +// original Polish wording exactly, en uses internal/i18n's English wording. +func TestGatherVersionNoVersionLang(t *testing.T) { + sec := liturgy.Section{Heading: "Ewangelia (J 20, 1. 11-18)"} + + _, blocks := GatherVersion("zzz", sec, "new", "pl") + if len(blocks) == 0 || blocks[0] != `(brak w „zzz”)` { + t.Errorf(`GatherVersion(..., "pl") blocks = %v, want [(brak w „zzz”)]`, blocks) + } + + _, blocks = GatherVersion("zzz", sec, "new", "en") + if len(blocks) == 0 || blocks[0] != "(not in zzz)" { + t.Errorf(`GatherVersion(..., "en") blocks = %v, want [(not in zzz)]`, blocks) + } +} + +// TestGatherVersionNoReferenceLang checks the "(no reference)" block (no +// citation resolvable at all) follows lang. +func TestGatherVersionNoReferenceLang(t *testing.T) { + sec := liturgy.Section{Heading: "Bez odwołania"} + + _, blocks := GatherVersion("wuj", sec, "new", "pl") + if len(blocks) == 0 || blocks[0] != "(brak odwołania)" { + t.Errorf(`GatherVersion(..., "pl") blocks = %v, want [(brak odwołania)]`, blocks) + } + + _, blocks = GatherVersion("wuj", sec, "new", "en") + if len(blocks) == 0 || blocks[0] != "(no reference)" { + t.Errorf(`GatherVersion(..., "en") blocks = %v, want [(no reference)]`, blocks) + } +} + +// TestGatherVersionNoReferenceErrLang checks the "(no reference: ...)" block +// (a citation that bible.ToEnglishRef fails to convert, e.g. an unrecognised +// book) follows lang. +func TestGatherVersionNoReferenceErrLang(t *testing.T) { + sec := liturgy.Section{Citation: "Xyz 1, 1-2"} + + _, blocks := GatherVersion("wuj", sec, "new", "pl") + if len(blocks) == 0 || !strings.HasPrefix(blocks[0], "(brak odwołania: ") { + t.Errorf(`GatherVersion(..., "pl") blocks = %v, want prefix "(brak odwołania: "`, blocks) + } + + _, blocks = GatherVersion("wuj", sec, "new", "en") + if len(blocks) == 0 || !strings.HasPrefix(blocks[0], "(no reference: ") { + t.Errorf(`GatherVersion(..., "en") blocks = %v, want prefix "(no reference: "`, blocks) + } +} + func TestOfflineVersions(t *testing.T) { got := OfflineVersions([]string{"pl", "wuj", "vul"}) for _, v := range got { @@ -143,6 +193,12 @@ func TestLocalizeHeading(t *testing.T) { {"unknown partID unchanged", "Coś innego (X 1)", "", "en", "Coś innego (X 1)"}, {"already-English heading unchanged (traditional lectionary, no pl prefix to match)", "Gospel (Luke 7:36-50)", "ewangelia", "en", "Gospel (Luke 7:36-50)"}, {"prefix mismatch unchanged", "Nieoczekiwany tytuł (J 1)", "ewangelia", "en", "Nieoczekiwany tytuł (J 1)"}, + // Split (two-reading) feast day: niedziela.pl scrapes + // PartID="drugie_czytanie" onto a heading that still literally + // starts with "1. czytanie" (its own numbering quirk). Matching + // must follow the heading's actual text, not partID's label, so + // this localises to "1st reading", not staying Polish. + {"drugie_czytanie partID with a 1. czytanie heading (split feast day)", "1. czytanie (Dz 2, 14. 22-33)", "drugie_czytanie", "en", "1st reading (Dz 2, 14. 22-33)"}, } for _, c := range cases { |
