DEV Community

Cover image for Building an i18n Pipeline That Doesn't Break Screen Readers: EAA Compliance for Devs
Diogo Heleno
Diogo Heleno

Posted on Originally published at m21global.com

Building an i18n Pipeline That Doesn't Break Screen Readers: EAA Compliance for Devs

The European Accessibility Act (EAA) has been in force since 28 June 2025, and if you ship e-commerce, banking, ticketing or e-reader products into the EU, it applies to you. Most engineering teams have already run the checklist: ARIA roles, focus states, color contrast ratios. That's the part of accessibility we're good at, because it's testable with tools like axe or Lighthouse.

The part that quietly breaks compliance is text. Not whether text exists in the DOM, but whether it's understandable once it's translated, and whether your i18n pipeline preserves the structure assistive tech depends on. A good breakdown of the legal and content side is in this article on localisation and the EAA. This post is about the engineering side: how to build a pipeline that doesn't silently produce inaccessible translations.

Why your i18n setup can pass tests and still fail the EAA

Screen readers read DOM order, not visual order. Your translation pipeline usually only sees isolated strings, pulled out of context via i18next, gettext, or whatever key-value system you're using. That disconnect is where accessibility problems get introduced without anyone noticing:

  • A string gets translated correctly in isolation but its length blows past a fixed-width label and gets truncated by CSS text-overflow: ellipsis, silently dropping the actual instruction.
  • A gendered language (Portuguese, Spanish, German) needs a different word for "selected" or "required" depending on the referenced UI element, but your key structure only has one placeholder for it.
  • RTL languages need the DOM's logical order to match reading direction, but your translation memory tool only touches text nodes, not markup structure.

None of these show up in unit tests unless you specifically test for them.

Structuring your string files for translator context

The biggest fix is cheap: stop shipping flat key-value JSON with no context to your translation team or TMS (Translation Management System).

Bad:

{
  "cancel_button": "Cancel"
}
Enter fullscreen mode Exit fullscreen mode

Better:

{
  "cancel_button": {
    "value": "Cancel",
    "context": "Button on the payment confirmation modal. Action is irreversible once confirmed.",
    "max_length": 20,
    "screenshot": "payment-modal-v3.png"
  }
}
Enter fullscreen mode Exit fullscreen mode

Tools like Phrase, Lokalise, and Crowdin all support screenshot-to-string mapping. Use it. Translators working from an isolated string list will produce technically correct, contextually wrong output, especially on anything irreversible ("Cancel", "Delete", "Confirm").

Handling grammatical gender without hardcoding logic

If you're supporting Portuguese, Spanish, French, German or Polish, don't hardcode gender agreement into your UI logic. Use ICU MessageFormat, which most i18n libraries (i18next, FormatJS, react-intl) support natively:

{
  "item_selected": "{gender, select, masculine {Selecionado} feminine {Selecionada} other {Selecionado}}"
}
Enter fullscreen mode Exit fullscreen mode

This pushes the gender decision into your translation layer instead of your component logic, which is where it belongs. If your current setup interpolates raw strings without this kind of branching, you will eventually ship inconsistent agreement that trips up screen reader users, even if sighted users never notice.

Automated checks you can actually add to CI

You can't fully automate the semantic review the EAA effectively requires, but you can catch a chunk of the structural issues in CI:

  • String length ratio checks. Flag any translated string that exceeds a threshold (commonly 130-180% of the English source length) against a fixed-width container. Simple script, big payoff for German and Finnish.
  • Truncation detection in Lighthouse CI. Add a custom audit that checks computed text overflow on translated builds, not just the English default.
  • RTL snapshot testing. Run visual regression (Percy, Chromatic) against your Arabic or Hebrew builds specifically, not just LTR locales. Reading order bugs are visual, not just structural, so screenshot diffing catches things unit tests won't.
  • Placeholder/interpolation linting. i18next-scanner or eslint-plugin-i18next can catch missing or mismatched interpolation variables across locale files before they hit production.

None of this replaces a human reviewing the actual rendered screen with a screen reader running. But it stops the obvious regressions from reaching that review stage.

Testing with real assistive tech, not just automated audits

Automated accessibility tools (axe-core, WAVE) check DOM structure and attributes. They will not tell you that a translated label reads ambiguously with VoiceOver, or that your Arabic build has the wrong tab order because a flex container wasn't set up with dir="rtl" in mind.

Minimum viable manual test pass, per locale:

  1. Full keyboard navigation, tab order matches visual/logical reading order.
  2. Screen reader pass (VoiceOver on Mac, NVDA on Windows, TalkBack on Android) reading every interactive element aloud.
  3. Text zoom to 200%, checking for truncation or overlap.
  4. Error message review: does the spoken output tell the user what to actually do, not just that something failed.

This is slow. It's also the only way to catch a lot of what the EAA is actually asking for, which is comprehension, not just markup compliance.

Wiring this into a CI/CD-friendly localisation workflow

If your product ships frequently, you can't treat each release as a one-off translation job. A workable setup looks like:

  • CMS/codebase pushes new/changed strings to your TMS automatically on merge to a release branch.
  • TMS enforces context fields (screenshot, max length, component name) as required, not optional.
  • Translated strings come back via webhook/PR, triggering the automated checks above before merge.
  • A recurring (not one-off) manual assistive-tech pass on a sampled set of screens per release, not just at launch.

This is essentially a continuous localisation model applied specifically to accessibility requirements. Teams running regulated products (banking, e-commerce with EU exposure) increasingly bake this into an ISO 17100-aligned process, which is worth reading about if you're evaluating vendors or setting up an in-house equivalent.

The takeaway

The EAA turns "translate the UI" into "translate the UI without breaking the assistive technology contract." That's a pipeline problem as much as a linguistic one. If your i18n setup treats strings as flat, context-free key-value pairs, you have a gap regardless of how good your translators are. Fix the pipeline first, then the review process, in that order.

Top comments (0)