React Router v7에서 다국어 사이트맵 생성하는 방법
확장성을 위해 언어별로 사이트맵 구성하기
문제
사이트맵은 검색 엔진이 사이트의 모든 페이지를 발견하고 크롤링하는 데 도움을 줍니다. 언어당 수백 또는 수천 개의 페이지가 있는 다국어 사이트는 빠르게 거대한 사이트맵을 생성할 수 있습니다. 모든 언어의 모든 URL을 나열하는 단일 파일은 다루기 어려워지고, 50,000개 URL 또는 50MB 크기 제한을 초과할 수 있으며, 유지 관리가 어려워집니다. 한 언어의 구조를 업데이트할 때 전체 파일을 재생성하고 재검증해야 합니다. 이러한 접근 방식은 사이트가 성장함에 따라 확장되지 않습니다.
해결책
사이트맵을 계층 구조로 분할하여 별도의 언어별 사이트맵을 가리키는 최상위 사이트맵 인덱스를 만듭니다. 각 언어는 해당 언어의 URL만 포함하는 자체 사이트맵 파일을 갖습니다. 인덱스 파일은 디렉토리 역할을 하며 각 언어 사이트맵의 위치를 나열합니다. 이렇게 하면 개별 파일을 관리하기 쉽게 유지하고, 각 언어를 독립적으로 업데이트할 수 있으며, 새로운 언어나 페이지를 추가할 때 잘 확장됩니다. 검색 엔진은 먼저 인덱스를 크롤링한 다음 각 언어 사이트맵으로 연결되는 링크를 따라갑니다.
단계
1. 사이트맵 인덱스 라우트 생성
모든 언어별 사이트맵을 나열하는 XML 응답을 반환하는 리소스 라우트를 생성합니다.
import type { Route } from "./+types/sitemap";
const LOCALES = ["en", "es", "fr", "de"];
export function loader({ request }: Route.LoaderArgs) {
const { origin } = new URL(request.url);
const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${LOCALES.map(locale => ` <sitemap>
<loc>${origin}/sitemap-${locale}.xml</loc>
</sitemap>`).join("
")}
</sitemapindex>`;
return new Response(sitemapIndex, {
headers: {
"Content-Type": "application/xml",
},
});
}
이 라우트는 XML 응답을 반환하여 API 엔드포인트로 작동합니다. 인덱스는 언어당 하나의 사이트맵을 나열하므로 LOCALES 배열을 업데이트하여 언어를 쉽게 추가하거나 제거할 수 있습니다.
2. 언어별 사이트맵 라우트 생성
각 언어에 대한 개별 사이트맵을 생성하기 위해 동적 세그먼트가 있는 리소스 라우트를 정의합니다.
import type { Route } from "./+types/sitemap.$locale";
export async function loader({ params }: Route.LoaderArgs) {
const locale = params.locale;
const urls = await getUrlsForLocale(locale);
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map(url => ` <url>
<loc>${url}</loc>
</url>`).join("
")}
</urlset>`;
return new Response(sitemap, {
headers: {
"Content-Type": "application/xml",
},
});
}
async function getUrlsForLocale(locale: string): Promise<string[]> {
return [];
}
라우트 경로의 동적 세그먼트는 파싱되어 params.locale로 제공됩니다. 각 언어 사이트맵에는 해당 특정 로케일의 URL만 포함됩니다.
3. 각 언어별 페이지 가져오기
데이터 소스에서 특정 로케일의 모든 페이지를 검색하는 헬퍼 함수를 구현합니다.
async function getUrlsForLocale(locale: string): Promise<string[]> {
const pages = await db.pages.findMany({
where: { locale, published: true },
select: { slug: true },
});
return pages.map((page) => `https://example.com/${locale}/${page.slug}`);
}
이 함수는 요청된 언어로 게시된 페이지를 데이터베이스 또는 콘텐츠 소스에서 쿼리하고 전체 URL을 구성합니다. 애플리케이션에 맞게 쿼리 및 URL 구조를 조정하세요.
4. 사이트맵 라우트 등록
라우트 구성 파일에 사이트맵 라우트를 추가합니다.
import { type RouteConfig, route } from "@react-router/dev/routes";
export default [
route("sitemap.xml", "./routes/sitemap.tsx"),
route("sitemap-:locale.xml", "./routes/sitemap.$locale.tsx"),
] satisfies RouteConfig;
각 라우트는 매칭할 URL 패턴과 라우트 모듈의 파일 경로를 가지고 있습니다. 인덱스 라우트는 /sitemap.xml에서 응답하고, 언어 라우트는 /sitemap-en.xml, /sitemap-es.xml 등에서 응답합니다.
5. robots.txt에 사이트맵 인덱스 추가
public 디렉토리 루트의 robots.txt 파일에서 검색 엔진이 사이트맵 인덱스를 찾을 수 있도록 지정합니다.
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
각 사이트맵을 나열하는 사이트맵 인덱스를 사용하면 검색 엔진이 단일 진입점에서 모든 언어별 사이트맵을 자동으로 발견할 수 있습니다. 검색 엔진은 인덱스를 크롤링하고 각 언어 사이트맵으로의 링크를 자동으로 따라갑니다.