avatar
05.【个人网站】基于i18n在Next项目中搭建国际化网站
🌐

05.【个人网站】基于i18n在Next项目中搭建国际化网站

keywords
Next.js, 国际化, i18n, 个人网站
published_date
最新编辑 2024年10月16日
Created time
2024年08月06日
slug
本文分享了如何在Next.js项目中使用i18n实现国际化网站,包括依赖安装、项目结构、配置文件、国际化文件的设置,以及组件的使用示例。此外,还提供了常见错误及其解决方案,确保服务器端和客户端的语言设置一致。
tags
Website
Next.js
WEBSITE:
GitHub:
 
在开发个人网站的时候,实现国际化几乎是必不可少的功能,今天给大家分享一下如何使用i18n在Next项目中实现国际化。

安装依赖

npm install next react-i18next i18next next-i18next

项目结构

. ├── next.config.js ├── next-i18next.config.js ├── i18n.js ├── package.json ├── pages │ ├── _app.js │ └── index.js └── public └── locales ├── en │ └── common.json └── zh └── common.json

配置文件

next-i18next.config.js
// next-i18next.config.js const path = require("path"); module.exports = { i18n: { defaultLocale: "zh", locales: ["en", "zh"], }, localePath: path.resolve("./public/locales"), // react: { useSuspense: false }, };
next.config.js
const { i18n } = require('./next-i18next.config'); module.exports = { i18n, };
i18n.js
// i18n.js import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import nextI18NextConfig from "./next-i18next.config"; import en from "./public/locales/en/common.json"; import zh from "./public/locales/zh/common.json"; i18n.use(initReactI18next).init({ resources: { en: { translation: en }, zh: { translation: zh }, }, fallbackLng: nextI18NextConfig.i18n.defaultLocale, lng: nextI18NextConfig.i18n.defaultLocale, keySeparator: false, interpolation: { escapeValue: false, }, }); export default i18n;

应用程序入口

pages/_app.js
import { appWithTranslation } from 'next-i18next'; import '../styles/globals.css'; function MyApp({ Component, pageProps }) { return <Component {...pageProps} />; } export default appWithTranslation(MyApp);
pages/index.js
import { GetStaticProps } from "next"; import NotionService from "@/lib/notion/NotionServer"; import { NOTION_HOME_ID } from "@/lib/constants"; import NotionPage from "@/components/NotionPage"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; const notionService = new NotionService(); export const getStaticProps: GetStaticProps = async ({ locale }: any) => { const post = await notionService.getPage(NOTION_HOME_ID); return { props: { post, ...(await serverSideTranslations(locale, ["common"])), }, revalidate: 10, }; }; const Home = ({ post }: any) => { return ( <> <NotionPage recordMap={post} /> </> ); }; export default Home;

国际化文件

public/locales/en/common.json
{ "home": "Home", "post": "Post", "tags": "Tags", "projects": "Projects", "about": "About", "contact": "Contact Me" }
public/locales/zh/common.json
{ "home": "首页", "post": "文章", "tags": "标签", "projects": "项目", "about": "关于我", "contact": "联系" }

组件使用

示例组件 ExampleComponent.js
import { useTranslation } from 'react-i18next'; const ExampleComponent = () => { const { t } = useTranslation(); return <h1>{t('welcome')}</h1>; }; export default ExampleComponent;
语言切换器 LanguageSwitch.tsx
import { useState } from "react"; import { useRouter } from "next/router"; const LanguageSwitcher = () => { const [dropdownVisible, setDropdownVisible] = useState(false); const router = useRouter(); const { locale, locales, pathname, asPath, query } = router; const toggleDropdown = () => { setDropdownVisible(!dropdownVisible); }; const changeLanguage = (e) => { const selectedLocale = e.target.getAttribute("data-lang"); router.push({ pathname, query }, asPath, { locale: selectedLocale }); setDropdownVisible(false); // Hide dropdown after selecting a language }; return ( <div className="relative inline-block text-left"> <button className="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" onClick={toggleDropdown} > <span className="mr-2">{locale === "en" ? "🇺🇸" : "🇨🇳"}</span> {locale === "en" ? "English" : "中文"} </button> {dropdownVisible && ( <div className="origin-top-right z-10 absolute right-0 mt-2 w-30 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5"> {locales?.map((loc) => ( <div key={loc} data-lang={loc} onClick={changeLanguage} className="flex items-center px-4 py-2 text-sm text-gray-700 cursor-pointer hover:bg-gray-100" > <span className="mr-2">{loc === "en" ? "🇺🇸" : "🇨🇳"}</span> {loc === "en" ? "English" : "中文"} </div> ))} </div> )} </div> ); }; export default LanguageSwitcher;

踩坑

在实际开发的时候会遇到这样的报错
Error: Text content does not match server-rendered HTML.
Text content did not match. Server: "欢迎" Client: "welcome"
这个错误通常是因为在服务器端渲染(SSR)期间生成的内容与在客户端渲染(CSR)期间生成的内容不匹配。可能的原因是 i18next 在服务器端和客户端之间没有正确同步语言设置。
为了解决这个问题,可以尝试以下步骤:
  1. 确保服务器端和客户端的语言设置一致: 确保在服务器端和客户端都设置了正确的语言。
  1. 使用 next-i18next 提供的 serverSideTranslations 函数: 在页面组件中使用 serverSideTranslations 函数来获取翻译文件。
  1. 确保翻译文件的路径正确: 确保翻译文件路径和内容没有错误。
 
如果以上几个步骤都没有解决,在home.tsx中的getStaticProps加入...(await serverSideTranslations(locale, ["common"]))
import { GetStaticProps } from "next"; import NotionService from "@/lib/notion/NotionServer"; import { NOTION_HOME_ID } from "@/lib/constants"; import NotionPage from "@/components/NotionPage"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; const notionService = new NotionService(); export const getStaticProps: GetStaticProps = async ({ locale }: any) => { const post = await notionService.getPage(NOTION_HOME_ID); return { props: { post, ...(await serverSideTranslations(locale, ["common"])), }, revalidate: 10, }; }; const Home = ({ post }: any) => { return ( <> <NotionPage recordMap={post} /> </> ); }; export default Home;

系列文章

🌐
01.【个人网站】如何使用Notion作为数据库进行全栈开发
🌐
02.【个人网站】如何在Next中集成Notion数据库
🌐
03.【个人网站】如何做网站自定义页面 URL 映射
🌐
04.【个人网站】如何使用 Vercel 快速部署个人网站 | 全流程指南
🌐
05.【个人网站】基于i18n在Next项目中搭建国际化网站
🌐
06.【个人网站】使用Mailchimp做网站邮件订阅功能
 

关于我

My desire to practice my skills and share my acquired knowledge fuels my endeavors.

联系 : znjessie858@gmail.com

订阅

订阅我的文章,收到我的最新发布通知,可随时取消订阅!