Skip to content

feat: QA checks for translations#3479

Draft
Anty0 wants to merge 56 commits intomainfrom
jirikuchynka/qa-checks
Draft

feat: QA checks for translations#3479
Anty0 wants to merge 56 commits intomainfrom
jirikuchynka/qa-checks

Conversation

@Anty0
Copy link
Collaborator

@Anty0 Anty0 commented Feb 19, 2026

Summary

Built-in QA checks that detect translation quality issues (missing numbers, punctuation mismatches, spacing problems, case mismatches, empty translations) directly in the Tolgee UI.

  • Dual-mode QA engine: live preview during editing + persisted results on save
  • QA panel in the translation tools sidebar with issue descriptions and CORRECT autofill
  • Pluggable check architecture — each check is a Spring component auto-discovered by the runner

Pitch: #2858
Building plan: #2858 (comment)

@Anty0 Anty0 linked an issue Feb 19, 2026 that may be closed by this pull request
22 tasks
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ca6a2a7f-e63e-4e7b-ad15-3720b31efe6b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jirikuchynka/qa-checks
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

@Anty0 Anty0 force-pushed the jirikuchynka/qa-checks branch from ae14442 to 191333b Compare March 8, 2026 10:13
Anty0 added 27 commits March 9, 2026 16:20
Add the QA checks feature framework with an "empty translation" check
running from the backend live preview endpoint through to the QA panel
in the translation tools sidebar.

Backend:
- QaCheckType, QaCheckSeverity, QaIssueState, QaIssueMessage enums
- TranslationQaIssue entity with Liquibase migration
- Pluggable QaCheck interface with EmptyTranslationCheck implementation
- QaCheckRunnerService orchestrator
- POST /v2/projects/{projectId}/qa-check/preview endpoint (EE, gated)
- QaCheckPreviewControllerTest (3 tests)

Frontend:
- useQaCheckPreview hook (follows glossary pattern)
- QaChecksPanel and QaCheckItem components
- Registered in eeModule.ee.tsx via addPanel pattern
- API schema regenerated with new endpoint
Switch @Enumerated to EnumType.STRING for type, message, and state
columns to avoid fragile ordinal-based storage.
Wrap each check in try-catch so a failing check produces a fallback
issue (with QA_CHECK_FAILED message) instead of breaking the entire run.
Add 4 QA check implementations that compare translation text against
the base language, giving the QA panel real substance beyond the
initial empty-translation check.

Backend:
- Add params field to QaCheckResult pipeline for parameterized messages
- Add 14 QaIssueMessage enum values
- Update preview controller to fetch base translation text from DB
- Implement SpacesMismatchCheck (7 variants), PunctuationMismatchCheck
  (3 variants), CharacterCaseMismatchCheck (2 variants), and
  MissingNumbersCheck

Frontend:
- Extend useQaIssueMessage to accept params and handle 14 new cases
- Add 4 check type labels to useQaCheckTypeLabel
- Add params field to QaCheckResultItem type
- Pass params through QaCheckItem to message hook

Tests:
- 37 unit tests across 4 check test classes
- 7 integration tests in QaCheckPreviewControllerTest
Wire up the Correct button in QaCheckItem to apply the suggested fix
by replacing the text between positionStart and positionEnd with the
replacement value, updating the editor via setValue.
Run all QA checks when a translation is saved and persist the results
as TranslationQaIssue entities. This enables cell indicators, filtering,
and dashboard counts downstream.

- Add params column to TranslationQaIssue for message interpolation
- Add TranslationQaIssueRepository with project-scoped queries
- Add QaIssueService for persisting/retrieving QA issues
- Add async event listener on OnTranslationsSet to trigger checks
- Add GET endpoint for persisted QA issues per translation
- Add qaIssueCount to the translation list API (follows commentCount pattern)
- Fix Liquibase migration: remove bogus columns, fold params into createTable
…t to KeyCreateDialog, fix n+1 in language delete
Backend:
- IGNORE/UNIGNORE endpoints on QaIssueController (PUT .../ignore, .../unignore)
- Preview endpoint cross-references persisted issues to include ignored/persistedIssueId
- State inheritance: replaceIssuesForTranslation preserves IGNORED state on re-persist
- filterHasQaIssuesInLang filter parameter for translation queries

Frontend:
- QaCheckItem supports ignored state (dimmed) with IGNORE/UNIGNORE buttons
- QaChecksPanel wires ignore/unignore mutations with preview invalidation
- TranslationFlags shows QA warning icon + count badge when qaIssueCount > 0
- SubfilterQaChecks submenu in translation filter dropdown ("Has QA issues")
Anty0 added 13 commits March 9, 2026 16:20
- Introduced `ProjectQaConfig` entity to manage project-level QA check types and severity.
- Updated `QaCheckRunnerService` to filter checks based on project settings.
- Added new endpoints for retrieving and updating project QA settings.
- Enhanced frontend to enable QA settings management via `ProjectSettingsQa` component.
- Refactored QA check handling, resolving type import redundancies across hooks and components.
- Added tooltips and descriptions for better QA check configurability.
- Updated tests and migrations to reflect the new configuration structure.
… schema update

- Remove unused imports (Box, Typography, BoxProps, QaBadge)
- Add translations-toolbar-to-top and translations-toolbar-counter to dataCyType
- Add filterHasQaIssuesInLang to apiSchema.generated.ts
- Added support for rendering inline QA issue highlights in translations.
- Extended the API to include detailed QA issues when requested (`includeQaIssues` parameter).
- Integrated backend and frontend changes to handle QA issue data and highlight rendering.
- Added new repository query and hateoas model assembler for QA issues.
- Updated tests, components, and schema files to support the feature.
@Anty0 Anty0 force-pushed the jirikuchynka/qa-checks branch from 4a31c59 to 3a4fd39 Compare March 9, 2026 15:21
Anty0 added 16 commits March 9, 2026 16:23
…checking + QA stale flag backend side

- Introduced `qaChecksStale` flag to mark translations requiring QA rechecks.
- Replaced asynchronous QA issue handling with batch job processing.
- Implemented QA rechecking on QA settings change.
- Updated database schema and views to support new functionalities.
- Updated tests for batch QA checks.
…qaChecksStale` to manually constructed translation object in frontend
…eview to WebSocket

- Removed `QaCheckPreviewController` and related classes, models, tests, and API schema definitions.
- Implemented WebSocket-based QA checks preview service and integrated it with the frontend.
- Refactored `QaCheckRunnerService` to support individual QA checks with debounce functionality.
- Updated `QaChecksPanel` to handle real-time QA check previews using WebSocket.
- Adjusted tests and components to remove dependencies on the old API.
- Added database schema and model support for language-specific QA configurations.
- Implemented APIs for managing per-language QA settings.
- Extended frontend to support viewing and editing per-language QA settings.
- Updated `QaCheckRunnerService` and related services to respect language-level QA settings.
- Adjusted WebSocket-based QA Check Preview to apply language-specific settings.
- Dropped `project_id` from `language_qa_config` table and related model.
- Adjusted database schema, indexes, and foreign keys.
- Renamed repository methods to align with updated structure.
- Refactored services and logic to work without explicit project link.
Add a popover that opens when clicking QA badges on the project
dashboard, showing issue counts grouped by check type with navigation
links to filtered translations view and QA settings.

- New backend endpoint GET /stats/qa-issue-counts for per-check-type counts
- New QaBadgePopover component matching Figma design
- Gray icon state when stale with no issues (darkWhenNoIssues prop)
- Extract getProjectTranslationsUrl helper for consistent URL building
Add individual QA check type filter checkboxes to the QA filtering
submenu, replacing the single "Has QA issues" toggle with a richer UI.

Backend:
- New QaCheckCategory enum (COMPARISON, SYNTAX) and CATEGORIES mapping
  on QaCheckType as single source of truth for grouping/ordering
- New GET /v2/projects/{projectId}/qa-check-types endpoint returning
  categories with their ordered check types
- New filterQaCheckType query parameter (List<QaCheckType>) on
  translation filters, applied via EXISTS subquery on TranslationQaIssue
- Unit test verifying CATEGORIES completeness

Frontend:
- SubfilterQaChecks rewritten to fetch categories from API and render
  per-type checkboxes with divider separators between groups
- filterQaCheckTypes and filterHasQaIssues are mutually exclusive
- QaBadgePopover "SHOW" links now navigate to specific check type filter
…ection

Show persisted QA issues from translation data when the QA panel opens,
instead of immediately connecting the WebSocket. The WebSocket only
connects when the user modifies the text or when qaChecksStale is true.
Persisted issues are seeded into the WebSocket hook's issuesByType map
so the transition is seamless — each check type's results are replaced
individually as the WebSocket delivers them.
- Publish QA_CHECKS_COMPLETED WebSocket event when QA batch job finishes,
  including full qaIssues list for inline highlights and panel initialization
- Optimistically set qaChecksStale=true on save so badge shows loading spinner
- Gate QA badge behind QA_CHECKS feature flag in translations view and dashboard
- Add correctTranslation action that saves (or suggests) the corrected
  translation directly without opening the editor
- Extract getTranslationPermissions from getEditorActions for shared
  save/suggest permission checks
- Extract saveTranslationValue/suggestTranslationValue in useEditService
  to share save logic between editor and inline correction
- Add applyQaReplacement utility for shared text replacement logic
- Add canEditTranslation helper to hide CORRECT button when user lacks
  permissions
- Fix click propagation through React portals by stopping event bubbling
  on tooltip content (QA and glossary highlights)
- Gate QA inline highlights behind QA_CHECKS feature flag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

QA checks 1.0

1 participant