ci: add ja-JP publish workflow
This commit is contained in:
parent
a2fe84c9e1
commit
3d8c6c5a4e
183
.github/workflows/translate-ja-jp.yml
vendored
Normal file
183
.github/workflows/translate-ja-jp.yml
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
name: Translate ja-JP
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types:
|
||||
- translate-ja-jp-release
|
||||
schedule:
|
||||
- cron: "47 3 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: translate-ja-jp
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
translate-ja-jp:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout publish repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Read source metadata
|
||||
id: meta
|
||||
run: |
|
||||
node - <<'NODE'
|
||||
const fs = require("node:fs");
|
||||
const path = ".openclaw-sync/source.json";
|
||||
const data = JSON.parse(fs.readFileSync(path, "utf8"));
|
||||
if (!data.repository || !data.sha) {
|
||||
throw new Error(`invalid source metadata in ${path}`);
|
||||
}
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `repository=${data.repository}\n`);
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `sha=${data.sha}\n`);
|
||||
NODE
|
||||
|
||||
- name: Checkout source repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ steps.meta.outputs.repository }}
|
||||
ref: ${{ steps.meta.outputs.sha }}
|
||||
path: source
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.23"
|
||||
|
||||
- name: Prune stale ja-JP pages
|
||||
run: |
|
||||
python - <<'PY'
|
||||
from pathlib import Path
|
||||
root = Path("docs")
|
||||
locale_root = root / "ja-JP"
|
||||
if not locale_root.exists():
|
||||
raise SystemExit(0)
|
||||
for path in sorted(locale_root.rglob("*"), reverse=True):
|
||||
if path.is_dir():
|
||||
if not any(path.iterdir()):
|
||||
path.rmdir()
|
||||
continue
|
||||
rel = path.relative_to(locale_root)
|
||||
source = root / rel
|
||||
if not source.exists():
|
||||
path.unlink()
|
||||
for path in sorted(locale_root.rglob("*"), reverse=True):
|
||||
if path.is_dir() and not any(path.iterdir()):
|
||||
path.rmdir()
|
||||
PY
|
||||
|
||||
- name: Build pending docs file list
|
||||
id: pending
|
||||
run: |
|
||||
python - <<'PY'
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
source_hash_re = re.compile(r'^x-i18n:\n(?: .*\n)*? source_hash: ([0-9a-f]{64})$', re.M)
|
||||
|
||||
def stored_source_hash(path: Path) -> str:
|
||||
if not path.exists():
|
||||
return ""
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
match = source_hash_re.search(text)
|
||||
if not match:
|
||||
return ""
|
||||
return match.group(1).strip()
|
||||
|
||||
all_files = []
|
||||
pending_files = []
|
||||
for path in Path("docs").rglob("*"):
|
||||
if not path.is_file():
|
||||
continue
|
||||
if path.suffix.lower() not in {".md", ".mdx"}:
|
||||
continue
|
||||
rel = path.as_posix()
|
||||
if rel.startswith("docs/zh-CN/"):
|
||||
continue
|
||||
if rel.startswith("docs/ja-JP/"):
|
||||
continue
|
||||
if rel.startswith("docs/.generated/"):
|
||||
continue
|
||||
all_files.append(str(path.resolve()))
|
||||
|
||||
rel_doc = path.relative_to("docs")
|
||||
locale_path = Path("docs") / "ja-JP" / rel_doc
|
||||
source_hash = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
if stored_source_hash(locale_path) != source_hash:
|
||||
pending_files.append(str(path.resolve()))
|
||||
|
||||
Path(".openclaw-sync").mkdir(exist_ok=True)
|
||||
Path(".openclaw-sync/docs-i18n-ja-files.txt").write_text("\n".join(pending_files) + ("\n" if pending_files else ""))
|
||||
print(f"all_docs={len(all_files)} pending_docs={len(pending_files)}")
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
|
||||
fh.write(f"all_count={len(all_files)}\n")
|
||||
fh.write(f"pending_count={len(pending_files)}\n")
|
||||
PY
|
||||
|
||||
- name: Translate changed docs into ja-JP
|
||||
if: steps.pending.outputs.pending_count != '0'
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY }}
|
||||
OPENCLAW_DOCS_I18N_PROVIDER: openai
|
||||
OPENCLAW_DOCS_I18N_MODEL: gpt-5.4
|
||||
OPENCLAW_DOCS_I18N_PROMPT_TIMEOUT: 10m
|
||||
run: |
|
||||
if [ ! -s .openclaw-sync/docs-i18n-ja-files.txt ]; then
|
||||
echo "No docs files found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mapfile -t DOC_FILES < .openclaw-sync/docs-i18n-ja-files.txt
|
||||
attempt=1
|
||||
max_attempts=5
|
||||
while [ "$attempt" -le "$max_attempts" ]; do
|
||||
echo "docs-i18n attempt $attempt/$max_attempts"
|
||||
if (
|
||||
cd source/scripts/docs-i18n
|
||||
go run . \
|
||||
--docs "$GITHUB_WORKSPACE/docs" \
|
||||
--lang ja-JP \
|
||||
--src en \
|
||||
--mode doc \
|
||||
--thinking low \
|
||||
--parallel 8 \
|
||||
"${DOC_FILES[@]}"
|
||||
); then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$attempt" -eq "$max_attempts" ]; then
|
||||
echo "docs-i18n failed after $max_attempts attempts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
sleep 5
|
||||
done
|
||||
|
||||
- name: Commit ja-JP refresh
|
||||
run: |
|
||||
if git diff --quiet -- docs/ja-JP docs/.i18n/ja-JP.tm.jsonl; then
|
||||
echo "No ja-JP translation changes."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "openclaw-docs-i18n[bot]"
|
||||
git config user.email "openclaw-docs-i18n[bot]@users.noreply.github.com"
|
||||
git add docs/ja-JP docs/.i18n/ja-JP.tm.jsonl
|
||||
git commit -m "chore(i18n): refresh ja-JP translations"
|
||||
git push origin HEAD:main
|
||||
11
README.md
11
README.md
@ -8,27 +8,28 @@ Source of truth lives in [`openclaw/openclaw`](https://github.com/openclaw/openc
|
||||
|
||||
1. English docs are authored in `openclaw/openclaw`.
|
||||
2. `openclaw/openclaw/.github/workflows/docs-sync-publish.yml` mirrors the docs tree into this repo.
|
||||
3. This repo stores the published docs tree plus generated zh-CN output.
|
||||
3. This repo stores the published docs tree plus generated locale output.
|
||||
4. `openclaw/docs/.github/workflows/translate-zh-cn.yml` runs once a day, on manual dispatch, and after release dispatches from `openclaw/openclaw` to refresh `docs/zh-CN/**`.
|
||||
5. `openclaw/docs/.github/workflows/translate-ja-jp.yml` does the same for `docs/ja-JP/**`.
|
||||
|
||||
## Translation behavior
|
||||
|
||||
- zh-CN pages are generated output.
|
||||
- zh-CN and ja-JP pages are generated output.
|
||||
- Each translated page stores `x-i18n.source_hash`.
|
||||
- The translate workflow computes a pending file list before calling the model.
|
||||
- If no English source hashes changed, the workflow skips the expensive translation step entirely.
|
||||
- If files changed, only the pending files are translated.
|
||||
- The workflow retries transient model-format failures.
|
||||
- Published releases in `openclaw/openclaw` dispatch an extra zh-CN refresh so release-adjacent docs updates do not wait for the daily cron.
|
||||
- Published releases in `openclaw/openclaw` dispatch extra zh-CN and ja-JP refreshes so release-adjacent docs updates do not wait for the daily cron.
|
||||
|
||||
## Editing rules
|
||||
|
||||
- Do not treat this repo as the primary place for English doc edits.
|
||||
- Make English doc changes in `openclaw/openclaw`, then let sync copy them here.
|
||||
- zh-CN pages in `docs/zh-CN/**` are generated output.
|
||||
- Generated locale pages in `docs/zh-CN/**` and `docs/ja-JP/**` are generated output.
|
||||
- `.openclaw-sync/source.json` records which `openclaw/openclaw` commit this mirror was synced from.
|
||||
|
||||
## Secrets
|
||||
|
||||
- `OPENCLAW_DOCS_SYNC_TOKEN` lives in `openclaw/openclaw` and lets the source repo push into this repo.
|
||||
- `OPENCLAW_DOCS_I18N_OPENAI_API_KEY` lives in this repo and powers zh-CN translation refreshes.
|
||||
- `OPENCLAW_DOCS_I18N_OPENAI_API_KEY` lives in this repo and powers locale translation refreshes.
|
||||
|
||||
@ -0,0 +1 @@
|
||||
|
||||
Loading…
Reference in New Issue
Block a user