i18n - 따라해보기
이 튜토리얼에서는 도큐사우루스 i18n 시스템의 기본 개념을 살펴봅니다.
새로 초기화한 영어 도큐사우루스 웹사이트에 프랑스어 번역을 추가하겠습니다.
(이 예제처럼) 새 사이트를 초기화하세요:
- npm
- Yarn
- pnpm
- Bun
npx create-docusaurus@latest website classic
yarn dlx create-docusaurus@latest website classic
pnpm dlx create-docusaurus@latest website classic
bun x create-docusaurus@latest website classic
사이트 설정하기
docusaurus.config.js를 수정하여 프랑스어 i18n 지원을 추가하세요.
사이트 설정
사이트 i18n 설정에서 i18n 로케일을 선언하세요:
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'fa'],
localeConfigs: {
en: {
htmlLang: 'en-GB',
},
// 기본값을 재정의할 필요가 없다면 로케일(예: fr)을 생략할 수 있습니다
fa: {
direction: 'rtl',
},
},
},
};
로케일 이름은 번역된 파일 위치와 번역된 로케일 base URL에 사용됩니다. 모든 로케일 빌드 시 기본 로케일만 base URL에서 이름이 생략됩니다.
도큐사우루스는 로케일 이름을 사용해 \<html lang="..."> 속성, 로케일 레이블, 달력 형식 등에 합리적인 기본값을 제공합니다. localeConfigs로 이 기본값을 변경할 수 있습니다.
테마 설정
사용자가 원하는 로케일을 선택할 수 있도록 localeDropdown 유형의 내비게이션 바 항목을 추가하세요:
export default {
themeConfig: {
navbar: {
items: [
{
type: 'localeDropdown',
position: 'left',
},
],
},
},
};
사용자가 드롭다운으로 로케일을 변경할 때 URL에 추가할 쿼리 매개변수를 전달할 수 있습니다(예: queryString: '?persistLocale=true').
이는 서버에서 로케일 자동 감지 기능을 구현할 때 유용합니다. 예를 들어 이 매개변수를 사용해 사용자가 선호하는 로케일을 쿠키에 저장할 수 있습니다.
사이트 시작하기
원하는 로케일로 현지화된 사이트를 개발 모드에서 시작하세요:
- npm
- Yarn
- pnpm
- Bun
npm run start -- --locale fr
yarn run start --locale fr
pnpm run start --locale fr
bun run start --locale fr
사이트는 http://localhost:3000/fr/에서 확인할 수 있습니다.
아직 번역을 제공하지 않았으므로 사이트는 대부분 번역되지 않은 상태입니다.
도큐사우루스는 페이지 탐색의 "다음"과 "이전" 같은 일반적인 테마 레이블에 기본 번역을 제공합니다.
이 **기본 번역**을 완성하는 데 도움을 주세요.
각 로케일은 서로 독립된 별도의 단일 페이지 애플리케이션입니다. 모든 로케일의 도큐사우루스 사이트를 동시에 시작할 수는 없습니다.
사이트 번역하기
프랑스어 로케일의 모든 번역 데이터는 website/i18n/fr에 저장됩니다. 각 플러그인은 해당 폴더에서 자체 번역 콘텐츠를 가져오며, code.json 파일은 리액트 코드에 사용되는 모든 텍스트 레이블을 정의합니다.
파일을 복사한 후 npm run start -- --locale fr 명령으로 사이트를 다시 시작하세요. 기존 파일을 편집할 때는 핫 리로드가 더 잘 동작합니다.
리액트 코드 번역하기
리액트 페이지, 리액트 컴포넌트 등 직접 작성한 리액트 코드는 번역 API를 사용해 번역합니다.
리액트 코드에서 사용자에게 표시되는 모든 텍스트 레이블을 찾아 번역 API로 표시하세요. API에는 두 가지 종류가 있습니다:
\<Translate>컴포넌트는 문자열을 JSX 요소로 감쌉니다;translate()콜백은 메시지를 받아 문자열을 반환합니다.
파일을 복사하고 npm run start -- --locale fr 명령으로 사이트를 다시 시작합니다. 예를 들어 \<Translate>는 리액트의 자식 요소로 사용할 수 있고, 문자열이 필요한 props에는 콜백을 사용할 수 있습니다.
JSX 요소는 문자열이 아닌 _객체_입니다. 문자열이 필요한 곳(\<option>의 자식 등)에 JSX 요소를 사용하면 문자열로 강제 변환되어 "[object Object]"가 반환됩니다. \<Translate>를 JSX 자식 요소로 사용하는 것을 권장하지만, 요소 형식이 실제로 동작하는 경우에만 사용하세요.
- Before
- After
import React from 'react';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
export default function Home() {
return (
<Layout>
<h1>Welcome to my website</h1>
<main>
You can also visit my
<Link to="https://docusaurus.io/blog">blog</Link>
<img
src="/img/home.png"
alt="Home icon"
/>
</main>
</Layout>
);
}
import React from 'react';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import Translate, {translate} from '@docusaurus/Translate';
export default function Home() {
return (
<Layout>
<h1>
<Translate>Welcome to my website</Translate>
</h1>
<main>
<Translate
id="homepage.visitMyBlog"
description="The homepage message to ask the user to visit my blog"
values={{
blogLink: (
<Link to="https://docusaurus.io/blog">
<Translate
id="homepage.visitMyBlog.linkLabel"
description="The label for the link to my blog">
blog
</Translate>
</Link>
),
}}>
{'You can also visit my {blogLink}'}
</Translate>
<img
src="/img/home.png"
alt={
translate({
message: 'Home icon',
description: 'The homepage icon alt message',
})
}
/>
</main>
</Layout>
);
}
도큐사우루스는 의도적으로 매우 작고 가벼운 번역 런타임을 제공하며, ICU 메시지 형식의 일부를 사용한 기본적인 자리표시자 보간만 지원합니다.
대부분의 문서 웹사이트는 일반적으로 정적이므로 고급 i18n 기능(복수형, 성별 등)이 필요하지 않습니다. 더 복잡한 기능이 필요하다면 react-intl 같은 라이브러리를 사용하세요.
docusaurus write-translations 명령은 사이트에 사용된 모든 리액트 코드 파일을 정적으로 분석하여 번역 API 호출을 추출하고 code.json 파일에 모읍니다. 번역 파일은 ID를 번역 메시지 객체(번역된 레이블과 레이블 설명 포함)에 연결하는 맵으로 저장됩니다. 도큐사우루스가 각 번역 항목을 해당 API 호출과 올바르게 연결할 수 있도록, 번역 API(\<Translate> 또는 translate())를 호출할 때 기본 미번역 메시지나 ID를 지정해야 합니다.
docusaurus write-translations 명령은 코드의 정적 분석만 수행합니다. 고급 기능을 사용하고 싶다면 react-intl 같은 라이브러리를 사용하세요. 따라서 메시지가 _문자열_이 아닌 _표현식_인 동적 메시지는 추출할 수 없습니다:
const items = [
{id: 1, title: 'Hello'},
{id: 2, title: 'World'},
];
function ItemsList() {
return (
<ul>
{/* 이렇게 하지 마세요: write-translations 명령으로 처리할 수 없습니다 */}
{items.map((item) => (
<li key={item.id}>
<Translate>{item.title}</Translate>
</li>
))}
<ul>
);
}
이 코드는 런타임에서는 여전히 올바르게 동작합니다. 하지만 향후에는 런타임에 API를 호출하는 대신 Babel 변환을 통해 번역을 리액트 코드에 직접 인라인으로 삽입하는 "런타임 없는" 방식을 제공할 수도 있습니다. 따라서 향후 변경에도 대응하려면 항상 정적으로 분석할 수 있는 메시지를 사용하는 것이 좋습니다. 예를 들어 위 코드를 다음과 같이 리팩터링할 수 있습니다:
const items = [
{id: 1, title: <Translate>Hello</Translate>},
{id: 2, title: <Translate>World</Translate>},
];
function ItemsList() {
return (
<ul>
{/* 이제 렌더링할 때 제목이 이미 번역되어 있습니다! */}
{items.map((item) => (
<li key={item.id}>{item.title}</li>
))}
<ul>
);
}
번역 API 호출은 도큐사우루스에 "번역된 메시지로 대체할 텍스트 레이블이 여기 있다"고 알려 주는 _표시_라고 생각하면 됩니다.
복수화
write-translations를 실행하면 일부 레이블에 복수형이 사용된 것을 볼 수 있습니다:
{
// ...
"theme.blog.post.plurals": "One post|{count} posts"
// ...
}
각 언어에는 사용할 수 있는 복수형 범주가 있습니다. 도큐사우루스는 이를 ["zero", "one", "two", "few", "many", "other"] 순서로 배치합니다. 예를 들어 영어(en)에는 두 가지 복수형 범주("one"과 "other")가 있으므로 번역 메시지에는 파이프(|)로 구분된 두 개의 레이블이 들어갑니다. 복수형 범주가 세 가지("one", "few", "many")인 폴란드어(pl)에서는 이 순서대로 세 개의 레이블을 파이프로 연결해 제공해야 합니다.
번역 API에 대한 호출은 도큐사우루스에 "번역된 메시지로 대체할 텍스트 라벨이 있다"고 알려주는 마커 역할만 하게 됩니다.
import {translate} from '@docusaurus/Translate';
import {usePluralForm} from '@docusaurus/theme-common';
function ItemsList({items}) {
// `usePluralForm`은 현재 로케일의 복수형 선택기를 제공합니다
const {selectMessage} = usePluralForm();
// `items.length`에 따라 적절한 복수형 레이블을 선택합니다
const message = selectMessage(
items.length,
translate(
{message: 'One item|{count} items'},
{count: items.length},
),
);
return (
<>
<h2>{message}</h2>
<ul>{items.map((item) => <li key={item.id}>{item.title}</li>)}<ul>
</>
);
}
도큐사우루스는 Intl.PluralRules를 사용해 복수형을 판별하고 선택합니다. selectMessage가 동작하려면 올바른 개수의 복수형을 올바른 순서로 제공해야 합니다.
플러그인 데이터 번역하기
여러분의 코드 메시지를 복수화할 수도 있습니다.
- 위에서 처리한 번역된 라벨을 포함한 리액트 코드
- 테마 설정 내에 메뉴바와 푸터 라벨
sidebars.js의 문서 사이드바 카테고리 레이블- 플러그인 옵션의 블로그 사이드바 제목
- ...
write-translations 명령을 실행하세요:
- npm
- Yarn
- pnpm
- Bun
npm run write-translations -- --locale fr
yarn write-translations --locale fr
pnpm run write-translations --locale fr
bun run write-translations --locale fr
도큐사우루스는 복수형을 확인하고 선택하기 위해 Intl.PluralRules를 사용합니다. 루트의 code.json 파일에는 소스 코드에서 추출한 모든 번역 API 호출이 포함됩니다. 직접 작성한 호출뿐 아니라 테마에서 제공하는 호출도 포함되며, 일부는 기본적으로 이미 번역되어 있을 수 있습니다.
{
// <Translate> 컴포넌트에 ID가 없으면 기본 메시지가 ID로 사용됩니다
"Welcome to my website": {
"message": "Welcome to my website"
},
"home.visitMyBlog": {
"message": "You can also visit my {blog}",
"description": "The homepage message to ask the user to visit my blog"
},
"homepage.visitMyBlog.linkLabel": {
"message": "Blog",
"description": "The label for the link to my blog"
},
"Home icon": {
"message": "Home icon",
"description": "The homepage icon alt message"
}
}
플러그인과 테마도 다음과 같이 자체 JSON 번역 파일을 작성합니다:
{
"title": {
"message": "My Site",
"description": "The title in the navbar"
},
"item.label.Docs": {
"message": "Docs",
"description": "Navbar item with label Docs"
},
"item.label.Blog": {
"message": "Blog",
"description": "Navbar item with label Blog"
},
"item.label.GitHub": {
"message": "GitHub",
"description": "Navbar item with label GitHub"
}
}
i18n/fr의 JSON 파일에서 message 속성을 번역하면 사이트 레이아웃과 홈페이지가 번역됩니다.
마크다운 파일 번역하기
아래와 같이 write-translations 명령을 실행합니다.
문서 번역하기
docs/의 마크다운 문서 파일을 i18n/fr/docusaurus-plugin-content-docs/current로 복사한 후 번역하세요:
mkdir -p i18n/fr/docusaurus-plugin-content-docs/current
cp -r docs/. i18n/fr/docusaurus-plugin-content-docs/current
docusaurus-plugin-content-docs 플러그인은 항상 콘텐츠를 버전별로 나눈다는 점에 유의하세요. ./docs 폴더의 데이터는 current 하위 폴더와 current.json 파일에 번역됩니다. "current"의 의미에 대한 자세한 내용은 문서 버전 관리 가이드를 참고하세요.
블로그 번역하기
블로그 마크다운 파일을 i18n/fr/docusaurus-plugin-content-blog로 복사한 후 번역하세요:
mkdir -p i18n/fr/docusaurus-plugin-content-blog
cp -r blog/. i18n/fr/docusaurus-plugin-content-blog
페이지 번역하기
페이지 마크다운 파일을 i18n/fr/docusaurus-plugin-content-pages로 복사한 후 번역하세요:
mkdir -p i18n/fr/docusaurus-plugin-content-pages
cp -r src/pages/. i18n/fr/docusaurus-plugin-content-pages
리액트 페이지는 이미 JSON 번역 파일을 통해 번역되므로 .md와 .mdx 파일만 복사합니다.
기본적으로 마크다운 제목 ### Hello World에는 hello-world라는 ID가 생성됩니다. 다른 문서에서 [link](#hello-world)로 이 제목에 링크할 수 있습니다. 하지만 번역 후 제목이 ### Bonjour le Monde로 바뀌면 ID도 bonjour-le-monde가 됩니다.
리액트 페이지는 JSON 번역 파일에서 번역하기 때문에 .md, .mdx 파일만 복사하면 됩니다.
- [link](#hello-world).
+ [link](#bonjour-le-monde)
현지화된 사이트에서는 **명시적 제목 ID**를 사용하는 것이 좋습니다.
사이트를 배포합니다.
사이트를 단일 도메인에 배포하거나 여러 (하위) 도메인을 사용할 수 있습니다.
도큐사우루스는 기본 로케일을 제외한 각 로케일에 대해 사이트 경로에 /\<locale>/ 구간을 자동으로 추가합니다. 이 방식은 대부분의 사이트에서 잘 동작하지만, 배포 요구사항에 따라 로케일별로 설정할 수도 있습니다.
자세한 내용은 siteConfig.baseUrl 문서를 참고하세요.
단일 도메인에 배포하기
이렇게 만들어지는 ID가 번역된 사이트에 항상 적합한 것은 아닙니다. 여러분이 적절한 링크를 직접 수정해주어야 합니다.
- npm
- Yarn
- pnpm
- Bun
npm run build
yarn build
pnpm run build
bun run build
도큐사우루스는 로케일마다 하나의 단일 페이지 애플리케이션을 빌드합니다:
website/build: 기본 언어인 영어용website/build/fr: 프랑스어용
이제 build 폴더를 원하는 정적 호스팅 서비스에 배포할 수 있습니다.
도큐사우루스 웹사이트는 이 방식을 사용합니다:
정적 호스팅 서비스는 일반적으로 관례에 따라 /unknown/url을 /404.html로 리디렉션하므로 항상 영어 404 페이지가 표시됩니다.
호스트가 /fr/*를 /fr/404.html로 리디렉션하도록 설정하여 404 페이지를 현지화하세요.
이 설정의 지원 여부는 호스트에 따라 다릅니다. GitHub Pages는 지원하지 않지만 Netlify는 지원합니다.
여러 도메인에 배포하기
호스팅 서비스에서는 일반적으로 /unknown/url 페이지는 규칙에 따라 /404.html로 리다이렉트합니다. 해당 페이지는 영어로 작성된 404 페이지를 보여줍니다.
- npm
- Yarn
- pnpm
- Bun
npm run build -- --locale fr
yarn build --locale fr
pnpm run build --locale fr
bun run build --locale fr
로케일을 하나씩 빌드할 때는 각 로케일을 별도 도메인에 배포하려는 것으로 간주하므로 도큐사우루스가 /fr/ URL 접두사를 자동으로 추가하지 않습니다.
정적 호스팅 서비스에서:
- 로케일마다 배포 파일을 만듭니다.
--locale옵션을 사용해 적절한 빌드 명령을 설정합니다- 선택한 배포 대상에 따라 (하위) 도메인을 설정해줍니다.
siteConfig.i18n.localeConfigs[\<locale>].url 속성으로 각 로케일에 서로 다른 사이트 URL을 설정하세요:
const config = {
i18n: {
localeConfigs: {
en: {
url: 'https://en.docusaurus.io',
baseUrl: '/',
},
fr: {
url: 'https://fr.docusaurus.io',
baseUrl: '/',
},
},
},
};
\<link rel="alternate" hreflang="\<locale>"/> 메타 태그 덕분에 Google 같은 검색 엔진이 페이지의 현지화된 버전을 파악하는 데 도움이 됩니다.
또한 사용자가 보통 내비게이션 바의 로케일 드롭다운으로 로케일을 전환할 때 도큐사우루스 테마가 적절한 URL로 리디렉션할 수 있게 합니다.
자세한 내용은 siteConfig.url과 siteConfig.baseUrl 문서를 참고하세요.
GitHub Pages에서는 배포를 하나만 만들 수 있으므로 이 방식을 사용할 수 없습니다.
혼합 방식
여러분이 이용하는 호스팅 서비스에서 아래와 같은 작업이 필요합니다.
각 로케일을 별도의 하위 도메인에 배포한 다음 CDN 계층에서 하위 도메인을 하나의 통합 도메인으로 합칠 수도 있습니다:
- 사이트를
fr.docusaurus.io로 배포합니다 docusaurus.io/fr에서 제공되도록 CDN을 설정합니다
번역 관리
도큐사우루스는 번역 관리 방식에 관여하지 않습니다. 빌드 시 모든 번역 파일(JSON, 마크다운 또는 기타 데이터 파일)이 파일 시스템에 있으면 됩니다. 하지만 사이트 제작자는 번역 기여자들이 원활하게 협업할 수 있도록 번역을 관리하는 방식을 고려해야 합니다.
일반적인 번역 협업 방식 두 가지인 git 사용하기와 Crowdin 사용하기를 소개하겠습니다.