Skip to content

Hydration completed but contains mismatches #193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
TohidMth opened this issue Dec 1, 2024 · 3 comments
Open

Hydration completed but contains mismatches #193

TohidMth opened this issue Dec 1, 2024 · 3 comments

Comments

@TohidMth
Copy link

TohidMth commented Dec 1, 2024

hi

When using this plugin in inertia
There is a hydration problem in SSR mode

In the following case
ssr.ts

.use(i18nVue, {
    lang: "fa",
    resolve: (lang) => {
        const langs = import.meta.glob("../../lang/*.json", { eager: true });
        return (langs[`../../lang/${lang}.json`] as any).default;
    },
})

Error: Hydration completed but contains mismatches

And in the following case
ssr.ts

.use(i18nVue, {
    resolve: (lang) => {
        const langs = import.meta.glob("../../lang/*.json", { eager: true });
        return (langs[`../../lang/${lang}.json`] as any).default;
    },
})

The hydrated problem is solved. But the texts in the page source are not translated. and are displayed as follows:
messages.example ...

@WentTheFox
Copy link

WentTheFox commented Feb 2, 2025

I managed to solve this by using the page.props to pass down the locale from the app

app/Http/Middleware/HandleInertiaRequests.php

  /**
   * Define the props that are shared by default.
   *
   * @return array<string, mixed>
   */
  public function share(Request $request):array {
    return [
      ...parent::share($request),
      'app' => [
        'name' => config('app.name'),
        'locale' => App::getLocale(),
      ],
      // …
    ];
  }

ssr.ts

createServer((page) =>
  createInertiaApp({
    page,
    render: renderToString,
    title: (title) => title ? `${title} - ${page.props.app.name}` : page.props.app.name,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue')),
    setup({ App, props, plugin }) {
      return createSSRApp({ render: () => h(App, props) })
        .use(plugin)
        .use(ZiggyVue, {
          ...page.props.ziggy,
          location: new URL(page.props.ziggy.location),
        })
        .use(i18nVue, {
          // Set lang dynamically here
          lang: page.props.app.locale,
          fallbackLang: 'en',
          fallbackMissingTranslations: true,
          resolve: (lang: string) => {
            const langJsonImporters = import.meta.glob(`../../lang/php_*.json`, { eager: true });
            const result = langJsonImporters[`../../lang/php_${lang}.json`];
            return result.default;
          },
        });
    },
  }),
);

@SpeedJack
Copy link

SpeedJack commented Feb 3, 2025

I managed to solve this by using the page.props to pass down the locale from the app

This solves the issue of having the correct translation loaded with SSR but does not solve the hydration mismatch.

The mismatch is caused by the async loading of the language. To solve, the app needs to be mounted after the language has been loaded (of course this comes at the cost of delaying the loading of the app). So:

app/Http/Middleware/HandleInertiaRequests.php

namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
	/* ... */

	public function share(Request $request): array
	{
		return array_merge(parent::share($request), [
			'app' => [
				'locale' => App::getLocale(),
			],
		]);
	}
}

resources/js/app.ts

import '../css/app.css';
import './bootstrap';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createSSRApp, type DefineComponent, h } from 'vue';
import { i18nVue } from 'laravel-vue-i18n';

const appName = 'Laravel';

createInertiaApp({
	title: (title) => title ? `${title} - ${appName}` : `${appName}`,
	resolve: (name) => resolvePageComponent(
		`./Pages/${name}.vue`,
		import.meta.glob<DefineComponent>('./Pages/**/*.vue')
	),
	setup({ el, App, props, plugin }) {
		const app = createSSRApp({
			render: () => h(App, props),
		})
		.use(plugin)
		.use(i18nVue, {
			resolve: async lang => {
				const langs = import.meta.glob('../../lang/*.json');
				return await langs[`../../lang/${lang}.json`]();
			},
			onLoad: () => { /* mount app after language is loaded */
				if (el && el.__vue_app__) /* check needed to avoid remounting (which would fail) when we call loadLanguageAsync to change language */
					return;
				app.mount(el);
			}
		}); /* note that app is not mounted here anymore */
	},
});

resources/js/ssr.ts

import { createInertiaApp } from '@inertiajs/vue3';
import createServer from '@inertiajs/vue3/server';
import { renderToString } from '@vue/server-renderer';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createSSRApp, type DefineComponent, h } from 'vue';
import { i18nVue } from 'laravel-vue-i18n';

const appName = 'Laravel';

createServer((page) =>
	createInertiaApp({
		page,
		render: renderToString,
		title: (title) => title ? `${title} - ${appName}` : `${appName}`,
		resolve: (name) => resolvePageComponent(
			`./Pages/${name}.vue`,
			import.meta.glob<DefineComponent>('./Pages/**/*.vue')
		),
		setup({ App, props, plugin }) {
			return createSSRApp({ render: () => h(App, props) })
				.use(plugin)
				.use(i18nVue, {
					lang: page.props.app.locale, /* use correct language server-side */
					resolve: lang => {
						const langs = import.meta.glob('../../lang/*.json', { eager: true });
						return langs[`../../lang/${lang}.json`].default;
					},
				});
		},
	})
);

I think that this should be documented in the README.

@xiCO2k
Copy link
Owner

xiCO2k commented May 10, 2025

Can you send a PR adding that to the readme?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants