AstroMiddleCoding
Как реализовать i18n в Astro?
Astro 4.0+ имеет встроенный i18n-роутинг через i18n в конфиге. Для переводов контента используют Content Collections или сторонние библиотеки (i18next, paraglide).
Встроенный i18n-роутинг в Astro 4
Начиная с Astro 4.0, в ядро встроена поддержка интернационализации. Настройка в astro.config.mjs:
import { defineConfig } from 'astro/config';
export default defineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'ru', 'de'],
routing: {
prefixDefaultLocale: false, // /about (не /en/about)
},
},
});
Структура директорий
src/pages/
index.astro # / (дефолтный язык)
about.astro # /about
ru/
index.astro # /ru/
about.astro # /ru/about
de/
index.astro # /de/
about.astro # /de/about
Хелперы для i18n
---
import { getRelativeLocaleUrl, getAbsoluteLocaleUrl } from 'astro:i18n';
// Генерация URL для конкретной локали
const ruUrl = getRelativeLocaleUrl('ru', '/about'); // '/ru/about'
const enUrl = getRelativeLocaleUrl('en', '/about'); // '/about'
// Текущая локаль
const currentLocale = Astro.currentLocale; // 'ru' | 'en' | 'de'
---
<nav>
<a href={enUrl}>English</a>
<a href={ruUrl}>Русский</a>
</nav>
Переводы строк с i18next
npm install i18next
// src/i18n/index.ts
import i18next from 'i18next';
const resources = {
en: {
translation: {
hero_title: 'Find your dream job',
hero_cta: 'Browse jobs',
},
},
ru: {
translation: {
hero_title: 'Найдите работу мечты',
hero_cta: 'Смотреть вакансии',
},
},
};
export function getTranslations(locale: string) {
i18next.init({ lng: locale, resources });
return i18next.t.bind(i18next);
}
---
import { getTranslations } from '../../i18n';
const t = getTranslations(Astro.currentLocale ?? 'en');
---
<h1>{t('hero_title')}</h1>
<a href="/jobs">{t('hero_cta')}</a>
Переводы контента через Content Collections
src/content/
blog/
en/
my-post.md
ru/
my-post.md
---
import { getCollection } from 'astro:content';
const locale = Astro.currentLocale ?? 'en';
const posts = await getCollection('blog', (entry) =>
entry.id.startsWith(`${locale}/`)
);
---
Переадресация на локаль пользователя
// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(({ request, redirect }, next) => {
const url = new URL(request.url);
if (url.pathname === '/') {
const acceptLang = request.headers.get('accept-language') ?? '';
const preferred = acceptLang.split(',')[0].split('-')[0];
if (preferred === 'ru') {
return redirect('/ru/', 302);
}
}
return next();
});
Подводные камни
- Встроенный i18n-роутинг не управляет переводами строк — это только маршрутизация. Для переводов нужен отдельный механизм.
prefixDefaultLocale: falseможет конфликтовать с SEO-стратегией: Google рекомендует явные hreflang-теги с полными URL для всех локалей.- При статической сборке каждая локаль генерирует полный набор HTML-файлов — сайт с 5 языками и 100 страницами создаёт 500 HTML-файлов.
- Автоматический detect по
Accept-Languageв статическом режиме невозможен без middleware (SSR-режим обязателен). - Параметр
Astro.currentLocaleвозвращаетundefinedна страницах вне языковой директории — всегда добавляйте фолбэк. - i18next на сервере — синглтон; параллельные запросы с разными локалями могут конфликтовать. Используйте
createInstance()вместо глобального инстанса. - Отсутствие
hreflang-мета-тегов снижает SEO для мультиязычных сайтов — добавляйте их явно в<head>.
Common mistakes
- Не добавлять
hreflangи терять SEO-связь между локалями. - Делать словари как
Record<string, string>без типизации и пропускать ключи. - Игнорировать RTL и сломать вёрстку для
ar/he.
What the interviewer is testing
- Знает конфигурацию
i18nв Astro. - Использует
getRelativeLocaleUrlиgetLocaleByPath. - Помнит про fallback и
hreflang.