diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx index 4c63a8cceb7bec2c86632886b6e195ff1c4535ae..708e84adc6ea0740febdaf72a4156a38066ed1c6 100644 --- a/src/containers/costume-tab.jsx +++ b/src/containers/costume-tab.jsx @@ -11,6 +11,8 @@ import {connect} from 'react-redux'; import {handleFileUpload, costumeUpload} from '../lib/file-uploader.js'; import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx'; import DragConstants from '../lib/drag-constants'; +import {emptyCostume} from '../lib/empty-assets'; +import sharedMessages from '../lib/shared-messages'; import { closeCameraCapture, @@ -37,7 +39,7 @@ import searchIcon from '../components/action-menu/icon--search.svg'; import costumeLibraryContent from '../lib/libraries/costumes.json'; import backdropLibraryContent from '../lib/libraries/backdrops.json'; -const messages = defineMessages({ +let messages = defineMessages({ addLibraryBackdropMsg: { defaultMessage: 'Choose a Backdrop', description: 'Button to add a backdrop in the editor tab', @@ -75,6 +77,8 @@ const messages = defineMessages({ } }); +messages = {...messages, ...sharedMessages}; + class CostumeTab extends React.Component { constructor (props) { super(props); @@ -150,20 +154,10 @@ class CostumeTab extends React.Component { this.props.vm.addCostume(costume.md5, costume); } handleNewBlankCostume () { - const emptyItem = costumeLibraryContent.find(item => ( - item.name === 'Empty' - )); - const name = this.props.vm.editingTarget.isStage ? `backdrop1` : `costume1`; - const vmCostume = { - name: name, - md5: emptyItem.md5, - rotationCenterX: emptyItem.info[0], - rotationCenterY: emptyItem.info[1], - bitmapResolution: emptyItem.info.length > 2 ? emptyItem.info[2] : 1, - skinId: null - }; - - this.handleNewCostume(vmCostume); + const name = this.props.vm.editingTarget.isStage ? + this.props.intl.formatMessage(messages.backdrop, {index: 1}) : + this.props.intl.formatMessage(messages.costume, {index: 1}); + this.handleNewCostume(emptyCostume(name)); } handleSurpriseCostume () { const item = costumeLibraryContent[Math.floor(Math.random() * costumeLibraryContent.length)]; @@ -201,7 +195,8 @@ class CostumeTab extends React.Component { } handleCameraBuffer (buffer) { const storage = this.props.vm.runtime.storage; - costumeUpload(buffer, 'image/png', 'costume1', storage, this.handleNewCostume); + const name = this.props.intl.formatMessage(messages.costume, {index: 1}); + costumeUpload(buffer, 'image/png', name, storage, this.handleNewCostume); } handleFileUploadClick () { this.fileInput.click(); diff --git a/src/containers/stage-selector.jsx b/src/containers/stage-selector.jsx index e5a86fcc067417198d55724646f85f1ebecebfa9..ad302d51d3b6f38d364d67ab104b049ec3ba0437 100644 --- a/src/containers/stage-selector.jsx +++ b/src/containers/stage-selector.jsx @@ -2,6 +2,7 @@ import bindAll from 'lodash.bindall'; import omit from 'lodash.omit'; import PropTypes from 'prop-types'; import React from 'react'; +import {intlShape, injectIntl} from 'react-intl'; import {connect} from 'react-redux'; import {openBackdropLibrary} from '../reducers/modals'; @@ -9,11 +10,12 @@ import {activateTab, COSTUMES_TAB_INDEX} from '../reducers/editor-tab'; import {setHoveredSprite} from '../reducers/hovered-target'; import DragConstants from '../lib/drag-constants'; import DropAreaHOC from '../lib/drop-area-hoc.jsx'; +import {emptyCostume} from '../lib/empty-assets'; +import sharedMessages from '../lib/shared-messages'; import StageSelectorComponent from '../components/stage-selector/stage-selector.jsx'; import backdropLibraryContent from '../lib/libraries/backdrops.json'; -import costumeLibraryContent from '../lib/libraries/costumes.json'; import {handleFileUpload, costumeUpload} from '../lib/file-uploader.js'; const dragTypes = [ @@ -66,11 +68,7 @@ class StageSelector extends React.Component { this.addBackdropFromLibraryItem(item); } handleEmptyBackdrop () { - // @todo this is brittle, will need to be refactored for localized libraries - const emptyItem = costumeLibraryContent.find(item => item.name === 'Empty'); - if (emptyItem) { - this.addBackdropFromLibraryItem(emptyItem); - } + this.handleNewBackdrop(emptyCostume(this.props.intl.formatMessage(sharedMessages.backdrop, {index: 1}))); } handleBackdropUpload (e) { const storage = this.props.vm.runtime.storage; @@ -108,7 +106,7 @@ class StageSelector extends React.Component { } render () { const componentProps = omit(this.props, [ - 'assetId', 'dispatchSetHoveredSprite', 'id', 'onActivateTab', 'onSelect']); + 'assetId', 'dispatchSetHoveredSprite', 'id', 'intl', 'onActivateTab', 'onSelect']); return ( <DroppableStage fileInputRef={this.setFileInput} @@ -128,6 +126,7 @@ class StageSelector extends React.Component { StageSelector.propTypes = { ...StageSelectorComponent.propTypes, id: PropTypes.string, + intl: intlShape.isRequired, onSelect: PropTypes.func }; @@ -152,7 +151,7 @@ const mapDispatchToProps = dispatch => ({ } }); -export default connect( +export default injectIntl(connect( mapStateToProps, mapDispatchToProps -)(StageSelector); +)(StageSelector)); diff --git a/src/containers/target-pane.jsx b/src/containers/target-pane.jsx index 4444c31432c50174ff1eba9a799fd7a8d710c9c7..a2e5fdcc5f11eeb516375c2908da2214f75ffeb4 100644 --- a/src/containers/target-pane.jsx +++ b/src/containers/target-pane.jsx @@ -2,6 +2,7 @@ import bindAll from 'lodash.bindall'; import React from 'react'; import {connect} from 'react-redux'; +import {intlShape, injectIntl} from 'react-intl'; import { openSpriteLibrary, @@ -15,6 +16,8 @@ import DragConstants from '../lib/drag-constants'; import TargetPaneComponent from '../components/target-pane/target-pane.jsx'; import spriteLibraryContent from '../lib/libraries/sprites.json'; import {handleFileUpload, spriteUpload} from '../lib/file-uploader.js'; +import sharedMessages from '../lib/shared-messages'; +import {emptySprite} from '../lib/empty-assets'; class TargetPane extends React.Component { constructor (props) { @@ -109,15 +112,17 @@ class TargetPane extends React.Component { this.props.vm.addSprite(JSON.stringify(item.json)); } handlePaintSpriteClick () { - // @todo this is brittle, will need to be refactored for localized libraries - const emptyItem = spriteLibraryContent.find(item => item.name === 'Empty'); - if (emptyItem) { - this.props.vm.addSprite(JSON.stringify(emptyItem.json)).then(() => { - setTimeout(() => { // Wait for targets update to propagate before tab switching - this.props.onActivateTab(COSTUMES_TAB_INDEX); - }); + const formatMessage = this.props.intl.formatMessage; + const emptyItem = emptySprite( + formatMessage(sharedMessages.sprite, {index: 1}), + formatMessage(sharedMessages.pop), + formatMessage(sharedMessages.costume, {index: 1}) + ); + this.props.vm.addSprite(JSON.stringify(emptyItem)).then(() => { + setTimeout(() => { // Wait for targets update to propagate before tab switching + this.props.onActivateTab(COSTUMES_TAB_INDEX); }); - } + }); } handleNewSprite (spriteJSONString) { this.props.vm.addSprite(spriteJSONString); @@ -127,8 +132,9 @@ class TargetPane extends React.Component { } handleSpriteUpload (e) { const storage = this.props.vm.runtime.storage; + const costumeSuffix = this.props.intl.formatMessage(sharedMessages.costume, {index: 1}); handleFileUpload(e.target, (buffer, fileType, fileName) => { - spriteUpload(buffer, fileType, fileName, storage, this.handleNewSprite); + spriteUpload(buffer, fileType, fileName, storage, this.handleNewSprite, costumeSuffix); }); } setFileInput (input) { @@ -215,6 +221,7 @@ const { } = TargetPaneComponent.propTypes; TargetPane.propTypes = { + intl: intlShape.isRequired, ...targetPaneProps }; @@ -253,7 +260,7 @@ const mapDispatchToProps = dispatch => ({ } }); -export default connect( +export default injectIntl(connect( mapStateToProps, mapDispatchToProps -)(TargetPane); +)(TargetPane)); diff --git a/src/lib/default-project/index.js b/src/lib/default-project/index.js index 332e1bd98de43cea52b57b687766c3a80361be6d..df1154b6e8a7b34534c5370790164edcb375a408 100644 --- a/src/lib/default-project/index.js +++ b/src/lib/default-project/index.js @@ -1,5 +1,5 @@ import {TextEncoder} from 'text-encoding'; -import projectJson from './project.json'; +import projectData from './project-data'; /* eslint-disable import/no-unresolved */ import popWav from '!arraybuffer-loader!./83a9787d4cb6f3b7632b4ddfebf74367.wav'; @@ -10,34 +10,39 @@ import costume2 from '!raw-loader!./3696356a03a8d938318876a593572843.svg'; /* eslint-enable import/no-unresolved */ const encoder = new TextEncoder(); -export default [{ - id: 0, - assetType: 'Project', - dataFormat: 'JSON', - data: JSON.stringify(projectJson) -}, { - id: '83a9787d4cb6f3b7632b4ddfebf74367', - assetType: 'Sound', - dataFormat: 'WAV', - data: new Uint8Array(popWav) -}, { - id: '83c36d806dc92327b9e7049a565c6bff', - assetType: 'Sound', - dataFormat: 'WAV', - data: new Uint8Array(meowWav) -}, { - id: 'cd21514d0531fdffb22204e0ec5ed84a', - assetType: 'ImageVector', - dataFormat: 'SVG', - data: encoder.encode(backdrop) -}, { - id: '09dc888b0b7df19f70d81588ae73420e', - assetType: 'ImageVector', - dataFormat: 'SVG', - data: encoder.encode(costume1) -}, { - id: '3696356a03a8d938318876a593572843', - assetType: 'ImageVector', - dataFormat: 'SVG', - data: encoder.encode(costume2) -}]; +const defaultProject = translator => { + const projectJson = projectData(translator); + return [{ + id: 0, + assetType: 'Project', + dataFormat: 'JSON', + data: JSON.stringify(projectJson) + }, { + id: '83a9787d4cb6f3b7632b4ddfebf74367', + assetType: 'Sound', + dataFormat: 'WAV', + data: new Uint8Array(popWav) + }, { + id: '83c36d806dc92327b9e7049a565c6bff', + assetType: 'Sound', + dataFormat: 'WAV', + data: new Uint8Array(meowWav) + }, { + id: 'cd21514d0531fdffb22204e0ec5ed84a', + assetType: 'ImageVector', + dataFormat: 'SVG', + data: encoder.encode(backdrop) + }, { + id: '09dc888b0b7df19f70d81588ae73420e', + assetType: 'ImageVector', + dataFormat: 'SVG', + data: encoder.encode(costume1) + }, { + id: '3696356a03a8d938318876a593572843', + assetType: 'ImageVector', + dataFormat: 'SVG', + data: encoder.encode(costume2) + }]; +}; + +export default defaultProject; diff --git a/src/lib/default-project/project-data.js b/src/lib/default-project/project-data.js new file mode 100644 index 0000000000000000000000000000000000000000..e108eaa17eddd957e233e10baf2a6908c664e5a3 --- /dev/null +++ b/src/lib/default-project/project-data.js @@ -0,0 +1,128 @@ +import {defineMessages} from 'react-intl'; +import sharedMessages from '../shared-messages'; + +let messages = defineMessages({ + meow: { + defaultMessage: 'Meow', + description: 'Name for the meow sound', + id: 'gui.defaultProject.meow' + }, + variable: { + defaultMessage: 'my variable', + description: 'Name for the default variable', + id: 'gui.defaultProject.variable' + } +}); + +messages = {...messages, ...sharedMessages}; + +// use the default message if a translation function is not passed +const defaultTranslator = msgObj => msgObj.defaultMessage; + +/** + * Generate a localized version of the default project + * @param {function} translateFunction a function to use for translating the default names + * @return {object} the project data json for the default project + */ +const projectData = translateFunction => { + const translator = translateFunction || defaultTranslator; + return ({ + targets: [ + { + isStage: true, + name: 'Stage', + variables: { + '`jEk@4|i[#Fk?(8x)AV.-my variable': [ + translator(messages.variable), + 0 + ] + }, + lists: {}, + broadcasts: {}, + blocks: {}, + currentCostume: 0, + costumes: [ + { + assetId: 'cd21514d0531fdffb22204e0ec5ed84a', + name: translator(messages.backdrop, {index: 1}), + md5ext: 'cd21514d0531fdffb22204e0ec5ed84a.svg', + dataFormat: 'svg', + rotationCenterX: 240, + rotationCenterY: 180 + } + ], + sounds: [ + { + assetId: '83a9787d4cb6f3b7632b4ddfebf74367', + name: translator(messages.pop), + dataFormat: 'wav', + format: '', + rate: 11025, + sampleCount: 258, + md5ext: '83a9787d4cb6f3b7632b4ddfebf74367.wav' + } + ], + volume: 100, + tempo: 60, + videoTransparency: 50, + videoState: 'off' + }, + { + isStage: false, + name: translator(messages.sprite, {index: 1}), + variables: {}, + lists: {}, + broadcasts: {}, + blocks: {}, + currentCostume: 0, + costumes: [ + { + assetId: '09dc888b0b7df19f70d81588ae73420e', + name: translator(messages.costume, {index: 1}), + bitmapResolution: 1, + md5ext: '09dc888b0b7df19f70d81588ae73420e.svg', + dataFormat: 'svg', + rotationCenterX: 47, + rotationCenterY: 55 + }, + { + assetId: '3696356a03a8d938318876a593572843', + name: translator(messages.costume, {index: 2}), + bitmapResolution: 1, + md5ext: '3696356a03a8d938318876a593572843.svg', + dataFormat: 'svg', + rotationCenterX: 47, + rotationCenterY: 55 + } + ], + sounds: [ + { + assetId: '83c36d806dc92327b9e7049a565c6bff', + name: translator(messages.meow), + dataFormat: 'wav', + format: '', + rate: 22050, + sampleCount: 18688, + md5ext: '83c36d806dc92327b9e7049a565c6bff.wav' + } + ], + volume: 100, + visible: true, + x: 0, + y: 0, + size: 100, + direction: 90, + draggable: false, + rotationStyle: 'all around' + } + ], + meta: { + semver: '3.0.0', + vm: '0.1.0', + agent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' // eslint-disable-line max-len + } + }); +}; + + +export default projectData; diff --git a/src/lib/default-project/project.json b/src/lib/default-project/project.json deleted file mode 100755 index 6ffa9fa3c7148ee8c320a5c68501db1f33009587..0000000000000000000000000000000000000000 --- a/src/lib/default-project/project.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "targets": [ - { - "isStage": true, - "name": "Stage", - "variables": { - "`jEk@4|i[#Fk?(8x)AV.-my variable": [ - "my variable", - 0 - ] - }, - "lists": {}, - "broadcasts": {}, - "blocks": {}, - "currentCostume": 0, - "costumes": [ - { - "assetId": "cd21514d0531fdffb22204e0ec5ed84a", - "name": "backdrop1", - "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg", - "dataFormat": "svg", - "rotationCenterX": 240, - "rotationCenterY": 180 - } - ], - "sounds": [ - { - "assetId": "83a9787d4cb6f3b7632b4ddfebf74367", - "name": "pop", - "dataFormat": "wav", - "format": "", - "rate": 11025, - "sampleCount": 258, - "md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav" - } - ], - "volume": 100, - "tempo": 60, - "videoTransparency": 50, - "videoState": "off" - }, - { - "isStage": false, - "name": "Sprite1", - "variables": {}, - "lists": {}, - "broadcasts": {}, - "blocks": {}, - "currentCostume": 0, - "costumes": [ - { - "assetId": "09dc888b0b7df19f70d81588ae73420e", - "name": "costume1", - "bitmapResolution": 1, - "md5ext": "09dc888b0b7df19f70d81588ae73420e.svg", - "dataFormat": "svg", - "rotationCenterX": 47, - "rotationCenterY": 55 - }, - { - "assetId": "3696356a03a8d938318876a593572843", - "name": "costume2", - "bitmapResolution": 1, - "md5ext": "3696356a03a8d938318876a593572843.svg", - "dataFormat": "svg", - "rotationCenterX": 47, - "rotationCenterY": 55 - } - ], - "sounds": [ - { - "assetId": "83c36d806dc92327b9e7049a565c6bff", - "name": "Meow", - "dataFormat": "wav", - "format": "", - "rate": 22050, - "sampleCount": 18688, - "md5ext": "83c36d806dc92327b9e7049a565c6bff.wav" - } - ], - "volume": 100, - "visible": true, - "x": 0, - "y": 0, - "size": 100, - "direction": 90, - "draggable": false, - "rotationStyle": "all around" - } - ], - "meta": { - "semver": "3.0.0", - "vm": "0.1.0", - "agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" - } -} diff --git a/src/lib/empty-assets.js b/src/lib/empty-assets.js new file mode 100644 index 0000000000000000000000000000000000000000..65f1f678c5ad695eb51fdcdef323b90f8d0be7df --- /dev/null +++ b/src/lib/empty-assets.js @@ -0,0 +1,64 @@ +/** + * @fileoverview + * Utility functions to return json corresponding to default empty assets. + */ + +/** + * Generate a blank costume object for vm.addCostume with the provided name. + * @param {string} name the name to use for the costume, caller should localize + * @return {object} vm costume object + */ +const emptyCostume = name => ({ + name: name, + md5: 'cd21514d0531fdffb22204e0ec5ed84a.svg', + rotationCenterX: 0, + rotationCenterY: 0, + bitmapResolution: 1, + skinId: null +}); + +/** + * Generate a new empty sprite. The caller should provide localized versions of the + * default names. + * @param {string} name the name to use for the sprite + * @param {string} soundName the name to use for the default sound + * @param {string} costumeName the name to use for the default costume + * @return {object} object expected by vm.addSprite + */ +const emptySprite = (name, soundName, costumeName) => ({ + objName: name, + sounds: [ + { + soundName: soundName, + soundID: -1, + md5: '83a9787d4cb6f3b7632b4ddfebf74367.wav', + sampleCount: 258, + rate: 11025, + format: '' + } + ], + costumes: [ + { + costumeName: costumeName, + baseLayerID: -1, + baseLayerMD5: 'cd21514d0531fdffb22204e0ec5ed84a.svg', + bitmapResolution: 1, + rotationCenterX: 0, + rotationCenterY: 0 + } + ], + currentCostumeIndex: 0, + scratchX: 36, + scratchY: 28, + scale: 1, + direction: 90, + rotationStyle: 'normal', + isDraggable: false, + visible: true, + spriteInfo: {} +}); + +export { + emptyCostume, + emptySprite +}; diff --git a/src/lib/file-uploader.js b/src/lib/file-uploader.js index 53d0ab8f651442ebfe4e2d27e5484fe52fdeabbd..afa4371dde134bf46ea4af540d24d74ec309bf26 100644 --- a/src/lib/file-uploader.js +++ b/src/lib/file-uploader.js @@ -180,7 +180,8 @@ const soundUpload = function (fileData, fileType, soundName, storage, handleSoun handleSound(vmSound); }; -const spriteUpload = function (fileData, fileType, spriteName, storage, handleSprite) { +const spriteUpload = function (fileData, fileType, spriteName, storage, handleSprite, costumeSuffix) { + const costumeName = costumeSuffix || 'costume1'; switch (fileType) { case '': case 'application/zip': { // We think this is a .sprite2 or .sprite3 file @@ -191,7 +192,7 @@ const spriteUpload = function (fileData, fileType, spriteName, storage, handleSp case 'image/png': case 'image/jpeg': { // Make a sprite from an image by making it a costume first - costumeUpload(fileData, fileType, `${spriteName}-costume1`, storage, (vmCostume => { + costumeUpload(fileData, fileType, `${spriteName}-${costumeName}`, storage, (vmCostume => { const newSprite = { name: spriteName, isStage: false, diff --git a/src/lib/project-loader-hoc.jsx b/src/lib/project-loader-hoc.jsx index 571f220fdea8786a24f8d557ae6c72fde38b37de..c045dc0eebe090cab651ffa903d806ebe9989a9c 100644 --- a/src/lib/project-loader-hoc.jsx +++ b/src/lib/project-loader-hoc.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {connect} from 'react-redux'; +import {injectIntl, intlShape} from 'react-intl'; import {setProjectId} from '../reducers/project-id'; @@ -24,6 +25,7 @@ const ProjectLoaderHOC = function (WrappedComponent) { }; storage.setProjectHost(props.projectHost); storage.setAssetHost(props.assetHost); + storage.setTranslatorFunction(props.intl.formatMessage); props.setProjectId(props.projectId); if ( props.projectId !== '' && @@ -88,6 +90,7 @@ const ProjectLoaderHOC = function (WrappedComponent) { } ProjectLoaderComponent.propTypes = { assetHost: PropTypes.string, + intl: intlShape.isRequired, projectHost: PropTypes.string, projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), setProjectId: PropTypes.func @@ -104,7 +107,7 @@ const ProjectLoaderHOC = function (WrappedComponent) { setProjectId: id => dispatch(setProjectId(id)) }); - return connect(mapStateToProps, mapDispatchToProps)(ProjectLoaderComponent); + return injectIntl(connect(mapStateToProps, mapDispatchToProps)(ProjectLoaderComponent)); }; export { diff --git a/src/lib/shared-messages.js b/src/lib/shared-messages.js new file mode 100644 index 0000000000000000000000000000000000000000..0de3e342de2af06fa17aaafe6e098dc3ae59994a --- /dev/null +++ b/src/lib/shared-messages.js @@ -0,0 +1,24 @@ +import {defineMessages} from 'react-intl'; + +export default defineMessages({ + backdrop: { + defaultMessage: 'backdrop{index}', + description: 'Default name for a new backdrop, scratch will automatically adjust the number if necessary', + id: 'gui.sharedMessages.backdrop' + }, + costume: { + defaultMessage: 'costume{index}', + description: 'Default name for a new costume, scratch will automatically adjust the number if necessary', + id: 'gui.sharedMessages.costume' + }, + sprite: { + defaultMessage: 'Sprite{index}', + description: 'Default name for a new sprite, scratch will automatically adjust the number if necessary', + id: 'gui.sharedMessages.sprite' + }, + pop: { + defaultMessage: 'pop', + description: 'Name of the pop sound, the default sound added to a sprite', + id: 'gui.sharedMessages.pop' + } +}); diff --git a/src/lib/storage.js b/src/lib/storage.js index 38ee7ede4050bd1985ffb300306d48f89a392fcb..b0634d9c3cfa0f79a659559bb8e2f2cda6fb5ffb 100644 --- a/src/lib/storage.js +++ b/src/lib/storage.js @@ -1,6 +1,6 @@ import ScratchStorage from 'scratch-storage'; -import defaultProjectAssets from './default-project'; +import defaultProject from './default-project'; /** * Wrapper for ScratchStorage which adds default web sources. @@ -9,12 +9,7 @@ import defaultProjectAssets from './default-project'; class Storage extends ScratchStorage { constructor () { super(); - defaultProjectAssets.forEach(asset => this.cache( - this.AssetType[asset.assetType], - this.DataFormat[asset.dataFormat], - asset.data, - asset.id - )); + this.cacheDefaultProject(); this.addWebStore( [this.AssetType.Project], this.getProjectGetConfig.bind(this), @@ -54,6 +49,19 @@ class Storage extends ScratchStorage { getAssetGetConfig (asset) { return `${this.assetHost}/internalapi/asset/${asset.assetId}.${asset.dataFormat}/get/`; } + setTranslatorFunction (translator) { + this.translator = translator; + this.cacheDefaultProject(); + } + cacheDefaultProject () { + const defaultProjectAssets = defaultProject(this.translator); + defaultProjectAssets.forEach(asset => this.cache( + this.AssetType[asset.assetType], + this.DataFormat[asset.dataFormat], + asset.data, + asset.id + )); + } } const storage = new Storage(); diff --git a/test/unit/util/project-loader-hoc.test.jsx b/test/unit/util/project-loader-hoc.test.jsx index 6c30453e8a28124c16378958a8597e1aa4fc2139..a0a51cc66101947abdfe5751ff33441c48de0579 100644 --- a/test/unit/util/project-loader-hoc.test.jsx +++ b/test/unit/util/project-loader-hoc.test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import ProjectLoaderHOC from '../../../src/lib/project-loader-hoc.jsx'; import storage from '../../../src/lib/storage'; -import {mount} from 'enzyme'; +import {mountWithIntl} from '../../helpers/intl-helpers.jsx'; jest.mock('react-ga'); @@ -19,7 +19,7 @@ describe('ProjectLoaderHOC', () => { const WrappedComponent = ProjectLoaderHOC(Component); const originalLoad = storage.load; storage.load = jest.fn((type, id) => Promise.resolve({data: id})); - const mounted = mount( + const mounted = mountWithIntl( <WrappedComponent projectId="100" store={store} @@ -37,7 +37,7 @@ describe('ProjectLoaderHOC', () => { const WrappedComponent = ProjectLoaderHOC(Component); const originalLoad = storage.load; storage.load = jest.fn(() => Promise.resolve(null)); - const mounted = mount(<WrappedComponent store={store} />); + const mounted = mountWithIntl(<WrappedComponent store={store} />); storage.load = originalLoad; const mountedDiv = mounted.find('div'); expect(mountedDiv.exists()).toEqual(false);