i18n - Usando Crowdin
O sistema i18n do Docusaurus é desacoplado de qualquer software de tradução.
Você pode integrar o Docusaurus com as ferramentas e SaaS de sua escolha, contanto que coloque os arquivos de tradução no local correto.
Nós documentamos o uso de Crowdin, como um possível exemplo de integração.
caution
Isso é não é um endosso de Crowdin como a escolha única para traduzir um site Docusaurus, mas é usado com sucesso pelo Facebook para traduzir projetos de documentação como Jest, Docusaurus e ReasonML.
Consulte a documentação do Crowdin e suporte do Crowdin para obter ajuda.
tip
Use esta questão do GitHub conduzida pela comunidade para discutir qualquer coisa relacionada ao Docusaurus + Crowdin.
Visão geral do Crowdin#
Crowdin é uma tradução SaaS, oferecendo um plano gratuito para projetos de código aberto.
Recomendamos o seguinte fluxo de trabalho de tradução:
- Carregar arquivos fontes para Crowdin (arquivos não traduzidos)
 - Use o Crowdin para traduzir o conteúdo
 - Baixar traduções do Crowdin (arquivos de tradução localizados)
 
Crowdin fornece uma CLI para carregar fontes e baixar traduções, permitindo que você automatize o processo de tradução.
O crowdin.yml arquivo de configuração é conveniente para o Docusaurus, e permite baixar os arquivos de tradução localizados no local esperado (em i18n/<locale>/.).
Leia a documentação oficial para saber mais sobre recursos avançados e diferentes fluxos de trabalho de tradução.
Tutorial do Crowdin#
Esse é um passo em frente no uso do Crowdin para traduzir um recém-iniciado site Docusaurus Inglês para o Francês, e assuma que você já seguiu o tutorial i18n.
O resultado final pode ser visto no docusaurus-crowdin-example.netlify.app (repositório).
Preparar o site do Docusaurus#
Inicializar um novo site do Docusaurus:
npx @docusaurus/init@latest init website classicAdicione a configuração do site para o idioma francês:
module.exports = {  i18n: {    defaultLocale: 'en',    locales: ['en', 'fr'],  },  themeConfig: {    navbar: {      items: [        // ...        {          type: 'localeDropdown',          position: 'left',        },        // ...      ],    },  },  // ...};Traduzir a página inicial:
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>  );}Crie um projeto Crowdin#
Faça uma conta em Crowdin e crie um projeto.
Use o inglês como idioma de origem e o francês como idioma alvo.

Seu projeto foi criado, mas está vazio por enquanto. Enviaremos o upload dos arquivos para traduzir nos próximos passos.
Crie a configuração Crowdin#
Esta configuração (doc) fornece um mapeamento para a CLI Crowdin entender:
- Onde encontrar os arquivos de origem a serem carregados (JSON e Markdown)
 - Onde baixar os arquivos após a tradução (em 
i18n/<locale>) 
Criar crowdin.yml no site:
project_id: '123456'api_token_env: 'CROWDIN_PERSONAL_TOKEN'preserve_hierarchy: truefiles: [    # JSON translation files    {      source: '/i18n/en/**/*',      translation: '/i18n/%two_letters_code%/**/%original_file_name%',    },    # Docs Markdown files    {      source: '/docs/**/*',      translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-docs/current/**/%original_file_name%',    },    # Blog Markdown files    {      source: '/blog/**/*',      translation: '/i18n/%two_letters_code%/docusaurus-plugin-content-blog/**/%original_file_name%',    },  ]Crowdin tem sua própria sintaxe para declarar caminhos de origem/tradução:
**/*: tudo em uma subpasta%two_letters_code%: a variante de 2 letras dos idiomas de destino do Crowdin (frno nosso caso)**/%original_file_name%: as traduções irão preservar a pasta/hierarquia de arquivos original
info
Os avisos Crowdin CLI nem sempre são fáceis de entender.
Aconselhamos a:
- alterar uma coisa de cada vez
 - re-enviar fontes após qualquer alteração de configuração
 - usar caminhos que começam com 
/(./não funciona) - evitar padrões de globalização extravagantes como 
/docs/**/*.(md|mdx)(não funciona) 
Token de acesso#
O atributo api_token_env define o nome da variável env lido pelo Crowdin CLI.
Você pode obter um Token de Acesso Pessoal em página de seu perfil pessoal.
tip
Você pode manter o valor padrão CROWDIN_PERSONAL_TOKEN, e definir esta variável de ambiente e no seu computador e no servidor CI para o token de acesso gerado.
caution
Um Token de acesso pessoal concede acesso de leitura e escrita a todos os seus projetos no Crowdin.
Você não deve fazer commitar isso, e pode ser uma boa ideia criar um dedicado perfil Crowdin para a sua empresa em vez de usar uma conta pessoal.
Outros campos de conifuração#
project_id: pode ser codificado e é encontrado emhttps://crowdin.com/project/<MY_PROJECT_NAME>/settings#apipreserve_hierarchy: preservar a hierarquia da pasta de sua documentação na interface do Crowdin em vez de nivelar tudo
Instalar o Crowdin CLI#
Este tutorial usa a CLI na versão 3.5.2, mas esperamos que as versões 3.x continuem funcionando.
Instale o Crowdin CLI como um pacote NPM no seu site Docusaurus:
- npm
 - Yarn
 
npm install @crowdin/cli@3yarn add @crowdin/cli@3Adicione um script do Crowdin:
{  "scripts": {    "crowdin": "crowdin"  }}Teste se você pode executar o Crowdin CLI:
- npm
 - Yarn
 
npm run crowdin -- --versionyarn run crowdin -- --versionDefina a variável env CROWDIN_PERSONAL_TOKEN no seu computador, para permitir que o CLI se autentique com a API Crowdin.
tip
Temporariamente, você pode codificar o seu token pessoal em crowdin.yml com api_token: 'MEU-TOKEN'.
Faça upload dos arquivos fontes#
Gere os arquivos de tradução JSON para a língua padrão no website/i18n/en:
- npm
 - Yarn
 
npm run write-translationsyarn run write-translationsCarregar todos os arquivos de tradução JSON e Markdown:
- npm
 - Yarn
 
npm run crowdin uploadyarn run crowdin upload
Seus arquivos de origem agora são visíveis na interface Crowdin: https://crowdin.com/project/<MY_PROJECT_NAME>/settings#files

Traduza os arquivos fontes#
Em https://crowdin.com/project/<MY_PROJECT_NAME>, clique na língua-alvo francesa.

Traduza alguns arquivos do Markdown.

tip
Use Hide String para garantir que os tradutores não traduzam coisas que não devem:
- Frontmatter: 
id,slug,tags... - Avisos: 
:::,:::note,:::tip... 

Traduza alguns arquivos JSON.

info
O atributo description dos arquivos de tradução JSON é visível no Crowdin para ajudar a traduzir as strings.
tip
Pré-traduza seu site e corrija os erros de pré-tradução manualmente (primeiro habilite a Memória de Tradução Global nas configurações).
Use primeiro o recurso Hide String pois o Crowdin está pré-traduzindo as coisas muito otimisticamente.
Baixe as traduções#
Use o Crowdin CLI para baixar os arquivos traduzidos JSON e Markdown.
- npm
 - Yarn
 
npm run crowdin downloadyarn run crowdin downloadO conteúdo traduzido deve ser baixado em i18n/fr.
Inicie seu site na localidade francesa:
- npm
 - Yarn
 
npm run start -- --locale fryarn run start -- --locale frCertifique-se de que seu site esteja traduzido em francês em http://localhost:3000/fr/.
Automatizar com CI#
Vamos configurar o CI para baixar as traduções Crowdin no horário de compilação, e mantê-las fora do Git.
Adicione website/i18n ao .gitignore.
Defina a variável de ambiente CROWDIN_PERSONAL_TOKEN no seu CI.
Crie um script npm para sincronizar Crowdin (extrair fontes, fazer upload de fontes, baixar traduções):
{  "scripts": {    "crowdin:sync": "docusaurus write-translations && crowdin upload && crowdin download"  }}Chame o comando npm run crowdin:sync no seu CI, logo antes de construir o site do Docusaurus.
tip
Mantenha suas visualizações de implantação rápidas: não baixe traduções e use npm run build - --locale en para ramificações de recursos.
caution
Crowdin não suporta bem múltiplos uploads/downloads simultâneos: é preferível incluir apenas traduções para sua implantação de produção e manter as visualizações de implantação não traduzidas.
Tópicos avançados do Crowdin#
MDX#
caution
Preste atenção especial aos fragmentos JSX em documentos MDX!
Crowdin não oferece suporte oficialmente para MDX, mas adicionou  suporte para a extensão .mdx , e interpretar esses arquivos como Markdown (em vez de texto simples).
Problemas MDX#
Crowdin pensa que a sintaxe JSX é HTML embutido e pode bagunçar a marcação JSX quando você baixa as traduções, levando a um site à falha na construção devido ao JSX inválido.
Fragmentos JSX simples usando propriedades de string simples como <Username name="Sebastien"/> funcionarão bem.
Fragmentos JSX mais complexos usando propriedades de objeto/array como <User person={{name: "Sebastien"}}/> têm mais probabilidade de falhar devido a uma sintaxe que não se parece com HTML.
Soluções MDX#
Recomendamos mover o código JSX incorporado complexo como componentes autônomos separados.
Também adicionamos uma sintaxe de escape mdx-code-block:
# Como fazer deploy do Docusaurus
Para fazer deploy do Docusaurus, execute o seguinte comando:
````mdx-code-blockimport Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs  defaultValue="bash"  values={[    { label: 'Bash', value: 'bash' },    { label: 'Windows', value: 'windows' }]}>  <TabItem value="bash">
  ```bash  GIT_USER=<GITHUB_USERNAME> yarn deploy  ```
  </TabItem>  <TabItem value="windows">
  ```batch  cmd /C "set "GIT_USER=<GITHUB_USERNAME>" && yarn deploy"  ```
  </TabItem></Tabs>````Isso vai:
- ser interpretado pelo Crowdin como um código de blocos (e não enviar mensagens com a marcação no download)
 - ser interpretado pelo Docusaurus como JSX normal (como se ele não fosse envolvido por nenhum bloco de código)
 - infelizmente opt-out na ferramenta MDX (destaque de sintaxe IDE, Prettier...)
 
Controle de versão dos documentos#
Configurar arquivos de tradução para a pasta website/versioned_docs.
Ao criar uma nova versão, as strings de origem geralmente serão bastante semelhantes à versão atual (website/docs) e você não quer traduzir a nova documentação de versão de novo e de novo.
Crowdin fornece uma configuração Strings duplicadas.

Recomendamos usar Hide, mas a configuração ideal depende da quantidade de versões diferentes.
caution
Não usar Hide leva a um valor muito maior de strings de origem em quotas, e afetará os preços.
Plugins de multi-instância#
Você precisa configurar os arquivos de tradução para cada instância do plugin.
Se você tem uma instância do plugin de documentação com id=ios, você precisará configurar esses arquivos de origem também
website/ioswebsite/ios_versioned_docs(se versionado)
Mantendo o seu site#
Às vezes, você removerá ou renomeará um arquivo de origem no Git, e o Crowdin exibirá avisos de CLI:

Quando as suas fontes são refatoradas, você deve usar a interface de usuário do Crowdin para atualizar seus arquivos Crowdin manualmente:

Integrações VCS (Git)#
Crowdin tem várias integrações de VCS para GitHub, GitLab, Bitbucket.
warning
Recomendamos evitá-los.
Poderia ter sido útil ser capaz de editar as traduções em Git e Crowdin, e ter uma sincronização bidirecional entre os 2 sistemas.
Na prática, não funcionou de maneira muito confiável por alguns motivos:
- O Crowdin -> Git sync funciona bem (com uma pull request)
 - O Git -> sincronização Crowdin é manual (você tem que pressionar um botão)
 - As heurísticas usadas pelo Crowdin para corresponder as traduções Markdown existentes com as fontes Markdown existentes não são 100% confiáveis, e você tem que verificar o resultado na Crowdin UI após qualquer sincronização do Git
 - Ao mesmo tempo, edição de 2 usuários no Git e Crowdin pode levar a uma perda de tradução
 - Requer que o arquivo 
crowdin.ymlesteja na raiz do repositório 
Localização contextual#
Crowdin tem um recurso de localização contextual.
caution
Infelizmente, ainda não funciona por razões técnicas, mas temos boas esperanças de que possa ser resolvido.
Crowdin substitui strings de markdown por ids técnicos como crowdin: id12345, mas faz de forma muito agressiva, incluindo strings ocultas e bagunçando com frontmatter, admoestações, jsx...
Localizar Urls de edição#
Quando o usuário está navegando em uma página em /fr/doc1, o botão de edição será vinculado por padrão ao documento não localizado em website/docs/doc1.md.
Você pode preferir o botão de edição para vincular à interface do Crowdin, e pode usar a função editUrl para personalizar os urls de edição por localidade.
const DefaultLocale = 'en';
module.exports = {  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/master/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/master/website/${blogDirPath}/${blogPath}`;          },        },      },    ],  ],};note
Atualmente não é possível vincular a um arquivo específico no Crowdin.
Configuração de exemplo#
O arquivo de configuração do Docusaurus v2 é um bom exemplo de como usar versionamento e multi-instância:
project_id: '428890'api_token_env: 'CROWDIN_PERSONAL_TOKEN'preserve_hierarchy: truelanguages_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,    },  ]