File-based routing. All routes language-prefixed: /[lang]/{path}.
pages/
├── index.astro # Root redirect page
└── [lang]/ # Language-prefixed pages
├── index.astro
├── enrol.astro
├── results.astro
├── before/ # Pre-race information
├── during/ # Race day information
├── after/ # Post-race information
└── info/ # General information
All pages must:
getStaticPaths() to generate pages for each languagelang from Astro.paramsuseTranslations(lang) for textLayout component or custom HTML structure---
import { useTranslations, languages } from '../../../i18n/utils';
import type { Language } from '../../../i18n/utils';
import Layout from '../../../layouts/Layout.astro';
export function getStaticPaths() {
return Object.keys(languages).map((lang) => ({
params: { lang },
}));
}
const { lang } = Astro.params as { lang: Language };
const t = useTranslations(lang);
const pageTitle = `${t('nav.section.page.title')} | SantYaGo10K 2026`;
---
<Layout title={pageTitle} description={t('nav.section.page.subtitle')} lang={lang}>
<!-- Hero Section -->
<section class="relative min-h-[50vh] flex items-center justify-center header-offset">
<div class="absolute inset-0 bg-gradient-to-br from-{color}-500 to-{color}-600"></div>
<div class="relative z-10 text-center px-4">
<h1 class="text-5xl md:text-6xl font-bold text-white mb-4">
{t('nav.section.page.title')}
</h1>
<p class="text-xl text-white/90">
{t('nav.section.page.subtitle')}
</p>
</div>
</section>
<!-- Content sections -->
</Layout>
Use when: No hero image is available, or for simple informational pages.
<section class="relative min-h-[50vh] flex items-center justify-center header-offset">
<div class="absolute inset-0 bg-gradient-to-br from-blue-500 to-blue-600"></div>
<div class="relative z-10 text-center px-4">
<h1 class="text-5xl md:text-6xl font-bold text-white mb-4">
{t('section.title')}
</h1>
<p class="text-xl text-white/90">
{t('section.subtitle')}
</p>
</div>
</section>
Use when: You have a featured image to showcase (recommended pattern for main pages).
Example: Track page, Volunteer page.
---
import { Image } from 'astro:assets';
import heroImage from '../../../assets/section/hero.jpg';
---
<!-- Hero Section with Image -->
<section class="relative header-offset py-12 md:py-16">
<div class="absolute inset-0 bg-gradient-to-br from-orange-400 to-orange-500"></div>
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
<div class="grid lg:grid-cols-2 gap-8 items-center">
<!-- Left: Title and Description -->
<div>
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-4">
{t('section.title')}
</h1>
<p class="text-lg md:text-xl text-white/90">
{t('section.subtitle')}
</p>
</div>
<!-- Right: Header Image -->
<div class="relative h-48 md:h-56 lg:h-64 rounded-2xl overflow-hidden shadow-2xl">
<Image
src={heroImage}
alt="Descriptive alt text"
class="w-full h-full object-cover"
widths={[400, 800]}
sizes="(max-width: 768px) 100vw, 50vw"
/>
</div>
</div>
</div>
</section>
Key implementation details:
Image asset organization:
src/assets/{section}/hero.jpgsrc/assets/track/hero.jpg, src/assets/volunteer/hero.jpgImage optimization:
Image component for automatic optimizationwidths={[400, 800]}sizes attribute for better loading performanceResponsive heights:
h-48 (192px)md:h-56 (224px)lg:h-64 (256px)Grid behavior:
lg:grid-cols-2Hero section gradients:
src/components/Navbar.astrogradient propertysrc/components/CLAUDE.md for the complete list of gradientsReal examples:
src/pages/[lang]/during/track.astro (lines 28-55)src/pages/[lang]/info/volunteer.astro (lines 35-69)<section class="py-16 bg-white dark:bg-night-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-3xl font-bold text-gray-800 dark:text-white mb-8">
{t('section.heading')}
</h2>
<!-- Content -->
</div>
</section>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{items.map(item => (
<div class="bg-neutral-50 dark:bg-night-800 rounded-xl p-6 border-2 border-neutral-200 dark:border-night-600">
<h3 class="text-xl font-bold text-gray-800 dark:text-white mb-4">
{item.title}
</h3>
<p class="text-gray-600 dark:text-gray-300">
{item.description}
</p>
</div>
))}
</div>
When creating a new page:
pages/[lang]/{section}/ directorygetStaticPaths() function for language generationlang from Astro.paramsuseTranslations(lang)Layout component (or create custom HTML if needed)config/routes.ts if it’s a main routeNavbar.astro with correct gradientNavbar.astro to the hero section (check the gradient property)header-offset class to first section to account for fixed navbarsrc/pages/[lang]/index.astro - Home page with full trackingsrc/pages/[lang]/results.astro - Example of feature flag implementationsrc/pages/[lang]/after/photos.astro - Example of feature flag implementationsrc/config/CLAUDE.mdsrc/i18n/CLAUDE.mdsrc/layouts/CLAUDE.mdsrc/components/CLAUDE.mdsrc/styles/CLAUDE.md