next-intlを導入したらISRが動かなくなった

2025-08-03

公式サイト にめちゃくちゃ記述がありました。

とはいえめちゃくちゃ見落としていたので、以下備忘録がてら。


next-intl を導入してかつ Static rendering に対応する方法

以下のいずれかとなります。

  1. Layout で全ページに対応する
  2. Page で各ページに対応する

基本は 1 で良いっぽいです。

Layout で全ページに対応する

import { setRequestLocale } from 'next-intl/server';
import { hasLocale } from 'next-intl';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default async function LocaleLayout({children, params}) {
  const { locale } = await params;

  if (!hasLocale(routing.locales, locale)) {
    notFound();
  }

  // Enable static rendering
  setRequestLocale(locale);

  return (
    // ...
  );
}

基本はこれで良いっぽいですが、紐づくページにおいて、locale 以外のパラメーターが存在する場合、必要に応じて generateStaticParams を呼び出しましょう。

例: /[locale]/blog/[slug] のように slug を持つ場合など

Page で各ページに対応する

import { use } from 'react';
import { setRequestLocale } from 'next-intl/server';
import { useTranslations } from 'next-intl';
import { routing } from '@/i18n/routing';

export const revalidate = 86400;

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default function IndexPage({params}) {
  const { locale } = use(params);

  // Enable static rendering
  setRequestLocale(locale);

  // Once the request locale is set, you
  // can call hooks from `next-intl`
  const t = useTranslations('IndexPage');

  return (
    // ...
  );
}

比較的レアケースな気がします。


またローカルで ISR が正しく設定されているか確認もできます。

npm run build
npm run start
curl -I http://localhost:3000/hoge

curl の結果に Cache-Control が存在するはずなので、s-maxage に revalidate で設定した値が表示されていたらオッケーです。

ちなみに Vercel の仕様で、Vercel 環境に対して curl を叩いても s-maxage は確認できないので注意が必要です。

next-intl を導入した状態でも、Layout や Page での静的対応と、再検証の確認手順を理解しておけば、ISR は問題なく動作することがわかって安心しました。