Check out the example project list here: React i18n
In the realm of micro-frontends, ensuring each application remains as autonomous as possible is crucial. However, scenarios arise where inter-application communication is inevitable. A common requirement is synchronizing language preferences across micro-frontends, such as when a user changes the language setting in one application, and it cascades across all integrated micro-frontends. This documentation outlines a strategy for implementing internationalization using the react-i18next
library within a micro-frontend architecture facilitated by Module Federation.
Consider two applications: App A (the container application) and App B (the remote application). While App B functions independently as a standalone application, it is also designed to be embedded within App A at runtime. Our objective is to seamlessly synchronize language settings between App A and App B, ensuring both applications can manage and display their localized content.
To accommodate micro-frontend integration, we extend the existing Webpack/Rspack/Rsbuild and Create React App (CRA) configurations using the Module Federation plugin. This extension allows App B to expose various elements (e.g., components, themes, hooks) for consumption by App A or any other integrated applications without requiring codebase ejection.
The react-i18next
implementation forms the backbone of our translation functionality. Initially, an instance of i18next
is configured and imported directly into the main application file (App.js
). This instance leverages a context store to manage state, resources (translations), and plugins.
A direct implementation approach where each application initializes its i18next
instance could lead to resource conflicts, particularly where translated terms are overridden. To avoid this, we establish separate i18next
instances for App A and App B, ensuring each application maintains its translation terms independently.
For both App A and App B, configure separate i18next
instances as follows:
Wrap the application components in I18nextProvider
, passing the respective i18next
instances to ensure translation contexts are correctly applied.
For App B, write a custom hook to facilitate language switching, for example:
Expose this hook via Module Federation to allow its consumption by App A or other integrated applications.
In App A, implement a hook that orchestrates language switching across all integrated micro-frontends:
Implement a user interface component, such as a button, to trigger language changes across all applications:
To conditionally display language switcher components (e.g., hide the switcher in App B when embedded in App A), leverage a custom hook like useIsRemote
.
The useIsRemote
hook is designed to determine if the current application (e.g., App B) is running in a standalone mode or is embedded within another application (e.g., App A). This distinction allows us to conditionally render components based on the application's context.
Below we provided an example of a simplified implementation of the useIsRemote
hook that checks for a specific condition to determine the application's environment. In the real application this condition could be based on URL parameters, DOM presence checks, or any other trigger that differentiates between being embedded and running standalone:
With the useIsRemote hook implemented, you can now use it within your components to conditionally render elements based on whether the application is running standalone or is embedded. Here's an example of how it might be used to conditionally display a language switcher component in App B:
In this example, LanguageSwitcher
will only render when App B is not embedded within App A, based on the isRemote
state determined by the useIsRemote
hook. This approach ensures that components like language switchers are only shown in appropriate contexts, enhancing the user experience and maintaining the independence of micro-frontend applications.