Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
9 changes: 6 additions & 3 deletions client/components/AddRemoveButton.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';


import AddIcon from '../images/plus.svg';
import RemoveIcon from '../images/minus.svg';

const AddRemoveButton = ({ type, onClick }) => {
const alt = type === 'add' ? 'Add to collection' : 'Remove from collection';
const AddRemoveButton = ({ type, onClick, t }) => {
const alt = type === 'add' ? t('AddRemoveButton.AltAddARIA') : t('AddRemoveButton.AltRemoveARIA');
const Icon = type === 'add' ? AddIcon : RemoveIcon;

return (
Expand All @@ -22,6 +24,7 @@ const AddRemoveButton = ({ type, onClick }) => {
AddRemoveButton.propTypes = {
type: PropTypes.oneOf(['add', 'remove']).isRequired,
onClick: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
};

export default AddRemoveButton;
export default withTranslation()(AddRemoveButton);
12 changes: 7 additions & 5 deletions client/components/PreviewNav.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Link } from 'react-router';
import { withTranslation } from 'react-i18next';

import LogoIcon from '../images/p5js-logo-small.svg';
import CodeIcon from '../images/code.svg';

const PreviewNav = ({ owner, project }) => (
const PreviewNav = ({ owner, project, t }) => (
<nav className="nav preview-nav">
<div className="nav__items-left">
<div className="nav__item-logo">
<LogoIcon role="img" aria-label="p5.js Logo" focusable="false" className="svg__logo" />
<LogoIcon role="img" aria-label={t('Common.p5logoARIA')} focusable="false" className="svg__logo" />
</div>
<Link className="nav__item" to={`/${owner.username}/sketches/${project.id}`}>{project.name}</Link>
<p className="toolbar__project-owner">by</p>
<p className="toolbar__project-owner">{t('PreviewNav.ByUser')}</p>
<Link className="nav__item" to={`/${owner.username}/sketches/`}>{owner.username}</Link>
</div>
<div className="nav__items-right">
<Link to={`/${owner.username}/sketches/${project.id}`} aria-label="Edit Sketch" >
<Link to={`/${owner.username}/sketches/${project.id}`} aria-label={t('PreviewNav.EditSketchARIA')} >
<CodeIcon className="preview-nav__editor-svg" focusable="false" aria-hidden="true" />
</Link>
</div>
Expand All @@ -31,6 +32,7 @@ PreviewNav.propTypes = {
name: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
}).isRequired,
t: PropTypes.func.isRequired
};

export default PreviewNav;
export default withTranslation()(PreviewNav);
27 changes: 15 additions & 12 deletions client/modules/IDE/components/AssetList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { bindActionCreators } from 'redux';
import { Link } from 'react-router';
import { Helmet } from 'react-helmet';
import prettyBytes from 'pretty-bytes';
import { withTranslation } from 'react-i18next';

import Loader from '../../App/components/loader';
import * as AssetActions from '../actions/assets';
Expand Down Expand Up @@ -85,7 +86,7 @@ class AssetListRowBase extends React.Component {
onClick={this.toggleOptions}
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
aria-label="Toggle Open/Close Asset Options"
aria-label={this.props.t('AssetList.ToggleOpenCloseARIA')}
>
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
</button>
Expand All @@ -100,7 +101,7 @@ class AssetListRowBase extends React.Component {
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
Delete
{this.props.t('AssetList.Delete')}
</button>
</li>
<li>
Expand All @@ -111,7 +112,7 @@ class AssetListRowBase extends React.Component {
onFocus={this.onFocusComponent}
className="asset-table__action-option"
>
Open in New Tab
{this.props.t('AssetList.OpenNewTab')}
</Link>
</li>
</ul>}
Expand All @@ -131,7 +132,8 @@ AssetListRowBase.propTypes = {
size: PropTypes.number.isRequired
}).isRequired,
deleteAssetRequest: PropTypes.func.isRequired,
username: PropTypes.string.isRequired
username: PropTypes.string.isRequired,
t: PropTypes.func.isRequired
};

function mapStateToPropsAssetListRow(state) {
Expand All @@ -153,7 +155,7 @@ class AssetList extends React.Component {
}

getAssetsTitle() {
return 'p5.js Web Editor | My assets';
return this.props.t('AssetList.Title');
}

hasAssets() {
Expand All @@ -167,13 +169,13 @@ class AssetList extends React.Component {

renderEmptyTable() {
if (!this.props.loading && this.props.assetList.length === 0) {
return (<p className="asset-table__empty">No uploaded assets.</p>);
return (<p className="asset-table__empty">{this.props.t('AssetList.NoUploadedAssets')}</p>);
}
return null;
}

render() {
const { assetList } = this.props;
const { assetList, t } = this.props;
return (
<article className="asset-table-container">
<Helmet>
Expand All @@ -185,9 +187,9 @@ class AssetList extends React.Component {
<table className="asset-table">
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Sketch</th>
<th>{t('AssetList.HeaderName')}</th>
<th>{t('AssetList.HeaderSize')}</th>
<th>{t('AssetList.HeaderSketch')}</th>
<th scope="col"></th>
</tr>
</thead>
Expand All @@ -212,7 +214,8 @@ AssetList.propTypes = {
sketchId: PropTypes.string
})).isRequired,
getAssets: PropTypes.func.isRequired,
loading: PropTypes.bool.isRequired
loading: PropTypes.bool.isRequired,
t: PropTypes.func.isRequired
};

function mapStateToProps(state) {
Expand All @@ -227,4 +230,4 @@ function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, AssetActions), dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(AssetList);
export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(AssetList));
10 changes: 6 additions & 4 deletions client/modules/IDE/components/CopyableInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import Clipboard from 'clipboard';
import classNames from 'classnames';
import { withTranslation } from 'react-i18next';

import ShareIcon from '../../../images/share.svg';

Expand Down Expand Up @@ -45,7 +46,7 @@ class CopyableInput extends React.Component {
<div className={copyableInputClass}>
<div
className="copyable-input__value-container tooltipped-no-delay"
aria-label="Copied to Clipboard!"
aria-label={this.props.t('CopyableInput.CopiedARIA')}
ref={(element) => { this.tooltip = element; }}
onMouseLeave={this.onMouseLeaveHandler}
>
Expand All @@ -69,7 +70,7 @@ class CopyableInput extends React.Component {
rel="noopener noreferrer"
href={value}
className="copyable-input__preview"
aria-label={`Open ${label} view in new tab`}
aria-label={this.props.t('CopyableInput.CopiedARIA', { label })}
>
<ShareIcon focusable="false" aria-hidden="true" />
</a>
Expand All @@ -82,11 +83,12 @@ class CopyableInput extends React.Component {
CopyableInput.propTypes = {
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
hasPreviewLink: PropTypes.bool
hasPreviewLink: PropTypes.bool,
t: PropTypes.func.isRequired
};

CopyableInput.defaultProps = {
hasPreviewLink: false
};

export default CopyableInput;
export default withTranslation()(CopyableInput);
11 changes: 7 additions & 4 deletions client/modules/IDE/components/EditableInput.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';

import { withTranslation } from 'react-i18next';
import i18next from 'i18next';
import EditIcon from '../../../images/pencil.svg';


// TODO I think this needs a description prop so that it's accessible
function EditableInput({
validate,
Expand Down Expand Up @@ -58,7 +60,7 @@ function EditableInput({
<button
className="editable-input__label"
onClick={beginEditing}
aria-label={`Edit ${displayValue} value`}
aria-label={this.props.t('EditableInput.EditValue', { display: displayValue })}
>
<span>{displayValue}</span>
<EditIcon
Expand All @@ -84,7 +86,7 @@ function EditableInput({
}

EditableInput.defaultProps = {
emptyPlaceholder: 'No value',
emptyPlaceholder: i18next.t('EditableInput.EmptyPlaceholder'),
InputComponent: 'input',
inputProps: {},
validate: () => true,
Expand All @@ -99,6 +101,7 @@ EditableInput.propTypes = {
onChange: PropTypes.func.isRequired,
validate: PropTypes.func,
value: PropTypes.string,
t: PropTypes.func.isRequired
};

export default EditableInput;
export default withTranslation()(EditableInput);
5 changes: 3 additions & 2 deletions client/modules/IDE/components/Feedback.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import { Helmet } from 'react-helmet';
import { withTranslation } from 'react-i18next';
import GitHubLogo from '../../../images/github.svg';

function Feedback(props) {
return (
<div className="feedback__content">
<Helmet>
<title>p5.js Web Editor | Feedback</title>
<title>{this.props.t('Feedback.Title')}</title>
</Helmet>
<div className="feedback__content-pane">
<h2 className="feedback__content-pane-header">
Expand Down Expand Up @@ -47,4 +48,4 @@ function Feedback(props) {
);
}

export default Feedback;
export default withTranslation()(Feedback);
4 changes: 3 additions & 1 deletion client/modules/IDE/components/Searchbar/Collection.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import i18next from 'i18next';
import * as SortingActions from '../../actions/sorting';

import Searchbar from './Searchbar';


const scope = 'collection';

function mapStateToProps(state) {
return {
searchLabel: 'Search collections...',
searchLabel: i18next.t('Searchbar.SearchCollection'),
searchTerm: state.search[`${scope}SearchTerm`],
};
}
Expand Down
11 changes: 7 additions & 4 deletions client/modules/IDE/components/Searchbar/Searchbar.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import PropTypes from 'prop-types';
import React from 'react';
import { throttle } from 'lodash';

import { withTranslation } from 'react-i18next';
import i18next from 'i18next';
import SearchIcon from '../../../../images/magnifyingglass.svg';


class Searchbar extends React.Component {
constructor(props) {
super(props);
Expand Down Expand Up @@ -50,7 +52,7 @@ class Searchbar extends React.Component {
<button
className="searchbar__clear-button"
onClick={this.handleResetSearch}
>clear
>{this.props.t('Searchbar.ClearTerm')}
</button>
</div>
);
Expand All @@ -62,10 +64,11 @@ Searchbar.propTypes = {
setSearchTerm: PropTypes.func.isRequired,
resetSearchTerm: PropTypes.func.isRequired,
searchLabel: PropTypes.string,
t: PropTypes.func.isRequired
};

Searchbar.defaultProps = {
searchLabel: 'Search sketches...',
searchLabel: i18next.t('Searchbar.SearchSketch')
};

export default Searchbar;
export default withTranslation()(Searchbar);
2 changes: 2 additions & 0 deletions client/modules/IDE/components/Searchbar/Sketch.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import i18next from 'i18next';
import * as SortingActions from '../../actions/sorting';

import Searchbar from './Searchbar';
Expand All @@ -8,6 +9,7 @@ const scope = 'sketch';

function mapStateToProps(state) {
return {
searchLabel: i18next.t('Searchbar.SearchSketch'),
searchTerm: state.search[`${scope}SearchTerm`],
};
}
Expand Down
40 changes: 40 additions & 0 deletions translations/locales/en-US/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,30 @@
"Verified": "All done, your email address has been verified.",
"InvalidState": "Something went wrong."
},
"AssetList": {
"Title": "p5.js Web Editor | My assets",
"ToggleOpenCloseARIA": "Toggle Open/Close Asset Options",
"Delete": "Delete",
"OpenNewTab": "Open in New Tab",
"NoUploadedAssets": "No uploaded assets.",
"HeaderName": "Name",
"HeaderSize": "Size",
"HeaderSketch": "Sketch"
},
"Feedback": {
"Title": "p5.js Web Editor | Feedback",
"ViaGithubHeader": "Via Github Issues",
"ViaGithubDescription": "If you're familiar with Github, this is our preferred method for receiving bug reports and feedback.",
"GoToGithub": "Go to Github",
"ViaGoogleHeader": "Via Google Form",
"ViaGoogleDescription": "You can also submit this quick form.",
"GoToForm": "Go to Form"
},
"Searchbar": {
"SearchSketch": "Search sketches...",
"SearchCollection": "Search collections...",
"ClearTerm": "clear"
},
"UploadFileModal": {
"Title": "Upload File",
"CloseButtonARIA": "Close upload file modal",
Expand Down Expand Up @@ -491,5 +515,21 @@
"Saved25Seconds": "Saved: 25 seconds ago",
"Saved35Seconds": "Saved: 35 seconds ago",
"SavedAgo": "Saved: {{timeAgo}} ago"
},
"AddRemoveButton": {
"AltAddARIA": "Add to collection",
"AltRemoveARIA": "Remove from collection"
},
"CopyableInput": {
"CopiedARIA": "Copied to Clipboard!",
"OpenViewTabARIA": "Open {{label}} view in new tab"
},
"EditableInput": {
"EditValue": "Edit {{display}} value",
"EmptyPlaceholder": "No value"
},
"PreviewNav": {
"EditSketchARIA": "Edit Sketch",
"ByUser": "by"
}
}
Loading