Localize your React App with Zero Dependencies

At Zyda (www.zyda.com), we make a food ordering application, restaurants sign up to use our service, setup or import their info and menu, and their customers can start ordering food directly from their restaurants.

Being based in Kuwait, restaurants and customers expect the menu and the entire interface to be in Arabic, or at least that customers have the option to switch to Arabic whenever they want, so we had localization in mind since day 1.

Our first impulse was to use an internationalization library and feed it our list of strings and go from there. The choices were many and they each had some extra bells and whistles. But then someone had an idea: why not do our own implementation in plain JavaScript?

The idea seemed kind of absurd at first: reinventing the wheel and whatnot. But then it started to make some sense considering we also had our package size in mind since day 1, performance initial load time are both very important in any e-commerce app. So we are continually cutting down dependencies that are neither absolutely essential nor easily replaceable.

Reinventing the wheel

First things first, “hello world” in Arabic and English:

localized strings

Now that our strings had a place to live, we just needed to access them:

Simply put, this method accepts a string id, ex: “HELLO_WORLD” and a language parameter, and it returns the required string in the desired language.
Bonus: if a string was missing in that language, for some reason, say a developer forgot to translate it, the method would know to fallback to the other language after outputting a warning to the console.

Next, we needed to keep track of which language is “active” at any given time, our setup was Redux based, so we created languageReducer :

Again, very simple. The language can either be en or ar , and a toggleLanguage action would only switch between the 2.

Of course, to put it all together in the presentational component, we needed to access the language that lives in Redux and call getString , since this will be needed in every presentational component, we we ended up creating a Higher Order Component.

The withLanguage Higher Order Component

withLanguage is basically a connect that accesses state.language , the one we store and toggle using languageReducer .

What about RTL?

Having a translated string doesn’t mean you’re done localizing your app, it needed to to be displayed in RTL when users select Arabic. We achieved this using pure CSS and some logic connected to the language value we persist.

The withDirectionStyle Higher Order Component

Similar to withLanguage , it’s just a connect that accesses state.language and returns a style object containing layoutDirection = "rtl/ltr" accordingly.

Putting it all together

Neat.

Results

After some trial and error, we’re very satisfied with our decision not to use an external library to handle localization, especially after needing to further customize our setup to accommodate more use cases. For example, we’ve now introduced a customizable default language setting that restaurants control. You can see the whole setup in action in any restaurant using our service: http://orders.johnnyrockets-me.com/

On our to-do

1. Use route instead of Redux state to hold the currently selected language.
This will result in some cool things like the back button serving as an undo to an unwanted language change. And to links shared with other people opening in the sharer’s language.

2. Check during compile time to make sure no strings are missing.

Gotchas

A very minimal representation of the whole setup can be accessed on this repo:

If you’re unfamiliar with React Higher Order Components

The official documentation:

A great article that dives deep into HOCs:

Like what you read? Give Mahmoud AlyuDeen a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.