Problem:
Both execute and update workflows were triggering for the same commit
when a translation PR already existed, causing duplicate auto-sync
commits (e.g., commit 2ddf04bc in PR #167 created two identical commits
in PR #168).
Root Cause:
- Execute workflow (sync_docs_execute.yml) - handles initial PR creation
- Update workflow (sync_docs_update.yml) - handles incremental updates
- Both listen for "Analyze Documentation Changes" workflow completion
- No coordination to prevent both from running when translation PR exists
Solution:
Execute workflow now skips all translation steps if translation branch
already exists, letting the update workflow handle incremental changes.
This ensures only one workflow processes each commit.
Changes:
- Added "Skip if translation PR already exists" step after branch check
- Updated all subsequent steps to check branch_exists != 'true'
- Steps affected: Python setup, dependencies, approval check, translation,
and PR comments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- PR title: "Auto-translations" → "Sync PR #X to cn/jp"
- PR body: More concise, clearer
- Workflow comments: Drastically simplified
- "Translation PR" → "Sync PR"
- Removed verbose sections, kept essential info only
- Success: Link + file count + failures (if any)
- Cancellation: Brief explanation + manual re-run link
- Back-link: One sentence
Before: 20+ line comments with multiple sections
After: 2-5 line comments with just the facts
This makes the multi-language sync feature more straightforward for
doc writers without overwhelming them with information.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fix YAML parsing error caused by multiline template literals in
JavaScript code. Changed from backtick template literals to string
concatenation to avoid YAML parser confusion with markdown syntax.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add handle-cancellation jobs to both Execute and Update workflows to notify
doc writers when their commits are skipped due to rapid updates.
Features:
- Detects when workflows are cancelled due to concurrency
- Extracts PR number from analyze workflow artifacts
- Posts clear notification to PR explaining what happened
- Provides easy manual re-run instructions with direct link
- Recommends "do nothing" as default (latest commit always translated)
This makes the concurrency behavior transparent to doc writers and
gives them an easy path to re-run if needed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Use github.event.workflow_run.head_branch instead of pull_requests array
for concurrency grouping. The pull_requests array is empty in workflow_run
triggered workflows, causing all workflows to use the same empty group.
This ensures:
- Different PRs don't block each other
- Same PR's workflows serialize correctly
- Concurrency control actually works
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add concurrency groups to both Execute and Update workflows
- Prevent race conditions when user pushes multiple commits quickly
- Queue workflows per PR instead of running concurrently
- Remove obsolete should_skip logic made redundant by concurrency groups
This ensures only one translation workflow runs per PR at a time,
eliminating git conflicts on the translation branch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Instead of removing 'synchronize' trigger from analyze workflow (which is
needed for security checks), we now make the execute workflow skip when:
- It's an incremental update (synchronize event)
- AND a translation branch already exists
This ensures:
- Security checks always run (analyze workflow on all PR events)
- No race condition (execute skips, update handles incremental changes)
- Initial PRs still work (execute runs when no translation branch exists)
The logic:
- PR opened/reopened: analyze → execute → create new translation PR
- PR synchronized: analyze (security) + update → update existing translation PR
- Execute workflow sees incremental=true + branch_exists=true and skips
* refactor: extract translation logic into reusable Python script
- Created tools/translate/translate_pr.py to consolidate translation workflow
- Refactored sync_docs_execute.yml: reduced from 941 to 513 lines
- Refactored sync_docs_update.yml: reduced from 552 to 381 lines
- Total reduction: ~600 lines of duplicated workflow YAML
Benefits:
- Single source of truth for translation logic
- All fixes (English file removal, branch handling) automatically apply to both workflows
- Easier to test and maintain
- Reusable Python module with proper error handling
The script handles:
- Branch setup (create new or checkout existing)
- Translation of documentation files
- English file removal (fixes the leak bug)
- Committing and pushing changes
- Creating/updating translation PRs
- JSON output for workflow integration
* touch ups
* more touch ups
The issue was that line 320 checks out English files from the PR
(git checkout $HEAD_SHA -- en/) for translation purposes, but these
files remained in the working directory when committing.
The previous fix (find command at line 691) wasn't effective because:
1. It only removed files matching ./en/* pattern
2. Files might have already been staged by git
This fix:
1. Uses rm -rf to explicitly remove en/*.md and en/*.mdx files
2. Explicitly unstages any en/ files with git reset
3. Runs right before git add to ensure clean commits
The branch existence check was running before the repo was checked out,
causing git ls-remote to fail or return incorrect results. This led to
the workflow creating new branches instead of checking out existing ones,
resulting in:
1. English source files leaking into translation branches
2. Non-fast-forward push errors on incremental updates
Moving the check after PR branch checkout ensures we have full repo
access when checking if the translation branch exists.
After checkout translation branch, remove English source files that remain
in working directory from PR branch checkout. This prevents English files
from being accidentally committed to translation PR.
Also addresses issue where first Japanese file was being modified during
incremental updates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When translation branch exists remotely, fetch and checkout it before
making incremental commits. This prevents non-fast-forward errors.
Fixes the issue where second commit would fail to push because it was
trying to push from PR branch to translation branch without checking
out the translation branch first.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace heredoc syntax with bash variable assignments using $'\n' for newlines.
Fix indentation of JavaScript template literals in script blocks.
Root cause: Multi-line strings in bash and JavaScript template literals
must be properly indented within YAML literal block scalars to prevent
parser errors.
\ud83e\udd16 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comments to trigger GitHub to re-scan and update workflow metadata.
This should fix the issue where workflow names show as file paths instead
of the defined name field.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Use heredoc with command substitution for multi-line git commit messages
in bash scripts within YAML workflows to prevent parsing errors.
Fixes:
- sync_docs_execute.yml: Both incremental and initial commit messages
- sync_docs_update.yml: Update commit messages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Implements full incremental translation system with commit-based change detection:
## Key Features
### 1. Incremental Change Detection (analyze workflow)
- Detects synchronize events and compares with last processed commit
- Queries translation PR for Last-Processed-Commit from comments
- Falls back to github.event.before, then PR base
- Passes is_incremental flag to sync plan
### 2. Append-Only Translation Commits (execute workflow)
- Checks if translation branch exists before creating/updating
- For existing branches: fetches and appends new commit
- For new branches: creates initial translation commit
- Embeds Last-Processed-Commit: SHA in commit message
- Removes --force push to preserve history
- Adds tracking comment to translation PR
### 3. Incremental Update System (update workflow)
- Queries translation PR for last processed commit
- Uses incremental comparison range for re-translation
- Appends update commits with tracking metadata
- No force-push - preserves full commit history
## Benefits
- **Efficiency**: Only translates changed files (~10x API reduction)
- **Traceability**: 1:1 mapping between source and translation commits
- **Robustness**: Handles force-pushes gracefully via persistent tracking
- **History**: Preserved translation timeline, not overwritten
## Breaking Changes
None - workflows are backward compatible with existing PRs.
## Changes
### Unified Configuration
- Centralized all language configuration in `tools/translate/config.json`
- Added `source_language`, `target_languages`, and `languages` structure
- Merged translation notices from `notices.json` into language configs
- Each language now has: code, name, directory, and translation_notice
### Updated sync_and_translate.py
- Removed hardcoded LANGUAGES dict and TARGET_LANGUAGES list
- Enhanced load_config() with validation
- Added helper methods for language info access
- All methods now use config-based language properties
### Updated main.py
- Added config loading at module level
- Dynamically builds docs_structure from config
- Keeps plugin-dev/versioned paths hardcoded as requested
### Updated workflow
- .github/workflows/sync_docs_execute.yml now loads config
- Replaced all hardcoded language references with config values
### Cleanup
- Removed deprecated notices.json
### Test File
- Added en/testing/config-refactor-test.mdx to test the refactoring
- Added to docs.json to trigger auto-translation workflow
## Benefits
- Single source of truth for language configuration
- Adding new languages requires only config.json changes
- No code changes needed to add/modify languages
- Better validation and error handling
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improved auto-translation system to better handle updates to existing documentation:
**Core Changes:**
- Updated translate_text() to accept optional `the_doc_exist` and `diff_original` parameters
- Added get_file_diff() helper method to retrieve git diffs for specific files
- Enhanced translate_file_with_notice() to pass optional parameters to translation API
**Modified File Handling:**
- Refactored translate_new_and_modified_files() to distinguish between added and modified files
- For modified files: loads existing translation and retrieves git diff
- For added files: continues with existing flow (no additional inputs needed)
- Passes both existing translation and diff to Dify API for context-aware updates
**Workflow Updates:**
- Updated sync_docs_execute.yml inline secure_sync.py script
- Detects file status (added vs modified) using git diff
- Loads existing translations for modified files
- Retrieves diffs for modified files
- Passes appropriate inputs based on file status
**Benefits:**
- New translations for modified files generated based on existing translation and diff
- Maintains translation consistency across updates
- Reduces re-translation of unchanged content
- Improves translation quality for incremental changes
🤖 Generated with Claude Code
Improvements:
- Add detailed logging for git diff detection of deleted files
- Add comprehensive logging in sync_docs_json_incremental for deletions
- Track each step of the deletion process to aid debugging
- Add error handling and traceback output for failed operations
- Log dropdown search process and removal attempts
This will help diagnose why cn/jp entries are not being removed from
docs.json when English files are deleted. The test in test_delete_logic.py
proves the remove_page_from_structure method works correctly, so the issue
must be in how deleted_files are detected or how the workflow calls the sync.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, the workflows only removed entries from docs.json but did not
delete the actual cn/ and jp/ translation files when English files were deleted.
Changes:
- Add file deletion logic in sync_docs_execute.yml
- Add file deletion logic in sync_docs_update.yml
- Delete corresponding cn/ and jp/ files when en/ files are deleted
- Clean up empty parent directories after file deletion
- Track deleted files in workflow results
This ensures that when English documentation is deleted, the corresponding
translations are also removed from the repository, keeping the codebase clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>