name: Native App Locale Refresh on: push: branches: - main paths: - apps/android/app/src/main/** - apps/ios/** - apps/macos/Sources/** - apps/macos/Package.swift - apps/shared/OpenClawKit/Sources/** - apps/.i18n/native-source.json - scripts/control-ui-i18n.ts - scripts/native-app-i18n.ts - ui/src/i18n/.i18n/glossary.*.json - .github/workflows/native-app-locale-refresh.yml workflow_dispatch: permissions: contents: write concurrency: group: native-app-locale-refresh-${{ github.event_name == 'push' && github.ref || format('manual-{0}', github.run_id) }} cancel-in-progress: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.actor != 'github-actions[bot]' }} jobs: refresh: if: github.repository == 'openclaw/openclaw' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main') && (github.event_name != 'push' || github.actor != 'github-actions[bot]') strategy: fail-fast: false max-parallel: 2 matrix: locale: [ zh-CN, zh-TW, pt-BR, de, es, ja-JP, ko, fr, hi, ar, it, tr, uk, id, pl, th, vi, nl, fa, ru, sv, ] runs-on: ubuntu-latest name: Refresh native ${{ matrix.locale }} steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: persist-credentials: true submodules: false - name: Setup Node environment uses: ./.github/actions/setup-node-env with: install-bun: "false" - name: Ensure translation provider secrets exist env: OPENCLAW_DOCS_I18N_OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | set -euo pipefail if [ -z "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ] && [ -z "${OPENAI_API_KEY:-}" ] && [ -z "${ANTHROPIC_API_KEY:-}" ]; then echo "Missing OPENCLAW_DOCS_I18N_OPENAI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY secret." exit 1 fi - name: Refresh native locale artifact env: OPENCLAW_DOCS_I18N_OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ANTHROPIC_MODEL: claude-opus-4-8 OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.5' }} OPENCLAW_CONTROL_UI_I18N_THINKING: low OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "0" LOCALE: ${{ matrix.locale }} run: | set -euo pipefail run_refresh() { local provider="$1" local model="$2" local openai_api_key="${3-}" if [ "$provider" = "openai" ]; then OPENAI_API_KEY="$openai_api_key" \ OPENCLAW_CONTROL_UI_I18N_PROVIDER="$provider" \ OPENCLAW_CONTROL_UI_I18N_MODEL="$model" \ node --import tsx scripts/native-app-i18n.ts sync --write --locale "${LOCALE}" return fi OPENCLAW_CONTROL_UI_I18N_PROVIDER="$provider" \ OPENCLAW_CONTROL_UI_I18N_MODEL="$model" \ node --import tsx scripts/native-app-i18n.ts sync --write --locale "${LOCALE}" } run_openai_refresh() { local status=1 if [ -n "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ]; then set +e run_refresh openai "${OPENAI_MODEL}" "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY}" status="$?" set -e if [ "$status" -eq 0 ]; then return 0 fi if [ -z "${OPENAI_API_KEY:-}" ] || [ "${OPENAI_API_KEY}" = "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY}" ]; then return "$status" fi echo "::warning::Docs OpenAI native locale refresh key failed for ${LOCALE}; retrying with repository OpenAI key." fi if [ -z "${OPENAI_API_KEY:-}" ]; then return "$status" fi run_refresh openai "${OPENAI_MODEL}" "${OPENAI_API_KEY}" } if [ -n "${ANTHROPIC_API_KEY:-}" ]; then set +e run_refresh anthropic "${ANTHROPIC_MODEL}" status="$?" set -e if [ "$status" -eq 0 ]; then exit 0 fi if [ -z "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ] && [ -z "${OPENAI_API_KEY:-}" ]; then exit "$status" fi echo "::warning::Anthropic native locale refresh failed for ${LOCALE}; retrying with OpenAI." fi run_openai_refresh - name: Prepare locale artifact env: LOCALE: ${{ matrix.locale }} run: | set -euo pipefail artifact_dir="${RUNNER_TEMP}/native-locale-${LOCALE}" mkdir -p "${artifact_dir}" git add -A apps/.i18n/native git diff --cached --binary --full-index -- apps/.i18n/native > "${artifact_dir}/${LOCALE}.patch" - name: Upload locale artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: native-locale-${{ matrix.locale }} path: ${{ runner.temp }}/native-locale-${{ matrix.locale }}/${{ matrix.locale }}.patch if-no-files-found: error retention-days: 1 finalize: name: Commit native locale refresh needs: refresh if: needs.refresh.result == 'success' runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 0 persist-credentials: true submodules: false - name: Download locale artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: native-locale-* path: ${{ runner.temp }}/native-locale-artifacts merge-multiple: true - name: Apply locale artifacts run: | set -euo pipefail while IFS= read -r patch; do if [ -s "${patch}" ]; then git apply "${patch}" fi done < <(find "${RUNNER_TEMP}/native-locale-artifacts" -type f -name '*.patch' | sort) - name: Setup Node environment uses: ./.github/actions/setup-node-env with: install-bun: "false" # Every worker observes the same source inventory. Generate it once here # so locale patches remain independent and can be applied sequentially. - name: Refresh shared native inventory run: node --import tsx scripts/native-app-i18n.ts sync --write - name: Validate native locale refresh run: node --import tsx scripts/native-app-i18n.ts check - name: Commit and push aggregate locale refresh env: TARGET_BRANCH: ${{ github.event.repository.default_branch }} run: | set -euo pipefail if ! git status --porcelain -- apps/.i18n/native apps/.i18n/native-source.json | grep -q .; then echo "No native locale changes." exit 0 fi git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add -A apps/.i18n/native apps/.i18n/native-source.json git commit --no-verify -m "chore(i18n): refresh native locales" for attempt in 1 2 3 4 5; do git fetch origin "${TARGET_BRANCH}" git rebase "origin/${TARGET_BRANCH}" if git push origin HEAD:"${TARGET_BRANCH}"; then exit 0 fi git rebase --abort >/dev/null 2>&1 || true echo "Aggregate push attempt ${attempt} failed; retrying." sleep $((attempt * 2)) done echo "Failed to push aggregate native locale update after retries." exit 1