페이지 메타데이터 번역하기

로컬라이즈된 <title> 및 <description> 태그 설정하기

문제

사용자가 스페인어로 페이지를 볼 때 모든 표시되는 콘텐츠는 올바르게 번역됩니다. 그러나 브라우저 탭과 검색 엔진 결과 스니펫에는 여전히 영어 제목과 설명이 표시됩니다. 이러한 메타데이터 불일치는 혼란스러운 사용자 경험을 만들고, 검색에서 관련 없는 정보를 표시하여 SEO에 악영향을 미칩니다.

해결 방법

페이지와 레이아웃 내에서 Next.js generateMetadata 함수를 사용하세요. 이 서버 측 함수는 lang 매개변수를 기반으로 올바른 번역을 로드하고(컴포넌트와 동일한 사전 로딩 로직 사용), 지역화된 제목과 설명이 포함된 동적 metadata 객체를 반환할 수 있습니다.

단계

1. 딕셔너리를 로드하는 함수 생성하기

서버에서 플랫 번역 파일을 로드할 수 있는 방법이 필요합니다. 이를 위한 헬퍼 함수를 생성하세요.

// app/get-dictionary.ts
import 'server-only';

type Messages = Record<string, string>;

const dictionaries: { [key: string]: () => Promise<Messages> } = {
  en: () => import('@/dictionaries/en.json').then((module) => module.default),
  es: () => import('@/dictionaries/es.json').then((module) => module.default),
};

export const getDictionary = async (lang: string) => {
  const load = dictionaries[lang];
  if (load) {
    return load();
  }
  return dictionaries.en();
};

2. 페이지에서 메타데이터 정의하기

페이지 파일(예: app/[lang]/about/page.tsx)에서 generateMetadata라는 async 함수를 내보내세요. Next.js는 페이지를 렌더링할 때 이를 자동으로 호출합니다.

// app/[lang]/about/page.tsx
import { getDictionary } from '@/app/get-dictionary';
import type { Metadata } from 'next';

type Props = {
  params: { lang: string };
};

// This function generates metadata
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  // Load the dictionary for this page
  const dict = await getDictionary(params.lang);

  return {
    title: dict['about.title'], // e.g., "About Us" or "Sobre Nosotros"
    description: dict['about.description'],
  };
}

// The rest of your page component
export default function AboutPage() {
  return (
    <div>
      {/* Page content */}
      <h1>...</h1>
    </div>
  );
}

3. 루트 레이아웃에서 제목 템플릿 설정하기

모든 제목에서 사이트 이름을 반복하지 않으려면 루트 레이아웃에서 템플릿을 설정할 수 있습니다.

// app/[lang]/layout.tsx
import { getDictionary } from '@/app/get-dictionary';
import type { Metadata } from 'next';

type Props = {
  params: { lang: string };
  children: React.ReactNode;
};

// You can generate metadata in layouts too
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const dict = await getDictionary(params.lang);

  return {
    // This provides a base title and a template
    title: {
      default: dict['site.name'], // e.g., "My Awesome Site"
      template: `%s | ${dict['site.name']}`, // e.g., "About Us | My Awesome Site"
    },
    description: dict['site.description'],
  };
}

export default async function RootLayout({ children, params }: Props) {
  // ... rest of your layout (loading providers, etc.)
  return (
    <html lang={params.lang}>
      <body>{children}</body>
    </html>
  );
}