Last active
November 30, 2017 19:06
-
-
Save dkarmalita/5250416e7bc48212db15e51752cfbd7c to your computer and use it in GitHub Desktop.
Example: React-Intl + Redux (i18n)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react'; | |
import { render } from 'react-dom'; | |
import { createStore, combineReducers, bindActionCreators } from 'redux' | |
import { Provider, connect } from 'react-redux'; | |
import { | |
FormattedDate, | |
FormattedTime, | |
FormattedRelative, | |
FormattedNumber, | |
FormattedPlural, | |
FormattedMessage, | |
IntlProvider, addLocaleData } from 'react-intl'; | |
// utils | |
// ===== | |
const getBrowserLocale = ()=> { | |
return (navigator.languages && navigator.languages[0]) || | |
navigator.language || | |
navigator.userLanguage; | |
} | |
const getBrowserLanguage = () => getBrowserLocale().toLowerCase().split(/[_-]+/)[0]; | |
const addLocales = (locales) => { | |
locales.forEach(locale=>{ | |
addLocaleData(require('react-intl/locale-data/'+locale)) | |
}) | |
} | |
// types | |
// ===== | |
const UPDATE_LOCALE = 'UPDATE_LOCALE'; | |
// actions (creators) | |
// ================== | |
const createUpdateLocale = locale => ({ | |
type: UPDATE_LOCALE, | |
payload: locale | |
}); | |
// config.js | |
// ===================== | |
const locales = ['en', 'ru', 'it']; | |
// note: If browser doesn't support Intl (i.e. IE11, then we manually import | |
// the intl polyfill and locale data. | |
if (!window.Intl) { | |
require.ensure([ | |
'intl', | |
'intl/locale-data/jsonp/en.js', | |
'intl/locale-data/jsonp/ru.js', | |
'intl/locale-data/jsonp/it.js', | |
], (require) => { | |
require('intl'); | |
require('intl/locale-data/jsonp/en.js'); | |
require('intl/locale-data/jsonp/ru.js'); | |
require('intl/locale-data/jsonp/it.js'); | |
addLocales(locales); | |
}); | |
}else{ | |
//setTimeout(()=>addLocales(locales), 1000); | |
addLocales(locales); | |
} | |
// note: Suppress [React Intl] console noise for "default message as fallback" | |
if (process.env.NODE_ENV !== 'production') { | |
const originalConsoleError = console.error | |
if (console.error === originalConsoleError) { | |
console.error = (...args) => { | |
if (args[0].indexOf('[React Intl] Missing message:') === 0) { | |
return | |
} | |
originalConsoleError.call(console, ...args) | |
} | |
} | |
} | |
// messages.json | |
// ========================= | |
// const messages = {"en":{}} | |
const messages = { | |
"en": { | |
"app.helloWorld": "Hello World", | |
"app.greeting": "Hello, {name}!" | |
}, | |
"ru": { | |
"app.helloWorld": "Привет, Мир!", | |
"app.greeting": "Привет, {name}!" | |
} } | |
// conteiner | |
// ========= | |
const mapStateToIntlProps = (state) => { | |
return { | |
locale: state.i18n.locale, | |
messages: state.i18n.messages | |
} | |
} | |
const IntlProviderConnected = connect(mapStateToIntlProps)(IntlProvider) | |
// reducer | |
// ======= | |
const browserLanguage = getBrowserLanguage(); | |
//const browserLanguage = 'az'; | |
const initialState = { | |
locale: browserLanguage,//'en', | |
messages: messages[browserLanguage]//'en']//{} | |
} | |
const updateLocale = (state, action) => { | |
const newState = { | |
...state, | |
locale: action.payload, | |
messages: messages[action.payload] | |
}; | |
return newState; | |
} | |
const i18n = (state = initialState, action) => { | |
switch (action.type) { | |
case UPDATE_LOCALE: | |
return updateLocale(state, action); | |
default: | |
return state; | |
} | |
}; | |
// Main app.js | |
// =========== | |
class Root extends Component { | |
constructor(props) { | |
super(props); | |
} | |
render() { | |
return <div> | |
<div>Locale: {this.props.locale}</div> | |
<input type="button" value={this.props.locale === 'en'?'ru':'en'} onClick={()=>this.props.updateLocale(this.props.locale === 'en'?'ru':'en')}/> | |
<br/><FormattedMessage | |
id="app.helloWorld" | |
defaultMessage={`Hello World`} | |
/> | |
<br/><FormattedMessage | |
id="app.no-translation-msg" | |
defaultMessage={`This message has no translation.`} | |
/> | |
<br/><FormattedDate | |
value={new Date(1459913574887)} | |
year='numeric' | |
month='long' | |
day='numeric' | |
weekday='long' | |
/> | |
<br/><FormattedDate value={new Date(1459832991883)}/> | |
<br/><FormattedTime value={new Date(1459832991883)}/> | |
<br/><FormattedRelative value={Date.now()}/> | |
<br/><FormattedNumber value={1000}/> | |
<br/>10 <FormattedPlural | |
value={10} | |
one='message' | |
other='messages' | |
/> | |
<br/><FormattedMessage | |
id='app.greeting' | |
description='Greeting to welcome the user to the app' | |
defaultMessage='Hello, {name}!' | |
values={{ | |
name: <b>Eric</b> | |
}} | |
/> | |
</div> | |
} | |
} | |
const rootReducer = combineReducers({ | |
i18n | |
}) | |
const store = createStore(rootReducer) | |
const mapStateToProps = (state) => { | |
return { | |
locale: state.i18n.locale, | |
} | |
} | |
const mapDispatchToProps = (dispatch) => { | |
return { | |
updateLocale: bindActionCreators(updateLocale, dispatch) | |
} | |
} | |
const ConnectedRoot = connect(mapStateToProps, mapDispatchToProps)(Root) | |
const appRun = () => { | |
render( | |
<Provider store={store}> | |
<IntlProvider> | |
<ConnectedRoot/> | |
</IntlProvider> | |
</Provider>, | |
document.getElementById('root') | |
); | |
} | |
appRun(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment