Skip to content
Apothem

국제화(i18n)

Apothem 문서 사이트가 로케일 코호트를 선언하고, hreflang 대체 언어 링크를 내보내며, 열두 개 언어에 걸쳐 오른쪽에서 왼쪽 방향을 렌더링하는 방식.

이 페이지는 Apothem 문서 사이트가 여러 언어를 처리하는 방식, 즉 사이트가 선언하는 로케일 코호트, 내보내는 hreflang 메커니즘, 오른쪽에서 왼쪽 렌더링, 그리고 각 언어의 페이지가 라우팅에 연결되는 방식을 설명합니다.

결정 요약

  • 플랫폼: Next.js App Router + Fumadocs. 사이트는 site/에서 빌드됩니다. 로케일 코호트는 site/lib/i18n.ts에 선언되며, 대체 언어 링크 메커니즘은 site/lib/hreflang.ts에 있습니다.
  • 로케일 코호트: 열두 개 언어. 열두 개 로케일로 이루어진 Modern Dev Cohort가 정식 진실의 원천입니다. 영어가 소스 로케일이며, 열한 개 대상 로케일은 각각 영어 페이지 세트에서 기계로 시드됩니다. 로케일별 사람 검토가 진행 중이며, 어떤 로케일이 아직 작성하지 않은 페이지는 fallbackLanguage: 'en'이 처리합니다.
  • 로케일별 라우팅: 코호트 전체에서 활성화. 모든 로케일이 라우팅에 연결되어 각자의 URL 접두사(/es/, /zh-cn/, …)로 접근할 수 있으며, 영어는 사이트 루트에서 제공됩니다.
  • hreflang 메커니즘: 활성. 모든 페이지는 각 로케일과 x-default 폴백을 포괄하는 <link rel="alternate"> 세트를 내보내므로, 검색 엔진은 전체 대체 언어 클러스터를 볼 수 있습니다. 링크는 파일 시스템에서 파일별로 확인되므로, 페이지는 해당 로케일에 그 페이지가 있을 때만 그 로케일로 알려집니다.
  • 오른쪽에서 왼쪽 렌더링: 활성. 공유 스타일시트는 전반적으로 논리적 CSS 속성을 사용하므로, 아랍어 페이지가 dir="rtl" 아래에서 올바르게 렌더링됩니다.
  • 번역 검토: 페이지별 추적. 기계로 시드된 로케일 페이지는 제공되며, 사람이 검토하기 전까지 프런트매터에 machineTranslated: true를 지닙니다. 이 플래그는 검토 추적용 메타데이터이며 페이지에 표시되지 않습니다. 어떤 로케일에 없는 페이지는 영어가 폴백으로 처리합니다. 로케일 페이지의 80%를 검토하는 것은 검토 목표이지, 게시를 막는 관문이 아닙니다.
  • 번역 최신성: 페이지별 추적. 각 로케일 페이지는 번역의 바탕이 된 영어 텍스트를 기록합니다. 이후 영어 페이지가 변경되면, 번역된 페이지에 영어 페이지로 연결되는 한 줄짜리 안내가 표시되며, 영어 페이지가 계속 권위를 가집니다.

로케일 코호트

Modern Dev Cohort는 열두 개 로케일을 선언합니다. 영어는 사이트 루트에서 제공됩니다. 열한 개 대상 로케일은 각각 영어 페이지 세트에서 기계로 시드되어 자체 URL 접두사에서 제공되며, 아직 작성되지 않은 페이지는 fallbackLanguage: 'en'이 처리합니다.

코드경로언어방향
en/영어LTR
zh-CN/zh-cn/중국어 간체LTR
es/es/스페인어LTR
pt-BR/pt-br/브라질 포르투갈어LTR
fr/fr/프랑스어LTR
de/de/독일어LTR
ja/ja/일본어LTR
ko/ko/한국어LTR
ru/ru/러시아어LTR
id/id/인도네시아어LTR
ar/ar/아랍어RTL
hi/hi/힌디어LTR

코호트는 단일 진실의 원천입니다. 코호트에 대한 수정은 신중한 결정을 거치며, 결코 조용한 편집으로 이루어지지 않습니다.

hreflang 작동 방식

site/lib/hreflang.ts는 Next.js가 각 페이지의 <head>에 렌더링하는 alternates.languages 맵을 만듭니다. 이 맵은 한 가지 규칙을 따릅니다. 로케일의 대체 언어 링크는 해당 로케일이 그 페이지를 작성한 경우에만 내보내며, 이는 파일 시스템에서 파일별로 확인됩니다 (site/lib/translated-pages.ts). 따라서 완전히 번역된 페이지는 전체 클러스터를 내보냅니다.

<link rel="alternate" hreflang="en" href="https://apothem.ahmedgad.com/..." />
<link rel="alternate" hreflang="es" href="https://apothem.ahmedgad.com/es/..." />
<link rel="alternate" hreflang="ar" href="https://apothem.ahmedgad.com/ar/..." dir="rtl" />
<!-- … one per cohort locale … -->
<link rel="alternate" hreflang="x-default" href="https://apothem.ahmedgad.com/..." />

페이지의 canonical 링크는 항상 그 페이지 자신의 URL이며, 결코 다른 로케일을 가리키지 않습니다.

오른쪽에서 왼쪽 렌더링

아랍어는 코호트의 오른쪽에서 왼쪽 방향 로케일이며, 사이트는 이를 올바르게 렌더링합니다.

  • 논리적 CSS 속성만 사용. 공유 스타일시트와 컴포넌트는 물리적 속성 (margin-left, text-align: left) 대신 논리적 속성(margin-inline-start, padding-inline-end, text-align: start, inset-inline-start)을 사용합니다. 논리적 속성은 dir="rtl" 아래에서 자동으로 뒤집히므로, 같은 스타일시트가 두 방향 모두를 올바르게 지원합니다.
  • 방향 속성. 아랍어 페이지는 <html> 요소에 lang="ar"와 함께 dir="rtl"을 설정합니다.
  • 양방향 콘텐츠. 방향이 섞인 문자열 — 예를 들어 아랍어 단락 안의 영어 명령 — 은 <bdi>로 감싸, 포함된 왼쪽에서 오른쪽 방향 구간이 오른쪽에서 왼쪽 흐름 안에서 올바르게 렌더링되도록 합니다.

로케일 추가 또는 업데이트

코호트와 라우팅은 site/lib/i18n.ts가 구동합니다.

  1. 영어 소스를 그대로 반영하여 content/docs/<locale>/ 아래에 페이지를 작성합니다.
  2. 페이지가 번역한 영어 텍스트를 기록합니다. site/에서 node scripts/translation-sources.mjs --stamp <locale>/<path>.mdx를 실행하면, 영어 페이지의 해시가 로케일 페이지의 sourceHash 프런트매터에 기록됩니다.
  3. 로케일이 ROUTED_LOCALES에 나열되어 있는지 확인합니다(현재 코호트의 열두 개 로케일이 모두 라우팅됩니다).
  4. 해당 로케일의 hreflang 링크와 라우트는 파일 시스템에서 자동으로 확인됩니다.

오래된 번역

로케일 페이지의 sourceHash는 번역의 바탕이 된 영어 페이지의 해시로, 영어 프런트매터와 본문은 포함하지만 레퍼런스 생성기가 모든 언어에서 한꺼번에 다시 쓰는 생성된 표는 포함하지 않습니다. 빌드 시 사이트는 현재 영어 페이지의 해시를 계산하며, 두 값이 다르면 번역된 페이지에 번역 이후 영어 페이지가 변경되었다는 안내가 영어 페이지 링크와 함께 표시됩니다. site/에서 node scripts/translation-sources.mjs를 실행해 로케일별로 오래된 페이지를 나열한 다음, 각 번역을 갱신하고 위 2단계와 같이 스탬프합니다. 어떤 로케일이 전혀 번역하지 않은 페이지는 영어 텍스트로 표시된 채 영어 소스에서 제공됩니다.

영어가 계속 진실의 원천이며, 각 로케일 페이지는 대응하는 영어 페이지의 구조, 링크, 코드 샘플을 그대로 반영합니다.

On this page