RustyCMS: File-based headless CMS with REST API, admin UI, multilingual support

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Peter Meier
2026-02-16 09:30:30 +01:00
commit aad93d145f
224 changed files with 19225 additions and 0 deletions

59
docs/multilingual.md Normal file
View File

@@ -0,0 +1,59 @@
# Multilingual (i18n)
## Recommended approach: Locale as folder (implemented)
Content per language in separate folders:
```
content/
de/
page/
home.json5
about.json5
post/
example-post.json5
en/
page/
home.json5
about.json5
post/
example-post.json5
```
- **Same slug per language** (e.g. `home` in DE and EN).
- **API:** `?_locale=de` or `?_locale=en`. If parameter is missing, default locale is used.
- **Configuration:** `RUSTYCMS_LOCALES=de,en` enables the mode; **first locale = default** (e.g. `de`).
- **Without `RUSTYCMS_LOCALES`:** Previous behavior (single language). Content remains under `content/{collection}/` (no locale folder).
## Activation
```bash
# .env or export
RUSTYCMS_LOCALES=de,en
```
On startup you'll see e.g.: `Multilingual: locales ["de", "en"] (default: de)`.
## API usage
```bash
# Default locale (first in RUSTYCMS_LOCALES, e.g. de)
GET /api/content/page/home
# Explicit locale
GET /api/content/page/home?_locale=en
GET /api/content/page?_page=1&_per_page=50&_locale=en
```
Response still has the same structure; only the content is locale-dependent. For POST/PUT/DELETE, `_locale` can be passed as a query parameter so the entry is created/updated/deleted in the correct locale.
## Optional extensions
- **page_config per locale:** e.g. `content/de/page_config/default.json5` and `content/en/page_config/default.json5` for locale-specific SEO, footer text, etc.
- **Available locales in API:** e.g. `GET /api/locales``["de","en"]` (from config).
- **hreflang / languageAlternates:** derive in frontend from page config or known locales (e.g. already considered in `@types/SeoProps.ts`).
## Alternatives (not implemented)
- **Locale as field in entry:** Entry with `locale: "de"`, slug unique per language (e.g. `home-de`, `home-en`). Works without store changes, but same logical content has different slugs.
- **Translations in one entry:** File with `translations: { de: {...}, en: {...} }`. No extra folders, but schema and API (filter, resolve) become more complex.