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(
Proposals page
; + return{this.props.t('proposals.pageTitle')}
; } } + +ProposalsPage.propTypes = { + // translate HoC: + t: PropTypes.func +}; + +export default translate()(ProposalsPage);