A HoC (higher-order component) to add multi-language support to your React/Redux components.
- Supports multiple languages
- Provides components with global and component specific translations
- Will render HTML tags included in translation copy
- With webpack code splitting translation json can be bundled with their component
- Installation
- Usage
- Bundle translations with Webpack and react-router
- API
- Introduction to react-localize-redux
The following dependencies are required:
npm install react-localize-redux --save
Add the localeReducer
to your app's redux store. This will contain all translations data as well as the setting for current language.
import React from 'react';
import { createStore, combineReducers } from 'redux';
import ReactDOM from 'react-dom';
import { Store } from 'redux';
import { Provider } from 'react-redux';
import { localeReducer } from 'react-localize-redux';
const ROOT_NODE = document.getElementById('root');
const store = createStore(
combineReducers({
locale: localeReducer
}),
);
const App = props => {
return (
<Provider store={ store }>
...
</Provider>
);
};
ReactDOM.render(<App />, ROOT_NODE);
Set the current language for your app by dispatching the updateLanguage
action creator.
import { updateLanguage } from 'react-localize-redux';
store.dispatch(updateLanguage('en'));
Translations that are shared between components are called global
translations.
Assuming you have global transaltions stored in a file called global.locale.json
you can add them
to your store by dispatching the setGlobalTranslations
action creator.
NOTE: The following assumes you are using webpack with json-loader
import { setGlobalTranslations } from 'react-localize-redux';
const json = require("global.locale.json");
store.dispatch(setGlobalTranslations(json));
As mentioned above translation content is stored in json files. Each json file requires that there be a property for each supported language, where the property name would match the language key passed to updateLanguage.
{
"en": {
"greeting": "Hello ${ name }",
"farwell": "Goodbye"
},
"fr": {
"greeting": "Bonjour ${ name }",
"farwell": "Au revoir"
},
"es": {
"greeting": "Hola ${ name }",
"farwell": "Adiós"
}
}
To add translations to a component you will need to decorate it with the localize function. By default
all components decorated with localize
have access to global
translations. It will not modify your
component class, but return a new localized component with additional props translate
and currentLanguage
.
The translate
prop is a function that takes the unique id from the transaltion file as a param,
and an optional data
param for variable substitutions. The function will return the localized string based on currentLanguage
.
import React from 'react';
import { localize } from 'react-localize-redux';
const Greeting = ({ translate, currentLanguage }) => (
<div>
<h1>{ translate('greeting', { name: 'Ryan' }) }</h1>
<p>The current language is { `${ currentLanguage }` }</p>
<button>{ translate('farwell') }</button>
</div>
);
// decorate your component with localize
export default localize()(Greeting);
In addtion to global
translations you can also include translations specific to your component called local
translations.
Similar to global translations local
transaltions are added using an action creator setLocalTranslations
.
Assuming we have a component called WelcomeView
with translations specific to it stored in a file named welcome.locale.json
.
{
"en": {
"welcome-body": "Here is some <strong>bold</strong> text."
},
"fr": {
"welcome-body": "Voici un texte en <strong>gras</strong>"
},
"es": {
"welcome-body": "Aquí le damos algunos texto en <strong>negrita</strong>"
}
}
First you will load the local json data passing in a translationId
, in this case welcome
, followed by the json data.
import { setLocalTranslations } from 'react-localize-redux';
const json = require("welcome.locale.json");
store.dispatch(setLocalTranslations('welcome', json));
To access local
translations in your component you still use the localize
function,
but this time passing in the unique id that was used in setLocalTranslations
.
NOTE: In addition to the
local
translations you will still have accessglobal
translations as well.
import React from 'react';
import { localize } from 'react-localize-redux';
const WelcomeView = ({ translate }) => (
<div>
<h1>{ translate('greeting') }</h1>
<p>{ translate('welcome-body') }</p>
<button>{ translate('farwell') }</button>
</div>
);
// pass in the unique id for the local content you would like to add
export default localize('welcome')(Greeting);
When used with Webpack's json-loader, and react-router Dynamic Routing you can leverage code splitting to bundle components with their transaltion data.
See the dynamic-routes
folder in the examples forward on a working example of how to implement this setup.
A HoC factory method that returns an enhanced version of the WrappedComponent with the additional props for adding localized content to your component.
By calling localize
with no params your WrappedComponent will only have access to global
translations.
const MyComponent = ({ translate }) => <div>{ translate('greeting') }</div>;
export default localize()(MyComponent);
By default all components decorated with localize
will have access to global
transaltions. To add additional transaltion
data that was added by setLocalTranslations(translationId, json) you will need pass the translationId
as a param to localize
.
const MyComponent = ({ translate }) => <div>{ translate('title') }</div>;
export default localize('translationId')(MyComponent);
The following additional props are provided to localized components:
The current language set in your application. See updateLanguage on how to update current language.
The translate will be used to insert translated copy in your component. The id
param will need to match the property of the string you wish
to retrieve from your json translaion data.
The data
param is optional and can be used to insert dynamic data into your translations. The syntax follows the Javascript template
literal format.
// Here is a string where I want to dynamically insert the user's name, and country
{ "greet": "Hi here is my ${ name } and ${ country }" }
// With translate you'd do the following
translate('greet', { name: 'Ryan', country: 'Canada' })
For example if the below json file was added using either setGlobalTranslations or setLocalTranslations.
{
"en": {
"title": "My Title",
"desc": "My Description"
},
"fr": {
"title": "My Title French",
"desc": "My Description French"
}
}
and this component had been decorated with localize you would access the json content like so...
<h1>{ translate('title') }</h1>
<p>{ translate('desc') }</p>
NOTE: The json content that
translate
has access to will depend on thetranslationId
passed to thelocalize
method.
This will set the current language for your application, where languageCode
should match the languageCode
prop used in your translation json data.
The global json should contain any localized content that will be shared by multiple components. By default all components created by localize will have access to transaltion from this global json.
The local json should contain localized content specific to a component. This is especially useful when used in combination with react-router dynamic routing, and webpack code splitting features.