Я использую встроенную поддержку i18n (интернационализация) на Next.js.
Next.js имеет встроенную поддержку интернационализированной (i18n) маршрутизации, начиная с версии 10.0.0. Вы можете указать список локалей, локаль по умолчанию и локали для конкретного домена, и Next.js автоматически выполнит маршрутизацию.
— Интернационализированная маршрутизация https://nextjs.org/docs/advanced-features/i18n-routing
Добавить конфигурацию
Добавьте i18n
конфигурацию в next.config.js
файл. Напишите все локали, которые вы хотите поддерживать, в locales
. А также запишите локаль по умолчанию в defaultLocale
.
module.exports = { i18n: { locales: ['en', 'ja'], defaultLocale: 'ja', }, }
Существует две стратегии обработки локали: маршрутизация подпути и маршрутизация домена. Маршрутизация подпути — /en
/fr
, Маршрутизация домена — example.com
example.fr
.
На этом сайте я выбрал Sub-path Routing.
Например, страница БЛОГ ( pages/blog.js
) будет такой.
/blog
/en/blog
После добавления этой конфигурации Next.js попытается автоматически определить ее в зависимости от среды пользователя.
Вы также можете проверить другие настройки в официальной документации Next.js (Internationalized Routing).
Создать переключатель
Создание Switcher позволяет пользователю менять язык.
Вы можете получить текущую локаль с помощью useRouter
. А также вы можете получить список локалей, которые вы поддерживаете, на своем веб-сайте или в приложении.
import Link from "next/link"; import { useRouter } from "next/router"; export const LocaleSwitcher = () => { const { locale, locales, asPath } = useRouter() return ( <div> {locales && locales.map(localeName => ( <Link key={localeName} href={asPath} passHref locale={localeName}> <a className={locale === localeName ? "current" : "" }> {localeName} </a> </Link> ))} </div> ) }
Поместите в любом месте на вашем веб-сайте или в приложении.
Структура файлового каталога
Я создаю страницу сообщения и статическую страницу с файлом уценки. Я добавил file-name.locale.md
для отображения локализованной страницы.
src/ └── contents/ ├── pages/ | ├── about.en.md | └── about.md | └── posts/ ├── blog/ | ├── blog-post.en.md | └── blog-post.md | └── tips/ ├── tips-post.en.md └── tips-post.md
Создать компонент
На /src/pages/about.tsx
(страница О нас) этого сайта,
- Получите содержимое с помощью
getStaticProps
- Получить данные из файла уценки с помощью
getPageData()
- Конвертировать в HTML и отображать данные с отмеченным
Это фрагмент кода с этого сайта. Получите locale
в getStaticProps
и перейдите к getPageData()
, чтобы получить файл уценки.
import { GetStaticProps, NextPage } from "next"; import { marked } from "marked"; import { getPageData } from "@utils/post"; import { Page } from "@libs/types"; const About: NextPage<{ post: Page }> = ({ post }) => { return ( <div className={post.data.slug} dangerouslySetInnerHTML={{ __html: marked(post.content) }} /> ) } export default About export const getStaticProps: GetStaticProps = async ({ locale }) => { const post = await getPageData("pages", "about", locale) return { props: { post, } } }
Это пример для getPageData()
. В locale === "ja" ? postSlug : postSlug + "." + locale
, какой файл уценки я получу, зависит от текущей локали: about.md
или about.en.md
.
import fs from "fs"; import path from "path"; import matter from "gray-matter"; export function getPageData( type: string, postIdentifier: string, locale: string = "ja", ) { // .md を除いたファイル名を取得 const postSlug = postIdentifier.replace(/\.md$/, ""); // locale に応じたファイルのパスを取得 const filePath = path.join(contentsDirectory, type, `${locale === "ja" ? postSlug : postSlug + "." + locale}.md`); const readFile = fs.readFileSync(filePath, "utf-8"); const { data, content } = matter(readFile); const postData = { slug: postSlug, data, content }; return postData }
投稿ページや記事の一覧ページも同様に、基本的には getStaticProps
で локаль を取得し、 markdown ファイルを取得する функция に渡して、 локаль に応じたファイルを取得して表示します。
Страница со списком сообщений
Я добавил locale
в файл уценки для удобства.
--- title: My Blog Post locale: en date: "2022-02-11" category: "blog" --- ...
Получение локали с getStaticProps
и переход к getPosts()
для получения файла уценки.
export const getStaticProps: GetStaticProps = async ({ locale }) => { const tipsPosts = await getTypePosts("tips", locale) const sortedPosts = tipsPosts.sort((postA, postB) => postA.data.date > postB.data.date ? -1 : 1) return { props: { posts: sortedPosts, }, revalidate: 30 } }
После получения всего файла верните файл уценки, который имеет ту же локаль с текущей локалью, используя filter()
.
export function getPosts( type: string, locale: string = "ja" ) { // get the files from specific directory const files = getPostsDirectory(type); // get the data contains locale from files const allPosts = files.map(file => { return getPostMeta(file, type, locale) }); let filteredPosts = []; // filter the file which has same locale with current locale if (locale === "ja") { filteredPosts = allPosts.filter(post => post.data.locale === "ja") } else { /** en */ filteredPosts = allPosts.filter(post => post.data.locale === "en") }; return filteredPosts }
Страница сведений о публикации
Отображение страницы сведений о публикации с использованием динамических маршрутов Next.js.
src/ └── pages/ └── tips/ └── [slug].tsx
In [slug].tsx
- Получить список путей с помощью
getPostPaths()
- Создать список путей с
getStaticPaths
для рендеринга - Получить данные из файла уценки с помощью
getPostByPath()
- Получите контент с помощью
getStaticProps
- Конвертировать в HTML и отображать данные с отмеченным
Пример: getStaticPaths
в [slug].tsx
export const getStaticPaths: GetStaticPaths = async ({ locales }) => { // Get the path list const postPaths = getPostsPaths("tips") let paths: any[] = [] // Generate pass list with map() for rendering postPaths.map((path: string) => { locales?.map((locale: string) => { paths.push({ params: { slug: `${path}` }, locale, }) }) }) return { paths, fallback: "blocking" } }
И paths
будет таким
{ params: { slug: 'tips-post1' }, locale: 'ja' }, { params: { slug: 'tips-post1' }, locale: 'en' }
Пример: getPostByPath()
для получения файла уценки
export function getPostByPath( path: any, type: string, locale: string = "ja", ) { let postData: Post = initialPost; const files = getPostsDirectory(type); // get the path const filteredFiles = files.filter(file => { return file.includes(path) }) filteredFiles.map((file) => { const tempData = getPost(file, type, locale) // return the data from markdown // if markdown has the same locale with current locale // if it's not, return false if (tempData.data.locale === locale) { postData = getPost(file, type, locale) } else { return false } }) return postData }
Вернитесь к файлу [slug].tsx
, получите локаль в getStaticProps
и перейдите к getPostByPath()
, получите данные из уценки, а затем передайте данные компоненту для отображения данных.
export const getStaticProps: GetStaticProps = async ({ locale, params }) => { const post = await getPostByPath(params!.slug, "tips", locale) return { props: { post: post, slug: params!.slug, }, revalidate: 600 }
Если страница еще не доступна на английском языке
В этом случае добавьте <meta name="robots" content="noindex" />
к тегу заголовка.
Пример: [slug].tsx
На этом сайте для удобства я добавил localized: boolean
в файл уценки. А также отображать сообщение.
import Head from "next/head"; const TipsPost: NextPage<PostProps> = ({ post, slug, tags }) => { return( <> <Head> {locale === "en" && !post.data.localized && <meta name="robots" content="noindex" />} </Head> <article> <p>This page is not available in English yet.</p> <article> </> ) }
Рекомендации
- Расширенные возможности: интернационализированная маршрутизация | Next.js https://nextjs.org/docs/advanced-features/i18n-routing (2023–2–11 参照)
- i18n (интернационализация) с next.js. и уценка https://medium.com/@albert_barsegyan/i18n-internationalization-with-next-js-and-markdown-6477d818e906 (2023-1-14参照)
Первоначально опубликовано 14 февраля 2023 г. на https://chocolat5.com.