다국어를 위한 사이트맵 인덱스 생성하기

SEO를 위한 대규모 다국어 사이트 관리

문제

사이트에 여러 언어로 된 많은 페이지가 있습니다. 모든 언어의 모든 URL을 나열하는 단일 대용량 sitemap.xml 파일은 비효율적이고 관리하기 어려우며 파일 크기 제한을 초과할 수 있습니다. 이로 인해 한 언어의 URL을 업데이트하거나 검색 엔진이 모든 콘텐츠를 효율적으로 발견하기 어렵습니다.

해결책

"사이트맵 인덱스" 역할을 하는 sitemap.xml 파일을 만들어 다른 언어별 사이트맵(예: sitemap-en.xml, sitemap-es.xml)을 가리키도록 합니다. 이 접근 방식은 콘텐츠를 구성하고, 관리하기 쉬우며, 새로운 언어나 페이지가 추가될 때 효율적으로 확장됩니다.

단계

1. 사이트맵 인덱스 라우트 생성

기존 sitemap.ts 파일 대신 표준 라우트 핸들러를 생성해야 합니다. 이를 통해 사이트맵 인덱스를 생성하는 데 완전한 제어권을 갖게 됩니다.

app/sitemap.xml/route.ts를 생성하세요.

// app/sitemap.xml/route.ts
import { locales, siteBaseUrl } from '@/i18n-config';

export async function GET() {
  const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="[http://www.sitemaps.org/schemas/sitemap/0.9](http://www.sitemaps.org/schemas/sitemap/0.9)">
  ${locales
    .map((locale) => {
      return `
    <sitemap>
      <loc>${siteBaseUrl}/sitemap-${locale}.xml</loc>
      <lastmod>${new Date().toISOString()}</lastmod>
    </sitemap>`;
    })
    .join('')}
</sitemapindex>
`;

  return new Response(sitemapIndex, {
    headers: {
      'Content-Type': 'application/xml',
    },
  });
}

이 파일은 검색 엔진에게 사이트의 사이트맵이 sitemap-en.xml, sitemap-es.xml 등과 같은 다른 파일을 가리키는 인덱스임을 알려줍니다.

2. 언어별 사이트맵을 위한 동적 라우트 생성

다음으로, 각 언어별 사이트맵을 생성할 동적 라우트를 만듭니다.

app/sitemap-[lang].xml/route.ts를 생성하세요.

// app/sitemap-[lang].xml/route.ts
import { locales, siteBaseUrl } from '@/i18n-config';

// 이것은 Next.js에게 빌드 시 어떤 사이트맵을 생성할지 알려줍니다
export async function generateStaticParams() {
  return locales.map((lang) => ({
    lang,
  }));
}

// 언어별 모든 페이지를 가져오는 헬퍼 함수
// 실제 앱에서는 CMS나 데이터베이스에서 가져올 것입니다
async function getPagesForLanguage(lang: string): Promise<string[]> {
  // 이것들은 상대 경로로, 언어 접두사 *없이* 표시됩니다
  // 예: '/', '/about', '/blog/my-post'
  return ['/', '/about', '/contact'];
}

export async function GET(
  request: Request,
  { params }: { params: { lang: string } }
) {
  const { lang } = params;

  if (!locales.includes(lang)) {
    return new Response('Not Found', { status: 404 });
  }

  const pages = await getPagesForLanguage(lang);

  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="[http://www.sitemaps.org/schemas/sitemap/0.9](http://www.sitemaps.org/schemas/sitemap/0.9)">
  ${pages
    .map((page) => {
      const path = page === '/' ? '' : page;
      return `
    <url>
      <loc>${siteBaseUrl}/${lang}${path}</loc>
      <lastmod>${new Date().toISOString()}</lastmod>
    </url>`;
    })
    .join('')}
</urlset>
`;

  return new Response(sitemap, {
    headers: {
      'Content-Type': 'application/xml',
    },
  });
}

이제 sitemap.xml 파일은 깔끔한 인덱스가 되고, 각 언어의 URL은 이 동적 라우트에 의해 생성되는 자체 파일(예: /sitemap-en.xml)에 깔끔하게 구성됩니다.