next-intl 국제화 라우팅 notFound, error 페이지 설정하기

next js에서 next-intl을 사용시 notFound, error 페이지 설정하는 방법을 알아보겠습니다.


Next js에서 초기 설정 방법에 대한 내용은 이전글 또는 다음 링크를 참고해주세요.
https://recodelog.com/blog/next/internationalization

소개

웹 애플리케이션에서 notFound(404)와 error 페이지는 사용자 경험에 매우 중요한 요소입니다. 사용자가 존재하지 않는 페이지에 접근하거나 예기치 않은 오류가 발생했을 때, 적절한 안내 메시지를 제공하는 것은 필수적입니다

이번 블로그 포스트에서는 next.js에서 next-intl을 사용하여 notFound, error 페이지를 설정하는 방법에 대해 알아보겠습니다.

목차

  1. notFound 페이지 설정하기
  2. error 페이지 설정하기
  3. 마무리
  4. Github Repository
  5. 참고

1. notFound 페이지 설정하기

next.js에서는 404(notFound) 페이지를 설정하기 위해 file-based routing을 사용합니다.

각 라우팅 폴더별 not-found.tsx 파일을 생성하고 해당 파일에 404 페이지를 구현합니다.

기본 app/[locale]/not-found.tsx 경로에서만 not-found 파일을 생성하면

예를들어 루트 경로인 localhost:3000/abc로 접속시 404 페이지가 표시되지 않습니다.

사용자에게 루트 경로까지 404 페이지를 표시하기 위해서는 app/not-found.tsx 파일을 생성해야 합니다.

기본적인 폴더 구조는 다음과 같습니다.

root
└── app
    └── [locale] # 다국어 페이지
   ├── [...rest]
   └── page.tsx
   ├── layout.tsx
   └── page.tsx
    ├── layout.tsx # 기본 레이아웃
    ├── page.tsx # 기본 페이지
    ├── not-found.tsx # 404 페이지
    └── error.tsx # error 페이지
`not-found`페이지를 추가하기위해 반드시 루트 폴더에 layout.tsx 파일이 존재해야 합니다.

다국어를 사용한 app/[locale]/layout.tsx 등의 폴더 구조는 app/layout.tsx 파일을 사용하지 않더라도 redirect를 통해 정상적으로 동작합니다.

다국어를 사용하기위해서 app 폴더에 layout.tsx 파일이 필요하지 않을 수 있겠지만, not-found 페이지 및 기존 next.js에서 제공하는 file-based routing을 사용하기 위해 app 폴더에 layout.tsx 파일이 필요합니다.

다음과 같이 app/layout.tsx 파일을 생성합니다.

app/layout.tsx
// not-found를 사용하기 위해서 반드시 root layout을 만들어야 합니다.
export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return children;
}

해당 코드는 children props를 받아서 그대로 반환하는 코드입니다.

<html> <body> 등 코드를 사용하지 않았습니다. 국제화 next-intl 설정시 html 태그를 반환하면 Hydration 에러가 발생합니다.

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used

해당 원인과 이유는 next-intl 라이브러리를 사용하면 "/" 경로로 접속시 root/en, root/ko 등의 경로로 자동으로 리다이렉트 되는데 이때 app/[locale]/layout.tsx 파일에서 html 태그의 lang 속성이 변경되면서 발생하는 에러입니다.

이를 해결하기 위해 app/layout.tsx 파일을 만들어서 children props를 그대로 반환하도록 하였습니다.

not-found 페이지를 구현하기 위해 app/not-found.tsx 파일을 생성합니다.

app/not-found.tsx
'use client';
 
import Error from 'next/error';
 
export default function NotFound() {
  return (
    <html>
      <body>
        <Error statusCode={404} />
        {/* 예시로 기본 제공하는 Error 컴포넌트를 사용하였습니다. */}
        {/* 컴포넌트는 디자인된 것을 사용하면됩니다. */}
      </body>
    </html>
  );
}
 
export default NotFound;

위 코드는 404 페이지를 구현한 코드입니다. 해당 코드는 html 태그를 사용하였지만, app/layout.tsx 파일에서 html 태그를 사용하지 않았기 때문에 Hydration 에러가 발생하지 않습니다.

app/layout.tsx 파일에서 html 태그를 사용하지 않았기 때문에 app/not-found.tsx 파일에서는 반드시 html, body 태그를 사용해야 합니다.

만약 html, body 태그를 사용하지 않으면 아무 내용도 표시되지 않습니다.

이제 설정되지 않은 경로 예)http://localhost:3000/abc로 접속시 404 페이지가 정상적으로 표시됩니다.

루트 페이지에서 not-found 설정을 했다면 이제 다국어 페이지에서 not-found 페이지를 설정해보겠습니다.

app/[locale]/not-found.tsx 파일을 생성하여 404 페이지를 구현합니다.

app/[locale]/not-found.tsx
'use client';
 
import Error from 'next/error';
 
export default function NotFound() {
  return (
    <div>
      <h1>404 - Page Not Found</h1>
      <p>국제화 페이지 404 에러 페이지입니다.</p>
    </div>
  );
}
 
export default NotFound;

위 코드는 다국어 페이지에서 404 페이지를 구현한 코드입니다.

다국어 페이지에서 404 페이지를 구현할 때는 `html`, `body` 태그를 사용하지 않아도 됩니다.

이미 app/[locale]/layout.tsx 파일에서 html, body 태그를 사용했기 때문에 app/[locale]/not-found.tsx 파일에서는 html, body 태그를 사용하지 않아도 됩니다.

동일한 디자인의 not-found 페이지라면 재사용을 위해 컴포넌트를 만들어 재사용하면 좋습니다. 단, app/not-found.tsx 페이지는 반드시 html, body 태그 안에서 사용해야 합니다.

2. error 페이지 설정하기

루트 경로에서 error를 표시할 내용은 없기 때문에 `app/error.tsx` 파일을 생성하지 않아도 됩니다.

next.js에서 제공하는 error 페이지는 error.tsx 파일을 생성하여 사용할 수 있습니다.

app/[locale]/error.tsx 파일을 생성하여 error 페이지를 구현합니다.

app/[locale]/error.tsx
'use client';
 
import { useEffect } from 'react';
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    console.error(error);
  }, [error]);
 
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}

위 코드는 next.js 공식 홈페이지에서 제공하는 기본 error 페이지를 구현한 코드입니다.

하지만 next-intl을 사용하여 각 언어별로 다른 메세지를 표시할 수 있습니다.

app/[locale]/error.tsx 파일을 다음과 같이 수정합니다.

app/[locale]/error.tsx
'use client';
 
import { useTranslations } from 'next-intl';
import { useEffect } from 'react';
 
type Props = {
  error: Error;
  reset(): void;
};
 
export default function Error({ error, reset }: Props) {
  const t = useTranslations('Error');
 
  useEffect(() => {
    console.error(error);
  }, [error]);
 
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
      <button onClick={reset}>reset</button>
    </div>
  );
}

해당 코드를 사용하기 위해서 json 파일에 Error 키를 추가합니다.

messages/ko.json
{
  "Error": {
    "description": "문제가 발생했습니다. 다시 시도해주세요.",
    "retry": "다시 시도"
  }
}
messages/en.json
{
  "Error": {
    "description": "Something went wrong! Please try again.",
    "retry": "Retry"
  }
}
messages/ja.json
{
  "Error": {
    "description": "問題が発生しました。もう一度お試しください。",
    "retry": "再試行"
  }
}

이제 error 페이지를 다국어로 설정할 수 있습니다.

3. 마무리

이번 포스트에서는 next-intl을 사용하여 notFound와 error 페이지를 설정하는 방법에 대해 알아보았습니다.

주요 내용을 정리하면 다음과 같습니다.

  1. notFound(404) 페이지 설정
  • 루트 경로의 404 페이지를 위해 app/not-found.tsx 파일이 필요
  • 다국어 경로의 404 페이지를 위해 app/[locale]/not-found.tsx 파일 필요
  • 루트 레이아웃(app/layout.tsx)이 반드시 필요하며, Hydration 에러 방지를 위해 최소한의 구조로 구현
  1. error 페이지 설정
  • 다국어 지원 error 페이지는 app/[locale]/error.tsx에 구현
  • useTranslations 훅을 사용하여 각 언어별 에러 메시지 표시 가능
  • 언어별 메시지는 각각의 messages JSON 파일에서 관리

이러한 설정을 통해 사용자들에게 더 나은 경험을 제공할 수 있으며, 특히 다국어 지원이 필요한 웹사이트에서 일관된 에러 처리와 페이지를 제공할 수 있습니다. Next.js와 next-intl의 조합으로 효과적인 국제화 지원과 함께 에러 처리까지 구현할 수 있어, 더욱 견고한 웹 애플리케이션을 만들 수 있습니다.

Github Repository

`Next.js 국제화 예시 저장소`

참고

`next-intl 공식 홈페이지`

관련 태그