Fix: Index Page Not Found for i18n in Astro

Error message:
Index page not found.
Internationalization 2025-01-25

What Causes This Error?

This error occurs when Astro’s i18n routing tries to redirect to a locale-specific index page that doesn’t exist. This typically happens when you enable i18n but haven’t created the required index pages.

The Problem

// astro.config.mjs
export default defineConfig({
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'es'],
    routing: {
      prefixDefaultLocale: true,
    },
  },
});
src/pages/
└── index.astro    # ❌ No /en/index.astro for redirect

The Fix

Create Locale Index Pages

src/pages/
├── en/
│   └── index.astro    # ✅ English index
├── es/
│   └── index.astro    # ✅ Spanish index
└── index.astro        # Root redirect (optional)

Common Scenarios

With prefixDefaultLocale: true

// astro.config.mjs
export default defineConfig({
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'es'],
    routing: {
      prefixDefaultLocale: true,  // All URLs need locale prefix
    },
  },
});
# Required structure
src/pages/
├── en/
│   ├── index.astro      # /en/
│   └── about.astro      # /en/about
└── es/
    ├── index.astro      # /es/
    └── about.astro      # /es/about

With prefixDefaultLocale: false (Default)

// astro.config.mjs
export default defineConfig({
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'es'],
    routing: {
      prefixDefaultLocale: false,  // Default locale has no prefix
    },
  },
});
# Required structure
src/pages/
├── index.astro          # / (English)
├── about.astro          # /about (English)
└── es/
    ├── index.astro      # /es/
    └── about.astro      # /es/about

Root Redirect Page

---
// src/pages/index.astro (when prefixDefaultLocale: true)
// Redirect to default locale
return Astro.redirect('/en/');
---

Dynamic Index Pages

---
// src/pages/[locale]/index.astro
export function getStaticPaths() {
  return [
    { params: { locale: 'en' } },
    { params: { locale: 'es' } },
    { params: { locale: 'fr' } },
  ];
}

const { locale } = Astro.params;
const translations = await getTranslations(locale);
---

<h1>{translations.welcome}</h1>

Language Switcher

---
import { getRelativeLocaleUrl } from 'astro:i18n';

const locales = ['en', 'es', 'fr'];
const currentPath = Astro.url.pathname.replace(/^\/[a-z]{2}/, '');
---

<nav>
  {locales.map((locale) => (
    <a href={getRelativeLocaleUrl(locale, currentPath || '/')}>
      {locale.toUpperCase()}
    </a>
  ))}
</nav>

Check Route Coverage

# Verify all locale routes exist
ls -R src/pages/

# Expected output with i18n:
# src/pages/en/index.astro
# src/pages/es/index.astro
# etc.

Fallback Strategy

// astro.config.mjs
export default defineConfig({
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'es', 'fr'],
    fallback: {
      es: 'en',
      fr: 'en',
    },
    routing: {
      prefixDefaultLocale: false,
      fallbackType: 'rewrite',  // Use English content for missing pages
    },
  },
});

Shared Layout with Locale

---
// src/layouts/Layout.astro
const locale = Astro.currentLocale || 'en';
---

<html lang={locale}>
  <head>
    <link rel="alternate" hreflang="en" href="/en/" />
    <link rel="alternate" hreflang="es" href="/es/" />
  </head>
  <body>
    <slot />
  </body>
</html>

Quick Checklist

  • Create index.astro for each locale folder
  • Match folder structure to configured locales
  • Root index handles redirect if needed
  • Check prefixDefaultLocale setting
  • Use fallback for missing translations