6.4 KiB
Internationalization (i18n) Setup
This project includes a comprehensive internationalization system built with Astro 5.x. The system supports multiple languages with URL-based routing and automatic language detection.
Features
- ✅ URL-based language routing (Spanish:
/, English:/en/) - ✅ Spanish as default language (no URL prefix)
- ✅ Automatic language detection from URL
- ✅ Language switcher component
- ✅ Type-safe translation keys
- ✅ Fallback to default language
- ✅ Middleware for automatic redirects
- ✅ SEO-friendly URLs
Supported Languages
Currently supported languages:
- Spanish (es) - Default language (no URL prefix)
- English (en) - Secondary language (with
/en/prefix)
URL Structure
- Spanish (default):
/,/elements,/about - English:
/en/,/en/elements,/en/about
How to Use
1. Adding New Translations
Edit the translation dictionaries in src/lib/i18n.ts:
const translations = {
es: {
'your.new.key': 'Texto en español',
// ... more translations
},
en: {
'your.new.key': 'English text',
// ... more translations
}
}
2. Using Translations in Components
---
import { t, getLanguageFromPath } from '../lib/i18n';
const currentLang = getLanguageFromPath(Astro.url.pathname);
---
<h1>{t('your.new.key', currentLang)}</h1>
3. Creating Language-Specific Pages
For English pages, create them in the src/pages/[lang]/ directory:
---
// src/pages/[lang]/about.astro (English only)
import { t, isSupportedLanguage, type SupportedLanguage, DEFAULT_LANGUAGE } from '../../lib/i18n';
const { lang } = Astro.params;
if (!lang || !isSupportedLanguage(lang)) {
return Astro.redirect('/about');
}
const currentLang = lang as SupportedLanguage;
// Redirect Spanish to root
if (currentLang === DEFAULT_LANGUAGE) {
return Astro.redirect('/about');
}
---
<h1>{t('about.title', currentLang)}</h1>
For Spanish pages (default), create them directly in src/pages/:
---
// src/pages/about.astro (Spanish default)
import { t, DEFAULT_LANGUAGE } from '../lib/i18n';
const currentLang = DEFAULT_LANGUAGE;
---
<h1>{t('about.title', currentLang)}</h1>
4. Adding the Language Switcher
The language switcher is automatically included in the main layout. To add it to other components:
---
import LanguageSwitcher from '../components/LanguageSwitcher.astro';
---
<LanguageSwitcher />
5. Creating Localized Links
Use the getLocalizedPath function for navigation:
---
import { getLocalizedPath, getLanguageFromPath } from '../lib/i18n';
const currentLang = getLanguageFromPath(Astro.url.pathname);
---
<a href={getLocalizedPath('/about', currentLang)}>About</a>
File Structure
src/
├── lib/
│ └── i18n.ts # Main i18n utilities and translations
├── components/
│ ├── LanguageSwitcher.astro # Language selection component
│ └── ... # Other components
├── pages/
│ ├── [lang]/ # English-specific pages
│ │ ├── index.astro # Redirects Spanish to root
│ │ ├── elements.astro # Redirects Spanish to root
│ │ └── ...
│ ├── index.astro # Spanish default homepage
│ ├── elements.astro # Spanish default elements page
│ └── ... # Other Spanish default pages
└── middleware.ts # Language routing middleware
API Reference
Translation Functions
t(key, lang?)
Get a translation for a given key and language.
t('nav.home', 'es') // Returns: "Inicio"
t('nav.home', 'en') // Returns: "Home"
getLanguageFromPath(pathname)
Extract language from URL path.
getLanguageFromPath('/en/elements') // Returns: "en"
getLanguageFromPath('/elements') // Returns: "es" (default)
getLanguageFromPath('/') // Returns: "es" (default)
getLocalizedPath(path, lang)
Generate a localized URL path.
getLocalizedPath('/elements', 'es') // Returns: "/elements"
getLocalizedPath('/elements', 'en') // Returns: "/en/elements"
isSupportedLanguage(lang)
Check if a language is supported.
isSupportedLanguage('es') // Returns: true
isSupportedLanguage('fr') // Returns: false
Constants
SUPPORTED_LANGUAGES- Array of supported language codes (['es', 'en'])DEFAULT_LANGUAGE- Default language code ('es')TranslationKey- TypeScript type for translation keys
Adding New Languages
- Add the language code to
SUPPORTED_LANGUAGESinsrc/lib/i18n.ts - Add translations for the new language in the
translationsobject - Update the language switcher component if needed
- Create language-specific pages in
src/pages/[lang]/
Example for French:
export const SUPPORTED_LANGUAGES = ['es', 'en', 'fr'] as const;
const translations = {
es: { /* Spanish translations */ },
en: { /* English translations */ },
fr: { /* French translations */ }
}
Best Practices
- Use descriptive keys: Use namespaced keys like
nav.home,elements.title - Keep translations organized: Group related translations together
- Test all languages: Ensure all translations are complete
- Use TypeScript: Leverage the
TranslationKeytype for type safety - Handle missing translations: The system falls back to the default language
- Spanish first: Always put Spanish translations first in the dictionary
SEO Considerations
- Spanish content is served at root URLs (better for SEO)
- English content has
/en/prefix - Language is properly set in the HTML
langattribute - Search engines can index content in multiple languages
- Use proper hreflang tags if needed for advanced SEO
Troubleshooting
Common Issues
- Translation not found: Check if the key exists in all language dictionaries
- Language not detected: Ensure the URL follows the correct pattern
- Redirect loops: Check middleware configuration
- Type errors: Use the
TranslationKeytype for translation keys
Debug Mode
Enable debug logging by adding console logs in the i18n functions:
export function t(key: TranslationKey, lang: SupportedLanguage = DEFAULT_LANGUAGE): string {
console.log(`Translating: ${key} for language: ${lang}`);
// ... rest of function
}