diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml
index 9b4203a5c..bd2b06251 100644
--- a/.github/workflows/build-and-deploy.yml
+++ b/.github/workflows/build-and-deploy.yml
@@ -2,14 +2,16 @@ name: Build and Deploy to GitHub Pages
on:
schedule:
- - cron: '0 2 * * *'
+ - cron: '0 2 * * *'
push:
branches:
- 3.14
workflow_dispatch:
permissions:
- contents: write
+ contents: read
+ pages: write
+ id-token: write
concurrency:
group: "pages"
@@ -24,41 +26,52 @@ jobs:
with:
repository: python/cpython
ref: v3.14.6
-
+
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
-
+
- name: Setup virtual environment
run: make venv
working-directory: ./Doc
-
+
- name: Checkout translation files
uses: actions/checkout@v4
with:
path: Doc/locales/fa/LC_MESSAGES
- - name: Install gettext
- run: sudo apt-get install -y gettext
+ - name: Strip stray fuzzy markers
+ run: python3 Doc/locales/fa/LC_MESSAGES/scripts/strip_fuzzy.py $(find Doc/locales/fa/LC_MESSAGES -name "*.po" -not -path "*/.git/*")
- name: Compile .po files to .mo
run: |
- find Doc/locales/fa/LC_MESSAGES -name "*.po" | while read f; do
+ find Doc/locales/fa/LC_MESSAGES -name "*.po" -not -path "*/.git/*" | while read f; do
msgfmt "$f" -o "${f%.po}.mo"
done
- name: Setup problem matcher
uses: sphinx-doc/github-problem-matcher@v1.1
-
+
- name: Build documentation
run: make -e SPHINXOPTS="--color -D language='fa' -D gettext_allow_fuzzy_translations=1 --keep-going" html
working-directory: ./Doc
-
- - name: Deploy to gh-pages
- uses: peaceiris/actions-gh-pages@v4
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v4
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: Doc/build/html
- keep_files: true
- enable_jekyll: false
\ No newline at end of file
+ path: Doc/build/html
+
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
\ No newline at end of file
diff --git a/.github/workflows/build-docs-preview.yml b/.github/workflows/build-docs-preview.yml
deleted file mode 100644
index fa8dd4147..000000000
--- a/.github/workflows/build-docs-preview.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-# .github/workflows/build-docs-preview.yml
-name: Build Docs Preview
-
-on:
- pull_request:
- types:
- - opened
- - synchronize
- paths:
- - '**/*.po'
-
-concurrency:
- group: docs-preview-${{ github.event.pull_request.number }}
- cancel-in-progress: true
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout CPython
- uses: actions/checkout@v4
- with:
- repository: python/cpython
- ref: v3.14.6
-
- - name: Set up Python
- uses: actions/setup-python@v4
- with:
- python-version: '3.12'
-
- - name: Setup virtual environment
- run: make venv
- working-directory: ./Doc
-
- - name: Checkout translation files (this PR's branch)
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.pull_request.head.sha }}
- path: Doc/locales/fa/LC_MESSAGES
-
- - name: Install gettext
- run: sudo apt-get install -y gettext
-
- - name: Compile .po files to .mo
- run: |
- find Doc/locales/fa/LC_MESSAGES -name "*.po" | while read f; do
- msgfmt "$f" -o "${f%.po}.mo"
- done
-
- - name: Build documentation
- id: build
- run: |
- set +e
- make -e SPHINXOPTS="--color -D language='fa' -D gettext_allow_fuzzy_translations=1 --keep-going" html 2>&1 | tee build.log
- echo "exit_code=${PIPESTATUS[0]}" >> $GITHUB_OUTPUT
- working-directory: ./Doc
-
- - name: Patch HTML static paths
- # Sphinx builds _static paths as relative (e.g. ../../_static/),
- # which breaks when served from a subdirectory like /previews/12/.
- # We rewrite them to absolute URLs so CSS/JS load correctly
- # regardless of which subdirectory the HTML file is in.
- run: |
- BASE="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/previews/${{ github.event.pull_request.number }}"
- find Doc/build/html -name "*.html" | while read f; do
- sed -i 's|||g' "$f"
- sed -i "s|href=\"\(\.\./\)*_static/|href=\"$BASE/_static/|g" "$f"
- sed -i "s|src=\"\(\.\./\)*_static/|src=\"$BASE/_static/|g" "$f"
- done
-
- - name: Move log to root
- run: mv Doc/build.log build.log
-
- - name: Save PR number
- run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
-
- - name: Upload build result
- uses: actions/upload-artifact@v4
- with:
- name: build-result
- path: |
- build.log
- pr_number.txt
-
- - name: Upload HTML preview
- uses: actions/upload-artifact@v4
- with:
- name: docs-html
- path: Doc/build/html/
- retention-days: 7
\ No newline at end of file
diff --git a/.github/workflows/comment-docs-preview.yml b/.github/workflows/comment-docs-preview.yml
deleted file mode 100644
index b01754d5f..000000000
--- a/.github/workflows/comment-docs-preview.yml
+++ /dev/null
@@ -1,149 +0,0 @@
-# .github/workflows/comment-docs-preview.yml
-name: Comment Docs Build Status
-
-on:
- workflow_run:
- workflows: ["Build Docs Preview"]
- types:
- - completed
- pull_request:
- types:
- - closed
- paths:
- - '**/*.po'
-
-jobs:
- comment:
- if: github.event_name == 'workflow_run'
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- contents: write
- actions: read
-
- steps:
- - name: Checkout repo
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
-
- - name: Ensure gh-pages branch exists
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
- if ! git ls-remote --exit-code --heads origin gh-pages; then
- echo "gh-pages branch not found, creating it..."
- git checkout --orphan gh-pages
- git rm -rf .
- echo "# Doc Previews" > README.md
- git add README.md
- git commit -m "chore: initialize gh-pages branch"
- git push origin gh-pages
- git checkout -
- else
- echo "gh-pages branch already exists, skipping."
- fi
-
- - name: Download build result
- uses: actions/download-artifact@v4
- with:
- name: build-result
- github-token: ${{ secrets.GITHUB_TOKEN }}
- run-id: ${{ github.event.workflow_run.id }}
-
- - name: Download HTML preview
- uses: actions/download-artifact@v4
- with:
- name: docs-html
- path: html-preview/
- github-token: ${{ secrets.GITHUB_TOKEN }}
- run-id: ${{ github.event.workflow_run.id }}
-
- - name: Read PR number
- id: pr
- run: echo "number=$(find . -name "pr_number.txt" | head -1 | xargs cat)" >> $GITHUB_OUTPUT
-
- - name: Read build log
- id: log
- run: |
- LOG=$(find . -name "build.log" | head -1 | xargs tail -20)
- echo "content<> $GITHUB_OUTPUT
- echo "$LOG" >> $GITHUB_OUTPUT
- echo "EOF" >> $GITHUB_OUTPUT
-
- - name: Deploy preview to gh-pages
- uses: peaceiris/actions-gh-pages@v4
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./html-preview
- destination_dir: previews/${{ steps.pr.outputs.number }}
- keep_files: true
- enable_jekyll: false
-
- - name: Post comment
- uses: actions/github-script@v7
- with:
- script: |
- const success = '${{ github.event.workflow_run.conclusion }}' === 'success';
- const icon = success ? '✅' : '❌';
- const status = success ? 'succeeded' : 'failed';
- const prNumber = ${{ steps.pr.outputs.number }};
- const owner = context.repo.owner;
- const repo = context.repo.repo;
- const previewUrl = `https://${owner}.github.io/${repo}/previews/${prNumber}/index.html`;
-
- const body = `### ${icon} Docs build ${status}
-
- ${success ? `📖 **[Preview the docs](${previewUrl})**` : ''}
-
-
- Build log (last 20 lines)
-
- \`\`\`
- ${{ steps.log.outputs.content }}
- \`\`\`
-
- `;
-
- github.rest.issues.createComment({
- owner,
- repo,
- issue_number: prNumber,
- body
- });
-
- cleanup:
- if: github.event_name == 'pull_request' && github.event.action == 'closed'
- runs-on: ubuntu-latest
- permissions:
- contents: write
-
- steps:
- - name: Check if gh-pages exists
- id: check
- run: |
- if git ls-remote --exit-code --heads https://github.com/${{ github.repository }}.git gh-pages; then
- echo "exists=true" >> $GITHUB_OUTPUT
- else
- echo "exists=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Checkout gh-pages
- if: steps.check.outputs.exists == 'true'
- uses: actions/checkout@v4
- with:
- ref: gh-pages
-
- - name: Remove preview folder
- if: steps.check.outputs.exists == 'true'
- run: |
- PR=${{ github.event.pull_request.number }}
- if [ -d "previews/$PR" ]; then
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
- git rm -rf "previews/$PR"
- git commit -m "chore: remove preview for PR #$PR"
- git push
- else
- echo "No preview folder found for PR #$PR, nothing to clean up."
- fi
\ No newline at end of file
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 000000000..fafcca811
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,24 @@
+version: 2
+
+build:
+ os: ubuntu-24.04
+ tools:
+ python: "3.12"
+
+ commands:
+ - git clone --depth 1 --branch v3.14.6 https://github.com/python/cpython venv/cpython
+ - pip install -r venv/cpython/Doc/requirements.txt
+ - mkdir -p venv/cpython/Doc/locales/fa/LC_MESSAGES
+ - cp --parents *.po venv/cpython/Doc/locales/fa/LC_MESSAGES/
+ - find */ -name "*.po" -not -path "venv/*" | xargs -I{} cp --parents {} venv/cpython/Doc/locales/fa/LC_MESSAGES/
+ - find venv/cpython/Doc/locales/fa/LC_MESSAGES -name "*.po" | xargs python3 scripts/strip_fuzzy.py
+ - find venv/cpython/Doc/locales/fa/LC_MESSAGES -name "*.po" | while read f; do python venv/cpython/Tools/i18n/msgfmt.py -o "${f%.po}.mo" "$f"; done
+ - python -m sphinx -T -j auto -b html
+ -d $READTHEDOCS_OUTPUT/doctrees
+ -D language=fa
+ -D locale_dirs=locales
+ -D gettext_compact=0
+ -D gettext_allow_fuzzy_translations=1
+ -D html_theme_options.is_rtl=1
+ venv/cpython/Doc
+ $READTHEDOCS_OUTPUT/html
\ No newline at end of file
diff --git a/scripts/strip_fuzzy.py b/scripts/strip_fuzzy.py
new file mode 100644
index 000000000..1af9342b7
--- /dev/null
+++ b/scripts/strip_fuzzy.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+"""Remove '#, fuzzy' marker lines from .po files.
+
+CPython's Tools/i18n/msgfmt.py treats a stray fuzzy flag on the file
+header as applying to every entry in the file, silently producing an
+empty .mo catalog. Since our translations are complete (not actually
+rough drafts), we strip the marker before compiling.
+"""
+import sys
+
+
+def strip_fuzzy(path: str) -> None:
+ with open(path, encoding="utf-8") as f:
+ lines = f.readlines()
+
+ kept = [line for line in lines if not line.lstrip().startswith("#, fuzzy")]
+
+ if kept != lines:
+ with open(path, "w", encoding="utf-8") as f:
+ f.writelines(kept)
+
+
+def main() -> None:
+ for path in sys.argv[1:]:
+ strip_fuzzy(path)
+
+
+if __name__ == "__main__":
+ main()