Add an English translation of the corralito training-courses page

It was deliberately left Italian-only when /en support was first added;
now translated and following the same thin-page + shared-view pattern
as every other route, with the nav link and language switch no longer
special-casing it.
This commit is contained in:
2026-09-11 15:39:31 +02:00
parent 1247a2ca07
commit ac536bd152
8 changed files with 173 additions and 148 deletions
+5 -4
View File
@@ -8,7 +8,7 @@
| `/blog` | `/en/blog` | `app/pages/blog/index.vue` + `app/pages/en/blog/index.vue``BlogIndexView.vue` | Paginated archive (`PAGE_SIZE = 12`), grid of `ArticleCard`, prev/next via `?page=`. |
| `/blog/[slug]` | `/en/blog/[slug]` | `app/pages/blog/[slug].vue` + `app/pages/en/blog/[slug].vue``ArticleView.vue` | Full article: fetches `/content/articles/:slug`, renders the pre-converted `article.html`, SEO meta, canonical URL, Open Graph, JSON-LD `BlogPosting`, breadcrumb to its category. |
| `/category/[slug]` | `/en/category/[slug]` | `app/pages/category/[slug].vue` + `app/pages/en/category/[slug].vue``CategoryView.vue` | Fetches the category by slug, then a paginated, category-filtered article list; 404s if the category doesn't exist. |
| `/come-difendersi-dal-corralito` | *(none)* | `app/pages/come-difendersi-dal-corralito.vue` | Fully static marketing page, no PocketBase data, Italian only — see [English content](#english-content-1). |
| `/come-difendersi-dal-corralito` | `/en/come-difendersi-dal-corralito` | `app/pages/come-difendersi-dal-corralito.vue` + `app/pages/en/come-difendersi-dal-corralito.vue``CorralitoView.vue` | Fully static marketing page, no PocketBase data — copy lives in `STRINGS[locale].corralito` (`shared/utils/i18n.ts`), same pattern as every other view. |
All pages are SSR (`useFetch`/`useSeoMeta`); nothing blog-related is client-only-rendered.
@@ -47,8 +47,9 @@ Nitro locale-awareness, and most of the SEO work are custom code either way).
by the time a page component's own `<script setup>` would set that state, the header has already
resolved and rendered with whatever the default was — middleware runs, and fully resolves,
before the layout/page tree starts rendering at all, which is the only way to avoid that race.
When unavailable, the switch falls back to the other language's blog index (articles/categories)
or home page (the static corralito page, which has no English version at all).
When unavailable, the switch falls back to the other language's blog index/category list; every
other route (including the static corralito page) exists in both languages unconditionally, so
the mechanical `/en` prefix swap is always valid there.
- **SEO**: `app/composables/useSeo.ts` centralises canonical URL, Open Graph, JSON-LD, and
`hreflang` alternate links (`it`, `en`, `x-default`) for a given `{ locale, path, ... }``path`
is always the bare, unprefixed path, so IT/EN pages for the same content always agree on each
@@ -166,7 +167,7 @@ layout shift results.
render its own `<a>``RouterLink`'s built-in active-class/`aria-current` detection compares
only the route's `path`, not its query string, so with plain `NuxtLink`s every `?page=N` link
would end up (wrongly) marked as the current page.
- `app/components/views/*.vue` (`HomeView`, `BlogIndexView`, `ArticleView`, `CategoryView`) — the
- `app/components/views/*.vue` (`HomeView`, `BlogIndexView`, `ArticleView`, `CategoryView`, `CorralitoView`) — the
actual page markup/logic, parametrized by a `locale` prop; the real `pages/**` and `pages/en/**`
files are thin wrappers around these (see [English content](#english-content)). Registered
without Nuxt's default nested-directory name prefix