Reading pane: chapter and book headings in the module's language, no scroll bar #18

Merged
schaefera merged 11 commits from phase1/chapter-headings into phase1/core-layout 2026-10-21 10:53:37 +00:00
Collaborator

Stacked on #17 (base phase1/core-layout). Merge this into phase1/core-layout first, then #17 into main. Part of #11.

What

  • Each chapter starts with a heading in the module's language (conf Lang): GerSch shows "1. Mose / Kapitel 1", BSB "Genesis / Chapter 1". A book's first chapter also gets the book name in larger type. If there is no table for the module's language (TR grc, OSHB hbo), the phone's languages are used (gettext order: LANGUAGE, then LC_ALL/LC_MESSAGES/LANG, none under C), else English.
  • All language data is in data files, not Rust. Book names come from JSword's BibleNames_*.properties (LGPL-2.1+, 61 locales). tools/booknames/ generates them from a pinned JSword commit into core/src/bible/names/books.ini, which has one [locale] section of Gen=Genesis lines per language. The words "Chapter"/"Psalm" (de en es fr it nl pt) are in the hand-written names/headings.ini; other languages show the number alone. Core embeds both with include_str! and reads them in place.
  • Locales are a type, not strings: core/src/bible/locale.rs parses a conf's BCP 47 Lang or a phone's POSIX locale once into a Locale (language, region). Section names are matched by parsed value.
  • The glue's section role is the heading itself ("book\nchapter"); qml/components/books.js is gone. The glue changes a chapter's rows and its entry together, between begin and end.
  • A heading's height binds to its lines (an Item, not a Column, which sized itself a frame late, so a reused heading overlapped verse 1). The top-verse report looks past a heading. The scroll indicator is removed.

Blast radius

trunk: core/src/bible*, qt/src/reading_model.rs, qml/pages/ReadingPane.qml.
Gate / rollback: no flag. Undo by reverting this merge, or reinstalling the #17 click. No schema or saved-state change: the saved anchor is still ordinal + fraction.
Budgets (docs/07): peak PSS 147565 kB at 37025d4 in mem-check (149959 at 36ee071, base #17 146382; budget 165000), so within run-to-run noise of ~2 MB. The name tables are ~80 KB of read-only data, paged in only where touched; nothing is parsed at start-up. A module open parses the 61 section headers (twice at most, for the region and the bare language), which is negligible; a heading scans at most 66 lines. Start-up 130 ms (noise range 80–130).
Visible change: English names are JSword's ("Revelation of John", not "Revelation"). The old qsTr book-name strings are gone; there were no translations yet. A script subtag is now skipped, so zh-Hant-TW finds zh_TW (it used to fall back to zh).

Proof

  • cargo make at 0025b06: fmt, clippy, all tests pass (40 core), coverage 94.78% (floor 93.97%), release, deny, audit. gen.py regenerates books.ini byte-identical.
  • cargo make app-docker at 37025d4: qmllint, qt clippy, -Werror build, clang-tidy pass; kill -9 restore matches in core and on screen. At 36ee071 also: mem-check scrolling 68 reports down / 21 up, steps ≤ 8 verses; inactive save 188 ms after the scroll. (Not re-run since: no QML, glue or C++ change.)
  • New tests, each shown failing under a deliberate break (undone with Edit):
    • reader::heads_chapters_in_the_module_language (GerSch → "1. Mose"/"Kapitel 1", "Psalm 23") fails when the reader ignores conf Lang.
    • names::speaks_the_module_language_else_the_phone_language_else_english fails without the region fallback (de-CH → de).
    • names::heads_chapters_and_psalms fails with the Psalm word broken.
    • names::reads_the_phone_languages_as_gettext_does fails without the C-locale rule, and again when Locale::parse accepts one-letter languages (so "C" counts).
    • locale::reads_bcp47_tags_and_posix_locales_alike fails with the script skip disabled (zh-Hant-TW → "zh", not "zh_TW").
    • names::has_every_book_in_every_language (61 locales × 66 books in order, none empty) fails with "Exod" removed from [af].
    • names::has_both_heading_words_for_languages_with_book_names fails with fr Psalm= removed.
    • names::names_its_sections_by_locale: every section name round-trips through Locale.
    • reader::reads_kjv now asserts "Genesis / Chapter 1" and "Chapter 3".
  • Heading overlap: headless Xvfb run of the real app (BSB, wheel-scrolled from Gen 1 into Exod 1). At 36ee071, "Exodus / Chapter 1" was drawn over Exod 1:1; at 37025d4 it sits in its own space. Confirmed fixed on the device.
  • Headless screenshots with only GerSch installed (36ee071): "1. Mose / Kapitel 1", "Kapitel 3" between Gen 2:25 and 3:1. Playwright doesn't apply (native Qt).
  • arm64 click built and passes click-review; installed on the device (b846f7f).
  • Not covered: the glue's Span/heading role (no qt test harness in CI); no QML test for the heading height; the number-only heading (e.g. Russian) is unit-tested in core but not on screen; the GerSch screenshot was not re-run after the height fix; gen.py's empty-name check was not run against bad input; the data-file and Locale commits were not re-installed on the device (same output by the tests). Please look at: GerSch on the device, a book boundary (Mal → Matt), and a module whose language has no table.

Review

  • Earlier rounds (be765b5 … 36ee071): reviews 1–4, audits 55 and 55; see the previous trailers. Fixed then: empty LANGUAGE entries, fetch.sh pinned, number-only heading, gettext order as a pure function.
  • Review 5/6 (b846f7f, 37025d4, heading height): no correctness bug; one source for layout numbers, plain-text headings. Audit: 75.
  • Review 7 (medium, f1169a5, books.ini): two low points fixed in 5baa837 (LF pinned by .gitattributes; gen.py refuses empty names). Audit: 85.
  • Review 8 (medium, d9b1e5f, headings.ini): no defects; nits only (whole-file scan per lookup, as before).
  • Review 9 (high, 5baa837..695782e, Locale): no correctness bugs. Three low notes, none changed:
    1. An unparseable LANG (LANG=english) now gives no languages and drops LANGUAGE. Kept: glibc's setlocale fails on an unknown locale, so messages are in C and gettext ignores LANGUAGE too.
    2. Extlang zh-yue-HK → zh, untested. Kept: no SWORD conf or phone locale uses extlang.
    3. Re-parsing ~61 section names per lookup. Kept: once per Bible open (see Budgets).
  • Audit (0025b06): Review-Confidence 80. Deductions: findings 1 and 2 kept without a test or a run showing the claim (−10, −10). No missed defect found.

Confidence by part

  • core/src/bible/names.rs, locale.rs, names/section.rs, reader.rs, names/*.ini: medium-high. Unit and golden tests, each shown failing under a break; both data files are checked whole by tests. Read Locale::parse and Names::languages.
  • reading_model.rs (Span, heading role, slide/drop ordering): medium. Reviewed and exercised by mem-check, but no unit test.
  • ReadingPane.qml (section split, heading height, restore/reportTop): medium. Screenshots, the device check and the mem-check restore cover it; no QML test harness.
  • tools/booknames/: high. Reproducible from the pinned commit.

Merge with "Create merge commit".

🤖 Generated with Claude Code

Stacked on #17 (base `phase1/core-layout`). Merge this into `phase1/core-layout` first, then #17 into `main`. Part of #11. ## What - Each chapter starts with a heading in the **module's language** (conf `Lang`): GerSch shows "1. Mose / Kapitel 1", BSB "Genesis / Chapter 1". A book's first chapter also gets the book name in larger type. If there is no table for the module's language (TR grc, OSHB hbo), the phone's languages are used (gettext order: LANGUAGE, then LC_ALL/LC_MESSAGES/LANG, none under C), else English. - All language data is in **data files**, not Rust. Book names come from JSword's `BibleNames_*.properties` (LGPL-2.1+, 61 locales). `tools/booknames/` generates them from a pinned JSword commit into `core/src/bible/names/books.ini`, which has one `[locale]` section of `Gen=Genesis` lines per language. The words "Chapter"/"Psalm" (de en es fr it nl pt) are in the hand-written `names/headings.ini`; other languages show the number alone. Core embeds both with `include_str!` and reads them in place. - Locales are a type, not strings: `core/src/bible/locale.rs` parses a conf's BCP 47 `Lang` or a phone's POSIX locale once into a `Locale` (language, region). Section names are matched by parsed value. - The glue's section role is the heading itself (`"book\nchapter"`); `qml/components/books.js` is gone. The glue changes a chapter's rows and its entry together, between begin and end. - A heading's height binds to its lines (an Item, not a Column, which sized itself a frame late, so a reused heading overlapped verse 1). The top-verse report looks past a heading. The scroll indicator is removed. ## Blast radius **trunk**: `core/src/bible*`, `qt/src/reading_model.rs`, `qml/pages/ReadingPane.qml`. Gate / rollback: no flag. Undo by reverting this merge, or reinstalling the #17 click. No schema or saved-state change: the saved anchor is still ordinal + fraction. Budgets (docs/07): peak PSS 147565 kB at 37025d4 in mem-check (149959 at 36ee071, base #17 146382; budget 165000), so within run-to-run noise of ~2 MB. The name tables are ~80 KB of read-only data, paged in only where touched; nothing is parsed at start-up. A module open parses the 61 section headers (twice at most, for the region and the bare language), which is negligible; a heading scans at most 66 lines. Start-up 130 ms (noise range 80–130). Visible change: English names are JSword's ("Revelation of John", not "Revelation"). The old `qsTr` book-name strings are gone; there were no translations yet. A script subtag is now skipped, so `zh-Hant-TW` finds `zh_TW` (it used to fall back to `zh`). ## Proof - `cargo make` at 0025b06: fmt, clippy, all tests pass (40 core), coverage 94.78% (floor 93.97%), release, deny, audit. `gen.py` regenerates `books.ini` byte-identical. - `cargo make app-docker` at 37025d4: qmllint, qt clippy, -Werror build, clang-tidy pass; kill -9 restore matches in core and on screen. At 36ee071 also: mem-check scrolling 68 reports down / 21 up, steps ≤ 8 verses; inactive save 188 ms after the scroll. (Not re-run since: no QML, glue or C++ change.) - New tests, each shown failing under a deliberate break (undone with Edit): - `reader::heads_chapters_in_the_module_language` (GerSch → "1. Mose"/"Kapitel 1", "Psalm 23") fails when the reader ignores conf `Lang`. - `names::speaks_the_module_language_else_the_phone_language_else_english` fails without the region fallback (de-CH → de). - `names::heads_chapters_and_psalms` fails with the Psalm word broken. - `names::reads_the_phone_languages_as_gettext_does` fails without the C-locale rule, and again when `Locale::parse` accepts one-letter languages (so "C" counts). - `locale::reads_bcp47_tags_and_posix_locales_alike` fails with the script skip disabled (`zh-Hant-TW` → "zh", not "zh_TW"). - `names::has_every_book_in_every_language` (61 locales × 66 books in order, none empty) fails with "Exod" removed from `[af]`. - `names::has_both_heading_words_for_languages_with_book_names` fails with fr `Psalm=` removed. - `names::names_its_sections_by_locale`: every section name round-trips through `Locale`. - `reader::reads_kjv` now asserts "Genesis / Chapter 1" and "Chapter 3". - Heading overlap: headless Xvfb run of the real app (BSB, wheel-scrolled from Gen 1 into Exod 1). At 36ee071, "Exodus / Chapter 1" was drawn over Exod 1:1; at 37025d4 it sits in its own space. Confirmed fixed on the device. - Headless screenshots with only GerSch installed (36ee071): "1. Mose / Kapitel 1", "Kapitel 3" between Gen 2:25 and 3:1. Playwright doesn't apply (native Qt). - arm64 click built and passes click-review; installed on the device (b846f7f). - **Not covered:** the glue's `Span`/heading role (no qt test harness in CI); no QML test for the heading height; the number-only heading (e.g. Russian) is unit-tested in core but not on screen; the GerSch screenshot was not re-run after the height fix; `gen.py`'s empty-name check was not run against bad input; the data-file and `Locale` commits were not re-installed on the device (same output by the tests). **Please look at:** GerSch on the device, a book boundary (Mal → Matt), and a module whose language has no table. ## Review - **Earlier rounds (be765b5 … 36ee071):** reviews 1–4, audits 55 and 55; see the previous trailers. Fixed then: empty LANGUAGE entries, fetch.sh pinned, number-only heading, gettext order as a pure function. - **Review 5/6 (b846f7f, 37025d4, heading height):** no correctness bug; one source for layout numbers, plain-text headings. **Audit:** 75. - **Review 7 (medium, f1169a5, books.ini):** two low points fixed in 5baa837 (LF pinned by `.gitattributes`; gen.py refuses empty names). **Audit:** 85. - **Review 8 (medium, d9b1e5f, headings.ini):** no defects; nits only (whole-file scan per lookup, as before). - **Review 9 (high, 5baa837..695782e, `Locale`):** no correctness bugs. Three low notes, none changed: 1. An unparseable LANG (`LANG=english`) now gives no languages and drops LANGUAGE. Kept: glibc's setlocale fails on an unknown locale, so messages are in C and gettext ignores LANGUAGE too. 2. Extlang `zh-yue-HK` → `zh`, untested. Kept: no SWORD conf or phone locale uses extlang. 3. Re-parsing ~61 section names per lookup. Kept: once per Bible open (see Budgets). - **Audit (0025b06):** **Review-Confidence 80**. Deductions: findings 1 and 2 kept without a test or a run showing the claim (−10, −10). No missed defect found. ## Confidence by part - `core/src/bible/names.rs`, `locale.rs`, `names/section.rs`, `reader.rs`, `names/*.ini`: **medium-high**. Unit and golden tests, each shown failing under a break; both data files are checked whole by tests. **Read `Locale::parse` and `Names::languages`.** - `reading_model.rs` (`Span`, heading role, slide/drop ordering): **medium**. Reviewed and exercised by mem-check, but no unit test. - `ReadingPane.qml` (section split, heading height, `restore`/`reportTop`): **medium**. Screenshots, the device check and the mem-check restore cover it; no QML test harness. - `tools/booknames/`: **high**. Reproducible from the pinned commit. Merge with "Create merge commit". 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Each chapter opens with a heading ("Chapter N", "Psalm N" in Psalms) and
each book with its name, as ListView sections on a new "reference" role.
The top-verse report looks past a heading to the first verse below; a
restore with a fraction lands on the verse, not the heading. The scroll
indicator is gone: the list is only the loaded chapters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading model: a chapter's rows and entry change together
All checks were successful
CI / rust (pull_request) Successful in 3m19s
CI / audit (pull_request) Successful in 12s
CI / app (pull_request) Successful in 1m51s
CI / click (pull_request) Successful in 1m14s
be765b5f6a
data() now reads the chapter list for the reference role, so it changes
between begin and end with the rows. The heading scan steps by at least
one pixel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Confidence: 55
Review-Tier: trunk
@ -0,0 +3,4 @@
// The books' names as the reader sees them, by OSIS id (the ids in the
// core's references, e.g. "Gen 1"). A book missing here, e.g. from a
// versification with the deuterocanon, shows its id.
const names = {
Owner

This likely won't scale very well to multiple languages; what happens when we load the Schlachter Bibel, for example?

This likely won't scale very well to multiple languages; what happens when we load the Schlachter Bibel, for example?
Book names come from JSword's BibleNames tables (LGPL-2.1-or-later),
generated into core by tools/booknames; the chapter word from a small
table (de en es fr it nl pt), else the book's name and number. The
module's conf Lang picks the table, else the phone's language, else
English: GerSch shows "1. Mose / Kapitel 1". The glue's section role
is now the heading itself, and qml/components/books.js is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LANGUAGE=":de" now picks de, as glibc does. tools/booknames/fetch.sh
fetches one JSword commit; it regenerates data.rs unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Book names: number-only headings without chapter words, gettext's language order
All checks were successful
CI / rust (pull_request) Successful in 2m46s
CI / audit (pull_request) Successful in 10s
CI / app (pull_request) Successful in 1m34s
CI / click (pull_request) Successful in 58s
36ee071d26
A language without chapter words no longer shows the book's name twice
on chapter 1: the heading is the number. The phone's languages are the
LANGUAGE list then the locale, none under C, read through a pure
function the tests feed. gen.py writes UTF-8 whatever the locale, and
fetch.sh fails on an incomplete table list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Confidence: 55
Review-Tier: trunk
claude-bot changed title from Reading pane: chapter and book headings, no scroll bar to Reading pane: chapter and book headings in the module's language, no scroll bar 2026-10-21 09:09:30 +00:00
Author
Collaborator

Re the comment on qml/components/books.js ("what happens when we load the Schlachter Bibel?"): fixed in 91bbc79..36ee071, and books.js is gone.

Headings now follow the module's language (its conf Lang=), in the Rust core:

  • GerSch shows "1. Mose / Kapitel 1", then "Kapitel 2", …, "Psalm 23"; BSB/KJV stay "Genesis / Chapter 1".
  • Book names come from JSword's BibleNames_*.properties (61 locales, LGPL-2.1+), generated into core/src/bible/names/data.rs by tools/booknames/ (pinned JSword commit).
  • No table for the module's language (TR is grc, OSHB hbo) → the phone's language, else English.
  • "Chapter"/"Psalm" words exist for de en es fr it nl pt; other languages show the number alone under the book name.

Tested in core (GerSch golden test plus locale unit tests) and on a headless screenshot; the build is on your phone.

Re the comment on `qml/components/books.js` ("what happens when we load the Schlachter Bibel?"): fixed in 91bbc79..36ee071, and `books.js` is gone. Headings now follow the module's language (its conf `Lang=`), in the Rust core: - GerSch shows **"1. Mose / Kapitel 1"**, then "Kapitel 2", …, "Psalm 23"; BSB/KJV stay "Genesis / Chapter 1". - Book names come from JSword's `BibleNames_*.properties` (61 locales, LGPL-2.1+), generated into `core/src/bible/names/data.rs` by `tools/booknames/` (pinned JSword commit). - No table for the module's language (TR is `grc`, OSHB `hbo`) → the phone's language, else English. - "Chapter"/"Psalm" words exist for de en es fr it nl pt; other languages show the number alone under the book name. Tested in core (GerSch golden test plus locale unit tests) and on a headless screenshot; the build is on your phone.
The heading was a Column, which sizes itself at polish. The ListView
reuses section items, so a one-line heading reused for "Exodus /
Chapter 1" kept its old height and overlapped verse 1. An Item whose
height binds to its Texts' implicit heights resizes at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading pane: one source for the heading's layout, plain text
All checks were successful
CI / rust (pull_request) Successful in 2m32s
CI / audit (pull_request) Successful in 11s
CI / app (pull_request) Successful in 1m33s
CI / click (pull_request) Successful in 59s
37025d4239
The height reads the chapter line's position instead of repeating the
sum, so the two can't drift apart. A module's book name is never parsed
as rich text, as for the verses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Confidence: 75
Review-Tier: trunk
@ -0,0 +12,4 @@
/// Per JSword locale, the books' full names in [`BOOKS`] order.
pub(super) const NAMES: &[(&str, [&str; 66])] = &[
(
Owner

Is there a way we can keep these strings in a different file type rather than in rust to indicate that it's static data and not actual dynamic code? I want to really keep the code files as code focused as possible.

Is there a way we can keep these strings in a different file type rather than in rust to indicate that it's static data and not actual dynamic code? I want to really keep the code files as code focused as possible.
@ -0,0 +11,4 @@
];
/// Per JSword locale, the books' full names in [`BOOKS`] order.
pub(super) const NAMES: &[(&str, [&str; 66])] = &[
Owner

A more readable type alias might be helpful here.

A more readable type alias might be helpful here.
JSword's names now live in core/src/bible/names/books.ini, one
[locale] section of Gen=Genesis lines per language, embedded with
include_str! and read in place: no allocation, and the code file holds
only code. data.rs and its BOOKS/NAMES consts are gone. A test checks
every language has all 66 books in order. gen.py regenerates the file
byte-identical from the pinned JSword commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Book names: books.ini keeps LF endings; gen.py refuses empty names
All checks were successful
CI / rust (pull_request) Successful in 2m32s
CI / audit (pull_request) Successful in 11s
CI / app (pull_request) Successful in 1m25s
CI / click (pull_request) Successful in 53s
5baa837a6c
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Confidence: 85
Review-Tier: trunk
Author
Collaborator

Re the two comments on core/src/bible/names/data.rs, fixed in f1169a5 and 5baa837.

Data file instead of Rust. The names now live in core/src/bible/names/books.ini, a plain data file with one [locale] section of OSIS=name lines per language:

[de]
Gen=1. Mose
Exod=2. Mose

names.rs embeds it with include_str! and reads the strings where they lie, without copying them. A lookup scans at most 66 lines of one section. It uses the same memory as before (~80 KB of read-only data) and does no work at start-up. tools/booknames/gen.py writes the file, and regenerating it from the pinned JSword commit gives a byte-identical file. .gitattributes keeps it at LF line endings.

Type alias. It isn't needed any more: data.rs is gone, and with it the BOOKS and NAMES consts and their array type. Names now holds just its locale and that locale's section of the file.

A new test, has_every_book_in_every_language, checks that all 61 languages have the 66 books in the same order, with no empty names. It fails if a book is missing.

Re the two comments on `core/src/bible/names/data.rs`, fixed in f1169a5 and 5baa837. **Data file instead of Rust.** The names now live in `core/src/bible/names/books.ini`, a plain data file with one `[locale]` section of `OSIS=name` lines per language: ```ini [de] Gen=1. Mose Exod=2. Mose ``` `names.rs` embeds it with `include_str!` and reads the strings where they lie, without copying them. A lookup scans at most 66 lines of one section. It uses the same memory as before (~80 KB of read-only data) and does no work at start-up. `tools/booknames/gen.py` writes the file, and regenerating it from the pinned JSword commit gives a byte-identical file. `.gitattributes` keeps it at LF line endings. **Type alias.** It isn't needed any more: `data.rs` is gone, and with it the `BOOKS` and `NAMES` consts and their array type. `Names` now holds just its locale and that locale's section of the file. A new test, `has_every_book_in_every_language`, checks that all 61 languages have the 66 books in the same order, with no empty names. It fails if a book is missing.
The "Kapitel"/"Psalm" table moves from names.rs to a hand-written
names/headings.ini, in the books.ini shape. Both files are read by one
small Section type (names/section.rs); the English fallback is a named
constant. Tests check every heading language has both words and a book
table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Book names: a typed Locale instead of locale strings
All checks were successful
CI / rust (pull_request) Successful in 1m52s
CI / audit (pull_request) Successful in 9s
CI / app (pull_request) Successful in 1m13s
CI / click (pull_request) Successful in 42s
0025b06788
A conf's Lang (BCP 47) and the phone's locales (POSIX) parse once into a
Locale: lower-case language, upper-case region, codeset, modifier and
script dropped, None for C and POSIX. Names matches .ini sections by
parsed Locale, not by slicing and comparing strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review-Confidence: 80
Review-Tier: trunk
Author
Collaborator

Locale strings, in two commits:

  • d9b1e5f moves the chapter words ("Kapitel", "Salmo", …) out of Rust into core/src/bible/names/headings.ini, read the same way as books.ini through a small Section type.
  • 0025b06 replaces locale strings with a type. core/src/bible/locale.rs parses a conf's Lang ("pt-BR", "de-Latn-DE") or a phone locale ("de_DE.UTF-8@euro") once into Locale { language, region }, and gives none for C/POSIX. Names::pick(Option<&Locale>, &[Locale]) and ui_languages() -> Vec<Locale> take values. .ini sections are found by comparing parsed Locales, so names.rs no longer splits, trims or replaces "-" with "_". The only locale literal left in production code is FALLBACK = "en". The tests still feed raw tags, since parsing them is what they test.

Gate passes (40 core tests, coverage 94.78%); a fresh high review found no bugs; audit 80. PR body updated.

Locale strings, in two commits: - **d9b1e5f** moves the chapter words ("Kapitel", "Salmo", …) out of Rust into `core/src/bible/names/headings.ini`, read the same way as `books.ini` through a small `Section` type. - **0025b06** replaces locale strings with a type. `core/src/bible/locale.rs` parses a conf's `Lang` ("pt-BR", "de-Latn-DE") or a phone locale ("de_DE.UTF-8@euro") once into `Locale { language, region }`, and gives none for C/POSIX. `Names::pick(Option<&Locale>, &[Locale])` and `ui_languages() -> Vec<Locale>` take values. `.ini` sections are found by comparing parsed `Locale`s, so `names.rs` no longer splits, trims or replaces "-" with "_". The only locale literal left in production code is `FALLBACK = "en"`. The tests still feed raw tags, since parsing them is what they test. Gate passes (40 core tests, coverage 94.78%); a fresh high review found no bugs; audit 80. PR body updated.
schaefera merged commit 9677417bd7 into phase1/core-layout 2026-10-21 10:53:37 +00:00
schaefera deleted branch phase1/chapter-headings 2026-10-21 10:53:37 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
schaefera/utStudyBIble!18
No description provided.