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.
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:
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
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
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
withLanguage , it’s just a connect that accesses
state.language and returns a style object containing
layoutDirection = "rtl/ltr" accordingly.
Putting it all together
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.
A very minimal representation of the whole setup can be accessed on this repo:
Contribute to react-localization-demo development by creating an account on GitHub.
If you’re unfamiliar with React Higher Order Components
The official documentation:
Higher-Order Components - React
A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the…
A great article that dives deep into HOCs: