localise chrome, smooth prose, in English and Bengali
The engine now owns the words it puts on a page that the author did not write (ADR-0034). `internal/render/chrome.go` holds the phrase table, Gregorian month names and decimal digits per language, keyed phrase-then-language so both forms sit side by side and a half-translated row is visible while reading. Templates reach it through `t`, `num` and `day`, registered before parsing so a site override's blocks may call them too. The reference theme stops hardcoding English: "Newer", "Page 2 of 2" and every date now come from the table, while `datetime` attributes stay ASCII because a parser reads them. Authored text gets goldmark's typographer and nothing else — quotes, dashes and ellipses smoothed, code spans untouched because it works on the parsed tree. It is a parser option rather than a function over a page, so the transforms counter does not move; state.md now says why, so the next reader does not miscount. Deliberately absent: relative dates, which need a validity window that only the cache entry will have, and body widow prevention, which cannot be done safely by a pass over rendered HTML.
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/yuin/goldmark"
|
||||
"github.com/yuin/goldmark/extension"
|
||||
|
||||
"khosra/internal/content"
|
||||
)
|
||||
@@ -129,7 +130,12 @@ func New(siteFS fs.FS) (*Renderer, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Renderer{page: page, list: list, md: goldmark.New(), style: css}, nil
|
||||
// The typographer smooths quotes, dashes and ellipses in authored prose and leaves code spans alone,
|
||||
// because it works on the parsed tree rather than the text. That is the only change the engine makes to
|
||||
// an author's words (ADR-0034), and it is a parser option rather than a render transform, so it does
|
||||
// not move the transforms counter.
|
||||
md := goldmark.New(goldmark.WithExtensions(extension.Typographer))
|
||||
return &Renderer{page: page, list: list, md: md, style: css}, nil
|
||||
}
|
||||
|
||||
// parseSet builds one kind of page: the embedded base and block, then the site's versions of exactly
|
||||
@@ -140,7 +146,9 @@ func New(siteFS fs.FS) (*Renderer, error) {
|
||||
// site template into every set would let a listing's "main" leak into bundle pages, which is the
|
||||
// collision per-kind sets exist to prevent.
|
||||
func parseSet(siteFS fs.FS, kind string) (*template.Template, error) {
|
||||
set, err := template.ParseFS(themeFS, "templates/base.html", kind)
|
||||
// Funcs are attached before anything is parsed, so the chrome helpers are available to a site
|
||||
// override's blocks as well as the embedded ones (ADR-0034).
|
||||
set, err := template.New("theme").Funcs(funcs).ParseFS(themeFS, "templates/base.html", kind)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse embedded: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user