diff --git a/.github/workflows/ai-translation.yml b/.github/workflows/ai-translation.yml new file mode 100644 index 000000000000..34cf56f3973a --- /dev/null +++ b/.github/workflows/ai-translation.yml @@ -0,0 +1,202 @@ +name: Translation(zh) by AI (docs/ai) + +on: + workflow_dispatch: + inputs: + file_names: + description: "Specify file names to translate under docs/ai (comma-separated list). Example: foo.md,subdir/bar.mdx" + required: false + type: string + default: "" + +env: + DOCS_CN_BASE: release-8.5 + +jobs: + translate: + if: github.repository == 'pingcap/docs-cn' + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + name: Checkout docs-cn + with: + ref: ${{ env.DOCS_CN_BASE }} + path: docs-cn + fetch-depth: 0 + + - uses: actions/checkout@v4 + name: Checkout docs-toolkit + with: + repository: pingcap/docs-toolkit + ref: main + path: docs-toolkit + + - uses: actions/setup-node@v4 + name: Setup node + with: + node-version: 20 + cache: yarn + cache-dependency-path: docs-toolkit/markdown-translator/yarn.lock + + - name: Install deps + shell: bash + run: | + corepack enable + yarn --cwd docs-toolkit/markdown-translator + + - name: Normalize file list + id: normalize + shell: bash + run: | + set -euo pipefail + + files="${{ inputs.file_names }}" + if [ -z "${files}" ]; then + echo "files=" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + IFS=',' read -ra items <<< "${files}" + out="" + for item in "${items[@]}"; do + rel="$(echo "${item}" | xargs)" + [ -z "${rel}" ] && continue + + if [[ "${rel}" != ai/* ]]; then + rel="ai/${rel}" + fi + + if [ -z "${out}" ]; then + out="${rel}" + else + out="${out},${rel}" + fi + done + + echo "files=${out}" >> "${GITHUB_OUTPUT}" + + - name: Prepare docs source working dir + shell: bash + run: | + set -euo pipefail + + src_cfg="docs-cn/latest_translation_commit.json" + if [ ! -f "${src_cfg}" ]; then + echo "::error::Missing ${src_cfg}. Please add it to the base branch so the workflow can track the last translated commit." + exit 1 + fi + + workdir="${{ runner.temp }}/docs-source" + rm -rf "${workdir}" + mkdir -p "${workdir}" + cp "${src_cfg}" "${workdir}/latest_translation_commit.json" + + - name: Download files + uses: pingcap/docs-toolkit/actions/file-diff-update@main + with: + config_file: latest_translation_commit.json + working_directory: ${{ runner.temp }}/docs-source + filter_by_cloud_toc: "false" + folder: "ai" + files: ${{ steps.normalize.outputs.files }} + + - name: Show tmp directory structure + shell: bash + run: | + find "${{ runner.temp }}/docs-source/tmp" -type f | head -200 || true + + - name: Check downloaded files + id: check + shell: bash + run: | + set -euo pipefail + input_dir="${{ runner.temp }}/docs-source/tmp/ai" + if [ ! -d "${input_dir}" ]; then + echo "ai_files=0" >> "${GITHUB_OUTPUT}" + exit 0 + fi + echo "ai_files=$(find "${input_dir}" -type f | wc -l | tr -d ' ')" >> "${GITHUB_OUTPUT}" + + - name: Download variables.json + if: steps.check.outputs.ai_files != '0' + uses: pingcap/docs-toolkit/actions/file-diff-update@main + with: + config_file: latest_translation_commit.json + working_directory: ${{ runner.temp }}/docs-source + filter_by_cloud_toc: "false" + files: variables.json + + - name: Prepare variables + if: steps.check.outputs.ai_files != '0' + shell: bash + run: | + set -euo pipefail + workdir="${{ runner.temp }}/docs-source" + cp "${workdir}/tmp/variables.json" "${workdir}/tmp/ai/variables.json" + + - name: Translate + if: steps.check.outputs.ai_files != '0' + shell: bash + env: + LANGLINK_ACCESS_KEY: ${{ secrets.LANGLINK_ACCESS_KEY }} + LANGLINK_ACCESS_SECRET: ${{ secrets.LANGLINK_ACCESS_SECRET }} + LANGLINK_USER: ${{ secrets.LANGLINK_USER }} + run: | + set -euo pipefail + + node docs-toolkit/markdown-translator/src/index.js \ + --input-dir "${{ runner.temp }}/docs-source/tmp/ai" \ + --output-dir "docs-cn/ai" + + - name: Show output (first 50 files) + if: steps.check.outputs.ai_files != '0' + shell: bash + run: | + cd docs-cn + find ai -type f | head -50 || true + + - name: Persist translation cursor + if: steps.check.outputs.ai_files != '0' + shell: bash + run: | + set -euo pipefail + cp "${{ runner.temp }}/docs-source/latest_translation_commit.json" "docs-cn/latest_translation_commit.json" + + - name: Set build ID + id: build_id + if: steps.check.outputs.ai_files != '0' + shell: bash + run: echo "id=$(date +%s)" >> "$GITHUB_OUTPUT" + + - name: Create PR + if: steps.check.outputs.ai_files != '0' + uses: peter-evans/create-pull-request@v7 + with: + path: docs-cn + token: ${{ github.token }} + branch: zh-translation/ai-${{ steps.build_id.outputs.id }} + base: ${{ env.DOCS_CN_BASE }} + title: "ci: ZH translation(ai) ${{ steps.build_id.outputs.id }}" + body: | + ### What is changed, added or deleted? (Required) + + Translate `pingcap/docs` `docs/ai` to Chinese and sync to `docs-cn/ai`. + + ### Which TiDB version(s) do your changes apply to? (Required) + + - [x] ${{ env.DOCS_CN_BASE }} + + ### What is the related PR or file link(s)? + + ### Do your changes match any of the following descriptions? + + - [ ] Delete files + - [ ] Change aliases + - [ ] Need modification after applied to another branch + - [ ] Might cause conflicts after applied to another branch + delete-branch: true diff --git a/.github/workflows/translation-cron.yml b/.github/workflows/translation-cron.yml new file mode 100644 index 000000000000..46b400359c54 --- /dev/null +++ b/.github/workflows/translation-cron.yml @@ -0,0 +1,23 @@ +name: Translation Cron + +on: + schedule: + # every Wednesday at 11:00 AM + - cron: "0 11 * * 3" + workflow_dispatch: + +jobs: + dispatch-ai-translation: + if: github.repository == 'pingcap/docs-cn' + runs-on: ubuntu-latest + continue-on-error: true + + steps: + - name: Dispatch ai-translation workflow + run: | + curl \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: token ${{ github.token }}" \ + https://api.github.com/repos/${{ github.repository }}/actions/workflows/ai-translation.yml/dispatches \ + -d '{"ref":"master"}'