Skip to content

Sync with CPython

Sync with CPython #2

name: Sync with CPython
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
inputs:
cpython_tag:
description: 'CPython tag to sync against (e.g. v3.14.6)'
required: false
default: 'v3.14.6'
permissions:
contents: write
issues: write
concurrency:
group: sync
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout translation repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install gettext
run: sudo apt-get install -y gettext
- name: Install Python dependencies
run: pip install sphinx sphinx-intl
- name: Checkout CPython docs only (sparse)
run: |
git clone \
--depth 1 \
--filter=blob:none \
--sparse \
--branch ${{ github.event.inputs.cpython_tag || 'v3.14.6' }} \
https://github.com/python/cpython.git \
.cpython-src
cd .cpython-src
git sparse-checkout set Doc Include
- name: Install CPython doc dependencies
run: |
python -m venv .cpython-src/Doc/venv
.cpython-src/Doc/venv/bin/pip install \
-r .cpython-src/Doc/requirements.txt
- name: Build .pot templates
run: |
cd .cpython-src/Doc
./venv/bin/sphinx-build \
-b gettext \
. \
../../.pot-templates
- name: Merge .pot into .po files
run: |
find .pot-templates -name "*.pot" | while read f; do
rel="${f#.pot-templates/}"
po="${rel%.pot}.po"
if [ -f "$po" ]; then
msgmerge --update --backup=off --no-location --no-wrap "$po" "$f"
fi
done
- name: Ensure translation label exists
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh label create "translation" \
--color "0075ca" \
--description "Translation review needed" \
--repo ${{ github.repository }} \
2>/dev/null || true
- name: Open issue for fuzzy strings
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CPYTHON_TAG: ${{ github.event.inputs.cpython_tag || 'v3.14.6' }}
run: |
tmpfile=$(mktemp)
while IFS= read -r f; do
fuzzy=$(msgattrib --only-fuzzy --no-obsolete "$f" 2>/dev/null)
if [ -n "$fuzzy" ]; then
entries=$(echo "$fuzzy" | awk '
/^msgid / {
first=$0; msg=$0"\n"; lines=1; incapture=1; next
}
incapture && /^"/ {
msg = msg $0 "\n"; lines++; next
}
incapture && /^msgstr/ {
incapture=0
if (!(first == "msgid \"\"" && lines==1)) {
printf "- %s\n", msg
}
next
}
')
count=$(echo "$entries" | grep -c '^- ' || echo 0)
if [ "$count" -gt 0 ]; then
echo "### $f ($count fuzzy)" >> "$tmpfile"
echo "$entries" | head -20 >> "$tmpfile"
echo "" >> "$tmpfile"
fi
fi
done < <(find . -name "*.po" \
-not -path "./.git/*" \
-not -path "./.cpython-src/*" \
-not -path "./.pot-templates/*")
if [ -s "$tmpfile" ]; then
gh issue create \
--title "🔍 Fuzzy strings need review after CPython sync ($(date +%Y-%m-%d))" \
--body "$(cat "$tmpfile")
Triggered by sync with \`$CPYTHON_TAG\`." \
--label "translation" \
--repo ${{ github.repository }}
fi
rm -f "$tmpfile"
- name: Validate .po files
run: |
tmpfile=$(mktemp)
find . -name "*.po" \
-not -path "./.git/*" \
-not -path "./.cpython-src/*" \
-not -path "./.pot-templates/*" | while read f; do
msgfmt --check "$f" -o /dev/null || echo "FAIL: $f" >> "$tmpfile"
done
if [ -s "$tmpfile" ]; then
cat "$tmpfile"
rm -f "$tmpfile"
exit 1
fi
rm -f "$tmpfile"
- name: Clean up scratch files
run: rm -rf .cpython-src .pot-templates
- name: Stage changes
run: git add --all
- name: Unstage POT-Creation-Date-only changes
run: |
git diff --staged --name-only | while read f; do
if git diff --staged -U0 -- "$f" \
| grep '^[+-]' \
| grep -v '^[+-][+-][+-]' \
| grep -qv 'POT-Creation-Date'; then
: # has real changes, keep staged
else
git restore --staged "$f"
git restore "$f"
fi
done
- name: Commit if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if git diff --staged --quiet; then
echo "Nothing to commit, skipping."
exit 0
fi
git commit -m \
"chore: sync msgids with CPython ${{ github.event.inputs.cpython_tag || 'v3.14.6' }}"
git push