React Router v7에서 페이지 메타데이터를 번역하는 방법
검색 및 소셜을 위한 메타데이터 번역
문제
페이지 메타데이터(제목 및 설명)는 페이지 자체가 아닌 브라우저 탭, 북마크, 검색 결과 및 소셜 미디어 미리보기에 표시됩니다. 이 메타데이터가 페이지의 언어와 일치하지 않으면 불일치가 발생합니다. 영어 제목이 있는 스페인어 페이지는 사용자가 콘텐츠를 보기도 전에 혼란을 줍니다. 검색 엔진은 이러한 불일치를 페이지가 제대로 현지화되지 않았거나 품질이 낮다는 신호로 해석하여 언어별 검색 결과에서 순위가 낮아질 수 있습니다. 사용자는 페이지가 자신의 언어로 되어 있지 않다고 생각하여 로드되기 전에 페이지를 떠날 수 있습니다.
해결책
라우트 모듈에서 메타 함수를 내보내 페이지 메타데이터를 현재 언어와 일치하도록 번역하세요. react-intl의 formatMessage API를 메시지 디스크립터와 함께 사용하여 제목 및 설명 문자열을 번역하고, 메타데이터가 페이지 콘텐츠와 동일한 번역 리소스를 사용하도록 합니다. 이렇게 하면 브라우저 탭, 검색 결과 및 페이지 자체에 표시되는 모든 것이 일관성을 유지합니다.
단계
1. 컴포넌트 외부에서 intl에 접근하기 위한 헬퍼 생성
intl 객체는 formatMessage를 제공하며 컴포넌트에서는 useIntl 훅을 통해, 또는 비 React 환경에서는 createIntl로 직접 생성하여 접근할 수 있습니다. 메타 함수는 React 컴포넌트 트리 외부에서 실행되므로 메시지에서 intl 인스턴스를 생성하는 헬퍼를 만듭니다.
import { createIntl, createIntlCache } from "react-intl";
const cache = createIntlCache();
export function createIntlForLocale(
locale: string,
messages: Record<string, string>,
) {
return createIntl(
{
locale,
messages,
},
cache,
);
}
이 헬퍼는 React 컴포넌트뿐만 아니라 모든 함수에서 메시지를 포맷할 수 있는 intl 인스턴스를 생성합니다.
2. 부모 라우트 로더에서 메시지 로드
라우트 로더는 컴포넌트가 loaderData props를 통해 접근하는 데이터를 반환합니다. 번역 메시지를 부모 라우트에서 로드하여 자식 라우트에서 사용할 수 있도록 합니다.
import type { Route } from "./+types/root";
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.pathname.split("/")[1] || "en";
const messages = await import(`../translations/${locale}.json`);
return {
locale,
messages: messages.default,
};
}
메타 함수는 모든 일치하는 라우트의 로더 데이터를 포함하는 matches 매개변수를 받아, 자식 라우트 메타 함수에서 부모 로더 데이터에 접근할 수 있게 합니다.
3. 메타데이터를 번역하는 메타 함수 내보내기
라우트 모듈에서 메타 디스크립터 객체 배열을 반환하는 메타 함수를 내보냅니다. matches에서 부모 로더 데이터에 접근하고 intl 헬퍼를 사용하여 문자열을 번역합니다.
import type { Route } from "./+types/product";
import { createIntlForLocale } from "~/utils/intl";
export function meta({ matches }: Route.MetaArgs) {
const rootMatch = matches.find((match) => match.id === "root");
const { locale, messages } = rootMatch?.data || {
locale: "en",
messages: {},
};
const intl = createIntlForLocale(locale, messages);
return [
{
title: intl.formatMessage({
id: "product.meta.title",
defaultMessage: "Product Details",
}),
},
{
name: "description",
content: intl.formatMessage({
id: "product.meta.description",
defaultMessage: "View detailed information about this product",
}),
},
];
}
formatMessage 함수는 id와 defaultMessage가 있는 메시지 디스크립터를 받아 현재 로케일에 맞는 번역된 문자열을 반환합니다.
4. 번역된 메타데이터 문자열을 메시지 파일에 추가하기
각 로케일의 메시지 파일에 메타데이터 번역 키를 추가하여 formatMessage가 이를 찾을 수 있도록 합니다.
{
"product.meta.title": "Détails du produit",
"product.meta.description": "Voir les informations détaillées sur ce produit"
}
사용자가 이 라우트로 이동하면 루트 레이아웃의 Meta 컴포넌트가 라우트 메타 내보내기에서 생성된 모든 메타 태그를 렌더링하여 페이지 언어와 일치하는 번역된 제목과 설명을 표시합니다.