Using dynamic localization to improve Accessibility with React and Redux

Paul Zaich
Checkr Engineering
Published in
5 min readJul 27, 2017

Due to the sensitive legal requirements established by the FCRA (Fair Credit Reporting Act) which protects the rights of applicants in our industry, we take compliance very seriously. Each time an applicant authorizes Checkr to perform a background check on behalf of a client, a legal document is created on their behalf. Ensuring that these authorization documents are accurate is a critical part of our compliance effort. Making these authorization documents easy to read and understand aligns directly with Checkr’s mission to build a fairer future. As part of our recent redesign of this authorization flow, we targeted adding full localization support to ensure that non-native English speakers have an equally accessible experience and can complete the authorization in their preferred language.

https://xkcd.com/850/

Background

Previously localization had been implemented in a haphazard approach due to incremental changes in scope and pressures in delivery timeline. Each template or view was re-implemented in the supported languages (English and Spanish) across several different applicant workflows. This had several drawbacks:

  • Duplication: Components (and associated logic) were often implemented twice. This made updates to our components or implementing new features expensive and it was easy for engineers to mistakenly forget to update views in other languages. Furthermore, some workflows did not support localization at all.
  • Visibility for legal review: Since all legal text was embedded directly into HTML views, it was difficult to make copy directly accessible for review outside the engineering team.

Creating an extensible localization pattern for the Checkr application flow has enabled us to quickly add additional language and feature support , DRY up our component logic and streamlined the review process with our legal team.

How our localized text gets generated

Localization is slightly more complicated than a simple change to static text rendered in HTML. Checkr/apply renders internationalized text from 2 different sources:

  • Static copy: Rendered and stored by the Client application.
  • Custom Configurable text: Returned by the API that pertains to particular clients, types of background checks and the location of the applicant. For instance, New York City requires specific types of disclosures when authorizing a credit check. In other cases, clients require custom legal disclosures provided by their in-house compliance team.

Simple state change triggers a change in translation

Under the hood Checkr/apply uses a simple Redux store to store translations via the react-redux-i18 npm package.

react-redux-18n provides a simple set of actions and reducer to store the current active locale and a dictionary the contains a set of translation dictionaries.

New dictionaries are loaded into a store via a loadTranslations action

We use simple ECMAScript modules to store our translations as part of our primary application bundle due to their small size but YAML or JSON configuration files could just as easily be mounted as part of a transpiler’s build configuration. We chose to couple all static copy to the client application because much of the copy is directly related to component development but it would be easy to load additional localized dictionaries from remote sources as part of a separate localized bundle since the active bundle is stored in application state.

Configurable on a per package basis

The Checkr/apply application derives the set of available languages from the API response for a given background check package. Right now we support English and Spanish for all of our background check applications domestically. We can easily configure international background checks to support a different set of default languages.

Dispatching a change or locale

Updating a locale change requires an asynchronous request via redux-thunk + a request to our API via fetch in order to get translations for custom text snippets stored from our DB. We then dispatch the static locale change (that will trigger component updates) synchronously with our other custom text field state changes.

Connecting to the UI

Connecting this action to the UI is simple. Here’s a simplified version of our LanguageDropdown component.

The component consists of:

  • A dumb component LanguageDropdown that renders props that will be derived from mapStateToProps
  • A Higher Order Component generated by connect that connects to the redux store and wraps our updateLocale action in our store’s dispatch.

The component connects to our store to derive its localization state and available dropdown options:

Since our UI components are connected to the localization dictionary, any update made by the i18n reducer will trigger components to re-render based on the change in the translation key.

Verifying integrity of localized dictionaries

Given the legal sensitivity of our copy, it’s imperative that we validate for consistency across our dictionaries prior to deployment. We treat our English dictionary as the canonical set of keys and run a quick validation that all key paths exist in other localization dictionaries as part of our test suite.

Decoupling our localized copy from the components has had the added benefit of making translation and legal review a simple exercise that can be performed via a Github pull request by our Product Manager.

Next steps

Overall, we’re really happy with the flexibility that our React i18n implementation gives us. In fact, we’ve already ported the same pattern to another client-side service in our suite of services and we now implement localization in English and Spanish as a default.

In the future we’d like to do our best to anticipate the best language match for the applicant using the Accept-Language header to pre-select the preferred language rather than defaulting to English. Accept-Language provides the application with a set of probabilities that can be used to infer the preferred locale for the requesting user.

Conclusion

Integrating i18n into our React stack has greatly improved the workflow required to add additional localization to our client side applications. By smoothing out the process for legal review and translation, we’ve drastically reduced the cost of additional language support which will enable a better and fairer experience for applicants using our background check services.

--

--