Skip to main content

Localization & Theming

Strings

  • l10n.yaml generates lib/l10n/app_localizations.dart from lib/l10n/app_en.arb + app_cy.arb (English/Welsh). Every user-facing string is an ARB entry; design_system holds none (purity test enforces).
  • titleKey/bodyKey/altKey from backend remain localizable keys — inspector prose (notes, contestReason, conditionNote) is never translated and never appears in ARB.
  • Dates: booking selector uses literal MM/DD/YYYY; other dates use intl locale-sensitive DateFormat (GB/Cymraeg diverge — screenshot note).
  • Grammar fix: "will be automatically accepted" (corrected) enforced via ARB value, not screenshot typo.

Locale switching

LocaleCubit persists en|cy via PreferencesService and rebuilds MaterialApp.locale. Widget sweep tests render every matrix at en and cy to catch overflow from longer Cymraeg strings.

Theming

ThemeCubitThemeMode.system|light|dark persisted vs system Brightness. KxTheme.light() / dark() maps KxColors + KxTypography to ThemeData including ColorScheme AA-checked tokens and textSelectionTheme. KxTone maps product states (outstanding→warning, accepted→success) away from raw color.

Tokens → WCAG

test/design_system/contrast_test.dart asserts every foreground/on background pair ≥4.5:1 and non-text ≥3:1 both themes; tealAccentDecorative never appears as foreground (explicit failure would block build if a new token mistakenly aliases it).

Adding a string

  1. Add key to app_en.arb (and app_cy.arb same key).
  2. Run flutter gen-l10n.
  3. Consume via context.l10n.newKey.
  4. Never hardcode literal — design_system_purity_test will fail.

RTL & motion

  • KxBreakpoints thresholds pinned at 599/600/839/840/1439/1440; responsive_sweep_test renders 360/600/840/1440 × 1.0/1.3/2.0 text scale × LTR/RTL × light/dark without overflow.
  • MediaQuery.disableAnimations collapses all KxMotion to 0; KxSkeleton shimmer stops and pumpAndSettle returns.