diff --git a/.github/workflows/check_for_crowdin_updates.yml b/.github/workflows/check_for_crowdin_updates.yml index 2ee495b..42a6430 100644 --- a/.github/workflows/check_for_crowdin_updates.yml +++ b/.github/workflows/check_for_crowdin_updates.yml @@ -14,6 +14,11 @@ on: required: true type: boolean default: true + SKIP_VALIDATION_ERRORS: + description: 'Continue even if string validation fails' + required: false + type: boolean + default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -77,10 +82,56 @@ jobs: if-no-files-found: warn retention-days: 7 + parse_translations: + name: Parse and validate translations + runs-on: ubuntu-latest + needs: [fetch_translations] + steps: + - name: Checkout Repo Content + uses: actions/checkout@v4 + with: + path: 'scripts' + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + cache: 'pip' + + - name: Install Dependencies + shell: bash + run: | + pip install -r ${{ github.workspace }}/scripts/crowdin/requirements.txt + + - name: Download raw translations + uses: actions/download-artifact@v4 + with: + name: session-download + path: "${{ github.workspace }}/raw_translations" + + - name: Parse and validate XLIFF files + run: | + python "${{ github.workspace }}/scripts/crowdin/parse_xliff.py" \ + "${{ github.workspace }}/raw_translations" \ + "${{ github.workspace }}/parsed_translations.json" \ + ${{ inputs.SKIP_VALIDATION_ERRORS != true && '--error-on-validation-failure' || '' }} \ + --validation-report "${{ github.workspace }}/validation_report.json" + + - name: Upload parsed translations + uses: actions/upload-artifact@v4 + with: + name: session-parsed + path: | + ${{ github.workspace }}/parsed_translations.json + ${{ github.workspace }}/validation_report.json + overwrite: true + if-no-files-found: error + retention-days: 7 + build_ios: name: Build iOS strings runs-on: ubuntu-latest - needs: [fetch_translations] + needs: [parse_translations] steps: - name: Checkout Repo Content uses: actions/checkout@v4 @@ -93,10 +144,16 @@ jobs: - name: Setup shared uses: ./scripts/actions/setup_shared + - name: Download parsed translations + uses: actions/download-artifact@v4 + with: + name: session-parsed + path: "${{ github.workspace }}" + - name: Prepare iOS Strings run: | python "${{ github.workspace }}/scripts/crowdin/generate_ios_strings.py" \ - "${{ github.workspace }}/raw_translations" \ + "${{ github.workspace }}/parsed_translations.json" \ "${{ github.workspace }}/ios/Session/Meta/Translations" \ "${{ github.workspace }}/ios/SessionUIKit/Style Guide/Constants.swift" - name: Upload iOS artefacts @@ -114,7 +171,7 @@ jobs: build_desktop: name: Build Desktop strings - needs: [fetch_translations] + needs: [parse_translations] runs-on: ubuntu-latest steps: - name: Checkout Repo Content @@ -128,11 +185,16 @@ jobs: - name: Checkout Desktop uses: ./scripts/actions/checkout_desktop + - name: Download parsed translations + uses: actions/download-artifact@v4 + with: + name: session-parsed + path: "${{ github.workspace }}" - name: Prepare Desktop Strings run: | python "${{ github.workspace }}/scripts/crowdin/generate_desktop_strings.py" \ - "${{ github.workspace }}/raw_translations" \ + "${{ github.workspace }}/parsed_translations.json" \ "${{ github.workspace }}/desktop/_locales" \ "${{ github.workspace }}/desktop/ts/localization/constants.ts" @@ -152,7 +214,7 @@ jobs: build_qa: name: Build QA strings - needs: [fetch_translations] + needs: [parse_translations] runs-on: ubuntu-latest steps: - name: Checkout Repo Content @@ -166,10 +228,16 @@ jobs: - name: Checkout Desktop uses: ./scripts/actions/checkout_desktop + - name: Download parsed translations + uses: actions/download-artifact@v4 + with: + name: session-parsed + path: "${{ github.workspace }}" + - name: Export QA Strings (json) run: | python "${{ github.workspace }}/scripts/crowdin/generate_desktop_strings.py" --qa_build \ - "${{ github.workspace }}/raw_translations" \ + "${{ github.workspace }}/parsed_translations.json" \ "${{ github.workspace }}/desktop/_locales" \ "${{ github.workspace }}/desktop/ts/localization/constants.ts" - name: Prepare QA strings (ts) @@ -191,7 +259,7 @@ jobs: build_android: name: Build Android strings runs-on: ubuntu-latest - needs: [fetch_translations] + needs: [parse_translations] steps: - name: Checkout Repo Content @@ -210,16 +278,24 @@ jobs: with: distribution: 'temurin' java-version: 17 - cache: gradle - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 + with: + gradle-version: wrapper + cache-read-only: false + + - name: Download parsed translations + uses: actions/download-artifact@v4 + with: + name: session-parsed + path: "${{ github.workspace }}" - name: Prepare Android Strings run: | rm -rf ${{ github.workspace }}/android/app/src/main/res/values*/strings.xml python "${{ github.workspace }}/scripts/crowdin/generate_android_strings.py" \ - "${{ github.workspace }}/raw_translations" \ + "${{ github.workspace }}/parsed_translations.json" \ "${{ github.workspace }}/android/app/src/main/res" \ "${{ github.workspace }}/android/app/src/main/java/org/session/libsession/utilities/NonTranslatableStringConstants.kt" - name: Upload Android artefacts @@ -234,7 +310,16 @@ jobs: retention-days: 7 - name: Validate strings for Android - run: cd ${{ github.workspace }}/android && ${{ github.workspace }}/android/gradlew app:mergePlayDebugResources + run: | + cd ${{ github.workspace }}/android + ./gradlew app:generatePlayDebugResValues \ + --parallel \ + --build-cache \ + --configuration-cache \ + -Dorg.gradle.jvmargs="-Xmx2g -XX:+UseParallelGC" \ + -Dorg.gradle.caching=true \ + -x lint \ + -x test jobs_sync: @@ -370,4 +455,4 @@ jobs: body: ${{ env.PR_DESCRIPTION }} branch: ${{ env.PR_TARGET_BRANCH }} commit-message: ${{ env.PR_TITLE }} - delete-branch: true \ No newline at end of file + delete-branch: true diff --git a/.github/workflows/notify_failure.yml b/.github/workflows/notify_failure.yml new file mode 100644 index 0000000..2757c16 --- /dev/null +++ b/.github/workflows/notify_failure.yml @@ -0,0 +1,34 @@ +name: Discord Failure Notification + +on: + workflow_run: + workflows: + - "Check for Crowdin Updates" + - "Test Failure Notification" + types: + - completed + +jobs: + notify: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + steps: + - name: Send Discord notification + env: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} + DISCORD_ROLE_ID: ${{ secrets.DISCORD_ROLE_ID }} + run: | + curl -H "Content-Type: application/json" \ + -d '{ + "content": "<@&'"$DISCORD_ROLE_ID"'> ⚠️ GitHub Action failed!", + "embeds": [{ + "title": "Workflow Failed: ${{ github.event.workflow_run.name }}", + "url": "${{ github.event.workflow_run.html_url }}", + "color": 15158332, + "fields": [ + {"name": "Repository", "value": "${{ github.repository }}", "inline": true}, + {"name": "Branch", "value": "${{ github.event.workflow_run.head_branch }}", "inline": true} + ] + }] + }' \ + "$DISCORD_WEBHOOK_URL" diff --git a/.github/workflows/test_failure_notification.yml b/.github/workflows/test_failure_notification.yml new file mode 100644 index 0000000..d22440c --- /dev/null +++ b/.github/workflows/test_failure_notification.yml @@ -0,0 +1,11 @@ +name: Test Failure Notification + +on: + workflow_dispatch: + +jobs: + fail: + runs-on: ubuntu-latest + steps: + - name: Fail on purpose + run: exit 1 diff --git a/.gitignore b/.gitignore index e046d9c..3fb72ac 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # Exclude venv folder venv +.env __pycache__ .vscode/ diff --git a/README.md b/README.md index 8b9e7f1..88cf0ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,60 @@ # Session Shared Scripts This repo houses scripts which are shared between the different platform repos for Session, it also contains a number of Actions used to automatically sync some shared elements across the repos. + +## Crowdin Translation Workflow + +Automated workflow that downloads translations from Crowdin, validates them, and creates PRs for iOS, Android, and Desktop platforms. + +### Required Secrets + +| Secret | Description | +| ------------------- | ----------------------------------------- | +| `CROWDIN_API_TOKEN` | Crowdin API token with project access | +| `CROWDIN_PR_TOKEN` | GitHub token with PR creation permissions | + +### Workflow Inputs + +| Input | Default | Description | +| ------------------------ | ------- | ---------------------------------------- | +| `UPDATE_PULL_REQUESTS` | `true` | Create/update PRs for all platforms | +| `SKIP_VALIDATION_ERRORS` | `false` | Continue even if string validation fails | + +### Schedule + +Runs automatically every Monday at 00:00 UTC. + +### Validation Rules + +#### All Strings (including plurals) + +- **Valid `{variable}` syntax** - No broken braces (`{`, `}`, `{}`, `{ space }`) +- **Allowed HTML tags only** - Only ``, `
`, `` +- **Valid tag syntax** - No malformed `<` (e.g., `