diff options
Diffstat (limited to 'AGENTS.md')
| -rw-r--r-- | AGENTS.md | 33 |
1 files changed, 31 insertions, 2 deletions
@@ -52,6 +52,8 @@ internal/store/ Store = control DB (users, blog registry, create/delete bl BlogStore = one blog's DB (settings, pages, posts, images, sections, modules, menu) internal/auth/ bcrypt, JWT issue/parse, cookie, HMAC CSRF internal/markdown/ Render(md) → sanitized HTML +internal/i18n/ languages, T/Tf (English keys → catalog), FormatDate/Month, Accept-Language Match; + el.go is the Greek catalog, el_months.go the month tables internal/slug/ Make/Valid/WithSuffix (Greek transliteration included) internal/web/ server.go (host router, middleware, render helpers) routes.go (all routes), handlers_*.go (sections = announcements, layout = modules + menu) @@ -65,7 +67,7 @@ internal/web/ server.go (host router, middleware, render helpers) - **One database per blog**: the registry row (`blogs`: id, owner, subdomain, `db_name`) lives in the control DB; everything else — a one-row `settings` - table (title, tagline, theme) plus pages, posts, images, sections, modules, + table (title, tagline, language, theme) plus pages, posts, images, sections, modules, menu_items — lives in `blog_<sub>` (`db.DBName`: dashes → underscores, so subdomains are capped at 58 chars). No table in a blog DB carries a blog id; the database is the scope. `store.Store` (control) hands out a @@ -189,6 +191,33 @@ internal/web/ server.go (host router, middleware, render helpers) `notice notice-<style>` use translucent colours so they fit any theme. - **Dashboard nav**: `dashnav.html` marks the current tab with `hasPrefix .Path`; a new management section needs a tab there. +- **Languages** (`internal/i18n`, `settings.language`): every blog has a + language (`en` by default, `el` = Greek) chosen on the Settings tab. Public + pages use the blog's language; management pages use the **logged-in user's + own blog's** language (a user has one blog, so a superadmin editing someone + else's blog keeps theirs); anonymous pages (`/webadmin`) match + `Accept-Language`. `server.go`: `hostBlog`/`withBlog` put it in `ctxLang`, + `s.lang(r)` resolves it (lazily looking the user's blog up otherwise), the + `view` carries it as `.Lang` (also the `<html lang>`). + Keys are the English strings: templates write `{{t "Save"}}` / + `{{tf "Page %d of %d" .N .Last}}`, handlers `s.tr(r, "Post deleted.")` / + `s.trf(r, "Uploaded %s.", name)`; an unknown key renders as English. + Templates are compiled once **per language** (`templates.get(lang, name)`) + with `funcsFor(lang)`, whose `t`, `tf`, `date` (dashboard, long style), + `postdate` (`style, time` for the theme's `DateFormat`), `month` + (archive headings) and `modsummary` are closed over the language — so + templates need no data plumbing. A sentence with a link in the middle is + split into fragments around the `<a>`. `moduleNames`/`areaNames`/preset + names stay English maps and are translated where used (`{{t (index …)}}`, + `s.tr(r, moduleNames[k])`). Content the blogger typed is never translated; + default module headings are created in the blog's language. + `TestGreekCatalogComplete` scans the templates and handlers for keys and + fails when the Greek catalog misses one or keeps a stale one — reword an + English string and the catalog entry must follow. Keys reached through a + variable (`{{t .Role}}`) are listed in that test by hand. + Adding a language: an entry in `i18n.languages`, a catalog file, a month + table in `monthTables` (nominative, in-date and short forms), and the test + gets a copy per language if its rules differ. - **Slugs**: auto-generated from the title; on collision generated slugs get `-2`, `-3`…, user-typed slugs return a 409 with a message. - **Errors**: `store.ErrNotFound` / `store.ErrConflict` are the sentinels @@ -217,7 +246,7 @@ superadmin password to `admin`. Production refuses both. (runs in every blog database — it must not reference `users`/`blogs`) and `internal/db/migrations/control/` for users and the registry; goose `-- +goose Up/Down` sections; they run automatically at startup. Never - edit an applied migration. Both chains were re-baselined at 00001 after + edit an applied migration. Blog chain so far: `00001_init`, `00002_language`. Both chains were re-baselined at 00001 after the move to per-blog databases; deployments from before it have `goose_db_version` rows 2–7 in the control DB that must be deleted once (README "Upgrading from a single database") or the next control migration |
