TanStack Start v1에서 페이지 메타데이터를 번역하는 방법
검색 및 소셜을 위한 메타데이터 번역
문제
페이지 메타데이터(제목 및 설명)는 브라우저 탭, 북마크, 검색 결과 및 소셜 미디어 미리보기에 표시됩니다. 메타데이터 언어가 페이지 콘텐츠 언어와 일치하지 않으면 사용자는 페이지를 보기도 전에 불일치를 경험하게 됩니다. 검색 결과에서 스페인어 페이지에 영어 제목이 표시되는 것은 현지화 품질이 낮다는 신호입니다. 검색 엔진은 이러한 불일치를 랭킹 신호로 해석하여 특정 언어 검색 결과에서 가시성이 낮아질 수 있습니다.
이러한 불일치는 발견 단계에서 사용자 경험을 저하시킵니다. 선호하는 언어로 검색하는 사용자는 메타데이터가 일치할 것으로 기대하며, 불일치는 첫 클릭 전에 신뢰를 약화시킵니다.
해결책
페이지 콘텐츠와 동일한 번역 리소스를 사용하여 페이지 메타데이터를 번역하세요. 라우트 구성에서 번역된 문자열에 접근하고 현지화된 제목 및 설명 메타데이터를 반환하는 head 함수를 정의하세요. 이렇게 하면 브라우저 크롬, 검색 결과 및 렌더링된 페이지에 표시되는 내용 간의 일관성이 보장됩니다.
head 함수 내에서 react-intl의 메시지 포맷팅을 사용함으로써 메타데이터는 번역 워크플로우와 동기화되고 로케일이 변경될 때 자동으로 업데이트됩니다.
단계
1. React 컴포넌트 외부에서 메시지를 포맷팅하는 헬퍼 생성
head 함수는 훅을 사용할 수 없는 React 컴포넌트 트리 외부에서 실행됩니다. react-intl의 createIntl을 사용하여 메시지를 포맷팅하는 유틸리티를 생성하세요.
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export function formatMetadataMessage(
locale: string,
messages: Record<string, string>,
id: string,
values?: Record<string, string | number>,
): string {
const intl = createIntl({ locale, messages }, cache);
return intl.formatMessage({ id }, values);
}
이 헬퍼는 head 함수와 같은 비 React 컨텍스트에서 사용하기 위해 필요에 따라 intl 인스턴스를 생성합니다.
2. 메타데이터 번역 키 정의하기
지역화된 메타데이터가 필요한 각 페이지에 대해 제목과 설명 키를 번역 파일에 추가하세요.
export const enMessages = {
"page.home.title": "Welcome to Our Site",
"page.home.description": "Discover amazing content in your language",
"page.about.title": "About Us",
"page.about.description": "Learn more about our mission and team",
};
export const esMessages = {
"page.home.title": "Bienvenido a Nuestro Sitio",
"page.home.description": "Descubre contenido increíble en tu idioma",
"page.about.title": "Acerca de Nosotros",
"page.about.description": "Conoce más sobre nuestra misión y equipo",
};
이러한 키들은 컴포넌트 번역과 동일한 패턴을 따르며, 모든 지역화된 콘텐츠를 한 곳에 유지합니다.
3. 라우트에 head 함수 추가하기
createFileRoute의 head 옵션을 사용하여 번역된 메타데이터를 반환하세요. 라우트 매개변수나 로더 데이터에서 현재 로케일에 접근한 다음, 헬퍼를 사용하여 메시지를 포맷하세요.
import { createFileRoute } from "@tanstack/react-router";
import { formatMetadataMessage } from "../utils/formatMetadataMessage";
import { enMessages, esMessages } from "../i18n/messages";
const messagesByLocale = {
en: enMessages,
es: esMessages,
};
export const Route = createFileRoute("/$locale/about")({
head: ({ params }) => {
const locale = params.locale || "en";
const messages = messagesByLocale[locale] || messagesByLocale.en;
return {
meta: [
{
title: formatMetadataMessage(locale, messages, "page.about.title"),
},
{
name: "description",
content: formatMetadataMessage(
locale,
messages,
"page.about.description",
),
},
],
};
},
component: AboutPage,
});
function AboutPage() {
return <div>About content</div>;
}
head 함수는 라우트 매칭 중에 실행되며 TanStack Start가 문서 헤드에 렌더링하는 메타데이터 객체를 반환합니다.
4. 동적 메타데이터에 로더 데이터 사용하기
메타데이터가 가져온 데이터에 의존할 때, head 함수에서 loaderData에 접근하여 동적 콘텐츠와 번역된 템플릿을 결합하세요.
import { createFileRoute } from "@tanstack/react-router";
import { formatMetadataMessage } from "../utils/formatMetadataMessage";
import { enMessages, esMessages } from "../i18n/messages";
const messagesByLocale = {
en: enMessages,
es: esMessages,
};
export const Route = createFileRoute("/$locale/posts/$postId")({
loader: async ({ params }) => {
const post = await fetchPost(params.postId);
return { post };
},
head: ({ params, loaderData }) => {
const locale = params.locale || "en";
const messages = messagesByLocale[locale] || messagesByLocale.en;
const { post } = loaderData;
return {
meta: [
{
title: formatMetadataMessage(locale, messages, "page.post.title", {
title: post.title,
}),
},
{
name: "description",
content: post.excerpt,
},
],
};
},
component: PostPage,
});
function PostPage() {
const { post } = Route.useLoaderData();
return <article>{post.content}</article>;
}
로더는 head 함수가 실행되기 전에 데이터를 가져오므로, 동적 값을 번역된 메타데이터 템플릿에 삽입할 수 있습니다.