Why a11y and i18n matter
- Accessibility (a11y) is not only compliance; it is good product design that extends reach and reduces support.
- Internationalization (i18n) decouples content and layout from code, enabling fast iteration and global scale.
- Doing both well requires deliberate architecture choices, automated checks, and close collaboration with design and localization teams.
Contents
- Accessibility fundamentals in Flutter
- Semantics, labels, roles, and actions
- Focus order, traversal, and keyboard support
- Dynamic text scaling, contrast, and color-blind friendly palettes
- Gestures, hit targets, and motion sensitivity
- Internationalization setup and workflows
- Pluralization, gender, date/time/number formatting
- RTL layout and bidi text
- Continuous localization (CL) pipelines and QA
- Automation: linters, tests, and CI gates
- Governance and adoption plan
Accessibility fundamentals in Flutter
- Flutter’s a11y works by projecting a semantic tree to native accessibility APIs (VoiceOver, TalkBack).
- Good a11y means the semantic tree matches user intent, not just visual layout.
Semantics and roles
- Use
Semanticsto provide labels, hints, and roles for non-standard widgets. - Prefer high-level widgets that already include semantics (e.g., ElevatedButton) when possible.
- Provide concise, action-oriented labels (“Add to cart”) and avoid redundant labels (“Button, Add to cart button”).
Examples (patterns)
- Decorative images: mark as
excludeSemantics: trueorSemantics(label: '', container: true)to avoid noise. - Interactive icons: wrap with
Semantics(button: true, label: 'Play')or useIconButtonwithtooltip. - Custom controls: implement
SemanticswithonTap,onLongPress, and states (toggled,selected).
Focus and traversal
- Keyboard and switch access depend on correct focus order:
- Ensure logical focus sequence using
FocusTraversalGroup+OrderedTraversalPolicywhere necessary. - Use
Focus/FocusNodeto manage custom behaviors andShortcuts/Actionsfor keyboard bindings.
- Ensure logical focus sequence using
- Keep tab order consistent with visual order; avoid focus traps (dialogs, drawers).
Text scaling, contrast, and motion
- Respect user font scaling: design with
MediaQuery.textScaleFactor, test up to 200%. - Avoid clipping by using flexible layout (
Expanded,Flexible) and ensuring minimum heights expand with text. - Contrast: adhere to WCAG AA (4.5:1 for small text); enforce using automated color contrast checks on tokens.
- Motion: offer reduced motion toggles or detect platform settings; avoid gratuitous animations for vestibular sensitivity.
Gestures and hit targets
- Minimum hit target ~48x48 dp; use
InkWell/GestureDetectorwith sufficient padding. - Provide multiple input methods: not only drag, but also tap/keyboard alternatives.
- Avoid long-press-only affordances; supplement with explicit menus.
Internationalization (i18n) setup
- Use Flutter’s
flutter_localizationswithintlordart-intltoolchain. - Store strings in ARB files (one per locale) and generate strongly typed accessors.
- Keep keys stable and descriptive (e.g.,
cart_add_button_label), avoid embedding parameters in the key.
Pluralization and gender
- Use ICU MessageFormat in ARB:
- Plurals:
{count, plural, =0{No items} one{1 item} other{{count} items}} - Gender:
{gender, select, female{She added} male{He added} other{They added}}
- Plurals:
- Avoid string concatenation; always use placeholders for variables to maintain grammar across locales.
Formatting and units
- Use locale-aware formatters for dates, times, numbers, currencies (
NumberFormat,DateFormat). - Use consistent units and symbols per locale; clarify thousand and decimal separators.
RTL and bidi
- Flutter supports RTL layouts with
Directionality. - Test all screens in RTL; verify:
- Padding/margins mirrored correctly (use
EdgeInsetsDirectionalinstead ofEdgeInsets) - Icons that imply direction (arrows, play) are swapped when needed
- LTR content in RTL (like code, IDs) remains readable with bidi control characters if required
- Padding/margins mirrored correctly (use
- Ensure images with directionality have RTL variants or remain semantically neutral.
Continuous Localization (CL)
- Establish a pipeline:
- Designers and PMs propose copy → Localization team translates → CI syncs ARB files → App rebuilds with generated localizations.
- Tools:
- Use a TMS (Translation Management System) with ARB export/import, translation memory, and QA checks.
- Process:
- Freeze strings before releases; allow hotfix locales separately.
- Keep screenshots per locale for translators to see context.
Automation and QA
- Linting:
- Enforce
EdgeInsetsDirectional, forbid raw strings in widgets (require l10n lookups). - Require
Semanticsor tooltips on custom tappables.
- Enforce
- Tests:
- Golden localization tests for a subset of screens across two extra locales.
- Semantics tests verifying labels and roles for critical flows.
- UI tests under 200% text scale to catch overflows.
- CI gates:
- Fail builds on missing translations for required locales.
- Color contrast token audit as part of design system checks.
Governance and adoption plan
- Baseline audit: identify top screens for a11y and i18n gaps.
- Establish design tokens, contrast rules, and l10n key conventions.
- Add lints and CI gates; fix violations incrementally.
- Add semantics and focus order to critical flows first.
- Expand locale coverage gradually; prioritize markets by impact.
Checklist
- All interactive elements have accessible names and roles
- Focus order matches visual order; keyboard and switch access work
- Text scales without clipping up to 200%
- Color tokens meet WCAG AA
- Strings in ARB with ICU formats; no concatenation
- RTL verified with
EdgeInsetsDirectionaland icon mirroring where needed - CL pipeline integrated with CI; missing translations fail fast
Conclusion Accessibility and internationalization are multiplicative force multipliers. Investing early yields broader reach, better UX, and fewer production issues. Bake semantics and localization into your design system and CI to scale confidently across markets.