Skip to content
Snippets Groups Projects
Commit 991c944a authored by Jessie Keck's avatar Jessie Keck
Browse files

Add a LanguageSettings component and hook it up to the WorkspaceMenu.

parent eb1aa24d
No related branches found
No related tags found
No related merge requests found
describe('Language Switching', () => {
describe('Application Language', () => {
it('allows the user to switch the application language', async () => {
await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/');
await expect(page).toClick('#menuBtn');
await expect(page).toMatchElement('ul[role="menu"]');
await expect(page).toMatchElement('li p', { text: 'Language' });
await expect(page).not.toMatchElement('li', { text: 'Deutsch' });
await expect(page).not.toMatchElement('li', { text: 'English' });
await expect(page).toClick('li', { text: 'Language' });
await expect(page).toMatchElement('li', { text: 'Deutsch' });
await expect(page).toMatchElement('li', { text: 'English' });
await expect(page).toMatchElement('[aria-label="Toggle window sidebar"]');
await expect(page).not.toMatchElement('[aria-label="Seitenleiste umschalten"]');
await expect(page).toClick('li', { text: 'Deutsch' });
await page.waitFor(1000);
await expect(page).not.toMatchElement('[aria-label="Toggle window sidebar"]');
await expect(page).toMatchElement('[aria-label="Seitenleiste umschalten"]');
});
});
});
import React from 'react';
import { shallow } from 'enzyme';
import LanguageSettings from '../../../src/components/LanguageSettings';
/**
* Helper function to create a shallow wrapper around LanguageSettings
*/
function createWrapper(props) {
return shallow(
<LanguageSettings
active={lang => lang === 'de'}
handleClick={() => {}}
languages={{}}
{...props}
/>,
);
}
describe('LanguageSettings', () => {
let wrapper;
const languages = {
de: 'Deutsch',
en: 'English',
};
it('renders a list with a list item for each language passed in props', () => {
wrapper = createWrapper({ languages });
expect(wrapper.find('WithStyles(MenuItem)').length).toBe(2);
});
it('non-active list items are buttons (and active are not)', () => {
wrapper = createWrapper({ languages });
expect(
wrapper
.find('WithStyles(MenuItem)')
.first() // The German / active button
.prop('button'),
).toBe(false);
expect(
wrapper
.find('WithStyles(MenuItem)')
.last() // The English / non-active button
.prop('button'),
).toBe(true);
});
it('renders the check icon when the active prop returns true', () => {
wrapper = createWrapper({ languages });
expect(
wrapper
.find('WithStyles(MenuItem)')
.first()
.find('WithStyles(ListItemIcon) pure(CheckSharpIcon)')
.length,
).toBe(1);
});
it('renders the language value in an Typography element wrapped in a ListItemText', () => {
wrapper = createWrapper({ languages });
const firstListText = wrapper
.find('WithStyles(MenuItem)')
.first()
.find('WithStyles(ListItemText) WithStyles(Typography)')
.children()
.text();
expect(firstListText).toEqual('Deutsch');
});
it('triggers the handleClick prop when clicking a list item', () => {
const mockHandleClick = jest.fn();
wrapper = createWrapper({ languages, handleClick: mockHandleClick });
wrapper.find('WithStyles(MenuItem)').last().simulate('click');
expect(mockHandleClick).toHaveBeenCalledTimes(1);
expect(mockHandleClick).toHaveBeenCalledWith('en');
});
it('passes the language prop to the active prop function to determine if the given language is active', () => {
const mockActiveFn = jest.fn();
wrapper = createWrapper({ active: mockActiveFn, languages: { en: 'English' } });
expect(mockActiveFn).toHaveBeenCalledWith('en');
});
});
......@@ -21,6 +21,7 @@
"downloadExportWorkspace": "Download/Export Arbeitsfläche",
"fetchManifest": "Hinzufügen",
"fullScreen": "Vollbild",
"language": "Sprache",
"light": "Hell",
"listAllOpenWindows": "Liste der geöffneten Fenster",
"manifestError": "Die Ressource konnte nicht hinzugefügt werden:",
......
......@@ -22,6 +22,7 @@
"fetchManifest": "Add",
"fullScreen": "Full Screen",
"hideZoomControls": "Hide zoom controls",
"language": "Language",
"light": "Light",
"listAllOpenWindows": "List all open windows",
"manifestError": "The resource cannot be added:",
......
import React, { Component } from 'react';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import List from '@material-ui/core/List';
import MenuItem from '@material-ui/core/MenuItem';
import Typography from '@material-ui/core/Typography';
import CheckIcon from '@material-ui/icons/CheckSharp';
import PropTypes from 'prop-types';
/**
* LanguageSettings ~ the workspace sub menu to change the language
* of the application
*/
export default class LanguageSettings extends Component {
/**
* Returns the rendered component
*/
render() {
const {
handleClick, languages, active,
} = this.props;
return (
<List>
{
Object.keys(languages).map(language => (
<MenuItem
button={!(active(language))}
key={language}
onClick={() => { handleClick(language); }}
>
{
active(language)
&& <ListItemIcon><CheckIcon /></ListItemIcon>
}
<ListItemText inset>
<Typography variant="inherit">
{languages[language]}
</Typography>
</ListItemText>
</MenuItem>
))
}
</List>
);
}
}
LanguageSettings.propTypes = {
active: PropTypes.func.isRequired,
handleClick: PropTypes.func.isRequired,
languages: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
import React, { Component } from 'react';
import Menu from '@material-ui/core/Menu';
import Divider from '@material-ui/core/Divider';
import LanguageIcon from '@material-ui/icons/Language';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import LoupeIcon from '@material-ui/icons/Loupe';
import MenuItem from '@material-ui/core/MenuItem';
......@@ -9,6 +10,8 @@ import SaveAltIcon from '@material-ui/icons/SaveAlt';
import SettingsIcon from '@material-ui/icons/Settings';
import ViewHeadlineIcon from '@material-ui/icons/ViewHeadline';
import PropTypes from 'prop-types';
import LanguageSettings from '../containers/LanguageSettings';
import NestedMenu from './NestedMenu';
import WindowList from '../containers/WindowList';
import WorkspaceSettings from '../containers/WorkspaceSettings';
import WorkspaceExport from '../containers/WorkspaceExport';
......@@ -92,6 +95,7 @@ class WorkspaceMenu extends Component {
</ListItemIcon>
<Typography varient="inherit">{t('listAllOpenWindows')}</Typography>
</MenuItem>
<Divider />
<MenuItem
aria-haspopup="true"
onClick={(e) => { this.handleZoomToggleClick(e); handleClose(e); }}
......@@ -104,6 +108,11 @@ class WorkspaceMenu extends Component {
{ showZoomControls ? t('hideZoomControls') : t('showZoomControls') }
</Typography>
</MenuItem>
<NestedMenu icon={<LanguageIcon />} label={t('language')}>
<LanguageSettings afterSelect={handleClose} />
</NestedMenu>
<Divider />
<MenuItem
aria-haspopup="true"
......
......@@ -11,6 +11,10 @@ export default {
}
},
language: 'en',
availableLanguages: { // All the languages available in the language switcher
de: 'Deutsch',
en: 'English',
},
translations: {
},
window: {
......
import { connect } from 'react-redux';
import * as actions from '../state/actions';
import LanguageSettings from '../components/LanguageSettings';
/**
* Map state to props for connect
*/
const mapStateToProps = state => ({
languages: state.config.availableLanguages,
currentLanguage: state.config.language,
active: language => language === state.config.language,
});
/**
* Map action dispatches to props for connect
*/
const mapDispatchToProps = (dispatch, { afterSelect }) => ({
handleClick: (language) => {
dispatch(actions.updateConfig({ language }));
afterSelect && afterSelect();
},
});
export default connect(mapStateToProps, mapDispatchToProps)(LanguageSettings);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment