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);