From 5af98ca7658e9275f06bd5800e27ba7f272dd00e Mon Sep 17 00:00:00 2001 From: ov Date: Sat, 22 Aug 2020 11:50:49 +0100 Subject: [PATCH] Spanish Translation: My Collection/My Sketch lists in My Account Menu (#1554) * Translations for Collection functionality * Translation for Sketch functionality * Translation ARIA for Sketch functionality --- client/modules/App/components/Overlay.jsx | 6 +- .../IDE/components/AddToCollectionList.jsx | 13 +- .../components/AddToCollectionSketchList.jsx | 10 +- .../CollectionList/CollectionList.jsx | 32 ++--- .../CollectionList/CollectionListRow.jsx | 14 ++- .../components/QuickAddList/QuickAddList.jsx | 12 +- client/modules/IDE/components/SketchList.jsx | 50 ++++---- client/modules/User/components/Collection.jsx | 61 ++++----- .../User/components/CollectionCreate.jsx | 24 ++-- .../User/components/DashboardTabSwitcher.jsx | 16 ++- client/modules/User/pages/CollectionView.jsx | 9 +- client/modules/User/pages/DashboardView.jsx | 18 +-- translations/locales/en-US/translations.json | 111 +++++++++++++++++ translations/locales/es-419/translations.json | 117 +++++++++++++++++- 14 files changed, 376 insertions(+), 117 deletions(-) diff --git a/client/modules/App/components/Overlay.jsx b/client/modules/App/components/Overlay.jsx index 4e54b615..3ebeca45 100644 --- a/client/modules/App/components/Overlay.jsx +++ b/client/modules/App/components/Overlay.jsx @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { browserHistory } from 'react-router'; +import { withTranslation } from 'react-i18next'; import ExitIcon from '../../../images/exit.svg'; @@ -80,7 +81,7 @@ class Overlay extends React.Component {

{title}

{actions} -
@@ -101,6 +102,7 @@ Overlay.propTypes = { ariaLabel: PropTypes.string, previousPath: PropTypes.string, isFixedHeight: PropTypes.bool, + t: PropTypes.func.isRequired }; Overlay.defaultProps = { @@ -113,4 +115,4 @@ Overlay.defaultProps = { isFixedHeight: false, }; -export default Overlay; +export default withTranslation()(Overlay); diff --git a/client/modules/IDE/components/AddToCollectionList.jsx b/client/modules/IDE/components/AddToCollectionList.jsx index e003a896..f4369124 100644 --- a/client/modules/IDE/components/AddToCollectionList.jsx +++ b/client/modules/IDE/components/AddToCollectionList.jsx @@ -3,6 +3,7 @@ import React from 'react'; import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import { withTranslation } from 'react-i18next'; import * as ProjectActions from '../actions/project'; import * as ProjectsActions from '../actions/projects'; @@ -42,9 +43,9 @@ class CollectionList extends React.Component { getTitle() { if (this.props.username === this.props.user.username) { - return 'p5.js Web Editor | My collections'; + return this.props.t('AddToCollectionList.Title'); } - return `p5.js Web Editor | ${this.props.username}'s collections`; + return this.props.t('AddToCollectionList.AnothersTitle', { anotheruser: this.props.username }); } handleCollectionAdd = (collection) => { @@ -74,10 +75,11 @@ class CollectionList extends React.Component { items={collectionWithSketchStatus} onAdd={this.handleCollectionAdd} onRemove={this.handleCollectionRemove} + t={this.props.t} /> ); } else { - content = 'No collections'; + content = this.props.t('AddToCollectionList.Empty'); } return ( @@ -135,7 +137,8 @@ CollectionList.propTypes = { owner: PropTypes.shape({ id: PropTypes.string }) - }) + }), + t: PropTypes.func.isRequired }; CollectionList.defaultProps = { @@ -164,4 +167,4 @@ function mapDispatchToProps(dispatch) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(CollectionList); +export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(CollectionList)); diff --git a/client/modules/IDE/components/AddToCollectionSketchList.jsx b/client/modules/IDE/components/AddToCollectionSketchList.jsx index 6abb9aad..339ead18 100644 --- a/client/modules/IDE/components/AddToCollectionSketchList.jsx +++ b/client/modules/IDE/components/AddToCollectionSketchList.jsx @@ -3,6 +3,7 @@ import React from 'react'; import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import { withTranslation } from 'react-i18next'; // import find from 'lodash/find'; import * as ProjectsActions from '../actions/projects'; import * as CollectionsActions from '../actions/collections'; @@ -32,9 +33,9 @@ class SketchList extends React.Component { getSketchesTitle() { if (this.props.username === this.props.user.username) { - return 'p5.js Web Editor | My sketches'; + return this.props.t('AddToCollectionSketchList.Title'); } - return `p5.js Web Editor | ${this.props.username}'s sketches`; + return this.props.t('AddToCollectionSketchList.AnothersTitle', { anotheruser: this.props.username }); } handleCollectionAdd = (sketch) => { @@ -68,7 +69,7 @@ class SketchList extends React.Component { /> ); } else { - content = 'No collections'; + content = this.props.t('AddToCollectionSketchList.NoCollections'); } return ( @@ -113,6 +114,7 @@ SketchList.propTypes = { }).isRequired, addToCollection: PropTypes.func.isRequired, removeFromCollection: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; SketchList.defaultProps = { @@ -136,4 +138,4 @@ function mapDispatchToProps(dispatch) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(SketchList); +export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(SketchList)); diff --git a/client/modules/IDE/components/CollectionList/CollectionList.jsx b/client/modules/IDE/components/CollectionList/CollectionList.jsx index 3d4e1aa6..2f556d36 100644 --- a/client/modules/IDE/components/CollectionList/CollectionList.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionList.jsx @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Helmet } from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import classNames from 'classnames'; @@ -50,9 +51,9 @@ class CollectionList extends React.Component { getTitle() { if (this.props.username === this.props.user.username) { - return 'p5.js Web Editor | My collections'; + return this.props.t('CollectionList.Title'); } - return `p5.js Web Editor | ${this.props.username}'s collections`; + return this.props.t('CollectionList.AnothersTitle', { anotheruser: this.props.username }); } showAddSketches = (collectionId) => { @@ -78,7 +79,7 @@ class CollectionList extends React.Component { _renderEmptyTable() { if (!this.props.loading && this.props.collections.length === 0) { - return (

No collections.

); + return (

{this.props.t('CollectionList.NoCollections')}

); } return null; } @@ -88,14 +89,14 @@ class CollectionList extends React.Component { let buttonLabel; if (field !== fieldName) { if (field === 'name') { - buttonLabel = `Sort by ${displayName} ascending.`; + buttonLabel = this.props.t('CollectionList.ButtonLabelAscendingARIA', { displayName }); } else { - buttonLabel = `Sort by ${displayName} descending.`; + buttonLabel = this.props.t('CollectionList.ButtonLabelDescendingARIA', { displayName }); } } else if (direction === SortingActions.DIRECTION.ASC) { - buttonLabel = `Sort by ${displayName} descending.`; + buttonLabel = this.props.t('CollectionList.ButtonLabelDescendingARIA', { displayName }); } else { - buttonLabel = `Sort by ${displayName} ascending.`; + buttonLabel = this.props.t('CollectionList.ButtonLabelAscendingARIA', { displayName }); } return buttonLabel; } @@ -116,10 +117,10 @@ class CollectionList extends React.Component { > {displayName} {field === fieldName && direction === SortingActions.DIRECTION.ASC && - + } {field === fieldName && direction === SortingActions.DIRECTION.DESC && - + } @@ -142,10 +143,10 @@ class CollectionList extends React.Component { - {this._renderFieldHeader('name', 'Name')} - {this._renderFieldHeader('createdAt', `${mobile ? '' : 'Date '}Created`)} - {this._renderFieldHeader('updatedAt', `${mobile ? '' : 'Date '}Updated`)} - {this._renderFieldHeader('numItems', mobile ? 'Sketches' : '# sketches')} + {this._renderFieldHeader('name', this.props.t('CollectionList.HeaderName'))} + {this._renderFieldHeader('createdAt', this.props.t('CollectionList.HeaderCreatedAt', { context: mobile ? 'mobile' : '' }))} + {this._renderFieldHeader('updatedAt', this.props.t('CollectionList.HeaderUpdatedAt', { context: mobile ? 'mobile' : '' }))} + {this._renderFieldHeader('numItems', this.props.t('CollectionList.HeaderNumItems', { context: mobile ? 'mobile' : '' }))} @@ -165,7 +166,7 @@ class CollectionList extends React.Component { { this.state.addingSketchesToCollectionId && ( } closeOverlay={this.hideAddSketches} isFixedHeight @@ -211,6 +212,7 @@ CollectionList.propTypes = { id: PropTypes.string }) }), + t: PropTypes.func.isRequired, mobile: PropTypes.bool, }; @@ -242,4 +244,4 @@ function mapDispatchToProps(dispatch) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(CollectionList); +export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(CollectionList)); diff --git a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx index de20cea9..4775639c 100644 --- a/client/modules/IDE/components/CollectionList/CollectionListRow.jsx +++ b/client/modules/IDE/components/CollectionList/CollectionListRow.jsx @@ -4,6 +4,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { bindActionCreators } from 'redux'; +import { withTranslation } from 'react-i18next'; import * as ProjectActions from '../../actions/project'; import * as CollectionsActions from '../../actions/collections'; import * as IdeActions from '../../actions/ide'; @@ -81,7 +82,7 @@ class CollectionListRowBase extends React.Component { handleCollectionDelete = () => { this.closeAll(); - if (window.confirm(`Are you sure you want to delete "${this.props.collection.name}"?`)) { + if (window.confirm(this.props.t('Common.DeleteConfirmation', { name: this.props.collection.name }))) { this.props.deleteCollection(this.props.collection.id); } } @@ -130,7 +131,7 @@ class CollectionListRowBase extends React.Component { onClick={this.toggleOptions} onBlur={this.onBlurComponent} onFocus={this.onFocusComponent} - aria-label="Toggle Open/Close collection options" + aria-label={this.props.t('CollectionListRow.ToggleCollectionOptionsARIA')} > @@ -145,7 +146,7 @@ class CollectionListRowBase extends React.Component { onBlur={this.onBlurComponent} onFocus={this.onFocusComponent} > - Add sketch + {this.props.t('CollectionListRow.AddSketch')} {userIsOwner && @@ -156,7 +157,7 @@ class CollectionListRowBase extends React.Component { onBlur={this.onBlurComponent} onFocus={this.onFocusComponent} > - Delete + {this.props.t('CollectionListRow.Delete')} } {userIsOwner && @@ -167,7 +168,7 @@ class CollectionListRowBase extends React.Component { onBlur={this.onBlurComponent} onFocus={this.onFocusComponent} > - Rename + {this.props.t('CollectionListRow.Rename')} } @@ -248,6 +249,7 @@ CollectionListRowBase.propTypes = { editCollection: PropTypes.func.isRequired, onAddSketches: PropTypes.func.isRequired, mobile: PropTypes.bool, + t: PropTypes.func.isRequired }; CollectionListRowBase.defaultProps = { @@ -258,4 +260,4 @@ function mapDispatchToPropsSketchListRow(dispatch) { return bindActionCreators(Object.assign({}, CollectionsActions, ProjectActions, IdeActions, ToastActions), dispatch); } -export default connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase); +export default withTranslation()(connect(null, mapDispatchToPropsSketchListRow)(CollectionListRowBase)); diff --git a/client/modules/IDE/components/QuickAddList/QuickAddList.jsx b/client/modules/IDE/components/QuickAddList/QuickAddList.jsx index be7a5ac3..32264230 100644 --- a/client/modules/IDE/components/QuickAddList/QuickAddList.jsx +++ b/client/modules/IDE/components/QuickAddList/QuickAddList.jsx @@ -1,11 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router'; +import { withTranslation } from 'react-i18next'; import Icons from './Icons'; const Item = ({ - isAdded, onSelect, name, url + isAdded, onSelect, name, url, t }) => { const buttonLabel = isAdded ? 'Remove from collection' : 'Add to collection'; return ( @@ -20,7 +21,7 @@ const Item = ({ target="_blank" onClick={e => e.stopPropogation()} > - View + {t('QuickAddList.View')} ); @@ -37,10 +38,11 @@ Item.propTypes = { url: PropTypes.string.isRequired, isAdded: PropTypes.bool.isRequired, onSelect: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; const QuickAddList = ({ - items, onAdd, onRemove + items, onAdd, onRemove, t }) => { const handleAction = (item) => { if (item.isAdded) { @@ -53,6 +55,7 @@ const QuickAddList = ({ return (
    {items.map(item => ( { @@ -70,6 +73,7 @@ QuickAddList.propTypes = { items: PropTypes.arrayOf(ItemType).isRequired, onAdd: PropTypes.func.isRequired, onRemove: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; -export default QuickAddList; +export default withTranslation()(QuickAddList); diff --git a/client/modules/IDE/components/SketchList.jsx b/client/modules/IDE/components/SketchList.jsx index d5f9d71d..93b5d004 100644 --- a/client/modules/IDE/components/SketchList.jsx +++ b/client/modules/IDE/components/SketchList.jsx @@ -2,6 +2,7 @@ import format from 'date-fns/format'; import PropTypes from 'prop-types'; import React from 'react'; import { Helmet } from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { Link } from 'react-router'; import { bindActionCreators } from 'redux'; @@ -148,14 +149,14 @@ class SketchListRowBase extends React.Component { handleSketchDelete = () => { this.closeAll(); - if (window.confirm(`Are you sure you want to delete "${this.props.sketch.name}"?`)) { + if (window.confirm(this.props.t('Common.DeleteConfirmation', { name: this.props.sketch.name }))) { this.props.deleteProject(this.props.sketch.id); } } renderViewButton = sketchURL => (
) @@ -170,7 +171,7 @@ class SketchListRowBase extends React.Component { onClick={this.toggleOptions} onBlur={this.onBlurComponent} onFocus={this.onFocusComponent} - aria-label="Toggle Open/Close Sketch Options" + aria-label={this.props.t('SketchList.ToggleLabelARIA')} >
- View + {this.props.t('SketchList.View')}
- {this._renderFieldHeader('name', 'Sketch')} - {this._renderFieldHeader('createdAt', `${mobile ? '' : 'Date '}Created`)} - {this._renderFieldHeader('updatedAt', `${mobile ? '' : 'Date '}Updated`)} + {this._renderFieldHeader('name', this.props.t('SketchList.HeaderName'))} + {this._renderFieldHeader('createdAt', this.props.t('SketchList.HeaderCreatedAt', { context: mobile ? 'mobile' : '' }))} + {this._renderFieldHeader('updatedAt', this.props.t('SketchList.HeaderUpdatedAt', { context: mobile ? 'mobile' : '' }))} @@ -453,6 +455,7 @@ class SketchList extends React.Component { onAddToCollection={() => { this.setState({ sketchToAddToCollection: sketch }); }} + t={this.props.t} />))}
} @@ -460,7 +463,7 @@ class SketchList extends React.Component { this.state.sketchToAddToCollection && this.setState({ sketchToAddToCollection: null })} > { +const ShareURL = ({ value, t }) => { const [showURL, setShowURL] = useState(false); const node = useRef(); @@ -56,11 +57,11 @@ const ShareURL = ({ value }) => { onClick={() => setShowURL(!showURL)} iconAfter={} > - Share + {t('Collection.Share')} { showURL &&
- +
} @@ -69,22 +70,23 @@ const ShareURL = ({ value }) => { ShareURL.propTypes = { value: PropTypes.string.isRequired, + t: PropTypes.func.isRequired }; const CollectionItemRowBase = ({ - collection, item, isOwner, removeFromCollection + collection, item, isOwner, removeFromCollection, t }) => { const projectIsDeleted = item.isDeleted; const handleSketchRemove = () => { const name = projectIsDeleted ? 'deleted sketch' : item.project.name; - if (window.confirm(`Are you sure you want to remove "${name}" from this collection?`)) { + if (window.confirm(t('Collection.DeleteFromCollection', { name_sketch: name }))) { removeFromCollection(collection.id, item.projectId); } }; - const name = projectIsDeleted ? Sketch was deleted : ( + const name = projectIsDeleted ? {t('Collection.SketchDeleted')} : ( {item.project.name} @@ -106,7 +108,7 @@ const CollectionItemRowBase = ({ @@ -138,7 +140,8 @@ CollectionItemRowBase.propTypes = { username: PropTypes.string, authenticated: PropTypes.bool.isRequired }).isRequired, - removeFromCollection: PropTypes.func.isRequired + removeFromCollection: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; function mapDispatchToPropsSketchListRow(dispatch) { @@ -163,9 +166,9 @@ class Collection extends React.Component { getTitle() { if (this.props.username === this.props.user.username) { - return 'p5.js Web Editor | My collections'; + return this.props.t('Collection.Title'); } - return `p5.js Web Editor | ${this.props.username}'s collections`; + return this.props.t('Collection.AnothersTitle', { anotheruser: this.props.username }); } getUsername() { @@ -257,27 +260,27 @@ class Collection extends React.Component { InputComponent="textarea" value={description} onChange={handleEditCollectionDescription} - emptyPlaceholder="Add description" + emptyPlaceholder={this.props.t('Collection.DescriptionPlaceholder')} /> : description }

-

Collection by{' '} +

{this.props.t('Collection.By')} {owner.username}

-

{items.length} sketch{items.length === 1 ? '' : 'es'}

+

{this.props.t('Collection.NumSketches', { count: items.length }) }

- +

{ this.isOwner() && }
@@ -304,7 +307,7 @@ class Collection extends React.Component { this.props.collection.items.length > 0; if (!isLoading && !hasCollectionItems) { - return (

No sketches in collection

); + return (

{this.props.t('Collection.NoSketches')}

); } return null; } @@ -314,14 +317,14 @@ class Collection extends React.Component { let buttonLabel; if (field !== fieldName) { if (field === 'name') { - buttonLabel = `Sort by ${displayName} ascending.`; + buttonLabel = this.props.t('Collection.ButtonLabelAscendingARIA', { displayName }); } else { - buttonLabel = `Sort by ${displayName} descending.`; + buttonLabel = this.props.t('Collection.ButtonLabelDescendingARIA', { displayName }); } } else if (direction === SortingActions.DIRECTION.ASC) { - buttonLabel = `Sort by ${displayName} descending.`; + buttonLabel = this.props.t('Collection.ButtonLabelDescendingARIA', { displayName }); } else { - buttonLabel = `Sort by ${displayName} ascending.`; + buttonLabel = this.props.t('Collection.ButtonLabelAscendingARIA', { displayName }); } return buttonLabel; } @@ -342,10 +345,10 @@ class Collection extends React.Component { > {displayName} {field === fieldName && direction === SortingActions.DIRECTION.ASC && - + } {field === fieldName && direction === SortingActions.DIRECTION.DESC && - + } @@ -371,9 +374,9 @@ class Collection extends React.Component { - {this._renderFieldHeader('name', 'Name')} - {this._renderFieldHeader('createdAt', 'Date Added')} - {this._renderFieldHeader('user', 'Owner')} + {this._renderFieldHeader('name', this.props.t('Collection.HeaderName'))} + {this._renderFieldHeader('createdAt', this.props.t('Collection.HeaderCreatedAt'))} + {this._renderFieldHeader('user', this.props.t('Collection.HeaderUser'))} @@ -386,6 +389,7 @@ class Collection extends React.Component { username={this.getUsername()} collection={this.props.collection} isOwner={isOwner} + t={this.props.t} />))}
@@ -393,7 +397,7 @@ class Collection extends React.Component { { this.state.isAddingSketches && ( } closeOverlay={this.hideAddSketches} isFixedHeight @@ -437,7 +441,8 @@ Collection.propTypes = { sorting: PropTypes.shape({ field: PropTypes.string.isRequired, direction: PropTypes.string.isRequired - }).isRequired + }).isRequired, + t: PropTypes.func.isRequired }; Collection.defaultProps = { @@ -468,4 +473,4 @@ function mapDispatchToProps(dispatch) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(Collection); +export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(Collection)); diff --git a/client/modules/User/components/CollectionCreate.jsx b/client/modules/User/components/CollectionCreate.jsx index cf679ccc..9a7b6315 100644 --- a/client/modules/User/components/CollectionCreate.jsx +++ b/client/modules/User/components/CollectionCreate.jsx @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Helmet } from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import * as CollectionsActions from '../../IDE/actions/collections'; @@ -24,7 +25,7 @@ class CollectionCreate extends React.Component { } getTitle() { - return 'p5.js Web Editor | Create collection'; + return this.props.t('CollectionCreate.Title'); } handleTextChange = field => (evt) => { @@ -55,34 +56,34 @@ class CollectionCreate extends React.Component {
- {creationError && Couldn't create collection} + {creationError && {this.props.t('CollectionCreate.FormError')}}

- + - {invalid && Collection name is required} + {invalid && {this.props.t('CollectionCreate.NameRequired')}}

- +