ci(core): add a workflow to generate translation context

[no changelog]
This commit is contained in:
Michal Kazda
2026-01-30 10:59:17 +01:00
committed by Roman Zeyde
parent 7b9a96e176
commit f8665dccab
4 changed files with 182 additions and 3 deletions

117
.github/workflows/crowdin-ui-check.yml vendored Normal file
View File

@@ -0,0 +1,117 @@
name: Crowdin - context generation (manual)
run-name: Crowdin - <${{ inputs.language }}> language context generation
on:
workflow_dispatch:
inputs:
language:
description: Select a language to generate UI flows for
required: true
type: choice
default: cs
options:
- cs
- fr
- de
- es
- pt
permissions:
id-token: write # for fetching OIDC token for AWS
env:
CROWDIN_COMMENT_PATH: ${{ github.workspace }}/tests/core-crowdin-comment.md
TREZOR_PYTEST_LOGS_DIR: ${{ github.workspace }}/tests/
jobs:
core_emu:
name: Build emulator (${{ matrix.model }}, universal, debuglink, noasan)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
model: [T2T1, T3B1, T3T1, T3W1]
env:
TREZOR_MODEL: ${{ matrix.model }}
BITCOIN_ONLY: 0
PYOPT: 0
ADDRESS_SANITIZER: 0
QUIET_MODE: 1
DISABLE_TROPIC: 0
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: ./.github/actions/environment
- run: nix-shell --run "uv run make -C core build_unix_frozen"
- uses: actions/upload-artifact@v6
with:
name: core-emu-${{ matrix.model }}-universal-debuglink-noasan
path: |
core/build/unix/trezor-emu-core*
retention-days: 7
# Context tests for Core. Generates screenshots of UI flows of curated list of tests
# for selected language. To be used as context for Crowdin localization work.
core_context_tests:
name: Context tests (${{ matrix.model }}, universal, noasan, ${{ matrix.language }})
runs-on: ubuntu-latest
needs: core_emu
strategy:
fail-fast: false
matrix:
model: [T2T1, T3B1, T3T1, T3W1]
language: ["en", "${{ inputs.language }}"]
env:
TREZOR_PROFILING: 0
TREZOR_MODEL: ${{ matrix.model }}
ADDRESS_SANITIZER: 0
PYTEST_TIMEOUT: 400
TEST_LANG: ${{ matrix.language }}
TESTOPTS: "@../tests/context_tests.txt --ui=test"
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/download-artifact@v7
with:
name: core-emu-${{ matrix.model }}-universal-debuglink-noasan
path: core/build/unix
- run: chmod +x core/build/unix/trezor-emu-core*
- uses: ./.github/actions/environment
- run: nix-shell --run "uv run make -C core test_emu_multicore"
- run: tail -v -n50 tests/trezor*.log || true
if: failure()
- uses: ./.github/actions/ui-report
with:
model: ${{ matrix.model }}
lang: ${{ matrix.language }}
status: ${{ job.status }}
if: always()
continue-on-error: true
core_ui_comment:
name: Comment with UI flows
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: sleep 1m # to avoid GitHub API rate limit
- run: |
python ci/make_crowdin_comment.py "${{ github.run_id }}" '["en", "${{ inputs.language }}"]' > ${{ env.CROWDIN_COMMENT_PATH }}
cat ${{ env.CROWDIN_COMMENT_PATH }} >> $GITHUB_STEP_SUMMARY
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::538326561891:role/gh_actions_deploy_dev_firmware_data
aws-region: eu-west-1
- run: python ci/make_summary_htmls.py "index" '["en", "${{ inputs.language }}"]' "tests/ui_tests/reporting/"
- run: python ci/make_summary_htmls.py "diff" '["en", "${{ inputs.language }}"]' "tests/ui_tests/reporting/"
- name: Upload per-language HTML summaries to S3
run: |
cd tests/ui_tests/reporting/
for F in *.html
do
aws s3 cp $F s3://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/$F
done

View File

@@ -0,0 +1,60 @@
import json
import sys
(RUN_ID, LANGS_JSON) = sys.argv[1:]
MAIN = json.loads(LANGS_JSON)
REPORT_URL = f"https://data.trezor.io/dev/firmware/ui_report/{RUN_ID}"
CI_RUN_URL = f"https://github.com/trezor/trezor-firmware/actions/runs/{RUN_ID}"
MODELS_INFO = [
{"id": "T2T1", "name": "Trezor Model T", "layout": "Bolt"},
{"id": "T3B1", "name": "Trezor Safe 3", "layout": "Caesar"},
{"id": "T3T1", "name": "Trezor Safe 5", "layout": "Delizia"},
{"id": "T3W1", "name": "Trezor Safe 7", "layout": "Eckhart"},
]
LANG_NAMES = {
"cs": "Czech",
"de": "German",
"en": "English",
"es": "Spanish",
"fr": "French",
"pt": "Portuguese",
}
def display_lang(code: str) -> str:
return LANG_NAMES.get(code, code) # fallback to the code if unknown
def main():
# a special marker for finding this comment (via CI)
print("<!-- ui-comment-Crowdin -->")
for lang in MAIN:
print_table(lang)
def format_table_row(cells: list[str]) -> str:
"""Format a list of cells as a markdown table row with proper delimiters."""
return "| " + " | ".join(cells) + " |"
def print_table(lang):
print(f"\n# `{display_lang(lang)}`\n")
header = ["layout", "context tests"]
print(format_table_row(header))
print(format_table_row(["---"] * len(header)))
for model in MODELS_INFO:
test_prefix = f"{REPORT_URL}/{model['id']}-{lang}-core_context_tests"
row = [
f"{model['layout']} / {model['name']}",
f"[UI flows]({test_prefix}-index.html)",
]
print(format_table_row(row))
if __name__ == "__main__":
main()

2
tests/context_tests.txt Normal file
View File

@@ -0,0 +1,2 @@
../tests/device_tests/test_pin.py::test_correct_pin
../tests/click_tests/test_pin.py::test_pin_short

View File

@@ -2,8 +2,8 @@
function createGif() {
// Finds all the screenshots on the screen, creates a new img
// element at the top and switches the src attribute every 200ms
// to create a notion of GIF.
// element at the top and switches the src attribute periodically
// (interval based on defaultDelay) to create a notion of GIF.
// Adds some controlling possibilities - buttons, input fields
// and sliders to enable pausing, stepping back and forth, changing
// the delay, etc.
@@ -28,7 +28,7 @@ function createGif() {
const delayText = 'Delay (ms):';
const sliderText = 'Progress:';
const defaultDelay = 200;
const defaultDelay = 1000;
const keyboardShortcutPrev = 'ArrowLeft';
const keyboardShortcutNext = 'ArrowRight';