메인 컨텐츠로 이동
Version: 2.0.0-beta.21 🚧

i18n - 따라해보기

This tutorial will walk you through the basics of the Docusaurus i18n system.

영어로 만든 도큐사우루스 웹 사이트프랑스어 번역을 추가해볼 겁니다.

npx [email protected] website classic 명령으로 새로운 사이트를 초기화합니다(이런 형태 파일 구조가 만들어집니다).

사이트 설정하기

프랑스어 i18n 지원에 필요한 설정을 docusaurus.config.js 파일에 추가합니다.

사이트 설정

사이트 i18n 설정을 참조해 i18n locales 항목을 아래와 같이 설정합니다.

docusaurus.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'fa'],
localeConfigs: {
en: {
htmlLang: 'en-GB',
},
// You can omit a locale (e.g. fr) if you don't need to override the defaults
fa: {
direction: 'rtl',
},
},
},
};

The locale names are used for the translation files' locations, as well as your translated locales' base URL. When building all locales, only the default locale will have its name omitted in the base URL.

Docusaurus uses the locale names to provide sensible defaults: the <html lang="..."> attribute, locale label, calendar format, etc. You can customize these defaults with the localeConfigs.

테마 설정

원하는 로케일을 선택할 수 있도록 navbar item 항목의 type 값을 localeDropdown으로 설정합니다.

docusaurus.config.js
module.exports = {
themeConfig: {
navbar: {
items: [
{
type: 'localeDropdown',
position: 'left',
},
],
},
},
};

사이트 시작하기

선택한 로케일 옵션으로 번역된 사이트를 개발 모드에서 시작합니다.

npm run start -- --locale fr

http://localhost:3000/fr/ 주소로 여러분의 번역된 사이트에 접근할 수 있습니다.

We haven't provided any translation yet, so the site is mostly untranslated.

tip

"다음"이나 "이전" 같은 도큐사우루스 기본 테마에 포함된 표현들은 번역을 제공합니다.

기본 번역이 적절하게 제공될 수 있도록 참여를 부탁드립니다.

caution

Each locale is a distinct standalone single-page application: it is not possible to start the Docusaurus sites in all locales at the same time.

사이트 번역하기

All translation data for the French locale is stored in website/i18n/fr. Each plugin sources its own translated content under the corresponding folder, while the code.json file defines all text labels used in the React code.

note

파일을 복사하고 npm run start -- --locale fr 명령으로 사이트를 다시 시작합니다. 복사한 파일을 편집할 때는 변경된 부분만 반영(Hot-reload)할 수 있습니다.

Translate your React code

For any React code you've written yourself: React pages, React components, etc., you will use the translation APIs.

Locate all text labels in your React code that will be visible to your users, and mark them with the translation APIs. There are two kinds of APIs:

  • The <Translate> component wraps a string as a JSX component;
  • The translate() callback takes a message and returns a string.

Use the one that better fits the context semantically. For example, the <Translate> can be used as React children, while for props that expect a string, the callback can be used.

src/pages/index.js
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"
>
</main>
</Layout>
);
}
info

도큐사우루스는 의도적으로 번역 기능을 매우 작고 가볍게 제공합니다. ICU 메시지 형식의 하위 집합을 사용해 기본 틀을 채우는 방식을 지원합니다.

대부분의 문서 웹 사이트는 일반적으로 정적인 파일로 구성됩니다. 때문에 i18n 고급 기능(plurals, genders 등)을 사용할 필요는 없습니다. 고급 기능을 사용하고 싶다면 react-intl 같은 라이브러리를 사용하세요.

The docusaurus write-translations command will statically analyze all React code files used in your site, extract calls to these APIs, and aggregate them in the code.json file. The translation files will be stored as maps from IDs to translation message objects (including the translated label and the description of the label). In your calls to the translation APIs (<Translate> or translate()), you need to specify either the default untranslated message or the ID, in order for Docusaurus to correctly correlate each translation entry to the API call.

text labels must be static

The docusaurus write-translations command only does static analysis of your code. It doesn't actually run your site. Therefore, dynamic messages can't be extracted, as the message is an expression, not a string:

const items = [
{id: 1, title: 'Hello'},
{id: 2, title: 'World'},
];

function ItemsList() {
return (
<ul>
{/* DON'T DO THIS: doesn't work with the write-translations command */}
{items.map((item) => (
<li key={item.id}>
<Translate>{item.title}</Translate>
</li>
))}
<ul>
);
}

This still behaves correctly at runtime. However, in the future, we may provide a "no-runtime" mechanism, allowing the translations to be directly inlined in the React code through Babel transformations, instead of calling the APIs at runtime. Therefore, to be future-proof, you should always prefer statically analyzable messages. For example, we can refactor the code above to:

const items = [
{id: 1, title: <Translate>Hello</Translate>},
{id: 2, title: <Translate>World</Translate>},
];

function ItemsList() {
return (
<ul>
{/* The titles are now already translated when rendering! */}
{items.map((item) => (
<li key={item.id}>{item.title}</li>
))}
<ul>
);
}

You can see the calls to the translation APIs as purely markers that tell Docusaurus that "here's a text label to be replaced with a translated message".

Pluralization

When you run write-translations, you will notice that some labels are pluralized:

i18n/en/code.json
{
// ...
"theme.blog.post.plurals": "One post|{count} posts"
// ...
}

Every language will have a list of possible plural categories. Docusaurus will arrange them in the order of ["zero", "one", "two", "few", "many", "other"]. For example, because English (en) has two plural forms ("one" and "other"), the translation message has two labels separated by a pipe (|). For Polish (pl) which has three plural forms ("one", "few", and "many"), you would provide three labels in that order, joined by pipes.

You can pluralize your own code's messages as well:

import {translate} from '@docusaurus/Translate';
import {usePluralForm} from '@docusaurus/theme-common';

function ItemsList({items}) {
// `usePluralForm` will provide the plural selector for the current locale
const {selectMessage} = usePluralForm();
// Select the appropriate pluralized label based on `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>
</>
);
}
note

Docusaurus uses Intl.PluralRules to resolve and select plural forms. It is important to provide the right number of plural forms in the right order for selectMessage to work.

Translate plugin data

JSON translation files are used for everything that is interspersed in your code:

  • React code, including the translated labels you have marked above
  • Navbar and footer labels in theme config
  • Docs sidebar category labels in sidebars.js
  • Blog sidebar title in plugin options
  • ...

아래와 같이 write-translations 명령을 실행합니다.

npm run write-translations -- --locale fr

명령이 실행되면 번역이 필요한 항목을 추출해서 JSON 번역 파일을 초기화합니다. The code.json file at the root includes all translation API calls extracted from the source code, which could either be written by you or provided by the themes, some of which may already be translated by default.

i18n/fr/code.json
{
// No ID for the <Translate> component: the default message is used as 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 번역 파일을 가지고 있습니다.

i18n/fr/docusaurus-theme-classic/navbar.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 항목을 번역하면 여러분의 사이트 레이아웃과 홈페이지가 번역되는 것입니다.

마크다운 파일 번역하기

공식적인 도큐사우루스 콘텐츠 플러그인은 다양한 부분에 마크다운/MDX 파일을 사용하며 이를 번역할 수 있습니다.

문서 번역하기

마크다운 파일을 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
info

Notice that the docusaurus-plugin-content-docs plugin always divides its content by versions. The data in ./docs folder will be translated in the current subfolder and current.json file. See the doc versioning guide for more information about what "current" means.

블로그 번역하기

블로그 마크다운 파일을 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/**.md i18n/fr/docusaurus-plugin-content-pages
cp -r src/pages/**.mdx i18n/fr/docusaurus-plugin-content-pages
caution

리액트 페이지는 JSON 번역 파일에서 번역하기 때문에 .md, .mdx 파일만 복사하면 됩니다.

명시적인 제목 id 사용하기

기본적으로 마크다운에서 제목으로 ### Hello World을 설정하면 hello-world로 id가 만들어집니다. 다른 문서에서 링크를 연결할 때는 [link](#hello-world) 형식을 사용합니다. 하지만 번역 후에 제목은 ### Bonjour le Monde이 되고 id는 bonjour-le-monde이 됩니다.

이렇게 만들어지는 id가 번역된 사이트에 항상 적합한 것은 아닙니다. 여러분이 적절한 링크를 직접 수정해주어야 합니다.

- [link](#hello-world).
+ [link](#bonjour-le-monde)

For localized sites, it is recommended to use explicit heading ids.

사이트를 배포합니다.

여러분의 사이트는 하나의 도메인을 사용할 수도 있고 여러(하위) 도메인을 사용할 수도 있습니다.

단일 도메인에 배포하기

아래 명령을 실행합니다.

npm run build

도큐사우루스는 로케일 별로 하나의 단일 페이지 애플리케이션을 만듭니다.

  • website/build: 기본값으로 영어 애플리케이션을 만듭니다.
  • website/build/fr: 프랑스어 애플리케이션을 위한 디렉터리입니다.

여러분은 이제 원하는 호스팅 서비스에 build 디렉터리를 배포할 수 있습니다.

note

도큐사우루스 v2 웹 사이트는 아래와 같은 형태를 사용합니다.

tip

호스팅 서비스에서는 일반적으로 /unknown/url 페이지는 규칙에 따라 /404.html로 리다이렉트합니다. 해당 페이지는 영어로 작성된 404 페이지를 보여줍니다.

/fr/* 하위 디렉터리 페이지는 /fr/404.html로 리다이렉트할 수 있도록 호스팅 서비스를 설정하면 여러분의 언어에 맞는 404 페이지를 처리할 수 있습니다.

모든 호스팅 서비스에서 지원하는 건 아닙니다. 깃허브 페이지는 지원하지 않으며 네트리파이(Netlify)는 지원합니다.

여러 도메인에 배포하기

하나의 로케일만 지원하도록 사이트를 빌드할 수 있습니다.

npm run build -- --locale fr

도큐사우루스에서는 /fr/ URL 접두사를 추가하지 않습니다.

여러분이 이용하는 호스팅 서비스에서 아래와 같은 작업이 필요합니다.

  • 로케일마다 배포 파일을 만듭니다.
  • --locale 옵션을 사용해 적절한 빌드 명령을 설정합니다.
  • 선택한 배포 대상에 따라 (하위) 도메인을 설정해줍니다.
caution

위에서 설명한 방법은 깃허브 페이지에서는 사용할 수 없습니다. 개별적인 배포 방식에 한정된 방법입니다.

혼합 방식

일부는 하위 경로 일부는 하위 도메인을 사용하도록 설정할 수 있습니다.

각 로케일 파일을 별도의 하위 도메인에 배포하고 CDN 수준에서 하나의 통합된 도메인의 하위 도메인으로 조합할 수 있습니다.

  • 사이트를 fr.docusaurus.io에 배포합니다.
  • CDN 설정으로 docusaurus.io/fr에서 서비스가 되도록 합니다.

Managing translations

Docusaurus doesn't care about how you manage your translations: all it needs is that all translation files (JSON, Markdown, or other data files) are available in the file system during building. However, as site creators, you would need to consider how translations are managed so your translation contributors could collaborate well.

We will share two common translation collaboration strategies: using git and using Crowdin.