본문으로 건너뛰기
버전: 3.0.0-rc.1

i18n - 크라우드인 사용하기

The i18n system of Docusaurus is decoupled from any translation software.

You can integrate Docusaurus with the tools and SaaS of your choice, as long as you put the translation files at the correct location.

We document the usage of Crowdin, as one possible integration example.

warning

This is not an endorsement of Crowdin as the unique choice to translate a Docusaurus site, but it is successfully used by Facebook to translate documentation projects such as Jest, Docusaurus, and ReasonML.

Refer to the Crowdin documentation and Crowdin support for help.

Use this community-driven GitHub discussion to discuss anything related to Docusaurus + Crowdin.

Crowdin overview

Crowdin is a translation SaaS, offering a free plan for open-source projects.

아래와 같은 순서로 번역을 진행하는 것을 권장합니다.

  • Upload sources to Crowdin (untranslated files)
  • Use Crowdin to translate the content
  • Download translations from Crowdin (localized translation files)

Crowdin provides a CLI to upload sources and download translations, allowing you to automate the translation process.

The crowdin.yml configuration file is convenient for Docusaurus, and permits to download the localized translation files at the expected location (in i18n/[locale]/..).

Read the official documentation to know more about advanced features and different translation workflows.

Crowdin tutorial

This is a walk-through of using Crowdin to translate a newly initialized English Docusaurus website into French, and assume you already followed the i18n tutorial.

The end result can be seen at docusaurus-crowdin-example.netlify.app (repository).

Prepare the Docusaurus site

새로운 도큐사우루스 사이트를 초기화합니다.

npx create-docusaurus@latest website classic

프랑스어 번역을 위해 site 설정을 아래와 같이 추가합니다.

docusaurus.config.js
export default {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
themeConfig: {
navbar: {
items: [
// ...
{
type: 'localeDropdown',
position: 'left',
},
// ...
],
},
},
// ...
};

홈페이지를 번역합니다.

src/pages/index.js
import React from 'react';
import Translate from '@docusaurus/Translate';
import Layout from '@theme/Layout';

export default function Home() {
return (
<Layout>
<h1 style={{margin: 20}}>
<Translate description="The homepage main heading">
Welcome to my Docusaurus translated site!
</Translate>
</h1>
</Layout>
);
}

Create a Crowdin project

Sign up on Crowdin, and create a project.

소스 언어로 영어를 설정하고 대상 언어로 프랑스어를 설정합니다.

Create a Crowdin project with english as source language, and french as target language

프로젝트가 만들어졌지만 아직은 아무것도 없습니다. 다음 단계에서 번역할 파일을 업로드할 겁니다.

Create the Crowdin configuration

This configuration (doc) provides a mapping for the Crowdin CLI to understand:

  • 업로드할 소스 파일(JSON, 마크다운)을 어디서 찾아야 하는지
  • Where to download the files after translation (in i18n/[locale])

Create crowdin.yml in website:

crowdin.yml
project_id: '123456'
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
files:
# JSON 번역 파일
- source: /i18n/en/**/*
translation: /i18n/%two_letters_code%/**/%original_file_name%
# 문서 마크다운 파일
- source: /docs/**/*
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
# 블로그 마크다운 파일
- source: /blog/**/*
translation: /i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%

크라우드인은 소스/번역 파일의 경로를 설정하는 자체 구문을 가지고 있습니다.

  • **/*: everything in a subfolder
  • %two_letters_code%: the 2-letters variant of Crowdin target languages (fr in our case)
  • **/%original_file_name%: the translations will preserve the original folder/file hierarchy
정보

크라우드인 명령행 도구에서 보여지는 경고 메시지 일부는 이해하기 어려울 수 있습니다.

그래서 아래와 같이 작업할 것을 권장합니다.

  • 한 번에 하나 씩만 변경하기
  • 설정을 변경했다면 소스를 다시 업로드하기
  • use paths starting with / (./ does not work)
  • avoid fancy globbing patterns like /docs/**/*.(md|mdx) (does not work)

Access token

The api_token_env attribute defines the env variable name read by the Crowdin CLI.

You can obtain a Personal Access Token on your personal profile page.

You can keep the default value CROWDIN_PERSONAL_TOKEN, and set this environment variable and on your computer and on the CI server to the generated access token.

warning

A Personal Access Tokens grant read-write access to all your Crowdin projects.

You should not commit it, and it may be a good idea to create a dedicated Crowdin profile for your company instead of using a personal account.

Other configuration fields

  • project_id: can be hardcoded, and is found on https://crowdin.com/project/<MY_PROJECT_NAME>/settings#api
  • preserve_hierarchy: preserve the folder's hierarchy of your docs on Crowdin UI instead of flattening everything

Install the Crowdin CLI

This tutorial uses the CLI version 3.5.2, but we expect 3.x releases to keep working.

여러분의 도큐사우루스 사이트에 npm 패키지로 크라우드인 명령행 도구를 설치합니다.

npm install @crowdin/cli@3

Add a crowdin script:

package.json
{
"scripts": {
// ...
"write-translations": "docusaurus write-translations",
"crowdin": "crowdin"
}
}

크라우드인 명령행 도구가 정상적으로 설치됐는지 확인합니다.

npm run crowdin -- --version

Set the CROWDIN_PERSONAL_TOKEN env variable on your computer, to allow the CLI to authenticate with the Crowdin API.

Temporarily, you can hardcode your personal token in crowdin.yml with api_token: 'MY-TOKEN'.

Upload the sources

Generate the JSON translation files for the default language in website/i18n/en:

npm run write-translations

JSON, 마크다운 번역 파일을 업로드합니다.

npm run crowdin upload

Crowdin CLI uploading Docusaurus source files

Your source files are now visible on the Crowdin interface: https://crowdin.com/project/<MY_PROJECT_NAME>/settings#files

Crowdin UI showing Docusaurus source files

Translate the sources

On https://crowdin.com/project/<MY_PROJECT_NAME>, click on the French target language.

Crowdin UI showing French translation files

마크다운 파일을 번역합니다.

Crowdin UI to translate a Markdown file

Use Hide String to make sure translators don't translate things that should not be:

  • Front matter: id, slug, tags ...
  • Admonitions: :::, :::note, :::tip ...

Crowdin UI hide string

JSON 파일을 번역합니다.

Crowdin UI to translate a JSON file

정보

The description attribute of JSON translation files is visible on Crowdin to help translate the strings.

Pre-translate your site, and fix pre-translation mistakes manually (enable the Global Translation Memory in settings first).

Use the Hide String feature first, as Crowdin is pre-translating things too optimistically.

Download the translations

번역한 JSON, 마크다운 파일을 크라우드인 명령행 도구를 사용해 내려받습니다.

npm run crowdin download

The translated content should be downloaded in i18n/fr.

이제 프랑스어 사이트를 시작해봅니다.

npm run start -- --locale fr

Make sure that your website is now translated in French at http://localhost:3000/fr/.

Automate with CI

We will configure the CI to download the Crowdin translations at build time and keep them outside of Git.

Add website/i18n to .gitignore.

Set the CROWDIN_PERSONAL_TOKEN env variable on your CI.

Create an npm script to sync Crowdin (extract sources, upload sources, download translations):

package.json
{
"scripts": {
"crowdin:sync": "docusaurus write-translations && crowdin upload && crowdin download"
}
}

Call the npm run crowdin:sync script in your CI, just before building the Docusaurus site.

Keep your deploy-previews fast: don't download translations, and use npm run build -- --locale en for feature branches.

warning

크라우드인은 동시에 여러 버전을 업로드하거나 내려받는 것을 지원하지 않습니다. 번역은 운영 배포에만 포함하고 배포 미리보기는 번역하지 않는 상태로 유지하는 것을 권장합니다.

Advanced Crowdin topics

MDX

warning

MDX 문서를 다룰 때는 문서 내 JSX 조각을 주의해주세요.

Crowdin does not support officially MDX, but they added support for the .mdx extension, and interpret such files as Markdown (instead of plain text).

MDX problems

크라우드인에서 JSX 구문을 HTML으로 인식해서 번역 파일을 내려받을 때 JSX 마크업이 훼손될 수 있습니다. 이로 인해 잘못된 JSX 구문으로 빌드 실패의 원인이 됩니다.

Simple JSX fragments using simple string props like <Username name="Sebastien"/> will work fine; more complex JSX fragments using object/array props like <User person={{name: "Sebastien"}}/> are more likely to fail due to a syntax that does not look like HTML.

MDX solutions

복잡한 JSX 코드는 별도로 독립적인 컴포넌트로 추출하는 것을 권장합니다. We also added an mdx-code-block escape hatch syntax:

# How to deploy Docusaurus

To deploy Docusaurus, run the following command:

````mdx-code-block 

import Tabs from '@theme/Tabs';

import TabItem from '@theme/TabItem';

<Tabs>
<TabItem value="bash" label="Bash">

```bash
GIT_USER=<GITHUB_USERNAME> yarn deploy
```

</TabItem>
<TabItem value="windows" label="Windows">

```batch
cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy"
```

</TabItem>
</Tabs>
````

이렇게 하면

  • 크라우드인에서는 코드 블럭으로 처리합니다(파일을 내려받을 때 마크업 코드를 훼손하지 않습니다).
  • 도큐사우루스에서는 일반적인 JSX 코드로 처리합니다(다른 코드 블럭과 다르게).
  • 아쉽지만 MDX 도구(IDE 구문 강조, 코드 정렬 같은)는 적용할 수 없습니다.

Docs versioning

Configure translation files for the website/versioned_docs folder.

When creating a new version, the source strings will generally be quite similar to the current version (website/docs), and you don't want to translate the new version docs again and again.

Crowdin provides a Duplicate Strings setting.

Crowdin Duplicate Strings option setting

We recommend using Hide, but the ideal setting depends on how much your versions are different.

warning

Not using Hide leads to a much larger amount of source strings in quotas, and will affect the pricing.

Multi-instance plugins

각 플러그인 인스턴스에 대한 번역 작업이 필요할 수 있습니다.

If you have a docs plugin instance with id=ios, you will need to configure those source files as well

  • website/ios
  • website/ios_versioned_docs (if versioned)

Maintaining your site

Sometimes, you will remove or rename a source file on Git, and Crowdin will display CLI warnings:

Crowdin CLI: download translation warning

When your sources are refactored, you should use the Crowdin UI to update your Crowdin files manually:

Crowdin UI: renaming a file

VCS (Git) integrations

Crowdin has multiple VCS integrations for GitHub, GitLab, Bitbucket.

TL;DR

하지만 이렇게 사용하는 건 권장하지 않습니다.

It could have been helpful to be able to edit the translations in both Git and Crowdin, and have a bi-directional sync between the 2 systems.

In practice, it didn't work very reliably for a few reasons:

  • The Crowdin -> Git sync works fine (with a pull request)
  • The Git -> Crowdin sync is manual (you have to press a button)
  • 크라우드인에서 기존 마크다운 번역을 마크다운 소스와 연결하기 위해 사용하는 접근법은 100% 신뢰할 수는 없습니다. 깃과 동기화 작업 후에 크라우드인 UI에서 결과를 직접 검토해주어야 합니다.
  • 2명의 번역자가 깃과 크라우드인에서 동시에 작업하는 경우에는 번역 작업 간 충돌이 생길 수 있습니다.
  • It requires the crowdin.yml file to be at the root of the repository

In-Context localization

Crowdin has an In-Context localization feature.

warning

아쉽게도 기술적인 이유로 잘 동작하지 않습니다. 나중에라도 문제가 해결되기를 바랍니다.

Crowdin replaces Markdown strings with technical IDs such as crowdin:id12345, but it does so too aggressively, including hidden strings, and messes up with front matter, admonitions, JSX...

Localize edit URLs

When the user is browsing a page at /fr/doc1, the edit button will link by default to the unlocalized doc at website/docs/doc1.md.

You may prefer the edit button to link to the Crowdin interface instead by using the editUrl function to customize the edit URLs on a per-locale basis.

docusaurus.config.js
const DefaultLocale = 'en';

export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
editUrl: ({locale, versionDocsDirPath, docPath}) => {
// Link to Crowdin for French docs
if (locale !== DefaultLocale) {
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
}
// Link to GitHub for English docs
return `https://github.com/facebook/docusaurus/edit/main/website/${versionDocsDirPath}/${docPath}`;
},
},
blog: {
editUrl: ({locale, blogDirPath, blogPath}) => {
if (locale !== DefaultLocale) {
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
}
return `https://github.com/facebook/docusaurus/edit/main/website/${blogDirPath}/${blogPath}`;
},
},
},
],
],
};
노트

It is currently not possible to link to a specific file in Crowdin.

Example configuration

The Docusaurus configuration file is a good example of using versioning and multi-instance:

crowdin.yml
project_id: '428890'
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
languages_mapping: &languages_mapping
two_letters_code:
pt-BR: pt-BR
files:
- source: /website/i18n/en/**/*
translation: /website/i18n/%two_letters_code%/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/docs/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/community/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs-community/current/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/versioned_docs/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-docs/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/blog/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%
languages_mapping: *languages_mapping
- source: /website/src/pages/**/*
translation: /website/i18n/%two_letters_code%/docusaurus-plugin-content-pages/**/%original_file_name%
ignore: [/**/*.js, /**/*.jsx, /**/*.ts, /**/*.tsx, /**/*.css]
languages_mapping: *languages_mapping