Localize default project (temporary solution)

This commit is contained in:
chrisgarrity committed 2018-09-14 16:11:46 -04:00
1 parent 0b2b0843aa
commit 102d3d7e79
5 files changed
+209 -37

No files matched your search

+37 -32
View File
@@ -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;
+150
View File
@@ -0,0 +1,150 @@
import {defineMessages} from 'react-intl';
const messages = defineMessages({
backdrop: {
defaultMessage: 'backdrop1',
description: 'Default name for the first backdrop',
id: 'gui.defaultProject.backdrop'
},
pop: {
defaultMessage: 'pop',
description: 'Default name for the pop sound',
id: 'gui.defaultProject.pop'
},
sprite: {
defaultMessage: 'Sprite1',
description: 'Name for the default sprite',
id: 'gui.defaultProject.sprite'
},
costume1: {
defaultMessage: 'costume1',
description: 'Name for the first default costume',
id: 'gui.defaultProject.costume1'
},
costume2: {
defaultMessage: 'costume2',
description: 'Name for the second default costume',
id: 'gui.defaultProject.costume2'
},
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'
}
});
// 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 {json} 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),
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),
variables: {},
lists: {},
broadcasts: {},
blocks: {},
currentCostume: 0,
costumes: [
{
assetId: '09dc888b0b7df19f70d81588ae73420e',
name: translator(messages.costume1),
bitmapResolution: 1,
md5ext: '09dc888b0b7df19f70d81588ae73420e.svg',
dataFormat: 'svg',
rotationCenterX: 47,
rotationCenterY: 55
},
{
assetId: '3696356a03a8d938318876a593572843',
name: translator(messages.costume2),
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;
+4 -1
View File
@@ -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 {
+15 -1
View File
@@ -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,6 +9,7 @@ import defaultProjectAssets from './default-project';
class Storage extends ScratchStorage {
constructor () {
super();
const defaultProjectAssets = defaultProject(this.translator);
defaultProjectAssets.forEach(asset => this.cache(
this.AssetType[asset.assetType],
this.DataFormat[asset.dataFormat],
@@ -54,6 +55,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();
+3 -3
View File
@@ -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);