Next.js Git Blog (8): 국제화(2) - 본문 매칭과 언어 토글

목차

소개#

이전 글에서는 pages/[lang]/...으로 프로젝트 구조를 개편하고, 동적 경로를 통해 언어별로 라우팅하는 작업을 진행했다. 그래서 현재는 주소창의 URL만 바뀔 뿐, 실제 내용은 언어에 맞춰 변하지 않는 상태다.

이번 포스팅에서는 현재 접속한 경로(lang)에 맞춰 적절한 마크다운 파일을 불러오는 데이터 바인딩 로직과 실시간으로 언어를 선택할 수 있는 **'언어 설정 토글 버튼'**을 구현해보고자 한다.


구현#

1. 언어별 마크다운 파일 매칭

가장 먼저 해야 할 일은 getStaticProps에서 받은 lang 값을 기반으로 동적으로 파일을 불러오는 것인데,
두 가지 구분 방식에 대해 조금 고민이 있었다.

  • 접미사 구분 방식: post-name.en.md
  • 폴더 구분 방식: posts/ko/post-name.md

결과적으로 파일 이름에 접미사를 붙이는 것보다, 폴더로 분리하는 것이 관리하기가 더 명확하다고 판단하여 두 번째 방식으로 진행하기로 결정했다.

그래서 변경된 콘텐츠 구조는 아래와 같다.

contents
├── ko
│   ├── blog
│   └── data
└── en
    ├── blog
    └── data

이제 section과 slug, 마크다운 본문을 가져오는 markdown-utils.ts의 유틸리티 함수들의 수정이 필요하다. 수정 사항은 간단하며, 모든 파일 탐색 경로의 시작점에 lang 파라미터를 끼워 넣어 주기만 하면 된다.

// markdown-utils.ts
 
export const getAllSections = ({
	lang, // lang 파라미터 추가
	sectionRoot = 'contents',
}: {
	lang: LangType;
	sectionRoot?: SectionType;
}): string[] => {
	// 경로상에 lang을 추가하여 해당 언어 폴더를 바라보게 한다.
	const contentRoot = path.join(process.cwd(), sectionRoot, lang);
 
	if (!fs.existsSync(contentRoot)) return [];
 
	return fs
		.readdirSync(contentRoot, { withFileTypes: true })
		.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
		.map((entry) => entry.name);
};

나머지 getAllPostIds나 getMarkdown 함수도 동일한 원리로 수정하면 된다. 이제 getStaticProps에서 전달받은 lang 값을 이 함수들에 넘겨주기만 하면, 각 언어 환경에 맞는 본문 데이터가 정상적으로 화면에 나타난다.

2. 언어 설정 토글 버튼

사용자가 직접 언어를 전환할 수 있도록 Switch 컴포넌트를 활용한 LangSwitch를 구현했다. 선택한 언어를 저장하고 해당 언어의 경로로 이동시키는 작업을 진행한다.

const LangSwitch = ({ lang }: { lang: LangType }) => {
	const router = useRouter();
	const pathname = usePathname();
 
	const toggleHandler = (checked: boolean) => {
		// checked가 true면 'en', false면 'ko'
		const nextLang = checked ? 'en' : 'ko';
 
		// localStorage에 언어 설정 저장
		localStorage.setItem('lang', nextLang);
 
		// 경로 변경
		const pathParts = pathname.split('/');
		pathParts[1] = nextLang;
		const nextPath = pathParts.join('/');
 
		// 페이지 새로고침 없이 부드럽게 이동
		router.push(nextPath);
	};
 
	return <Switch checked={lang === 'en'} onChange={toggleHandler} />;
};
 
export default LangSwitch;

이제 버튼을 클릭하면 언어 전환이 정상적으로 동작하는 것을 확인할 수 있다.

3. SEO를 위한 메타 데이터 최적화

마지막으로 각 페이지에서 props로 전달받는 lang 데이터를 활용해 SEO(검색 엔진 최적화) 수치를 높여보자.

<Head>
	<title>{pageTitle}</title>
	<meta name='description' content={description} />
	<meta property='og:title' content={pageTitle} />
	<meta property='og:description' content={description} />
	{/* 1. 기본 lang 설정 (검색엔진용) */}
	<meta name='language' content={lang} />
	{/* 2. Open Graph 설정 (SNS 공유용) */}
	<meta property='og:locale' content={lang === 'ko' ? 'ko_KR' : 'en_US'} />
</Head>

마무리#

이것으로 국제화 관련 기능 구현을 마쳤다. 아직 블로그에 전체 글 양이 많지 않아서 다행이지... 대부분 AI 도구를 통해 영문 번역 작업을 진행하고 있는데, 그럼에도 불구하고 피곤한 작업인 것 같다. Git 변경사항을 확인하고 자동으로 번역 파일을 생성해주는 스크립트를 구축해보는 것도 좋을 것 같다.