Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/i18n-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- 'i18n/**'
- 'content/**'
- 'hack/check-i18n.sh'
- 'hack/i18n/**'
- '.github/workflows/i18n-lint.yml'
push:
branches:
Expand All @@ -14,6 +15,7 @@ on:
- 'i18n/**'
- 'content/**'
- 'hack/check-i18n.sh'
- 'hack/i18n/**'
- '.github/workflows/i18n-lint.yml'
workflow_dispatch:

Expand All @@ -34,3 +36,15 @@ jobs:
persist-credentials: false
- name: Check i18n key parity and translation freshness
run: ./hack/check-i18n.sh
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Run i18n pipeline unit tests
# Guards the pure functions of the translation pipeline — including the
# ref/relref deref that keeps a partially-translated page from breaking
# the Hugo build. Only pyyaml is needed; the Claude SDK is imported lazily
# at runtime, not at test-import time.
run: |
python3 -m pip install --quiet pyyaml
python3 hack/i18n/test_i18n.py
111 changes: 111 additions & 0 deletions .github/workflows/i18n-translate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: i18n translate

# Daily translation run, one weekly PR — the same contract as hack/i18n/run-daily.sh,
# moved off a maintainer's clone and personal Max subscription onto CI and an
# ORG-OWNED Anthropic API key (auth: api-key). Nothing reaches production
# automatically: the run pushes to a weekly branch and opens a PR a maintainer
# merges. No auto-merge, CODEOWNERS/branch protection untouched.
#
# Required secret:
# I18N_ANTHROPIC_API_KEY — an organization-owned Anthropic API key (metered).
# Optional secret:
# I18N_GH_TOKEN — a PAT/app token used to push the branch and open the
# PR so its checks (i18n-lint, DCO) actually run; the
# default GITHUB_TOKEN cannot trigger them. Without it
# the run still works, but the PR opens with no checks.
#
# Until I18N_ANTHROPIC_API_KEY exists the job is a green no-op (see the guard step),
# so enabling the schedule before provisioning the key does not spam failures.
#
# Spend is bounded twice per run: a page limit (DEFAULT_PAGE_LIMIT on the schedule)
# and a wall-clock budget well inside timeout-minutes, so translate.py stops taking
# new pages while there is still time to commit and push what it has. A run killed
# by the timeout would lose every page it translated. Set a spend limit on the
# key's Anthropic workspace as the outer guard.

on:
schedule:
- cron: '17 3 * * *' # daily, 03:17 UTC
workflow_dispatch:
inputs:
lang:
description: 'Limit to one language code (e.g. ru); empty = all'
required: false
default: ''
limit:
description: 'Max pages this run; empty = the scheduled default (40)'
required: false
default: ''

concurrency:
group: i18n-translate
cancel-in-progress: false

permissions:
contents: write
pull-requests: write

jobs:
translate:
runs-on: ubuntu-latest
timeout-minutes: 300
env:
I18N_AUTH: api-key
DEFAULT_PAGE_LIMIT: '40'
# Leaves an hour of the 300-minute timeout for the page in flight and the
# commit/push/PR steps.
I18N_TIME_BUDGET_MIN: '240'
CLAUDE_CODE_VERSION: '2.1.287'
steps:
- name: Guard — org API key provisioned
id: guard
env:
ANTHROPIC_API_KEY: ${{ secrets.I18N_ANTHROPIC_API_KEY }}
run: |
if [ -z "${ANTHROPIC_API_KEY}" ]; then
echo "::notice::secret I18N_ANTHROPIC_API_KEY is not set yet — skipping this run."
echo "skip=true" >> "$GITHUB_OUTPUT"
fi

- name: Checkout
if: steps.guard.outputs.skip != 'true'
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.I18N_GH_TOKEN || github.token }}

- name: Fetch all branches (weekly-branch bookkeeping needs origin/i18n/week-*)
if: steps.guard.outputs.skip != 'true'
run: |
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git fetch --prune origin

- name: Set up Python
if: steps.guard.outputs.skip != 'true'
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Set up Node
if: steps.guard.outputs.skip != 'true'
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Install Claude CLI (driven by the Agent SDK)
if: steps.guard.outputs.skip != 'true'
run: npm install -g "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"

- name: Run translation pipeline
if: steps.guard.outputs.skip != 'true'
env:
# Secrets only reach the step that needs them, not the npm/pip installs.
ANTHROPIC_API_KEY: ${{ secrets.I18N_ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.I18N_GH_TOKEN || github.token }}
# Dispatch inputs go through env, never interpolated into the script.
INPUT_LANG: ${{ github.event.inputs.lang }}
INPUT_LIMIT: ${{ github.event.inputs.limit }}
run: |
args=(--limit "${INPUT_LIMIT:-$DEFAULT_PAGE_LIMIT}")
if [ -n "${INPUT_LANG}" ]; then args+=(--lang "${INPUT_LANG}"); fi
hack/i18n/run-daily.sh "${args[@]}"
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ static/docs/*/cozystack-api/

# Claude Code local settings
.claude/

# i18n pipeline venv (bootstrapped by hack/i18n/run-daily.sh)
.venv-i18n/

# i18n pipeline: per-run artifacts, not content
hack/i18n/last-run-findings.md

.demo-build-uidir

# demo overlay ships a public/ with the MSW worker — keep it despite the public/ ignore
Expand Down
12 changes: 12 additions & 0 deletions config/production/hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ module:
files:
- '! **/_include/*'
- '! docs/next/**'
- source: content/es
target: content
lang: es
files:
- '! **/_include/*'
- '! docs/next/**'
- source: content/pt-br
target: content
lang: pt-br
files:
- '! **/_include/*'
- '! docs/next/**'
- source: node_modules/bootstrap
target: assets/vendor/bootstrap
- source: node_modules/@fortawesome/fontawesome-free
Expand Down
30 changes: 0 additions & 30 deletions content/de/docs/v1.4/getting-started/_index.md

This file was deleted.

30 changes: 0 additions & 30 deletions content/hi/docs/v1.4/getting-started/_index.md

This file was deleted.

30 changes: 0 additions & 30 deletions content/ru/docs/v1.4/getting-started/_index.md

This file was deleted.

30 changes: 0 additions & 30 deletions content/zh-cn/docs/v1.4/getting-started/_index.md

This file was deleted.

4 changes: 4 additions & 0 deletions hack/i18n/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__pycache__/
*.pyc
# venv bootstrapped by run-daily.sh (repo root); listed here too for safety
.venv-i18n/
Loading
Loading