You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:43:05