From 683241cac12e98f1df6f59b1c46bd05bb9c41f73 Mon Sep 17 00:00:00 2001 From: chrisgarrity <chrisg@media.mit.edu> Date: Thu, 14 Dec 2017 15:53:18 -0500 Subject: [PATCH] Localize extension blocks (#968) Localizes the pen extension: - loads all pen locale information - may want to consider dynamically loading locales later. --- package.json | 2 +- src/containers/blocks.jsx | 19 ++++++++++++++++++- src/reducers/intl.js | 3 ++- test/integration/test.js | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d3fff0c95..34d4d64c4 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "rimraf": "^2.6.1", "scratch-audio": "latest", "scratch-blocks": "latest", - "scratch-l10n": "^2.0.0", + "scratch-l10n": "latest", "scratch-paint": "latest", "scratch-render": "latest", "scratch-storage": "^0.3.0", diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index 895c1af58..647f1f8ba 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -43,6 +43,7 @@ class Blocks extends React.Component { 'onBlockGlowOn', 'onBlockGlowOff', 'handleExtensionAdded', + 'handleBlocksInfoUpdate', 'onTargetsUpdate', 'onVisualReport', 'onWorkspaceUpdate', @@ -72,6 +73,7 @@ class Blocks extends React.Component { addFunctionListener(this.workspace, 'zoom', this.onWorkspaceMetricsChange); this.attachVM(); + this.props.vm.setLocale(this.props.locale, this.props.messages); } shouldComponentUpdate (nextProps, nextState) { return ( @@ -79,10 +81,15 @@ class Blocks extends React.Component { this.props.isVisible !== nextProps.isVisible || this.props.toolboxXML !== nextProps.toolboxXML || this.props.extensionLibraryVisible !== nextProps.extensionLibraryVisible || - this.props.customProceduresVisible !== nextProps.customProceduresVisible + this.props.customProceduresVisible !== nextProps.customProceduresVisible || + this.props.locale !== nextProps.locale ); } componentDidUpdate (prevProps) { + if (prevProps.locale !== this.props.locale) { + this.props.vm.setLocale(this.props.locale, this.props.messages); + } + if (prevProps.toolboxXML !== this.props.toolboxXML) { const selectedCategoryName = this.workspace.toolbox_.getSelectedItem().name_; this.workspace.updateToolbox(this.props.toolboxXML); @@ -120,6 +127,7 @@ class Blocks extends React.Component { this.props.vm.addListener('workspaceUpdate', this.onWorkspaceUpdate); this.props.vm.addListener('targetsUpdate', this.onTargetsUpdate); this.props.vm.addListener('EXTENSION_ADDED', this.handleExtensionAdded); + this.props.vm.addListener('BLOCKSINFO_UPDATE', this.handleBlocksInfoUpdate); } detachVM () { this.props.vm.removeListener('SCRIPT_GLOW_ON', this.onScriptGlowOn); @@ -130,6 +138,7 @@ class Blocks extends React.Component { this.props.vm.removeListener('workspaceUpdate', this.onWorkspaceUpdate); this.props.vm.removeListener('targetsUpdate', this.onTargetsUpdate); this.props.vm.removeListener('EXTENSION_ADDED', this.handleExtensionAdded); + this.props.vm.removeListener('BLOCKSINFO_UPDATE', this.handleBlocksInfoUpdate); } updateToolboxBlockValue (id, value) { const block = this.workspace @@ -212,6 +221,10 @@ class Blocks extends React.Component { const toolboxXML = makeToolboxXML(target.isStage, target.id, dynamicBlocksXML); this.props.updateToolboxState(toolboxXML); } + handleBlocksInfoUpdate (blocksInfo) { + // @todo Later we should replace this to avoid all the warnings from redefining blocks. + this.handleExtensionAdded(blocksInfo); + } handleCategorySelected (categoryName) { this.workspace.toolbox_.setSelectedCategoryByName(categoryName); } @@ -288,6 +301,8 @@ Blocks.propTypes = { customProceduresVisible: PropTypes.bool, extensionLibraryVisible: PropTypes.bool, isVisible: PropTypes.bool, + locale: PropTypes.string, + messages: PropTypes.objectOf(PropTypes.string), onActivateColorPicker: PropTypes.func, onActivateCustomProcedures: PropTypes.func, onRequestCloseCustomProcedures: PropTypes.func, @@ -351,6 +366,8 @@ Blocks.defaultProps = { const mapStateToProps = state => ({ extensionLibraryVisible: state.modals.extensionLibrary, + locale: state.intl.locale, + messages: state.intl.messages, toolboxXML: state.toolbox.toolboxXML, customProceduresVisible: state.customProcedures.active }); diff --git a/src/reducers/intl.js b/src/reducers/intl.js index 12841c407..15a2d307b 100644 --- a/src/reducers/intl.js +++ b/src/reducers/intl.js @@ -6,8 +6,9 @@ import defaultsDeep from 'lodash.defaultsdeep'; import localeData from 'scratch-l10n'; import guiMessages from 'scratch-l10n/locales/gui-msgs'; import paintMessages from 'scratch-l10n/locales/paint-msgs'; +import penMessages from 'scratch-l10n/locales/pen-msgs'; -const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages); +const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages); Object.keys(localeData).forEach(locale => { // TODO: will need to handle locales not in the default intl - see www/custom-locales diff --git a/test/integration/test.js b/test/integration/test.js index d6baaf094..ebfb3fbbd 100644 --- a/test/integration/test.js +++ b/test/integration/test.js @@ -219,4 +219,24 @@ describe('costumes, sounds and variables', () => { const logs = await getLogs(errorWhitelist); await expect(logs).toEqual([]); }); + + test('Localization', async () => { + await loadUri(uri); + await clickText('Blocks'); + await clickText('Extensions'); + await clickText('Pen', modalScope); // Modal closes + await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for scroll animation + await clickText('English'); + await clickText('Deutsch'); + await new Promise(resolve => setTimeout(resolve, 1000)); // wait for blocks refresh + await clickText('Pen'); // will need to be updated when 'Pen' is translated + + // Make sure "Add Sprite" has changed to "Figur hinzufügen" + await findByText('Figur hinzufügen'); + // Find the stamp block in German + await findByText('Abdruck'); + + const logs = await getLogs(errorWhitelist); + await expect(logs).toEqual([]); + }); }); -- GitLab