Выход на международный рынок невозможен без мультиязычного сайта. Долгое время разработчикам приходилось устанавливать тяжелые сторонние библиотеки (вроде i18next или vue-i18n) для управления переводами. Они требовали сложной настройки, добавляли лишние килобайты в клиентский JS-бандл и превращали роутинг в лабиринт.
Начиная с Astro 4, фреймворк предлагает встроенную поддержку i18n (интернационализации) прямо из коробки. В 2026 году это один из самых зрелых и удобных встроенных i18n-решений в экосистеме фронтенда. В этом гайде мы пройдем весь путь от настройки конфига до правильных SEO-тегов для Google.
Шаг 1: Настройка конфигурации
Вся магия начинается с astro.config.mjs. Объявляем список языков и язык по умолчанию:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://yoursite.com', // Обязательно для генерации hreflang
i18n: {
defaultLocale: 'ru',
locales: ['ru', 'en', 'es'],
routing: {
// false: русский по адресу '/', а не '/ru/'
// true: русский также получает префикс '/ru/'
prefixDefaultLocale: false,
},
// Что делать, если страница не переведена?
// 'redirect' — редиректит на версию по умолчанию
// 'ignore' — показывает 404
fallback: {
en: 'ru', // Если английской версии нет — берем русскую
es: 'ru',
},
},
}); После этой настройки Astro автоматически:
- Добавляет
/en/и/es/префиксы к нужным URL. - Предоставляет хелперы
getRelativeLocaleUrl()иAstro.currentLocaleво всех компонентах. - Корректно перенаправляет по правилам
fallback, если перевода нет.
Шаг 2: Файловая структура роутинга
Astro использует роутинг на основе файловой системы. Создайте папки с кодами локалей внутри src/pages/:
src/
└── pages/
├── index.astro ← Главная (русская, по умолчанию)
├── about.astro ← О нас (русская)
├── blog/
│ └── [slug].astro ← Блог (русский)
├── en/
│ ├── index.astro ← Home (english)
│ ├── about.astro ← About (english)
│ └── blog/
│ └── [slug].astro ← Blog (english)
└── es/
├── index.astro ← Inicio (español)
└── blog/
└── [slug].astro ← Blog (español) Шаг 3: Словари и перевод UI
Помимо контента, нужно переводить элементы интерфейса: кнопки навигации, заголовки разделов, подписи к формам.
Создайте файл src/i18n/ui.ts:
// src/i18n/ui.ts
export const languages = {
ru: { name: 'Русский', flag: '🇷🇺' },
en: { name: 'English', flag: '🇬🇧' },
es: { name: 'Español', flag: '🇪🇸' },
};
export const defaultLang = 'ru';
export const ui = {
ru: {
'nav.home': 'Главная',
'nav.blog': 'Блог',
'nav.about': 'О нас',
'nav.contact': 'Контакты',
'blog.readMore': 'Читать далее',
'blog.publishedOn': 'Опубликовано',
'footer.rights': 'Все права защищены',
},
en: {
'nav.home': 'Home',
'nav.blog': 'Blog',
'nav.about': 'About',
'nav.contact': 'Contact',
'blog.readMore': 'Read more',
'blog.publishedOn': 'Published on',
'footer.rights': 'All rights reserved',
},
es: {
'nav.home': 'Inicio',
'nav.blog': 'Blog',
'nav.about': 'Acerca de',
'nav.contact': 'Contacto',
'blog.readMore': 'Leer más',
'blog.publishedOn': 'Publicado el',
'footer.rights': 'Todos los derechos reservados',
},
} as const;
export type UiKey = keyof (typeof ui)['ru']; Создайте хелпер-функцию для получения строки:
// src/i18n/utils.ts
import { ui, defaultLang, type UiKey } from './ui';
export function useTranslations(locale: string) {
return function t(key: UiKey): string {
const lang = locale in ui ? (locale as keyof typeof ui) : defaultLang;
return ui[lang][key] ?? ui[defaultLang][key];
};
} Использование в компоненте:
---
// src/components/Navigation.astro
import { useTranslations } from '../i18n/utils';
import { getRelativeLocaleUrl } from 'astro:i18n';
const locale = Astro.currentLocale ?? 'ru';
const t = useTranslations(locale);
---
<nav>
<a href={getRelativeLocaleUrl(locale, '/')}>{t('nav.home')}</a>
<a href={getRelativeLocaleUrl(locale, '/blog')}>{t('nav.blog')}</a>
<a href={getRelativeLocaleUrl(locale, '/about')}>{t('nav.about')}</a>
</nav> Шаг 4: Мультиязычный контент с Content Collections
Для организации переведенных статей рекомендуется структура с локалью в папке:
src/content/
└── blog/
├── ru/
│ ├── kak-sozdat-sait.mdx
│ └── vvedenie-v-astro.mdx
├── en/
│ ├── how-to-create-website.mdx
│ └── introduction-to-astro.mdx
└── es/
└── como-crear-un-sitio.mdx В content.config.ts настраиваем коллекцию с учетом языка:
// content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
date: z.coerce.date(),
locale: z.enum(['ru', 'en', 'es']).default('ru'),
translationOf: z.string().optional(), // slug оригинала для перелинковки
cover: image().optional(),
coverAlt: z.string().optional(),
}),
});
export const collections = { blog }; Шаг 5: SEO и теги hreflang
Это самый критичный шаг для мультиязычного SEO. Теги hreflang сообщают Google, что существуют версии страницы для разных языков и регионов. Без них поисковик может:
- Показать английским пользователям русскую версию.
- Посчитать все языковые версии за дублированный контент и понизить их в выдаче.
---
// src/layouts/BaseLayout.astro
import { getRelativeLocaleUrl } from 'astro:i18n';
const { title, description } = Astro.props;
const locale = Astro.currentLocale ?? 'ru';
const currentPath = Astro.url.pathname.replace(/^\/(en|es)\//, '/');
const siteUrl = 'https://yoursite.com';
---
<html lang={locale}>
<head>
<title>{title}</title>
<meta name="description" content={description} />
<!-- hreflang для Google -->
<link
rel="alternate"
hreflang="ru"
href={`${siteUrl}${getRelativeLocaleUrl('ru', currentPath)}`}
/>
<link
rel="alternate"
hreflang="en"
href={`${siteUrl}${getRelativeLocaleUrl('en', currentPath)}`}
/>
<link
rel="alternate"
hreflang="es"
href={`${siteUrl}${getRelativeLocaleUrl('es', currentPath)}`}
/>
<!-- Язык по умолчанию (если Google не может определить язык браузера) -->
<link rel="alternate" hreflang="x-default" href={`${siteUrl}/`} />
</head>
<body>
<slot />
</body>
</html> Шаг 6: Переключатель языков
Создайте компонент переключения языка в навигации:
---
// src/components/LanguageSwitcher.astro
import { getRelativeLocaleUrl } from 'astro:i18n';
import { languages } from '../i18n/ui';
const locale = Astro.currentLocale ?? 'ru';
const currentPath = Astro.url.pathname.replace(/^\/(en|es)\//, '/');
---
<div class="lang-switcher">
{
Object.entries(languages).map(([lang, { name, flag }]) => (
<a
href={getRelativeLocaleUrl(lang, currentPath)}
class:list={['lang-btn', { active: locale === lang }]}
hreflang={lang}
>
{flag} {name}
</a>
))
}
</div> Типичные ошибки при создании мультиязычных сайтов
- Забытые hreflang: Ошибка №1. Без них Google игнорирует языковую структуру.
- Одинаковые метатеги на всех языках: Каждая версия страницы должна иметь уникальные
titleиdescriptionна своем языке. - Дублирование контента: Если у вас нет испанской версии статьи — лучше настроить
fallbackна русскую и не создавать пустую страницу. - Жесткий текст в компонентах: Все UI-строки должны идти через функцию
t(), иначе переключение языка сломает интерфейс.
Итог
Astro предлагает один из самых элегантных встроенных i18n-роутеров в мире фронтенда. Он берет на себя сложную работу с URL, предоставляет удобные хелперы и прекрасно интегрируется с Content Collections. Самое трудоемкое в мультиязычном сайте — не техническая часть, а качественный перевод контента. Инвестируйте в него — и ваш Astro-сайт откроет двери для аудитории со всего мира.