Я использую встроенную поддержку 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.