mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 19:59:12 +00:00
ci: sync translations from develop to version-16-hotfix (#55348)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
49
.github/helper/merge_po_files.py
vendored
Normal file
49
.github/helper/merge_po_files.py
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Overlay develop's .po translations onto hotfix's .po files.
|
||||||
|
|
||||||
|
Called by sync_hotfix_translations.sh before `bench update-po-files`.
|
||||||
|
Merge rules:
|
||||||
|
a. msgid absent from develop → keep hotfix's existing msgstr
|
||||||
|
b. language not yet in hotfix → copy file as-is (bench will filter to main.pot)
|
||||||
|
c. msgid present in both → use develop's msgstr
|
||||||
|
"""
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from babel.messages.pofile import read_po, write_po
|
||||||
|
|
||||||
|
DEVELOP = Path("/tmp/develop-po/erpnext/locale/")
|
||||||
|
LOCALE = Path("./apps/erpnext/erpnext/locale/")
|
||||||
|
|
||||||
|
added = updated = 0
|
||||||
|
|
||||||
|
for src in sorted(DEVELOP.glob("*.po")):
|
||||||
|
dst = LOCALE / src.name
|
||||||
|
|
||||||
|
with src.open("rb") as f:
|
||||||
|
dev = read_po(f)
|
||||||
|
|
||||||
|
if not dst.exists():
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
added += 1
|
||||||
|
print(f" [new] {src.name}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
with dst.open("rb") as f:
|
||||||
|
hf = read_po(f)
|
||||||
|
|
||||||
|
changes = 0
|
||||||
|
for msg in hf:
|
||||||
|
if msg.id and msg.id in dev and dev[msg.id].string and dev[msg.id].string != msg.string:
|
||||||
|
msg.string = dev[msg.id].string
|
||||||
|
changes += 1
|
||||||
|
|
||||||
|
if changes:
|
||||||
|
with dst.open("wb") as f:
|
||||||
|
write_po(f, hf)
|
||||||
|
updated += 1
|
||||||
|
print(f" [updated] {src.name} ({changes} msgstr(s) from develop)")
|
||||||
|
else:
|
||||||
|
print(f" [no-op] {src.name}")
|
||||||
|
|
||||||
|
print(f"\n{added} new language(s), {updated} updated.")
|
||||||
85
.github/helper/sync_hotfix_translations.sh
vendored
Normal file
85
.github/helper/sync_hotfix_translations.sh
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Syncs Crowdin translations from develop to version-16-hotfix.
|
||||||
|
# Merge logic: see merge_po_files.py.
|
||||||
|
# Env: GH_TOKEN, PR_REVIEWER, GITHUB_WORKSPACE (all set by Actions).
|
||||||
|
|
||||||
|
set -e
|
||||||
|
cd ~ || exit
|
||||||
|
|
||||||
|
echo "=== Setting up bench ==="
|
||||||
|
pip install frappe-bench
|
||||||
|
bench -v init frappe-bench --skip-assets --skip-redis-config-generation --python "$(which python)"
|
||||||
|
cd ./frappe-bench || exit
|
||||||
|
bench get-app --skip-assets erpnext "${GITHUB_WORKSPACE}"
|
||||||
|
|
||||||
|
echo "=== Fetching develop's .po files ==="
|
||||||
|
mkdir -p /tmp/develop-po
|
||||||
|
git -C "${GITHUB_WORKSPACE}" fetch origin develop
|
||||||
|
git -C "${GITHUB_WORKSPACE}" archive origin/develop erpnext/locale/ \
|
||||||
|
| tar -xf - -C /tmp/develop-po/
|
||||||
|
|
||||||
|
po_count=$(find /tmp/develop-po/erpnext/locale -name "*.po" | wc -l)
|
||||||
|
if [ "${po_count}" -eq 0 ]; then
|
||||||
|
echo "ERROR: No .po files found in develop's archive. Aborting." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Extracted ${po_count} .po file(s) from develop."
|
||||||
|
|
||||||
|
echo "=== Merging and reconciling ==="
|
||||||
|
env/bin/python "${GITHUB_WORKSPACE}/.github/helper/merge_po_files.py"
|
||||||
|
bench update-po-files --app erpnext
|
||||||
|
|
||||||
|
cd ./apps/erpnext || exit
|
||||||
|
|
||||||
|
git config user.email "developers@erpnext.com"
|
||||||
|
git config user.name "frappe-pr-bot"
|
||||||
|
git remote set-url upstream https://github.com/frappe/erpnext.git
|
||||||
|
|
||||||
|
if git diff --quiet erpnext/locale/; then
|
||||||
|
echo "Translations are already up to date. No PR needed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Changed files:"
|
||||||
|
git diff --name-only erpnext/locale/
|
||||||
|
|
||||||
|
echo "=== Committing and pushing ==="
|
||||||
|
git checkout -B translations_hotfix
|
||||||
|
git add erpnext/locale/
|
||||||
|
git commit -m "fix: sync translations to version-16-hotfix"
|
||||||
|
gh auth setup-git
|
||||||
|
git push -u upstream translations_hotfix --force
|
||||||
|
|
||||||
|
echo "=== Opening PR (if not already open) ==="
|
||||||
|
existing_pr=$(gh pr list \
|
||||||
|
--base "version-16-hotfix" \
|
||||||
|
--head "translations_hotfix" \
|
||||||
|
--state open \
|
||||||
|
--json number \
|
||||||
|
--jq 'length' \
|
||||||
|
-R frappe/erpnext)
|
||||||
|
|
||||||
|
if [ "${existing_pr}" -gt 0 ]; then
|
||||||
|
echo "PR already open — branch updated in place. No new PR needed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
gh pr create \
|
||||||
|
--base "version-16-hotfix" \
|
||||||
|
--head "translations_hotfix" \
|
||||||
|
--title "fix: sync translations to version-16-hotfix" \
|
||||||
|
--body "Automated sync of Crowdin translations from \`develop\` to \`version-16-hotfix\`.
|
||||||
|
|
||||||
|
A 3-way merge is performed per language, then \`bench update-po-files\` reconciles each \`.po\` against hotfix's \`main.pot\`:
|
||||||
|
|
||||||
|
| Case | Condition | Result |
|
||||||
|
|------|-----------|--------|
|
||||||
|
| **a** | \`msgid\` in hotfix's \`main.pot\`, **not** in develop's \`.po\` | Hotfix's existing \`msgstr\` is **preserved** (string removed from develop but still needed in hotfix) |
|
||||||
|
| **b** | \`msgid\` **not** in hotfix's \`main.pot\` | **Dropped** from hotfix's \`.po\` |
|
||||||
|
| **c** | \`msgid\` in both hotfix's \`main.pot\` and develop's \`.po\` | Develop's \`msgstr\` is used (Crowdin translation wins) |
|
||||||
|
|
||||||
|
Generated by the \`sync-hotfix-translations\` workflow." \
|
||||||
|
--label "translation" \
|
||||||
|
--label "skip-release-notes" \
|
||||||
|
--reviewer "${PR_REVIEWER}" \
|
||||||
|
-R frappe/erpnext
|
||||||
62
.github/workflows/sync-hotfix-translations.yml
vendored
Normal file
62
.github/workflows/sync-hotfix-translations.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Syncs Crowdin translations from develop into version-16-hotfix,
|
||||||
|
# filtered to only the strings present in hotfix's main.pot.
|
||||||
|
#
|
||||||
|
# Trigger: fires when version-16-hotfix's main.pot is updated — i.e., when
|
||||||
|
# the POT update PR from generate-pot-file.yml is merged. At that point
|
||||||
|
# hotfix's main.pot is authoritative, and this workflow fetches develop's
|
||||||
|
# latest .po files (Crowdin translations) and merges them against it.
|
||||||
|
#
|
||||||
|
# The weekly schedule acts as a safety net to pick up any Crowdin translations
|
||||||
|
# that arrived on develop between POT update cycles.
|
||||||
|
#
|
||||||
|
# POT file generation remains in generate-pot-file.yml (unchanged).
|
||||||
|
# Maintain this file on develop only; it always acts on version-16-hotfix.
|
||||||
|
|
||||||
|
name: Sync translations to version-16-hotfix
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- version-16-hotfix
|
||||||
|
paths:
|
||||||
|
- "erpnext/locale/main.pot" # fires exactly when the POT update PR merges
|
||||||
|
schedule:
|
||||||
|
# 10:00 UTC Monday — safety net for Crowdin translations that arrived
|
||||||
|
# on develop since the last POT update PR merged to version-16-hotfix
|
||||||
|
- cron: "0 10 * * 1"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Prevent concurrent runs. cancel-in-progress: false because a mid-flight
|
||||||
|
# `git push` + `gh pr create` cancellation can leave an orphaned remote branch.
|
||||||
|
concurrency:
|
||||||
|
group: sync-hotfix-translations
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-translations:
|
||||||
|
name: Sync translations to version-16-hotfix
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout version-16-hotfix
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
ref: version-16-hotfix
|
||||||
|
# Full history so `git fetch origin develop` inside the helper works
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Python
|
||||||
|
uses: actions/setup-python@v6
|
||||||
|
with:
|
||||||
|
# Match generate-pot-file.yml — bench runs under the same frappe
|
||||||
|
# stack and must use the same Python version.
|
||||||
|
python-version: "3.14"
|
||||||
|
|
||||||
|
- name: Run sync script
|
||||||
|
run: |
|
||||||
|
bash ${GITHUB_WORKSPACE}/.github/helper/sync_hotfix_translations.sh
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
PR_REVIEWER: barredterra # change to your GitHub username if you copied this file
|
||||||
Reference in New Issue
Block a user