Skip to content
This repository has been archived by the owner on Sep 1, 2021. It is now read-only.

Commit

Permalink
Language switcher using the Context API
Browse files Browse the repository at this point in the history
Makes it possible to switch language using the top right corner
dropdown. Note this uses a new `LanguageUpdate` component yet to be unit
tested.
closes #61 and closes #62
  • Loading branch information
AndreMiras committed Mar 7, 2020
1 parent 67ba5e7 commit 1b6292c
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 24 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## [Unreleased]

- Language switcher using the Context API, refs #61 and #62


## [2020.01.03]

- Setup up basic translations in French and Spanish, refs #2
Expand Down
26 changes: 17 additions & 9 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import React from 'react';
import { IntlProvider } from 'react-intl';
import { HashRouter as Router } from 'react-router-dom';
import './App.css';
import { IntlContext } from './contexts/IntlContext';
import Headers from './components/Headers';
import Footers from './components/Footers';
import Container from './components/Container';
import { messages } from './utils/locales';


const App = () => (
<Router>
<div className="App">
<Headers />
<Container />
<Footers />
</div>
</Router>
);
const App = () => {
const [locale] = React.useContext(IntlContext);
return (
<Router>
<IntlProvider locale={locale} messages={messages[locale]}>
<div className="App">
<Headers />
<Container />
<Footers />
</div>
</IntlProvider>
</Router>
);
};

export default App;
4 changes: 2 additions & 2 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { IntlProvider } from 'react-intl';
import IntlContextProvider from './contexts/IntlContext';
import App from './App';

it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<IntlProvider locale="en"><App /></IntlProvider>, div);
ReactDOM.render(<IntlContextProvider><App /></IntlContextProvider>, div);
ReactDOM.unmountComponentAtNode(div);
});
2 changes: 2 additions & 0 deletions src/components/Headers.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { NavLink } from 'react-router-dom';
import LanguageUpdate from './LanguageUpdate';

const Logo = () => (
<a className="navbar-brand" href="/">
Expand Down Expand Up @@ -62,6 +63,7 @@ const NavSections = () => (
/>
</a>
</li>
<LanguageUpdate />
</ul>
</div>
);
Expand Down
48 changes: 48 additions & 0 deletions src/components/LanguageUpdate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { arrayOf, func, string } from 'prop-types';
import { IntlContext } from '../contexts/IntlContext';
import { locales } from '../utils/locales';

const DropdownItem = ({ text, onClick }) => (
<button className="dropdown-item" type="button" onClick={() => onClick(text)}>{text}</button>
);
DropdownItem.propTypes = {
text: string.isRequired,
onClick: func.isRequired,
};

const DropdownMenu = ({ items, onClick }) => (
<div className="dropdown-menu" aria-labelledby="navbarDropdown">
{items.map(item => <DropdownItem text={item} onClick={onClick} key={item} />)}
</div>
);
DropdownMenu.propTypes = {
items: arrayOf(string).isRequired,
onClick: func.isRequired,
};

const LanguageUpdate = () => {
const [locale, setLocale] = React.useContext(IntlContext);

return (
<li className="nav-item dropdown">
<button
className="nav-link btn button-link dropdown-toggle"
id="navbarDropdown"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
type="button"
>
<i className="fas fa-flag" />
{locale.toUpperCase()}
</button>
<DropdownMenu
items={locales}
onClick={newLocale => setLocale(newLocale)}
/>
</li>
);
};

export default LanguageUpdate;
19 changes: 19 additions & 0 deletions src/contexts/IntlContext.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { element } from 'prop-types';


export const IntlContext = React.createContext();

const IntlContextProvider = ({ children }) => {
const [locale, setLocale] = React.useState('en');
return (
<IntlContext.Provider value={[locale, setLocale]}>
{children}
</IntlContext.Provider>
);
};
IntlContextProvider.propTypes = {
children: element.isRequired,
};

export default IntlContextProvider;
16 changes: 3 additions & 13 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { IntlProvider } from 'react-intl';
import messagesEs from './translations/es.json';
import messagesFr from './translations/fr.json';
import setupGA from './utils/analytics';
import setupSentry from './utils/sentry';
import IntlContextProvider from './contexts/IntlContext';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min';
Expand All @@ -15,18 +13,10 @@ import * as serviceWorker from './serviceWorker';
setupGA();
setupSentry();

const messages = {
en: null,
es: messagesEs,
fr: messagesFr,
};
// language without region code
const language = navigator.language.split(/[-_]/)[0];

ReactDOM.render(
<IntlProvider locale={language} messages={messages[language]}>
<IntlContextProvider>
<App />
</IntlProvider>,
</IntlContextProvider>,
document.getElementById('root'),
);

Expand Down
12 changes: 12 additions & 0 deletions src/utils/locales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import messagesEs from '../translations/es.json';
import messagesFr from '../translations/fr.json';


const messages = {
en: null,
es: messagesEs,
fr: messagesFr,
};
const locales = Object.keys(messages);

export { messages, locales };

0 comments on commit 1b6292c

Please sign in to comment.