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
prefixDefaultLocalesetting - Use fallback for missing translations