국제화
Xingluo는 중영 이중 언어 UI 지원을 제공하며, prefixDefaultLocale: false 라우팅 전략을 사용하여 기본 언어에 URL 접두사가 없도록 합니다.
라우팅 전략
Astro의 i18n 구성(astro.config.ts 참조):
tsi18n: { locales: ["zh-cn", "en"], defaultLocale: "zh-cn", routing: { prefixDefaultLocale: false }, }
중요: prefixDefaultLocale: false는 지역화된 페이지 복사본을 자동 생성하지 않습니다 — [locale]/ 미러 라우트를 수동으로 유지해야 합니다.
Xingluo의 접근 방식:
- 루트 페이지 = 기본 언어(
zh-cn), URL 접두사 없음(예:/posts/welcome/) - **
src/pages/[locale]/**가 모든 페이지를 미러링합니다.getStaticPaths는getLocaleParams()를 사용하여 기본값이 아닌 로케일만 생성(예:/en/posts/welcome/) - 미러 페이지도 얇은 래퍼이며, 동일한 View 컴포넌트를 렌더링 로직에 재사용합니다.
/ → 홈 (zh-cn) /en/ → 홈 (en) /posts/welcome/ → 게시물 (zh-cn) /en/posts/welcome/ → 게시물 (en)
로케일 확인
View 컴포넌트는 자동 확인을 위해 Astro.currentLocale을 사용합니다:
- 루트 페이지 →
zh-cn [locale]세그먼트 페이지 →en(또는 기타 기본값이 아닌 로케일)
컴포넌트 계층에서 경로 확인이 필요하지 않습니다. useTranslations(locale)이 해당 문자열을 직접 가져옵니다.
i18n 모듈 구조
| 파일 | 책임 |
|---|---|
index.ts | import.meta.glob("./lang/*.ts", {eager:true})가 언어 로드; DEFAULT_LOCALE, LOCALES, useTranslations(locale), tplStr 내보내기 |
types.ts | 전체 UIStrings 인터페이스(로컬라이즈할 모든 문자열) |
routing.ts | getLocalePrefix, withLocale(path, locale), parseLocaleFromPath(pathname) |
staticPaths.ts | NON_DEFAULT_LOCALES, getLocaleParams() |
format.ts | tplStr(template, vars) — {{key}} 플레이스홀더 교체 |
lang/zh-cn.ts | 간체 중국어(기본값) |
lang/en.ts | 영어 |
UIStrings 구조
UIStrings 인터페이스는 로컬라이즈할 모든 UI 문자열을 그룹별로 정의합니다:
nav: 탐색(홈/게시물/태그/소개/아카이브/검색/rss)post: 게시물(날짜, 공유, 태그, 뒤로, 편집, 목차, 코드 복사, 이미지 라이트박스 등)pagination: 페이지네이션home: 홈페이지(소셜 링크, 추천, 최신)archives: 아카이브(개수, 월)footer: 푸터(저작권)pages: 페이지 제목 및 설명a11y: 접근성 레이블languageSwitcher: 언어 전환기notFound: 404comments: 댓글 섹션
템플릿 문자열
플레이스홀더가 있는 문자열은 {{key}}를 사용하며 tplStr로 교체됩니다:
tsimport { tplStr } from "@/i18n"; // archives.postCount = "{{count}} posts" tplStr(t.archives.postCount, { count: 5 }); // "5 posts"
SEO 다국어 선언
Layout.astro의 head가 출력:
- 각 언어별
<link rel="alternate" hreflang="..." href="..."> x-default는 기본 언어를 가리킴- 사이트맵 통합이 i18n 설정을 활성화하여 hreflang 자동 생성
- 기본값이 아닌 로케일 게시물의 canonical은 기본 로케일 원본을 가리킴(중복 콘텐츠 페널티 방지, SEO 참조)
언어 추가
예: 일본어 ja 추가:
astro.config.ts:i18n.locales에"ja"를 추가하고 사이트맵i18n.locales에"ja": "ja-JP"매핑 추가src/i18n/lang/: 완전한UIStrings를 내보내는ja.ts생성(en.ts를 복사하여 번역)src/i18n/staticPaths.ts:NON_DEFAULT_LOCALES가ja를 자동 포함(LOCALES에서 계산)src/pages/[locale]/: 미러 페이지가 자동으로ja버전 생성(getLocaleParams가 처리)- 언어 전환기:
zh-cn.ts와en.ts의languageSwitcher.names에"ja": "日本語"추가
콘텐츠 수준 번역
Xingluo는 locale 및 translationKey 프론트매터 필드를 통해 게시물의 다국어 콘텐츠를 지원합니다.
기본 사용법
-
기본 언어 게시물:
src/content/posts/<slug>.md에 배치하고translationKey를 그룹 식별자로 설정: -
번역: 언어 하위 디렉토리
src/content/posts/<locale>/<slug>.md에 배치, 동일한translationKey사용:
디렉토리 구조
src/content/posts/ ├── welcome.md # 기본 언어 (zh-cn) ├── en/ │ └── welcome.md # 영어 번역 ├── ja/ │ └── welcome.md # 일본어 번역 └── another-post.md # 독립 게시물 (translationKey 없음)
- 언어 하위 디렉토리 이름은
astro.config.ts의i18n.locales언어 코드와 일치해야 함 - 언어 하위 디렉토리는 URL 슬러그에서 필터링됨(예:
/posts/welcome/,/posts/en/welcome/아님) translationKey가 없는 게시물은 독립적이며 언어 간 연결되지 않음
라우팅 동작
| 시나리오 | 동작 |
|---|---|
기본 로케일에서 zh-cn 게시물 접근 | 기본 언어 원본 렌더링 |
| 번역이 있는 비기본 로케일 | 해당 번역 렌더링 |
| 번역이 없는 비기본 로케일 | 기본 언어 원본으로 폴백(동일 콘텐츠, canonical이 SEO 보호) |
목록 중복 제거
목록 페이지(홈, 게시물 목록, 태그, 아카이브, RSS)는 getPostsForLocale을 사용하여 언어별 대표 게시물을 선택합니다. 각 번역 그룹은 대상 언어로 하나의 카드만 표시하여 동일 주제의 중복 항목을 방지합니다.
canonical 및 SEO
- 독립 번역이 있는 경우: canonical은 번역 자체 URL을 가리키며 검색 엔진이 개별적으로 인덱싱 가능
- 번역이 없는 경우(폴백): canonical은 기본 언어 원본을 가리켜 중복 콘텐츠 페널티 방지
- hreflang 선언이 모든 언어를 포괄하여 언어 버전 간의 관계를 검색 엔진에 전달
SEO 참조.