여러 언어를 위한 사이트맵 인덱스 생성

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

문제

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

해결 방법

다른 언어별 사이트맵(예: sitemap-en.xml, sitemap-es.xml)을 가리키는 "사이트맵 인덱스" 역할을 하는 sitemap.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';

// This tells Next.js which sitemaps to build at build time
export async function generateStaticParams() {
  return locales.map((lang) => ({
    lang,
  }));
}

// A helper function to get all pages for a language
// In a real app, this would fetch from a CMS or database
async function getPagesForLanguage(lang: string): Promise<string[]> {
  // These are relative paths, *without* the lang prefix
  // e.g., '/', '/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)에 깔끔하게 구성됩니다.