Translate #47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Translate | |
| on: | |
| # Automatic: when English content or prompts change | |
| push: | |
| branches: | |
| - master | |
| paths: | |
| - "docs/en/docs/**/*.md" | |
| - "docs/*/llm-prompt.md" | |
| - "_scripts/general-llm-prompt.md" | |
| # Manual trigger | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: >- | |
| normal: incrementally update translations based on English changes since the last translation PR. | |
| fix: scan all existing translations for structural issues and re-translate broken files from scratch. | |
| type: choice | |
| options: | |
| - normal | |
| - fix | |
| default: normal | |
| language: | |
| description: "Language code (empty = all)" | |
| type: string | |
| since: | |
| description: "Compare since this commit (default: auto-detect from last translation PR)" | |
| type: string | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| detect: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| languages: ${{ steps.detect.outputs.languages }} | |
| has_work: ${{ steps.detect.outputs.has_work }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: astral-sh/setup-uv@v7 | |
| - name: Detect work | |
| id: detect | |
| working-directory: _scripts | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| run: | | |
| uv run -q python -m translate ci-detect \ | |
| ${{ inputs.language && format('--language "{0}"', inputs.language) || '' }} \ | |
| ${{ inputs.since && format('--since "{0}"', inputs.since) || '' }} \ | |
| ${{ inputs.mode == 'fix' && '--fix' || '' }} \ | |
| >> $GITHUB_OUTPUT | |
| translate: | |
| needs: detect | |
| if: needs.detect.outputs.has_work == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false # Continue other languages if one fails | |
| matrix: | |
| language: ${{ fromJson(needs.detect.outputs.languages) }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: astral-sh/setup-uv@v7 | |
| - name: Translate ${{ matrix.language }} | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| working-directory: _scripts | |
| run: > | |
| uv run -q python -m translate sync ${{ matrix.language }} | |
| --log translate-${{ matrix.language }}.json | |
| ${{ inputs.mode == 'fix' && '--fix' || '' }} | |
| - name: Upload translation artifacts | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: translation-${{ matrix.language }} | |
| path: docs/${{ matrix.language }}/docs/ | |
| retention-days: 1 | |
| if-no-files-found: ignore | |
| - name: Upload translation log | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: log-${{ matrix.language }} | |
| path: _scripts/translate-${{ matrix.language }}.json | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| merge: | |
| needs: [detect, translate] | |
| if: always() && needs.detect.outputs.has_work == 'true' && !cancelled() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.sha }} # Use trigger SHA, not latest master (avoids workflow file conflicts) | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download all translation artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: translation-* | |
| path: artifacts/ | |
| - name: Check for artifacts | |
| id: check | |
| run: | | |
| if [ -z "$(ls -A artifacts/ 2>/dev/null)" ]; then | |
| echo "has_artifacts=false" >> $GITHUB_OUTPUT | |
| echo "No translation artifacts found" | |
| else | |
| echo "has_artifacts=true" >> $GITHUB_OUTPUT | |
| echo "Found translations for:" | |
| ls artifacts/ | sed 's/translation-/ - /' | |
| fi | |
| - name: Merge translations | |
| if: steps.check.outputs.has_artifacts == 'true' | |
| run: | | |
| for dir in artifacts/translation-*/; do | |
| lang=$(basename "$dir" | sed 's/translation-//') | |
| echo "Merging $lang..." | |
| mkdir -p "docs/$lang/docs/" | |
| cp -r "$dir"* "docs/$lang/docs/" | |
| done | |
| - uses: astral-sh/setup-uv@v7 | |
| if: steps.check.outputs.has_artifacts == 'true' | |
| - name: Run pre-commit on translations | |
| if: steps.check.outputs.has_artifacts == 'true' | |
| run: | | |
| pip install pre-commit | |
| pre-commit run --all-files || true | |
| - name: Delete orphaned translation files | |
| if: steps.check.outputs.has_artifacts == 'true' | |
| working-directory: _scripts | |
| run: uv run -q python -m translate ci-delete-orphans | |
| - name: Create PR | |
| if: steps.check.outputs.has_artifacts == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_SHA: ${{ github.sha }} | |
| GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| working-directory: _scripts | |
| run: | | |
| # Determine trigger description | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| TRIGGER="manual" | |
| else | |
| # Get first line of commit message for title | |
| TRIGGER=$(git log -1 --format=%s ${{ github.sha }}) | |
| # Get full commit message for body (passed via env var to handle multi-line) | |
| export TRIGGER_COMMIT_MESSAGE=$(git log -1 --format=%B ${{ github.sha }}) | |
| fi | |
| uv run -q python -m translate ci-pr --trigger "$TRIGGER" |