diff --git a/package.json b/package.json index b047de3..0d9ea21 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,17 @@ "@material-ui/core": "^1.0.0-rc.0", "@material-ui/icons": "1.0.0-beta.42", "eslint-plugin-flowtype": "2.46.3", + "i18next": "11.5.0", "material-ui": "1.0.0-beta.42", "mdi-material-ui": "^5.0.0", "react": "16.3.2", "react-dom": "16.3.2", + "react-i18next": "7.10.1", "react-redux": "5.0.7", "react-router-dom": "4.2.2", "react-scripts": "1.1.4", "redux": "4.0.0", + "redux-thunk": "2.3.0", "typeface-roboto": "^0.0.54" }, "scripts": { diff --git a/src/app/i18n/actions.js b/src/app/i18n/actions.js new file mode 100644 index 0000000..7d55da0 --- /dev/null +++ b/src/app/i18n/actions.js @@ -0,0 +1,10 @@ +import i18nInstance from './i18n'; + +export const setLocale = locale => dispatch => { + dispatch({ + type: 'SET_LOCALE', + locale + }); + + i18nInstance.changeLanguage(locale); +}; diff --git a/src/app/i18n/i18n.js b/src/app/i18n/i18n.js new file mode 100644 index 0000000..eca5689 --- /dev/null +++ b/src/app/i18n/i18n.js @@ -0,0 +1,18 @@ +import i18next from 'i18next'; + +import ro from './translations/ro.json'; +import en from './translations/en.json'; + +i18next.init({ + interpolation: { + // React already does escaping + escapeValue: false + }, + lng: 'ro', + resources: { + ro, + en + } +}); + +export default i18next; diff --git a/src/app/i18n/index.js b/src/app/i18n/index.js new file mode 100644 index 0000000..b9332bb --- /dev/null +++ b/src/app/i18n/index.js @@ -0,0 +1,3 @@ +export { default as i18nInstance } from './i18n'; +export { default as i18n } from './reducer'; +export * from './actions'; diff --git a/src/app/i18n/reducer.js b/src/app/i18n/reducer.js new file mode 100644 index 0000000..edc0853 --- /dev/null +++ b/src/app/i18n/reducer.js @@ -0,0 +1,18 @@ +const i18n = ( + state = { + locale: 'ro' + }, + action +) => { + switch (action.type) { + case 'SET_LOCALE': + return { + // set to 'cimode' to have i18next render translation keys instead of values + locale: action.locale + }; + default: + return state; + } +}; + +export default i18n; diff --git a/src/app/i18n/translations/en.json b/src/app/i18n/translations/en.json new file mode 100644 index 0000000..f9acf87 --- /dev/null +++ b/src/app/i18n/translations/en.json @@ -0,0 +1,7 @@ +{ + "translation": { + "proposals": { + "pageTitle": "Proposals page" + } + } +} diff --git a/src/app/i18n/translations/ro.json b/src/app/i18n/translations/ro.json new file mode 100644 index 0000000..6b5159e --- /dev/null +++ b/src/app/i18n/translations/ro.json @@ -0,0 +1,7 @@ +{ + "translation": { + "proposals": { + "pageTitle": "Pagina de propuneri" + } + } +} diff --git a/src/index.js b/src/index.js index e0e3045..db08cfc 100644 --- a/src/index.js +++ b/src/index.js @@ -1,29 +1,37 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; -import { combineReducers, createStore } from 'redux'; +import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; +import thunk from 'redux-thunk'; import { App } from './app'; +import { i18nInstance } from './app/i18n'; import registerServiceWorker from './registerServiceWorker'; // Import module reducers +import { i18n } from './app/i18n'; import { categorySelection } from './category-selection'; import { categories } from './categories'; const rootReducer = combineReducers({ + i18n, categorySelection, categories }); +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( rootReducer, - window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + composeEnhancers(applyMiddleware(thunk)) ); ReactDOM.render( - + + + , document.getElementById('root') ); diff --git a/src/proposals/components/ProposalsPage/ProposalsPage.jsx b/src/proposals/components/ProposalsPage/ProposalsPage.jsx index b6f8066..f1e0577 100644 --- a/src/proposals/components/ProposalsPage/ProposalsPage.jsx +++ b/src/proposals/components/ProposalsPage/ProposalsPage.jsx @@ -1,7 +1,16 @@ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { translate } from 'react-i18next'; -export default class ProposalsPage extends Component { +class ProposalsPage extends Component { render() { - return

Proposals page

; + return

{this.props.t('proposals.pageTitle')}

; } } + +ProposalsPage.propTypes = { + // translate HoC: + t: PropTypes.func +}; + +export default translate()(ProposalsPage);