Add translation to missing strings

Question, should ‘x’ and ‘y’ be localizable?
This commit is contained in:
chrisgarrity committed 2018-04-30 12:22:23 -04:00
1 parent 54c5bae6b8
commit 45032cc291
13 files changed
+193 -44

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
[experimental-scratch.scratch-gui]
[scratch-editor.interface]
file_filter = translations/<lang>.json
source_file = translations/en.json
source_lang = en
+19 -1
View File
@@ -1,6 +1,7 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import GreenFlag from '../green-flag/green-flag.jsx';
import StopAll from '../stop-all/stop-all.jsx';
@@ -8,10 +9,24 @@ import TurboMode from '../turbo-mode/turbo-mode.jsx';
import styles from './controls.css';
const messages = defineMessages({
goTitle: {
id: 'gui.controls.go',
defaultMessage: 'Go',
description: 'Green flag button title'
},
stopTitle: {
id: 'gui.controls.stop',
defaultMessage: 'Stop',
description: 'Stop button title'
}
});
const Controls = function (props) {
const {
active,
className,
intl,
onGreenFlagClick,
onStopAllClick,
turbo,
@@ -24,10 +39,12 @@ const Controls = function (props) {
>
<GreenFlag
active={active}
title={intl.formatMessage(messages.goTitle)}
onClick={onGreenFlagClick}
/>
<StopAll
active={active}
title={intl.formatMessage(messages.stopTitle)}
onClick={onStopAllClick}
/>
{turbo ? (
@@ -40,6 +57,7 @@ const Controls = function (props) {
Controls.propTypes = {
active: PropTypes.bool,
className: PropTypes.string,
intl: intlShape.isRequired,
onGreenFlagClick: PropTypes.func.isRequired,
onStopAllClick: PropTypes.func.isRequired,
turbo: PropTypes.bool
@@ -50,4 +68,4 @@ Controls.defaultProps = {
turbo: false
};
export default Controls;
export default injectIntl(Controls);
+13 -5
View File
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
import {FormattedMessage} from 'react-intl';
import styles from './crash-message.css';
import reloadIcon from './reload.svg';
@@ -13,13 +14,20 @@ const CrashMessage = props => (
src={reloadIcon}
/>
<h2>
Oops! Something went wrong.
<FormattedMessage
defaultMessage="Oops! Something went wrong."
description="Unhandled error title"
id="gui.crashMessage.title"
/>
</h2>
<p>
We are so sorry, but it looks like Scratch has crashed. This bug has been
automatically reported to the Scratch Team. Please refresh your page to try
again.
{ /* eslint-disable max-len */ }
<FormattedMessage
defaultMessage="We are so sorry, but it looks like Scratch has crashed. This bug has been automatically reported to the Scratch Team. Please refresh your page to try again."
description="Unhandled error description"
id="gui.crashMessage.description"
/>
{ /* eslint-enable max-len */ }
</p>
<button
className={styles.reloadButton}
+1 -1
View File
@@ -15,7 +15,7 @@ const Label = props => (
Label.propTypes = {
children: PropTypes.node,
secondary: PropTypes.bool,
text: PropTypes.string.isRequired
text: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired
};
Label.defaultProps = {
+12 -1
View File
@@ -2,6 +2,7 @@ import classNames from 'classnames';
import bindAll from 'lodash.bindall';
import PropTypes from 'prop-types';
import React from 'react';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import LibraryItem from '../library-item/library-item.jsx';
import Modal from '../../containers/modal.jsx';
@@ -14,6 +15,14 @@ import styles from './library.css';
const ALL_TAG_TITLE = 'All';
const tagListPrefix = [{title: ALL_TAG_TITLE}];
const messages = defineMessages({
filterPlaceholder: {
id: 'gui.library.filterPlaceholder',
defaultMessage: 'Search',
description: 'Placeholder text for library search field'
}
});
class LibraryComponent extends React.Component {
constructor (props) {
super(props);
@@ -101,6 +110,7 @@ class LibraryComponent extends React.Component {
)}
filterQuery={this.state.filterQuery}
inputClassName={styles.filterInput}
placeholderText={this.props.intl.formatMessage(messages.filterPlaceholder)}
onChange={this.handleFilterChange}
onClear={this.handleFilterClear}
/>
@@ -176,6 +186,7 @@ LibraryComponent.propTypes = {
),
filterable: PropTypes.bool,
id: PropTypes.string.isRequired,
intl: intlShape.isRequired,
onItemMouseEnter: PropTypes.func,
onItemMouseLeave: PropTypes.func,
onItemSelected: PropTypes.func,
@@ -188,4 +199,4 @@ LibraryComponent.defaultProps = {
filterable: true
};
export default LibraryComponent;
export default injectIntl(LibraryComponent);
+6 -1
View File
@@ -2,6 +2,7 @@ import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import ReactModal from 'react-modal';
import {FormattedMessage} from 'react-intl';
import Box from '../box/box.jsx';
import Button from '../button/button.jsx';
@@ -46,7 +47,11 @@ const ModalComponent = props => (
iconSrc={backIcon}
onClick={props.onRequestClose}
>
Back
<FormattedMessage
defaultMessage="Back"
description="Back button in modal"
id="gui.modal.back"
/>
</Button>
) : (
<CloseButton
+34 -3
View File
@@ -4,12 +4,36 @@ import Box from '../box/box.jsx';
import Waveform from '../waveform/waveform.jsx';
import Meter from '../meter/meter.jsx';
import AudioTrimmer from '../../containers/audio-trimmer.jsx';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import styles from './record-modal.css';
import backIcon from './icon--back.svg';
import stopIcon from './icon--stop-playback.svg';
import playIcon from './icon--play.svg';
const messages = defineMessages({
stopMsg: {
defaultMessage: 'Stop',
description: 'Stop/Play button in recording playback',
id: 'gui.playbackStep.stopMsg'
},
playMsg: {
defaultMessage: 'Play',
description: 'Stop/Play button in recording playback',
id: 'gui.playbackStep.playMsg'
},
loadingMsg: {
defaultMessage: 'Loading...',
description: 'Loading/Save button in recording playback',
id: 'gui.playbackStep.loadingMsg'
},
saveMsg: {
defaultMessage: 'Save',
description: 'Loading/Save button in recording playback',
id: 'gui.playbackStep.saveMsg'
}
});
const PlaybackStep = props => (
<Box>
<Box className={styles.visualizationContainer}>
@@ -48,7 +72,10 @@ const PlaybackStep = props => (
/>
<div className={styles.helpText}>
<span className={styles.playingText}>
{props.playing ? 'Stop' : 'Play'}
{props.playing ?
props.intl.formatMessage(messages.stopMsg) :
props.intl.formatMessage(messages.playMsg)
}
</span>
</div>
</button>
@@ -68,7 +95,10 @@ const PlaybackStep = props => (
disabled={props.encoding}
onClick={props.onSubmit}
>
{props.encoding ? 'Loading...' : 'Save'}
{props.encoding ?
props.intl.formatMessage(messages.loadingMsg) :
props.intl.formatMessage(messages.saveMsg)
}
</button>
</Box>
</Box>
@@ -76,6 +106,7 @@ const PlaybackStep = props => (
PlaybackStep.propTypes = {
encoding: PropTypes.bool.isRequired,
intl: intlShape.isRequired,
levels: PropTypes.arrayOf(PropTypes.number).isRequired,
onBack: PropTypes.func.isRequired,
onPlay: PropTypes.func.isRequired,
@@ -89,4 +120,4 @@ PlaybackStep.propTypes = {
trimStart: PropTypes.number.isRequired
};
export default PlaybackStep;
export default injectIntl(PlaybackStep);
+12 -2
View File
@@ -1,15 +1,24 @@
import PropTypes from 'prop-types';
import React from 'react';
import Box from '../box/box.jsx';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import RecordingStep from '../../containers/recording-step.jsx';
import PlaybackStep from '../../containers/playback-step.jsx';
import Modal from '../modal/modal.jsx';
import styles from './record-modal.css';
const messages = defineMessages({
title: {
defaultMessage: 'Record Sound',
description: 'Recording modal title',
id: 'gui.recordModal.title'
}
});
const RecordModal = props => (
<Modal
className={styles.modalContent}
contentLabel={'Record Sound'}
contentLabel={props.intl.formatMessage(messages.title)}
onRequestClose={props.onCancel}
>
<Box className={styles.body}>
@@ -44,6 +53,7 @@ const RecordModal = props => (
RecordModal.propTypes = {
encoding: PropTypes.bool.isRequired,
intl: intlShape.isRequired,
levels: PropTypes.arrayOf(PropTypes.number),
onBack: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
@@ -64,4 +74,4 @@ RecordModal.propTypes = {
trimStart: PropTypes.number.isRequired
};
export default RecordModal;
export default injectIntl(RecordModal);
+43 -7
View File
@@ -7,6 +7,7 @@ import Box from '../box/box.jsx';
import Label from '../forms/label.jsx';
import Input from '../forms/input.jsx';
import BufferedInputHOC from '../forms/buffered-input-hoc.jsx';
import {FormattedMessage} from 'react-intl';
import layout from '../../lib/layout-constants.js';
import styles from './sprite-info.css';
@@ -31,17 +32,52 @@ class SpriteInfo extends React.Component {
);
}
render () {
const sprite = (
<FormattedMessage
defaultMessage="Sprite"
description="Sprite info label"
id="gui.SpriteInfo.sprite"
/>
);
const spritePlaceholder = (
<FormattedMessage
defaultMessage="Name"
description="Placeholder text for sprite name"
id="gui.SpriteInfo.spritePlaceholder"
/>
);
const showLabel = (
<FormattedMessage
defaultMessage="Show"
description="Sprite info show label"
id="gui.SpriteInfo.show"
/>
);
const sizeLabel = (
<FormattedMessage
defaultMessage="Size"
description="Sprite info size label"
id="gui.SpriteInfo.size"
/>
);
const directionLabel = (
<FormattedMessage
defaultMessage="Direction"
description="Sprite info direction label"
id="gui.SpriteInfo.direction"
/>
);
return (
<Box
className={styles.spriteInfo}
>
<div className={classNames(styles.row, styles.rowPrimary)}>
<div className={styles.group}>
<Label text="Sprite">
<Label text={sprite}>
<BufferedInput
className={styles.spriteInput}
disabled={this.props.disabled}
placeholder="Name"
placeholder={spritePlaceholder}
tabIndex="0"
type="text"
value={this.props.disabled ? '' : this.props.name}
@@ -102,7 +138,7 @@ class SpriteInfo extends React.Component {
<MediaQuery minWidth={layout.fullSizeMinWidth}>
<Label
secondary
text="Show"
text={showLabel}
/>
</MediaQuery>
<div>
@@ -149,12 +185,12 @@ class SpriteInfo extends React.Component {
<div className={classNames(styles.group, styles.largerInput)}>
<Label
secondary
text="Size"
text={sizeLabel}
>
<BufferedInput
small
disabled={this.props.disabled}
label="Size"
label={sizeLabel}
tabIndex="0"
type="text"
value={this.props.disabled ? '' : this.props.size}
@@ -165,12 +201,12 @@ class SpriteInfo extends React.Component {
<div className={classNames(styles.group, styles.largerInput)}>
<Label
secondary
text="Direction"
text={directionLabel}
>
<BufferedInput
small
disabled={this.props.disabled}
label="Direction"
label={directionLabel}
tabIndex="0"
type="text"
value={this.props.disabled ? '' : this.props.direction}
+15 -10
View File
@@ -19,24 +19,29 @@ import styles from './stage-header.css';
const messages = defineMessages({
largeStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Large',
defaultMessage: 'Switch to large stage',
description: 'Button to change stage size to large',
id: 'gui.gui.stageSizeLarge'
id: 'gui.stageHeader.stageSizeLarge'
},
smallStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Small',
defaultMessage: 'Switch to small stage',
description: 'Button to change stage size to small',
id: 'gui.gui.stageSizeSmall'
id: 'gui.stageHeader.stageSizeSmall'
},
fullStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Full Screen',
defaultMessage: 'Enter full screen mode',
description: 'Button to change stage size to full screen',
id: 'gui.gui.stageSizeFull'
id: 'gui.stageHeader.stageSizeFull'
},
unFullStageSizeMessage: {
defaultMessage: 'Stage Size Toggle - Un-full screen',
defaultMessage: 'Exit full screen mode',
description: 'Button to get out of full screen mode',
id: 'gui.gui.stageSizeUnFull'
id: 'gui.stageHeader.stageSizeUnFull'
},
fullscreenControl: {
defaultMessage: 'Full Screen Control',
description: 'Button to enter/exit full screen mode',
id: 'gui.stageHeader.fullscreenControl'
}
});
@@ -71,7 +76,7 @@ const StageHeaderComponent = function (props) {
className={styles.stageButtonIcon}
draggable={false}
src={unFullScreenIcon}
title="Full Screen Control"
title={props.intl.formatMessage(messages.fullscreenControl)}
/>
</Button>
</Box>
@@ -133,7 +138,7 @@ const StageHeaderComponent = function (props) {
className={styles.stageButtonIcon}
draggable={false}
src={fullScreenIcon}
title="Full Screen Control"
title={props.intl.formatMessage(messages.fullscreenControl)}
/>
</Button>
</div>
+18 -3
View File
@@ -2,6 +2,7 @@ import bindAll from 'lodash.bindall';
import PropTypes from 'prop-types';
import React from 'react';
import VM from 'scratch-vm';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
import extensionLibraryContent from '../lib/libraries/extensions/index';
@@ -9,6 +10,19 @@ import analytics from '../lib/analytics';
import LibraryComponent from '../components/library/library.jsx';
import extensionIcon from '../components/action-menu/icon--sprite.svg';
const messages = defineMessages({
extensionTitle: {
defaultMessage: 'Choose an Extension',
description: 'Heading for the extension library',
id: 'gui.extensionLibrary.chooseAnExtension'
},
extensionUrl: {
defaultMessage: 'Enter the URL of the extension',
description: 'Prompt for unoffical extension url',
id: 'gui.extensionLibrary.extensionUrl'
}
});
class ExtensionLibrary extends React.PureComponent {
constructor (props) {
super(props);
@@ -20,7 +34,7 @@ class ExtensionLibrary extends React.PureComponent {
let url = item.extensionURL;
if (!item.disabled && !item.extensionURL) {
// eslint-disable-next-line no-alert
url = prompt('Enter the URL of the extension');
url = prompt(this.props.intl.formatMessage(messages.extensionUrl));
}
if (url && !item.disabled) {
if (this.props.vm.extensionManager.isExtensionLoaded(url)) {
@@ -47,7 +61,7 @@ class ExtensionLibrary extends React.PureComponent {
data={extensionLibraryThumbnailData}
filterable={false}
id="extensionLibrary"
title="Choose an Extension"
title={this.props.intl.formatMessage(messages.extensionTitle)}
visible={this.props.visible}
onItemSelected={this.handleItemSelect}
onRequestClose={this.props.onRequestClose}
@@ -57,10 +71,11 @@ class ExtensionLibrary extends React.PureComponent {
}
ExtensionLibrary.propTypes = {
intl: intlShape.isRequired,
onCategorySelected: PropTypes.func,
onRequestClose: PropTypes.func,
visible: PropTypes.bool,
vm: PropTypes.instanceOf(VM).isRequired // eslint-disable-line react/no-unused-prop-types
};
export default ExtensionLibrary;
export default injectIntl(ExtensionLibrary);
+12 -2
View File
@@ -3,6 +3,15 @@ import PropTypes from 'prop-types';
import bindAll from 'lodash.bindall';
import RecordingStepComponent from '../components/record-modal/recording-step.jsx';
import AudioRecorder from '../lib/audio/audio-recorder.js';
import {defineMessages, injectIntl, intlShape} from 'react-intl';
const messages = defineMessages({
alertMsg: {
defaultMessage: 'Could not start recording',
description: 'Alert for recording error',
id: 'gui.recordingStep.alertMsg'
}
});
class RecordingStep extends React.Component {
constructor (props) {
@@ -32,7 +41,7 @@ class RecordingStep extends React.Component {
this.setState({listening: true});
}
handleRecordingError () {
alert('Could not start recording'); // eslint-disable-line no-alert
alert(this.props.intl.formatMessage(messages.extensionUrl)); // eslint-disable-line no-alert
}
handleLevelUpdate (level) {
this.setState({level});
@@ -68,9 +77,10 @@ class RecordingStep extends React.Component {
}
RecordingStep.propTypes = {
intl: intlShape.isRequired,
onRecord: PropTypes.func.isRequired,
onStopRecording: PropTypes.func.isRequired,
recording: PropTypes.bool
};
export default RecordingStep;
export default injectIntl(RecordingStep);
+7 -7
View File
@@ -1,20 +1,20 @@
import React from 'react';
import {shallowWithIntl} from '../../helpers/intl-helpers.jsx';
import {mountWithIntl} from '../../helpers/intl-helpers.jsx';
import Controls from '../../../src/components/controls/controls';
import TurboMode from '../../../src/components/turbo-mode/turbo-mode';
import GreenFlag from '../../../src/components/green-flag/green-flag';
import StopAll from '../../../src/components/stop-all/stop-all';
describe('Controls component', () => {
const defaultProps = () => ({
active: false,
greenFlagTitle: 'Go',
onGreenFlagClick: jest.fn(),
onStopAllClick: jest.fn(),
stopAllTitle: 'Stop',
turbo: false
});
test('shows turbo mode when in turbo mode', () => {
const component = shallowWithIntl(
const component = mountWithIntl(
<Controls
{...defaultProps()}
/>
@@ -26,15 +26,15 @@ describe('Controls component', () => {
test('triggers the right callbacks when clicked', () => {
const props = defaultProps();
const component = shallowWithIntl(
const component = mountWithIntl(
<Controls
{...props}
/>
);
component.find('[title="Go"]').simulate('click');
component.find(GreenFlag).simulate('click');
expect(props.onGreenFlagClick).toHaveBeenCalled();
component.find('[title="Stop"]').simulate('click');
component.find(StopAll).simulate('click');
expect(props.onStopAllClick).toHaveBeenCalled();
});
});