Spec-Zone.ru › Next.js

Международная локализация (i18n) маршрутизация

Примеры
  • Маршрутизация i18n

Next.js имеет встроенную поддержку международной (i18n) маршрутизации с v10.0.0. Вы можете предоставить список языковых локалей, локаль по умолчанию, и домен-специфические локали, и Next.js автоматически обработает маршрутизацию.

Поддержка i18n маршрутизации в настоящее время предназначена для дополнения существующих решений библиотек i18n, таких как react-intl, react-i18next, lingui, rosetta, next-intl, next-translate, next-multilingual, tolgee и другие, упрощая маршрутизацию и обработку локалей.

Начало работы

Для начала добавьте конфигурацию i18n в ваш файл next.config.js.

Локали — это Идентификаторы локалей UTS, стандартизированный формат для определения локалей.

Обычно идентификатор локали состоит из языка, региона и сценария, разделенных дефисом: language-region-script. Регион и сценарий являются необязательными. Пример:

  • en-US — английский язык, используемый в Соединённых Штатах
  • nl-NL — голландский язык, используемый в Нидерландах
  • nl — голландский язык, без указания региона

Если языковая настройка пользователя nl-BE не указана в вашей конфигурации, он будет перенаправлен на nl если доступен, или на локаль по умолчанию в противном случае. Если вы не планируете поддерживать все регионы страны, рекомендуется включать регионы страны, которые будут использоваться как резервные варианты.

module.exports = {
  i18n: {
    // These are all the locales you want to support in
    // your application
    locales: ['en-US', 'fr', 'nl-NL'],
    // This is the default locale you want to be used when visiting
    // a non-locale prefixed path e.g. `/hello`
    defaultLocale: 'en-US',
    // This is a list of locale domains and the default locale they
    // should handle (these are only required when setting up domain routing)
    // Note: subdomains must be included in the domain value to be matched e.g. "fr.example.com".
    domains: [
      {
        domain: 'example.com',
        defaultLocale: 'en-US',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl-NL',
      },
      {
        domain: 'example.fr',
        defaultLocale: 'fr',
        // an optional http field can also be used to test
        // locale domains locally with http instead of https
        http: true,
      },
    ],
  },
}

Стратегии обработки локалей

Существует две стратегии обработки локалей: маршрутизация по подпути и маршрутизация по домену.

Маршрутизация по подпути

Маршрутизация по подпути помещает локаль в путь URL.

module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL'],
    defaultLocale: 'en-US',
  },
}

При данной конфигурации en-US, fr, и nl-NL будут доступны для маршрутизации, а en-US — это локаль по умолчанию. Если у вас есть pages/blog.js, следующие URL будут доступны:

  • /blog
  • /fr/blog
  • /nl-nl/blog

Локаль по умолчанию не имеет префикса.

Маршрутизация по домену

Используя маршрутизацию по домену, вы можете настроить локали для обслуживания с различных доменов:

module.exports = {
  i18n: {
    locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
    defaultLocale: 'en-US',
 
    domains: [
      {
        // Note: subdomains must be included in the domain value to be matched
        // e.g. www.example.com should be used if that is the expected hostname
        domain: 'example.com',
        defaultLocale: 'en-US',
      },
      {
        domain: 'example.fr',
        defaultLocale: 'fr',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl-NL',
        // specify other locales that should be redirected
        // to this domain
        locales: ['nl-BE'],
      },
    ],
  },
}

Например, если у вас есть pages/blog.js, следующие URL будут доступны:

  • example.com/blog
  • www.example.com/blog
  • example.fr/blog
  • example.nl/blog
  • example.nl/nl-BE/blog

Автоматическое определение локали

Когда пользователь посещает корневой адрес приложения (обычно /), Next.js попытается автоматически определить предпочтительную локаль пользователя на основе Accept-Language заголовка и текущего домена.

Если обнаружена локаль, отличная от локали по умолчанию, пользователь будет перенаправлен на:

  • При использовании маршрутизации по подпути: на путь с префиксом локали
  • При использовании маршрутизации по домену: на домен с заданной локаль по умолчанию

При использовании маршрутизации по домену, если пользователь с заголовком Accept-Language fr;q=0.9 посещает example.com, он будет перенаправлен на example.fr, так как этот домен обрабатывает локаль fr по умолчанию.

При использовании маршрутизации по подпути пользователь будет перенаправлен на /fr.

Добавление префикса к локали по умолчанию

С Next.js 12 и Middleware мы можем добавить префикс к локали по умолчанию с помощью обходного пути.

Например, вот файл next.config.js с поддержкой нескольких языков. Обратите внимание, что локаль "default" была добавлена намеренно.

module.exports = {
  i18n: {
    locales: ['default', 'en', 'de', 'fr'],
    defaultLocale: 'default',
    localeDetection: false,
  },
  trailingSlash: true,
}

Далее, мы можем использовать Middleware для добавления пользовательских правил маршрутизации:

import { NextRequest, NextResponse } from 'next/server'
 
const PUBLIC_FILE = /\.(.*)$/
 
export async function middleware(req: NextRequest) {
  if (
    req.nextUrl.pathname.startsWith('/_next') ||
    req.nextUrl.pathname.includes('/api/') ||
    PUBLIC_FILE.test(req.nextUrl.pathname)
  ) {
    return
  }
 
  if (req.nextUrl.locale === 'default') {
    const locale = req.cookies.get('NEXT_LOCALE')?.value || 'en'
 
    return NextResponse.redirect(
      new URL(`/${locale}${req.nextUrl.pathname}${req.nextUrl.search}`, req.url)
    )
  }
}

Этот Middleware пропускает добавление префикса по умолчанию для маршрутов API и файлов public, таких как шрифты или изображения. Если запрос отправляется на локаль по умолчанию, мы перенаправляем на наш префикс /en.

Отключение автоматического определения локали

Автоматическое определение локали можно отключить с помощью:

module.exports = {
  i18n: {
    localeDetection: false,
  },
}

Когда localeDetection установлено в значение false, Next.js больше не будет автоматически перенаправлять пользователя на основе его предпочтительной локали, а будет предоставлять только информацию о локали, обнаруженную либо по домену, основанному на локали, либо по пути локали, как описано выше.

Доступ к информации о локали

Вы можете получить доступ к информации о локали через маршрутизатор Next.js. Например, используя хук useRouter(), доступны следующие свойства:

  • locale содержит текущую активную локаль.
  • locales содержит все настроенные локали.
  • defaultLocale содержит настроенную локаль по умолчанию.

При пре-рендеринге страниц с getStaticProps или getServerSideProps, информация о локали предоставляется в контексте, предоставленном функции.

При использовании getStaticPaths, настроенные локали предоставляются в параметре контекста функции под locales, а настроенная локаль по умолчанию — под defaultLocale.

Переход между локалями

Вы можете использовать next/link или next/router для перехода между локалями.

Для next/link, можно предоставить параметр locale, чтобы перейти в другую локаль из текущей. Если параметр locale не указан, текущая активная locale используется во время клиентских переходов. Например:

import Link from 'next/link'
 
export default function IndexPage(props) {
  return (
    <Link href="/another" locale="fr">
      To /fr/another
    </Link>
  )
}

При прямом использовании методов next/router, вы можете указать используемую locale с помощью параметров перехода. Например:

import { useRouter } from 'next/router'
 
export default function IndexPage(props) {
  const router = useRouter()
 
  return (
    <div
      onClick={() => {
        router.push('/another', '/another', { locale: 'fr' })
      }}
    >
      to /fr/another
    </div>
  )
}

Обратите внимание, что для обработки переключения только locale при сохранении всей информации о маршрутизации, такой как значения динамического маршрута или скрытые значения запроса href, вы можете указать параметр href как объект:

import { useRouter } from 'next/router'
const router = useRouter()
const { pathname, asPath, query } = router
// change just the locale and maintain all other route information including href's query
router.push({ pathname, query }, asPath, { locale: nextLocale })

Подробнее об структуре объекта router.push см. здесь.

Если у вас есть href, который уже включает локаль, вы можете отказаться от автоматической обработки префикса локали:

import Link from 'next/link'
 
export default function IndexPage(props) {
  return (
    <Link href="/fr/another" locale={false}>
      To /fr/another
    </Link>
  )
}

Использование cookie NEXT_LOCALE

Next.js поддерживает переопределение заголовка accept-language с помощью cookie NEXT_LOCALE=the-locale. Этот cookie может быть установлен с помощью переключателя языка, и тогда при возвращении пользователя на сайт будет использована локаль, указанная в cookie, при перенаправлении из / на правильное местоположение локали.

Например, если пользователь предпочитает локаль fr в своем заголовке accept-language, но установлен cookie NEXT_LOCALE=en, то локаль en при посещении / будет перенаправлена на местоположение локали en до удаления или истечения срока действия cookie.

Поисковая оптимизация

Поскольку Next.js знает, на каком языке пользователь посещает сайт, он автоматически добавит атрибут lang к тегу <html>.

Next.js не знает о вариантах страницы, поэтому вам нужно добавить теги мета-данных hreflang с помощью next/head. Подробнее о hreflang см. в документации Google Webmasters здесь.

Как это работает со статической генерацией?

Обратите внимание, что Международная маршрутизация не интегрируется с output: 'export', так как не использует уровень маршрутизации Next.js. Гибридные приложения Next.js, которые не используют output: 'export' полностью поддерживаются.

Динамические маршруты и страницы getStaticProps

Для страниц, использующих getStaticProps с динамическими маршрутами, все варианты локализации страницы, которые необходимо предварительно рендерить, должны возвращаться из getStaticPaths. Наряду с объектом params, возвращаемым для paths, вы также можете вернуть поле locale, указывающее, какую локаль вы хотите отобразить. Например:

export const getStaticPaths = ({ locales }) => {
  return {
    paths: [
      // if no `locale` is provided only the defaultLocale will be generated
      { params: { slug: 'post-1' }, locale: 'en-US' },
      { params: { slug: 'post-1' }, locale: 'fr' },
    ],
    fallback: true,
  }
}

Для автоматически статически оптимизированных и нединамических getStaticProps страниц, будет сгенерирована версия страницы для каждой локализации. Это важно учитывать, так как это может увеличить время сборки в зависимости от того, сколько локалей настроено внутри getStaticProps.

Например, если у вас настроено 50 локалей с 10 нединамическими страницами, использующими getStaticProps, это означает, что getStaticProps будет вызвано 500 раз. 50 версий 10 страниц будут сгенерированы во время каждой сборки.

Чтобы уменьшить время сборки динамических страниц с getStaticProps, используйте режим fallback. Это позволяет возвращать только самые популярные маршруты и локали из getStaticPaths для предварительного рендеринга во время сборки. Затем Next.js соберет оставшиеся страницы во время выполнения по мере их запроса.

Автоматически статически оптимизированные страницы

Для страниц, которые автоматически статически оптимизированы, будет сгенерирована версия страницы для каждой локали.

Нединамические страницы getStaticProps

Для нединамических getStaticProps страниц версия генерируется для каждой локали, как и выше. getStaticProps вызывается для каждой locale , которая рендерится. Если вы хотите исключить определенную локаль из предварительного рендеринга, вы можете вернуть notFound: true из getStaticProps и этот вариант страницы не будет сгенерирован.

export async function getStaticProps({ locale }) {
  // Call an external API endpoint to get posts.
  // You can use any data fetching library
  const res = await fetch(`https://.../posts?locale=${locale}`)
  const posts = await res.json()
 
  if (posts.length === 0) {
    return {
      notFound: true,
    }
  }
 
  // By returning { props: posts }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

Ограничения для конфигурации i18n

  • locales: 100 общих локалей
  • domains: 100 общих элементов домена локализации

Важно знать: Эти ограничения были добавлены в первую очередь для предотвращения потенциальных проблем производительности во время сборки. Вы можете обойти эти ограничения с помощью пользовательского маршрутизирования, используя средства разработки в Next.js 12.

© 2024 Vercel, Inc.
Licensed under the MIT License.
https://nextjs.org/docs/pages/building-your-application/routing/internationalization

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API