Astro's internationalization (i18n) feature allows developers to easily build multilingual websites. Understanding how to configure and use Astro's i18n functionality is crucial for projects targeting global users.
Basic Configuration:
javascript// astro.config.mjs import { defineConfig } from 'astro/config'; import { i18n } from 'astro-i18next'; export default defineConfig({ integrations: [ i18n({ defaultLocale: 'en', locales: ['en', 'zh', 'ja', 'es'], fallbackLocale: 'en', routing: { prefixDefaultLocale: false, }, }), ], });
Using astro-i18next Integration:
bashnpm install astro-i18next i18next
javascript// astro.config.mjs import { defineConfig } from 'astro/config'; import i18next from 'astro-i18next'; export default defineConfig({ integrations: [ i18next({ defaultLocale: 'en', locales: ['en', 'zh'], routingStrategy: 'prefix', }), ], });
Translation File Structure:
shellsrc/ ├── i18n/ │ ├── en/ │ │ ├── common.json │ │ └── home.json │ ├── zh/ │ │ ├── common.json │ │ └── home.json │ └── ja/ │ ├── common.json │ └── home.json
Translation File Examples:
json// src/i18n/en/common.json { "nav": { "home": "Home", "about": "About", "contact": "Contact" }, "buttons": { "submit": "Submit", "cancel": "Cancel" } }
json// src/i18n/zh/common.json { "nav": { "home": "首页", "about": "关于", "contact": "联系" }, "buttons": { "submit": "提交", "cancel": "取消" } }
Using Translations in Components:
astro--- import { useTranslation } from 'astro-i18next'; const { t } = useTranslation(); --- <nav> <a href="/">{t('nav.home')}</a> <a href="/about">{t('nav.about')}</a> <a href="/contact">{t('nav.contact')}</a> </nav> <button>{t('buttons.submit')}</button>
Language Switcher:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); const locales = ['en', 'zh', 'ja', 'es']; --- <div class="language-switcher"> {locales.map(loc => ( <a href={`/${loc === 'en' ? '' : loc}`} class={locale === loc ? 'active' : ''} > {loc.toUpperCase()} </a> ))} </div> <style> .language-switcher { display: flex; gap: 0.5rem; } .active { font-weight: bold; text-decoration: underline; } </style>
Dynamic Route Internationalization:
astro--- // src/pages/[lang]/blog/[slug].astro import { useTranslation, useLocale } from 'astro-i18next'; import { getCollection } from 'astro:content'; const { t } = useTranslation(); const locale = useLocale(); const { slug } = Astro.params; const post = await getEntry('blog', slug); const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />
Content Collection Internationalization:
markdown--- # src/content/en/blog/my-post.md title: "My English Post" publishDate: 2024-01-15 --- This is the English version of the post.
markdown--- # src/content/zh/blog/my-post.md title: "我的中文文章" publishDate: 2024-01-15 --- 这是文章的中文版本。
astro--- // src/pages/blog/[slug].astro import { getCollection } from 'astro:content'; import { useLocale } from 'astro-i18next'; const locale = useLocale(); const { slug } = Astro.params; const post = await getEntry(`blog-${locale}`, slug); const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />
Date and Number Formatting:
astro--- import { useTranslation } from 'astro-i18next'; const { t, i18n } = useTranslation(); const date = new Date(); const number = 1234567.89; --- <p>Date: {date.toLocaleDateString(i18n.language)}</p> <p>Number: {number.toLocaleString(i18n.language)}</p> <p>Currency: {number.toLocaleString(i18n.language, { style: 'currency', currency: 'USD' })}</p>
SEO Optimization:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); --- <html lang={locale}> <head> <meta charset="UTF-8" /> <title>{t('meta.title')}</title> <meta name="description" content={t('meta.description')} /> <!-- Language switch links --> <link rel="alternate" hreflang="en" href="/en" /> <link rel="alternate" hreflang="zh" href="/zh" /> <link rel="alternate" hreflang="ja" href="/ja" /> <link rel="alternate" hreflang="x-default" href="/" /> </head> <body> <slot /> </body> </html>
Server-Side Rendering (SSR) Internationalization:
typescript// src/middleware.ts import { defineMiddleware } from 'astro:middleware'; export const onRequest = defineMiddleware((context, next) => { const url = new URL(context.request.url); const pathSegments = url.pathname.split('/').filter(Boolean); // Detect language const detectedLocale = detectLocale(context.request); // Redirect to detected language if no language prefix if (!pathSegments[0] || !['en', 'zh', 'ja'].includes(pathSegments[0])) { return context.redirect(`/${detectedLocale}${url.pathname}`); } // Store language in locals context.locals.locale = pathSegments[0]; return next(); }); function detectLocale(request: Request): string { const acceptLanguage = request.headers.get('accept-language'); const browserLocale = acceptLanguage?.split(',')[0].split('-')[0] || 'en'; const supportedLocales = ['en', 'zh', 'ja']; return supportedLocales.includes(browserLocale) ? browserLocale : 'en'; }
RTL (Right-to-Left) Language Support:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); const rtlLocales = ['ar', 'he', 'fa']; const isRTL = rtlLocales.includes(locale); --- <html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}> <head> <style> body { direction: {isRTL ? 'rtl' : 'ltr'}; } </style> </head> <body> <slot /> </body> </html>
Best Practices:
-
Translation Management:
- Use professional translation tools (like Crowdin, Locize)
- Keep translation file structure consistent
- Regularly review and update translations
-
Performance Optimization:
- Load translation files on demand
- Use caching to reduce duplicate requests
- Preload commonly used languages
-
User Experience:
- Provide clear language switcher
- Remember user language preference
- Handle missing translations gracefully
-
SEO Considerations:
- Set correct hreflang for each language
- Use appropriate language tags
- Avoid duplicate content issues
-
Development Workflow:
- Use type-safe translation keys
- Automate translation checks
- Integrate into CI/CD pipeline
Astro's internationalization feature provides flexible multilingual support to help developers build applications for global users.