Next.js更优雅的多语言方案

最近给老婆@暴走哒柠檬 的木炭业务重构了一个B2B的独立站。

需求主要有:

1.多语言

2.有询盘表单

3.完善的SEO优化

最终实际的SEO效果如下,当然这只是基础。

今天也主要分享一下如何做好多语言的建设。

欢迎访问:CharcoalGo

一、目录结构

-app/

|-[lang]/

  |-products/

  |-news/

  |-other/

|-page.js

以上的app就是整个项目的主要目录,其中[lang]代表url中的语言参数,可以被页面获取到;

二、利用中间件避免重复目录

从上边的目录其实可以看到,如果访问/en/products,一切正常,但访问/products,难道还需要在[lang]的同级复制一层吗?这样修改起来也太麻烦了。

最终,利用中间件实现如下重写:

javascript
import { locales } from './lib/i18n';
import { NextRequest, NextResponse } from 'next/server';

const rewritePaths = [
	{ pattern: /^\/$/, destination: '/en/' }, // 匹配根路径 /
	{ pattern: /^\/products(\/)?$/, destination: '/en/products' },
	{ pattern: /^\/products\/([^\/]+)(\/)?$/, destination: '/en/products/$1' }, // 匹配 /products/1 等动态路径
	{ pattern: /^\/news(\/)?$/, destination: '/en/news' },
	{ pattern: /^\/news\/([^\/]+)(\/)?$/, destination: '/en/news/$1' }, // 匹配 /news/1 等动态路径
	{ pattern: /^\/about$/, destination: '/en/about' },
	{ pattern: /^\/contact$/, destination: '/en/contact' },
	{ pattern: /^\/tags$/, destination: '/en/tags' },
	{ pattern: /^\/tags\/([^\/]+)(\/)?$/, destination: '/en/tags/$1' }, // 匹配 /tags/1 等动态路径
];

export function middleware(request) {
	const { pathname } = request.nextUrl;

	for (const { pattern, destination } of rewritePaths) {
		const match = pathname.match(pattern);
		if (match) {
			request.nextUrl.pathname = pathname.replace(pattern, destination);
			return NextResponse.rewrite(request.nextUrl);
		}
	}

	const isExit = locales.some((locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`);

	if (isExit) return;

	request.nextUrl.pathname = `/`;
	return NextResponse.redirect(request.nextUrl);
}

export const config = {
	matcher: ['/((?!_next)(?!.*\\.(?:ico|png|gif|svg|jpg|jpeg|webp|xml|txt|mp4)$)(?!/api).*)'],
};

三、内链优化

上述设计之后,随之而来的问题就是,当访问/en/products时,页面展示了产品列表。

此时,点击产品跳转到的页面应该是/en/products/[name],那这个/en/,如何拼接进去呢?而且在很多页面、组件中都需要拼接,每个地方都写一次判断,太麻烦了。

最终,选择了使用函数方法+Hooks的方式共享了几个参数:

javascript
// hooks/xxx.js
import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import { defaultLocale, locales } from '@/lib/i18n';

export const useLocalizedPath = () => {
	const pathname = usePathname();
	const [langName, setLangName] = useState(defaultLocale);

	useEffect(() => {
		if (pathname !== '/' && locales.includes(pathname.split('/')[1])) {
			setLangName(pathname.split('/')[1]);
		}
	}, [pathname]);

	return { pathname, langName };
};
javascript
export const getLocalizedUrl = (path, lang, link) => {
	if (!path.includes(lang)) {
		if(link == '/'){
			return '/'
		}else{
			return link
		}
	}
	return `/${lang}${link}`;
};

这样,在实际页面中,引用这两个方法进行判断即可。

 

目前也只是做到这里,如果你有更好的方法,欢迎讨论。

留言板

Next.js更优雅的多语言方案

写信给我

交个朋友

  1. Wechat

    yflowerred

    聊会儿
  2. 即刻

    抱走大柠檬

    关注我
  3. Twitter X

    hugLemon

    关注我

友情链接

  1. Free PDF Tools

    免费PDF工具集合

    查看
  2. indie hacker tools

    独立开发者工具集合

    查看
  3. Jasmine Business

    Make your business easier in China.

    查看
  4. 乘风外贸工具导航

    外贸工具导航大全

    查看
  5. inWind乘风出海

    智能外贸生态服务平台

    查看
  6. Charcoal Go

    shisha & BBQ charcoal supplies

    查看
  7. Next.js中文文档

    Next.js中文文档和资源

    查看