# {{projectName}} / {{appName}}

Bilingual (en/de) static SSG blog (template: **frontend-static-blog**).
Every page is pre-rendered at build time — no server, no per-request
rendering — once PER LOCALE: English at the bare path, German under `/de`.

## Boot

```bash
pnpm install
pnpm --filter @{{projectName}}/{{appName}} dev     # dev server with HMR
```

## What this template demonstrates

| Concept | Where |
|---|---|
| `renderMode = 'static'` (pre-render at build) | every page |
| `interactive = 'none'` (strip ALL JS) | `src/pages/index.tsx` |
| `interactive = 'islands'` (hydrate one widget) | `src/pages/blog/[slug].tsx` |
| `island()` + `hydrate: 'load'` strategy | `src/components/ReadingProgress.island.tsx` |
| `getStaticPaths` (enumerate dynamic routes) | `src/pages/blog/[slug].tsx` |
| `loader` + `useLoaderData<T>()` | `src/pages/blog/[slug].tsx` |
| `meta` as a function of loader data (per-post SEO) | `src/pages/blog/[slug].tsx` |
| A swappable content source (the "CMS") | `src/content/posts.ts` |
| Bilingual URL-prefix i18n (en + `/de`) | `src/lib/locale.ts`, `src/locales/{en,de}.ts` |
| `[locale]` mirror pages (per-locale SSG) | `src/pages/[locale]/**` |
| Cross-product `getStaticPaths` (locale × slug) | `src/pages/[locale]/blog/[slug].tsx` |

## Build + serve

```bash
pnpm --filter @{{projectName}}/{{appName}} build    # → dist/ (one HTML file per post)
pnpm --filter @{{projectName}}/{{appName}} start    # serve dist/ locally
```

Because the output is pure static files, you can also push `dist/` to a
cheap CDN instead of running a server:

```bash
voltro static deploy --host cloudflare-pages --project-name {{appName}}
```

## Adding posts

Append to the array in `src/content/posts.ts`. `getStaticPaths` reads
the same array, so a new entry is pre-rendered on the next build — no
route config. In a real app, replace that array with a CMS / database /
filesystem read; nothing else changes.
