From 11d43e000665cb4f873368fd246164b1390434a6 Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Mon, 21 Aug 2017 17:58:38 -0400
Subject: [PATCH 1/7] add i18n support

---
 .babelrc                                      |  9 ++-
 .eslintignore                                 |  1 +
 locale/messages.json                          |  6 ++
 package.json                                  |  9 ++-
 scripts/build-i18n-source.js                  | 45 +++++++++++++
 scripts/generate-locale-messages.js           | 67 +++++++++++++++++++
 src/components/brush-mode.jsx                 |  9 ++-
 src/locale.js                                 | 11 +++
 src/playground/playground.jsx                 |  6 +-
 src/reducers/combine-reducers.js              |  2 +
 src/reducers/intl.js                          | 30 +++++++++
 translations/en.json                          | 10 +++
 .../messages/src/components/brush-mode.json   |  7 ++
 .../messages/src/components/eraser-mode.json  |  7 ++
 14 files changed, 213 insertions(+), 6 deletions(-)
 create mode 100644 locale/messages.json
 create mode 100755 scripts/build-i18n-source.js
 create mode 100755 scripts/generate-locale-messages.js
 create mode 100644 src/locale.js
 create mode 100644 src/reducers/intl.js
 create mode 100644 translations/en.json
 create mode 100644 translations/messages/src/components/brush-mode.json
 create mode 100644 translations/messages/src/components/eraser-mode.json

diff --git a/.babelrc b/.babelrc
index 2e236249..3e9bd38e 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,4 +1,9 @@
 {
-  "plugins": ["transform-object-rest-spread"],
-  "presets": ["es2015", "react"]
+    "plugins": [
+        "transform-object-rest-spread",
+        ["react-intl", {
+            "messagesDir": "./translations/messages/"
+        }]
+    ],
+    "presets": ["es2015", "react"],
 }
diff --git a/.eslintignore b/.eslintignore
index fe1b4898..07a71bce 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,3 +1,4 @@
 node_modules/*
 dist/*
 playground/
+scripts/*
\ No newline at end of file
diff --git a/locale/messages.json b/locale/messages.json
new file mode 100644
index 00000000..490c8631
--- /dev/null
+++ b/locale/messages.json
@@ -0,0 +1,6 @@
+{
+  "en": {
+    "paint.brushMode.brush": "Brush",
+    "paint.eraserMode.eraser": "Eraser"
+  }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index ba1ba054..1d7fd76a 100644
--- a/package.json
+++ b/package.json
@@ -4,11 +4,13 @@
   "description": "Graphical User Interface for the Scratch 3.0 paint editor, which is used to make and edit sprites for use in projects.",
   "main": "./dist/scratch-paint.js",
   "scripts": {
-    "build": "npm run clean && webpack --progress --colors --bail",
+    "build": "npm run clean && npm run i18n:msgs && webpack --progress --colors --bail",
     "clean": "rimraf ./dist && mkdirp dist && rimraf ./playground && mkdirp playground",
     "deploy": "touch playground/.nojekyll && gh-pages -t -d playground -m \"Build for $(git log --pretty=format:%H -n1)\"",
+    "i18n:msgs": "node ./scripts/generate-locale-messages.js",
+    "i18n:src": "babel src > tmp.js && rimraf tmp.js && ./scripts/build-i18n-source.js ./translations/messages/ ./translations/",
     "lint": "eslint . --ext .js,.jsx",
-    "start": "webpack-dev-server",
+    "start": "npm run i18n:msgs && webpack-dev-server",
     "test": "npm run lint && npm run build && npm run unit",
     "unit": "jest",
     "watch": "webpack --progress --colors --watch"
@@ -26,10 +28,12 @@
   },
   "devDependencies": {
     "autoprefixer": "7.1.1",
+    "babel-cli": "6.24.1",
     "babel-core": "^6.23.1",
     "babel-eslint": "^7.1.1",
     "babel-jest": "^20.0.3",
     "babel-loader": "^7.0.0",
+    "babel-plugin-react-intl": "2.3.1",
     "babel-plugin-transform-object-rest-spread": "^6.22.0",
     "babel-preset-es2015": "^6.22.0",
     "babel-preset-react": "^6.22.0",
@@ -57,6 +61,7 @@
     "react": "15.6.1",
     "react-dom": "15.5.4",
     "react-intl": "2.3.0",
+    "react-intl-redux": "0.6.0",
     "react-redux": "5.0.5",
     "react-test-renderer": "^15.5.4",
     "redux": "3.6.0",
diff --git a/scripts/build-i18n-source.js b/scripts/build-i18n-source.js
new file mode 100755
index 00000000..9f6571c1
--- /dev/null
+++ b/scripts/build-i18n-source.js
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+
+const fs = require('fs');
+const glob = require('glob');
+const path = require('path');
+const mkdirp = require('mkdirp');
+
+var args = process.argv.slice(2);
+
+if (!args.length) {
+    process.stdout.write('You must specify the messages dir generated by babel-plugin-react-intl.\n');
+    process.exit(1);
+}
+
+const MESSAGES_PATTERN = args.shift() + '/**/*.json';
+
+if (!args.length) {
+    process.stdout.write('A destination directory must be specified.\n');
+    process.exit(1);
+}
+
+const LANG_DIR = args.shift();
+
+// Aggregates the default messages that were extracted from the example app's
+// React components via the React Intl Babel plugin. An error will be thrown if
+// there are messages in different components that use the same `id`. The result
+// is a chromei18n format collection of `id: {message: defaultMessage,
+// description: description}` pairs for the app's default locale.
+let defaultMessages = glob.sync(MESSAGES_PATTERN)
+    .map((filename) => fs.readFileSync(filename, 'utf8'))
+    .map((file) => JSON.parse(file))
+    .reduce((collection, descriptors) => {
+        descriptors.forEach(({id, defaultMessage, description}) => {
+            if (collection.hasOwnProperty(id)) {
+                throw new Error(`Duplicate message id: ${id}`);
+            }
+
+            collection[id] = {message: defaultMessage, description: description};
+        });
+
+        return collection;
+    }, {});
+
+mkdirp.sync(LANG_DIR);
+fs.writeFileSync(path.join(LANG_DIR, 'en.json'), JSON.stringify(defaultMessages, null, 2));
diff --git a/scripts/generate-locale-messages.js b/scripts/generate-locale-messages.js
new file mode 100755
index 00000000..44a1c581
--- /dev/null
+++ b/scripts/generate-locale-messages.js
@@ -0,0 +1,67 @@
+#!/usr/bin/env node
+
+/*
+Generates locale/messages.json from current translastion files
+
+Translations are expected to be in the ./translations directory.
+Translation files are in Chrome i18n json format:
+'''
+{
+    "message.id": {
+        "message": "The translated text",
+        "description": "Tips for translators"
+    },
+    ...
+}
+'''
+They are named by locale, for example: 'fr.json' or 'zh-cn.json'
+
+Current languages supported are listed in ../src/languages.json
+
+Converts the collection of translation files to a single set of messages.
+Example output:
+'''
+{
+  "en": {
+    "action.addBackdrop": "Add Backdrop",
+    "action.addCostume": "Add Costume",
+    "action.recordSound": "Record Sound",
+    "action.addSound": "Add Sound"
+  },
+  "fr": {
+    "action.addSound": "Ajouter Son",
+    "action.addCostume": "Ajouter Costume",
+    "action.addBackdrop": "Ajouter Arrière-plan",
+    "action.recordSound": "Enregistrement du Son"
+  }
+}
+'''
+
+Missing locales are ignored, react-intl will use the default messages for them.
+ */
+const fs = require('fs');
+const path = require('path');
+const mkdirp = require('mkdirp');
+
+const locales = ['en'];
+const LANG_DIR = './translations/';
+const MSGS_DIR = './locale/';
+
+let messages = locales.reduce((collection, lang) => {
+    let langMessages = {};
+    try {
+        let langData = JSON.parse(
+            fs.readFileSync(path.resolve(LANG_DIR, lang + '.json'), 'utf8')
+        );
+        Object.keys(langData).forEach((id) => {
+            langMessages[id] = langData[id].message;
+        });
+        collection[lang] = langMessages;
+    } catch (e) {
+        process.stdout.write(lang + ' translation file missing, will use defaults.\n');
+    }
+    return collection;
+}, {});
+
+mkdirp.sync(MSGS_DIR);
+fs.writeFileSync(MSGS_DIR + 'messages.json', JSON.stringify(messages, null, 2));
diff --git a/src/components/brush-mode.jsx b/src/components/brush-mode.jsx
index 865c04f4..84a831dd 100644
--- a/src/components/brush-mode.jsx
+++ b/src/components/brush-mode.jsx
@@ -1,8 +1,15 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import {FormattedMessage} from 'react-intl';
 
 const BrushModeComponent = props => (
-    <button onClick={props.onMouseDown}>Brush</button>
+    <button onClick={props.onMouseDown}>
+        <FormattedMessage
+            defaultMessage="Brush"
+            description="Label for the brush tool"
+            id="paint.brushMode.brush"
+        />
+    </button>
 );
 
 BrushModeComponent.propTypes = {
diff --git a/src/locale.js b/src/locale.js
new file mode 100644
index 00000000..fb1e72e9
--- /dev/null
+++ b/src/locale.js
@@ -0,0 +1,11 @@
+import localeDataEn from 'react-intl/locale-data/en';
+
+import messages from '../locale/messages.json'; // eslint-disable-line import/no-unresolved
+
+export default {
+    en: {
+        name: 'English',
+        localeData: localeDataEn,
+        messages: messages.en
+    }
+};
diff --git a/src/playground/playground.jsx b/src/playground/playground.jsx
index 8a27161e..7249b454 100644
--- a/src/playground/playground.jsx
+++ b/src/playground/playground.jsx
@@ -4,15 +4,19 @@ import PaintEditor from '..';
 import {Provider} from 'react-redux';
 import {createStore} from 'redux';
 import reducer from '../reducers/combine-reducers';
+import {intlInitialState, IntlProvider} from '../reducers/intl.js';
 
 const appTarget = document.createElement('div');
 document.body.appendChild(appTarget);
 const store = createStore(
     reducer,
+    intlInitialState,
     window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
 );
 ReactDOM.render((
     <Provider store={store}>
-        <PaintEditor />
+        <IntlProvider>
+            <PaintEditor />
+        </IntlProvider>
     </Provider>
 ), appTarget);
diff --git a/src/reducers/combine-reducers.js b/src/reducers/combine-reducers.js
index 31cfccc0..cc1b15c8 100644
--- a/src/reducers/combine-reducers.js
+++ b/src/reducers/combine-reducers.js
@@ -1,9 +1,11 @@
 import {combineReducers} from 'redux';
+import intlReducer from './intl';
 import modeReducer from './modes';
 import brushModeReducer from './brush-mode';
 import eraserModeReducer from './eraser-mode';
 
 export default combineReducers({
+    intl: intlReducer,
     mode: modeReducer,
     brushMode: brushModeReducer,
     eraserMode: eraserModeReducer
diff --git a/src/reducers/intl.js b/src/reducers/intl.js
new file mode 100644
index 00000000..51bce5e5
--- /dev/null
+++ b/src/reducers/intl.js
@@ -0,0 +1,30 @@
+import {addLocaleData} from 'react-intl';
+import {updateIntl as superUpdateIntl} from 'react-intl-redux';
+import {IntlProvider, intlReducer} from 'react-intl-redux';
+
+import locales from '../locale.js';
+
+Object.keys(locales).forEach(locale => {
+    // TODO: will need to handle locales not in the default intl - see www/custom-locales
+    addLocaleData(locales[locale].localeData);
+});
+
+const intlInitialState = {
+    intl: {
+        defaultLocale: 'en',
+        locale: 'en',
+        messages: locales.en.messages
+    }
+};
+
+const updateIntl = locale => superUpdateIntl({
+    locale: locale,
+    messages: locales[locale].messages || locales.en.messages
+});
+
+export {
+    intlReducer as default,
+    IntlProvider,
+    intlInitialState,
+    updateIntl
+};
diff --git a/translations/en.json b/translations/en.json
new file mode 100644
index 00000000..0e87a183
--- /dev/null
+++ b/translations/en.json
@@ -0,0 +1,10 @@
+{
+  "paint.brushMode.brush": {
+    "message": "Brush",
+    "description": "Label for the brush tool"
+  },
+  "paint.eraserMode.eraser": {
+    "message": "Eraser",
+    "description": "Label for the eraser tool"
+  }
+}
\ No newline at end of file
diff --git a/translations/messages/src/components/brush-mode.json b/translations/messages/src/components/brush-mode.json
new file mode 100644
index 00000000..fb8440ae
--- /dev/null
+++ b/translations/messages/src/components/brush-mode.json
@@ -0,0 +1,7 @@
+[
+  {
+    "id": "paint.brushMode.brush",
+    "description": "Label for the brush tool",
+    "defaultMessage": "Brush"
+  }
+]
\ No newline at end of file
diff --git a/translations/messages/src/components/eraser-mode.json b/translations/messages/src/components/eraser-mode.json
new file mode 100644
index 00000000..8cd5b6a3
--- /dev/null
+++ b/translations/messages/src/components/eraser-mode.json
@@ -0,0 +1,7 @@
+[
+  {
+    "id": "paint.eraserMode.eraser",
+    "description": "Label for the eraser tool",
+    "defaultMessage": "Eraser"
+  }
+]
\ No newline at end of file

From 8c0d69560a0513dbd5ef44ddc3df0802565438ab Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Mon, 21 Aug 2017 18:01:41 -0400
Subject: [PATCH 2/7] newlines

---
 .eslintignore                                         | 2 +-
 translations/en.json                                  | 2 +-
 translations/messages/src/components/brush-mode.json  | 2 +-
 translations/messages/src/components/eraser-mode.json | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.eslintignore b/.eslintignore
index 07a71bce..217e2872 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,4 @@
 node_modules/*
 dist/*
 playground/
-scripts/*
\ No newline at end of file
+scripts/*
diff --git a/translations/en.json b/translations/en.json
index 0e87a183..46b77f95 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -7,4 +7,4 @@
     "message": "Eraser",
     "description": "Label for the eraser tool"
   }
-}
\ No newline at end of file
+}
diff --git a/translations/messages/src/components/brush-mode.json b/translations/messages/src/components/brush-mode.json
index fb8440ae..cc898d9b 100644
--- a/translations/messages/src/components/brush-mode.json
+++ b/translations/messages/src/components/brush-mode.json
@@ -4,4 +4,4 @@
     "description": "Label for the brush tool",
     "defaultMessage": "Brush"
   }
-]
\ No newline at end of file
+]
diff --git a/translations/messages/src/components/eraser-mode.json b/translations/messages/src/components/eraser-mode.json
index 8cd5b6a3..5ba35343 100644
--- a/translations/messages/src/components/eraser-mode.json
+++ b/translations/messages/src/components/eraser-mode.json
@@ -4,4 +4,4 @@
     "description": "Label for the eraser tool",
     "defaultMessage": "Eraser"
   }
-]
\ No newline at end of file
+]

From ac024c6c6b4f0d7baa997b43c84513ab58db6278 Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Tue, 22 Aug 2017 15:57:12 -0400
Subject: [PATCH 3/7] make helper mouse functions have consistent interface

---
 src/containers/blob/blob.js                 | 6 +++---
 src/containers/blob/broad-brush-helper.js   | 2 +-
 src/containers/blob/segment-brush-helper.js | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/containers/blob/blob.js b/src/containers/blob/blob.js
index c3c9c2ca..b06199b8 100644
--- a/src/containers/blob/blob.js
+++ b/src/containers/blob/blob.js
@@ -82,9 +82,9 @@ class Blobbiness {
             blob.resizeCursorIfNeeded(event.point);
             if (event.event.button > 0) return;  // only first mouse button
             if (blob.brush === Blobbiness.BROAD) {
-                blob.broadBrushHelper.onBroadMouseDrag(event, blob.options);
+                blob.broadBrushHelper.onBroadMouseDrag(event, blob.tool, blob.options);
             } else if (blob.brush === Blobbiness.SEGMENT) {
-                blob.segmentBrushHelper.onSegmentMouseDrag(event, blob.options);
+                blob.segmentBrushHelper.onSegmentMouseDrag(event, blob.tool, blob.options);
             } else {
                 log.warn(`Brush type does not exist: ${blob.brush}`);
             }
@@ -102,7 +102,7 @@ class Blobbiness {
             if (blob.brush === Blobbiness.BROAD) {
                 lastPath = blob.broadBrushHelper.onBroadMouseUp(event, blob.tool, blob.options);
             } else if (blob.brush === Blobbiness.SEGMENT) {
-                lastPath = blob.segmentBrushHelper.onSegmentMouseUp(event);
+                lastPath = blob.segmentBrushHelper.onSegmentMouseUp(event, blob.tool, blob.options);
             } else {
                 log.warn(`Brush type does not exist: ${blob.brush}`);
             }
diff --git a/src/containers/blob/broad-brush-helper.js b/src/containers/blob/broad-brush-helper.js
index f4cf735c..b3bc1ca3 100644
--- a/src/containers/blob/broad-brush-helper.js
+++ b/src/containers/blob/broad-brush-helper.js
@@ -30,7 +30,7 @@ class BroadBrushHelper {
         this.lastPoint = this.secondLastPoint = event.point;
     }
     
-    onBroadMouseDrag (event, options) {
+    onBroadMouseDrag (event, tool, options) {
         const step = (event.delta).normalize(options.brushSize / 2);
 
         // Move the first point out away from the drag so that the end of the path is rounded
diff --git a/src/containers/blob/segment-brush-helper.js b/src/containers/blob/segment-brush-helper.js
index 8b716d50..88f7debd 100644
--- a/src/containers/blob/segment-brush-helper.js
+++ b/src/containers/blob/segment-brush-helper.js
@@ -36,7 +36,7 @@ class SegmentBrushHelper {
         this.lastPoint = event.point;
     }
     
-    onSegmentMouseDrag (event, options) {
+    onSegmentMouseDrag (event, tool, options) {
         if (event.event.button > 0) return;  // only first mouse button
 
         const step = (event.delta).normalize(options.brushSize / 2);

From 9521203e19da4322f707df57941895ada6a60a29 Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Tue, 22 Aug 2017 18:20:47 -0400
Subject: [PATCH 4/7] move the intl stuff to playground

---
 src/containers/brush-mode.jsx                             | 4 ++--
 src/containers/eraser-mode.jsx                            | 4 ++--
 src/index.js                                              | 6 +++++-
 src/playground/playground.jsx                             | 4 ++--
 src/playground/reducers/combine-reducers.js               | 8 ++++++++
 src/{ => playground}/reducers/intl.js                     | 2 +-
 .../{combine-reducers.js => scratch-paint-reducer.js}     | 2 --
 translations/messages/src/components/brush-mode.json      | 2 +-
 8 files changed, 21 insertions(+), 11 deletions(-)
 create mode 100644 src/playground/reducers/combine-reducers.js
 rename src/{ => playground}/reducers/intl.js (94%)
 rename src/reducers/{combine-reducers.js => scratch-paint-reducer.js} (83%)

diff --git a/src/containers/brush-mode.jsx b/src/containers/brush-mode.jsx
index cc33de75..cd1164ac 100644
--- a/src/containers/brush-mode.jsx
+++ b/src/containers/brush-mode.jsx
@@ -74,8 +74,8 @@ BrushMode.propTypes = {
 };
 
 const mapStateToProps = state => ({
-    brushModeState: state.brushMode,
-    isBrushModeActive: state.mode === Modes.BRUSH
+    brushModeState: state.scratchPaint.brushMode,
+    isBrushModeActive: state.scratchPaint.mode === Modes.BRUSH
 });
 const mapDispatchToProps = dispatch => ({
     changeBrushSize: brushSize => {
diff --git a/src/containers/eraser-mode.jsx b/src/containers/eraser-mode.jsx
index 96e02c03..bfab0469 100644
--- a/src/containers/eraser-mode.jsx
+++ b/src/containers/eraser-mode.jsx
@@ -70,8 +70,8 @@ EraserMode.propTypes = {
 };
 
 const mapStateToProps = state => ({
-    eraserModeState: state.eraserMode,
-    isEraserModeActive: state.mode === Modes.ERASER
+    eraserModeState: state.scratchPaint.eraserMode,
+    isEraserModeActive: state.scratchPaint.mode === Modes.ERASER
 });
 const mapDispatchToProps = dispatch => ({
     changeBrushSize: brushSize => {
diff --git a/src/index.js b/src/index.js
index 6611b719..b7d91a70 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,3 +1,7 @@
 import PaintEditor from './containers/paint-editor.jsx';
+import ScratchPaintReducer from './reducers/scratch-paint-reducer';
 
-export default PaintEditor;
+export {
+    PaintEditor as default,
+    ScratchPaintReducer
+};
diff --git a/src/playground/playground.jsx b/src/playground/playground.jsx
index 7249b454..9f68704a 100644
--- a/src/playground/playground.jsx
+++ b/src/playground/playground.jsx
@@ -3,8 +3,8 @@ import ReactDOM from 'react-dom';
 import PaintEditor from '..';
 import {Provider} from 'react-redux';
 import {createStore} from 'redux';
-import reducer from '../reducers/combine-reducers';
-import {intlInitialState, IntlProvider} from '../reducers/intl.js';
+import reducer from './reducers/combine-reducers';
+import {intlInitialState, IntlProvider} from './reducers/intl.js';
 
 const appTarget = document.createElement('div');
 document.body.appendChild(appTarget);
diff --git a/src/playground/reducers/combine-reducers.js b/src/playground/reducers/combine-reducers.js
new file mode 100644
index 00000000..e3182b5e
--- /dev/null
+++ b/src/playground/reducers/combine-reducers.js
@@ -0,0 +1,8 @@
+import {combineReducers} from 'redux';
+import intlReducer from './intl';
+import {ScratchPaintReducer} from '../..';
+
+export default combineReducers({
+    intl: intlReducer,
+    scratchPaint: ScratchPaintReducer
+});
diff --git a/src/reducers/intl.js b/src/playground/reducers/intl.js
similarity index 94%
rename from src/reducers/intl.js
rename to src/playground/reducers/intl.js
index 51bce5e5..a9d43eda 100644
--- a/src/reducers/intl.js
+++ b/src/playground/reducers/intl.js
@@ -2,7 +2,7 @@ import {addLocaleData} from 'react-intl';
 import {updateIntl as superUpdateIntl} from 'react-intl-redux';
 import {IntlProvider, intlReducer} from 'react-intl-redux';
 
-import locales from '../locale.js';
+import locales from '../../locale.js';
 
 Object.keys(locales).forEach(locale => {
     // TODO: will need to handle locales not in the default intl - see www/custom-locales
diff --git a/src/reducers/combine-reducers.js b/src/reducers/scratch-paint-reducer.js
similarity index 83%
rename from src/reducers/combine-reducers.js
rename to src/reducers/scratch-paint-reducer.js
index cc1b15c8..31cfccc0 100644
--- a/src/reducers/combine-reducers.js
+++ b/src/reducers/scratch-paint-reducer.js
@@ -1,11 +1,9 @@
 import {combineReducers} from 'redux';
-import intlReducer from './intl';
 import modeReducer from './modes';
 import brushModeReducer from './brush-mode';
 import eraserModeReducer from './eraser-mode';
 
 export default combineReducers({
-    intl: intlReducer,
     mode: modeReducer,
     brushMode: brushModeReducer,
     eraserMode: eraserModeReducer
diff --git a/translations/messages/src/components/brush-mode.json b/translations/messages/src/components/brush-mode.json
index cc898d9b..fb8440ae 100644
--- a/translations/messages/src/components/brush-mode.json
+++ b/translations/messages/src/components/brush-mode.json
@@ -4,4 +4,4 @@
     "description": "Label for the brush tool",
     "defaultMessage": "Brush"
   }
-]
+]
\ No newline at end of file

From 1661e86d7c3d8dbd7c93360421e886ab3dd1dd3c Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Wed, 23 Aug 2017 13:35:26 -0400
Subject: [PATCH 5/7] newline

---
 locale/messages.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locale/messages.json b/locale/messages.json
index 490c8631..fe18f10b 100644
--- a/locale/messages.json
+++ b/locale/messages.json
@@ -3,4 +3,4 @@
     "paint.brushMode.brush": "Brush",
     "paint.eraserMode.eraser": "Eraser"
   }
-}
\ No newline at end of file
+}

From fd651a6fbbd397fb49db63443c9811b7741ef72e Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Wed, 23 Aug 2017 17:11:44 -0400
Subject: [PATCH 6/7] ignore generated folders

---
 .gitignore | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1b3b3bf7..c6c5feec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,7 @@ dist/*
 # Editors
 /#*
 *~
+
+# generated translation files
+/translations
+/locale

From 5ead61d3389c73c44c03af96bcaa25b1fc45eacb Mon Sep 17 00:00:00 2001
From: DD Liu <liudi@media.mit.edu>
Date: Wed, 23 Aug 2017 17:13:45 -0400
Subject: [PATCH 7/7] remove generated folders

---
 locale/messages.json                                  |  6 ------
 translations/en.json                                  | 10 ----------
 translations/messages/src/components/brush-mode.json  |  7 -------
 translations/messages/src/components/eraser-mode.json |  7 -------
 4 files changed, 30 deletions(-)
 delete mode 100644 locale/messages.json
 delete mode 100644 translations/en.json
 delete mode 100644 translations/messages/src/components/brush-mode.json
 delete mode 100644 translations/messages/src/components/eraser-mode.json

diff --git a/locale/messages.json b/locale/messages.json
deleted file mode 100644
index fe18f10b..00000000
--- a/locale/messages.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "en": {
-    "paint.brushMode.brush": "Brush",
-    "paint.eraserMode.eraser": "Eraser"
-  }
-}
diff --git a/translations/en.json b/translations/en.json
deleted file mode 100644
index 46b77f95..00000000
--- a/translations/en.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "paint.brushMode.brush": {
-    "message": "Brush",
-    "description": "Label for the brush tool"
-  },
-  "paint.eraserMode.eraser": {
-    "message": "Eraser",
-    "description": "Label for the eraser tool"
-  }
-}
diff --git a/translations/messages/src/components/brush-mode.json b/translations/messages/src/components/brush-mode.json
deleted file mode 100644
index fb8440ae..00000000
--- a/translations/messages/src/components/brush-mode.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
-  {
-    "id": "paint.brushMode.brush",
-    "description": "Label for the brush tool",
-    "defaultMessage": "Brush"
-  }
-]
\ No newline at end of file
diff --git a/translations/messages/src/components/eraser-mode.json b/translations/messages/src/components/eraser-mode.json
deleted file mode 100644
index 5ba35343..00000000
--- a/translations/messages/src/components/eraser-mode.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[
-  {
-    "id": "paint.eraserMode.eraser",
-    "description": "Label for the eraser tool",
-    "defaultMessage": "Eraser"
-  }
-]