diff --git a/package.json b/package.json index 55f78b485..e7d75b97c 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,9 @@ "bitcore-mnemonic": "=1.1.1", "copy-to-clipboard": "=3.0.6", "flexboxgrid": "=6.3.1", + "i18next": "^9.0.0", + "i18next-localstorage-cache": "^1.1.1", + "i18next-xhr-backend": "^1.4.2", "lisk-js": "=0.4.5", "moment": "=2.15.1", "postcss": "=6.0.2", @@ -42,6 +45,7 @@ "react-circular-progressbar": "=0.1.5", "react-css-themr": "=2.1.2", "react-dom": "=15.6.x", + "react-i18next": "^5.2.0", "react-redux": "=5.0.5", "react-router": "=4.1.2", "react-router-dom": "=4.1.2", diff --git a/src/components/app/index.test.js b/src/components/app/index.test.js index ab864a635..b249a7275 100644 --- a/src/components/app/index.test.js +++ b/src/components/app/index.test.js @@ -4,6 +4,8 @@ import { MemoryRouter } from 'react-router'; import { Provider } from 'react-redux'; import { expect } from 'chai'; import configureStore from 'redux-mock-store'; +import { I18nextProvider } from 'react-i18next'; +import i18n from '../../i18n'; // initialized i18next instance import App from './'; import Login from '../login'; import Transactions from '../transactions'; @@ -16,7 +18,9 @@ const addRouter = Component => (props, path) => mount( + + , ); diff --git a/src/components/header/header.js b/src/components/header/header.js index 61d57ee3a..bac432ad0 100644 --- a/src/components/header/header.js +++ b/src/components/header/header.js @@ -54,13 +54,13 @@ const Header = props => ( })} /> - + + })}>{props.t('send')} ); diff --git a/src/components/header/header.test.js b/src/components/header/header.test.js index 3b5058f1b..3adf251a3 100644 --- a/src/components/header/header.test.js +++ b/src/components/header/header.test.js @@ -15,6 +15,7 @@ describe('Header', () => { const mockInputProps = { setActiveDialog: () => { }, account: {}, + t: t => t, }; propsMock = sinon.mock(mockInputProps); wrapper = shallow(
); diff --git a/src/components/header/index.js b/src/components/header/index.js index bb858ad9d..cee76574c 100644 --- a/src/components/header/index.js +++ b/src/components/header/index.js @@ -1,4 +1,5 @@ import { connect } from 'react-redux'; +import { translate } from 'react-i18next'; import { dialogDisplayed } from '../../actions/dialog'; import { accountLoggedOut } from '../../actions/account'; import Header from './header'; @@ -11,8 +12,7 @@ const mapDispatchToProps = dispatch => ({ setActiveDialog: data => dispatch(dialogDisplayed(data)), logOut: () => dispatch(accountLoggedOut()), }); - export default connect( mapStateToProps, mapDispatchToProps, -)(Header); +)(translate()(Header)); diff --git a/src/components/header/index.test.js b/src/components/header/index.test.js index 196225312..9f7894f33 100644 --- a/src/components/header/index.test.js +++ b/src/components/header/index.test.js @@ -3,6 +3,8 @@ import { expect } from 'chai'; import { mount } from 'enzyme'; import { Provider } from 'react-redux'; import sinon from 'sinon'; +import { I18nextProvider } from 'react-i18next'; +import i18n from '../../i18n'; // initialized i18next instance import * as accountActions from '../../actions/account'; import * as dialogActions from '../../actions/dialog'; import Header from './header'; @@ -14,7 +16,11 @@ describe('HeaderHOC', () => { let wrapper; beforeEach(() => { - wrapper = mount(); + wrapper = mount( + + + + ); }); it('should render Header', () => { diff --git a/src/i18n.js b/src/i18n.js new file mode 100755 index 000000000..ea7622042 --- /dev/null +++ b/src/i18n.js @@ -0,0 +1,37 @@ +import i18n from 'i18next'; +import XHR from 'i18next-xhr-backend'; +// import Cache from 'i18next-localstorage-cache'; + +i18n + .use(XHR) + // .use(Cache) + .init({ + fallbackLng: 'en', + lng: 'en', + react: { + // wait: true, // globally set to wait for loaded translations in translate hoc + // exposeNamespace: true // exposes namespace on data-i18next-options to be used in eg. + }, + + // have a common namespace used around the full app + ns: ['common'], + defaultNS: 'common', + + debug: true, + + // cache: { + // enabled: true, + // }, + + interpolation: { + escapeValue: false, // not needed for react!! + formatSeparator: ',', + format: (value, format) => { + if (format === 'uppercase') return value.toUpperCase(); + return value; + }, + }, + }); + + +export default i18n; diff --git a/src/locales/de/common.json b/src/locales/de/common.json new file mode 100644 index 000000000..26873f929 --- /dev/null +++ b/src/locales/de/common.json @@ -0,0 +1,4 @@ +{ + "send": "senden", + "logout": "Ausloggen" +} diff --git a/src/locales/en/common.json b/src/locales/en/common.json new file mode 100644 index 000000000..3d74db400 --- /dev/null +++ b/src/locales/en/common.json @@ -0,0 +1,4 @@ +{ + "send": "send", + "logout": "logout" +} diff --git a/src/main.js b/src/main.js index acf338c8c..3ac36ddbc 100644 --- a/src/main.js +++ b/src/main.js @@ -2,15 +2,19 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { HashRouter as Router } from 'react-router-dom'; import { Provider } from 'react-redux'; +import { I18nextProvider } from 'react-i18next'; import App from './components/app'; import store from './store'; +import i18n from './i18n'; // initialized i18next instance const rootElement = document.getElementById('app'); const renderWithRouter = Component => - + + + ;