국제화 (i18n)
EmDash는 다국어 콘텐츠 관리를 제공하기 위해 Astro의 내장 i18n 라우팅과 통합됩니다. Astro는 URL 라우팅과 로케일 감지를 처리하고, EmDash는 번역된 콘텐츠 저장 및 검색을 처리합니다.
각 번역은 자체 슬러그, 상태 및 수정 기록을 가진 완전하고 독립적인 콘텐츠 항목입니다. 게시물의 프랑스어 버전은 초안 상태인 동안 영어 버전은 게시될 수 있습니다.
Astro 설정에 i18n 블록을 추가하여 i18n을 활성화하세요. EmDash는 이 구성을 자동으로 읽습니다 — EmDash에서 별도의 로케일 설정이 필요하지 않습니다.
import { defineConfig } from "astro/config";import emdash, { local } from "emdash/astro";import { sqlite } from "emdash/db";
export default defineConfig({ i18n: { defaultLocale: "en", locales: ["en", "fr", "es"], fallback: { fr: "en", es: "en" }, }, integrations: [ emdash({ database: sqlite({ url: "file:./data.db" }), storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file", }), }), ],});Astro 설정에 i18n이 없을 경우, 모든 i18n 기능이 비활성화되고 EmDash는 단일 언어 CMS처럼 동작합니다.
번역 작동 방식
섹션 제목: “번역 작동 방식”EmDash는 로케일별 행(row-per-locale) 모델을 사용합니다. 각 번역은 데이터베이스에서 자체 ID, 슬러그 및 상태를 가진 별도의 행이며, 공유된 translation_group 식별자를 통해 다른 번역들과 연결됩니다.
ec_posts:id | slug | locale | translation_group | status---------|-------------|--------|-------------------|----------01ABC... | my-post | en | 01ABC... | published01DEF... | mon-article | fr | 01ABC... | draft01GHI... | mi-entrada | es | 01ABC... | published이 설계는 다음을 의미합니다:
- 로케일별 슬러그 —
/blog/my-post와/fr/blog/mon-article이 자연스럽게 작동합니다 - 로케일별 게시 — 영어 버전을 게시하면서 프랑스어 버전을 초안 상태로 유지합니다
- 로케일별 수정 기록 — 각 번역은 자체 수정 기록을 가집니다
- 로케일 간 쿼리 복잡성 없음 — 목록 쿼리는 하나의 로케일에 대한 항목만 반환합니다
번역된 콘텐츠 쿼리하기
섹션 제목: “번역된 콘텐츠 쿼리하기”단일 항목
섹션 제목: “단일 항목”특정 번역을 검색하려면 getEmDashEntry에 locale을 전달하세요. 생략할 경우, 요청의 현재 로케일(Astro의 i18n 미들웨어에 의해 설정됨)로 기본 설정됩니다.
astro title="src/pages/[...slug].astro"---import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug, { locale: Astro.currentLocale,});
if (!post) return Astro.redirect("/404");---
<article> <h1>{post.data.title}</h1></article>폴백 체인
섹션 제목: “폴백 체인”요청된 로케일에 대한 콘텐츠가 없을 경우, EmDash는 Astro 설정에 정의된 폴백 체인을 따릅니다. fallback: { fr: "en" }가 주어지면:
- 요청된 로케일(
fr)을 시도합니다 - 폴백 로케일(
en)을 시도합니다 - 기본 로케일을 시도합니다
폴백은 단일 항목 쿼리에만 적용됩니다. 목록 쿼리는 요청된 로케일에 대한 항목만 반환합니다 — 로케일 간 혼합이 없습니다.
컬렉션 목록
섹션 제목: “컬렉션 목록”로케일별로 컬렉션을 필터링합니다:
astro title="src/pages/posts.astro"---import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts", { locale: Astro.currentLocale, status: "published",});---
<ul> {posts.map((post) => ( <li><a href={`/${post.data.slug}`}>{post.data.title}</a></li> ))}</ul>언어 전환기
섹션 제목: “언어 전환기”현재 항목의 기존 번역에 연결하는 언어 전환기를 구축하려면 getTranslations를 사용하세요:
astro title="src/components/LanguageSwitcher.astro"---import { getTranslations } from "emdash";import { getRelativeLocaleUrl } from "astro:i18n";
interface Props { collection: string; entryId: string;}
const { collection, entryId } = Astro.props;const { translations } = await getTranslations(collection, entryId);---
<nav aria-label="Language"> <ul> {translations.map((t) => ( <li> <a href={getRelativeLocaleUrl(t.locale, `/blog/${t.slug}`)} aria-current={t.locale === Astro.currentLocale ? "page" : undefined} > {t.locale.toUpperCase()} </a> </li> ))} </ul></nav>getTranslations 함수는 동일한 번역 그룹 내의 모든 로케일 변형을 반환합니다:
const { translationGroup, translations } = await getTranslations("posts", post.entry.id);// translations: [// { locale: "en", id: "01ABC...", slug: "my-post", status: "published" },// { locale: "fr", id: "01DEF...", slug: "mon-article", status: "draft" },// ]관리자에서 번역 관리하기
섹션 제목: “관리자에서 번역 관리하기”콘텐츠 목록
섹션 제목: “콘텐츠 목록”i18n이 활성화되면 콘텐츠 목록에 다음이 표시됩니다:
- 각 항목의 로케일을 표시하는 로케일 열
- 로케일 간 전환을 위한 도구 모음의 로케일 필터
번역 생성하기
섹션 제목: “번역 생성하기”편집기에서 콘텐츠 항목을 엽니다. 사이드바에는 구성된 모든 로케일을 나열하는 번역 패널이 표시됩니다. 각 로케일에 대해:
- 번역이 없는 로케일에는 “번역” 이 나타납니다 — 클릭하여 생성하세요
- 기존 번역이 있는 로케일에는 “편집” 이 나타납니다 — 클릭하여 이동하세요
- 현재 로케일은 체크 표시로 표시됩니다
번역을 생성할 때, 새 항목은 소스 로케일의 데이터로 미리 채워지고 {source-slug}-{locale}의 기본 슬러그가 할당됩니다. 필요에 따라 슬러그와 콘텐츠를 조정한 후 저장하세요.
로케일별 게시
섹션 제목: “로케일별 게시”각 번역은 자체 상태를 가집니다. 번역을 독립적으로 게시, 게시 취소 또는 예약하세요. 프랑스어 버전이 초안 상태인 동안 영어 버전이 라이브 상태일 수 있습니다.
콘텐츠 API
섹션 제목: “콘텐츠 API”로케일 매개변수
섹션 제목: “로케일 매개변수”모든 콘텐츠 API 경로는 선택적 locale 쿼리 매개변수를 허용합니다:
GET /_emdash/api/content/posts?locale=frGET /_emdash/api/content/posts/my-post?locale=fr생략할 경우, 구성된 기본 로케일로 기본 설정됩니다.
API를 통한 번역 생성
섹션 제목: “API를 통한 번역 생성”콘텐츠 생성 엔드포인트에 locale과 translationOf를 전달하여 번역을 생성하세요:
POST /_emdash/api/content/postsContent-Type: application/json
{ "locale": "fr", "translationOf": "01ABC...", "data": { "title": "Mon Article", "slug": "mon-article" }}새 항목은 소스 항목의 translation_group을 공유하며 초안 상태로 시작합니다.
번역 목록 조회
섹션 제목: “번역 목록 조회”주어진 항목에 대한 모든 번역을 검색합니다:
GET /_emdash/api/content/posts/01ABC.../translations번역 그룹 ID와 해당 ID, 슬러그 및 상태를 가진 로케일 변형 배열을 반환합니다.
CLI
섹션 제목: “CLI”CLI는 콘텐츠 명령어에서 --locale 플래그를 지원합니다:
# List French postsemdash content list posts --locale fr
# 프랑스어로 특정 항목 가져오기emdash content get posts my-post --locale fr
# 기존 항목의 프랑스어 번역 생성하기emdash content create posts --locale fr --translation-of 01ABC...다국어 콘텐츠 시딩
섹션 제목: “다국어 콘텐츠 시딩”시드 파일은 locale과 translationOf를 사용하여 번역을 표현합니다:
json title=".emdash/seed.json"{ "content": { "posts": [ { "id": "welcome", "slug": "welcome", "locale": "en", "status": "published", "data": { "title": "환영합니다" } }, { "id": "welcome-fr", "slug": "bienvenue", "locale": "fr", "translationOf": "welcome", "status": "draft", "data": { "title": "Bienvenue" } } ] }}소스 로케일 항목은 translationOf 참조가 올바르게 해결되도록 시드 파일에서 해당 번역들보다 먼저 나타나야 합니다.
필드 번역 가능성
섹션 제목: “필드 번역 가능성”각 필드는 translatable 설정(기본값: true)을 가집니다. 번역을 생성할 때:
- 번역 가능 필드는 편집을 위해 소스 로케일에서 미리 채워집니다
- 번역 불가능 필드는 복사되어 그룹 내 모든 번역에서 동기화 상태로 유지됩니다
status, published_at, author_id와 같은 시스템 필드는 항상 로케일별이며 절대 동기화되지 않습니다.
URL 전략
섹션 제목: “URL 전략”EmDash는 로케일 URL을 관리하지 않습니다 — 라우팅은 Astro가 처리합니다. 일반적인 패턴:
# prefix-other-locales (Astro default)/blog/my-post → en (default locale, no prefix)/fr/blog/mon-article → fr
# prefix-always/en/blog/my-post → en/fr/blog/mon-article → fr라우팅 모드에 관계없이 올바른 URL을 구성하려면 astro:i18n의 getRelativeLocaleUrl을 사용하세요.
다국어 콘텐츠 가져오기
섹션 제목: “다국어 콘텐츠 가져오기”WPML 또는 Polylang과 함께하는 WordPress
섹션 제목: “WPML 또는 Polylang과 함께하는 WordPress”WordPress 플러그인 가져오기 소스는 WPML과 Polylang을 자동으로 감지합니다. 감지되면 가져온 콘텐츠에 로케일 및 번역 그룹 메타데이터가 포함되어 다국어 구조를 보존합니다.
WXR 파일
섹션 제목: “WXR 파일”WXR 내보내기에는 WPML/Polylang 메타데이터가 포함되지 않습니다. 단일 로케일로 가져와 수동으로 번역을 생성하거나, --locale 플래그를 사용하여 모든 가져온 항목에 로케일을 할당하세요:
# Import a French WXR exportemdash import wordpress export-fr.xml --execute --locale fr
# 슬러그를 기준으로 기존 영어 콘텐츠와 매칭emdash import wordpress export-fr.xml --execute --locale fr --translation-of-locale en다음 단계
섹션 제목: “다음 단계”- 콘텐츠 쿼리하기 — 전체 쿼리 API 참조
- 콘텐츠 작업하기 — 관리자 콘텐츠 관리
- Astro i18n 라우팅 — Astro의 라우팅 구성