总结一下新的Nextjs项目快速接入多语言配置
项目目录:
/
├── README.md
├── messages
│ ├── ar.json
│ ├── en.json
│ ├── ru.json
│ └── zh.json
├── next.config.js
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── src
│ ├── app
│ │ ├── [locale]
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ ├── about
│ │ │ │ └── page.tsx
│ │ │ ├── price
│ │ │ │ └── page.tsx
│ ├── components
│ │ └── LanguageSwitcher.tsx //语言切换组件
│ ├── globals.css
│ ├── i18n.ts
│ ├── middleware.ts
│ └── navigation.ts
├── tailwind.config.ts
└── tsconfig.json
- 将页面都已入到
src->app->[locale]目录下,这样切换语言同一个页面的访问路由就可以进行切换 - 这个多语言采用的是
next-intl方案,需先安装next-intl
npm I -S next-intl
或
pnpm I -S next-intl
3. 在根目录中创建 message 文件夹用来放语言文件
- 在 src 下新建
i18n.ts文件,来配置我们的国际化逻辑。
// src/i18n.tsx
import {headers} from 'next/headers';
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
import {locales} from './navigation';
export default getRequestConfig(async ({locale}) => {
// Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale as any)) notFound();
const now = headers().get('x-now');
const timeZone = headers().get('x-time-zone') ?? 'Europe/Vienna';
const messages = (await import(`../messages/${locale}.json`)).default;
return {
now: now ? new Date(now) : undefined,
timeZone,
messages,
defaultTranslationValues: {
globalString: 'Global string',
// highlight: (chunks) => <strong>{chunks}</strong>
},
formats: {
dateTime: {
medium: {
dateStyle: 'medium',
timeStyle: 'short',
hour12: false
}
}
},
onError(error) {
if (
error.message ===
(process.env.NODE_ENV === 'production'
? 'MISSING_MESSAGE'
: 'MISSING_MESSAGE: Could not resolve `missing` in `Index`.')
) {
// Do nothing, this error is triggered on purpose
} else {
console.error(JSON.stringify(error.message));
}
},
getMessageFallback({key, namespace}) {
return (
'`getMessageFallback` called for ' +
[namespace, key].filter((part) => part != null).join('.')
);
}
};
});
这段逻辑全局配置了 国际化加载的路径,格式化数据的方式,时间等参数,当然还有更多的逻辑处理可以参考 next-intl 文档。
- 配置
navigation.tsx内容定义了国际化的:
- 默认语言和语言列表
- 路由映射
- 国际化路径前缀 这样我们后面在封装 国际化切换组件的收就会有很好的 ts提示
import {
createLocalizedPathnamesNavigation,
Pathnames
} from 'next-intl/navigation';
export const defaultLocale = 'en';
export const locales = ['en', 'zh', 'fr', 'de', 'ar', 'ru'] as const;
export const localePrefix =
process.env.NEXT_PUBLIC_LOCALE_PREFIX === 'never' ? 'never' : 'as-needed';
export const pathnames = {
'/': '/',
'/about': '/about',
'/price': '/price',
} satisfies Pathnames<typeof locales>;
export const {Link, redirect, usePathname, useRouter} =
createLocalizedPathnamesNavigation({
locales,
localePrefix,
pathnames
});
- 配置 next 国际化中间件
在
src目录下新建middleware.ts, 内容如下:
import createMiddleware from 'next-intl/middleware';
import {locales, pathnames, localePrefix, defaultLocale} from './navigation';
export default createMiddleware({
defaultLocale,
localePrefix,
pathnames,
locales,
});
export const config = {
// Skip all paths that should not be internationalized
matcher: ['/((?!_next|.*\\..*).*)']
};
- 在组件 / 页面中使用i18n
'use client';
import { useTranslations } from 'next-intl';
export default Page(){
const t = useTranslations('global');
return <div> { t('technological exchanges') } </div>
}
- 由于 next 项目支持客户端渲染和服务端渲染,所以使用
next-intl的方式也是有区别的,如果我们在页面中出现next-intl相关的服务端渲染报错, 可以在页面同级添加layout.tsx, 然后做如下封装:
import { NextIntlClientProvider, useMessages } from 'next-intl';
type Props = {
children: React.ReactNode;
params: {locale: string};
};
export default function LocaleLayout({children, params: { locale }}: Props) {
// Receive messages provided in `i18n.ts`
const messages = useMessages();
return <NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
}
然后运行项目就可以进行多语言切换了,默认语言为英文,对应的路径为根路径,切换中文后路径变为/zh或、/zh/xxx