From 41397113f4c11c4b6bb9a49463232e41526dfb53 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Mon, 2 Sep 2019 02:26:25 +0800
Subject: [PATCH 01/56] Update for Python 3.8

---
 README.rst | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/README.rst b/README.rst
index bd2e4765a..4425a600b 100644
--- a/README.rst
+++ b/README.rst
@@ -12,11 +12,16 @@ Maintained versions:
    * - Version
      - Build status
      - Translation progress
+   * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
+     - .. image:: https://travis-ci.org/python/python-docs-zh-cn.svg?branch=3.8-staging
+          :target: https://travis-ci.org/python/python-docs-zh-cn
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/newest
+          :target: https://www.transifex.com/python-doc/python-newest/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://travis-ci.org/python/python-docs-zh-cn.svg?branch=3.7-staging
           :target: https://travis-ci.org/python/python-docs-zh-cn
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http%3A%2F%2Fgce.zhsj.me%2Fpython/newest
-          :target: https://www.transifex.com/python-doc/python-newest/
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37
+          :target: https://www.transifex.com/python-doc/python-37/
 
 Documentation Contribution Agreement
 ------------------------------------

From d499d11a6a1484e48f28f398909082fabfb9da07 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Tue, 8 Oct 2019 12:18:35 +0800
Subject: [PATCH 02/56] Add github workflows to update translation

---
 .github/actions/commit/Dockerfile    | 10 ++++++++
 .github/actions/commit/action.yml    |  5 ++++
 .github/actions/commit/entrypoint.sh | 13 ++++++++++
 .github/actions/update/Dockerfile    | 12 ++++++++++
 .github/actions/update/action.yml    | 16 +++++++++++++
 .github/actions/update/entrypoint.sh | 36 ++++++++++++++++++++++++++++
 .github/workflows/python-37.yml      | 25 +++++++++++++++++++
 .github/workflows/python-38.yml      | 25 +++++++++++++++++++
 README.rst                           | 10 ++++----
 9 files changed, 147 insertions(+), 5 deletions(-)
 create mode 100644 .github/actions/commit/Dockerfile
 create mode 100644 .github/actions/commit/action.yml
 create mode 100755 .github/actions/commit/entrypoint.sh
 create mode 100644 .github/actions/update/Dockerfile
 create mode 100644 .github/actions/update/action.yml
 create mode 100755 .github/actions/update/entrypoint.sh
 create mode 100644 .github/workflows/python-37.yml
 create mode 100644 .github/workflows/python-38.yml

diff --git a/.github/actions/commit/Dockerfile b/.github/actions/commit/Dockerfile
new file mode 100644
index 000000000..027660ad1
--- /dev/null
+++ b/.github/actions/commit/Dockerfile
@@ -0,0 +1,10 @@
+FROM debian:stable-slim
+
+RUN set -ex \
+    && apt-get update \
+    && apt-get install -y --no-install-recommends git ca-certificates \
+    && apt-get clean \
+    && rm -rf /var/lib/apt/lists/*
+
+ADD entrypoint.sh /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
diff --git a/.github/actions/commit/action.yml b/.github/actions/commit/action.yml
new file mode 100644
index 000000000..ea2b045e5
--- /dev/null
+++ b/.github/actions/commit/action.yml
@@ -0,0 +1,5 @@
+name: Commit Translation
+description: Commit translation in git repo and push to remote
+runs:
+  using: 'docker'
+  image: 'Dockerfile'
diff --git a/.github/actions/commit/entrypoint.sh b/.github/actions/commit/entrypoint.sh
new file mode 100755
index 000000000..86f07cf95
--- /dev/null
+++ b/.github/actions/commit/entrypoint.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -ex
+
+cd docs || exit 1
+git config user.email "github-actions[bot]@users.noreply.github.com"
+git config user.name "github-actions[bot]"
+if git status -s|grep '\.po'; then
+  git add .
+  git commit -m '[po] auto sync'
+  header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
+  git -c http.extraheader="AUTHORIZATION: basic $header" push
+fi
diff --git a/.github/actions/update/Dockerfile b/.github/actions/update/Dockerfile
new file mode 100644
index 000000000..717ef9ffd
--- /dev/null
+++ b/.github/actions/update/Dockerfile
@@ -0,0 +1,12 @@
+FROM python:3-slim
+
+RUN set -ex \
+    && pip install transifex-client \
+    && rm -rf ~/.cache \
+    && apt-get update \
+    && apt-get install -y --no-install-recommends git make \
+    && apt-get clean \
+    && rm -rf /var/lib/apt/lists/*
+
+ADD entrypoint.sh /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
diff --git a/.github/actions/update/action.yml b/.github/actions/update/action.yml
new file mode 100644
index 000000000..5ceecc839
--- /dev/null
+++ b/.github/actions/update/action.yml
@@ -0,0 +1,16 @@
+name: Update Translation
+description: Update translation of Python documentation from Transifex
+inputs:
+  pythonVersion:
+    description: Python Version
+    required: true
+  locale:
+    description: Locale Name
+    required: true
+    default: zh_CN
+runs:
+  using: 'docker'
+  image: 'Dockerfile'
+  args:
+    - ${{ inputs.pythonVersion }}
+    - ${{ inputs.locale }}
diff --git a/.github/actions/update/entrypoint.sh b/.github/actions/update/entrypoint.sh
new file mode 100755
index 000000000..c99be9c62
--- /dev/null
+++ b/.github/actions/update/entrypoint.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -ex
+
+pythonVersion="$1"
+locale="$2"
+
+echo "Python Version: $pythonVersion"
+echo "Locale: $locale"
+
+cur=$(pwd)
+git clone --depth=1 --branch="$pythonVersion" https://github.com/python/cpython cpython
+git clone --branch="$pythonVersion" https://github.com/"$GITHUB_REPOSITORY" docs
+
+if [[ -n "$TRANSIFEX_APIKEY" ]]; then
+  cat > ~/.transifexrc << EOF
+[https://www.transifex.com]
+api_hostname = https://api.transifex.com
+hostname = https://www.transifex.com
+password = $TRANSIFEX_APIKEY
+username = api
+EOF
+fi
+
+# Pull Transifex translation
+pushd docs || exit 1
+tx pull --force --parallel --language "$locale"
+popd || exit 1
+
+# Test building docs
+pushd cpython/Doc || exit 1
+mkdir -p locales/"$locale"/
+ln -sfn "$cur"/docs locales/"$locale"/LC_MESSAGES
+make venv
+make html SPHINXOPTS="-D language=$locale -D gettext_compact=0 -j4 -W --keep-going"
+popd || exit 1
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
new file mode 100644
index 000000000..35099bdd9
--- /dev/null
+++ b/.github/workflows/python-37.yml
@@ -0,0 +1,25 @@
+name: python-37
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "38 * * * *"
+
+jobs:
+  update:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+        with:
+          fetch-depth: 1
+      - uses: ./.github/actions/update
+        with:
+          pythonVersion: "3.7"
+          locale: zh_CN
+        env:
+          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+      - uses: ./.github/actions/commit
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
new file mode 100644
index 000000000..782a3125b
--- /dev/null
+++ b/.github/workflows/python-38.yml
@@ -0,0 +1,25 @@
+name: python-38
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "18 * * * *"
+
+jobs:
+  update:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+        with:
+          fetch-depth: 1
+      - uses: ./.github/actions/update
+        with:
+          pythonVersion: "3.8"
+          locale: zh_CN
+        env:
+          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+      - uses: ./.github/actions/commit
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.rst b/README.rst
index 4425a600b..fc3b74b22 100644
--- a/README.rst
+++ b/README.rst
@@ -10,16 +10,16 @@ Maintained versions:
    :header-rows: 1
 
    * - Version
-     - Build status
+     - Sync status
      - Translation progress
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
-     - .. image:: https://travis-ci.org/python/python-docs-zh-cn.svg?branch=3.8-staging
-          :target: https://travis-ci.org/python/python-docs-zh-cn
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/newest
           :target: https://www.transifex.com/python-doc/python-newest/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
-     - .. image:: https://travis-ci.org/python/python-docs-zh-cn.svg?branch=3.7-staging
-          :target: https://travis-ci.org/python/python-docs-zh-cn
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37
           :target: https://www.transifex.com/python-doc/python-37/
 

From 76451e78b819a3fb3fcd46aee5f61fe12f703458 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Tue, 8 Oct 2019 23:32:37 +0800
Subject: [PATCH 03/56] Refactor github actions

+ just use shell scripts, not docker image.
+ rewrite transifex pull command to speed up.
+ show error message with logging commands.
---
 .github/actions/commit/Dockerfile    | 10 --------
 .github/actions/commit/action.yml    |  5 ----
 .github/actions/commit/entrypoint.sh | 13 ----------
 .github/actions/update/Dockerfile    | 12 ---------
 .github/actions/update/action.yml    | 16 ------------
 .github/actions/update/entrypoint.sh | 36 --------------------------
 .github/scripts/build.sh             | 17 +++++++++++++
 .github/scripts/commit.sh            | 15 +++++++++++
 .github/scripts/prepare.sh           | 11 ++++++++
 .github/scripts/transifex_pull.py    | 38 ++++++++++++++++++++++++++++
 .github/scripts/update.sh            | 18 +++++++++++++
 .github/workflows/python-37.yml      | 18 ++++++++-----
 .github/workflows/python-38.yml      | 18 ++++++++-----
 13 files changed, 123 insertions(+), 104 deletions(-)
 delete mode 100644 .github/actions/commit/Dockerfile
 delete mode 100644 .github/actions/commit/action.yml
 delete mode 100755 .github/actions/commit/entrypoint.sh
 delete mode 100644 .github/actions/update/Dockerfile
 delete mode 100644 .github/actions/update/action.yml
 delete mode 100755 .github/actions/update/entrypoint.sh
 create mode 100755 .github/scripts/build.sh
 create mode 100755 .github/scripts/commit.sh
 create mode 100755 .github/scripts/prepare.sh
 create mode 100755 .github/scripts/transifex_pull.py
 create mode 100755 .github/scripts/update.sh

diff --git a/.github/actions/commit/Dockerfile b/.github/actions/commit/Dockerfile
deleted file mode 100644
index 027660ad1..000000000
--- a/.github/actions/commit/Dockerfile
+++ /dev/null
@@ -1,10 +0,0 @@
-FROM debian:stable-slim
-
-RUN set -ex \
-    && apt-get update \
-    && apt-get install -y --no-install-recommends git ca-certificates \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/*
-
-ADD entrypoint.sh /entrypoint.sh
-ENTRYPOINT ["/entrypoint.sh"]
diff --git a/.github/actions/commit/action.yml b/.github/actions/commit/action.yml
deleted file mode 100644
index ea2b045e5..000000000
--- a/.github/actions/commit/action.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-name: Commit Translation
-description: Commit translation in git repo and push to remote
-runs:
-  using: 'docker'
-  image: 'Dockerfile'
diff --git a/.github/actions/commit/entrypoint.sh b/.github/actions/commit/entrypoint.sh
deleted file mode 100755
index 86f07cf95..000000000
--- a/.github/actions/commit/entrypoint.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-cd docs || exit 1
-git config user.email "github-actions[bot]@users.noreply.github.com"
-git config user.name "github-actions[bot]"
-if git status -s|grep '\.po'; then
-  git add .
-  git commit -m '[po] auto sync'
-  header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
-  git -c http.extraheader="AUTHORIZATION: basic $header" push
-fi
diff --git a/.github/actions/update/Dockerfile b/.github/actions/update/Dockerfile
deleted file mode 100644
index 717ef9ffd..000000000
--- a/.github/actions/update/Dockerfile
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM python:3-slim
-
-RUN set -ex \
-    && pip install transifex-client \
-    && rm -rf ~/.cache \
-    && apt-get update \
-    && apt-get install -y --no-install-recommends git make \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/*
-
-ADD entrypoint.sh /entrypoint.sh
-ENTRYPOINT ["/entrypoint.sh"]
diff --git a/.github/actions/update/action.yml b/.github/actions/update/action.yml
deleted file mode 100644
index 5ceecc839..000000000
--- a/.github/actions/update/action.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: Update Translation
-description: Update translation of Python documentation from Transifex
-inputs:
-  pythonVersion:
-    description: Python Version
-    required: true
-  locale:
-    description: Locale Name
-    required: true
-    default: zh_CN
-runs:
-  using: 'docker'
-  image: 'Dockerfile'
-  args:
-    - ${{ inputs.pythonVersion }}
-    - ${{ inputs.locale }}
diff --git a/.github/actions/update/entrypoint.sh b/.github/actions/update/entrypoint.sh
deleted file mode 100755
index c99be9c62..000000000
--- a/.github/actions/update/entrypoint.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-pythonVersion="$1"
-locale="$2"
-
-echo "Python Version: $pythonVersion"
-echo "Locale: $locale"
-
-cur=$(pwd)
-git clone --depth=1 --branch="$pythonVersion" https://github.com/python/cpython cpython
-git clone --branch="$pythonVersion" https://github.com/"$GITHUB_REPOSITORY" docs
-
-if [[ -n "$TRANSIFEX_APIKEY" ]]; then
-  cat > ~/.transifexrc << EOF
-[https://www.transifex.com]
-api_hostname = https://api.transifex.com
-hostname = https://www.transifex.com
-password = $TRANSIFEX_APIKEY
-username = api
-EOF
-fi
-
-# Pull Transifex translation
-pushd docs || exit 1
-tx pull --force --parallel --language "$locale"
-popd || exit 1
-
-# Test building docs
-pushd cpython/Doc || exit 1
-mkdir -p locales/"$locale"/
-ln -sfn "$cur"/docs locales/"$locale"/LC_MESSAGES
-make venv
-make html SPHINXOPTS="-D language=$locale -D gettext_compact=0 -j4 -W --keep-going"
-popd || exit 1
diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
new file mode 100755
index 000000000..bbf4eb060
--- /dev/null
+++ b/.github/scripts/build.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+set -o pipefail
+
+error() {
+  while read -r line; do
+    echo
+    echo ::error::"$line"
+  done
+}
+
+cd cpython/Doc || exit 1
+mkdir -p locales/"$LOCALE"/
+ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
+make venv
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)
diff --git a/.github/scripts/commit.sh b/.github/scripts/commit.sh
new file mode 100755
index 000000000..ae7d04096
--- /dev/null
+++ b/.github/scripts/commit.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -ex
+
+cd docs || exit 1
+git config user.email "github-actions[bot]@users.noreply.github.com"
+git config user.name "github-actions[bot]"
+if ! git status -s|grep '\.po'; then
+  echo "Nothing to commit"
+  exit 0
+fi
+git add .
+git commit -m '[po] auto sync'
+header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
+git -c http.extraheader="AUTHORIZATION: basic $header" push
diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
new file mode 100755
index 000000000..d16dbc056
--- /dev/null
+++ b/.github/scripts/prepare.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -ex
+
+git clone --depth=1 --branch="$VERSION" https://github.com/python/cpython cpython
+git clone --branch="$VERSION" https://github.com/"$GITHUB_REPOSITORY" docs
+
+pip3 install --user setuptools
+pip3 install --user transifex-client
+sudo apt-get update
+sudo apt-get install -y python3-venv
diff --git a/.github/scripts/transifex_pull.py b/.github/scripts/transifex_pull.py
new file mode 100755
index 000000000..66c4046d9
--- /dev/null
+++ b/.github/scripts/transifex_pull.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+
+from txclib import project
+from txclib.utils import perform_parallel_requests
+
+
+def pull(path, lang):
+    skip_decode = False
+    params = {}
+    parallel = True
+
+    prj = project.Project(path)
+    resource_list = prj.get_chosen_resources([])
+    for resource in resource_list:
+        project_slug, resource_slug = resource.split(".", 1)
+        host = prj.get_resource_host(resource)
+        prj._set_url_info(host=host, project=project_slug, resource=resource_slug)
+
+        files = prj.get_resource_files(resource)
+        url = prj._get_url_by_pull_mode(None)
+        local_file = files.get(lang)
+        prj.do_url_request(
+            url,
+            language=lang,
+            skip_decode=skip_decode,
+            params=params,
+            parallel=parallel,
+            callback=prj._save_file,
+            callback_args={"local_file": local_file},
+        )
+
+    perform_parallel_requests()
+
+
+if __name__ == "__main__":
+    import os
+
+    pull(os.getcwd(), os.getenv("LOCALE", "zh_CN"))
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
new file mode 100755
index 000000000..544a31ae5
--- /dev/null
+++ b/.github/scripts/update.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -ex
+
+script_dir="$(dirname "$(realpath "$0")")"
+
+if [[ -n "$TRANSIFEX_APIKEY" ]]; then
+  cat > ~/.transifexrc << EOF
+[https://www.transifex.com]
+api_hostname = https://api.transifex.com
+hostname = https://www.transifex.com
+password = $TRANSIFEX_APIKEY
+username = api
+EOF
+fi
+
+cd docs || exit 1
+"$script_dir"/transifex_pull.py
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index 35099bdd9..cb34a052d 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -8,18 +8,24 @@ on:
     - cron: "38 * * * *"
 
 jobs:
-  update:
+  sync:
     runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.7"
     steps:
       - uses: actions/checkout@v1
         with:
           fetch-depth: 1
-      - uses: ./.github/actions/update
-        with:
-          pythonVersion: "3.7"
-          locale: zh_CN
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
         env:
           TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
-      - uses: ./.github/actions/commit
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index 782a3125b..f9dbfc1b7 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -8,18 +8,24 @@ on:
     - cron: "18 * * * *"
 
 jobs:
-  update:
+  sync:
     runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.8"
     steps:
       - uses: actions/checkout@v1
         with:
           fetch-depth: 1
-      - uses: ./.github/actions/update
-        with:
-          pythonVersion: "3.8"
-          locale: zh_CN
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
         env:
           TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
-      - uses: ./.github/actions/commit
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

From f17823e0d2539a6a815097a76d6abe3c2f5b4fc0 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Tue, 7 Apr 2020 17:13:14 +0800
Subject: [PATCH 04/56] Fix broken CI caused by Sphinx 3.0

Closes: #107
---
 .github/scripts/build.sh | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index bbf4eb060..a71cb350d 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,5 +13,11 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-make venv
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)
+
+# make venv
+# create venv manually, so we can specify sphinx version
+VENVDIR=./venv
+python3 -m venv $VENVDIR
+$VENVDIR/bin/python3 -m pip install -U pip setuptools
+$VENVDIR/bin/python3 -m pip install -U "Sphinx<3.0" blurb python-docs-theme
+make html VENVDIR=$VENVDIR SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)

From 3068bdd56843a7fdd7c5cf2a4f21e8228793e782 Mon Sep 17 00:00:00 2001
From: zhsj <i@zhsj.me>
Date: Mon, 20 Apr 2020 16:24:11 +0800
Subject: [PATCH 05/56] Use same build dependencies from docsbuild-scripts

Hopefully this can fix unexpected build errors when sphinx releases new versions.
---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index a71cb350d..45440fcaf 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -19,5 +19,5 @@ ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 VENVDIR=./venv
 python3 -m venv $VENVDIR
 $VENVDIR/bin/python3 -m pip install -U pip setuptools
-$VENVDIR/bin/python3 -m pip install -U "Sphinx<3.0" blurb python-docs-theme
+$VENVDIR/bin/python3 -m pip install -r https://raw.githubusercontent.com/python/docsbuild-scripts/master/requirements.txt
 make html VENVDIR=$VENVDIR SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)

From 1cddd54fd4f8d9ba8454e3fe8cc3b11bbb0a2ed3 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Sun, 31 May 2020 20:54:57 +0800
Subject: [PATCH 06/56] Add Python 3.9

---
 .github/workflows/python-39.yml | 31 +++++++++++++++++++++++++++++++
 README.rst                      |  9 +++++++--
 2 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 .github/workflows/python-39.yml

diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
new file mode 100644
index 000000000..8a1bd3599
--- /dev/null
+++ b/.github/workflows/python-39.yml
@@ -0,0 +1,31 @@
+name: python-39
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "58 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.9"
+    steps:
+      - uses: actions/checkout@v1
+        with:
+          fetch-depth: 1
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.rst b/README.rst
index fc3b74b22..f9c9694c3 100644
--- a/README.rst
+++ b/README.rst
@@ -12,11 +12,16 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/newest
+          :target: https://www.transifex.com/python-doc/python-newest/
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/newest
-          :target: https://www.transifex.com/python-doc/python-newest/
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
+          :target: https://www.transifex.com/python-doc/python-38/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37

From 15d62bbff6534faca78e7f1c1876e77c230bfff8 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Mon, 1 Jun 2020 02:53:18 +0800
Subject: [PATCH 07/56] Add generate_tx_config.py script

---
 .github/scripts/generate_tx_config.py | 76 +++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100755 .github/scripts/generate_tx_config.py

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
new file mode 100755
index 000000000..0e72833f1
--- /dev/null
+++ b/.github/scripts/generate_tx_config.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+import glob
+import json
+import os
+import re
+import sys
+import urllib.request
+
+
+def list_resources(token, project):
+    auth_handler = urllib.request.HTTPBasicAuthHandler()
+    auth_handler.add_password(
+        realm="api", uri="https://api.transifex.com/", user="api", passwd=token
+    )
+    opener = urllib.request.build_opener(auth_handler)
+    urllib.request.install_opener(opener)
+    next_ = (
+        "https://api.transifex.com/organizations/python-doc/projects/"
+        + project
+        + "/resources/"
+    )
+    resources = []
+    while True:
+        resp = urllib.request.urlopen(next_)
+        result = json.loads(resp.read().decode("utf-8"))
+        resources.extend([i["slug"] for i in result])
+        link = re.findall('<([^<]*)>; rel="next"', resp.getheader("Link") or "")
+        if not link:
+            break
+        next_ = link[0]
+    return resources
+
+
+def render_config(doc_dir, project, resources):
+    os.chdir(doc_dir)
+    tpl = """
+
+[{project}.{resource}]
+trans.zh_CN = {filename}
+source_lang = en
+type = PO"""
+    conf = """[main]
+host = https://www.transifex.com"""
+    for resource in sorted(resources):
+        if resource == "glossary_":
+            filename = "glossary.po"
+        elif resource == "sphinx":
+            filename = "sphinx.po"
+        else:
+            pattern = resource.replace("--", "/").replace("_", "?")
+            matches = glob.glob(pattern + ".rst")
+            if len(matches) == 0:
+                print("missing", resource, file=sys.stderr)
+                continue
+            elif len(matches) == 1:
+                filename = matches[0].replace(".rst", ".po")
+            else:
+                print("multi match", resource, pattern, matches, file=sys.stderr)
+        conf += tpl.format(project=project, resource=resource, filename=filename)
+    return conf
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--token")
+    parser.add_argument("--project")
+    parser.add_argument("--doc-dir")
+    args = parser.parse_args()
+
+    resources = list_resources(args.token, args.project)
+    conf = render_config(args.doc_dir, args.project, resources)
+    print(conf)
+
+# vim: set et ts=4 sw=4 sts=4:

From 1a1312a83142ba877f1b756a60aa81077d8ddbb1 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Thu, 25 Jun 2020 22:45:25 +0800
Subject: [PATCH 08/56] Revert building venv manually

Closes: #123
---
 .github/scripts/build.sh | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 45440fcaf..bbf4eb060 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,11 +13,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-
-# make venv
-# create venv manually, so we can specify sphinx version
-VENVDIR=./venv
-python3 -m venv $VENVDIR
-$VENVDIR/bin/python3 -m pip install -U pip setuptools
-$VENVDIR/bin/python3 -m pip install -r https://raw.githubusercontent.com/python/docsbuild-scripts/master/requirements.txt
-make html VENVDIR=$VENVDIR SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)
+make venv
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)

From 7a7064ef102efec1b348f88ab5d52f687b199b6f Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Wed, 9 Jun 2021 11:02:10 +0800
Subject: [PATCH 09/56] Fix python-39 badge

The project is renamed on transifex.
---
 README.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.rst b/README.rst
index f9c9694c3..5f3cd5949 100644
--- a/README.rst
+++ b/README.rst
@@ -15,8 +15,8 @@ Maintained versions:
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/newest
-          :target: https://www.transifex.com/python-doc/python-newest/
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/39
+          :target: https://www.transifex.com/python-doc/python-39/
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38

From 2fd4a276ee5b5e0168fd7de58faf347df658566f Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Sun, 1 Aug 2021 23:05:56 +0800
Subject: [PATCH 10/56] Add Python 3.10

---
 .github/workflows/python-310.yml | 29 +++++++++++++++++++++++++++++
 .github/workflows/python-37.yml  |  6 ++----
 .github/workflows/python-38.yml  |  6 ++----
 .github/workflows/python-39.yml  |  6 ++----
 README.rst                       |  5 +++++
 5 files changed, 40 insertions(+), 12 deletions(-)
 create mode 100644 .github/workflows/python-310.yml

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
new file mode 100644
index 000000000..54037983e
--- /dev/null
+++ b/.github/workflows/python-310.yml
@@ -0,0 +1,29 @@
+name: python-310
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "8 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.10"
+    steps:
+      - uses: actions/checkout@v2
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index cb34a052d..c35d61d2b 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "38 * * * *"
+    - cron: "53 * * * *"
 
 jobs:
   sync:
@@ -14,9 +14,7 @@ jobs:
       LOCALE: zh_CN
       VERSION: "3.7"
     steps:
-      - uses: actions/checkout@v1
-        with:
-          fetch-depth: 1
+      - uses: actions/checkout@v2
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index f9dbfc1b7..a99f0e20e 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "18 * * * *"
+    - cron: "38 * * * *"
 
 jobs:
   sync:
@@ -14,9 +14,7 @@ jobs:
       LOCALE: zh_CN
       VERSION: "3.8"
     steps:
-      - uses: actions/checkout@v1
-        with:
-          fetch-depth: 1
+      - uses: actions/checkout@v2
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 8a1bd3599..76a6793bb 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "58 * * * *"
+    - cron: "23 * * * *"
 
 jobs:
   sync:
@@ -14,9 +14,7 @@ jobs:
       LOCALE: zh_CN
       VERSION: "3.9"
     steps:
-      - uses: actions/checkout@v1
-        with:
-          fetch-depth: 1
+      - uses: actions/checkout@v2
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update
diff --git a/README.rst b/README.rst
index 5f3cd5949..4ff062bc4 100644
--- a/README.rst
+++ b/README.rst
@@ -12,6 +12,11 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
+          :target: https://www.transifex.com/python-doc/python-39/
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39

From 065e4c9d87833baa6065ea7f905c6ecc1876c4d4 Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Wed, 3 Nov 2021 00:27:36 +0800
Subject: [PATCH 11/56] Pin docutils version when build with Sphinx 2.3.1

Closes: #227
---
 .github/scripts/build.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index bbf4eb060..e29f73036 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,5 +13,8 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
+
+# Hotfix for #227
+sed -i 's|Sphinx==2.3.1|Sphinx==2.3.1 "docutils<0.18"|g'  Makefile
 make venv
 make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)

From 4dac60f469b2bfa9c0d2e067f5087fae1d2a059c Mon Sep 17 00:00:00 2001
From: Shengjing Zhu <i@zhsj.me>
Date: Fri, 17 Jun 2022 10:49:21 +0800
Subject: [PATCH 12/56] Revert "Pin docutils version when build with Sphinx
 2.3.1"

This reverts commit 065e4c9d87833baa6065ea7f905c6ecc1876c4d4.

Closes: #258
---
 .github/scripts/build.sh | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index e29f73036..bbf4eb060 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,8 +13,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-
-# Hotfix for #227
-sed -i 's|Sphinx==2.3.1|Sphinx==2.3.1 "docutils<0.18"|g'  Makefile
 make venv
 make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)

From a67273b9fb80157109304f5c5ef6222e9a4fce8b Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Mon, 27 Feb 2023 16:01:18 +0800
Subject: [PATCH 13/56] Update to Python 3.11

---
 .github/scripts/generate_tx_config.py | 119 ++++++++++++--------------
 .github/scripts/prepare.sh            |   2 +-
 .github/scripts/transifex_pull.py     |  38 --------
 .github/scripts/update.sh             |  15 +---
 .github/workflows/python-310.yml      |   2 +-
 .github/workflows/python-311.yml      |  29 +++++++
 .github/workflows/python-37.yml       |   2 +-
 .github/workflows/python-38.yml       |   2 +-
 .github/workflows/python-39.yml       |   2 +-
 README.rst                            |   3 +
 10 files changed, 93 insertions(+), 121 deletions(-)
 delete mode 100755 .github/scripts/transifex_pull.py
 create mode 100644 .github/workflows/python-311.yml

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
index 0e72833f1..b21e099ee 100755
--- a/.github/scripts/generate_tx_config.py
+++ b/.github/scripts/generate_tx_config.py
@@ -1,76 +1,67 @@
-#!/usr/bin/env python3
-import glob
-import json
-import os
+"""Please note that this script requires a Transifex API token to run."""
+import subprocess
+from functools import partial
+from pathlib import Path
 import re
-import sys
-import urllib.request
 
+run = partial(subprocess.run, check=True)
 
-def list_resources(token, project):
-    auth_handler = urllib.request.HTTPBasicAuthHandler()
-    auth_handler.add_password(
-        realm="api", uri="https://api.transifex.com/", user="api", passwd=token
+
+def init_project():
+    run(["tx", "init"])
+
+
+def add_files(version: str):
+    run(
+        [
+            "tx",
+            "add",
+            "remote",
+            "--file-filter",
+            "trans/<lang>/<resource_slug>.<ext>",
+            f"https://www.transifex.com/python-doc/{version}/dashboard/",
+        ]
     )
-    opener = urllib.request.build_opener(auth_handler)
-    urllib.request.install_opener(opener)
-    next_ = (
-        "https://api.transifex.com/organizations/python-doc/projects/"
-        + project
-        + "/resources/"
+
+
+FILTER_PATTERN = re.compile(
+    r"^(?P<prefix>file_filter( *)=( *))(?P<resource>.+)$", re.MULTILINE
+)
+
+
+def name_replacer(match: re.Match[str]):
+    prefix, resource = match.group("prefix", "resource")
+    override_prefix = prefix.replace("file_filter", "trans.zh_CN")
+    override_resource = (
+        resource.replace("trans/<lang>/", "")
+        .replace("--", "/")
+        .replace("glossary_", "glossary")
+        .replace("_", ".")
     )
-    resources = []
-    while True:
-        resp = urllib.request.urlopen(next_)
-        result = json.loads(resp.read().decode("utf-8"))
-        resources.extend([i["slug"] for i in result])
-        link = re.findall('<([^<]*)>; rel="next"', resp.getheader("Link") or "")
-        if not link:
-            break
-        next_ = link[0]
-    return resources
-
-
-def render_config(doc_dir, project, resources):
-    os.chdir(doc_dir)
-    tpl = """
-
-[{project}.{resource}]
-trans.zh_CN = {filename}
-source_lang = en
-type = PO"""
-    conf = """[main]
-host = https://www.transifex.com"""
-    for resource in sorted(resources):
-        if resource == "glossary_":
-            filename = "glossary.po"
-        elif resource == "sphinx":
-            filename = "sphinx.po"
-        else:
-            pattern = resource.replace("--", "/").replace("_", "?")
-            matches = glob.glob(pattern + ".rst")
-            if len(matches) == 0:
-                print("missing", resource, file=sys.stderr)
-                continue
-            elif len(matches) == 1:
-                filename = matches[0].replace(".rst", ".po")
-            else:
-                print("multi match", resource, pattern, matches, file=sys.stderr)
-        conf += tpl.format(project=project, resource=resource, filename=filename)
-    return conf
+    return f"{prefix}{resource}\n{override_prefix}{override_resource}"
+
+
+def patch_config():
+    tx_config_path = Path(".tx", "config")
+
+    config_content = tx_config_path.read_text("utf-8")
+    config_content = FILTER_PATTERN.sub(name_replacer, config_content)
+    tx_config_path.write_text(config_content, "utf-8")
 
 
 if __name__ == "__main__":
-    import argparse
+    from argparse import ArgumentParser
+    import os
+
+    parser = ArgumentParser()
 
-    parser = argparse.ArgumentParser()
     parser.add_argument("--token")
-    parser.add_argument("--project")
-    parser.add_argument("--doc-dir")
-    args = parser.parse_args()
+    parser.add_argument("--version")
+
+    params = parser.parse_args()
 
-    resources = list_resources(args.token, args.project)
-    conf = render_config(args.doc_dir, args.project, resources)
-    print(conf)
+    os.environ["TX_TOKEN"] = params.token
 
-# vim: set et ts=4 sw=4 sts=4:
+    init_project()
+    add_files(params.version)
+    patch_config()
diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
index d16dbc056..cf1326646 100755
--- a/.github/scripts/prepare.sh
+++ b/.github/scripts/prepare.sh
@@ -6,6 +6,6 @@ git clone --depth=1 --branch="$VERSION" https://github.com/python/cpython cpytho
 git clone --branch="$VERSION" https://github.com/"$GITHUB_REPOSITORY" docs
 
 pip3 install --user setuptools
-pip3 install --user transifex-client
+curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
 sudo apt-get update
 sudo apt-get install -y python3-venv
diff --git a/.github/scripts/transifex_pull.py b/.github/scripts/transifex_pull.py
deleted file mode 100755
index 66c4046d9..000000000
--- a/.github/scripts/transifex_pull.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-
-from txclib import project
-from txclib.utils import perform_parallel_requests
-
-
-def pull(path, lang):
-    skip_decode = False
-    params = {}
-    parallel = True
-
-    prj = project.Project(path)
-    resource_list = prj.get_chosen_resources([])
-    for resource in resource_list:
-        project_slug, resource_slug = resource.split(".", 1)
-        host = prj.get_resource_host(resource)
-        prj._set_url_info(host=host, project=project_slug, resource=resource_slug)
-
-        files = prj.get_resource_files(resource)
-        url = prj._get_url_by_pull_mode(None)
-        local_file = files.get(lang)
-        prj.do_url_request(
-            url,
-            language=lang,
-            skip_decode=skip_decode,
-            params=params,
-            parallel=parallel,
-            callback=prj._save_file,
-            callback_args={"local_file": local_file},
-        )
-
-    perform_parallel_requests()
-
-
-if __name__ == "__main__":
-    import os
-
-    pull(os.getcwd(), os.getenv("LOCALE", "zh_CN"))
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index 544a31ae5..8424d2901 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,18 +1,5 @@
 #!/bin/bash
 
-set -ex
-
-script_dir="$(dirname "$(realpath "$0")")"
-
-if [[ -n "$TRANSIFEX_APIKEY" ]]; then
-  cat > ~/.transifexrc << EOF
-[https://www.transifex.com]
-api_hostname = https://api.transifex.com
-hostname = https://www.transifex.com
-password = $TRANSIFEX_APIKEY
-username = api
-EOF
-fi
 
 cd docs || exit 1
-"$script_dir"/transifex_pull.py
+tx pull --languages "$LOCALE"
diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 54037983e..5524337ef 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
new file mode 100644
index 000000000..e37354ae2
--- /dev/null
+++ b/.github/workflows/python-311.yml
@@ -0,0 +1,29 @@
+name: python-310
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "8 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.11"
+    steps:
+      - uses: actions/checkout@v2
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index c35d61d2b..6864df933 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index a99f0e20e..35948544c 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 76a6793bb..4b16958a5 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/README.rst b/README.rst
index 4ff062bc4..cf08f1294 100644
--- a/README.rst
+++ b/README.rst
@@ -12,6 +12,9 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310

From 8602d5e6b7413731814e85181ab97032d384ccb7 Mon Sep 17 00:00:00 2001
From: Nyuan Zhang <blueglassblock@outlook.com>
Date: Mon, 27 Feb 2023 16:20:58 +0800
Subject: [PATCH 14/56] Update python-311.yml

---
 .github/workflows/python-311.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index e37354ae2..d2f7aee35 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -1,11 +1,11 @@
-name: python-310
+name: python-311
 
 on:
   push:
     branches:
       - master
   schedule:
-    - cron: "8 * * * *"
+    - cron: "11 * * * *"
 
 jobs:
   sync:

From 3554fc2397bf0d7975b5368b569ce36a8e81dc71 Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Mon, 27 Feb 2023 17:59:07 +0800
Subject: [PATCH 15/56] Fix transifex cli position

---
 .github/scripts/update.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index 8424d2901..41279d019 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
 
-
+tx=$(realpath ./tx)
 cd docs || exit 1
-tx pull --languages "$LOCALE"
+$tx pull --languages "$LOCALE"

From c259ee1c2ba0576ceedbb67aeac979c85c9ebbd2 Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Tue, 28 Feb 2023 14:11:44 +0800
Subject: [PATCH 16/56] Fix config generation script

---
 .github/scripts/generate_tx_config.py | 35 +++++++++++++++++++--------
 .github/scripts/update.sh             |  2 +-
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
index b21e099ee..f021d4ac9 100755
--- a/.github/scripts/generate_tx_config.py
+++ b/.github/scripts/generate_tx_config.py
@@ -1,4 +1,5 @@
 """Please note that this script requires a Transifex API token to run."""
+import glob
 import subprocess
 from functools import partial
 from pathlib import Path
@@ -32,20 +33,33 @@ def add_files(version: str):
 def name_replacer(match: re.Match[str]):
     prefix, resource = match.group("prefix", "resource")
     override_prefix = prefix.replace("file_filter", "trans.zh_CN")
-    override_resource = (
+    pattern = (
         resource.replace("trans/<lang>/", "")
-        .replace("--", "/")
         .replace("glossary_", "glossary")
-        .replace("_", ".")
+        .replace("--", "/")
+        .replace("_", "?")
     )
-    return f"{prefix}{resource}\n{override_prefix}{override_resource}"
-
-
-def patch_config():
+    matches = list(glob.glob(pattern.replace(".po", ".rst")))
+    if not matches:
+        print("missing", pattern)
+        return f"{prefix}{resource}\n{override_prefix}{pattern}"
+    elif len(matches) == 1:
+        filename = matches[0].replace(".rst", ".po").replace("\\", "/")
+    else:
+        raise ValueError("multi match", resource, pattern, matches)
+    return f"{prefix}{resource}\n{override_prefix}{filename}"
+
+
+def patch_config(path: str):
     tx_config_path = Path(".tx", "config")
 
     config_content = tx_config_path.read_text("utf-8")
+
+    cwd = os.getcwd()
+    os.chdir(path)
     config_content = FILTER_PATTERN.sub(name_replacer, config_content)
+    os.chdir(cwd)
+
     tx_config_path.write_text(config_content, "utf-8")
 
 
@@ -55,8 +69,9 @@ def patch_config():
 
     parser = ArgumentParser()
 
-    parser.add_argument("--token")
-    parser.add_argument("--version")
+    parser.add_argument("--token", required=True)
+    parser.add_argument("--version", required=True)
+    parser.add_argument("--doc-path", required=True)
 
     params = parser.parse_args()
 
@@ -64,4 +79,4 @@ def patch_config():
 
     init_project()
     add_files(params.version)
-    patch_config()
+    patch_config(params.doc_path)
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index 41279d019..bcdb2d7d9 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -2,4 +2,4 @@
 
 tx=$(realpath ./tx)
 cd docs || exit 1
-$tx pull --languages "$LOCALE"
+$tx pull --languages "$LOCALE" -t --use-git-timestamps

From 6d039834cda6b52dd18cefea6cde0ca8a2134fed Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Tue, 28 Feb 2023 14:14:22 +0800
Subject: [PATCH 17/56] Add 3.11 to workflows

---
 README.rst | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/README.rst b/README.rst
index cf08f1294..d6847fc9c 100644
--- a/README.rst
+++ b/README.rst
@@ -15,11 +15,13 @@ Maintained versions:
    * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
+          :target: https://www.transifex.com/python-doc/python-311/
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
-          :target: https://www.transifex.com/python-doc/python-39/
+          :target: https://www.transifex.com/python-doc/python-310/
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39

From c3d4b1a1b8502a649bfd502eee732cf25d723b0c Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Sat, 13 May 2023 21:36:05 +0800
Subject: [PATCH 18/56] chore: update 3.11 links and badges

---
 README.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.rst b/README.rst
index d6847fc9c..53e6a6bed 100644
--- a/README.rst
+++ b/README.rst
@@ -12,10 +12,10 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
-   * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
+   * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.11>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/311
           :target: https://www.transifex.com/python-doc/python-311/
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg

From e01effbf98990f1f451c89ee77aa3af4089a5e33 Mon Sep 17 00:00:00 2001
From: BlueGlassBlock <blueglassblock@outlook.com>
Date: Mon, 29 May 2023 13:14:03 +0800
Subject: [PATCH 19/56] chore: Add 3.12 to workflow

---
 .github/scripts/generate_tx_config.py | 17 ++++++++--------
 .github/workflows/python-312.yml      | 29 +++++++++++++++++++++++++++
 README.rst                            | 15 +++++++++-----
 3 files changed, 48 insertions(+), 13 deletions(-)
 create mode 100644 .github/workflows/python-312.yml

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
index f021d4ac9..ca3bb39e4 100755
--- a/.github/scripts/generate_tx_config.py
+++ b/.github/scripts/generate_tx_config.py
@@ -4,6 +4,7 @@
 from functools import partial
 from pathlib import Path
 import re
+import os
 
 run = partial(subprocess.run, check=True)
 
@@ -12,7 +13,7 @@ def init_project():
     run(["tx", "init"])
 
 
-def add_files(version: str):
+def add_files(project_name: str):
     run(
         [
             "tx",
@@ -20,7 +21,7 @@ def add_files(version: str):
             "remote",
             "--file-filter",
             "trans/<lang>/<resource_slug>.<ext>",
-            f"https://www.transifex.com/python-doc/{version}/dashboard/",
+            f"https://www.transifex.com/python-doc/{project_name}/dashboard/",
         ]
     )
 
@@ -42,7 +43,7 @@ def name_replacer(match: re.Match[str]):
     matches = list(glob.glob(pattern.replace(".po", ".rst")))
     if not matches:
         print("missing", pattern)
-        return f"{prefix}{resource}\n{override_prefix}{pattern}"
+        return f"{prefix}{resource}\n{override_prefix}{pattern.replace('?', '_')}"
     elif len(matches) == 1:
         filename = matches[0].replace(".rst", ".po").replace("\\", "/")
     else:
@@ -65,18 +66,18 @@ def patch_config(path: str):
 
 if __name__ == "__main__":
     from argparse import ArgumentParser
-    import os
 
     parser = ArgumentParser()
 
-    parser.add_argument("--token", required=True)
-    parser.add_argument("--version", required=True)
+    parser.add_argument("--token", default="")
+    parser.add_argument("--project-name", required=True)
     parser.add_argument("--doc-path", required=True)
 
     params = parser.parse_args()
 
-    os.environ["TX_TOKEN"] = params.token
+    if params.token:
+        os.environ["TX_TOKEN"] = params.token
 
     init_project()
-    add_files(params.version)
+    add_files(params.project_name)
     patch_config(params.doc_path)
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
new file mode 100644
index 000000000..51c5b3f6a
--- /dev/null
+++ b/.github/workflows/python-312.yml
@@ -0,0 +1,29 @@
+name: python-312
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "42 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.12"
+    steps:
+      - uses: actions/checkout@v2
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.rst b/README.rst
index 53e6a6bed..604acc8ba 100644
--- a/README.rst
+++ b/README.rst
@@ -12,31 +12,36 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.12 <https://github.com/python/python-docs-zh-cn/tree/3.12>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-312/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-312
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/312
+          :target: https://app.transifex.com/python-doc/python-newest/
    * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.11>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/311
-          :target: https://www.transifex.com/python-doc/python-311/
+          :target: https://app.transifex.com/python-doc/python-311/
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
-          :target: https://www.transifex.com/python-doc/python-310/
+          :target: https://app.transifex.com/python-doc/python-310/
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/39
-          :target: https://www.transifex.com/python-doc/python-39/
+          :target: https://app.transifex.com/python-doc/python-39/
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
-          :target: https://www.transifex.com/python-doc/python-38/
+          :target: https://app.transifex.com/python-doc/python-38/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37
-          :target: https://www.transifex.com/python-doc/python-37/
+          :target: https://app.transifex.com/python-doc/python-37/
 
 Documentation Contribution Agreement
 ------------------------------------

From b40b5b2cecd1e03e28d09512ac8b9b61c26c18fa Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Tue, 20 Jun 2023 19:49:27 +0800
Subject: [PATCH 20/56] Commit

---
 .github/scripts/prepare.sh       |  3 ---
 .github/scripts/update.sh        |  3 +--
 .github/workflows/python-312.yml | 13 ++++++++++++-
 3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
index cf1326646..970963db6 100755
--- a/.github/scripts/prepare.sh
+++ b/.github/scripts/prepare.sh
@@ -2,9 +2,6 @@
 
 set -ex
 
-git clone --depth=1 --branch="$VERSION" https://github.com/python/cpython cpython
-git clone --branch="$VERSION" https://github.com/"$GITHUB_REPOSITORY" docs
-
 pip3 install --user setuptools
 curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
 sudo apt-get update
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index bcdb2d7d9..b66e8758a 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
 
-tx=$(realpath ./tx)
 cd docs || exit 1
-$tx pull --languages "$LOCALE" -t --use-git-timestamps
+$(realpath ../tx) pull --languages "$LOCALE" -t --use-git-timestamps --worker 25
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 51c5b3f6a..4f0fbfd27 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -14,7 +14,18 @@ jobs:
       LOCALE: zh_CN
       VERSION: "3.12"
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
+      - name: Checkout CPython
+        uses: actions/checkout@v3
+        with:
+          repository: 'python/cpython'
+          ref: ${{env.VERSION}}
+          path: cpython
+      - name: Checkout Current Files
+        uses: actions/checkout@v3
+        with:
+          ref: ${{env.VERSION}}
+          path: docs
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update

From 0738865ffc16d6deaa29ac9d9712048b37d1c9ff Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Tue, 20 Jun 2023 19:51:00 +0800
Subject: [PATCH 21/56] commit

---
 .github/scripts/update.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index b66e8758a..d2f6f13be 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,4 +1,4 @@
 #!/bin/bash
 
 cd docs || exit 1
-$(realpath ../tx) pull --languages "$LOCALE" -t --use-git-timestamps --worker 25
+$(realpath ../tx) pull --languages "$LOCALE" -t --use-git-timestamps --workers 25 --silent

From 2e0347328dc1287a9c730c7e4ce8ca5a2ce0ac7f Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Tue, 20 Jun 2023 20:07:25 +0800
Subject: [PATCH 22/56] Remove token

---
 .github/scripts/commit.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/commit.sh b/.github/scripts/commit.sh
index ae7d04096..da2acf89a 100755
--- a/.github/scripts/commit.sh
+++ b/.github/scripts/commit.sh
@@ -12,4 +12,4 @@ fi
 git add .
 git commit -m '[po] auto sync'
 header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
-git -c http.extraheader="AUTHORIZATION: basic $header" push
+git push

From 2a26dfb8036869778e767edd1a0e17de6c9ddf91 Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 10:33:27 +0800
Subject: [PATCH 23/56] fix

---
 .github/workflows/python-312.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 4f0fbfd27..c3dde8a3c 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -21,7 +21,7 @@ jobs:
           repository: 'python/cpython'
           ref: ${{env.VERSION}}
           path: cpython
-      - name: Checkout Current Files
+      - name: Checkout Current Branch
         uses: actions/checkout@v3
         with:
           ref: ${{env.VERSION}}

From 3040c4b8056c6dd46cdbfdc56c3d7205f7a6c200 Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 10:56:04 +0800
Subject: [PATCH 24/56] remove venv

---
 .github/scripts/build.sh   | 4 ++--
 .github/scripts/prepare.sh | 3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index bbf4eb060..2cbcb8e11 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,5 +13,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-make venv
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)
+pip3 install -q -r requirements.txt
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
index 970963db6..9b60c4479 100755
--- a/.github/scripts/prepare.sh
+++ b/.github/scripts/prepare.sh
@@ -2,7 +2,4 @@
 
 set -ex
 
-pip3 install --user setuptools
 curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
-sudo apt-get update
-sudo apt-get install -y python3-venv

From 15998601742e604bd87b64c48ee1db43f86c3fc5 Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 11:18:08 +0800
Subject: [PATCH 25/56] faster

---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 2cbcb8e11..720a268f0 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,4 +14,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -D html_copy_source=False -W --keep-going" 2> >(error)

From 296c3d3eb94f299e25046ea15cb1c7f37690b4a7 Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 11:58:13 +0800
Subject: [PATCH 26/56] search

---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 720a268f0..ca2b7dba9 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,4 +14,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -D html_copy_source=False -W --keep-going" 2> >(error)
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -D html_search_language='' -W --keep-going" 2> >(error)

From 52551de04d32a304daaa83b0938733a180ee44d6 Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 12:39:16 +0800
Subject: [PATCH 27/56] cache

---
 .github/scripts/commit.sh        |  1 -
 .github/workflows/python-312.yml | 12 ++++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/.github/scripts/commit.sh b/.github/scripts/commit.sh
index da2acf89a..878c0d57e 100755
--- a/.github/scripts/commit.sh
+++ b/.github/scripts/commit.sh
@@ -11,5 +11,4 @@ if ! git status -s|grep '\.po'; then
 fi
 git add .
 git commit -m '[po] auto sync'
-header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
 git push
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index c3dde8a3c..b4a8f5b84 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -32,9 +32,17 @@ jobs:
         run: .github/scripts/update.sh
         env:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: Restore doctrees Cache
+        uses: actions/cache/restore@v3
+        with:
+          path: ./cpython/Doc/build/doctrees
+          key: sphinx-cache-${{env.VERSION}}
       - name: build
         run: .github/scripts/build.sh
+      - name: Save doctrees Cache
+        uses: actions/cache/save@v3
+        with:
+          path: ./cpython/Doc/build/doctrees
+          key: sphinx-cache-${{env.VERSION}}
       - name: commit
         run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

From 73af92c9fee9ba88ee7a327eda23be3df63ca01b Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 12:49:40 +0800
Subject: [PATCH 28/56] update cache path

---
 .github/scripts/build.sh         | 2 +-
 .github/workflows/python-312.yml | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index ca2b7dba9..2cbcb8e11 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,4 +14,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -D html_search_language='' -W --keep-going" 2> >(error)
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index b4a8f5b84..b3338b880 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -32,17 +32,17 @@ jobs:
         run: .github/scripts/update.sh
         env:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: Restore doctrees Cache
+      - name: Restore build Cache
         uses: actions/cache/restore@v3
         with:
-          path: ./cpython/Doc/build/doctrees
+          path: ./cpython/Doc/build
           key: sphinx-cache-${{env.VERSION}}
       - name: build
         run: .github/scripts/build.sh
-      - name: Save doctrees Cache
+      - name: Save build Cache
         uses: actions/cache/save@v3
         with:
-          path: ./cpython/Doc/build/doctrees
+          path: ./cpython/Doc/build
           key: sphinx-cache-${{env.VERSION}}
       - name: commit
         run: .github/scripts/commit.sh

From 7c46dfd1d62b9db942c163e7119912cd6dcfc4fc Mon Sep 17 00:00:00 2001
From: A <793763955@qq.com>
Date: Wed, 21 Jun 2023 13:56:36 +0800
Subject: [PATCH 29/56] remove cache

---
 .github/workflows/python-312.yml | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index b3338b880..bc9a5b47b 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -32,17 +32,7 @@ jobs:
         run: .github/scripts/update.sh
         env:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: Restore build Cache
-        uses: actions/cache/restore@v3
-        with:
-          path: ./cpython/Doc/build
-          key: sphinx-cache-${{env.VERSION}}
       - name: build
         run: .github/scripts/build.sh
-      - name: Save build Cache
-        uses: actions/cache/save@v3
-        with:
-          path: ./cpython/Doc/build
-          key: sphinx-cache-${{env.VERSION}}
       - name: commit
         run: .github/scripts/commit.sh

From df8186d4ceeb7e75e37587bfbe948097aff5bbe4 Mon Sep 17 00:00:00 2001
From: Nyuan Zhang <blueglassblock@outlook.com>
Date: Thu, 3 Aug 2023 15:08:39 +0800
Subject: [PATCH 30/56] Update to Python 3.12 (#301)

* Update to Python 3.11

* Update python-311.yml

* Fix transifex cli position

* Fix config generation script

* Add 3.11 to workflows

* chore: update 3.11 links and badges

* chore: Add 3.12 to workflow
---
 .github/scripts/generate_tx_config.py | 135 ++++++++++++++------------
 .github/scripts/prepare.sh            |   2 +-
 .github/scripts/transifex_pull.py     |  38 --------
 .github/scripts/update.sh             |  17 +---
 .github/workflows/python-310.yml      |   2 +-
 .github/workflows/python-311.yml      |  29 ++++++
 .github/workflows/python-312.yml      |  29 ++++++
 .github/workflows/python-37.yml       |   2 +-
 .github/workflows/python-38.yml       |   2 +-
 .github/workflows/python-39.yml       |   2 +-
 README.rst                            |  18 +++-
 11 files changed, 150 insertions(+), 126 deletions(-)
 delete mode 100755 .github/scripts/transifex_pull.py
 create mode 100644 .github/workflows/python-311.yml
 create mode 100644 .github/workflows/python-312.yml

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
index 0e72833f1..ca3bb39e4 100755
--- a/.github/scripts/generate_tx_config.py
+++ b/.github/scripts/generate_tx_config.py
@@ -1,76 +1,83 @@
-#!/usr/bin/env python3
+"""Please note that this script requires a Transifex API token to run."""
 import glob
-import json
-import os
+import subprocess
+from functools import partial
+from pathlib import Path
 import re
-import sys
-import urllib.request
+import os
+
+run = partial(subprocess.run, check=True)
+
 
+def init_project():
+    run(["tx", "init"])
 
-def list_resources(token, project):
-    auth_handler = urllib.request.HTTPBasicAuthHandler()
-    auth_handler.add_password(
-        realm="api", uri="https://api.transifex.com/", user="api", passwd=token
+
+def add_files(project_name: str):
+    run(
+        [
+            "tx",
+            "add",
+            "remote",
+            "--file-filter",
+            "trans/<lang>/<resource_slug>.<ext>",
+            f"https://www.transifex.com/python-doc/{project_name}/dashboard/",
+        ]
     )
-    opener = urllib.request.build_opener(auth_handler)
-    urllib.request.install_opener(opener)
-    next_ = (
-        "https://api.transifex.com/organizations/python-doc/projects/"
-        + project
-        + "/resources/"
+
+
+FILTER_PATTERN = re.compile(
+    r"^(?P<prefix>file_filter( *)=( *))(?P<resource>.+)$", re.MULTILINE
+)
+
+
+def name_replacer(match: re.Match[str]):
+    prefix, resource = match.group("prefix", "resource")
+    override_prefix = prefix.replace("file_filter", "trans.zh_CN")
+    pattern = (
+        resource.replace("trans/<lang>/", "")
+        .replace("glossary_", "glossary")
+        .replace("--", "/")
+        .replace("_", "?")
     )
-    resources = []
-    while True:
-        resp = urllib.request.urlopen(next_)
-        result = json.loads(resp.read().decode("utf-8"))
-        resources.extend([i["slug"] for i in result])
-        link = re.findall('<([^<]*)>; rel="next"', resp.getheader("Link") or "")
-        if not link:
-            break
-        next_ = link[0]
-    return resources
-
-
-def render_config(doc_dir, project, resources):
-    os.chdir(doc_dir)
-    tpl = """
-
-[{project}.{resource}]
-trans.zh_CN = {filename}
-source_lang = en
-type = PO"""
-    conf = """[main]
-host = https://www.transifex.com"""
-    for resource in sorted(resources):
-        if resource == "glossary_":
-            filename = "glossary.po"
-        elif resource == "sphinx":
-            filename = "sphinx.po"
-        else:
-            pattern = resource.replace("--", "/").replace("_", "?")
-            matches = glob.glob(pattern + ".rst")
-            if len(matches) == 0:
-                print("missing", resource, file=sys.stderr)
-                continue
-            elif len(matches) == 1:
-                filename = matches[0].replace(".rst", ".po")
-            else:
-                print("multi match", resource, pattern, matches, file=sys.stderr)
-        conf += tpl.format(project=project, resource=resource, filename=filename)
-    return conf
+    matches = list(glob.glob(pattern.replace(".po", ".rst")))
+    if not matches:
+        print("missing", pattern)
+        return f"{prefix}{resource}\n{override_prefix}{pattern.replace('?', '_')}"
+    elif len(matches) == 1:
+        filename = matches[0].replace(".rst", ".po").replace("\\", "/")
+    else:
+        raise ValueError("multi match", resource, pattern, matches)
+    return f"{prefix}{resource}\n{override_prefix}{filename}"
+
+
+def patch_config(path: str):
+    tx_config_path = Path(".tx", "config")
+
+    config_content = tx_config_path.read_text("utf-8")
+
+    cwd = os.getcwd()
+    os.chdir(path)
+    config_content = FILTER_PATTERN.sub(name_replacer, config_content)
+    os.chdir(cwd)
+
+    tx_config_path.write_text(config_content, "utf-8")
 
 
 if __name__ == "__main__":
-    import argparse
+    from argparse import ArgumentParser
+
+    parser = ArgumentParser()
+
+    parser.add_argument("--token", default="")
+    parser.add_argument("--project-name", required=True)
+    parser.add_argument("--doc-path", required=True)
 
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--token")
-    parser.add_argument("--project")
-    parser.add_argument("--doc-dir")
-    args = parser.parse_args()
+    params = parser.parse_args()
 
-    resources = list_resources(args.token, args.project)
-    conf = render_config(args.doc_dir, args.project, resources)
-    print(conf)
+    if params.token:
+        os.environ["TX_TOKEN"] = params.token
 
-# vim: set et ts=4 sw=4 sts=4:
+    init_project()
+    add_files(params.project_name)
+    patch_config(params.doc_path)
diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
index d16dbc056..cf1326646 100755
--- a/.github/scripts/prepare.sh
+++ b/.github/scripts/prepare.sh
@@ -6,6 +6,6 @@ git clone --depth=1 --branch="$VERSION" https://github.com/python/cpython cpytho
 git clone --branch="$VERSION" https://github.com/"$GITHUB_REPOSITORY" docs
 
 pip3 install --user setuptools
-pip3 install --user transifex-client
+curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
 sudo apt-get update
 sudo apt-get install -y python3-venv
diff --git a/.github/scripts/transifex_pull.py b/.github/scripts/transifex_pull.py
deleted file mode 100755
index 66c4046d9..000000000
--- a/.github/scripts/transifex_pull.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-
-from txclib import project
-from txclib.utils import perform_parallel_requests
-
-
-def pull(path, lang):
-    skip_decode = False
-    params = {}
-    parallel = True
-
-    prj = project.Project(path)
-    resource_list = prj.get_chosen_resources([])
-    for resource in resource_list:
-        project_slug, resource_slug = resource.split(".", 1)
-        host = prj.get_resource_host(resource)
-        prj._set_url_info(host=host, project=project_slug, resource=resource_slug)
-
-        files = prj.get_resource_files(resource)
-        url = prj._get_url_by_pull_mode(None)
-        local_file = files.get(lang)
-        prj.do_url_request(
-            url,
-            language=lang,
-            skip_decode=skip_decode,
-            params=params,
-            parallel=parallel,
-            callback=prj._save_file,
-            callback_args={"local_file": local_file},
-        )
-
-    perform_parallel_requests()
-
-
-if __name__ == "__main__":
-    import os
-
-    pull(os.getcwd(), os.getenv("LOCALE", "zh_CN"))
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index 544a31ae5..bcdb2d7d9 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,18 +1,5 @@
 #!/bin/bash
 
-set -ex
-
-script_dir="$(dirname "$(realpath "$0")")"
-
-if [[ -n "$TRANSIFEX_APIKEY" ]]; then
-  cat > ~/.transifexrc << EOF
-[https://www.transifex.com]
-api_hostname = https://api.transifex.com
-hostname = https://www.transifex.com
-password = $TRANSIFEX_APIKEY
-username = api
-EOF
-fi
-
+tx=$(realpath ./tx)
 cd docs || exit 1
-"$script_dir"/transifex_pull.py
+$tx pull --languages "$LOCALE" -t --use-git-timestamps
diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 54037983e..5524337ef 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
new file mode 100644
index 000000000..d2f7aee35
--- /dev/null
+++ b/.github/workflows/python-311.yml
@@ -0,0 +1,29 @@
+name: python-311
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "11 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.11"
+    steps:
+      - uses: actions/checkout@v2
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
new file mode 100644
index 000000000..51c5b3f6a
--- /dev/null
+++ b/.github/workflows/python-312.yml
@@ -0,0 +1,29 @@
+name: python-312
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "42 * * * *"
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: "3.12"
+    steps:
+      - uses: actions/checkout@v2
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index c35d61d2b..6864df933 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index a99f0e20e..35948544c 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 76a6793bb..4b16958a5 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -20,7 +20,7 @@ jobs:
       - name: update
         run: .github/scripts/update.sh
         env:
-          TRANSIFEX_APIKEY: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
       - name: commit
diff --git a/README.rst b/README.rst
index 4ff062bc4..604acc8ba 100644
--- a/README.rst
+++ b/README.rst
@@ -12,26 +12,36 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.12 <https://github.com/python/python-docs-zh-cn/tree/3.12>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-312/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-312
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/312
+          :target: https://app.transifex.com/python-doc/python-newest/
+   * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.11>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
+     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/311
+          :target: https://app.transifex.com/python-doc/python-311/
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
-          :target: https://www.transifex.com/python-doc/python-39/
+          :target: https://app.transifex.com/python-doc/python-310/
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/39
-          :target: https://www.transifex.com/python-doc/python-39/
+          :target: https://app.transifex.com/python-doc/python-39/
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
-          :target: https://www.transifex.com/python-doc/python-38/
+          :target: https://app.transifex.com/python-doc/python-38/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37
-          :target: https://www.transifex.com/python-doc/python-37/
+          :target: https://app.transifex.com/python-doc/python-37/
 
 Documentation Contribution Agreement
 ------------------------------------

From c6da1da3c831474afeb129c8c3106345ebb310d7 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 15:40:47 +0800
Subject: [PATCH 31/56] Add reusable workflow

---
 .github/workflows/python-312.yml | 31 ++++--------------------
 .github/workflows/sync.yml       | 41 ++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 27 deletions(-)
 create mode 100644 .github/workflows/sync.yml

diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index bc9a5b47b..44a05ee9e 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -9,30 +9,7 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.12"
-    steps:
-      - uses: actions/checkout@v3
-      - name: Checkout CPython
-        uses: actions/checkout@v3
-        with:
-          repository: 'python/cpython'
-          ref: ${{env.VERSION}}
-          path: cpython
-      - name: Checkout Current Branch
-        uses: actions/checkout@v3
-        with:
-          ref: ${{env.VERSION}}
-          path: docs
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.12"
+    secrets: inherit
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
new file mode 100644
index 000000000..a5a126e20
--- /dev/null
+++ b/.github/workflows/sync.yml
@@ -0,0 +1,41 @@
+name: Reusable workflow example
+
+on:
+  workflow_call:
+    inputs:
+      version:
+        required: true
+        type: string
+    secrets:
+      TRANSIFEX_APIKEY:
+        required: true
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: ${{ inputs.version }}
+    steps:
+      - uses: actions/checkout@v3
+      - name: Checkout CPython
+        uses: actions/checkout@v3
+        with:
+          repository: 'python/cpython'
+          ref: ${{env.VERSION}}
+          path: cpython
+      - name: Checkout Current Branch
+        uses: actions/checkout@v3
+        with:
+          ref: ${{env.VERSION}}
+          path: docs
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
\ No newline at end of file

From 2200481fe14145cca4e85fd04c6455eb792a2953 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 15:53:53 +0800
Subject: [PATCH 32/56] Update all workflows

---
 .github/workflows/python-310.yml | 23 +++++------------------
 .github/workflows/python-311.yml | 23 +++++------------------
 .github/workflows/python-37.yml  | 22 ++++------------------
 .github/workflows/python-38.yml  | 22 ++++------------------
 .github/workflows/python-39.yml  | 23 +++++------------------
 5 files changed, 23 insertions(+), 90 deletions(-)

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 5524337ef..84b9c7ff6 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -9,21 +9,8 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.10"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.10"
+    secrets: inherit
+    
\ No newline at end of file
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index d2f7aee35..4c3cf79f1 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -9,21 +9,8 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.11"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.11"
+    secrets: inherit
+    
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index 6864df933..9aa726015 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -9,21 +9,7 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.7"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.7"
+    secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index 35948544c..41fa86e01 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -9,21 +9,7 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.8"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.8"
+    secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 4b16958a5..0d0e60aa4 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -9,21 +9,8 @@ on:
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.9"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.9"
+    secrets: inherit
+    
\ No newline at end of file

From 7ab7c930930663095f6d41e3683b8c57a5b8523d Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 15:59:37 +0800
Subject: [PATCH 33/56] Update workflows schedule

---
 .github/workflows/python-310.yml | 2 +-
 .github/workflows/python-311.yml | 2 +-
 .github/workflows/python-312.yml | 2 +-
 .github/workflows/python-37.yml  | 2 +-
 .github/workflows/python-38.yml  | 2 +-
 .github/workflows/python-39.yml  | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 84b9c7ff6..10e299b45 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "8 * * * *"
+    - cron: "26 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index 4c3cf79f1..3ac6cf1ba 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "11 * * * *"
+    - cron: "38 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 44a05ee9e..228e64d78 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "42 * * * *"
+    - cron: "50 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index 9aa726015..867c77ad3 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "53 * * * *"
+    - cron: "0 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index 41fa86e01..e3725dc36 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "38 * * * *"
+    - cron: "2 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 0d0e60aa4..458459371 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "23 * * * *"
+    - cron: "14 * * * *"
 
 jobs:
   sync:

From 0147e2bd42249a90a3c342bc3d77b5ccc9ea0807 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:00:16 +0800
Subject: [PATCH 34/56] Use docsbuild-scripts to build

---
 .github/scripts/build.sh   | 5 ++++-
 .github/workflows/sync.yml | 5 +++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 2cbcb8e11..bb8e643b3 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,5 +13,8 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
+
+cd ../../docsbuild/
 pip3 install -q -r requirements.txt
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
+python3 ./build_docs.py --quick --build-root ./build_root --www-root ./www --skip-cache-invalidation --language $LOCALE --branch $VERSION
+# make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index a5a126e20..2508339d2 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -29,6 +29,11 @@ jobs:
         with:
           ref: ${{env.VERSION}}
           path: docs
+      - name: Checkout Build Scripts
+        uses: actions/checkout@v3
+        with:
+          ref: ${{env.VERSION}}
+          path: docsbuild
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update

From 345361d30218cd9fda030cbb52dc027535665081 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:06:08 +0800
Subject: [PATCH 35/56] install python docs packages

---
 .github/scripts/build.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index bb8e643b3..3bc169765 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,6 +13,7 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
+pip3 install -q -r requirements.txt
 
 cd ../../docsbuild/
 pip3 install -q -r requirements.txt

From 8bb7d448ee695d765d3913716086a1fefc1e816f Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:08:32 +0800
Subject: [PATCH 36/56] Add docsbuild-scripts repo

---
 .github/workflows/sync.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 2508339d2..ef04046ac 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -32,6 +32,7 @@ jobs:
       - name: Checkout Build Scripts
         uses: actions/checkout@v3
         with:
+          repository: 'python/docsbuild-scripts'
           ref: ${{env.VERSION}}
           path: docsbuild
       - name: prepare

From 0aa564649b0b67235e0092f24cc36d7046360c37 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:30:14 +0800
Subject: [PATCH 37/56] remvoe docsbuild-scripts

---
 .github/scripts/build.sh   | 7 +------
 .github/workflows/sync.yml | 6 ------
 2 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 3bc169765..8d420e12f 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,9 +13,4 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-pip3 install -q -r requirements.txt
-
-cd ../../docsbuild/
-pip3 install -q -r requirements.txt
-python3 ./build_docs.py --quick --build-root ./build_root --www-root ./www --skip-cache-invalidation --language $LOCALE --branch $VERSION
-# make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index ef04046ac..a5a126e20 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -29,12 +29,6 @@ jobs:
         with:
           ref: ${{env.VERSION}}
           path: docs
-      - name: Checkout Build Scripts
-        uses: actions/checkout@v3
-        with:
-          repository: 'python/docsbuild-scripts'
-          ref: ${{env.VERSION}}
-          path: docsbuild
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update

From c2b3e9648a026e2677b3d5ff5a9ddd8709db6bb2 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:32:56 +0800
Subject: [PATCH 38/56] Add env setup

---
 .github/scripts/build.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 8d420e12f..2cbcb8e11 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,4 +13,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
+pip3 install -q -r requirements.txt
 make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)

From 4592fcd942df8b9e5ebc9bd4ccfdd34f3d256e1a Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:43:09 +0800
Subject: [PATCH 39/56] Update workflow and make it reusable (#315)

* Update workflow definition and dependencies version.
* Simplify the code structure.
* Make workflow reusable across versions.
---
 .github/scripts/build.sh         |  4 ++--
 .github/scripts/commit.sh        |  3 +--
 .github/scripts/prepare.sh       |  8 +------
 .github/scripts/update.sh        |  3 +--
 .github/workflows/python-310.yml | 25 +++++--------------
 .github/workflows/python-311.yml | 25 +++++--------------
 .github/workflows/python-312.yml | 24 ++++---------------
 .github/workflows/python-37.yml  | 24 ++++---------------
 .github/workflows/python-38.yml  | 24 ++++---------------
 .github/workflows/python-39.yml  | 25 +++++--------------
 .github/workflows/sync.yml       | 41 ++++++++++++++++++++++++++++++++
 11 files changed, 79 insertions(+), 127 deletions(-)
 create mode 100644 .github/workflows/sync.yml

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index bbf4eb060..2cbcb8e11 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -13,5 +13,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-make venv
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going -j2" 2> >(error)
+pip3 install -q -r requirements.txt
+make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
diff --git a/.github/scripts/commit.sh b/.github/scripts/commit.sh
index ae7d04096..878c0d57e 100755
--- a/.github/scripts/commit.sh
+++ b/.github/scripts/commit.sh
@@ -11,5 +11,4 @@ if ! git status -s|grep '\.po'; then
 fi
 git add .
 git commit -m '[po] auto sync'
-header="$(echo -n token:"$GITHUB_TOKEN" | base64)"
-git -c http.extraheader="AUTHORIZATION: basic $header" push
+git push
diff --git a/.github/scripts/prepare.sh b/.github/scripts/prepare.sh
index cf1326646..1ca5daab0 100755
--- a/.github/scripts/prepare.sh
+++ b/.github/scripts/prepare.sh
@@ -2,10 +2,4 @@
 
 set -ex
 
-git clone --depth=1 --branch="$VERSION" https://github.com/python/cpython cpython
-git clone --branch="$VERSION" https://github.com/"$GITHUB_REPOSITORY" docs
-
-pip3 install --user setuptools
-curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
-sudo apt-get update
-sudo apt-get install -y python3-venv
+curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash
\ No newline at end of file
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index bcdb2d7d9..d2f6f13be 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
 
-tx=$(realpath ./tx)
 cd docs || exit 1
-$tx pull --languages "$LOCALE" -t --use-git-timestamps
+$(realpath ../tx) pull --languages "$LOCALE" -t --use-git-timestamps --workers 25 --silent
diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 5524337ef..10e299b45 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -5,25 +5,12 @@ on:
     branches:
       - master
   schedule:
-    - cron: "8 * * * *"
+    - cron: "26 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.10"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.10"
+    secrets: inherit
+    
\ No newline at end of file
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index d2f7aee35..3ac6cf1ba 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -5,25 +5,12 @@ on:
     branches:
       - master
   schedule:
-    - cron: "11 * * * *"
+    - cron: "38 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.11"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.11"
+    secrets: inherit
+    
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 51c5b3f6a..228e64d78 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -5,25 +5,11 @@ on:
     branches:
       - master
   schedule:
-    - cron: "42 * * * *"
+    - cron: "50 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.12"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.12"
+    secrets: inherit
diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index 6864df933..867c77ad3 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -5,25 +5,11 @@ on:
     branches:
       - master
   schedule:
-    - cron: "53 * * * *"
+    - cron: "0 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.7"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.7"
+    secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index 35948544c..e3725dc36 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -5,25 +5,11 @@ on:
     branches:
       - master
   schedule:
-    - cron: "38 * * * *"
+    - cron: "2 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.8"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.8"
+    secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 4b16958a5..458459371 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -5,25 +5,12 @@ on:
     branches:
       - master
   schedule:
-    - cron: "23 * * * *"
+    - cron: "14 * * * *"
 
 jobs:
   sync:
-    runs-on: ubuntu-latest
-    env:
-      LOCALE: zh_CN
-      VERSION: "3.9"
-    steps:
-      - uses: actions/checkout@v2
-      - name: prepare
-        run: .github/scripts/prepare.sh
-      - name: update
-        run: .github/scripts/update.sh
-        env:
-          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - name: build
-        run: .github/scripts/build.sh
-      - name: commit
-        run: .github/scripts/commit.sh
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.9"
+    secrets: inherit
+    
\ No newline at end of file
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
new file mode 100644
index 000000000..a5a126e20
--- /dev/null
+++ b/.github/workflows/sync.yml
@@ -0,0 +1,41 @@
+name: Reusable workflow example
+
+on:
+  workflow_call:
+    inputs:
+      version:
+        required: true
+        type: string
+    secrets:
+      TRANSIFEX_APIKEY:
+        required: true
+
+jobs:
+  sync:
+    runs-on: ubuntu-latest
+    env:
+      LOCALE: zh_CN
+      VERSION: ${{ inputs.version }}
+    steps:
+      - uses: actions/checkout@v3
+      - name: Checkout CPython
+        uses: actions/checkout@v3
+        with:
+          repository: 'python/cpython'
+          ref: ${{env.VERSION}}
+          path: cpython
+      - name: Checkout Current Branch
+        uses: actions/checkout@v3
+        with:
+          ref: ${{env.VERSION}}
+          path: docs
+      - name: prepare
+        run: .github/scripts/prepare.sh
+      - name: update
+        run: .github/scripts/update.sh
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - name: build
+        run: .github/scripts/build.sh
+      - name: commit
+        run: .github/scripts/commit.sh
\ No newline at end of file

From 2f78e1957c2b7c8cd8e3e5d0e522b079b60583b2 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:55:13 +0800
Subject: [PATCH 40/56] Update 3.7 to EOL

---
 .github/workflows/python-37.yml | 7 +------
 README.rst                      | 2 +-
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/python-37.yml b/.github/workflows/python-37.yml
index 867c77ad3..47c224c3b 100644
--- a/.github/workflows/python-37.yml
+++ b/.github/workflows/python-37.yml
@@ -1,11 +1,6 @@
 name: python-37
 
-on:
-  push:
-    branches:
-      - master
-  schedule:
-    - cron: "0 * * * *"
+on: workflow_dispatch
 
 jobs:
   sync:
diff --git a/README.rst b/README.rst
index 604acc8ba..33129de16 100644
--- a/README.rst
+++ b/README.rst
@@ -37,7 +37,7 @@ Maintained versions:
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
           :target: https://app.transifex.com/python-doc/python-38/
-   * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
+   * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_ [EOL]
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37

From 0ce16a079ffdf51ae1d99daf70f2486f5e71c2a9 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 22:57:10 +0800
Subject: [PATCH 41/56] Add EOL table

---
 README.rst | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/README.rst b/README.rst
index 33129de16..3d791ca4a 100644
--- a/README.rst
+++ b/README.rst
@@ -37,7 +37,16 @@ Maintained versions:
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
           :target: https://app.transifex.com/python-doc/python-38/
-   * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_ [EOL]
+
+EOL versions:
+
+.. list-table::
+   :header-rows: 1
+
+   * - Version
+     - Sync status
+     - Translation progress
+   * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
      - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37

From fdb12f61705a81ca2ea163964702f277c1054400 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Thu, 3 Aug 2023 23:50:45 +0800
Subject: [PATCH 42/56] Add issue template (#317)

---
 .github/ISSUE_TEMPLATE/translation.yml | 46 ++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 .github/ISSUE_TEMPLATE/translation.yml

diff --git a/.github/ISSUE_TEMPLATE/translation.yml b/.github/ISSUE_TEMPLATE/translation.yml
new file mode 100644
index 000000000..6ed458362
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/translation.yml
@@ -0,0 +1,46 @@
+name: Translation Issue Report
+description: File a translation issue report
+title: "[Typo]: "
+labels: ["translation"]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thanks for taking the time to fill out this translation issue report!
+  - type: input
+    id: version
+    attributes:
+      label: Python Version
+      description: Which version of Python docs contains the issue?
+      placeholder: ex. 3.12
+    validations:
+      required: true
+  - type: input
+    id: url
+    attributes:
+      label: Docs Page
+      description: What is the url of the page contains the issue?
+      placeholder: https://docs.python.org/3/about.html
+    validations:
+      required: true
+  - type: textarea
+    id: zh-original
+    attributes:
+      label: Original Translation
+      description: Which translated paragraph in Chinese contains the issue?
+    validations:
+      required: true
+  - type: textarea
+    id: en-original
+    attributes:
+      label: Original Docs Paragraph
+      description: Which original paragraph in English contains the issue?
+    validations:
+      required: false
+  - type: textarea
+    id: zh-suggested
+    attributes:
+      label: Suggested Fix
+      description: What is you suggeest fix?
+    validations:
+      required: true
\ No newline at end of file

From 09da4827a6030168c1144721195b236baabd3f19 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Fri, 4 Aug 2023 13:15:38 +0800
Subject: [PATCH 43/56] Fix translation progress badges (#318)

Create a new `.stat.json` file for each sync. A badge will be generated based on this stat file.
---
 .github/ISSUE_TEMPLATE/translation.yml |  6 ++---
 .github/scripts/tx_stat.py             | 33 ++++++++++++++++++++++++++
 .github/workflows/python-310.yml       |  1 +
 .github/workflows/python-311.yml       |  1 +
 .github/workflows/python-312.yml       |  1 +
 .github/workflows/python-38.yml        |  1 +
 .github/workflows/python-39.yml        |  1 +
 .github/workflows/sync.yml             |  8 +++++++
 README.rst                             | 12 +++++-----
 9 files changed, 55 insertions(+), 9 deletions(-)
 create mode 100644 .github/scripts/tx_stat.py

diff --git a/.github/ISSUE_TEMPLATE/translation.yml b/.github/ISSUE_TEMPLATE/translation.yml
index 6ed458362..780ebc722 100644
--- a/.github/ISSUE_TEMPLATE/translation.yml
+++ b/.github/ISSUE_TEMPLATE/translation.yml
@@ -11,7 +11,7 @@ body:
     id: version
     attributes:
       label: Python Version
-      description: Which version of Python docs contains the issue?
+      description: Which version of the Python documentation covers this issue?
       placeholder: ex. 3.12
     validations:
       required: true
@@ -19,7 +19,7 @@ body:
     id: url
     attributes:
       label: Docs Page
-      description: What is the url of the page contains the issue?
+      description: What is the url of the page containing the issue?
       placeholder: https://docs.python.org/3/about.html
     validations:
       required: true
@@ -41,6 +41,6 @@ body:
     id: zh-suggested
     attributes:
       label: Suggested Fix
-      description: What is you suggeest fix?
+      description: What is your suggested fix?
     validations:
       required: true
\ No newline at end of file
diff --git a/.github/scripts/tx_stat.py b/.github/scripts/tx_stat.py
new file mode 100644
index 000000000..00dcf965c
--- /dev/null
+++ b/.github/scripts/tx_stat.py
@@ -0,0 +1,33 @@
+import json
+import os
+import urllib.request
+from datetime import datetime
+
+key = os.environ.get('TX_TOKEN')
+project = os.environ.get('TX_PROJECT')
+
+url = "https://rest.api.transifex.com/resource_language_stats?filter[project]=o%3Apython-doc%3Ap%3A{}&filter[language]=l%3Azh_CN".format(project)
+
+headers = {
+    "accept": "application/vnd.api+json",
+    "authorization": "Bearer " + key
+}
+
+total = 0
+translated = 0
+
+while(url):
+    request = urllib.request.Request(url=url,headers=headers)
+
+    with urllib.request.urlopen(request) as response:
+        data = json.loads(response.read().decode("utf-8"))
+        url = data['links'].get('next')
+        for resourse in data['data']:
+            translated = translated + resourse['attributes']['translated_strings']
+            total =  total + resourse['attributes']['total_strings']
+
+p = '{:.2%}'.format(translated/total)
+print(json.dumps({
+    'translation':p,
+    'updated_at':datetime.utcnow().isoformat(timespec='seconds') + 'Z',
+    }))
\ No newline at end of file
diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 10e299b45..6607518d7 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -12,5 +12,6 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.10"
+      tx_project: "python-310"
     secrets: inherit
     
\ No newline at end of file
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index 3ac6cf1ba..9566d743f 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -12,5 +12,6 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.11"
+      tx_project: "python-311"
     secrets: inherit
     
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 228e64d78..d1bb99d95 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -12,4 +12,5 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.12"
+      tx_project: "python-newest"
     secrets: inherit
diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index e3725dc36..4da2959f9 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -12,4 +12,5 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.8"
+      tx_project: "python-38"
     secrets: inherit
\ No newline at end of file
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 458459371..3d6e5da9a 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -12,5 +12,6 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.9"
+      tx_project: "python-39"
     secrets: inherit
     
\ No newline at end of file
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index a5a126e20..3d2741421 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -6,6 +6,9 @@ on:
       version:
         required: true
         type: string
+      tx_project:
+        required: true
+        type: string
     secrets:
       TRANSIFEX_APIKEY:
         required: true
@@ -37,5 +40,10 @@ jobs:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
       - name: build
         run: .github/scripts/build.sh
+      - name: stat
+        run: python .github/scripts/tx_stat.py > ./docs/.stat.json
+        env:
+          TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+          TX_PROJECT: ${{ inputs.tx_project }}
       - name: commit
         run: .github/scripts/commit.sh
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 3d791ca4a..5c38d3110 100644
--- a/README.rst
+++ b/README.rst
@@ -15,27 +15,27 @@ Maintained versions:
    * - `3.12 <https://github.com/python/python-docs-zh-cn/tree/3.12>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-312/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-312
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/312
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.12%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-newest/
    * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.11>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/311
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.11%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-311/
    * - `3.10 <https://github.com/python/python-docs-zh-cn/tree/3.10>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-310/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-310
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/310
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.10%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-310/
    * - `3.9 <https://github.com/python/python-docs-zh-cn/tree/3.9>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-39/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/39
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.9%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-39/
    * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/38
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.8%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-38/
 
 EOL versions:
@@ -49,7 +49,7 @@ EOL versions:
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37
-     - .. image:: https://img.shields.io/badge/dynamic/json.svg?label=zh_CN&query=%24.zh_CN&url=http://gce.zhsj.me/python/37
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.7%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-37/
 
 Documentation Contribution Agreement

From adcbce5bf4dd045a767e2b692ac20e628962c16e Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Fri, 4 Aug 2023 18:18:40 +0800
Subject: [PATCH 44/56] optimize build time (#319)

- Add a GitHub action cache layer
- Refill files modified time to use incremental build
- Change from html builder to dummy builder
---
 .github/scripts/build.sh   |  2 +-
 .github/scripts/update.sh  | 16 ++++++++++++++++
 .github/workflows/sync.yml |  9 +++++++++
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 2cbcb8e11..4e9b1556c 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,4 +14,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-make html SPHINXOPTS="-D language=$LOCALE -D gettext_compact=0 -W --keep-going" 2> >(error)
+sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -W --keep-going -W . build/html 2> >(error)
\ No newline at end of file
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index d2f6f13be..4a15d3095 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,4 +1,20 @@
 #!/bin/bash
 
+cd cpython || exit 1
+
+# Restore git timestamp for enabling build cache
+rev=HEAD
+for f in $(git ls-tree -r -t --full-name --name-only "$rev" Doc) ; do
+    touch -d $(git log --pretty=format:%cI -1 "$rev" -- "$f") "$f";
+done
+
+cd ..
 cd docs || exit 1
+
+# Restore git timestamp for enabling build cache
+rev=HEAD
+for f in $(git ls-tree -r -t --full-name --name-only "$rev") ; do
+    touch -d $(git log --pretty=format:%cI -1 "$rev" -- "$f") "$f";
+done
+
 $(realpath ../tx) pull --languages "$LOCALE" -t --use-git-timestamps --workers 25 --silent
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 3d2741421..83a51080a 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -38,8 +38,17 @@ jobs:
         run: .github/scripts/update.sh
         env:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
+      - uses: actions/cache/restore@v3
+        with:
+          path: cpython/Doc/build
+          key: cache-${{ inputs.version }}-${{ github.run_id }}
+          restore-keys: cache-${{ inputs.version }}-
       - name: build
         run: .github/scripts/build.sh
+      - uses: actions/cache/save@v3
+        with:
+          path: cpython/Doc/build
+          key: cache-${{ inputs.version }}-${{ github.run_id }}
       - name: stat
         run: python .github/scripts/tx_stat.py > ./docs/.stat.json
         env:

From 12fad780e73dc3fc3e5fcf326ffde2241b4b5561 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Mon, 7 Aug 2023 00:04:41 +0800
Subject: [PATCH 45/56] cache .mo files for build time optimization (#320)

* Cache .mo files

* Avoid clean cache
---
 .github/workflows/sync.yml | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 83a51080a..3fed1aca7 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -27,11 +27,19 @@ jobs:
           repository: 'python/cpython'
           ref: ${{env.VERSION}}
           path: cpython
+      - uses: actions/cache/restore@v3
+        with:
+          path: |
+            cpython/Doc/build
+            docs
+          key: cache-${{ inputs.version }}-${{ github.run_id }}
+          restore-keys: cache-${{ inputs.version }}-
       - name: Checkout Current Branch
         uses: actions/checkout@v3
         with:
           ref: ${{env.VERSION}}
           path: docs
+          clean: false
       - name: prepare
         run: .github/scripts/prepare.sh
       - name: update
@@ -47,7 +55,9 @@ jobs:
         run: .github/scripts/build.sh
       - uses: actions/cache/save@v3
         with:
-          path: cpython/Doc/build
+          path: |
+            cpython/Doc/build
+            docs
           key: cache-${{ inputs.version }}-${{ github.run_id }}
       - name: stat
         run: python .github/scripts/tx_stat.py > ./docs/.stat.json

From 2797f58ed3f6debf1e35019121889eb85fbc54b4 Mon Sep 17 00:00:00 2001
From: Rafael Fontenelle <rffontenelle@users.noreply.github.com>
Date: Wed, 29 Nov 2023 08:43:49 -0300
Subject: [PATCH 46/56] Error on unset variable in scritps (#339)

* Error on unset variable in build.sh

* Error on unset variable in update.sh
---
 .github/scripts/build.sh  | 3 ++-
 .github/scripts/update.sh | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 4e9b1556c..64b6cc9fc 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -1,6 +1,7 @@
 #!/bin/bash
 
 set -e
+set -u
 set -o pipefail
 
 error() {
@@ -14,4 +15,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -W --keep-going -W . build/html 2> >(error)
\ No newline at end of file
+sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -W --keep-going -W . build/html 2> >(error)
diff --git a/.github/scripts/update.sh b/.github/scripts/update.sh
index 4a15d3095..0f2231d9f 100755
--- a/.github/scripts/update.sh
+++ b/.github/scripts/update.sh
@@ -1,5 +1,7 @@
 #!/bin/bash
 
+set -u
+
 cd cpython || exit 1
 
 # Restore git timestamp for enabling build cache

From 4a41046a506f8af897175cf2077df6c02cac36e7 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sat, 2 Mar 2024 01:53:49 +0800
Subject: [PATCH 47/56] Update the tx config format

---
 .github/scripts/generate_tx_config.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/scripts/generate_tx_config.py b/.github/scripts/generate_tx_config.py
index ca3bb39e4..ebcc3b2dd 100755
--- a/.github/scripts/generate_tx_config.py
+++ b/.github/scripts/generate_tx_config.py
@@ -59,6 +59,10 @@ def patch_config(path: str):
     cwd = os.getcwd()
     os.chdir(path)
     config_content = FILTER_PATTERN.sub(name_replacer, config_content)
+    config_content = re.sub(r'replace_edited_strings.*\n','', config_content)
+    config_content = re.sub(r'keep_translations.*\n','', config_content)
+    config_content = re.sub(r'0\ntrans\.zh_CN.*\n','0\n', config_content)
+    config_content = config_content.replace('         =','=')
     os.chdir(cwd)
 
     tx_config_path.write_text(config_content, "utf-8")

From 2507666cf0a92e240ee936aca44182c06269ef95 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sat, 2 Mar 2024 01:55:34 +0800
Subject: [PATCH 48/56] Update actions deps

---
 .github/workflows/sync.yml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 3fed1aca7..0788a37c0 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -20,14 +20,14 @@ jobs:
       LOCALE: zh_CN
       VERSION: ${{ inputs.version }}
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Checkout CPython
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           repository: 'python/cpython'
           ref: ${{env.VERSION}}
           path: cpython
-      - uses: actions/cache/restore@v3
+      - uses: actions/cache/restore@v4
         with:
           path: |
             cpython/Doc/build
@@ -35,7 +35,7 @@ jobs:
           key: cache-${{ inputs.version }}-${{ github.run_id }}
           restore-keys: cache-${{ inputs.version }}-
       - name: Checkout Current Branch
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           ref: ${{env.VERSION}}
           path: docs
@@ -46,14 +46,14 @@ jobs:
         run: .github/scripts/update.sh
         env:
           TX_TOKEN: ${{ secrets.TRANSIFEX_APIKEY }}
-      - uses: actions/cache/restore@v3
+      - uses: actions/cache/restore@v4
         with:
           path: cpython/Doc/build
           key: cache-${{ inputs.version }}-${{ github.run_id }}
           restore-keys: cache-${{ inputs.version }}-
       - name: build
         run: .github/scripts/build.sh
-      - uses: actions/cache/save@v3
+      - uses: actions/cache/save@v4
         with:
           path: |
             cpython/Doc/build

From 5de9a3a57dc9b9887122a3c8edc4dd347815f737 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sat, 11 May 2024 04:43:40 +0000
Subject: [PATCH 49/56] Add version 3.13

---
 .github/workflows/python-310.yml |  2 +-
 .github/workflows/python-311.yml |  2 +-
 .github/workflows/python-312.yml |  4 ++--
 .github/workflows/python-313.yml | 16 ++++++++++++++++
 .github/workflows/python-39.yml  |  2 +-
 README.rst                       |  7 ++++++-
 6 files changed, 27 insertions(+), 6 deletions(-)
 create mode 100644 .github/workflows/python-313.yml

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 6607518d7..84950aa6a 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "26 * * * *"
+    - cron: "22 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index 9566d743f..2fd788f9f 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "38 * * * *"
+    - cron: "32 * * * *"
 
 jobs:
   sync:
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index d1bb99d95..289d6e577 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -5,12 +5,12 @@ on:
     branches:
       - master
   schedule:
-    - cron: "50 * * * *"
+    - cron: "42 * * * *"
 
 jobs:
   sync:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.12"
-      tx_project: "python-newest"
+      tx_project: "python-312"
     secrets: inherit
diff --git a/.github/workflows/python-313.yml b/.github/workflows/python-313.yml
new file mode 100644
index 000000000..9391d7e23
--- /dev/null
+++ b/.github/workflows/python-313.yml
@@ -0,0 +1,16 @@
+name: python-313
+
+on:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "52 * * * *"
+
+jobs:
+  sync:
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.13"
+      tx_project: "python-newest"
+    secrets: inherit
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 3d6e5da9a..4284b55b7 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -5,7 +5,7 @@ on:
     branches:
       - master
   schedule:
-    - cron: "14 * * * *"
+    - cron: "12 * * * *"
 
 jobs:
   sync:
diff --git a/README.rst b/README.rst
index 5c38d3110..c18935a85 100644
--- a/README.rst
+++ b/README.rst
@@ -12,11 +12,16 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.13 <https://github.com/python/python-docs-zh-cn/tree/3.13>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-313/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-313
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.13%2F.stat.json&query=%24.translation&label=zh-CN
+          :target: https://app.transifex.com/python-doc/python-newest/
    * - `3.12 <https://github.com/python/python-docs-zh-cn/tree/3.12>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-312/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-312
      - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.12%2F.stat.json&query=%24.translation&label=zh-CN
-          :target: https://app.transifex.com/python-doc/python-newest/
+          :target: https://app.transifex.com/python-doc/python-312/
    * - `3.11 <https://github.com/python/python-docs-zh-cn/tree/3.11>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-311/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-311

From c6514dd2d9f205de8509d4c78c4020ec7d73b2e6 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Wed, 21 Aug 2024 20:34:56 +0800
Subject: [PATCH 50/56] update build command to use fresh environment

Attempt to resolve the environment cache cause building stuck issues.
---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 64b6cc9fc..46c229e10 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -15,4 +15,4 @@ cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
 pip3 install -q -r requirements.txt
-sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -W --keep-going -W . build/html 2> >(error)
+sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -E --keep-going -W . build/html 2> >(error)

From d9be07d661527b849d9ce617470f3dc9e535946c Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Fri, 11 Oct 2024 18:52:38 +0800
Subject: [PATCH 51/56] Remove python3.8 as it has reached EOL

---
 .github/workflows/python-38.yml |  7 +------
 README.rst                      | 10 +++++-----
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/.github/workflows/python-38.yml b/.github/workflows/python-38.yml
index 4da2959f9..9d0bc6daf 100644
--- a/.github/workflows/python-38.yml
+++ b/.github/workflows/python-38.yml
@@ -1,11 +1,6 @@
 name: python-38
 
-on:
-  push:
-    branches:
-      - master
-  schedule:
-    - cron: "2 * * * *"
+on: workflow_dispatch
 
 jobs:
   sync:
diff --git a/README.rst b/README.rst
index c18935a85..a4eb6ee9a 100644
--- a/README.rst
+++ b/README.rst
@@ -37,11 +37,6 @@ Maintained versions:
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-39
      - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.9%2F.stat.json&query=%24.translation&label=zh-CN
           :target: https://app.transifex.com/python-doc/python-39/
-   * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
-     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
-          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
-     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.8%2F.stat.json&query=%24.translation&label=zh-CN
-          :target: https://app.transifex.com/python-doc/python-38/
 
 EOL versions:
 
@@ -51,6 +46,11 @@ EOL versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.8 <https://github.com/python/python-docs-zh-cn/tree/3.8>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-38/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-38
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.8%2F.stat.json&query=%24.translation&label=zh-CN
+          :target: https://app.transifex.com/python-doc/python-38/
    * - `3.7 <https://github.com/python/python-docs-zh-cn/tree/3.7>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-37/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-37

From 8e0a0fd29f68b83c8e1d24660a329a382102362b Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Fri, 11 Oct 2024 19:20:11 +0800
Subject: [PATCH 52/56] Fix error: externally-managed-environment in GitHub
 Actions runner

---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index 46c229e10..e811371e6 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,5 +14,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-pip3 install -q -r requirements.txt
+pip3 install -q -r requirements.txt --break-system-packages
 sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -E --keep-going -W . build/html 2> >(error)

From 2928f3045178da9ca2c6a088d8cd5ae319c53444 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sun, 13 Oct 2024 08:16:11 +0000
Subject: [PATCH 53/56] add workflow dispatch triggers

---
 .github/workflows/python-310.yml | 1 +
 .github/workflows/python-311.yml | 1 +
 .github/workflows/python-312.yml | 1 +
 .github/workflows/python-313.yml | 1 +
 .github/workflows/python-39.yml  | 1 +
 5 files changed, 5 insertions(+)

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 84950aa6a..27c0ef443 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -1,6 +1,7 @@
 name: python-310
 
 on:
+  workflow_dispatch
   push:
     branches:
       - master
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index 2fd788f9f..166ca8bfc 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -1,6 +1,7 @@
 name: python-311
 
 on:
+  workflow_dispatch
   push:
     branches:
       - master
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 289d6e577..02ee39a5b 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -1,6 +1,7 @@
 name: python-312
 
 on:
+  workflow_dispatch
   push:
     branches:
       - master
diff --git a/.github/workflows/python-313.yml b/.github/workflows/python-313.yml
index 9391d7e23..5c13ff70f 100644
--- a/.github/workflows/python-313.yml
+++ b/.github/workflows/python-313.yml
@@ -1,6 +1,7 @@
 name: python-313
 
 on:
+  workflow_dispatch
   push:
     branches:
       - master
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index 4284b55b7..bec73ca6b 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -1,6 +1,7 @@
 name: python-39
 
 on:
+  workflow_dispatch
   push:
     branches:
       - master

From 294909422abfb96d7be9f4c89e6ad437c0793aa5 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sun, 13 Oct 2024 08:19:10 +0000
Subject: [PATCH 54/56] add workflow dispatch triggers

---
 .github/workflows/python-310.yml | 2 +-
 .github/workflows/python-311.yml | 2 +-
 .github/workflows/python-312.yml | 2 +-
 .github/workflows/python-313.yml | 2 +-
 .github/workflows/python-39.yml  | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/python-310.yml b/.github/workflows/python-310.yml
index 27c0ef443..35a148f47 100644
--- a/.github/workflows/python-310.yml
+++ b/.github/workflows/python-310.yml
@@ -1,7 +1,7 @@
 name: python-310
 
 on:
-  workflow_dispatch
+  workflow_dispatch:
   push:
     branches:
       - master
diff --git a/.github/workflows/python-311.yml b/.github/workflows/python-311.yml
index 166ca8bfc..4fa85bb77 100644
--- a/.github/workflows/python-311.yml
+++ b/.github/workflows/python-311.yml
@@ -1,7 +1,7 @@
 name: python-311
 
 on:
-  workflow_dispatch
+  workflow_dispatch:
   push:
     branches:
       - master
diff --git a/.github/workflows/python-312.yml b/.github/workflows/python-312.yml
index 02ee39a5b..75cc1d35e 100644
--- a/.github/workflows/python-312.yml
+++ b/.github/workflows/python-312.yml
@@ -1,7 +1,7 @@
 name: python-312
 
 on:
-  workflow_dispatch
+  workflow_dispatch:
   push:
     branches:
       - master
diff --git a/.github/workflows/python-313.yml b/.github/workflows/python-313.yml
index 5c13ff70f..657d53443 100644
--- a/.github/workflows/python-313.yml
+++ b/.github/workflows/python-313.yml
@@ -1,7 +1,7 @@
 name: python-313
 
 on:
-  workflow_dispatch
+  workflow_dispatch:
   push:
     branches:
       - master
diff --git a/.github/workflows/python-39.yml b/.github/workflows/python-39.yml
index bec73ca6b..39305f585 100644
--- a/.github/workflows/python-39.yml
+++ b/.github/workflows/python-39.yml
@@ -1,7 +1,7 @@
 name: python-39
 
 on:
-  workflow_dispatch
+  workflow_dispatch:
   push:
     branches:
       - master

From ac84487938688e71d42f5b64b431d866a453ebe4 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Tue, 26 Nov 2024 21:18:41 +0800
Subject: [PATCH 55/56] remove the break-system-packages option to fix the
 build

---
 .github/scripts/build.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/scripts/build.sh b/.github/scripts/build.sh
index e811371e6..46c229e10 100755
--- a/.github/scripts/build.sh
+++ b/.github/scripts/build.sh
@@ -14,5 +14,5 @@ error() {
 cd cpython/Doc || exit 1
 mkdir -p locales/"$LOCALE"/
 ln -sfn "$(realpath ../../docs)" locales/"$LOCALE"/LC_MESSAGES
-pip3 install -q -r requirements.txt --break-system-packages
+pip3 install -q -r requirements.txt
 sphinx-build -b dummy -d build/doctrees  -j auto -D language=$LOCALE -D gettext_compact=0 -E --keep-going -W . build/html 2> >(error)

From d0a223a5bc1cd5d896d223478211c45ec79352b5 Mon Sep 17 00:00:00 2001
From: A <5249513+Dumeng@users.noreply.github.com>
Date: Sat, 10 May 2025 14:03:34 +0800
Subject: [PATCH 56/56] Add version 3.14

---
 .github/workflows/python-313.yml |  2 +-
 .github/workflows/python-314.yml | 17 +++++++++++++++++
 README.rst                       |  7 ++++++-
 3 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 .github/workflows/python-314.yml

diff --git a/.github/workflows/python-313.yml b/.github/workflows/python-313.yml
index 657d53443..5cf9c8340 100644
--- a/.github/workflows/python-313.yml
+++ b/.github/workflows/python-313.yml
@@ -13,5 +13,5 @@ jobs:
     uses: ./.github/workflows/sync.yml
     with:
       version: "3.13"
-      tx_project: "python-newest"
+      tx_project: "python-313"
     secrets: inherit
diff --git a/.github/workflows/python-314.yml b/.github/workflows/python-314.yml
new file mode 100644
index 000000000..9118a8ce8
--- /dev/null
+++ b/.github/workflows/python-314.yml
@@ -0,0 +1,17 @@
+name: python-314
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: "2 * * * *"
+
+jobs:
+  sync:
+    uses: ./.github/workflows/sync.yml
+    with:
+      version: "3.14"
+      tx_project: "python-newest"
+    secrets: inherit
diff --git a/README.rst b/README.rst
index a4eb6ee9a..f17ac8294 100644
--- a/README.rst
+++ b/README.rst
@@ -12,11 +12,16 @@ Maintained versions:
    * - Version
      - Sync status
      - Translation progress
+   * - `3.14 <https://github.com/python/python-docs-zh-cn/tree/3.14>`_
+     - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-314/badge.svg
+          :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-314
+     - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.14%2F.stat.json&query=%24.translation&label=zh-CN
+          :target: https://app.transifex.com/python-doc/python-newest/
    * - `3.13 <https://github.com/python/python-docs-zh-cn/tree/3.13>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-313/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-313
      - .. image:: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpython%2Fpython-docs-zh-cn%2F3.13%2F.stat.json&query=%24.translation&label=zh-CN
-          :target: https://app.transifex.com/python-doc/python-newest/
+          :target: https://app.transifex.com/python-doc/python-313/
    * - `3.12 <https://github.com/python/python-docs-zh-cn/tree/3.12>`_
      - .. image:: https://github.com/python/python-docs-zh-cn/workflows/python-312/badge.svg
           :target: https://github.com/python/python-docs-zh-cn/actions?workflow=python-312