# Mintlify > Translate your Mintlify docs with Crowdin URL: https://store.crowdin.com/mintlify Category: CMS Type: Guide Author: Crowdin 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: 1. `crowdin.yml` tells Crowdin which Mintlify source files to upload and where translated files should be downloaded. 2. `docs.json` tells Mintlify which languages exist and which translated pages belong to each language. 3. A [GitHub Actions](https://github.com/crowdin/github-action) workflow keeps GitHub and Crowdin synchronized. 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. ## Expected repository layout A typical Mintlify repository starts with English source pages at the root: ```text . |-- 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: ```text . |-- 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. ## 1. Choose language codes Use language codes supported by Mintlify and Crowdin. Common examples: ```text 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. ## 2. Add `crowdin.yml` Create `crowdin.yml` in the repository root. Use environment variables for credentials. Do not commit personal tokens. ```yaml "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: ```yaml "base_url": "https://your-org.api.crowdin.com" ``` If you use Crowdin.com, keep: ```yaml "base_url": "https://api.crowdin.com" ``` ## 3. Configure source files in Crowdin In Crowdin, create or open the project for the docs site. Recommended project setup: - Source language: English, or the language used in the root Mintlify files. - Target languages: the languages you want to publish in Mintlify. - File format: Markdown/MDX content should be handled as Markdown-style content. Keep MDX syntax, imports, code blocks, and component tags intact. - Translation process: choose AI, human translation, review steps, or a combination. Practical rules for translators and reviewers: - Translate frontmatter values such as `title` and `description`. - Do not translate frontmatter keys such as `title`, `description`, or `icon`. - Do not translate file paths, imports, component names, props, or code blocks unless the text is clearly user-facing. - Keep Mintlify component syntax valid. Examples: ``, ``, ``, ``. ## 4. Configure the MDX parser in Crowdin 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: - MDX tags are exposed to translators as editable text. - Component props are segmented incorrectly. - Frontmatter is not handled as expected. - Code examples or imports appear in translation strings. ## 5. Import existing translations carefully 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](https://store.crowdin.com/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. ## 6. Update `docs.json` 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: ```json { "$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: - Keep English/source inside `navigation.languages`. This lets Mintlify treat it as the source language in the language switcher and admin views. - Use root paths for English source files: `index`, `quickstart`, `essentials/markdown`. - Use language-prefixed paths for translated files: `de/index`, `de/quickstart`, `de/essentials/markdown`. - Do not use the same page path in multiple language entries. - Add a language to `docs.json` only when the translated files exist or when you are ready for Mintlify to expect those paths. ## 7. Add GitHub secrets In GitHub, open the repository settings and add these secrets: ```text 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. ## 8. Add the GitHub Actions workflow Create `.github/workflows/crowdin-sync.yml`. This workflow uploads source MDX files to Crowdin and opens a pull request with downloaded translations. ```yaml 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: 1. A writer changes English MDX files on `main`. 2. GitHub Actions uploads those source files to Crowdin. 3. Translators, reviewers, or AI workflows complete translation work in Crowdin. 4. The workflow downloads translations into folders such as `de/`. 5. The action opens or updates a pull request with the translated files. 6. You review and merge the translation pull request. 7. Mintlify deploys the updated localized docs. ## 9. Translate content before it reaches `main` 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](https://github.com/crowdin/github-action) 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: 1. Run the Crowdin upload workflow on pull requests or feature branches. 2. Pass the current Git branch name to Crowdin, so branch content is isolated from `main` content. 3. Translate or pre-translate that branch content in Crowdin. 4. Download translations back to the same GitHub branch or to a translation PR targeting that branch. 5. Merge the feature only after the source and translated docs are ready. This avoids waiting for localization after `main` is already updated. ## 10. Optional: download only approved translations If translations must be reviewed before publishing, add export options: ```yaml 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. ## 11. Optional: separate upload and download workflows Some teams prefer two workflows: - Upload source changes automatically on every merge to `main`. - Download translations manually or on a schedule. Upload only: ```yaml 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: ```yaml 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. ## 12. Validate before merging translation PRs Before merging a translation PR, check these items: - `docs.json` contains every language you want Mintlify to render. - Every page path listed in `docs.json` exists in the repository. - Translated folders are not uploaded back as source files in `crowdin.yml`. - Frontmatter is valid YAML. - MDX component syntax is valid. - Internal links point to the correct localized paths when needed. - Mintlify deployment succeeds. Useful commands: ```bash python3 -m json.tool docs.json >/dev/null mint broken-links mint dev ``` ## 13. Common issues ### Translated files are uploaded back to Crowdin as source Add language folders to the `ignore` list in `crowdin.yml`: ```yaml ignore: - /de/** ``` ### A language does not appear in Mintlify Check that: - The language code is supported by Mintlify. - The language is listed in `navigation.languages`. - The translated files exist at the paths listed in `docs.json`. - The source language is also listed in `navigation.languages`. ### Mintlify deployment fails with an invalid language code 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. ### The admin view shows duplicate or confusing entries Check for these causes: - Translated folders are being treated as source files by Crowdin because they are missing from `crowdin.yml` `ignore`. - Source and translated pages have the same untranslated frontmatter titles. - The same page path is listed in more than one language entry in `docs.json`. ### A translated page returns 404 The translated file is missing, or the path in `docs.json` does not match the file path. For example, this entry: ```json "pages": ["de/quickstart"] ``` requires this file: ```text de/quickstart.mdx ``` ## Final checklist Use this checklist when setting up a new Mintlify and Crowdin integration: - Create a Crowdin project. - Add target languages in Crowdin. - Add `crowdin.yml` to the Mintlify repository. - Ignore all translated language folders in `crowdin.yml`. - Add each published language to `docs.json` under `navigation.languages`. - Keep the source language, usually `en`, in `navigation.languages` and mark it as default. - Add GitHub secrets for Crowdin credentials. - Add a Crowdin GitHub Actions workflow. - Run the workflow manually once. - Confirm sources appear in Crowdin. - Complete or pre-translate content in Crowdin. - Download translations through the workflow. - Review the translation PR. - Run Mintlify checks. - Merge and deploy.