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>
        </>
    )
}

最终效果

本站资源来源互联网,用于互联网爱好者学习和研究,如不慎侵犯了您的权利,请及时联系站长处理删除。敬请谅解!
IT资源网 » next ssg 国际化多语言

发表回复

提供最优质的资源集合

立即查看 了解详情