I’ve been doing some work with internationalization and localization (mostly language translation) which
I first addressed here.
In my continuing work with using the react-i18next package, I ran into a few places where it wasn’t very easy
to use the package’s
<I18n /> component. This I18n component is significant because, as seen in the article
from the link, it prevents the raw translation strings from being rendered until the translations themselves have been loaded.
Now, for the majority of cases components can be refactored in such a way that the above implementation can be achieved. However,
there were a few cases as I was going through and adding translations in which I couldn’t cleanly use the
<I18n /> component provided
One such case was a utility function used in multiple places in the app. In a very simplified example, this function would either return a formatted date/time or “Today” based on the current timestamp.
This is pretty much all that needs to be done, since the
<I18n /> component basically calls this exact function and configuration “under the covers”. Due to the asynchornous
nature of loading the translation strings though (at least in my case since I’m using an XHR plugin to fetch the JSON files), if the
i18n.t('date.today') statement was executed
before the translations loaded, the string would be interpolated by React as “date.today” and be stuck that way, even after the translations loaded.
After doing a little digging, I turned to Higher-Order Components to solve my problem. From the link,
A higher-order component (HOC) is a function that takes a component and returns a new component
That is essentially what the
<I18n /> component was doing as well, except that component was taking its children (already conveniently wrapped as a function) and passing the translation function into it once the
translations had loaded. This works for most cases until you either want to share logic that provides translated strings, or the translations are nested in such a way that it would be too much of a pain or too messy to pass the
t() function through a series of other functions once it becomes available.
Luckily the underlying i18next package offers a callback when the translations are loaded. That way we can wrap any any component that uses the
i18n.t() function without the
<I18n /> component and hide it until the translations are loaded, thus mimicking the
<I18n /> component while
giving a more generic and flexible use-case.
Now when the component is exported, just wrap it in this HOC function and the wrapped component will re-render when the translations are loaded!