diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 19:03:15 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 19:03:15 +0200 |
| commit | 9100973576f87adcadaf6c8b331df7e729aeb117 (patch) | |
| tree | b67377705bb50c30004c52abc423573d1b335ca8 /internal/i18n/golden_test.go | |
| parent | 771ec96f07499d6efbcb587f94e30ffcbc4e0e58 (diff) | |
| download | lectio-9100973576f87adcadaf6c8b331df7e729aeb117.tar.gz lectio-9100973576f87adcadaf6c8b331df7e729aeb117.zip | |
i18n: make all UI chrome user-translatable via ui/<code>.ini
The interface chrome (version labels, TUI keybar/messages, CLI banner words,
web control labels, section-heading words) was English/Polish hardcoded in Go.
It is now data: the English and Polish tables ship as embedded lang/en.ini and
lang/pl.ini, and any language is user-overridable at <config>/ui/<code>.ini,
resolved per key with an English fallback. With ui_language = <code> plus a
names/<code>.ini, the WHOLE interface -- chrome, day names, saint names -- is
translatable without a rebuild.
- i18n.Get loads the embedded English baseline, overlays the embedded/user
language file, caches per lang; field <-> INI-key mapping is by reflection
(lang.go) so the tables and files stay in sync automatically. Edge-space
values (e.g. "error: ") are double-quoted so the INI trim keeps them. The
Go tables move to golden_test.go; TestGoldenMatchesEmbedded asserts the
embedded files still parse back to them, and TestGenerateLangFiles
regenerates them (LECTIO_GEN=1).
- config.UIDir(); wire i18n.SetUserDir in the CLI, TUI and web entry points.
- README/config: document ui/<code>.ini alongside names/<code>.ini.
Diffstat (limited to 'internal/i18n/golden_test.go')
| -rw-r--r-- | internal/i18n/golden_test.go | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/internal/i18n/golden_test.go b/internal/i18n/golden_test.go new file mode 100644 index 0000000..e6dc00a --- /dev/null +++ b/internal/i18n/golden_test.go @@ -0,0 +1,191 @@ +package i18n + +import ( + "reflect" + "testing" +) + +// enUI and plUI are the golden chrome tables. They are the SOURCE the embedded +// lang/en.ini and lang/pl.ini are generated from (TestGenerateLangFiles), and +// TestGoldenMatchesEmbedded asserts the embedded files still parse back to them +// -- so a hand-edit to a lang file that drifts from these is caught. +var enUI = UI{ + Version: map[string]string{ + "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 d date j/k scroll space/b page g/G top/bottom q quit", + Loading: "loading…", + NoReadingsFor: "no readings for ", + ErrorPrefix: "error: ", + ErrorHint: "change date (←/→)", + JumpPrompt: "go to date (YYYY-MM-DD)", + ReaderTitle: "reader — pick a book", + ReaderPickKeys: "type to filter ↑/↓ move enter open esc quit", + ReaderReadKeys: "n/p chapter c go-to tab version j/k scroll m mark b bookmarks esc books q quit", + ReaderNoText: "(no text in this version)", + ReaderNoMatch: "(no matching books)", + ReaderMarkPrompt: "note (enter to save, esc to cancel)", + ReaderBookmarksTitle: "bookmarks", + ReaderBookmarksKeys: "j/k move enter open d delete esc back q quit", + ReaderNoBookmarks: "no bookmarks yet — press m while reading", + ReaderMarkVerseKeys: "↑/↓ pick verse enter add note esc cancel", + ReaderConfirmDelete: "Delete this bookmark?", + ReaderConfirmKeys: "y = delete n = cancel", + ReaderMarkNote: "note", + ReaderMarkTags: "tags", + ReaderMarkHelp: "enter save · tab switch field · esc cancel", + ReaderJumpChapter: "go to chapter", + ReaderJumpChapterKeys: "enter go · esc cancel", + BannerGospel: "Gospel", + BannerReadings: "Readings", + BannerConnective: "for", + Months: [12]string{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}, + 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", + NoInterlinearVerses: "(no verses to align)", + NavReader: "reader", + WebBook: "book", + WebChapter: "chapter", + NavHome: "home", + NavSettings: "settings", + NavBookmarks: "bookmarks", + WebVerseOptional: "verse (optional)", + WebTagsPlaceholder: "tags, comma-separated", + WebAddBookmark: "bookmark", + WebAllTags: "all", + WebNoBookmarks: "No bookmarks yet.", + WebDelete: "delete", + WebSaved: "Saved.", + WebUILang: "UI language", + WebSiglaStyle: "sigla style", + WebDefaultVersion: "default version", + WebVersions: "versions", + WebWebVersions: "web versions", + WebOffline: "offline", + WebWidth: "width", + WebPort: "web port", + WebPager: "pager", + WebSave: "Save", + Export: "download", + Calendar: "month calendar", + NoReadingsDay: "no readings for this day", + NoVersion: "(not in %s)", + NoVersionPartial: "(not in %s: %s)", + NoReference: "(no reference)", + NoReferenceErr: "(no reference: %v)", +} + +var plUI = UI{ + Version: map[string]string{ + "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ń d data j/k przewiń spacja/b strona g/G góra/dół q wyjście", + Loading: "ładowanie…", + NoReadingsFor: "brak czytań na ", + ErrorPrefix: "błąd: ", + ErrorHint: "zmień datę (←/→)", + JumpPrompt: "przejdź do daty (RRRR-MM-DD)", + ReaderTitle: "czytnik — wybierz księgę", + ReaderPickKeys: "wpisz, by filtrować ↑/↓ ruch enter otwórz esc wyjście", + ReaderReadKeys: "n/p rozdział c skok tab wersja j/k przewiń m zakładka b zakładki esc księgi q wyjście", + ReaderNoText: "(brak tekstu w tej wersji)", + ReaderNoMatch: "(brak pasujących ksiąg)", + ReaderMarkPrompt: "notatka (enter zapisz, esc anuluj)", + ReaderBookmarksTitle: "zakładki", + ReaderBookmarksKeys: "j/k ruch enter otwórz d usuń esc wróć q wyjście", + ReaderNoBookmarks: "brak zakładek — naciśnij m podczas czytania", + ReaderMarkVerseKeys: "↑/↓ wybierz werset enter notatka esc anuluj", + ReaderConfirmDelete: "Usunąć zakładkę?", + ReaderConfirmKeys: "y = usuń n = anuluj", + ReaderMarkNote: "notatka", + ReaderMarkTags: "tagi", + ReaderMarkHelp: "enter zapisz · tab pole · esc anuluj", + ReaderJumpChapter: "przejdź do rozdziału", + ReaderJumpChapterKeys: "enter przejdź · esc anuluj", + BannerGospel: "Ewangelia", + BannerReadings: "Czytania", + BannerConnective: "na", + Months: [12]string{"Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"}, + 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", + NoInterlinearVerses: "(brak wersetów do zestawienia interlinearnego)", + NavReader: "czytnik", + WebBook: "księga", + WebChapter: "rozdział", + NavHome: "strona główna", + NavSettings: "ustawienia", + NavBookmarks: "zakładki", + WebVerseOptional: "werset (opcjonalnie)", + WebTagsPlaceholder: "tagi, oddzielone przecinkami", + WebAddBookmark: "zakładka", + WebAllTags: "wszystkie", + WebNoBookmarks: "Brak zakładek.", + WebDelete: "usuń", + WebSaved: "Zapisano.", + WebUILang: "język interfejsu", + WebSiglaStyle: "styl sigli", + WebDefaultVersion: "wersja domyślna", + WebVersions: "wersje", + WebWebVersions: "wersje web", + WebOffline: "offline", + WebWidth: "szerokość", + WebPort: "port web", + WebPager: "pager", + WebSave: "Zapisz", + Export: "pobierz", + Calendar: "kalendarz miesiąca", + NoReadingsDay: "brak czytań na ten dzień", + NoVersion: "(brak w „%s”)", + NoVersionPartial: "(brak w „%s”: %s)", + NoReference: "(brak odwołania)", + NoReferenceErr: "(brak odwołania: %w)", +} + +func TestGoldenMatchesEmbedded(t *testing.T) { + if got := Get("en"); !reflect.DeepEqual(got, enUI) { + t.Errorf("Get(en) != golden enUI:\n got %+v\nwant %+v", got, enUI) + } + if got := Get("pl"); !reflect.DeepEqual(got, plUI) { + t.Errorf("Get(pl) != golden plUI:\n got %+v\nwant %+v", got, plUI) + } +} |
