☝️Toàn bộ giải thích Triển khai i18next ở pages

C:\Users\Administrator\Desktop\study\next-i18next

Hydration failed because the server rendered HTML didn't match the client...
+ about_title
- Giới thiệu

có nghĩa là SSR (server-side rendering) đã render một nội dung, nhưng client-side sau khi tải lại render nội dung khác — gây ra mismatch. Trong trường hợp của bạn, có vẻ như server render ra about_title (chưa dịch) nhưng client lại hiển thị "Giới thiệu" (bản dịch đúng).


🧠 Nguyên nhân phổ biến trong dự án next-i18next + [lang] dynamic

  1. Bạn dùng useTranslation() nhưng chưa inject bản dịch đúng ở getStaticProps.

  2. Bạn quên truyền i18n từ serverSideTranslations() vào.

  3. Bạn không sử dụng namespacesRequired đúng.

  4. Bạn dùng I18nextProvider thủ công (không cần nữa nếu đã cấu hình next-i18next).

  5. Bạn dùng i18n.changeLanguage() không đúng lúc — gây rehydrate sai.


✅ Cách sửa chính xác

1. Đảm bảo bạn có getStaticProps đúng:

import { GetStaticProps } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import i18nextConfig from '../../../next-i18next.config.js';

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const locale = params?.lang as string;

  return {
    props: {
      ...(await serverSideTranslations(locale, ['translation'], i18nextConfig)),
    },
  };
};

Không cần truyền i18n.changeLanguage() thủ công trong component nữa nếu đã dùng [lang] route.


2. Gọi useTranslation() đúng namespacelang đến từ URL

import { useTranslation } from 'next-i18next';

const { t } = useTranslation('translation'); // namespace 'translation'

3. Đảm bảo bạn không dùng I18nextProvider thủ công trong _app.tsx

next-i18next tự động inject provider qua appWithTranslation(App) — bạn nên dùng như sau:

// pages/_app.tsx
import { appWithTranslation } from 'next-i18next';
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default appWithTranslation(MyApp);

4. Đảm bảo translation.json có key:

{
  "about_title": "Giới thiệu",
  "about_content": "Nội dung giới thiệu"
}

Đặt tại:

public/locales/vi/translation.json
public/locales/en/translation.json

✅ Mẫu about.tsx đúng chuẩn

// src/pages/[lang]/about.tsx
import { GetStaticPaths, GetStaticProps } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import i18nextConfig from '../../../next-i18next.config';
import { useTranslation } from 'next-i18next';

export default function About() {
  const { t } = useTranslation('translation');
  return (
    <div className="p-4">
      <h1 className="text-xl font-bold">{t('about_title')}</h1>
      <p>{t('about_content')}</p>
    </div>
  );
}

export const getStaticPaths: GetStaticPaths = async () => {
  const paths = i18nextConfig.i18n.locales.map((lang) => ({
    params: { lang },
  }));
  return { paths, fallback: false };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const locale = params?.lang as string;
  return {
    props: {
      ...(await serverSideTranslations(locale, ['translation'], i18nextConfig)),
    },
  };
};

Nếu bạn muốn, mình có thể kiểm tra tận gốc trong dự án bạn vừa zip hoặc gửi bản mẫu 100% đúng mà bạn chỉ cần copy vào là chạy được luôn.

Bạn muốn mình gửi bản mẫu không?

Last updated

Was this helpful?