Categories
This guide assumes you already have a Mintlify documentation site in a GitHub repository and want to translate the MDX content with Crowdin.
The setup has three moving parts:
crowdin.yml tells Crowdin which Mintlify source files to upload and where translated files should be downloaded.docs.json tells Mintlify which languages exist and which translated pages belong to each language.After the integration is connected, you can decide how translation work is done in Crowdin: fully AI-generated translations, human translation/review, or a mixed workflow where only part of the content is routed through AI before review.
A typical Mintlify repository starts with English source pages at the root:
.
|-- docs.json
|-- index.mdx
|-- quickstart.mdx
|-- essentials/
| |-- markdown.mdx
| `-- settings.mdx
`-- api-reference/
`-- introduction.mdx
Crowdin should download translations into language folders that mirror the source structure:
.
|-- index.mdx # English source
|-- quickstart.mdx # English source
`-- de/
|-- index.mdx
`-- quickstart.mdx
Keep the same file names and folder structure for every language. That makes docs.json predictable and makes missing translations easy to find.
Use language codes supported by Mintlify and Crowdin. Common examples:
en English
fr French
de German
pt Portuguese
pt-BR Brazilian Portuguese
uk Ukrainian
es Spanish
ja Japanese
ko Korean
zh-Hans Simplified Chinese
zh-Hant Traditional Chinese
Do not assume every ISO language code is accepted by Mintlify. For example, if Mintlify rejects a code during deployment, do not add it to docs.json until Mintlify supports it.
Create crowdin.yml in the repository root.
Use environment variables for credentials. Do not commit personal tokens.
"project_id_env": "CROWDIN_PROJECT_ID"
"api_token_env": "CROWDIN_PERSONAL_TOKEN"
"base_path": "."
"base_url": "https://api.crowdin.com"
"preserve_hierarchy": true
files:
- source: /**/*.mdx
translation: /%two_letters_code%/**/%original_file_name%
ignore:
- /de/**
- /fr/**
- /pt/**
- /pt-BR/**
- /uk/**
- /es/**
- /ja/**
- /ko/**
- /zh/**
- /zh-Hans/**
- /zh-Hant/**
- /node_modules/**
What this does:
source: /**/*.mdx uploads MDX files from the repository.translation: /%two_letters_code%/**/%original_file_name% downloads translations into language folders such as de/index.mdx and de/quickstart.mdx.preserve_hierarchy: true keeps the folder structure from the source docs.ignore prevents translated folders from being uploaded back to Crowdin as source files.If you use Crowdin Enterprise, set base_url to your organization API URL, for example:
"base_url": "https://your-org.api.crowdin.com"
If you use Crowdin.com, keep:
"base_url": "https://api.crowdin.com"
In Crowdin, create or open the project for the docs site.
Recommended project setup:
Practical rules for translators and reviewers:
title and description.title, description, or icon.<Card>, <Accordion>, <Tabs>, <CodeGroup>.If a client reports import issues, or if imported MDX files are segmented in a way the team does not expect, check the parser settings in Crowdin before translating a large batch.
In Crowdin, open Settings > Parser Configuration > MDX (v2). Use this area to control how Crowdin treats MDX content, tags, and inline syntax. This is especially important for Mintlify pages because they often contain JSX-like components, props, code blocks, and frontmatter.
Check parser settings when:
Some teams already have translated MDX files before they connect Crowdin. You can upload those translations, but alignment can be difficult if the files were translated outside professional translation tools.
The main risk is that the source and translated files no longer have the same segment structure. This can happen when translators rewrote sections, moved paragraphs, merged sentences, split sentences, or changed MDX structure.
If existing translations do not align cleanly, use Crowdin's Translation Alignment app. It uses AI to match source and target text when uploaded translations are out of order or when segment counts differ. It supports Markdown-style content, including .md files, and can help when importing existing MDX translations.
Mintlify does not enable languages only because translated folders exist. You must declare languages in docs.json.
Use navigation.languages and include the full navigation for each language. The source language should also be present as a language entry.
Example with English source plus German:
{
"$schema": "https://mintlify.com/docs.json",
"theme": "mint",
"name": "Example Docs",
"navigation": {
"languages": [
{
"language": "en",
"default": true,
"tabs": [
{
"tab": "Guides",
"groups": [
{
"group": "Getting started",
"pages": [
"index",
"quickstart"
]
},
{
"group": "Writing content",
"pages": [
"essentials/markdown",
"essentials/settings"
]
}
]
}
]
},
{
"language": "de",
"tabs": [
{
"tab": "Guides",
"groups": [
{
"group": "Getting started",
"pages": [
"de/index",
"de/quickstart"
]
},
{
"group": "Writing content",
"pages": [
"de/essentials/markdown",
"de/essentials/settings"
]
}
]
}
]
}
]
}
}
Important details:
navigation.languages. This lets Mintlify treat it as the source language in the language switcher and admin views.index, quickstart, essentials/markdown.de/index, de/quickstart, de/essentials/markdown.docs.json only when the translated files exist or when you are ready for Mintlify to expect those paths.In GitHub, open the repository settings and add these secrets:
CROWDIN_PROJECT_ID
CROWDIN_PERSONAL_TOKEN
Use a Crowdin token with access to upload source files and download translations for the project.
The workflow can use GitHub's built-in GITHUB_TOKEN for creating branches and pull requests. If your repository has stricter permissions, use a GitHub App token or a fine-grained token with contents and pull request permissions.
Create .github/workflows/crowdin-sync.yml.
This workflow uploads source MDX files to Crowdin and opens a pull request with downloaded translations.
name: Sync Crowdin translations
on:
push:
branches:
- main
paths:
- "**/*.mdx"
- "docs.json"
- "crowdin.yml"
- ".github/workflows/crowdin-sync.yml"
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
crowdin-sync:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Upload sources and download translations
uses: crowdin/github-action@v2
with:
upload_sources: true
upload_translations: false
download_translations: true
localization_branch_name: l10n_crowdin_translations
create_pull_request: true
pull_request_title: "Update Crowdin translations"
pull_request_body: "Downloads the latest translations from Crowdin."
pull_request_base_branch_name: "main"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
This is the usual flow:
main.de/.Some teams need translations ready before new documentation is merged to main. For example, a feature branch might contain new English docs, and the team may want German translations prepared before the feature launch PR is merged.
The Crowdin GitHub Action supports branch-based workflows. Use the Crowdin GitHub Action documentation for the exact setup, especially the options for uploading sources to a Crowdin branch and checking out or pushing translations from a branch. In practice, this usually means:
main content.This avoids waiting for localization after main is already updated.
If translations must be reviewed before publishing, add export options:
with:
upload_sources: true
upload_translations: false
download_translations: true
export_only_approved: true
skip_untranslated_strings: true
localization_branch_name: l10n_crowdin_translations
create_pull_request: true
Use this when you do not want unapproved or untranslated strings to reach the docs repository.
Some teams prefer two workflows:
main.Upload only:
name: Upload sources to Crowdin
on:
push:
branches:
- main
paths:
- "**/*.mdx"
- "crowdin.yml"
workflow_dispatch:
jobs:
upload-sources:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crowdin/github-action@v2
with:
upload_sources: true
upload_translations: false
download_translations: false
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
Download translations and create a PR:
name: Download translations from Crowdin
on:
workflow_dispatch:
schedule:
- cron: "0 6 * * 1-5"
permissions:
contents: write
pull-requests: write
jobs:
download-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crowdin/github-action@v2
with:
upload_sources: false
upload_translations: false
download_translations: true
localization_branch_name: l10n_crowdin_translations
create_pull_request: true
pull_request_title: "Update Crowdin translations"
pull_request_body: "Downloads the latest translations from Crowdin."
pull_request_base_branch_name: "main"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
This setup gives localization managers more control over when translated content is proposed for publishing.
Before merging a translation PR, check these items:
docs.json contains every language you want Mintlify to render.docs.json exists in the repository.crowdin.yml.Useful commands:
python3 -m json.tool docs.json >/dev/null
mint broken-links
mint dev
Add language folders to the ignore list in crowdin.yml:
ignore:
- /de/**
Check that:
navigation.languages.docs.json.navigation.languages.Remove that language from docs.json or map it to a Mintlify-supported code. Keep the files out of Mintlify indexing until the code is supported.
Check for these causes:
crowdin.yml ignore.docs.json.The translated file is missing, or the path in docs.json does not match the file path. For example, this entry:
"pages": ["de/quickstart"]
requires this file:
de/quickstart.mdx
Use this checklist when setting up a new Mintlify and Crowdin integration:
crowdin.yml to the Mintlify repository.crowdin.yml.docs.json under navigation.languages.en, in navigation.languages and mark it as default.Crowdin is a platform that helps you manage and translate content into different languages. Integrate Crowdin with your repo, CMS, or other systems. Source content is always up to date for your translators, and translated content is returned automatically.
Learn MoreAll product and company names are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.