diff --git a/package.json b/package.json index 8a8a1a5..2ee8a06 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,9 @@ "favicons-webpack-plugin-cesco": "^0.0.6", "feather-icons": "^4.5.0", "html-webpack-plugin": "^2.30.1", + "i18next": "^10.3.0", "jest": "^22.2.2", + "json-loader": "^0.5.7", "npm-run-all": "^4.1.2", "postcss-cssnext": "^3.1.0", "postcss-loader": "^2.1.0", @@ -73,12 +75,14 @@ "react": "^16.2.0", "react-dom": "^16.2.0", "react-ga": "^2.4.1", + "react-i18next": "^7.3.6", "style-loader": "^0.20.1", "svg-react-loader": "^0.4.5", "uglifyjs-webpack-plugin": "^1.1.8", "webpack": "^3.10.0", "webpack-merge": "^4.1.1", - "workbox-webpack-plugin": "^2.1.2" + "workbox-webpack-plugin": "^2.1.2", + "yaml-loader": "^0.5.0" }, "devDependencies": { "http-server": "^0.11.1", diff --git a/src/components/Footer.js b/src/components/Footer.js index df542b9..9b91a29 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -1,20 +1,24 @@ import React from 'react'; +import { translate, Trans } from 'react-i18next'; const Footer = () => ( ); -export default Footer; +export default translate()(Footer); +export { Footer }; diff --git a/src/components/Footer.test.js b/src/components/Footer.test.js index f7947b0..4478aaf 100644 --- a/src/components/Footer.test.js +++ b/src/components/Footer.test.js @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import Footer from './Footer'; +import { Footer } from './Footer'; test('Footer rendering', () => { const component = shallow( diff --git a/src/components/Header.js b/src/components/Header.js index 0ca4ec4..98cf9c2 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,4 +1,5 @@ import React from 'react'; +import { translate, Trans } from 'react-i18next'; import GithubIcon from 'feather-icons/dist/icons/github.svg'; @@ -10,10 +11,11 @@ const Header = () => ( ); -export default Header; +export default translate()(Header); +export { Header }; diff --git a/src/components/Header.test.js b/src/components/Header.test.js index fbf279e..726e74c 100644 --- a/src/components/Header.test.js +++ b/src/components/Header.test.js @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import Header from './Header'; +import { Header } from './Header'; const env = { ...process.env }; diff --git a/src/components/PageTemplate.js b/src/components/PageTemplate.js index 0ab2763..0dea74c 100644 --- a/src/components/PageTemplate.js +++ b/src/components/PageTemplate.js @@ -4,9 +4,6 @@ import PropTypes from 'prop-types'; import pkg from '../../package.json'; -import Header from '../components/Header'; -import Footer from '../components/Footer'; - const PageTemplate = ({ title, children }) => ( @@ -20,9 +17,7 @@ const PageTemplate = ({ title, children }) => (
-
{ children } -
diff --git a/src/components/RavenBoundary.js b/src/components/RavenBoundary.js index dc25ac4..b3c8a2b 100644 --- a/src/components/RavenBoundary.js +++ b/src/components/RavenBoundary.js @@ -21,7 +21,6 @@ class RavenBoundary extends React.Component { if (error) { const errorProps = { - heading: 'An error has occurred.', details: { extra: errorInfo }, error }; diff --git a/src/components/RavenError.js b/src/components/RavenError.js index 4b31605..d549540 100644 --- a/src/components/RavenError.js +++ b/src/components/RavenError.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { translate, Trans } from 'react-i18next'; import { Raven } from '../sentry'; import Message from './Message'; @@ -20,10 +21,12 @@ class RavenError extends React.Component { } render() { - const { heading } = this.props; + const { t } = this.props; - return -

This error has been logged. You may also fill out a report.

+ return +

+ This error has been logged. You may also fill out a report. +

; } } @@ -31,7 +34,8 @@ class RavenError extends React.Component { RavenError.propTypes = { error: PropTypes.object.isRequired, details: PropTypes.object.isRequired, - heading: PropTypes.string.isRequired + t: PropTypes.func }; -export default RavenError; +export default translate()(RavenError); +export { RavenError }; diff --git a/src/components/RavenError.test.js b/src/components/RavenError.test.js index 084bf25..4efa3f3 100644 --- a/src/components/RavenError.test.js +++ b/src/components/RavenError.test.js @@ -3,11 +3,12 @@ import { shallow } from 'enzyme'; jest.mock('../sentry'); -import RavenError from './RavenError'; +import { RavenError } from './RavenError'; import { Raven } from '../sentry'; const testError = { error: 'test error' }; const testDetails = { details: 'test details' }; +const translate = v => `translate(${ v })`; describe('RavenError', () => { test('rendering', () => { @@ -15,7 +16,7 @@ describe('RavenError', () => { + t={ translate }/> ); expect(component).toMatchSnapshot(); }); @@ -25,7 +26,7 @@ describe('RavenError', () => { + t={ translate }/> ); expect(Raven.captureException).toHaveBeenCalledWith(testError, testDetails); }); @@ -36,7 +37,7 @@ describe('RavenError', () => { + t={ translate }/> ); const eventObj = { preventDefault: jest.fn() }; component.find('a').simulate('click', eventObj); diff --git a/src/components/__snapshots__/Footer.test.js.snap b/src/components/__snapshots__/Footer.test.js.snap index ca2b0b6..6d82bb1 100644 --- a/src/components/__snapshots__/Footer.test.js.snap +++ b/src/components/__snapshots__/Footer.test.js.snap @@ -6,24 +6,30 @@ exports[`Footer rendering 1`] = ` className="inline with-separator" >
  • - Created by - - Jeff Avallone - + + Created by + + Jeff Avallone + +
  • - Generated images licensed: - - Creative Commons CC-BY-3.0 License - + Generated images licensed: + + Creative Commons CC-BY-3.0 License + +
  • diff --git a/src/components/__snapshots__/Header.test.js.snap b/src/components/__snapshots__/Header.test.js.snap index b7f3c15..318d478 100644 --- a/src/components/__snapshots__/Header.test.js.snap +++ b/src/components/__snapshots__/Header.test.js.snap @@ -20,7 +20,9 @@ exports[`Header rendering 1`] = ` href="https://github.com/javallone/regexper-static" > - Source on GitHub + + Source on GitHub + diff --git a/src/components/__snapshots__/PageTemplate.test.js.snap b/src/components/__snapshots__/PageTemplate.test.js.snap index aa190c7..eff8e67 100644 --- a/src/components/__snapshots__/PageTemplate.test.js.snap +++ b/src/components/__snapshots__/PageTemplate.test.js.snap @@ -28,11 +28,9 @@ exports[`PageTemplate rendering 1`] = `
    -

    Content

    -
    @@ -67,11 +65,9 @@ exports[`PageTemplate rendering with title 1`] = `
    -

    Content

    -
    diff --git a/src/components/__snapshots__/RavenBoundary.test.js.snap b/src/components/__snapshots__/RavenBoundary.test.js.snap index bbbe7d8..abd2cc5 100644 --- a/src/components/__snapshots__/RavenBoundary.test.js.snap +++ b/src/components/__snapshots__/RavenBoundary.test.js.snap @@ -3,7 +3,7 @@ exports[`RavenBoundary rendering (with error) 1`] = ``; exports[`RavenBoundary rendering (with error) 2`] = ` - `; diff --git a/src/components/__snapshots__/RavenError.test.js.snap b/src/components/__snapshots__/RavenError.test.js.snap index c1845df..14c595f 100644 --- a/src/components/__snapshots__/RavenError.test.js.snap +++ b/src/components/__snapshots__/RavenError.test.js.snap @@ -3,18 +3,22 @@ exports[`RavenError rendering 1`] = `

    - This error has been logged. You may also - - fill out a report - - . + This error has been logged. You may also + + fill out a report + + . +

    `; diff --git a/src/i18n.js b/src/i18n.js new file mode 100644 index 0000000..cce163a --- /dev/null +++ b/src/i18n.js @@ -0,0 +1,14 @@ +import i18n from 'i18next'; +import { reactI18nextModule } from 'react-i18next'; + +import locales from './locales'; + +i18n + .use(reactI18nextModule) + .init({ + fallbackLng: 'en', + debug: (process.env.NODE_ENV !== 'production'), + resources: locales + }); + +export default i18n; diff --git a/src/locales/en/translation.yaml b/src/locales/en/translation.yaml new file mode 100644 index 0000000..6b8c227 --- /dev/null +++ b/src/locales/en/translation.yaml @@ -0,0 +1,7 @@ +404 Page Not Found: 404 Page Not Found +An error has occurred: An error has occurred +Created by <1>Jeff Avallone: Created by <1>Jeff Avallone +Generated images licensed: "Generated images licensed: <1><0>" +Source on GitHub: Source on GitHub +The page you have requested could not be found: The page you have requested could not be found +This error has been logged: This error has been logged. You may also <1>fill out a report. diff --git a/src/locales/index.js b/src/locales/index.js new file mode 100644 index 0000000..80aa256 --- /dev/null +++ b/src/locales/index.js @@ -0,0 +1,5 @@ +export default { + en: { + translation: require('./en/translation.yaml') + } +}; diff --git a/src/pages/404/Component.js b/src/pages/404/Component.js new file mode 100644 index 0000000..8c23b7a --- /dev/null +++ b/src/pages/404/Component.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { translate, Trans } from 'react-i18next'; + +import Message from '../../components/Message'; +import AlertIcon from 'feather-icons/dist/icons/alert-octagon.svg'; +import Header from '../../components/Header'; +import Footer from '../../components/Footer'; + +const Component = ({ t }) => ( // eslint-disable-line react/prop-types + +
    + +

    The page you have requested could not be found

    +
    +