Add hand-rolled English support (/en/*) alongside the Italian site
PocketBase gains optional, manually-authored English fields on articles and categories (same record, same slug), and the frontend serves an /en counterpart of every dynamic route via thin page wrappers around shared view components — no i18n library, consistent with the project's existing minimalism stance for a two-locale site with ~20 UI strings. An article/category with no translation 404s cleanly on its own /en detail page and is filtered out of /en listings, and the header's language-switch link falls back to the English blog index rather than a dead link; resolving that requires a global route middleware, since the layout's header renders before the page content in document order and so can't react to state a page component sets during its own async setup.
This commit is contained in:
+27
-2
@@ -8,8 +8,8 @@ migration files). No custom Go/JS hooks exist for either collection — schema a
|
||||
|
||||
| Collection | Fields |
|
||||
|---|---|
|
||||
| **articles** | `title` (text, required, max 160), `slug` (text, required, unique, kebab-case pattern), `content` (text — Markdown source, not the WYSIWYG `editor` field type), `cover` (single file, images only), `coverAlt` (text, alt text), `category` (relation to `categories`), `publishedAt` (date, nullable), `authorName` (text) |
|
||||
| **categories** | `name` (text, required, unique), `slug` (text, required, unique, kebab-case pattern) |
|
||||
| **articles** | `title` (text, required, max 160), `slug` (text, required, unique, kebab-case pattern), `content` (text, max 10000 — Markdown source, not the WYSIWYG `editor` field type), `cover` (single file, images only), `coverAlt` (text, alt text), `category` (relation to `categories`), `publishedAt` (date, nullable), `authorName` (text), `titleEn`/`contentEn`/`coverAltEn` (text, optional — see [English content](#english-content) below) |
|
||||
| **categories** | `name` (text, required, unique), `slug` (text, required, unique, kebab-case pattern), `nameEn` (text, optional — see [English content](#english-content) below) |
|
||||
|
||||
Deliberately minimal: no tags, no separate SEO fields. Don't add these back without a concrete
|
||||
need — see `CLAUDE.md`:
|
||||
@@ -64,6 +64,31 @@ dimensions (see [frontend.md](./frontend.md)).
|
||||
5. The change is live immediately: the public site has no cache layer to invalidate (see
|
||||
[architecture.md](./architecture.md#request-flow-reading-an-article)).
|
||||
|
||||
## English content
|
||||
|
||||
The site is now bilingual (Italian, the source language, and English), but PocketBase has no
|
||||
localization feature and no separate translation workflow was introduced for it: `titleEn`,
|
||||
`contentEn`, `coverAltEn` on `articles` and `nameEn` on `categories` are plain, optional text
|
||||
fields living on the **same record** as their Italian counterparts — same slug, same cover, same
|
||||
`category` relation, same `publishedAt`. Added by migration
|
||||
`pocketbase/pb_migrations/1757500002_add_english_fields.js`, which alters the two existing
|
||||
collections (`app.findCollectionByNameOrId` + `collection.fields.add(...)` /
|
||||
`.removeByName(...)` on the down-migration) rather than recreating them — the first example of
|
||||
that pattern in this repo, since until now every migration only ever created a collection.
|
||||
|
||||
Translations are **written manually** by the editor in the admin UI, at their own pace — there is
|
||||
no auto-translation step. Consequently:
|
||||
|
||||
- An article/category with empty `titleEn`/`contentEn`/`nameEn` simply has no English version yet.
|
||||
This is normal, not an error state.
|
||||
- `listRule`/`viewRule` are unchanged: whether a record is *published* is still governed solely by
|
||||
`publishedAt`, independent of translation completeness. Whether it's *offered in English* is
|
||||
decided by the Nitro layer (`frontend/server/routes/content/*`), not by a PocketBase rule — see
|
||||
[frontend.md](./frontend.md#english-content).
|
||||
- There's no `publishedAtEn` or similar: translation is all-or-nothing at the field level, not a
|
||||
separate publish gate. If partial/staged English publishing is ever needed, that's the natural
|
||||
next field to add — don't build it speculatively now.
|
||||
|
||||
## Why Markdown, not a rich-text/WYSIWYG field
|
||||
|
||||
`content` is a plain PocketBase `text` field, not the `editor` field type (which stores HTML).
|
||||
|
||||
Reference in New Issue
Block a user