chore: i18n complete (#37)

* chore: i18n
This commit is contained in:
Raymond Zhou
2022-03-31 16:14:29 -04:00
committed by GitHub
parent 0f87a61639
commit dca18b9b97
17 changed files with 23701 additions and 75 deletions

23564
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,11 +18,11 @@ import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/image';
import 'tinymce/plugins/imagetools';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import {
Spinner,
Toast,
} from '@edx/paragon';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { actions, selectors } from '../../data/redux';
import { RequestKeys } from '../../data/constants/requests';
@@ -43,6 +43,8 @@ export const TextEditor = ({
blockFailed,
blockFinished,
initializeEditor,
// inject
intl,
}) => {
const { isOpen, openModal, closeModal } = modalToggle();
@@ -66,7 +68,7 @@ export const TextEditor = ({
{(!blockFinished)
? (
<div className="text-center p-6">
<Spinner animation="border" className="m-3" screenreadertext="loading" />
<Spinner animation="border" className="m-3" screenreadertext={intl.formatMessage(messages.spinnerScreenReaderText)} />
</div>
)
: (
@@ -101,6 +103,8 @@ TextEditor.propTypes = {
blockFailed: PropTypes.bool.isRequired,
blockFinished: PropTypes.bool.isRequired,
initializeEditor: PropTypes.func.isRequired,
// inject
intl: intlShape.isRequired,
};
export const mapStateToProps = (state) => ({
@@ -113,4 +117,4 @@ export const mapDispatchToProps = {
initializeEditor: actions.app.initializeEditor,
};
export default connect(mapStateToProps, mapDispatchToProps)(TextEditor);
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(TextEditor));

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { shallow } from 'enzyme';
import { formatMessage } from '../../../testUtils';
import { TextEditor, mapStateToProps, mapDispatchToProps } from './TextEditor';
import { actions, selectors } from '../../data/redux';
import { RequestKeys } from '../../data/constants/requests';
@@ -68,6 +70,8 @@ describe('TextEditor', () => {
blockFailed: false,
blockFinished: true,
initializeEditor: jest.fn().mockName('args.intializeEditor'),
// inject
intl: { formatMessage },
};
describe('snapshots', () => {
modalToggle.mockReturnValue({

View File

@@ -5,6 +5,9 @@ import {
ActionRow,
ModalDialog,
} from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import messages from './messages';
export const BaseModal = ({
isOpen,
@@ -15,7 +18,6 @@ export const BaseModal = ({
footerAction,
}) => (
<ModalDialog
title="My dialog"
isOpen={isOpen}
onClose={close}
size="lg"
@@ -37,7 +39,7 @@ export const BaseModal = ({
{footerAction}
<ActionRow.Spacer />
<ModalDialog.CloseButton variant="tertiary" onClick={close}>
Cancel
<FormattedMessage {...messages.cancelButtonLabel} />
</ModalDialog.CloseButton>
{confirmAction}
</ActionRow>

View File

@@ -1,8 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Form } from '@edx/paragon';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import * as hooks from './hooks';
import messages from './messages';
/**
* Wrapper for alt-text input and isDecorative checkbox control
@@ -16,16 +19,20 @@ export const AltTextControls = ({
setIsDecorative,
setValue,
value,
// inject
intl,
}) => (
<Form.Group className="mt-4.5">
<Form.Label as="h4">Accessibility</Form.Label>
<Form.Label as="h4">
<FormattedMessage {...messages.accessibilityLabel} />
</Form.Label>
<Form.Control
className="mt-4.5"
type="input"
value={value}
disabled={isDecorative}
onChange={hooks.onInputChange(setValue)}
floatingLabel="Alt Text"
floatingLabel={intl.formatMessage(messages.altTextFloatingLabel)}
/>
<Form.Checkbox
className="mt-4.5 decorative-control-label"
@@ -33,7 +40,7 @@ export const AltTextControls = ({
onChange={hooks.onCheckboxChange(setIsDecorative)}
>
<Form.Label>
This image is decorative (no alt text required).
<FormattedMessage {...messages.decorativeCheckboxLabel} />
</Form.Label>
</Form.Checkbox>
</Form.Group>
@@ -43,6 +50,8 @@ AltTextControls.propTypes = {
value: PropTypes.string.isRequired,
setValue: PropTypes.func.isRequired,
setIsDecorative: PropTypes.func.isRequired,
// inject
intl: intlShape.isRequired,
};
export default AltTextControls;
export default injectIntl(AltTextControls);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { shallow } from 'enzyme';
import AltTextControls from './AltTextControls';
import { formatMessage } from '../../../../../testUtils';
import { AltTextControls } from './AltTextControls';
jest.mock('./hooks', () => ({
onInputChange: (handler) => ({ 'hooks.onInputChange': handler }),
@@ -11,6 +13,8 @@ describe('AltTextControls', () => {
const props = {
isDecorative: true,
value: 'props.value',
// inject
intl: { formatMessage },
};
beforeEach(() => {
props.setValue = jest.fn().mockName('props.setValue');

View File

@@ -9,8 +9,10 @@ import {
Locked,
Unlocked,
} from '@edx/paragon/icons';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import hooks from './hooks';
import messages from './messages';
/**
* Wrapper for image dimension inputs and the lock checkbox.
@@ -30,9 +32,13 @@ export const DimensionControls = ({
unlock,
updateDimensions,
value,
// inject
intl,
}) => ((value !== null) && (
<Form.Group>
<Form.Label as="h4">Image Dimensions</Form.Label>
<Form.Label as="h4">
<FormattedMessage {...messages.imageDimensionsLabel} />
</Form.Label>
<div className="mt-4.5">
<Form.Control
className="dimension-input"
@@ -41,7 +47,7 @@ export const DimensionControls = ({
min={1}
onChange={hooks.onInputChange(setWidth)}
onBlur={updateDimensions}
floatingLabel="Width"
floatingLabel={intl.formatMessage(messages.widthFloatingLabel)}
/>
<Form.Control
className="dimension-input"
@@ -50,11 +56,15 @@ export const DimensionControls = ({
min={1}
onChange={hooks.onInputChange(setHeight)}
onBlur={updateDimensions}
floatingLabel="Height"
floatingLabel={intl.formatMessage(messages.heightFloatingLabel)}
/>
<IconButton
className="d-inline-block"
alt={isLocked ? 'unlock dimensions' : 'lock dimensions'}
alt={
isLocked
? intl.formatMessage(messages.unlockDimensionsLabel)
: intl.formatMessage(messages.lockDimensionsLabel)
}
iconAs={Icon}
src={isLocked ? Locked : Unlocked}
onClick={isLocked ? unlock : lock}
@@ -79,6 +89,8 @@ DimensionControls.propTypes = ({
lock: PropTypes.func.isRequired,
unlock: PropTypes.func.isRequired,
updateDimensions: PropTypes.func.isRequired,
// inject
intl: intlShape.isRequired,
});
export default DimensionControls;
export default injectIntl(DimensionControls);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { shallow } from 'enzyme';
import DimensionControls from './DimensionControls';
import { formatMessage } from '../../../../../testUtils';
import { DimensionControls } from './DimensionControls';
jest.mock('./hooks', () => ({
onInputChange: (handler) => ({ 'hooks.onInputChange': handler }),
@@ -12,6 +14,8 @@ describe('DimensionControls', () => {
locked: { 'props.locked': 'lockedValue' },
isLocked: true,
value: { width: 20, height: 40 },
// inject
intl: { formatMessage },
};
beforeEach(() => {
props.setWidth = jest.fn().mockName('props.setWidth');

View File

@@ -7,7 +7,11 @@ exports[`AltTextControls render snapshot: isDecorative=true 1`] = `
<Form.Label
as="h4"
>
Accessibility
<FormattedMessage
defaultMessage="Accessibility"
description="Label title for accessibility section."
id="authoring.texteditor.imagesettingsmodal.accessibilityLabel"
/>
</Form.Label>
<Form.Control
className="mt-4.5"
@@ -31,7 +35,11 @@ exports[`AltTextControls render snapshot: isDecorative=true 1`] = `
}
>
<Form.Label>
This image is decorative (no alt text required).
<FormattedMessage
defaultMessage="This image is decorative (no alt text required)."
description="Checkbox label for whether or not an image is decorative."
id="authoring.texteditor.imagesettingsmodal.decorativeCheckboxLabel"
/>
</Form.Label>
</Form.Checkbox>
</Form.Group>

View File

@@ -7,7 +7,11 @@ exports[`DimensionControls render snapshot 1`] = `
<Form.Label
as="h4"
>
Image Dimensions
<FormattedMessage
defaultMessage="Image Dimensions"
description="Label title for the image dimensions section."
id="authoring.texteditor.imagesettingsmodal.imageDimensionsLabel"
/>
</Form.Label>
<div
className="mt-4.5"
@@ -54,7 +58,11 @@ exports[`DimensionControls render unlocked dimensions 1`] = `
<Form.Label
as="h4"
>
Image Dimensions
<FormattedMessage
defaultMessage="Image Dimensions"
description="Label title for the image dimensions section."
id="authoring.texteditor.imagesettingsmodal.imageDimensionsLabel"
/>
</Form.Label>
<div
className="mt-4.5"

View File

@@ -28,7 +28,11 @@ exports[`ImageSettingsModal render snapshot 1`] = `
}
variant="primary"
>
Save
<FormattedMessage
defaultMessage="Save"
description="Label for save button."
id="authoring.texteditor.imagesettingsmodal.saveButtonLabel"
/>
</Button>
}
footerAction={null}
@@ -40,7 +44,11 @@ exports[`ImageSettingsModal render snapshot 1`] = `
size="inline"
variant="link"
>
Replace image
<FormattedMessage
defaultMessage="Replace image"
description="Label for replace image button."
id="authoring.texteditor.imagesettingsmodal.replaceImageButtonLabel"
/>
</Button>
<br />
<div

View File

@@ -2,12 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Button, Image } from '@edx/paragon';
import { ArrowBackIos } from '@edx/paragon/icons';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import BaseModal from '../BaseModal';
import AltTextControls from './AltTextControls';
import DimensionControls from './DimensionControls';
import hooks from './hooks';
import messages from './messages';
import './index.scss';
/**
@@ -26,6 +28,8 @@ export const ImageSettingsModal = ({
selection,
saveToEditor,
returnToSelection,
// inject
intl,
}) => {
const dimensions = hooks.dimensions();
const altText = hooks.altText();
@@ -37,7 +41,7 @@ export const ImageSettingsModal = ({
});
return (
<BaseModal
title="Image Settings"
title={intl.formatMessage(messages.titleLabel)}
close={close}
isOpen={isOpen}
confirmAction={(
@@ -46,7 +50,7 @@ export const ImageSettingsModal = ({
onClick={onSaveClick}
disabled={hooks.isSaveDisabled(altText)}
>
Save
<FormattedMessage {...messages.saveButtonLabel} />
</Button>
)}
>
@@ -56,7 +60,7 @@ export const ImageSettingsModal = ({
size="inline"
iconBefore={ArrowBackIos}
>
Replace image
<FormattedMessage {...messages.replaceImageButtonLabel} />
</Button>
<br />
<div className="d-flex flex-row m-2 img-settings-form-container">
@@ -87,5 +91,7 @@ ImageSettingsModal.propTypes = {
}).isRequired,
saveToEditor: PropTypes.func.isRequired,
returnToSelection: PropTypes.func.isRequired,
// inject
intl: intlShape.isRequired,
};
export default ImageSettingsModal;
export default injectIntl(ImageSettingsModal);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { shallow } from 'enzyme';
import ImageSettingsModal from '.';
import { formatMessage } from '../../../../../testUtils';
import { ImageSettingsModal } from '.';
jest.mock('./AltTextControls', () => 'AltTextControls');
jest.mock('./DimensionControls', () => 'DimensionControls');
@@ -24,6 +26,8 @@ describe('ImageSettingsModal', () => {
const props = {
isOpen: false,
selection: { selected: 'image data' },
// inject
intl: { formatMessage },
};
beforeEach(() => {
props.close = jest.fn().mockName('props.close');

View File

@@ -0,0 +1,64 @@
export const messages = {
// index
titleLabel: {
id: 'authoring.texteditor.imagesettingsmodal.titleLabel',
defaultMessage: 'Image Settings',
description: 'Label title for image settings modal.',
},
saveButtonLabel: {
id: 'authoring.texteditor.imagesettingsmodal.saveButtonLabel',
defaultMessage: 'Save',
description: 'Label for save button.',
},
replaceImageButtonLabel: {
id: 'authoring.texteditor.imagesettingsmodal.replaceImageButtonLabel',
defaultMessage: 'Replace image',
description: 'Label for replace image button.',
},
// DimensionControls
imageDimensionsLabel: {
id: 'authoring.texteditor.imagesettingsmodal.imageDimensionsLabel',
defaultMessage: 'Image Dimensions',
description: 'Label title for the image dimensions section.',
},
widthFloatingLabel: {
id: 'authoring.texteditor.imagesettingsmodal.widthFloatingLabel',
defaultMessage: 'Width',
description: 'Floating label for width input.',
},
heightFloatingLabel: {
id: 'authoring.texteditor.imagesettingsmodal.heightFloatingLabel',
defaultMessage: 'Height',
description: 'Floating label for height input.',
},
unlockDimensionsLabel: {
id: 'authoring.texteditor.imagesettingsmodal.unlockDimensionsLabel',
defaultMessage: 'unlock dimensions',
description: 'Label for button when unlocking dimensions.',
},
lockDimensionsLabel: {
id: 'authoring.texteditor.imagesettingsmodal.lockDimensionsLabel',
defaultMessage: 'lock dimensions',
description: 'Label for button when locking dimensions.',
},
// AltTextControls
accessibilityLabel: {
id: 'authoring.texteditor.imagesettingsmodal.accessibilityLabel',
defaultMessage: 'Accessibility',
description: 'Label title for accessibility section.',
},
altTextFloatingLabel: {
id: 'authoring.texteditor.imagesettingsmodal.altTextFloatingLabel',
defaultMessage: 'Alt Text',
description: 'Floating label title for alt text input.',
},
decorativeCheckboxLabel: {
id: 'authoring.texteditor.imagesettingsmodal.decorativeCheckboxLabel',
defaultMessage: 'This image is decorative (no alt text required).',
description: 'Checkbox label for whether or not an image is decorative.',
},
};
export default messages;

View File

@@ -8,7 +8,6 @@ exports[`BaseModal ImageUploadModal template component snapshot 1`] = `
isOpen={true}
onClose={[MockFunction props.close]}
size="lg"
title="My dialog"
variant="default"
>
<ModalDialog.Header>
@@ -27,7 +26,11 @@ exports[`BaseModal ImageUploadModal template component snapshot 1`] = `
onClick={[MockFunction props.close]}
variant="tertiary"
>
Cancel
<FormattedMessage
defaultMessage="Cancel"
description="Label for cancel button."
id="authoring.texteditor.baseModal.cancelButtonLabel"
/>
</ModalDialog.CloseButton>
props.confirmAction node
</ActionRow>

View File

@@ -0,0 +1,9 @@
export const messages = {
cancelButtonLabel: {
id: 'authoring.texteditor.baseModal.cancelButtonLabel',
defaultMessage: 'Cancel',
description: 'Label for cancel button.',
},
};
export default messages;

View File

@@ -4,6 +4,11 @@ export const messages = {
defaultMessage: 'Error: Could Not Load Text Content',
description: 'Error Message Dispayed When HTML content fails to Load',
},
spinnerScreenReaderText: {
id: 'authoring.texteditor.spinnerScreenReaderText',
defaultMessage: 'loading',
description: 'Loading message for spinner screenreader text.',
},
};
export default messages;