next ssg 国际化多语言
本篇文章将结合实例,介绍在nextjs-ssg的框架中如何使用多语言。
目前nextjs对ssg支持并不完善,仍存在不少不支持的功能,其中就有多语言路由部分。在ssr模式下,可以通过简单的配置实现通过路径区分页面语言。但ssg缺少相应的支持。
接下来就开始实现的步骤:
安装相关依赖库
#npm
npm i i18next i18next-ssg next-i18next
#yarn
yarn add i18next i18next-ssg next-i18next
创建配置文件
//项目根目录创建:next-i18next.config.js
module.exports = {
i18n: {
locales: ['en', 'zh'],//多语言配置
defaultLocale: 'en',//默认语言
},
localePath: './public/locales', // 语言文件存放位置
};
修改配置文件
//next.config.ts
import type { NextConfig } from "next";
const { i18n } = require('./next-i18next.config');
const nextConfig: NextConfig = {
//...添加如下配置
env: {
NEXT_PUBLIC_I18N: i18n
},
};
export default nextConfig;
创建翻译资源
//在public/locales目录下对每个语言创建翻译资源 /public/locales/【语言】/common.json
{
"home_text_title":"在线工具-IT资源网",
"welcome": "欢迎来到我的网站",
"description": "支持国际化的静态站点"
}
添加默认语言生成配置
// _app.tsx同级目录下创建 [[...paths]].tsx
export { getStaticProps, getStaticPaths } from "i18next-ssg/Redirect";
import { useRootPathRedirect } from "i18next-ssg";
export default function Page() {
useRootPathRedirect();
return <div>Redirecting...</div>;
}
最终目录结构如下
-public
--locales
---en
----common.json
---zh
----common.json
-src
--pages
---_app.tsx
---_document.tsx
---[[...paths]].tsx
---[locale]
----index.tsx
----其它页面
对页面进行翻译
直接放出我的一个布局文件进行参考,包括语言切换
const { t } = useTranslation("common")
{t("home_text_title")}
import { AppBar, Toolbar, Typography, Box, Container, Button, Menu, MenuItem, IconButton } from '@mui/material'
import { Language as LanguageIcon, KeyboardArrowDown } from '@mui/icons-material'
import Link from 'next/link'
import { useState } from 'react'
import { I18NLink, setUserLocale, useLocaleSwitcher, useTranslation } from 'i18next-ssg';
const localeMap: Record<Locale, string> = {
en: "English",
zh: "中文",
};
const LanguageDropdown = ({
options,
currentLabel
}: {
options: {
label: string;
path: string;
locale: Locale;
}[];
currentLabel: string;
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<Button
onClick={handleClick}
startIcon={<LanguageIcon />}
endIcon={<KeyboardArrowDown />}
sx={{
color: 'white',
textTransform: 'none',
borderRadius: 2,
px: 2,
py: 1,
'&:hover': {
backgroundColor: 'rgba(255, 255, 255, 0.1)',
}
}}
>
{currentLabel}
</Button>
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleClose}
PaperProps={{
sx: {
backgroundColor: 'rgba(255, 255, 255, 0.95)',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255, 255, 255, 0.2)',
borderRadius: 2,
mt: 1,
minWidth: 120,
}
}}
>
{options.map(({ label, path, locale }) => (
<MenuItem
key={path}
onClick={() => {
setUserLocale(locale);
handleClose();
}}
sx={{
'&:hover': {
backgroundColor: 'rgba(99, 102, 241, 0.1)',
}
}}
>
<Link href={path} style={{ textDecoration: 'none', color: 'inherit' }}>
{label}
</Link>
</MenuItem>
))}
</Menu>
</>
);
};
export default function Layout({ children }: { children: React.ReactNode }) {
const { label, options } = useLocaleSwitcher({ localeMap });
const { t } = useTranslation("common")
return (
<>
<AppBar
position="fixed"
sx={{
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
backdropFilter: 'blur(10px)',
backgroundColor: 'rgba(102, 126, 234, 0.9)',
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.1)',
zIndex: 1100,
}}
>
<Toolbar sx={{ minHeight: 64 }}>
<Typography
variant="h5"
component="div"
sx={{
flexGrow: 1,
fontWeight: 600,
background: 'linear-gradient(45deg, #ffffff 30%, #f0f9ff 90%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
textShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',
}}
>
{t("home_text_title")}
</Typography>
<LanguageDropdown options={options} currentLabel={label} />
</Toolbar>
</AppBar>
{/* 添加顶部间距以避免内容被固定导航栏遮挡 */}
<Box sx={{ mt: 8 }} />
<Container
maxWidth="md"
sx={{
mt: 4,
mb: 4,
px: { xs: 2, sm: 3 },
}}
>
{children}
</Container>
<Box
sx={{
textAlign: 'center',
py: 4,
background: 'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',
borderTop: '1px solid rgba(0, 0, 0, 0.05)',
mt: 'auto',
}}
>
<I18NLink href="/">
<Typography
variant="body2"
sx={{
color: '#64748b',
fontWeight: 500,
}}
>
© 2025 IT 资源网 - 专业的技术资源平台
</Typography>
</I18NLink>
</Box>
</>
)
}
最终效果

