Skip to content
Snippets Groups Projects
Unverified Commit 45ebe271 authored by chrisgarrity's avatar chrisgarrity Committed by GitHub
Browse files

Merge pull request #2326 from chrisgarrity/feature/enable-language-selector

Enable language selection menu
parents a4603bce 788af2d7
No related branches found
No related tags found
No related merge requests found
@import "../../css/colors.css";
@import "../../css/units.css";
.group {
display: inline-flex;
flex-direction: row; /* makes columns, for each label/form group */
align-items: center;
vertical-align: middle;
}
.language-icon {
height: 1.5rem;
}
......@@ -17,7 +10,7 @@
}
.language-select {
width: 100%;
margin: .5rem;
height: 1.85rem;
border: 1px solid $motion-primary;
user-select: none;
......
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
import locales from 'scratch-l10n';
import languageIcon from './language-icon.svg';
import dropdownCaret from './dropdown-caret.svg';
import styles from './language-selector.css';
const LanguageSelector = ({
currentLocale,
onChange,
open,
...props
}) => (
<Box {...props}>
<div className={styles.group}>
{open ? (
<select
disabled
aria-label="language selector"
className={styles.languageSelect}
value={currentLocale}
onChange={onChange}
class LanguageSelector extends React.Component {
render () {
const {
componentRef,
currentLocale,
onChange,
...componentProps
} = this.props;
return (
<Box
{...componentProps}
>
<div
className={styles.group}
ref={componentRef}
>
{Object.keys(locales).map(locale => (
<option
key={locale}
value={locale}
>
{locales[locale].name}
</option>
))}
</select>
) : (
<React.Fragment>
<img
className={classNames(styles.languageIcon, styles.disabled)}
src={languageIcon}
/>
<img
className={classNames(styles.dropdownCaret, styles.disabled)}
src={dropdownCaret}
/>
</React.Fragment>
)}
</div>
</Box>
);
<select
className={styles.languageSelect}
value={currentLocale}
onChange={onChange}
>
{Object.keys(locales).map(locale => (
<option
key={locale}
value={locale}
>
{locales[locale].name}
</option>
))}
</select>
</div>
</Box>
);
}
}
LanguageSelector.propTypes = {
componentRef: PropTypes.func,
currentLocale: PropTypes.string,
onChange: PropTypes.func,
open: PropTypes.bool
......
......@@ -44,6 +44,14 @@
vertical-align: middle;
}
.language-icon {
height: 1.5rem;
}
.language-menu {
display: inline-flex;
}
.menu {
z-index: $z-index-menu-bar;
top: $menu-bar-height;
......
import classNames from 'classnames';
import {connect} from 'react-redux';
import {FormattedMessage} from 'react-intl';
import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
import PropTypes from 'prop-types';
import React from 'react';
......@@ -22,7 +22,10 @@ import {
fileMenuOpen,
openEditMenu,
closeEditMenu,
editMenuOpen
editMenuOpen,
openLanguageMenu,
closeLanguageMenu,
languageMenuOpen
} from '../../reducers/menus';
import styles from './menu-bar.css';
......@@ -32,29 +35,56 @@ import feedbackIcon from './icon--feedback.svg';
import profileIcon from './icon--profile.png';
import communityIcon from './icon--see-community.svg';
import dropdownCaret from '../language-selector/dropdown-caret.svg';
import languageIcon from '../language-selector/language-icon.svg';
import scratchLogo from './scratch-logo.svg';
import helpIcon from './icon--help.svg';
const ariaMessages = defineMessages({
language: {
id: 'gui.menuBar.LanguageSelector',
defaultMessage: 'language selector',
description: 'accessibility text for the language selection menu'
},
howTo: {
id: 'gui.menuBar.howToLibrary',
defaultMessage: 'How-to Library',
description: 'accessibility text for the how-to library button'
}
});
const MenuBarItemTooltip = ({
children,
className,
enable,
id,
place = 'bottom'
}) => (
<ComingSoonTooltip
className={classNames(styles.comingSoon, className)}
place={place}
tooltipClassName={styles.comingSoonTooltip}
tooltipId={id}
>
{children}
</ComingSoonTooltip>
);
}) => {
if (enable) {
return (
<React.Fragment>
{children}
</React.Fragment>
);
}
return (
<ComingSoonTooltip
className={classNames(styles.comingSoon, className)}
place={place}
tooltipClassName={styles.comingSoonTooltip}
tooltipId={id}
>
{children}
</ComingSoonTooltip>
);
};
MenuBarItemTooltip.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
enable: PropTypes.bool,
id: PropTypes.string,
place: PropTypes.oneOf(['top', 'bottom', 'left', 'right'])
};
......@@ -111,12 +141,37 @@ const MenuBar = props => (
src={scratchLogo}
/>
</div>
<div className={classNames(styles.menuBarItem, styles.hoverable)}>
<div
className={classNames(styles.menuBarItem, styles.hoverable, {
[styles.active]: props.languageMenuOpen
})}
onMouseUp={props.onClickLanguage}
>
<MenuBarItemTooltip
enable={window.location.search.indexOf('enable=language') !== -1}
id="menubar-selector"
place="right"
>
<LanguageSelector />
<div
aria-label={props.intl.formatMessage(ariaMessages.language)}
className={classNames(styles.languageMenu)}
>
<img
className={styles.languageIcon}
src={languageIcon}
/>
<img
className={styles.dropdownCaret}
src={dropdownCaret}
/>
</div>
<MenuBarMenu
open={props.languageMenuOpen}
onRequestClose={props.onRequestCloseLanguage}
>
<LanguageSelector />
</MenuBarMenu>
</MenuBarItemTooltip>
</div>
<div
......@@ -314,7 +369,7 @@ const MenuBar = props => (
</div>
<div className={styles.accountInfoWrapper}>
<div
aria-label="How-to Library"
aria-label={props.intl.formatMessage(ariaMessages.howTo)}
className={classNames(styles.menuBarItem, styles.hoverable)}
onClick={props.onOpenTipLibrary}
>
......@@ -369,17 +424,22 @@ MenuBar.propTypes = {
editMenuOpen: PropTypes.bool,
enableCommunity: PropTypes.bool,
fileMenuOpen: PropTypes.bool,
intl: intlShape,
languageMenuOpen: PropTypes.bool,
onClickEdit: PropTypes.func,
onClickFile: PropTypes.func,
onClickLanguage: PropTypes.func,
onOpenTipLibrary: PropTypes.func,
onRequestCloseEdit: PropTypes.func,
onRequestCloseFile: PropTypes.func,
onRequestCloseLanguage: PropTypes.func,
onSeeCommunity: PropTypes.func
};
const mapStateToProps = state => ({
fileMenuOpen: fileMenuOpen(state),
editMenuOpen: editMenuOpen(state)
editMenuOpen: editMenuOpen(state),
languageMenuOpen: languageMenuOpen(state)
});
const mapDispatchToProps = dispatch => ({
......@@ -388,10 +448,12 @@ const mapDispatchToProps = dispatch => ({
onRequestCloseFile: () => dispatch(closeFileMenu()),
onClickEdit: () => dispatch(openEditMenu()),
onRequestCloseEdit: () => dispatch(closeEditMenu()),
onClickLanguage: () => dispatch(openLanguageMenu()),
onRequestCloseLanguage: () => dispatch(closeLanguageMenu()),
onSeeCommunity: () => dispatch(setPlayer(true))
});
export default connect(
export default injectIntl(connect(
mapStateToProps,
mapDispatchToProps
)(MenuBar);
)(MenuBar));
import bindAll from 'lodash.bindall';
import PropTypes from 'prop-types';
import React from 'react';
import {connect} from 'react-redux';
import {updateIntl} from 'react-intl-redux';
import {closeLanguageMenu} from '../reducers/menus';
import LanguageSelectorComponent from '../components/language-selector/language-selector.jsx';
class LanguageSelector extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
'handleChange'
]);
}
handleChange (e) {
this.props.onChangeLanguage(e.target.value);
}
render () {
const {
onChangeLanguage, // eslint-disable-line no-unused-vars
children,
...props
} = this.props;
return (
<LanguageSelectorComponent
onChange={this.handleChange}
{...props}
>
{children}
</LanguageSelectorComponent>
);
}
}
LanguageSelector.propTypes = {
children: PropTypes.node,
onChangeLanguage: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
currentLocale: state.intl.locale
});
const mapDispatchToProps = () => ({
onChange: e => {
e.preventDefault();
const mapDispatchToProps = dispatch => ({
onChangeLanguage: locale => {
dispatch(updateIntl({locale: locale, messages: {}}));
dispatch(closeLanguageMenu());
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(LanguageSelectorComponent);
)(LanguageSelector);
......@@ -3,11 +3,13 @@ const CLOSE_MENU = 'scratch-gui/menus/CLOSE_MENU';
const MENU_FILE = 'fileMenu';
const MENU_EDIT = 'editMenu';
const MENU_LANGUAGE = 'languageMenu';
const initialState = {
[MENU_FILE]: false,
[MENU_EDIT]: false
[MENU_EDIT]: false,
[MENU_LANGUAGE]: false
};
const reducer = function (state, action) {
......@@ -39,6 +41,9 @@ const fileMenuOpen = state => state.scratchGui.menus[MENU_FILE];
const openEditMenu = () => openMenu(MENU_EDIT);
const closeEditMenu = () => closeMenu(MENU_EDIT);
const editMenuOpen = state => state.scratchGui.menus[MENU_EDIT];
const openLanguageMenu = () => openMenu(MENU_LANGUAGE);
const closeLanguageMenu = () => closeMenu(MENU_LANGUAGE);
const languageMenuOpen = state => state.scratchGui.menus[MENU_LANGUAGE];
export {
reducer as default,
......@@ -47,6 +52,9 @@ export {
closeFileMenu,
openEditMenu,
closeEditMenu,
openLanguageMenu,
closeLanguageMenu,
fileMenuOpen,
editMenuOpen
editMenuOpen,
languageMenuOpen
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment