Перейти к содержимому

Реализация функций i18n

В этом руководстве вы узнаете, как использовать коллекции контента и динамическую маршрутизацию для создания собственного решения интернационализации (i18n) и отображения контента на разных языках.

В этом примере для каждого языка используется свой путь, например, example.com/en/blog для английского и example.com/ru/blog для русского.

Если вы хотите, чтобы язык по умолчанию не отображался в URL (в отличие от других языков), ниже вы найдете инструкции по скрытию языка по умолчанию в URL.

Ознакомьтесь с разделом ресурсов, где вы найдете внешние ссылки на связанные темы, такие как стили для письма справа налево (RTL) и выбор языковых тегов.
  1. Создайте директорию для каждого языка, который вы хотите поддерживать. Например, en/ и ru/ для поддержки английского и русского:

    • Директорияsrc/
      • Директорияpages/
        • Директорияen/
          • about.astro
          • index.astro
        • Директорияru/
          • about.astro
          • index.astro
        • index.astro
  2. Настройте src/pages/index.astro для перенаправления на язык по умолчанию.

    src/pages/index.astro
    <meta http-equiv="refresh" content="0;url=/en/" />

    Этот подход использует meta refresh и будет работать независимо от способа развертывания вашего сайта. На некоторых статических хостингах можно также настроить серверную переадресацию через специальный конфигурационный файл. Подробнее об этом читайте в документации вашей платформы развертывания.

Организация переводов с помощью коллекций

Заголовок раздела Организация переводов с помощью коллекций
  1. Создайте в src/content/ отдельные каталоги для каждого типа контента и добавьте в них подкаталоги для всех поддерживаемых языков. Например, для блог-постов на английском и русском:

    • Директорияsrc/
      • Директорияcontent/
        • Директорияblog/
          • Директорияen/ Посты на английском
            • post-1.md
            • post-2.md
          • Директорияru/ Посты на русском
            • post-1.md
            • post-2.md
  2. Создайте файл src/content.config.ts и экспортируйте коллекцию для каждого типа контента.

    src/content.config.ts
    import { defineCollection, z } from 'astro:content';
    const blogCollection = defineCollection({
    schema: z.object({
    title: z.string(),
    author: z.string(),
    date: z.date()
    })
    });
    export const collections = {
    'blog': blogCollection
    };
    Подробнее о Коллекциях контента.
  3. Используйте динамические маршруты для получения и отображения контента в зависимости от параметров lang и slug.

    В режиме статической генерации используйте функцию getStaticPaths, чтобы создать отдельную страницу для каждой записи контента:

    src/pages/[lang]/blog/[...slug].astro
    ---
    import { getCollection, render } from 'astro:content';
    export async function getStaticPaths() {
    const pages = await getCollection('blog');
    const paths = pages.map(page => {
    const [lang, ...slug] = page.id.split('/');
    return { params: { lang, slug: slug.join('/') || undefined }, props: page };
    });
    return paths;
    }
    const { lang, slug } = Astro.params;
    const page = Astro.props;
    const formattedDate = page.data.date.toLocaleString(lang);
    const { Content } = await render(page);
    ---
    <h1>{page.data.title}</h1>
    <p>by {page.data.author}{formattedDate}</p>
    <Content/>

Создайте словари с переводами для всех текстовых элементов интерфейса вашего сайта. Это позволит посетителям использовать сайт полностью на их родном языке.

  1. Создайте файл src/i18n/ui.ts для хранения переводов интерфейса:

    src/i18n/ui.ts
    export const languages = {
    en: 'English',
    ru: 'Русский',
    };
    export const defaultLang = 'en';
    export const ui = {
    en: {
    'nav.home': 'Home',
    'nav.about': 'About',
    'nav.twitter': 'Twitter',
    },
    ru: {
    'nav.home': 'Главная',
    'nav.about': 'О нас',
    },
    } as const;
  2. Создайте в файле src/i18n/utils.ts две вспомогательные функции: первую для определения языка страницы по текущему URL и вторую для получения переводов элементов интерфейса:

    src/i18n/utils.ts
    import { ui, defaultLang } from './ui';
    export function getLangFromUrl(url: URL) {
    const [, lang] = url.pathname.split('/');
    if (lang in ui) return lang as keyof typeof ui;
    return defaultLang;
    }
    export function useTranslations(lang: keyof typeof ui) {
    return function t(key: keyof typeof ui[typeof defaultLang]) {
    return ui[lang][key] || ui[defaultLang][key];
    }
    }
  3. Импортируйте нужные вспомогательные функции и используйте их для отображения текста на соответствующем языке. Например, компонент навигации может выглядеть так:

    src/components/Nav.astro
    ---
    import { getLangFromUrl, useTranslations } from '../i18n/utils';
    const lang = getLangFromUrl(Astro.url);
    const t = useTranslations(lang);
    ---
    <ul>
    <li>
    <a href={`/${lang}/home/`}>
    {t('nav.home')}
    </a>
    </li>
    <li>
    <a href={`/${lang}/about/`}>
    {t('nav.about')}
    </a>
    </li>
    <li>
    <a href="https://twitter.com/astrodotbuild">
    {t('nav.twitter')}
    </a>
    </li>
    </ul>
  4. На каждой странице элемент <html> должен содержать атрибут lang с указанием используемого языка. В этом примере базовый макет определяет язык из текущего маршрута:

    src/layouts/Base.astro
    ---
    import { getLangFromUrl } from '../i18n/utils';
    const lang = getLangFromUrl(Astro.url);
    ---
    <html lang={lang}>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <slot />
    </body>
    </html>

    Затем вы можете использовать этот макет, чтобы страницы автоматически получали правильный атрибут lang.

    src/pages/en/about.astro
    ---
    import Base from '../../layouts/Base.astro';
    ---
    <Base>
    <h1>About me</h1>
    ...
    </Base>

Позвольте пользователям переключать языки

Заголовок раздела Позвольте пользователям переключать языки

Создайте ссылки на все поддерживаемые языки, чтобы пользователи могли выбрать, на каком языке они хотят просматривать ваш сайт.

  1. Создайте компонент для переключения языков:

    src/components/LanguagePicker.astro
    ---
    import { languages } from '../i18n/ui';
    ---
    <ul>
    {Object.entries(languages).map(([lang, label]) => (
    <li>
    <a href={`/${lang}/`}>{label}</a>
    </li>
    ))}
    </ul>
  2. Добавьте компонент <LanguagePicker /> на сайт так, чтобы он отображался на каждой странице. В примере ниже он добавлен в футер сайта в базовом макете:

    src/layouts/Base.astro
    ---
    import LanguagePicker from '../components/LanguagePicker.astro';
    import { getLangFromUrl } from '../i18n/utils';
    const lang = getLangFromUrl(Astro.url);
    ---
    <html lang={lang}>
    <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width" />
    <title>Astro</title>
    </head>
    <body>
    <slot />
    <footer>
    <LanguagePicker />
    </footer>
    </body>
    </html>
  1. Создайте директорию для каждого языка, кроме языка по умолчанию. Например, храните страницы на языке по умолчанию непосредственно в pages/, а переведенные страницы в ru/:

    • Директорияsrc/
      • Директорияpages/
        • about.astro
        • index.astro
        • Директорияru/
          • about.astro
          • index.astro
  2. Добавьте еще одну строку в src/i18n/ui.ts для управления отображением языка по умолчанию:

    src/i18n/ui.ts
    export const showDefaultLang = false;
  3. Добавьте в файл src/i18n/utils.ts функцию, которая будет формировать правильные пути с учетом текущего языка:

    src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang } from './ui';
    export function useTranslatedPath(lang: keyof typeof ui) {
    return function translatePath(path: string, l: string = lang) {
    return !showDefaultLang && l === defaultLang ? path : `/${l}${path}`
    }
    }
  4. Импортируйте эту функцию там, где она нужна, например, в компонент навигации:

    src/components/Nav.astro
    ---
    import { getLangFromUrl, useTranslations, useTranslatedPath } from '../i18n/utils';
    const lang = getLangFromUrl(Astro.url);
    const t = useTranslations(lang);
    const translatePath = useTranslatedPath(lang);
    ---
    <ul>
    <li>
    <a href={translatePath('/home/')}>
    {t('nav.home')}
    </a>
    </li>
    <li>
    <a href={translatePath('/about/')}>
    {t('nav.about')}
    </a>
    </li>
    <li>
    <a href="https://twitter.com/astrodotbuild">
    {t('nav.twitter')}
    </a>
    </li>
    </ul>
  5. Эту же функцию можно использовать в переключателе языков:

    src/components/LanguagePicker.astro
    ---
    import { languages } from '../i18n/ui';
    import { getLangFromUrl, useTranslatedPath } from '../i18n/utils';
    const lang = getLangFromUrl(Astro.url);
    const translatePath = useTranslatedPath(lang);
    ---
    <ul>
    {Object.entries(languages).map(([lang, label]) => (
    <li>
    <a href={translatePath('/', lang)}>{label}</a>
    </li>
    ))}
    </ul>

Переведите маршруты ваших страниц для каждого языка.

  1. Добавьте соответствия маршрутов в src/i18n/ui.ts:

    src/i18n/ui.ts
    export const routes = {
    de: {
    'services': 'leistungen',
    },
    ru: {
    'services': 'услуги',
    },
    }
  2. Обновите функцию useTranslatedPath в src/i18n/utils.ts, добавив логику перевода маршрутов.

    src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang, routes } from './ui';
    export function useTranslatedPath(lang: keyof typeof ui) {
    return function translatePath(path: string, l: string = lang) {
    const pathName = path.replaceAll('/', '')
    const hasTranslation = defaultLang !== l && routes[l] !== undefined && routes[l][pathName] !== undefined
    const translatedPath = hasTranslation ? '/' + routes[l][pathName] : path
    return !showDefaultLang && l === defaultLang ? translatedPath : `/${l}${translatedPath}`
    }
    }
  3. Создайте вспомогательную функцию в src/i18n/utils.ts, чтобы получить маршрут на основе текущего URL (если он существует):

    src/i18n/utils.ts
    import { ui, defaultLang, showDefaultLang, routes } from './ui';
    export function getRouteFromUrl(url: URL): string | undefined {
    const pathname = new URL(url).pathname;
    const parts = pathname?.split('/');
    const path = parts.pop() || parts.pop();
    if (path === undefined) {
    return undefined;
    }
    const currentLang = getLangFromUrl(url);
    if (defaultLang === currentLang) {
    const route = Object.values(routes)[0];
    return route[path] !== undefined ? route[path] : undefined;
    }
    const getKeyByValue = (obj: Record<string, string>, value: string): string | undefined => {
    return Object.keys(obj).find((key) => obj[key] === value);
    }
    const reversedKey = getKeyByValue(routes[currentLang], path);
    if (reversedKey !== undefined) {
    return reversedKey;
    }
    return undefined;
    }
  4. Теперь эту функцию можно использовать для получения переведенного маршрута. Например, если перевод маршрута не определен, пользователь будет перенаправлен на главную страницу:

    src/components/LanguagePicker.astro
    ---
    import { languages } from '../i18n/ui';
    import { getRouteFromUrl, useTranslatedPath } from '../i18n/utils';
    const route = getRouteFromUrl(Astro.url);
    ---
    <ul>
    {Object.entries(languages).map(([lang, label]) => {
    const translatePath = useTranslatedPath(lang);
    return (
    <li>
    <a href={translatePath(`/${route ? route : ''}`)}>{label}</a>
    </li>
    )
    })}
    </ul>
  • astro-i18next — Интеграция Astro для i18next, включающая ряд полезных компонентов.
  • astro-i18n — Библиотека интернационализации для Astro с упором на TypeScript.
  • astro-i18n-aut — Интеграция Astro для i18n, которая поддерживает defaultLocale без генерации страниц. Интеграция не зависит от адаптера и UI-фреймворка.
  • astro-react-i18next — Интеграция Astro, которая позволяет легко использовать i18next и react-i18next в React-компонентах на сайтах Astro.
  • paraglide — Полностью типобезопасная библиотека i18n, специально разработанная для паттернов частичной гидратации, таких как островки Astro.
Внести свой вклад Сообщество Sponsor