aboutsummaryrefslogtreecommitdiff
path: root/internal/config
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-27 14:59:14 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-27 14:59:14 +0200
commitcb3379f41c06a94085c77fe359709b46712850dc (patch)
tree032801111764c83c3ab089ed101ba4d1222a9abd /internal/config
parenta13dd6224a095242da54062e4775570c4f16a718 (diff)
downloadlectio-cb3379f41c06a94085c77fe359709b46712850dc.tar.gz
lectio-cb3379f41c06a94085c77fe359709b46712850dc.zip
feat: books.toml -> books.ini, multi-language (add Latin dialect), config-scoped citation display
books.ini with [en]/[pl]/[la]; parseBooks reads INI (bible drops go-toml). Latin dialect resolves EF citations (Eccli->Sirach, Apoc->Revelation, Luc...); sigla_style gains 'latin'. Reading citations now DISPLAY in the configured sigla (FormatRef(SiglaLang)), not raw English. One-shot books.toml->books.ini user migration (go-toml now config-only). Web settings editor -> books.ini.
Diffstat (limited to 'internal/config')
-rw-r--r--internal/config/config.go74
1 files changed, 65 insertions, 9 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index 54185d1..8d2ddca 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -38,7 +38,7 @@ const configHeader = `# lectio configuration (INI). Full-line comments only (# o
# all true | false (all readings, or just the gospel)
# offline true | false (never fetch; cache/sigla only)
# ui_language en | pl (interface chrome; readings stay source-language)
-# sigla_style auto | polish | english (citation dialect; auto follows ui_language)
+# sigla_style auto | polish | english | latin (citation dialect; auto follows ui_language)
# web_theme a theme name (see docs/THEMES.md)
# web_port integer; 0 = try 1099, then any free port
# web_display horizontal | vertical | interlinear
@@ -135,6 +135,8 @@ func NormalizeSiglaStyle(s string) string {
switch strings.ToLower(strings.TrimSpace(s)) {
case "polish", "pl":
return "polish"
+ case "latin", "la":
+ return "latin"
case "english", "en":
return "english"
default:
@@ -190,6 +192,8 @@ func (c Config) SiglaLang() string {
switch c.SiglaStyle {
case "polish":
return "pl"
+ case "latin":
+ return "la"
case "english":
return "en"
default:
@@ -270,7 +274,7 @@ func CalendarsDir() (string, error) {
return filepath.Join(filepath.Dir(p), "calendars"), nil
}
-// BooksPath returns the path to the optional user books.toml (in the same
+// BooksPath returns the path to the optional user books.ini (in the same
// directory as the config file). There is no embedded seed on disk -- absence
// means "use the built-in defaults".
func BooksPath() (string, error) {
@@ -278,22 +282,74 @@ func BooksPath() (string, error) {
if err != nil {
return "", err
}
- return filepath.Join(filepath.Dir(p), "books.toml"), nil
+ return filepath.Join(filepath.Dir(p), "books.ini"), nil
}
-// UserBooksTOML returns the bytes of the optional user books.toml (see
-// BooksPath), or nil when it is absent or unreadable -- callers then fall back
-// to bible's embedded default table.
-func UserBooksTOML() []byte {
+// UserBooksINI returns the bytes of the optional user books.ini (see BooksPath),
+// or nil when absent/unreadable -- callers then fall back to bible's embedded
+// default table. A former books.toml at the same location is converted to
+// books.ini once, on first read (the old file is kept).
+func UserBooksINI() []byte {
p, err := BooksPath()
if err != nil {
return nil
}
- b, err := os.ReadFile(p)
+ if b, err := os.ReadFile(p); err == nil {
+ return b
+ }
+ tomlPath := filepath.Join(filepath.Dir(p), "books.toml")
+ data, err := os.ReadFile(tomlPath)
if err != nil {
return nil
}
- return b
+ out := booksTOMLtoINI(data)
+ if out == nil {
+ return nil
+ }
+ _ = os.WriteFile(p, out, 0o644)
+ fmt.Fprintf(os.Stderr, "lectio: migrated %s -> books.ini (old file kept)\n", tomlPath)
+ return out
+}
+
+// booksTOMLtoINI converts a former books.toml (dialect -> book -> [forms]) into
+// books.ini. Returns nil if the TOML is unparseable.
+func booksTOMLtoINI(data []byte) []byte {
+ var raw map[string]map[string][]string
+ if err := toml.Unmarshal(data, &raw); err != nil {
+ return nil
+ }
+ var b strings.Builder
+ b.WriteString("# lectio book names & abbreviations, per dialect (migrated from books.toml).\n")
+ emit := func(d string) {
+ books := raw[d]
+ if books == nil {
+ return
+ }
+ fmt.Fprintf(&b, "\n[%s]\n", d)
+ keys := make([]string, 0, len(books))
+ for k := range books {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ fmt.Fprintf(&b, "%s = %s\n", k, strings.Join(books[k], ", "))
+ }
+ }
+ seen := map[string]bool{"en": true, "pl": true, "la": true}
+ emit("en")
+ emit("pl")
+ emit("la")
+ others := make([]string, 0)
+ for d := range raw {
+ if !seen[d] {
+ others = append(others, d)
+ }
+ }
+ sort.Strings(others)
+ for _, d := range others {
+ emit(d)
+ }
+ return []byte(b.String())
}
// seedIfMissing writes the embedded default config to path if nothing is