InertiaJS/React 结合 i18next 页面加载时翻译重渲染问题及预加载需求
InertiaJS/React 结合 i18next 页面加载时翻译重渲染问题及预加载需求
我完全懂你碰到的糟心事——SSR页面先蹦出默认的英文,然后突然跳转到缓存的目标语言,不仅动画直接裂开,SEO还会抓取到错误的初始内容。核心问题其实是服务端渲染和客户端hydrate时的语言不一致,再加上客户端的LanguageDetector要等到页面加载完才检测到正确语言,直接导致了二次渲染。下面是一步步能解决问题的实操方案:
1. 服务端把当前语言传递给Inertia页面
首先得让Laravel服务端把用户的目标语言通过Inertia的共享props传给前端,这样客户端一开始就知道该用什么语言,不用自己瞎检测。
步骤1:创建共享语言的中间件
新建一个中间件来读取cookie里的语言,然后共享给所有Inertia页面:
// app/Http/Middleware/ShareCurrentLanguage.php <?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Inertia\Inertia; class ShareCurrentLanguage { public function handle(Request $request, Closure $next) { // 从cookie取语言,没有就用框架默认 fallback $locale = $request->cookie('i18next') ?? config('app.fallback_locale'); Inertia::share('locale', $locale); return $next($request); } }
步骤2:注册中间件
把这个中间件加到app/Http/Kernel.php的web中间件组里,放在Inertia中间件之后:
protected $middlewareGroups = [ 'web' => [ // ...其他中间件 \App\Http\Middleware\HandleInertiaRequests::class, \App\Http\Middleware\ShareCurrentLanguage::class, // 加这行 ], ];
2. 让客户端直接用服务端传递的语言初始化i18n
现在前端不用再自己检测语言了,直接用服务端传过来的localeprops,从根源上避免二次切换。
修改app.ts的Inertia初始化
// resources/js/app.ts import '../css/app.css'; import { createInertiaApp } from '@inertiajs/react'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import { createRoot } from 'react-dom/client'; import i18n from './lib/i18n'; // 这里要导入i18n实例,不是只引入文件 import { t } from 'i18next'; createInertiaApp({ title: (title) => `${title} - ${t('app.name') || import.meta.env.VITE_APP_NAME || 'Laravel'}`, resolve: (name) => resolvePageComponent(`./pages/${name}.tsx`, import.meta.glob('./pages/**/*.tsx')), setup({ el, App, props }) { // 关键:用服务端传的locale设置i18n语言,等设置完成再渲染组件 const initApp = () => { const root = createRoot(el); root.render(<App {...props} />); }; if (props.locale) { i18n.changeLanguage(props.locale).then(initApp); } else { initApp(); } }, progress: { color: '#0000ff' }, });
调整i18n.ts的服务端/客户端差异化配置
服务端不需要LanguageDetector,直接用我们传递的语言就行:
// resources/js/lib/i18n.ts import i18n from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; import en from '../../../lang/en.json'; import fa from '../../../lang/fa.json'; // 判断是否是服务端环境 const isServer = typeof window === 'undefined'; i18n // 服务端禁用LanguageDetector,客户端保留(用于后续语言切换) .use(isServer ? {} : LanguageDetector) .use(initReactI18next) .init({ debug: true, fallbackLng: 'en', preload: ['en', 'fa'], defaultNS: 'translation', ns: ['translation'], resources: { en: { translation: en }, fa: { translation: fa }, }, interpolation: { escapeValue: false }, detection: { order: ['cookie', 'localStorage', 'navigator'], caches: ['cookie'], cookieMinutes: 43200, }, react: { useSuspense: false, }, }); export default i18n;
3. 服务端SSR时用正确的语言渲染
最后要确保服务端渲染的时候就用正确的语言,不然SSR输出的HTML还是英文,hydrate的时候还是会有问题:
// resources/js/ssr.ts import { createInertiaApp } from '@inertiajs/react'; import createServer from '@inertiajs/react/server'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import ReactDOMServer from 'react-dom/server'; import { type RouteName, route } from 'ziggy-js'; import i18n from './lib/i18n'; import { t } from 'i18next'; createServer((page) => { // 从服务端传递的props里拿到当前语言 const currentLocale = page.props.locale || 'en'; // 服务端初始化i18n语言 i18n.changeLanguage(currentLocale); return createInertiaApp({ page, render: ReactDOMServer.renderToString, title: (title) => `${title} - ${t('app.name') || import.meta.env.VITE_APP_NAME || 'Laravel'}`, resolve: (name) => resolvePageComponent(`./pages/${name}.tsx`, import.meta.glob('./pages/**/*.tsx')), setup: ({ App, props }) => { /* eslint-disable */ // @ts-expect-error global.i18n = i18n; // @ts-expect-error global.route<RouteName> = (name, params, absolute) => route(name, params as any, absolute, { // @ts-expect-error ...page.props.ziggy, // @ts-expect-error location: new URL(page.props.ziggy.location), }); /* eslint-enable */ return <App {...props} />; }, }); });
4. 验证效果
重新构建并启动SSR服务:
npm run build:ssr php artisan inertia:start
现在打开浏览器,页面会直接渲染目标语言,不会再出现先英文再切换的情况,SSR输出的HTML里也是正确的语言内容,SEO和动画都能正常工作了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

