Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/containers/gui.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {compose} from 'redux';
import {connect} from 'react-redux';
import ReactModal from 'react-modal';
import VM from 'scratch-vm';
import {injectIntl, intlShape} from 'react-intl';
import {defineMessages, injectIntl, intlShape} from 'react-intl';

import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
import {openExtensionLibrary} from '../reducers/modals';
Expand All @@ -25,14 +25,22 @@ import {
} from '../reducers/modals';

import FontLoaderHOC from '../lib/font-loader-hoc.jsx';
import LocalizationHOC from '../lib/localization-hoc.jsx';
import ProjectFetcherHOC from '../lib/project-fetcher-hoc.jsx';
import ProjectSaverHOC from '../lib/project-saver-hoc.jsx';
import vmListenerHOC from '../lib/vm-listener-hoc.jsx';
import vmManagerHOC from '../lib/vm-manager-hoc.jsx';
import {defaultProjectTitleMessages} from '../reducers/project-title';

import GUIComponent from '../components/gui/gui.jsx';

const messages = defineMessages({

This comment was marked as abuse.

defaultProjectTitle: {
id: 'gui.gui.defaultProjectTitle',
description: 'Default title for project',
defaultMessage: 'Scratch Project'
}
});

class GUI extends React.Component {
componentDidMount () {
this.setReduxTitle(this.props.projectTitle);
Expand All @@ -48,7 +56,7 @@ class GUI extends React.Component {
setReduxTitle (newTitle) {
if (newTitle === null || typeof newTitle === 'undefined') {
this.props.onUpdateReduxProjectTitle(
this.props.intl.formatMessage(defaultProjectTitleMessages.defaultProjectTitle)
this.props.intl.formatMessage(messages.defaultProjectTitle)
);
} else {
this.props.onUpdateReduxProjectTitle(newTitle);
Expand Down Expand Up @@ -163,6 +171,7 @@ const ConnectedGUI = injectIntl(connect(
// the hierarchy of HOC constructor calls clearer here; it has nothing to do with redux's
// ability to compose reducers.
const WrappedGui = compose(
LocalizationHOC,
ErrorBoundaryHOC('Top Level App'),
FontLoaderHOC,
ProjectFetcherHOC,
Expand Down
5 changes: 1 addition & 4 deletions src/lib/app-state-hoc.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import {Provider} from 'react-redux';
import {createStore, combineReducers, compose} from 'redux';
import ConnectedIntlProvider from './connected-intl-provider.jsx';

import localesReducer, {initLocale, localesInitialState} from '../reducers/locales';

Expand Down Expand Up @@ -108,9 +107,7 @@ const AppStateHOC = function (WrappedComponent, localesOnly) {
} = this.props;
return (
<Provider store={this.store}>
<ConnectedIntlProvider>
<WrappedComponent {...componentProps} />
</ConnectedIntlProvider>
<WrappedComponent {...componentProps} />
</Provider>
);
}
Expand Down
55 changes: 55 additions & 0 deletions src/lib/localization-hoc.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';

import ConnectedIntlProvider from './connected-intl-provider.jsx';

/*
* Higher Order Component to provide localiztion state. Creates a nested IntlProvider
* to handle Gui intl context. The component accepts an onSetLanguage callback that is
* called when the locale chagnes.
* @param {React.Component} WrappedComponent - component to provide state for
* @returns {React.Component} component with intl state provided from redux
*/
const LocalizationHOC = function (WrappedComponent) {
class LocalizationWrapper extends React.Component {
componentDidUpdate (prevProps) {

This comment was marked as abuse.

This comment was marked as abuse.

if (prevProps.locale !== this.props.locale) {
this.props.onSetLanguage(this.props.locale);
}
}
render () {
const {
locale, // eslint-disable-line no-unused-vars
onSetLanguage, // eslint-disable-line no-unused-vars
...componentProps
} = this.props;
return (
<ConnectedIntlProvider>
<WrappedComponent {...componentProps} />
</ConnectedIntlProvider>
);
}
}
LocalizationWrapper.propTypes = {
locale: PropTypes.string,
onSetLanguage: PropTypes.func
};

LocalizationWrapper.defaultProps = {
onSetLanguage: () => {}
};

const mapStateToProps = state => ({
locale: state.locales.locale
});

const mapDispatchToProps = () => ({});

return connect(
mapStateToProps,
mapDispatchToProps
)(LocalizationWrapper);
};

export default LocalizationHOC;
18 changes: 3 additions & 15 deletions src/lib/titled-hoc.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React from 'react';
import bindAll from 'lodash.bindall';
import {intlShape, injectIntl} from 'react-intl';
import {defaultProjectTitleMessages} from '../reducers/project-title';

/* Higher Order Component to get and set the project title
* @param {React.Component} WrappedComponent component to receive project title related props
Expand All @@ -15,34 +13,24 @@ const TitledHOC = function (WrappedComponent) {
'handleUpdateProjectTitle'
]);
this.state = {
projectTitle: this.props.intl.formatMessage(defaultProjectTitleMessages.defaultProjectTitle)
projectTitle: null
};
}
handleUpdateProjectTitle (newTitle) {
this.setState({projectTitle: newTitle});
}
render () {
const {
/* eslint-disable no-unused-vars */
intl,
/* eslint-enable no-unused-vars */
...componentProps
} = this.props;
return (
<WrappedComponent
projectTitle={this.state.projectTitle}
onUpdateProjectTitle={this.handleUpdateProjectTitle}
{...componentProps}
{...this.props}
/>
);
}
}

TitledComponent.propTypes = {
intl: intlShape.isRequired
};

return injectIntl(TitledComponent);
return TitledComponent;
};

export {
Expand Down
11 changes: 0 additions & 11 deletions src/reducers/project-title.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import {defineMessages} from 'react-intl';

const SET_PROJECT_TITLE = 'projectTitle/SET_PROJECT_TITLE';

// we are initializing to a blank string instead of an actual title,
// because it would be hard to localize here
const initialState = '';

const defaultProjectTitleMessages = defineMessages({
defaultProjectTitle: {
id: 'gui.gui.defaultProjectTitle',
description: 'Default title for project',
defaultMessage: 'Scratch Project'
}
});

const reducer = function (state, action) {
if (typeof state === 'undefined') state = initialState;
switch (action.type) {
Expand All @@ -31,6 +21,5 @@ const setProjectTitle = title => ({
export {
reducer as default,
initialState as projectTitleInitialState,
defaultProjectTitleMessages,
setProjectTitle
};