Passer au contenu principal
L’internationalisation (i18n) est le processus qui consiste à concevoir un logiciel ou du contenu pour fonctionner avec différentes langues et différents paramètres régionaux. Ce guide explique comment structurer les fichiers, configurer la navigation et maintenir les traductions efficacement afin que vous puissiez aider vos utilisateurs à accéder à votre documentation dans leur langue préférée et améliorer votre portée à l’international.

Structure des fichiers

Organisez le contenu traduit dans des répertoires propres à chaque langue afin que votre documentation reste facile à maintenir et pour structurer votre navigation par langue. Créez un répertoire séparé pour chaque langue en utilisant les codes de langue ISO 639-1. Placez les fichiers traduits dans ces répertoires en respectant la même structure que pour votre langue par défaut.
Example file structure
docs/
├── index.mdx                    # anglais (par défaut)
├── quickstart.mdx
├── fr/
│   ├── index.mdx               # français
│   ├── quickstart.mdx
├── es/
│   ├── index.mdx               # espagnol
│   ├── quickstart.mdx
└── zh/
    ├── index.mdx               # Chinese
    └── quickstart.mdx
Conservez les mêmes noms de fichiers et la même structure de répertoires dans toutes les langues. Cela facilite la maintenance des traductions et l’identification du contenu manquant.

Configurer le sélecteur de langue

Pour ajouter un sélecteur de langue à votre documentation, configurez le tableau languages dans la propriété navigation de votre fichier docs.json.
docs.json
{
  "navigation": {
    "languages": [
      {
        "language": "en",
        "groups": [
          {
            "group": "Premiers pas",
            "pages": ["index", "quickstart"]
          }
        ]
      },
      {
        "language": "es",
        "groups": [
          {
            "group": "Comenzando",
            "pages": ["es/index", "es/quickstart"]
          }
        ]
      }
    ]
  }
}
Chaque entrée de langue dans le tableau languages nécessite :
  • language : code de langue ISO 639-1
  • Une structure de navigation complète
  • Les chemins d’accès aux fichiers traduits
La structure de navigation peut différer selon les langues pour s’adapter aux besoins de contenu propres à chacune.

Définir la langue par défaut

La première langue du tableau languages est automatiquement utilisée comme langue par défaut. Pour définir une autre langue comme langue par défaut, réorganisez le tableau ou ajoutez la propriété default :
docs.json
{
  "navigation": {
    "languages": [
      {
        "language": "es",
        "groups": [...]
      },
      {
        "language": "en",
        "groups": [...]
      }
    ]
  }
}
Vous pouvez également utiliser la propriété default pour modifier l’ordre :
docs.json
{
  "navigation": {
    "languages": [
      {
        "language": "en",
        "groups": [...]
      },
      {
        "language": "es",
        "default": true,
        "groups": [...]
      }
    ]
  }
}

Documentation en une seule langue

Si vous ne souhaitez proposer qu’une seule langue sans sélecteur de langue, supprimez le champ languages de votre configuration de navigation. Définissez ensuite directement votre structure de navigation :
docs.json
{
  "navigation": {
    "tabs": [
      {
        "tab": "Documentation",
        "groups": [
          {
            "group": "Premiers pas",
            "pages": ["index", "quickstart"]
          }
        ]
      }
    ]
  }
}
Cela affiche votre documentation dans une seule langue, sans l’interface du sélecteur de langue.
Traduisez les libellés de navigation, comme les noms de groupes ou d’onglets, afin de les faire correspondre à la langue du contenu. Cela crée une expérience entièrement localisée pour vos utilisateurs.
Pour ajouter des éléments de navigation globaux qui apparaissent dans toutes les langues, configurez l’objet global dans la propriété navigation de votre fichier docs.json.
docs.json
{
  "navigation": {
    "global": {
      "anchors": [
        {
          "anchor": "Documentation",
          "href": "https://example.com/docs"
        },
        {
          "anchor": "Blog",
          "href": "https://example.com/blog"
        }
      ]
    },
    "languages": [
      // Navigation spécifique à chaque langue
    ]
  }
}

Conserver les traductions

Veillez à ce que vos traductions restent exactes et synchronisées avec votre contenu source.

Processus de traduction

  1. Mettez à jour le contenu source dans votre langue principale.
  2. Identifiez le contenu modifié.
  3. Traduisez le contenu modifié.
  4. Relisez les traductions pour en vérifier l’exactitude.
  5. Mettez à jour les fichiers traduits.
  6. Vérifiez que la navigation et les liens fonctionnent.

Traductions automatisées

Pour des solutions de traduction automatique, contactez l’équipe commerciale de Mintlify.

Prestataires de traduction externes

Si vous travaillez avec vos propres prestataires de traduction ou traducteurs régionaux, vous pouvez intégrer leur processus à votre documentation Mintlify à l’aide de GitHub Actions ou d’outils CI/CD similaires.
  1. Exporter le contenu source : extrayez les fichiers MDX à traduire.
  2. Envoyer aux traducteurs : transmettez les fichiers à votre prestataire de traduction.
  3. Recevoir les traductions : récupérez les fichiers MDX traduits.
  4. Importer et déployer : ajoutez les fichiers traduits aux répertoires de langue et mettez à jour la navigation.
Ce processus GitHub Actions exporte automatiquement le contenu anglais modifié pour traduction lorsque des PR sont fusionnées dans main.
.github/workflows/export-for-translation.yml
name: Export content for translation

on:
  push:
    branches: [main]
    paths:
      - '*.mdx'
      - '!es/**'
      - '!fr/**'
      - '!zh/**'

# Prevent concurrent workflow runs to avoid race conditions
concurrency:
  group: translation-export-${{ github.ref }}
  cancel-in-progress: false

jobs:
  export:
    runs-on: ubuntu-latest
    
    # Early exit if no changes detected (optional - acts as additional safety)
    outputs:
      files-changed: ${{ steps.changed.outputs.has-files }}
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - name: Get changed MDX files
        id: changed
        run: |
          # Check if parent commit exists (handles initial push)
          if ! git rev-parse HEAD~1 >/dev/null 2>&1; then
            echo "has-files=false" >> $GITHUB_OUTPUT
            echo "files=" >> $GITHUB_OUTPUT
            echo "No parent commit found - skipping export"
            exit 0
          fi
          
          # Get list of changed MDX files (excluding translation dirs)
          files=$(git diff --name-only HEAD~1 HEAD -- '*.mdx' ':!es/' ':!fr/' ':!zh/' | tr '\n' ' ')
          
          if [ -z "$files" ]; then
            echo "has-files=false" >> $GITHUB_OUTPUT
            echo "files=" >> $GITHUB_OUTPUT
            echo "No MDX files changed - skipping export"
          else
            echo "has-files=true" >> $GITHUB_OUTPUT
            echo "files=$files" >> $GITHUB_OUTPUT
            echo "Found changed files: $files"
          fi
        shell: bash

      - name: Create translation package directory
        if: steps.changed.outputs.has-files == 'true'
        run: |
          mkdir -p translation-export
          echo "Created translation-export directory"

      - name: Copy changed files to export directory
        if: steps.changed.outputs.has-files == 'true'
        run: |
          failed_count=0
          for file in ${{ steps.changed.outputs.files }}; do
            if [ -f "$file" ]; then
              target_dir="translation-export/$(dirname "$file")"
              mkdir -p "$target_dir"
              cp "$file" "$target_dir/"
              echo "✓ Copied: $file"
            else
              echo "✗ File not found: $file"
              ((failed_count++))
            fi
          done
          
          if [ $failed_count -gt 0 ]; then
            echo "Warning: $failed_count file(s) could not be copied"
          fi
        shell: bash

      - name: Validate translation package
        if: steps.changed.outputs.has-files == 'true'
        run: |
          echo "Translation package contents:"
          find translation-export -type f -name "*.mdx" | sort
          echo ""
          file_count=$(find translation-export -type f -name "*.mdx" | wc -l)
          echo "Total MDX files: $file_count"

      - name: Upload translation package
        if: steps.changed.outputs.has-files == 'true'
        uses: actions/upload-artifact@v4
        with:
          name: translation-export-${{ github.sha }}
          path: translation-export/
          retention-days: 30
          if-no-files-found: error
          compression-level: 9

      - name: Print job summary
        if: steps.changed.outputs.has-files == 'true'
        run: |
          echo "## Translation Export Complete" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Artifact:** \`translation-export-${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Changed Files:**" >> $GITHUB_STEP_SUMMARY
          echo "${{ steps.changed.outputs.files }}" | tr ' ' '\n' | sed 's/^/- /' >> $GITHUB_STEP_SUMMARY
Ce processus GitHub Actions valide et importe le contenu traduit lorsqu’il est ajouté via une PR.
.github/workflows/import-translations.yml
name: Import translations

on:
  pull_request:
    paths:
      - 'es/**'
      - 'fr/**'
      - 'zh/**'

# Define explicit permissions
permissions:
  contents: read
  pull-requests: write

jobs:
  validate:
    runs-on: ubuntu-latest
    
    outputs:
      validation-status: ${{ steps.final-check.outputs.status }}
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history to ensure origin/main is available

      - name: Fetch origin/main reference
        run: |
          git fetch origin main:origin/main 2>/dev/null || echo "origin/main not available, using latest"
        continue-on-error: true

      - name: Get changed translation files
        id: changed-files
        run: |
          # Get all changed MDX files in translation directories
          files=$(git diff --name-only origin/main..HEAD -- 'es/**/*.mdx' 'fr/**/*.mdx' 'zh/**/*.mdx' | sort)
          
          if [ -z "$files" ]; then
            echo "No translation MDX files detected in this PR"
            echo "files=" >> $GITHUB_OUTPUT
            echo "count=0" >> $GITHUB_OUTPUT
          else
            echo "Found $(echo "$files" | wc -l) translation files"
            echo "$files"
            echo "files=$files" >> $GITHUB_OUTPUT
            echo "count=$(echo "$files" | wc -l)" >> $GITHUB_OUTPUT
          fi
        shell: bash

      - name: Validate frontmatter
        id: frontmatter
        if: steps.changed-files.outputs.count > 0
        run: |
          failed_files=()
          success_count=0
          total=${{ steps.changed-files.outputs.count }}
          
          while IFS= read -r file; do
            if [ ! -f "$file" ]; then
              echo "✗ File not found: $file"
              failed_files+=("$file")
              continue
            fi
            
            # Check for valid frontmatter (lines 1-2 must be ---)
            first_line=$(sed -n '1p' "$file")
            second_line=$(sed -n '2p' "$file")
            last_line=$(awk 'NF' "$file" | tail -1)
            
            if [ "$first_line" = "---" ] && grep -q "^---$" "$file"; then
              echo "✓ Valid frontmatter: $file"
              ((success_count++))
            else
              echo "✗ Invalid frontmatter in $file"
              echo "  Line 1: '$first_line'"
              failed_files+=("$file")
            fi
          done <<< "${{ steps.changed-files.outputs.files }}"
          
          echo ""
          echo "Frontmatter check: $success_count/$total passed"
          
          if [ ${#failed_files[@]} -gt 0 ]; then
            echo "frontmatter_valid=false" >> $GITHUB_OUTPUT
            printf 'failed_files=%s\n' "${failed_files[@]}" >> $GITHUB_OUTPUT
          else
            echo "frontmatter_valid=true" >> $GITHUB_OUTPUT
          fi
        shell: bash

      - name: Check file structure
        id: structure
        if: steps.changed-files.outputs.count > 0
        run: |
          missing_sources=()
          orphaned_count=0
          
          while IFS= read -r translated_file; do
            # Extract language and relative path
            # e.g., "es/docs/guide.mdx" -> lang="es", relative_path="docs/guide.mdx"
            lang=$(echo "$translated_file" | cut -d'/' -f1)
            relative_path=$(echo "$translated_file" | cut -d'/' -f2-)
            source_file="$relative_path"
            
            if [ ! -f "$source_file" ]; then
              echo "Missing source: $translated_file -> $source_file"
              missing_sources+=("$translated_file")
              ((orphaned_count++))
            else
              echo "✓ Found source: $translated_file -> $source_file"
            fi
          done <<< "${{ steps.changed-files.outputs.files }}"
          
          echo ""
          echo "Structure check: $orphaned_count orphaned file(s)"
          
          if [ $orphaned_count -gt 0 ]; then
            echo "structure_valid=false" >> $GITHUB_OUTPUT
            printf 'missing_sources=%s\n' "${missing_sources[@]}" >> $GITHUB_OUTPUT
          else
            echo "structure_valid=true" >> $GITHUB_OUTPUT
          fi
        shell: bash

      - name: Validate file integrity
        id: integrity
        if: steps.changed-files.outputs.count > 0
        run: |
          integrity_passed=true
          
          while IFS= read -r file; do
            # Check file is readable and not empty
            if [ ! -r "$file" ] || [ ! -s "$file" ]; then
              echo "✗ File integrity issue: $file (not readable or empty)"
              integrity_passed=false
            fi
            
            # Basic check: file should have content after frontmatter
            line_count=$(wc -l < "$file")
            if [ "$line_count" -lt 5 ]; then
              echo "File is suspiciously short: $file ($line_count lines)"
            fi
          done <<< "${{ steps.changed-files.outputs.files }}"
          
          if [ "$integrity_passed" = true ]; then
            echo "integrity_valid=true" >> $GITHUB_OUTPUT
          else
            echo "integrity_valid=false" >> $GITHUB_OUTPUT
          fi
        shell: bash

      - name: Generate validation report
        if: always()
        run: |
          echo "## Translation Validation Report" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Files Changed:** ${{ steps.changed-files.outputs.count }}" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          
          if [ "${{ steps.changed-files.outputs.count }}" = "0" ]; then
            echo "No translation MDX files found in this PR" >> $GITHUB_STEP_SUMMARY
            echo "" >> $GITHUB_STEP_SUMMARY
            echo "> This could mean:" >> $GITHUB_STEP_SUMMARY
            echo "- Only non-MDX files in es/, fr/, or zh/ directories were changed" >> $GITHUB_STEP_SUMMARY
            echo "- Workflow was triggered but no translation content to validate" >> $GITHUB_STEP_SUMMARY
          else
            echo "### Validation Results" >> $GITHUB_STEP_SUMMARY
            echo "- Frontmatter: ${{ steps.frontmatter.outputs.frontmatter_valid }}" >> $GITHUB_STEP_SUMMARY
            echo "- File Structure: ${{ steps.structure.outputs.structure_valid }}" >> $GITHUB_STEP_SUMMARY
            echo "- File Integrity: ${{ steps.integrity.outputs.integrity_valid }}" >> $GITHUB_STEP_SUMMARY
            echo "" >> $GITHUB_STEP_SUMMARY
          fi
        shell: bash

      - name: Final validation check
        id: final-check
        # Only run this check if we actually had MDX files to validate
        if: steps.changed-files.outputs.count > 0
        run: |
          validation_failed=false
          
          if [ "${{ steps.frontmatter.outputs.frontmatter_valid }}" != "true" ]; then
            echo "Frontmatter validation failed"
            validation_failed=true
          fi
          
          if [ "${{ steps.structure.outputs.structure_valid }}" != "true" ]; then
            echo "File structure validation failed"
            validation_failed=true
          fi
          
          if [ "${{ steps.integrity.outputs.integrity_valid }}" != "true" ]; then
            echo "File integrity validation failed"
            validation_failed=true
          fi
          
          if [ "$validation_failed" = true ]; then
            echo "status=failed" >> $GITHUB_OUTPUT
            exit 1
          else
            echo "status=passed" >> $GITHUB_OUTPUT
            echo "All validations passed"
          fi
        shell: bash

      - name: Handle no-files-to-validate case
        # Run only when there are no MDX files to validate
        if: steps.changed-files.outputs.count == 0
        run: |
          echo "No translation MDX files to validate - PR is valid"
          echo "status=no-changes" >> ${{ steps.final-check.outputs }}
        shell: bash
Bonnes pratiques pour les processus de traduction externes
  • Préserver le frontmatter : assurez-vous que les traducteurs conservent le frontmatter YAML intact et ne traduisent que les valeurs de title et description.
  • Protéger les code blocks : indiquez à vos prestataires que les code blocks ne doivent pas être traduits.
  • Utiliser la mémoire de traduction : fournissez des glossaires contenant les termes techniques qui doivent rester en anglais ou avoir des traductions spécifiques.
  • Automatiser la validation : utilisez des vérifications CI pour valider la syntaxe MDX et le frontmatter avant d’intégrer les traductions.
  • Contrôle de version : suivez la version source de chaque traduction afin d’identifier le contenu obsolète.

Images et médias

Stockez les images traduites dans des répertoires propres à chaque langue.
images/
├── dashboard.png          # Version anglaise
├── fr/
│   └── dashboard.png     # French version
└── es/
    └── dashboard.png     # Spanish version
Référencez les images à l’aide de chemins relatifs dans vos contenus traduits.
es/index.mdx
![Capture d'écran du Dashboard](/images/fr/dashboard.png)

SEO pour les sites multilingues

Optimisez chaque version dans chaque langue pour les moteurs de recherche.

Metadata de la page

Incluez les metadata traduites dans le frontmatter de chaque fichier :
fr/index.mdx
---
title: "Commencer"
description: "Apprenez à commencer avec notre produit."
keywords: ["démarrage", "tutoriel", "guide"]
---

Bonnes pratiques

Formats de date et de nombre

Tenez compte des formats propres à chaque langue pour les dates et les nombres.
  • Formats de date : MM/DD/YYYY vs DD/MM/YYYY
  • Formats de nombres : 1,000.00 vs 1.000,00
  • Symboles monétaires : $100.00 vs 100,00€
Incluez des exemples dans le format approprié pour chaque langue ou utilisez des formats universellement compréhensibles.

Maintenir la cohérence

  • Assurez une parité de contenu entre toutes les langues afin que chaque utilisateur bénéficie de la même qualité d’information.
  • Créez un glossaire de traduction pour les termes techniques.
  • Conservez la même structure de contenu dans toutes les langues.
  • Alignez le ton et le style sur ceux de votre contenu source.
  • Utilisez des branches Git pour gérer le travail de traduction séparément des mises à jour du contenu principal.

Différences de mise en page

Certaines langues nécessitent plus ou moins d’espace que l’anglais. Testez votre contenu traduit sur différentes tailles d’écran pour vous assurer que :
  • La navigation s’affiche correctement.
  • Les code blocks ne débordent pas.
  • Les tableaux et autres éléments de texte mis en forme restent lisibles.
  • Les images se redimensionnent correctement.

Encodage des caractères

Assurez-vous que votre environnement de développement et votre pipeline de déploiement prennent en charge l’UTF-8 afin d’afficher correctement tous les caractères dans les langues utilisant différents alphabets et caractères spéciaux.