다국어 지원 및 언어 전환
EpoCanvas Docs는 완전한 콘텐츠 수준 다국어를 내장하고 있습니다. 내비게이션 바, 사이드바, 검색 안내 등 화면 문구와 각 문서의 본문 모두 10개 언어의 독립 버전을 제공합니다. 독자가 페이지 오른쪽 위에서 언어를 선택하면 같은 글의 해당 언어 버전으로 이동하며 본문과 화면이 함께 전환됩니다.
지원 언어 목록
사이트는 현재 10개 언어를 제공하며 그중 간체 중국어가 기본 언어입니다:
| 언어 | 언어 이름 | URL 접두사 | UI 약칭 |
|---|---|---|---|
| 简体中文 | 중국어 간체(기본) | 접두사 없음 | ZH |
| 繁體中文 | 중국어 번체 | /zh-tw/ | TW |
| English | 영어 | /en/ | EN |
| 日本語 | 일본어 | /ja/ | JA |
| 한국어 | 한국어 | /ko/ | KO |
| Español | 스페인어 | /es/ | ES |
| Français | 프랑스어 | /fr/ | FR |
| Deutsch | 독일어 | /de/ | DE |
| Русский | 러시아어 | /ru/ | RU |
| Português | 포르투갈어 | /pt/ | PT |
언어 목록은 src/utils/i18n.ts의 SUPPORTED_LANGUAGES에 정의되어 있고, 언어 라우팅은 astro.config.mjs의 locales 설정에 등록되어 있으며 두 곳이 서로 일치해야 합니다.
언어를 전환하는 방법
- 페이지 상단 내비게이션 바 오른쪽에서 언어 버튼(현재 언어의 약칭, 예:
ZH표시)을 찾습니다; - 버튼을 클릭하면 드롭다운 메뉴에 전체 10개 언어가 나열됩니다;
- 대상 언어를 클릭합니다(예:
English또는日本語); - 브라우저가 지금 읽고 있는 이 글의 대상 언어 버전으로 이동하며 내비게이션, 사이드바, 목차, 본문이 함께 대상 언어로 바뀝니다.

그림: 「다국어 지원 및 언어 전환」 페이지에서 언어 버튼을 클릭한 뒤의 실제 주석 효과. ① 상단 바 오른쪽의 언어 전환 버튼, ② 펼쳐진 드롭다운 메뉴에 전체 10개 언어가 나열됨(목록은 스크롤 가능), ③ 현재 적용 중인 언어(체크 표시가 붙음).
그림: 언어 전환의 실행 흐름. 빌드 시점에 언어별로 한 벌의 정적 페이지가 생성되며, 언어 버튼을 클릭하면 해당 언어의 같은 글로 이동합니다. 일부 페이지에 번역문이 없으면 자동으로 간체 중국어로 대체 표시됩니다.
URL 규칙
언어별 페이지는 고유한 URL 접두사를 가지며, 같은 글은 언어마다 접두사만 다릅니다:
/canvas/i18n/ → 간체 중국어(기본 언어, 접두사 없음)/en/canvas/i18n/ → 영어/ja/canvas/i18n/ → 일본어/zh-tw/canvas/i18n/ → 번체 중국어- 언어 정보가 URL에 직접 인코딩되므로 전환된 페이지를 그대로 즐겨찾기하거나 공유할 수 있고, 검색 엔진도 언어별로 각각 수집합니다;
- 페이지 안에 나타나는 사이트 내부 링크(내비게이션, 사이드바, 본문의 추천 링크)는 자동으로 현재 언어의 접두사가 붙으므로, 한 언어 안에서 연속으로 읽다가 중국어 페이지로 튀어나가는 일이 없습니다;
- 각 언어 버전은 빌드 시점에 생성된 독립 정적 페이지이며, 페이지의
<html lang>속성이 언어와 일치하므로 스크린 리더와 번역 도구가 올바르게 인식할 수 있습니다.
번역문이 없으면 어떻게 되나요
시스템은 없는 번역문을 “기본 언어 대체 동작(폴백)” 정책으로 처리합니다. 어떤 문서에 아직 특정 언어의 번역문이 없으면, 그 언어의 페이지에 접속했을 때 기본 언어인 간체 중국어 내용이 표시되고 페이지의 나머지 부분(내비게이션, 사이드바, 화면 문구)은 대상 언어로 유지되며, 404 오류나 빈 페이지가 나타나지 않습니다.
이 정책의 장점은: 새 문서를 추가할 때 모든 언어의 번역문이 준비될 때까지 기다릴 필요가 없다는 것입니다. 먼저 중국어 버전을 발행하고, 번역문이 채워진 뒤 다시 빌드하면 됩니다.
구현 원리
다국어 기능은 Astro와 Starlight의 국제화 메커니즘에 의해 지원되며 빌드 흐름은 다음과 같습니다:
- 콘텐츠 디렉터리를 언어별로 분리: 기본 언어 문서는
src/content/docs/(간체 중국어)에 두고, 다른 언어는src/content/docs/<언어>/아래에 두며 디렉터리 구조는 중국어판과 완전히 대응됩니다. 예를 들어 영어판 「다국어 지원 및 언어 전환」은src/content/docs/en/canvas/i18n.md입니다; - 빌드 시점에 전체 언어 페이지 생성:
astro build가astro.config.mjs의locales설정을 읽어 언어별로 한 벌의 완전한 정적 페이지를 생성합니다; - 화면 문구를 언어별로 렌더링: 상단 바 내비게이션, 검색 안내, 목차 제목 등의 화면 문구는 각 컴포넌트가
getTranslation(key, lang)을 호출하여 빌드 시점에 해당 언어로 바로 출력하며, 페이지 안에 런타임 치환 스크립트가 없습니다; - 본문 내부 링크 자동 현지화: 빌드 파이프라인의
rehypeLocalizeInternalLinks플러그인이 번역문 본문의/canvas/xxx내부 링크에 자동으로 현재 언어 접두사를 붙입니다; - 전체 텍스트 검색을 언어별로 격리: Pagefind가 언어별로 독립 인덱스를 만들어, 영어 페이지에서 검색하면 영어 결과만 반환됩니다.
- 본문 이미지는 언어별로 자동 폴백:
rehypeLocalizeDiagramImages플러그인이 번역 본문의/images/canvas/<파일명>을/images/canvas/<언어>/<파일명>으로 다시 쓰고, 각 언어 이미지는public/images/canvas/<언어>/에 둡니다. 같은 이름의 파일이 없으면 원본 이미지를 그대로 쓰므로 새 이미지를 10개 언어에 동시에 맞출 필요는 없습니다; - 콜아웃과 각주도 페이지 언어를 따릅니다:
rehypeLocalizeAsides와rehypeLocalizeFootnotes가 소스 파일의 언어 디렉터리를 기준으로 콜아웃 제목과 각주 문구를 고칩니다. Starlight은 remark 단계에서 절대 경로로 언어를 추정하는데 로컬 빌드는 상대 경로를 넘기므로, 이 처리가 없으면 전부 중국어로 폴백합니다; - hreflang과 404 페이지:
hreflangXDefault()가 빌드 후 각 페이지에 간체중국어를 가리키는hreflang="x-default"한 줄을 추가하고,src/pages/404.astro는 같은 사전으로 브라우저 언어에 맞는 안내 문구를 출력합니다. 언어 메뉴는 각 언어 첫 페이지로 갑니다.
개발자: 새 언어를 추가하는 방법
이탈리아어(Italiano, 코드 it)를 추가하는 예를 들면:
- 언어 라우팅 등록:
astro.config.mjs의locales에it: { label: 'Italiano', lang: 'it' }를 추가합니다; - 사이드바 문구 보완: 같은 파일의
SIDEBAR_I18N에서 모든 그룹과 항목에it번역을 추가합니다; - 화면 문구 보완:
src/utils/i18n.ts의SUPPORTED_LANGUAGES에 언어 목록(코드, 이름, 약칭, URL 접두사)을 등록하고,UI_TRANSLATIONS에 해당 언어의 화면 문구를 채웁니다; - 문서 내용 번역:
src/content/docs/it/디렉터리를 새로 만들고 중국어판의 디렉터리 구조에 맞춰 번역문을 넣습니다. 아직 번역되지 않은 페이지는 일단 중국어로 대체 표시되므로 점진적으로 채울 수 있습니다; 인터페이스 스크린샷과 다이어그램도 번역하려면public/images/canvas/it/디렉터리를 만들고 같은 이름의 파일을 두면 페이지에서 자동 참조합니다. - 다시 빌드:
pnpm run build를 실행하면 새 언어 페이지와 검색 인덱스가 생성됩니다. 빌드 뒤에node scripts/audit-i18n.mjs와node scripts/check-localized-images.mjs를 실행해 번역 구조와 이미지 참조를 점검합니다. 두 항목 모두 CI에서 통과해야 하는 검사입니다.
개발자: 화면 문구를 추가하거나 수정하는 방법
새 화면 요소를 추가할 때는 src/utils/i18n.ts의 UI_TRANSLATIONS에 문구를 추가합니다:
// 사전은 「언어 → 문구 키」 두 단계로 구성되며 getTranslation의 읽기 순서와 일치합니다export const UI_TRANSLATIONS: Record<string, Record<string, string>> = { // 첫 번째 단계: 기본 언어 zh-CN에 문구를 추가합니다(없으면 화면이 키 이름으로 대체 표시됨) 'zh-CN': { 'nav.plugins': '插件生态', // ...나머지 기존 문구 }, // 두 번째 단계: 다른 언어에 같은 키 이름의 번역을 추가합니다, 채우지 않은 언어는 자동으로 중국어로 대체됩니다 en: { 'nav.plugins': 'Plugins', }, ja: { 'nav.plugins': 'プラグイン', },};그런 다음 컴포넌트에서 getTranslation을 호출하고 현재 언어를 전달합니다:
---import { getLangFromLocale, getTranslation } from '../../utils/i18n';const lang = getLangFromLocale(Astro.currentLocale);---
<a href={localizedHref('/plugins/', lang)}>{getTranslation('nav.plugins', lang)}</a>문구는 빌드 시점에 해당 언어의 정적 텍스트로 렌더링되며 런타임 비용이 없습니다.