This is an automated email from the ASF dual-hosted git repository.

johnbodley pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 1473e2c  Integrate translation module @superset-ui/translation (#6222)
1473e2c is described below

commit 1473e2cced916dfd6fc88f15a3c05ecb6300556b
Author: Krist Wongsuphasawat <krist.wo...@gmail.com>
AuthorDate: Tue Oct 30 14:51:44 2018 -0700

    Integrate translation module @superset-ui/translation (#6222)
    
    * add translation modules
    
    * Update package.json
    
    * Update instructions in CONTRIBUTING
    
    * Remove old files
    
    * Add new entry point "translation"
    
    * Change imports
    
    * move setupTranslation code
    
    * remove translation from entry
    
    * Update python template
    
    * Refactor utils into smaller, independent files
    
    * Define preamble
    
    * working state
    
    * combine toggleCheckbox with setupApp
    
    * move code block out of document.ready
    
    * move setupClient to preamble
    
    * fix unit tests
    
    * update package version
    
    * delete deletion code
---
 CONTRIBUTING.md                                    |   4 +-
 superset/assets/package.json                       |   4 +-
 superset/assets/spec/helpers/shim.js               |   2 +
 .../assets/spec/javascripts/modules/utils_spec.jsx |  41 ------
 .../javascripts/utils/getClientErrorObject_spec.js |  41 ++++++
 superset/assets/src/CRUD/CollectionTable.jsx       |   4 +-
 superset/assets/src/SqlLab/App.jsx                 |   4 +-
 superset/assets/src/SqlLab/actions.js              |   6 +-
 .../src/SqlLab/components/ExploreResultsButton.jsx |   2 +-
 .../src/SqlLab/components/HighlightedSql.jsx       |   3 +-
 .../assets/src/SqlLab/components/QueryHistory.jsx  |   2 +-
 .../assets/src/SqlLab/components/QuerySearch.jsx   |   2 +-
 .../assets/src/SqlLab/components/QueryTable.jsx    |   4 +-
 .../assets/src/SqlLab/components/ResultSet.jsx     |   2 +-
 .../src/SqlLab/components/RunQueryActionButton.jsx |   3 +-
 .../assets/src/SqlLab/components/SaveQuery.jsx     |   2 +-
 .../src/SqlLab/components/ShareSqlLabQuery.jsx     |   4 +-
 .../assets/src/SqlLab/components/SouthPane.jsx     |   2 +-
 .../assets/src/SqlLab/components/SqlEditor.jsx     |   3 +-
 .../src/SqlLab/components/SqlEditorLeftBar.jsx     |   2 +-
 .../src/SqlLab/components/TabbedSqlEditors.jsx     |   2 +-
 .../assets/src/SqlLab/components/TableElement.jsx  |   3 +-
 .../src/SqlLab/components/TemplateParamsEditor.jsx |   4 +-
 superset/assets/src/SqlLab/getInitialState.js      |   2 +-
 superset/assets/src/SqlLab/reducers.js             |   4 +-
 superset/assets/src/addSlice/AddSliceContainer.jsx |   2 +-
 superset/assets/src/addSlice/App.jsx               |   4 +-
 superset/assets/src/chart/chartAction.js           |   4 +-
 superset/assets/src/chart/chartReducer.js          |   2 +-
 superset/assets/src/common.js                      |  42 ------
 superset/assets/src/components/AlteredSliceTag.jsx |   3 +-
 superset/assets/src/components/AsyncSelect.jsx     |   2 +-
 superset/assets/src/components/CachedLabel.jsx     |   2 +-
 superset/assets/src/components/CopyToClipboard.jsx |   2 +-
 superset/assets/src/components/EditableTitle.jsx   |   2 +-
 superset/assets/src/components/FaveStar.jsx        |   2 +-
 .../assets/src/components/RefreshChartOverlay.jsx  |   2 +-
 superset/assets/src/components/TableLoader.jsx     |   2 +-
 .../assets/src/components/URLShortLinkButton.jsx   |   2 +-
 .../assets/src/components/URLShortLinkModal.jsx    |   2 +-
 superset/assets/src/dashboard/App.jsx              |   6 +-
 .../assets/src/dashboard/actions/dashboardState.js |   4 +-
 .../assets/src/dashboard/actions/datasources.js    |   2 +-
 .../assets/src/dashboard/actions/sliceEntities.js  |   8 +-
 .../src/dashboard/components/AddSliceCard.jsx      |   2 +-
 .../dashboard/components/BuilderComponentPane.jsx  |   2 +-
 .../assets/src/dashboard/components/CodeModal.jsx  |   2 +-
 .../assets/src/dashboard/components/CssEditor.jsx  |   3 +-
 .../assets/src/dashboard/components/Dashboard.jsx  |   3 +-
 .../dashboard/components/DeleteComponentModal.jsx  |   2 +-
 .../assets/src/dashboard/components/Header.jsx     |   2 +-
 .../dashboard/components/HeaderActionsDropdown.jsx |   2 +-
 .../src/dashboard/components/MissingChart.jsx      |   2 +-
 .../dashboard/components/RefreshIntervalModal.jsx  |   3 +-
 .../assets/src/dashboard/components/SaveModal.jsx  |   4 +-
 .../assets/src/dashboard/components/SliceAdder.jsx |   2 +-
 .../src/dashboard/components/SliceHeader.jsx       |   2 +-
 .../dashboard/components/SliceHeaderControls.jsx   |   4 +-
 .../components/gridComponents/new/NewColumn.jsx    |   2 +-
 .../components/gridComponents/new/NewDivider.jsx   |   2 +-
 .../components/gridComponents/new/NewHeader.jsx    |   2 +-
 .../components/gridComponents/new/NewRow.jsx       |   2 +-
 .../components/gridComponents/new/NewTabs.jsx      |   2 +-
 .../components/menu/MarkdownModeDropdown.jsx       |   2 +-
 .../assets/src/dashboard/reducers/sliceEntities.js |   4 +-
 .../src/dashboard/util/backgroundStyleOptions.js   |   2 +-
 .../src/dashboard/util/headerStyleOptions.js       |   2 +-
 .../assets/src/datasource/DatasourceEditor.jsx     |   3 +-
 superset/assets/src/datasource/DatasourceModal.jsx |   2 +-
 superset/assets/src/explore/App.jsx                |   6 +-
 .../assets/src/explore/actions/exploreActions.js   |   2 +-
 .../AdhocFilterEditPopoverSimpleTabContent.jsx     |   2 +-
 .../AdhocFilterEditPopoverSqlTabContent.jsx        |   2 +-
 .../explore/components/AdhocMetricEditPopover.jsx  |   2 +-
 .../src/explore/components/ControlHeader.jsx       |   2 +-
 .../explore/components/ControlPanelsContainer.jsx  |   3 +-
 .../src/explore/components/DisplayQueryButton.jsx  |   2 +-
 .../src/explore/components/EmbedCodeButton.jsx     |   3 +-
 .../explore/components/ExploreActionButtons.jsx    |   3 +-
 .../src/explore/components/ExploreChartHeader.jsx  |   2 +-
 .../src/explore/components/RowCountLabel.jsx       |   2 +-
 .../assets/src/explore/components/SaveModal.jsx    |   4 +-
 .../components/controls/AdhocFilterControl.jsx     |   2 +-
 .../components/controls/AnnotationLayer.jsx        |   5 +-
 .../components/controls/AnnotationLayerControl.jsx |   4 +-
 .../explore/components/controls/BoundsControl.jsx  |   2 +-
 .../components/controls/DatasourceControl.jsx      |   2 +-
 .../components/controls/DateFilterControl.jsx      |   2 +-
 .../explore/components/controls/MetricsControl.jsx |   3 +-
 .../components/controls/SelectAsyncControl.jsx     |   4 +-
 .../explore/components/controls/SelectControl.jsx  |   3 +-
 .../explore/components/controls/SpatialControl.jsx |   2 +-
 .../components/controls/TextAreaControl.jsx        |   4 +-
 .../explore/components/controls/VizTypeControl.jsx |   3 +-
 superset/assets/src/explore/controls.jsx           |   2 +-
 superset/assets/src/explore/validators.js          |   2 +-
 superset/assets/src/explore/visTypes.jsx           |   3 +-
 superset/assets/src/i18n.jsx                       |  32 -----
 superset/assets/src/locales.jsx                    | 148 ---------------------
 superset/assets/src/modules/utils.js               |  69 +---------
 superset/assets/src/preamble.js                    |  24 ++++
 superset/assets/src/profile/App.jsx                |   4 +-
 superset/assets/src/profile/components/App.jsx     |   3 +-
 .../src/profile/components/CreatedContent.jsx      |   3 +-
 .../assets/src/profile/components/Favorites.jsx    |   3 +-
 .../assets/src/profile/components/Security.jsx     |   2 +-
 .../assets/src/profile/components/UserInfo.jsx     |   2 +-
 superset/assets/src/setup/setupApp.js              |  57 ++++++++
 superset/assets/src/utils/common.js                |  10 +-
 superset/assets/src/utils/errorMessages.js         |   6 +
 superset/assets/src/utils/getClientErrorObject.js  |  40 ++++++
 .../src/visualizations/EventFlow/EventFlow.jsx     |   2 +-
 .../src/visualizations/FilterBox/FilterBox.jsx     |   2 +-
 superset/assets/src/visualizations/PlaySlider.jsx  |   7 +-
 superset/assets/src/visualizations/nvd3/NVD3Vis.js |   2 +-
 superset/assets/src/welcome/App.jsx                |   5 +-
 superset/assets/src/welcome/DashboardTable.jsx     |   4 +-
 superset/assets/src/welcome/Welcome.jsx            |   2 +-
 superset/assets/webpack.config.js                  |  27 ++--
 superset/assets/yarn.lock                          |  43 ++----
 superset/templates/superset/base.html              |  12 +-
 superset/templates/superset/basic.html             |  16 +--
 .../templates/superset/partials/_script_tag.html   |   2 +-
 123 files changed, 360 insertions(+), 552 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index baee1bc..6104c12 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -394,10 +394,10 @@ from flask_babel import lazy_gettext as _
 then wrap our translatable strings with it, e.g. `_('Translate me')`. During 
extraction, string literals passed to `_` will be added to the generated `.po` 
file for each language for later translation.
 At runtime, the `_` function will return the translation of the given string 
for the current language, or the given string itself if no translation is 
available.
 
-In JavaScript, the technique is similar: we import `t` (simple translation), 
`tn` (translation containing a number), and `TCT` (translating entire React 
Components).
+In JavaScript, the technique is similar: we import `t` (simple translation), 
`tn` (translation containing a number).
 
 ```javascript
-import {t, tn, TCT} from locales;
+import {t, tn } from '@superset-ui/translation';
 ```
 
 ### Enabling language selection
diff --git a/superset/assets/package.json b/superset/assets/package.json
index 8293e96..581af12 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -52,6 +52,7 @@
     "@data-ui/theme": "^0.0.62",
     "@data-ui/xy-chart": "^0.0.61",
     "@superset-ui/core": "^0.0.7",
+    "@superset-ui/translation": "^0.2.1",
     "@vx/legend": "^0.0.170",
     "@vx/responsive": "0.0.172",
     "@vx/scale": "^0.0.165",
@@ -78,7 +79,6 @@
     "geojson-extent": "^0.3.2",
     "geolib": "^2.0.24",
     "immutable": "^3.8.2",
-    "jed": "^1.1.1",
     "jquery": "3.1.1",
     "json-bigint": "^0.3.0",
     "lodash": "^4.17.11",
@@ -97,7 +97,6 @@
     "react-bootstrap": "^0.31.5",
     "react-bootstrap-dialog": "^0.10.0",
     "react-bootstrap-slider": "2.1.5",
-    "react-bootstrap-table": "^4.3.1",
     "react-color": "^2.13.8",
     "react-datetime": "^2.14.0",
     "react-dnd": "^2.5.4",
@@ -126,7 +125,6 @@
     "redux-undo": "^1.0.0-beta9-9-7",
     "reselect": "^4.0.0",
     "shortid": "^2.2.6",
-    "sprintf-js": "^1.1.1",
     "srcdoc-polyfill": "^1.0.0",
     "supercluster": "^4.1.1",
     "underscore": "^1.8.3",
diff --git a/superset/assets/spec/helpers/shim.js 
b/superset/assets/spec/helpers/shim.js
index 2884157..a9c2fa9 100644
--- a/superset/assets/spec/helpers/shim.js
+++ b/superset/assets/spec/helpers/shim.js
@@ -4,6 +4,7 @@ import 
'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
 import jsdom from 'jsdom';
 import { configure } from 'enzyme';
 import Adapter from 'enzyme-adapter-react-16';
+import { configure as configureTranslation } from '@superset-ui/translation';
 
 import setupSupersetClient from './setupSupersetClient';
 
@@ -48,4 +49,5 @@ global.window.location = { href: 'about:blank' };
 global.window.performance = { now: () => new Date().getTime() };
 global.$ = require('jquery')(global.window);
 
+configureTranslation();
 setupSupersetClient();
diff --git a/superset/assets/spec/javascripts/modules/utils_spec.jsx 
b/superset/assets/spec/javascripts/modules/utils_spec.jsx
index 46a73ec..d1566c2 100644
--- a/superset/assets/spec/javascripts/modules/utils_spec.jsx
+++ b/superset/assets/spec/javascripts/modules/utils_spec.jsx
@@ -5,7 +5,6 @@ import {
   d3TimeFormatPreset,
   defaultNumberFormatter,
   mainMetric,
-  getClientErrorObject,
 } from '../../../src/modules/utils';
 
 describe('utils', () => {
@@ -98,44 +97,4 @@ describe('utils', () => {
       expect(mainMetric(metrics)).toBe('foo');
     });
   });
-
-  describe('getClientErrorObject', () => {
-    it('Returns a Promise', () => {
-      const response = getClientErrorObject('error');
-      expect(response.constructor === Promise).toBe(true);
-    });
-
-    it('Returns a Promise that resolves to an object with an error key', () => 
{
-      const error = 'error';
-
-      return getClientErrorObject(error).then((errorObj) => {
-        expect(errorObj).toMatchObject({ error });
-      });
-    });
-
-    it('Handles Response that can be parsed as json', () => {
-      const jsonError = { something: 'something', error: 'Error message' };
-      const jsonErrorString = JSON.stringify(jsonError);
-
-      return getClientErrorObject(new 
Response(jsonErrorString)).then((errorObj) => {
-        expect(errorObj).toMatchObject(jsonError);
-      });
-    });
-
-    it('Handles Response that can be parsed as text', () => {
-      const textError = 'Hello I am a text error';
-
-      return getClientErrorObject(new Response(textError)).then((errorObj) => {
-        expect(errorObj).toMatchObject({ error: textError });
-      });
-    });
-
-    it('Handles plain text as input', () => {
-      const error = 'error';
-
-      return getClientErrorObject(error).then((errorObj) => {
-        expect(errorObj).toMatchObject({ error });
-      });
-    });
-  });
 });
diff --git 
a/superset/assets/spec/javascripts/utils/getClientErrorObject_spec.js 
b/superset/assets/spec/javascripts/utils/getClientErrorObject_spec.js
new file mode 100644
index 0000000..2f05021
--- /dev/null
+++ b/superset/assets/spec/javascripts/utils/getClientErrorObject_spec.js
@@ -0,0 +1,41 @@
+import getClientErrorObject from '../../../src/utils/getClientErrorObject';
+
+describe('getClientErrorObject()', () => {
+  it('Returns a Promise', () => {
+    const response = getClientErrorObject('error');
+    expect(response.constructor === Promise).toBe(true);
+  });
+
+  it('Returns a Promise that resolves to an object with an error key', () => {
+    const error = 'error';
+
+    return getClientErrorObject(error).then((errorObj) => {
+      expect(errorObj).toMatchObject({ error });
+    });
+  });
+
+  it('Handles Response that can be parsed as json', () => {
+    const jsonError = { something: 'something', error: 'Error message' };
+    const jsonErrorString = JSON.stringify(jsonError);
+
+    return getClientErrorObject(new Response(jsonErrorString)).then((errorObj) 
=> {
+      expect(errorObj).toMatchObject(jsonError);
+    });
+  });
+
+  it('Handles Response that can be parsed as text', () => {
+    const textError = 'Hello I am a text error';
+
+    return getClientErrorObject(new Response(textError)).then((errorObj) => {
+      expect(errorObj).toMatchObject({ error: textError });
+    });
+  });
+
+  it('Handles plain text as input', () => {
+    const error = 'error';
+
+    return getClientErrorObject(error).then((errorObj) => {
+      expect(errorObj).toMatchObject({ error });
+    });
+  });
+});
diff --git a/superset/assets/src/CRUD/CollectionTable.jsx 
b/superset/assets/src/CRUD/CollectionTable.jsx
index 514f866..f38c3d3 100644
--- a/superset/assets/src/CRUD/CollectionTable.jsx
+++ b/superset/assets/src/CRUD/CollectionTable.jsx
@@ -1,14 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import shortid from 'shortid';
-
+import { t } from '@superset-ui/translation';
 import Button from '../components/Button';
 import Fieldset from './Fieldset';
 import { recurseReactClone } from './utils';
 import './styles.css';
 
-import { t } from '../locales';
-
 const propTypes = {
   collection: PropTypes.arrayOf(PropTypes.object).isRequired,
   itemGenerator: PropTypes.func,
diff --git a/superset/assets/src/SqlLab/App.jsx 
b/superset/assets/src/SqlLab/App.jsx
index 37be951..9e242c3 100644
--- a/superset/assets/src/SqlLab/App.jsx
+++ b/superset/assets/src/SqlLab/App.jsx
@@ -9,13 +9,13 @@ import getInitialState from './getInitialState';
 import rootReducer from './reducers';
 import { initEnhancer } from '../reduxUtils';
 import App from './components/App';
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
 
 import './main.less';
 import '../../stylesheets/reactable-pagination.css';
 import '../components/FilterableTable/FilterableTableStyles.css';
 
-appSetup();
+setupApp();
 
 const appContainer = document.getElementById('app');
 const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/SqlLab/actions.js 
b/superset/assets/src/SqlLab/actions.js
index 6d2b6af..e869014 100644
--- a/superset/assets/src/SqlLab/actions.js
+++ b/superset/assets/src/SqlLab/actions.js
@@ -1,15 +1,15 @@
 import shortid from 'shortid';
 import JSONbig from 'json-bigint';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import { now } from '../modules/dates';
-import { t } from '../locales';
 import {
   addSuccessToast as addSuccessToastAction,
   addDangerToast as addDangerToastAction,
   addInfoToast as addInfoToastAction,
 } from '../messageToasts/actions';
-import { COMMON_ERR_MESSAGES } from '../utils/common';
+import COMMON_ERR_MESSAGES from '../utils/errorMessages';
 
 export const RESET_STATE = 'RESET_STATE';
 export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
@@ -153,7 +153,7 @@ export function runQuery(query) {
       .catch((error) => {
         let message = error.error || error.statusText || t('Unknown error');
         if (message.includes('CSRF token')) {
-          message = COMMON_ERR_MESSAGES.SESSION_TIMED_OUT;
+          message = t(COMMON_ERR_MESSAGES.SESSION_TIMED_OUT);
         }
         // @TODO how to verify link?
         dispatch(queryFailed(query, message, error.link));
diff --git a/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx 
b/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
index 329f731..06cddbc 100644
--- a/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
+++ b/superset/assets/src/SqlLab/components/ExploreResultsButton.jsx
@@ -5,12 +5,12 @@ import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 import { Alert } from 'react-bootstrap';
 import Dialog from 'react-bootstrap-dialog';
+import { t } from '@superset-ui/translation';
 
 import shortid from 'shortid';
 import { exportChart } from '../../explore/exploreUtils';
 import * as actions from '../actions';
 import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
-import { t } from '../../locales';
 import Button from '../../components/Button';
 
 const propTypes = {
diff --git a/superset/assets/src/SqlLab/components/HighlightedSql.jsx 
b/superset/assets/src/SqlLab/components/HighlightedSql.jsx
index 119e8d3..0cce92d 100644
--- a/superset/assets/src/SqlLab/components/HighlightedSql.jsx
+++ b/superset/assets/src/SqlLab/components/HighlightedSql.jsx
@@ -1,12 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-
 import SyntaxHighlighter, { registerLanguage } from 
'react-syntax-highlighter/dist/light';
 import sql from 'react-syntax-highlighter/dist/languages/hljs/sql';
 import github from 'react-syntax-highlighter/dist/styles/hljs/github';
+import { t } from '@superset-ui/translation';
 
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 registerLanguage('sql', sql);
 
diff --git a/superset/assets/src/SqlLab/components/QueryHistory.jsx 
b/superset/assets/src/SqlLab/components/QueryHistory.jsx
index 442bc4c..2c246e4 100644
--- a/superset/assets/src/SqlLab/components/QueryHistory.jsx
+++ b/superset/assets/src/SqlLab/components/QueryHistory.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Alert } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import QueryTable from './QueryTable';
-import { t } from '../../locales';
 
 const propTypes = {
   queries: PropTypes.array.isRequired,
diff --git a/superset/assets/src/SqlLab/components/QuerySearch.jsx 
b/superset/assets/src/SqlLab/components/QuerySearch.jsx
index 9e92029..62d0255 100644
--- a/superset/assets/src/SqlLab/components/QuerySearch.jsx
+++ b/superset/assets/src/SqlLab/components/QuerySearch.jsx
@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Button } from 'react-bootstrap';
 import Select from 'react-select';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import Loading from '../../components/Loading';
@@ -14,7 +15,6 @@ import {
 } from '../../modules/dates';
 import { STATUS_OPTIONS, TIME_OPTIONS } from '../constants';
 import AsyncSelect from '../../components/AsyncSelect';
-import { t } from '../../locales';
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
diff --git a/superset/assets/src/SqlLab/components/QueryTable.jsx 
b/superset/assets/src/SqlLab/components/QueryTable.jsx
index 9e53963..c4dc6c8 100644
--- a/superset/assets/src/SqlLab/components/QueryTable.jsx
+++ b/superset/assets/src/SqlLab/components/QueryTable.jsx
@@ -1,9 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-
 import moment from 'moment';
 import { Table } from 'reactable';
 import { Label, ProgressBar, Well } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import Link from './Link';
 import ResultSet from './ResultSet';
 import ModalTrigger from '../../components/ModalTrigger';
@@ -11,7 +12,6 @@ import HighlightedSql from './HighlightedSql';
 import { fDuration } from '../../modules/dates';
 import { storeQuery } from '../../utils/common';
 import QueryStateLabel from './QueryStateLabel';
-import { t } from '../../locales';
 
 const propTypes = {
   columns: PropTypes.array,
diff --git a/superset/assets/src/SqlLab/components/ResultSet.jsx 
b/superset/assets/src/SqlLab/components/ResultSet.jsx
index 6fa8200..6b482e4 100644
--- a/superset/assets/src/SqlLab/components/ResultSet.jsx
+++ b/superset/assets/src/SqlLab/components/ResultSet.jsx
@@ -2,13 +2,13 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
 import shortid from 'shortid';
+import { t } from '@superset-ui/translation';
 
 import Loading from '../../components/Loading';
 import ExploreResultsButton from './ExploreResultsButton';
 import HighlightedSql from './HighlightedSql';
 import FilterableTable from '../../components/FilterableTable/FilterableTable';
 import QueryStateLabel from './QueryStateLabel';
-import { t } from '../../locales';
 
 const propTypes = {
   actions: PropTypes.object,
diff --git a/superset/assets/src/SqlLab/components/RunQueryActionButton.jsx 
b/superset/assets/src/SqlLab/components/RunQueryActionButton.jsx
index dd1d8b0..a5b8dae 100644
--- a/superset/assets/src/SqlLab/components/RunQueryActionButton.jsx
+++ b/superset/assets/src/SqlLab/components/RunQueryActionButton.jsx
@@ -1,7 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
+
 import Button from '../../components/Button';
-import { t } from '../../locales';
 
 const propTypes = {
   allowAsync: PropTypes.bool.isRequired,
diff --git a/superset/assets/src/SqlLab/components/SaveQuery.jsx 
b/superset/assets/src/SqlLab/components/SaveQuery.jsx
index 007fd57..8b2a28c 100644
--- a/superset/assets/src/SqlLab/components/SaveQuery.jsx
+++ b/superset/assets/src/SqlLab/components/SaveQuery.jsx
@@ -1,10 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { FormControl, FormGroup, Row, Col } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import Button from '../../components/Button';
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   defaultLabel: PropTypes.string,
diff --git a/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx 
b/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx
index 55f8c88..f59129b 100644
--- a/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx
+++ b/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx
@@ -1,12 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Popover, OverlayTrigger } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import Button from '../../components/Button';
 import CopyToClipboard from '../../components/CopyToClipboard';
 import { storeQuery } from '../../utils/common';
-import { getClientErrorObject } from '../../modules/utils';
-import { t } from '../../locales';
+import getClientErrorObject from '../../utils/getClientErrorObject';
 import withToasts from '../../messageToasts/enhancers/withToasts';
 
 const propTypes = {
diff --git a/superset/assets/src/SqlLab/components/SouthPane.jsx 
b/superset/assets/src/SqlLab/components/SouthPane.jsx
index ce81c8d..eddc808 100644
--- a/superset/assets/src/SqlLab/components/SouthPane.jsx
+++ b/superset/assets/src/SqlLab/components/SouthPane.jsx
@@ -4,12 +4,12 @@ import shortid from 'shortid';
 import { Alert, Label, Tab, Tabs } from 'react-bootstrap';
 import { connect } from 'react-redux';
 import { bindActionCreators } from 'redux';
+import { t } from '@superset-ui/translation';
 
 import * as Actions from '../actions';
 import QueryHistory from './QueryHistory';
 import ResultSet from './ResultSet';
 import { STATUS_OPTIONS, STATE_BSSTYLE_MAP } from '../constants';
-import { t } from '../../locales';
 
 /*
     editorQueries are queries executed by users passed from SqlEditor component
diff --git a/superset/assets/src/SqlLab/components/SqlEditor.jsx 
b/superset/assets/src/SqlLab/components/SqlEditor.jsx
index 7f82e02..e739efa 100644
--- a/superset/assets/src/SqlLab/components/SqlEditor.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditor.jsx
@@ -14,6 +14,7 @@ import {
   Collapse,
 } from 'react-bootstrap';
 import SplitPane from 'react-split-pane';
+import { t } from '@superset-ui/translation';
 
 import Button from '../../components/Button';
 import TemplateParamsEditor from './TemplateParamsEditor';
@@ -26,8 +27,6 @@ import SqlEditorLeftBar from './SqlEditorLeftBar';
 import AceEditorWrapper from './AceEditorWrapper';
 import { STATE_BSSTYLE_MAP } from '../constants';
 import RunQueryActionButton from './RunQueryActionButton';
-import { t } from '../../locales';
-
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
diff --git a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx 
b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
index 12530eb..f0b4d1a 100644
--- a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
@@ -4,12 +4,12 @@ import { ControlLabel, Button } from 'react-bootstrap';
 import { connect } from 'react-redux';
 import Select from 'react-virtualized-select';
 import createFilterOptions from 'react-select-fast-filter-options';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import TableElement from './TableElement';
 import AsyncSelect from '../../components/AsyncSelect';
 import RefreshLabel from '../../components/RefreshLabel';
-import { t } from '../../locales';
 
 const propTypes = {
   queryEditor: PropTypes.object.isRequired,
diff --git a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx 
b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
index 9bf3978..43b7354 100644
--- a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -4,11 +4,11 @@ import { DropdownButton, MenuItem, Tab, Tabs } from 
'react-bootstrap';
 import { connect } from 'react-redux';
 import { bindActionCreators } from 'redux';
 import URI from 'urijs';
+import { t } from '@superset-ui/translation';
 
 import * as Actions from '../actions';
 import SqlEditor from './SqlEditor';
 import { areArraysShallowEqual } from '../../reduxUtils';
-import { t } from '../../locales';
 import TabStatusIcon from './TabStatusIcon';
 
 const propTypes = {
diff --git a/superset/assets/src/SqlLab/components/TableElement.jsx 
b/superset/assets/src/SqlLab/components/TableElement.jsx
index 96fae9b..d87d7e5 100644
--- a/superset/assets/src/SqlLab/components/TableElement.jsx
+++ b/superset/assets/src/SqlLab/components/TableElement.jsx
@@ -1,15 +1,14 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-
 import { ButtonGroup, Collapse, Well } from 'react-bootstrap';
 import shortid from 'shortid';
+import { t } from '@superset-ui/translation';
 
 import CopyToClipboard from '../../components/CopyToClipboard';
 import Link from './Link';
 import ColumnElement from './ColumnElement';
 import ModalTrigger from '../../components/ModalTrigger';
 import Loading from '../../components/Loading';
-import { t } from '../../locales';
 
 const propTypes = {
   table: PropTypes.object,
diff --git a/superset/assets/src/SqlLab/components/TemplateParamsEditor.jsx 
b/superset/assets/src/SqlLab/components/TemplateParamsEditor.jsx
index 8a3387a..baed940 100644
--- a/superset/assets/src/SqlLab/components/TemplateParamsEditor.jsx
+++ b/superset/assets/src/SqlLab/components/TemplateParamsEditor.jsx
@@ -1,7 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Badge } from 'react-bootstrap';
-
 import AceEditor from 'react-ace';
 import 'brace/mode/sql';
 import 'brace/mode/json';
@@ -9,10 +8,11 @@ import 'brace/mode/html';
 import 'brace/mode/markdown';
 import 'brace/theme/textmate';
 
+import { t } from '@superset-ui/translation';
+
 import ModalTrigger from '../../components/ModalTrigger';
 import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
 import Button from '../../components/Button';
-import { t } from '../../locales';
 
 const propTypes = {
   onChange: PropTypes.func,
diff --git a/superset/assets/src/SqlLab/getInitialState.js 
b/superset/assets/src/SqlLab/getInitialState.js
index aa98bf1..ba984c2 100644
--- a/superset/assets/src/SqlLab/getInitialState.js
+++ b/superset/assets/src/SqlLab/getInitialState.js
@@ -1,5 +1,5 @@
 import shortid from 'shortid';
-import { t } from '../locales';
+import { t } from '@superset-ui/translation';
 import getToastsFromPyFlashMessages from 
'../messageToasts/utils/getToastsFromPyFlashMessages';
 
 export default function getInitialState({ defaultDbId, ...restBootstrapData }) 
{
diff --git a/superset/assets/src/SqlLab/reducers.js 
b/superset/assets/src/SqlLab/reducers.js
index e1640a5..87d0332 100644
--- a/superset/assets/src/SqlLab/reducers.js
+++ b/superset/assets/src/SqlLab/reducers.js
@@ -1,7 +1,8 @@
 import { combineReducers } from 'redux';
 import shortid from 'shortid';
-import messageToasts from '../messageToasts/reducers';
+import { t } from '@superset-ui/translation';
 
+import messageToasts from '../messageToasts/reducers';
 import getInitialState from './getInitialState';
 import * as actions from './actions';
 import { now } from '../modules/dates';
@@ -13,7 +14,6 @@ import {
   getFromArr,
   addToArr,
 } from '../reduxUtils';
-import { t } from '../locales';
 
 export const sqlLabReducer = function (state = {}, action) {
   const actionHandlers = {
diff --git a/superset/assets/src/addSlice/AddSliceContainer.jsx 
b/superset/assets/src/addSlice/AddSliceContainer.jsx
index 0d876af..f46dbad 100644
--- a/superset/assets/src/addSlice/AddSliceContainer.jsx
+++ b/superset/assets/src/addSlice/AddSliceContainer.jsx
@@ -2,8 +2,8 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Button, Panel } from 'react-bootstrap';
 import Select from 'react-virtualized-select';
+import { t } from '@superset-ui/translation';
 import visTypes from '../explore/visTypes';
-import { t } from '../locales';
 
 const propTypes = {
   datasources: PropTypes.arrayOf(PropTypes.shape({
diff --git a/superset/assets/src/addSlice/App.jsx 
b/superset/assets/src/addSlice/App.jsx
index 56469cc..34154a9 100644
--- a/superset/assets/src/addSlice/App.jsx
+++ b/superset/assets/src/addSlice/App.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
 import { hot } from 'react-hot-loader';
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
 import AddSliceContainer from './AddSliceContainer';
 
-appSetup();
+setupApp();
 
 const addSliceContainer = document.getElementById('js-add-slice-container');
 const bootstrapData = 
JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/chart/chartAction.js 
b/superset/assets/src/chart/chartAction.js
index c26814e..5d5ae24 100644
--- a/superset/assets/src/chart/chartAction.js
+++ b/superset/assets/src/chart/chartAction.js
@@ -1,13 +1,13 @@
 /* global window, AbortController */
 /* eslint no-undef: 'error' */
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 import { getExploreUrlAndPayload, getAnnotationJsonUrl } from 
'../explore/exploreUtils';
 import { requiresQuery, ANNOTATION_SOURCE_TYPES } from 
'../modules/AnnotationTypes';
 import { addDangerToast } from '../messageToasts/actions';
 import { Logger, LOG_ACTIONS_LOAD_CHART } from '../logger';
-import { getClientErrorObject } from '../modules/utils';
 import { TIME_RANGE_SEPARATOR } from '../utils/common';
-import { t } from '../locales';
+import getClientErrorObject from '../utils/getClientErrorObject';
 
 export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
 export function chartUpdateStarted(queryController, latestQueryFormData, key) {
diff --git a/superset/assets/src/chart/chartReducer.js 
b/superset/assets/src/chart/chartReducer.js
index 65df6e5..f6b608c 100644
--- a/superset/assets/src/chart/chartReducer.js
+++ b/superset/assets/src/chart/chartReducer.js
@@ -1,7 +1,7 @@
 /* eslint camelcase: 0 */
+import { t } from '@superset-ui/translation';
 import { now } from '../modules/dates';
 import * as actions from './chartAction';
-import { t } from '../locales';
 
 export const chart = {
   id: 0,
diff --git a/superset/assets/src/common.js b/superset/assets/src/common.js
deleted file mode 100644
index 2dc0488..0000000
--- a/superset/assets/src/common.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* eslint global-require: 0 */
-import $ from 'jquery';
-import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
-import { SupersetClient } from '@superset-ui/core';
-import { toggleCheckbox } from './modules/utils';
-import setupClient from './setup/setupClient';
-import setupColors from './setup/setupColors';
-import setupPlugins from './setup/setupPlugins';
-
-setupColors();
-setupPlugins();
-
-$(document).ready(function () {
-  $(':checkbox[data-checkbox-api-prefix]').change(function () {
-    const $this = $(this);
-    const prefix = $this.data('checkbox-api-prefix');
-    const id = $this.attr('id');
-    toggleCheckbox(prefix, '#' + id);
-  });
-
-  // for language picker dropdown
-  $('#language-picker a').click(function (ev) {
-    ev.preventDefault();
-    SupersetClient.get({
-      endpoint: ev.currentTarget.getAttribute('href'),
-      parseMethod: null,
-    })
-      .then(() => {
-        location.reload();
-      });
-  });
-});
-
-export function appSetup() {
-  setupClient();
-
-  // A set of hacks to allow apps to run within a FAB template
-  // this allows for the server side generated menus to function
-  window.$ = $;
-  window.jQuery = $;
-  require('bootstrap');
-}
diff --git a/superset/assets/src/components/AlteredSliceTag.jsx 
b/superset/assets/src/components/AlteredSliceTag.jsx
index a0c1f1e..bfde6f6 100644
--- a/superset/assets/src/components/AlteredSliceTag.jsx
+++ b/superset/assets/src/components/AlteredSliceTag.jsx
@@ -2,11 +2,10 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Table, Tr, Td, Thead, Th } from 'reactable';
 import { isEqual, isEmpty } from 'lodash';
-
+import { t } from '@superset-ui/translation';
 import TooltipWrapper from './TooltipWrapper';
 import { controls } from '../explore/controls';
 import ModalTrigger from './ModalTrigger';
-import { t } from '../locales';
 
 const propTypes = {
   origFormData: PropTypes.object.isRequired,
diff --git a/superset/assets/src/components/AsyncSelect.jsx 
b/superset/assets/src/components/AsyncSelect.jsx
index 4c2ae81..579535f 100644
--- a/superset/assets/src/components/AsyncSelect.jsx
+++ b/superset/assets/src/components/AsyncSelect.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import Select from 'react-select';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
-import { t } from '../locales';
 
 const propTypes = {
   dataEndpoint: PropTypes.string.isRequired,
diff --git a/superset/assets/src/components/CachedLabel.jsx 
b/superset/assets/src/components/CachedLabel.jsx
index 9bfd037..845eac5 100644
--- a/superset/assets/src/components/CachedLabel.jsx
+++ b/superset/assets/src/components/CachedLabel.jsx
@@ -2,8 +2,8 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Label } from 'react-bootstrap';
 import moment from 'moment';
+import { t } from '@superset-ui/translation';
 import TooltipWrapper from './TooltipWrapper';
-import { t } from '../locales';
 
 const propTypes = {
   onClick: PropTypes.func,
diff --git a/superset/assets/src/components/CopyToClipboard.jsx 
b/superset/assets/src/components/CopyToClipboard.jsx
index c2b9c57..199e8d4 100644
--- a/superset/assets/src/components/CopyToClipboard.jsx
+++ b/superset/assets/src/components/CopyToClipboard.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Tooltip, OverlayTrigger, MenuItem } from 'react-bootstrap';
-import { t } from '../locales';
+import { t } from '@superset-ui/translation';
 
 const propTypes = {
   copyNode: PropTypes.node,
diff --git a/superset/assets/src/components/EditableTitle.jsx 
b/superset/assets/src/components/EditableTitle.jsx
index a3df712..4d71ac7 100644
--- a/superset/assets/src/components/EditableTitle.jsx
+++ b/superset/assets/src/components/EditableTitle.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
+import { t } from '@superset-ui/translation';
 import TooltipWrapper from './TooltipWrapper';
-import { t } from '../locales';
 
 const propTypes = {
   title: PropTypes.string,
diff --git a/superset/assets/src/components/FaveStar.jsx 
b/superset/assets/src/components/FaveStar.jsx
index 60de9d1..cba83db 100644
--- a/superset/assets/src/components/FaveStar.jsx
+++ b/superset/assets/src/components/FaveStar.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
+import { t } from '@superset-ui/translation';
 import TooltipWrapper from './TooltipWrapper';
-import { t } from '../locales';
 
 const propTypes = {
   itemId: PropTypes.number.isRequired,
diff --git a/superset/assets/src/components/RefreshChartOverlay.jsx 
b/superset/assets/src/components/RefreshChartOverlay.jsx
index 9e3fced..841559a 100644
--- a/superset/assets/src/components/RefreshChartOverlay.jsx
+++ b/superset/assets/src/components/RefreshChartOverlay.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 import Button from '../components/Button';
-import { t } from '../locales';
 
 const propTypes = {
   height: PropTypes.number.isRequired,
diff --git a/superset/assets/src/components/TableLoader.jsx 
b/superset/assets/src/components/TableLoader.jsx
index 2f57ab8..0d31934 100644
--- a/superset/assets/src/components/TableLoader.jsx
+++ b/superset/assets/src/components/TableLoader.jsx
@@ -1,10 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Table, Tr, Td } from 'reactable';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import withToasts from '../messageToasts/enhancers/withToasts';
-import { t } from '../locales';
 import Loading from '../components/Loading';
 import '../../stylesheets/reactable-pagination.css';
 
diff --git a/superset/assets/src/components/URLShortLinkButton.jsx 
b/superset/assets/src/components/URLShortLinkButton.jsx
index 47fd332..c2072db 100644
--- a/superset/assets/src/components/URLShortLinkButton.jsx
+++ b/superset/assets/src/components/URLShortLinkButton.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Popover, OverlayTrigger } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 import CopyToClipboard from './CopyToClipboard';
 import { getShortUrl } from '../utils/common';
-import { t } from '../locales';
 import withToasts from '../messageToasts/enhancers/withToasts';
 
 const propTypes = {
diff --git a/superset/assets/src/components/URLShortLinkModal.jsx 
b/superset/assets/src/components/URLShortLinkModal.jsx
index 907b239..1ad4d21 100644
--- a/superset/assets/src/components/URLShortLinkModal.jsx
+++ b/superset/assets/src/components/URLShortLinkModal.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 import CopyToClipboard from './CopyToClipboard';
 import { getShortUrl } from '../utils/common';
-import { t } from '../locales';
 import withToasts from '../messageToasts/enhancers/withToasts';
 import ModalTrigger from './ModalTrigger';
 
diff --git a/superset/assets/src/dashboard/App.jsx 
b/superset/assets/src/dashboard/App.jsx
index a1d8f2e..865803b 100644
--- a/superset/assets/src/dashboard/App.jsx
+++ b/superset/assets/src/dashboard/App.jsx
@@ -6,12 +6,14 @@ import { hot } from 'react-hot-loader';
 
 import { initFeatureFlags } from 'src/featureFlags';
 import { initEnhancer } from '../reduxUtils';
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
+import setupPlugins from '../setup/setupPlugins';
 import DashboardContainer from './containers/Dashboard';
 import getInitialState from './reducers/getInitialState';
 import rootReducer from './reducers/index';
 
-appSetup();
+setupApp();
+setupPlugins();
 
 const appContainer = document.getElementById('app');
 const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/dashboard/actions/dashboardState.js 
b/superset/assets/src/dashboard/actions/dashboardState.js
index 2ff139f..6fed016 100644
--- a/superset/assets/src/dashboard/actions/dashboardState.js
+++ b/superset/assets/src/dashboard/actions/dashboardState.js
@@ -1,19 +1,19 @@
 /* eslint camelcase: 0 */
 import { ActionCreators as UndoActionCreators } from 'redux-undo';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import { addChart, removeChart, refreshChart } from '../../chart/chartAction';
 import { chart as initChart } from '../../chart/chartReducer';
 import { fetchDatasourceMetadata } from '../../dashboard/actions/datasources';
 import { applyDefaultFormData } from '../../explore/store';
-import { getClientErrorObject } from '../../modules/utils';
+import getClientErrorObject from '../../utils/getClientErrorObject';
 import {
   Logger,
   LOG_ACTIONS_CHANGE_DASHBOARD_FILTER,
   LOG_ACTIONS_REFRESH_DASHBOARD,
 } from '../../logger';
 import { SAVE_TYPE_OVERWRITE } from '../util/constants';
-import { t } from '../../locales';
 import {
   addSuccessToast,
   addWarningToast,
diff --git a/superset/assets/src/dashboard/actions/datasources.js 
b/superset/assets/src/dashboard/actions/datasources.js
index 85d91bd..f5e8a48 100644
--- a/superset/assets/src/dashboard/actions/datasources.js
+++ b/superset/assets/src/dashboard/actions/datasources.js
@@ -1,5 +1,5 @@
 import { SupersetClient } from '@superset-ui/core';
-import { getClientErrorObject } from '../../modules/utils';
+import getClientErrorObject from '../../utils/getClientErrorObject';
 
 export const SET_DATASOURCE = 'SET_DATASOURCE';
 export function setDatasource(datasource, key) {
diff --git a/superset/assets/src/dashboard/actions/sliceEntities.js 
b/superset/assets/src/dashboard/actions/sliceEntities.js
index 31a03db..6194327 100644
--- a/superset/assets/src/dashboard/actions/sliceEntities.js
+++ b/superset/assets/src/dashboard/actions/sliceEntities.js
@@ -1,12 +1,10 @@
 /* eslint camelcase: 0 */
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import { addDangerToast } from '../../messageToasts/actions';
-import { t } from '../../locales';
-import {
-  getDatasourceParameter,
-  getClientErrorObject,
-} from '../../modules/utils';
+import { getDatasourceParameter } from '../../modules/utils';
+import getClientErrorObject from '../../utils/getClientErrorObject';
 
 export const SET_ALL_SLICES = 'SET_ALL_SLICES';
 export function setAllSlices(slices) {
diff --git a/superset/assets/src/dashboard/components/AddSliceCard.jsx 
b/superset/assets/src/dashboard/components/AddSliceCard.jsx
index a98546c..12f72a2 100644
--- a/superset/assets/src/dashboard/components/AddSliceCard.jsx
+++ b/superset/assets/src/dashboard/components/AddSliceCard.jsx
@@ -1,7 +1,7 @@
 import cx from 'classnames';
 import React from 'react';
 import PropTypes from 'prop-types';
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 
 const propTypes = {
   datasourceLink: PropTypes.string,
diff --git a/superset/assets/src/dashboard/components/BuilderComponentPane.jsx 
b/superset/assets/src/dashboard/components/BuilderComponentPane.jsx
index 4bfb2bb..145dcc3 100644
--- a/superset/assets/src/dashboard/components/BuilderComponentPane.jsx
+++ b/superset/assets/src/dashboard/components/BuilderComponentPane.jsx
@@ -4,6 +4,7 @@ import React from 'react';
 import cx from 'classnames';
 import { StickyContainer, Sticky } from 'react-sticky';
 import { ParentSize } from '@vx/responsive';
+import { t } from '@superset-ui/translation';
 
 import NewColumn from './gridComponents/new/NewColumn';
 import NewDivider from './gridComponents/new/NewDivider';
@@ -12,7 +13,6 @@ import NewRow from './gridComponents/new/NewRow';
 import NewTabs from './gridComponents/new/NewTabs';
 import NewMarkdown from './gridComponents/new/NewMarkdown';
 import SliceAdder from '../containers/SliceAdder';
-import { t } from '../../locales';
 
 const SUPERSET_HEADER_HEIGHT = 59;
 
diff --git a/superset/assets/src/dashboard/components/CodeModal.jsx 
b/superset/assets/src/dashboard/components/CodeModal.jsx
index cc0c9f2..c02f0f5 100644
--- a/superset/assets/src/dashboard/components/CodeModal.jsx
+++ b/superset/assets/src/dashboard/components/CodeModal.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   triggerNode: PropTypes.node.isRequired,
diff --git a/superset/assets/src/dashboard/components/CssEditor.jsx 
b/superset/assets/src/dashboard/components/CssEditor.jsx
index 45ef86d..846ee8a 100644
--- a/superset/assets/src/dashboard/components/CssEditor.jsx
+++ b/superset/assets/src/dashboard/components/CssEditor.jsx
@@ -1,13 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import Select from 'react-select';
-
 import AceEditor from 'react-ace';
 import 'brace/mode/css';
 import 'brace/theme/github';
+import { t } from '@superset-ui/translation';
 
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   initialCss: PropTypes.string,
diff --git a/superset/assets/src/dashboard/components/Dashboard.jsx 
b/superset/assets/src/dashboard/components/Dashboard.jsx
index 20c161b..fffcd69 100644
--- a/superset/assets/src/dashboard/components/Dashboard.jsx
+++ b/superset/assets/src/dashboard/components/Dashboard.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 
 import getChartIdsFromLayout from '../util/getChartIdsFromLayout';
 import DashboardBuilder from '../containers/DashboardBuilder';
@@ -21,8 +22,6 @@ import {
   LOG_ACTIONS_FIRST_DASHBOARD_LOAD,
 } from '../../logger';
 
-import { t } from '../../locales';
-
 import '../stylesheets/index.less';
 
 const propTypes = {
diff --git a/superset/assets/src/dashboard/components/DeleteComponentModal.jsx 
b/superset/assets/src/dashboard/components/DeleteComponentModal.jsx
index ea7721c..6ebdef4 100644
--- a/superset/assets/src/dashboard/components/DeleteComponentModal.jsx
+++ b/superset/assets/src/dashboard/components/DeleteComponentModal.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Button } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   triggerNode: PropTypes.node.isRequired,
diff --git a/superset/assets/src/dashboard/components/Header.jsx 
b/superset/assets/src/dashboard/components/Header.jsx
index 1dfe846..9cdafb8 100644
--- a/superset/assets/src/dashboard/components/Header.jsx
+++ b/superset/assets/src/dashboard/components/Header.jsx
@@ -1,6 +1,7 @@
 /* eslint-env browser */
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 
 import HeaderActionsDropdown from './HeaderActionsDropdown';
 import EditableTitle from '../../components/EditableTitle';
@@ -9,7 +10,6 @@ import FaveStar from '../../components/FaveStar';
 import UndoRedoKeylisteners from './UndoRedoKeylisteners';
 
 import { chartPropShape } from '../util/propShapes';
-import { t } from '../../locales';
 import {
   UNDO_LIMIT,
   SAVE_TYPE_OVERWRITE,
diff --git a/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx 
b/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
index 9967ce0..f97d4c1 100644
--- a/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
+++ b/superset/assets/src/dashboard/components/HeaderActionsDropdown.jsx
@@ -2,13 +2,13 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { SupersetClient } from '@superset-ui/core';
 import { DropdownButton, MenuItem } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import CssEditor from './CssEditor';
 import RefreshIntervalModal from './RefreshIntervalModal';
 import SaveModal from './SaveModal';
 import injectCustomCss from '../util/injectCustomCss';
 import { SAVE_TYPE_NEWDASHBOARD } from '../util/constants';
-import { t } from '../../locales';
 import URLShortLinkModal from '../../components/URLShortLinkModal';
 import getDashboardUrl from '../util/getDashboardUrl';
 
diff --git a/superset/assets/src/dashboard/components/MissingChart.jsx 
b/superset/assets/src/dashboard/components/MissingChart.jsx
index c45c445..56b2800 100644
--- a/superset/assets/src/dashboard/components/MissingChart.jsx
+++ b/superset/assets/src/dashboard/components/MissingChart.jsx
@@ -1,8 +1,8 @@
 import PropTypes from 'prop-types';
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import Loading from '../../components/Loading';
-import { t } from '../../locales';
 
 const propTypes = {
   height: PropTypes.number.isRequired,
diff --git a/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx 
b/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
index 1ed4f82..e5d375a 100644
--- a/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
+++ b/superset/assets/src/dashboard/components/RefreshIntervalModal.jsx
@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import Select from 'react-select';
+import { t } from '@superset-ui/translation';
+
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   triggerNode: PropTypes.node.isRequired,
diff --git a/superset/assets/src/dashboard/components/SaveModal.jsx 
b/superset/assets/src/dashboard/components/SaveModal.jsx
index 2e3d949..f726028 100644
--- a/superset/assets/src/dashboard/components/SaveModal.jsx
+++ b/superset/assets/src/dashboard/components/SaveModal.jsx
@@ -1,10 +1,10 @@
 /* eslint-env browser */
 import React from 'react';
 import PropTypes from 'prop-types';
-
 import { Button, FormControl, FormGroup, Radio } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import ModalTrigger from '../../components/ModalTrigger';
-import { t } from '../../locales';
 import Checkbox from '../../components/Checkbox';
 import { SAVE_TYPE_OVERWRITE, SAVE_TYPE_NEWDASHBOARD } from 
'../util/constants';
 
diff --git a/superset/assets/src/dashboard/components/SliceAdder.jsx 
b/superset/assets/src/dashboard/components/SliceAdder.jsx
index 608cfc1..96b87e9 100644
--- a/superset/assets/src/dashboard/components/SliceAdder.jsx
+++ b/superset/assets/src/dashboard/components/SliceAdder.jsx
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import { DropdownButton, MenuItem } from 'react-bootstrap';
 import { CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
 import SearchInput, { createFilter } from 'react-search-input';
+import { t } from '@superset-ui/translation';
 
 import AddSliceCard from './AddSliceCard';
 import AddSliceDragPreview from './dnd/AddSliceDragPreview';
@@ -12,7 +13,6 @@ import Loading from '../../components/Loading';
 import { CHART_TYPE, NEW_COMPONENT_SOURCE_TYPE } from '../util/componentTypes';
 import { NEW_CHART_ID, NEW_COMPONENTS_SOURCE_ID } from '../util/constants';
 import { slicePropShape } from '../util/propShapes';
-import { t } from '../../locales';
 
 const propTypes = {
   fetchAllSlices: PropTypes.func.isRequired,
diff --git a/superset/assets/src/dashboard/components/SliceHeader.jsx 
b/superset/assets/src/dashboard/components/SliceHeader.jsx
index 7631ba8..325b1fc 100644
--- a/superset/assets/src/dashboard/components/SliceHeader.jsx
+++ b/superset/assets/src/dashboard/components/SliceHeader.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 import EditableTitle from '../../components/EditableTitle';
 import TooltipWrapper from '../../components/TooltipWrapper';
 import SliceHeaderControls from './SliceHeaderControls';
diff --git a/superset/assets/src/dashboard/components/SliceHeaderControls.jsx 
b/superset/assets/src/dashboard/components/SliceHeaderControls.jsx
index b5ee0b8..de412f1 100644
--- a/superset/assets/src/dashboard/components/SliceHeaderControls.jsx
+++ b/superset/assets/src/dashboard/components/SliceHeaderControls.jsx
@@ -2,6 +2,8 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import moment from 'moment';
 import { Dropdown, MenuItem } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import {
   Logger,
   LOG_ACTIONS_EXPLORE_DASHBOARD_CHART,
@@ -9,8 +11,6 @@ import {
   LOG_ACTIONS_REFRESH_CHART,
 } from '../../logger';
 
-import { t } from '../../locales';
-
 const propTypes = {
   slice: PropTypes.object.isRequired,
   isCached: PropTypes.bool,
diff --git 
a/superset/assets/src/dashboard/components/gridComponents/new/NewColumn.jsx 
b/superset/assets/src/dashboard/components/gridComponents/new/NewColumn.jsx
index 4698736..1c691c7 100644
--- a/superset/assets/src/dashboard/components/gridComponents/new/NewColumn.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/new/NewColumn.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import { COLUMN_TYPE } from '../../../util/componentTypes';
 import { NEW_COLUMN_ID } from '../../../util/constants';
 import DraggableNewComponent from './DraggableNewComponent';
-import { t } from '../../../../locales';
 
 export default function DraggableNewColumn() {
   return (
diff --git 
a/superset/assets/src/dashboard/components/gridComponents/new/NewDivider.jsx 
b/superset/assets/src/dashboard/components/gridComponents/new/NewDivider.jsx
index 93518db..939ce6c 100644
--- a/superset/assets/src/dashboard/components/gridComponents/new/NewDivider.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/new/NewDivider.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import { DIVIDER_TYPE } from '../../../util/componentTypes';
 import { NEW_DIVIDER_ID } from '../../../util/constants';
 import DraggableNewComponent from './DraggableNewComponent';
-import { t } from '../../../../locales';
 
 export default function DraggableNewDivider() {
   return (
diff --git 
a/superset/assets/src/dashboard/components/gridComponents/new/NewHeader.jsx 
b/superset/assets/src/dashboard/components/gridComponents/new/NewHeader.jsx
index 8acf853..78ac9dd 100644
--- a/superset/assets/src/dashboard/components/gridComponents/new/NewHeader.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/new/NewHeader.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import { HEADER_TYPE } from '../../../util/componentTypes';
 import { NEW_HEADER_ID } from '../../../util/constants';
 import DraggableNewComponent from './DraggableNewComponent';
-import { t } from '../../../../locales';
 
 export default function DraggableNewHeader() {
   return (
diff --git 
a/superset/assets/src/dashboard/components/gridComponents/new/NewRow.jsx 
b/superset/assets/src/dashboard/components/gridComponents/new/NewRow.jsx
index 7a2ae01..68b0ae0 100644
--- a/superset/assets/src/dashboard/components/gridComponents/new/NewRow.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/new/NewRow.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import { ROW_TYPE } from '../../../util/componentTypes';
 import { NEW_ROW_ID } from '../../../util/constants';
 import DraggableNewComponent from './DraggableNewComponent';
-import { t } from '../../../../locales';
 
 export default function DraggableNewRow() {
   return (
diff --git 
a/superset/assets/src/dashboard/components/gridComponents/new/NewTabs.jsx 
b/superset/assets/src/dashboard/components/gridComponents/new/NewTabs.jsx
index a77b65e..9127c94 100644
--- a/superset/assets/src/dashboard/components/gridComponents/new/NewTabs.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/new/NewTabs.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
+import { t } from '@superset-ui/translation';
 
 import { TABS_TYPE } from '../../../util/componentTypes';
 import { NEW_TABS_ID } from '../../../util/constants';
 import DraggableNewComponent from './DraggableNewComponent';
-import { t } from '../../../../locales';
 
 export default function DraggableNewTabs() {
   return (
diff --git 
a/superset/assets/src/dashboard/components/menu/MarkdownModeDropdown.jsx 
b/superset/assets/src/dashboard/components/menu/MarkdownModeDropdown.jsx
index 10aa932..0be5e6f 100644
--- a/superset/assets/src/dashboard/components/menu/MarkdownModeDropdown.jsx
+++ b/superset/assets/src/dashboard/components/menu/MarkdownModeDropdown.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { t } from '../../../locales';
+import { t } from '@superset-ui/translation';
 
 import PopoverDropdown from './PopoverDropdown';
 
diff --git a/superset/assets/src/dashboard/reducers/sliceEntities.js 
b/superset/assets/src/dashboard/reducers/sliceEntities.js
index a96368a..9f790be 100644
--- a/superset/assets/src/dashboard/reducers/sliceEntities.js
+++ b/superset/assets/src/dashboard/reducers/sliceEntities.js
@@ -1,11 +1,11 @@
+import { t } from '@superset-ui/translation';
+
 import {
   FETCH_ALL_SLICES_FAILED,
   FETCH_ALL_SLICES_STARTED,
   SET_ALL_SLICES,
 } from '../actions/sliceEntities';
 
-import { t } from '../../locales';
-
 export const initSliceEntities = {
   slices: {},
   isLoading: true,
diff --git a/superset/assets/src/dashboard/util/backgroundStyleOptions.js 
b/superset/assets/src/dashboard/util/backgroundStyleOptions.js
index 926e7f1..885801f 100644
--- a/superset/assets/src/dashboard/util/backgroundStyleOptions.js
+++ b/superset/assets/src/dashboard/util/backgroundStyleOptions.js
@@ -1,4 +1,4 @@
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 import { BACKGROUND_TRANSPARENT, BACKGROUND_WHITE } from './constants';
 
 export default [
diff --git a/superset/assets/src/dashboard/util/headerStyleOptions.js 
b/superset/assets/src/dashboard/util/headerStyleOptions.js
index a37bd5f..815b032 100644
--- a/superset/assets/src/dashboard/util/headerStyleOptions.js
+++ b/superset/assets/src/dashboard/util/headerStyleOptions.js
@@ -1,4 +1,4 @@
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 import { SMALL_HEADER, MEDIUM_HEADER, LARGE_HEADER } from './constants';
 
 export default [
diff --git a/superset/assets/src/datasource/DatasourceEditor.jsx 
b/superset/assets/src/datasource/DatasourceEditor.jsx
index 7c7c8d2..98d0c9d 100644
--- a/superset/assets/src/datasource/DatasourceEditor.jsx
+++ b/superset/assets/src/datasource/DatasourceEditor.jsx
@@ -2,10 +2,9 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Alert, Badge, Col, Label, Tabs, Tab, Well } from 'react-bootstrap';
 import shortid from 'shortid';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
-import { t } from '../locales';
-
 import Button from '../components/Button';
 import Loading from '../components/Loading';
 import CheckboxControl from '../explore/components/controls/CheckboxControl';
diff --git a/superset/assets/src/datasource/DatasourceModal.jsx 
b/superset/assets/src/datasource/DatasourceModal.jsx
index 0d4d8e2..0b232d7 100644
--- a/superset/assets/src/datasource/DatasourceModal.jsx
+++ b/superset/assets/src/datasource/DatasourceModal.jsx
@@ -2,9 +2,9 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Alert, Button, Modal } from 'react-bootstrap';
 import Dialog from 'react-bootstrap-dialog';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
-import { t } from '../locales';
 import DatasourceEditor from '../datasource/DatasourceEditor';
 import withToasts from '../messageToasts/enhancers/withToasts';
 
diff --git a/superset/assets/src/explore/App.jsx 
b/superset/assets/src/explore/App.jsx
index 277d34c..e14363e 100644
--- a/superset/assets/src/explore/App.jsx
+++ b/superset/assets/src/explore/App.jsx
@@ -11,11 +11,13 @@ import ExploreViewContainer from 
'./components/ExploreViewContainer';
 import getInitialState from './reducers/getInitialState';
 import rootReducer from './reducers/index';
 
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
+import setupPlugins from '../setup/setupPlugins';
 import './main.css';
 import '../../stylesheets/reactable-pagination.css';
 
-appSetup();
+setupApp();
+setupPlugins();
 
 const exploreViewContainer = document.getElementById('app');
 const bootstrapData = 
JSON.parse(exploreViewContainer.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/explore/actions/exploreActions.js 
b/superset/assets/src/explore/actions/exploreActions.js
index 2323bf2..df792b2 100644
--- a/superset/assets/src/explore/actions/exploreActions.js
+++ b/superset/assets/src/explore/actions/exploreActions.js
@@ -1,7 +1,7 @@
 /* eslint camelcase: 0 */
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 import { addDangerToast } from '../../messageToasts/actions';
-import { t } from '../../locales';
 
 const FAVESTAR_BASE_URL = '/superset/favstar/slice';
 
diff --git 
a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
 
b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
index 84f8fad..5ddbe4a 100644
--- 
a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
+++ 
b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
@@ -2,12 +2,12 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { FormGroup } from 'react-bootstrap';
 import VirtualizedSelect from 'react-virtualized-select';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../AdhocFilter';
 import adhocMetricType from '../propTypes/adhocMetricType';
 import columnType from '../propTypes/columnType';
-import { t } from '../../locales';
 import {
   OPERATORS,
   TABLE_ONLY_OPERATORS,
diff --git 
a/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
 
b/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
index 6e5fe3c..e9c31d9 100644
--- 
a/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
+++ 
b/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
@@ -7,6 +7,7 @@ import 'brace/theme/github';
 import 'brace/ext/language_tools';
 import { FormGroup } from 'react-bootstrap';
 import VirtualizedSelect from 'react-virtualized-select';
+import { t } from '@superset-ui/translation';
 
 import { sqlWords } from '../../SqlLab/components/AceEditorWrapper';
 import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../AdhocFilter';
@@ -14,7 +15,6 @@ import adhocMetricType from '../propTypes/adhocMetricType';
 import columnType from '../propTypes/columnType';
 import OnPasteSelect from '../../components/OnPasteSelect';
 import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
-import { t } from '../../locales';
 
 const propTypes = {
   adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
diff --git a/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx 
b/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx
index 96b0314..73609a0 100644
--- a/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx
+++ b/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx
@@ -7,9 +7,9 @@ import AceEditor from 'react-ace';
 import 'brace/mode/sql';
 import 'brace/theme/github';
 import 'brace/ext/language_tools';
+import { t } from '@superset-ui/translation';
 
 import { AGGREGATES } from '../constants';
-import { t } from '../../locales';
 import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
 import OnPasteSelect from '../../components/OnPasteSelect';
 import AdhocMetricEditPopoverTitle from './AdhocMetricEditPopoverTitle';
diff --git a/superset/assets/src/explore/components/ControlHeader.jsx 
b/superset/assets/src/explore/components/ControlHeader.jsx
index 9dcdc61..eca86c9 100644
--- a/superset/assets/src/explore/components/ControlHeader.jsx
+++ b/superset/assets/src/explore/components/ControlHeader.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 import { ControlLabel, OverlayTrigger, Tooltip } from 'react-bootstrap';
 import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
-import { t } from '../../locales';
 
 const propTypes = {
   name: PropTypes.string,
diff --git a/superset/assets/src/explore/components/ControlPanelsContainer.jsx 
b/superset/assets/src/explore/components/ControlPanelsContainer.jsx
index fba2e57..7730a02 100644
--- a/superset/assets/src/explore/components/ControlPanelsContainer.jsx
+++ b/superset/assets/src/explore/components/ControlPanelsContainer.jsx
@@ -4,13 +4,14 @@ import PropTypes from 'prop-types';
 import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 import { Alert, Tab, Tabs } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import visTypes, { sectionsToRender } from '../visTypes';
 import ControlPanelSection from './ControlPanelSection';
 import ControlRow from './ControlRow';
 import Control from './Control';
 import controls from '../controls';
 import * as actions from '../actions/exploreActions';
-import { t } from '../../locales';
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
diff --git a/superset/assets/src/explore/components/DisplayQueryButton.jsx 
b/superset/assets/src/explore/components/DisplayQueryButton.jsx
index 0029eff..de18adc 100644
--- a/superset/assets/src/explore/components/DisplayQueryButton.jsx
+++ b/superset/assets/src/explore/components/DisplayQueryButton.jsx
@@ -8,6 +8,7 @@ import jsonSyntax from 
'react-syntax-highlighter/languages/hljs/json';
 import github from 'react-syntax-highlighter/styles/hljs/github';
 import { DropdownButton, MenuItem, Row, Col, FormControl } from 
'react-bootstrap';
 import { Table } from 'reactable';
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
 
 import CopyToClipboard from './../../components/CopyToClipboard';
@@ -16,7 +17,6 @@ import { getExploreUrlAndPayload } from '../exploreUtils';
 import Loading from '../../components/Loading';
 import ModalTrigger from './../../components/ModalTrigger';
 import Button from '../../components/Button';
-import { t } from '../../locales';
 import RowCountLabel from './RowCountLabel';
 
 registerLanguage('markdown', markdownSyntax);
diff --git a/superset/assets/src/explore/components/EmbedCodeButton.jsx 
b/superset/assets/src/explore/components/EmbedCodeButton.jsx
index e6cccac..ff28fbb 100644
--- a/superset/assets/src/explore/components/EmbedCodeButton.jsx
+++ b/superset/assets/src/explore/components/EmbedCodeButton.jsx
@@ -1,9 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Popover, OverlayTrigger } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import CopyToClipboard from './../../components/CopyToClipboard';
 import { getExploreLongUrl } from '../exploreUtils';
-import { t } from '../../locales';
 
 const propTypes = {
   latestQueryFormData: PropTypes.object.isRequired,
diff --git a/superset/assets/src/explore/components/ExploreActionButtons.jsx 
b/superset/assets/src/explore/components/ExploreActionButtons.jsx
index 1e60424..6bb059c 100644
--- a/superset/assets/src/explore/components/ExploreActionButtons.jsx
+++ b/superset/assets/src/explore/components/ExploreActionButtons.jsx
@@ -1,10 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
+import { t } from '@superset-ui/translation';
+
 import URLShortLinkButton from '../../components/URLShortLinkButton';
 import EmbedCodeButton from './EmbedCodeButton';
 import DisplayQueryButton from './DisplayQueryButton';
-import { t } from '../../locales';
 import { exportChart, getExploreLongUrl } from '../exploreUtils';
 
 const propTypes = {
diff --git a/superset/assets/src/explore/components/ExploreChartHeader.jsx 
b/superset/assets/src/explore/components/ExploreChartHeader.jsx
index 8c9ea91..3d6eb84 100644
--- a/superset/assets/src/explore/components/ExploreChartHeader.jsx
+++ b/superset/assets/src/explore/components/ExploreChartHeader.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 
 import { chartPropShape } from '../../dashboard/util/propShapes';
 import ExploreActionButtons from './ExploreActionButtons';
@@ -10,7 +11,6 @@ import FaveStar from '../../components/FaveStar';
 import TooltipWrapper from '../../components/TooltipWrapper';
 import Timer from '../../components/Timer';
 import CachedLabel from '../../components/CachedLabel';
-import { t } from '../../locales';
 
 const CHART_STATUS_MAP = {
   failed: 'danger',
diff --git a/superset/assets/src/explore/components/RowCountLabel.jsx 
b/superset/assets/src/explore/components/RowCountLabel.jsx
index 3367d13..1ba2102 100644
--- a/superset/assets/src/explore/components/RowCountLabel.jsx
+++ b/superset/assets/src/explore/components/RowCountLabel.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Label } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
-import { t } from '../../locales';
 import { defaultNumberFormatter } from '../../modules/utils';
 import TooltipWrapper from '../../components/TooltipWrapper';
 
diff --git a/superset/assets/src/explore/components/SaveModal.jsx 
b/superset/assets/src/explore/components/SaveModal.jsx
index 5a16659..930b676 100644
--- a/superset/assets/src/explore/components/SaveModal.jsx
+++ b/superset/assets/src/explore/components/SaveModal.jsx
@@ -2,10 +2,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
-
 import { Modal, Alert, Button, Radio } from 'react-bootstrap';
 import Select from 'react-select';
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
+
 import { supersetURL } from '../../utils/common';
 import { EXPLORE_ONLY_VIZ_TYPE } from '../constants';
 
diff --git 
a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx 
b/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx
index b51704d..95983e5 100644
--- a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx
+++ b/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx
@@ -2,7 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import VirtualizedSelect from 'react-virtualized-select';
 
-import { t } from '../../../locales';
+import { t } from '@superset-ui/translation';
 import ControlHeader from '../ControlHeader';
 import adhocFilterType from '../../propTypes/adhocFilterType';
 import adhocMetricType from '../../propTypes/adhocMetricType';
diff --git 
a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx 
b/superset/assets/src/explore/components/controls/AnnotationLayer.jsx
index e1c4dcf..c2e6c27 100644
--- a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx
+++ b/superset/assets/src/explore/components/controls/AnnotationLayer.jsx
@@ -3,8 +3,9 @@ import PropTypes from 'prop-types';
 import { CompactPicker } from 'react-color';
 import { Button } from 'react-bootstrap';
 import mathjs from 'mathjs';
-
+import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/core';
+
 import SelectControl from './SelectControl';
 import TextControl from './TextControl';
 import CheckboxControl from './CheckboxControl';
@@ -21,8 +22,6 @@ import PopoverSection from 
'../../../components/PopoverSection';
 import ControlHeader from '../ControlHeader';
 import { nonEmpty } from '../../validators';
 import getChartMetadataRegistry from 
'../../../visualizations/core/registries/ChartMetadataRegistrySingleton';
-
-import { t } from '../../../locales';
 import getCategoricalSchemeRegistry from 
'../../../modules/colors/CategoricalSchemeRegistrySingleton';
 
 const AUTOMATIC_COLOR = '';
diff --git 
a/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx 
b/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx
index b33dab0..16eb4e6 100644
--- a/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx
+++ b/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx
@@ -2,14 +2,12 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { OverlayTrigger, Popover, ListGroup, ListGroupItem } from 
'react-bootstrap';
 import { connect } from 'react-redux';
+import { t } from '@superset-ui/translation';
 import { getChartKey } from '../../exploreUtils';
 import { runAnnotationQuery } from '../../../chart/chartAction';
 import InfoTooltipWithTrigger from 
'../../../components/InfoTooltipWithTrigger';
 
-
 import AnnotationLayer from './AnnotationLayer';
-import { t } from '../../../locales';
-
 
 const propTypes = {
   colorScheme: PropTypes.string.isRequired,
diff --git a/superset/assets/src/explore/components/controls/BoundsControl.jsx 
b/superset/assets/src/explore/components/controls/BoundsControl.jsx
index 803a539..d19b11b 100644
--- a/superset/assets/src/explore/components/controls/BoundsControl.jsx
+++ b/superset/assets/src/explore/components/controls/BoundsControl.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Col, Row, FormGroup, FormControl } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 
 const propTypes = {
   onChange: PropTypes.func,
diff --git 
a/superset/assets/src/explore/components/controls/DatasourceControl.jsx 
b/superset/assets/src/explore/components/controls/DatasourceControl.jsx
index cd5ad6b..271eda9 100644
--- a/superset/assets/src/explore/components/controls/DatasourceControl.jsx
+++ b/superset/assets/src/explore/components/controls/DatasourceControl.jsx
@@ -9,9 +9,9 @@ import {
   Tooltip,
   Well,
 } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 import DatasourceModal from '../../../datasource/DatasourceModal';
 import ColumnOption from '../../../components/ColumnOption';
 import MetricOption from '../../../components/MetricOption';
diff --git 
a/superset/assets/src/explore/components/controls/DateFilterControl.jsx 
b/superset/assets/src/explore/components/controls/DateFilterControl.jsx
index c072946..366a954 100644
--- a/superset/assets/src/explore/components/controls/DateFilterControl.jsx
+++ b/superset/assets/src/explore/components/controls/DateFilterControl.jsx
@@ -18,10 +18,10 @@ import {
 import Datetime from 'react-datetime';
 import 'react-datetime/css/react-datetime.css';
 import moment from 'moment';
+import { t } from '@superset-ui/translation';
 
 import './DateFilterControl.css';
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 import PopoverSection from '../../../components/PopoverSection';
 
 const TYPES = Object.freeze({
diff --git a/superset/assets/src/explore/components/controls/MetricsControl.jsx 
b/superset/assets/src/explore/components/controls/MetricsControl.jsx
index 40f73da..7bbb4d1 100644
--- a/superset/assets/src/explore/components/controls/MetricsControl.jsx
+++ b/superset/assets/src/explore/components/controls/MetricsControl.jsx
@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import VirtualizedSelect from 'react-virtualized-select';
+import { t } from '@superset-ui/translation';
+
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 import VirtualizedRendererWrap from 
'../../../components/VirtualizedRendererWrap';
 import OnPasteSelect from '../../../components/OnPasteSelect';
 import MetricDefinitionOption from '../MetricDefinitionOption';
diff --git 
a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx 
b/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
index 2fb778b..b004369 100644
--- a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
+++ b/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
+
 import Select from '../../../components/AsyncSelect';
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-
 import withToasts from '../../../messageToasts/enhancers/withToasts';
 
 const propTypes = {
diff --git a/superset/assets/src/explore/components/controls/SelectControl.jsx 
b/superset/assets/src/explore/components/controls/SelectControl.jsx
index 4f1e8da..9e4dc29 100644
--- a/superset/assets/src/explore/components/controls/SelectControl.jsx
+++ b/superset/assets/src/explore/components/controls/SelectControl.jsx
@@ -2,8 +2,9 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import VirtualizedSelect from 'react-virtualized-select';
 import Select, { Creatable } from 'react-select';
+import { t } from '@superset-ui/translation';
+
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 import VirtualizedRendererWrap from 
'../../../components/VirtualizedRendererWrap';
 import OnPasteSelect from '../../../components/OnPasteSelect';
 
diff --git a/superset/assets/src/explore/components/controls/SpatialControl.jsx 
b/superset/assets/src/explore/components/controls/SpatialControl.jsx
index dac5cb9..5b9f8ac 100644
--- a/superset/assets/src/explore/components/controls/SpatialControl.jsx
+++ b/superset/assets/src/explore/components/controls/SpatialControl.jsx
@@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
 import {
   Row, Col, Button, Label, OverlayTrigger, Popover,
 } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import ControlHeader from '../ControlHeader';
 import SelectControl from './SelectControl';
 import PopoverSection from '../../../components/PopoverSection';
 import Checkbox from '../../../components/Checkbox';
-import { t } from '../../../locales';
 
 const spatialTypes = {
   latlong: 'latlong',
diff --git 
a/superset/assets/src/explore/components/controls/TextAreaControl.jsx 
b/superset/assets/src/explore/components/controls/TextAreaControl.jsx
index 4a500ea..c533804 100644
--- a/superset/assets/src/explore/components/controls/TextAreaControl.jsx
+++ b/superset/assets/src/explore/components/controls/TextAreaControl.jsx
@@ -8,12 +8,12 @@ import 'brace/mode/json';
 import 'brace/mode/html';
 import 'brace/mode/markdown';
 import 'brace/mode/javascript';
-
 import 'brace/theme/textmate';
 
+import { t } from '@superset-ui/translation';
+
 import ControlHeader from '../ControlHeader';
 import ModalTrigger from '../../../components/ModalTrigger';
-import { t } from '../../../locales';
 
 const propTypes = {
   name: PropTypes.string,
diff --git a/superset/assets/src/explore/components/controls/VizTypeControl.jsx 
b/superset/assets/src/explore/components/controls/VizTypeControl.jsx
index 3fb871e..113d3c5 100644
--- a/superset/assets/src/explore/components/controls/VizTypeControl.jsx
+++ b/superset/assets/src/explore/components/controls/VizTypeControl.jsx
@@ -3,9 +3,10 @@ import PropTypes from 'prop-types';
 import {
   Label, Row, Col, FormControl, Modal, OverlayTrigger,
   Tooltip } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import visTypes from '../../visTypes';
 import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
 
 const propTypes = {
   description: PropTypes.string,
diff --git a/superset/assets/src/explore/controls.jsx 
b/superset/assets/src/explore/controls.jsx
index ad32c52..92dfb1c 100644
--- a/superset/assets/src/explore/controls.jsx
+++ b/superset/assets/src/explore/controls.jsx
@@ -39,6 +39,7 @@
  * each and every visualization type.
  */
 import React from 'react';
+import { t } from '@superset-ui/translation';
 import {
   formatSelectOptionsForRange,
   formatSelectOptions,
@@ -49,7 +50,6 @@ import { PRIMARY_COLOR } from '../modules/colors';
 import { defaultViewport } from '../modules/geo';
 import ColumnOption from '../components/ColumnOption';
 import OptionDescription from '../components/OptionDescription';
-import { t } from '../locales';
 import getCategoricalSchemeRegistry from 
'../modules/colors/CategoricalSchemeRegistrySingleton';
 import getSequentialSchemeRegistry from 
'../modules/colors/SequentialSchemeRegistrySingleton';
 
diff --git a/superset/assets/src/explore/validators.js 
b/superset/assets/src/explore/validators.js
index b1625d4..ebf4271 100644
--- a/superset/assets/src/explore/validators.js
+++ b/superset/assets/src/explore/validators.js
@@ -4,7 +4,7 @@
  * as arguments and return something that evals to false if v is valid,
  * and an error message if not valid.
  * */
-import { t } from '../locales';
+import { t } from '@superset-ui/translation';
 
 export function numeric(v) {
   if (v && isNaN(v)) {
diff --git a/superset/assets/src/explore/visTypes.jsx 
b/superset/assets/src/explore/visTypes.jsx
index 30aba88..9a0943c 100644
--- a/superset/assets/src/explore/visTypes.jsx
+++ b/superset/assets/src/explore/visTypes.jsx
@@ -3,10 +3,11 @@
  * and associated with each and every visualization type.
  */
 import React from 'react';
+import { t } from '@superset-ui/translation';
+
 import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
 import { D3_TIME_FORMAT_OPTIONS } from './controls';
 import * as v from './validators';
-import { t } from '../locales';
 
 export const sections = {
   druidTimeSeries: {
diff --git a/superset/assets/src/i18n.jsx b/superset/assets/src/i18n.jsx
deleted file mode 100644
index b27f739..0000000
--- a/superset/assets/src/i18n.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import Jed from 'jed';
-
-const DEFAULT_LANGUAGE_PACK = {
-  domain: 'superset',
-  locale_data: {
-    superset: {
-      '': {
-        domain: 'superset',
-        lang: 'en',
-        plural_forms: 'nplurals=1; plural=0',
-      },
-    },
-  },
-};
-
-const i18n = (function () {
-  let languagePack = DEFAULT_LANGUAGE_PACK;
-
-  if (typeof window !== 'undefined') {
-    const root = document.getElementById('app');
-    const bootstrapData = root ? 
JSON.parse(root.getAttribute('data-bootstrap')) : {};
-    if (bootstrapData.common && bootstrapData.common.language_pack) {
-      languagePack = bootstrapData.common.language_pack;
-      delete bootstrapData.common.locale;
-      delete bootstrapData.common.language_pack;
-    }
-  }
-
-  return new Jed(languagePack);
-}());
-
-export default i18n;
diff --git a/superset/assets/src/locales.jsx b/superset/assets/src/locales.jsx
deleted file mode 100644
index 12b1a87..0000000
--- a/superset/assets/src/locales.jsx
+++ /dev/null
@@ -1,148 +0,0 @@
-/* eslint-disable global-require, import/no-dynamic-require */
-import React from 'react';
-import { sprintf } from 'sprintf-js';
-import i18n from './i18n';
-
-function formatForReact(formatString, args) {
-  const rv = [];
-  let cursor = 0;
-  sprintf.parse(formatString).forEach((match, idx) => {
-    const cpoyMatch = match;
-    let copyIdx = idx;
-    if (typeof match === 'string') {
-      rv.push(match);
-    } else {
-      let arg = null;
-      if (match[2]) {
-        arg = args[0][match[2][0]];
-      } else if (match[1]) {
-        arg = args[parseInt(match[1], 10) - 1];
-      } else {
-        arg = args[cursor++];
-      }
-      if (React.isValidElement(arg)) {
-        rv.push(React.cloneElement(arg, { key: idx }));
-      } else {
-        cpoyMatch[2] = null;
-        cpoyMatch[1] = 1;
-        rv.push(<span key={copyIdx++}>
-          {sprintf.format([cpoyMatch], [null, arg])}
-        </span>);
-      }
-    }
-  });
-  return rv;
-}
-
-function argsInvolveReact(args) {
-  if (args.some(React.isValidElement)) {
-    return true;
-  }
-  if (args.length === 1 && typeof args[0] === 'object') {
-    return Object.keys(args[0]).some(function (key) {
-      return React.isValidElement(args[0][key]);
-    });
-  }
-  return false;
-}
-
-export function parseComponentTemplate(string) {
-  const rv = {};
-  function process(startPos, group, inGroup) {
-    const regex = /\[(.*?)(:|\])|\]/g;
-    let match;
-    const buf = [];
-    let satisfied = false;
-    let pos = regex.lastIndex = startPos;
-    match = regex.exec(string);
-    while (match !== null) {
-      const substr = string.substr(pos, match.index - pos);
-      if (substr !== '') {
-        buf.push(substr);
-      }
-      if (match[0] === ']') {
-        if (inGroup) {
-          satisfied = true;
-          break;
-        } else {
-          pos = regex.lastIndex;
-          continue;
-        }
-      }
-      if (match[2] === ']') {
-        pos = regex.lastIndex;
-      } else {
-        pos = regex.lastIndex = process(regex.lastIndex, match[1], true);
-      }
-      buf.push({ group: match[1] });
-      match = regex.exec(string);
-    }
-    let endPos = regex.lastIndex;
-    if (!satisfied) {
-      const rest = string.substr(pos);
-      if (rest) {
-        buf.push(rest);
-      }
-      endPos = string.length;
-    }
-    rv[group] = buf;
-    return endPos;
-  }
-  process(0, 'root', false);
-  return rv;
-}
-
-export function renderComponentTemplate(template, components) {
-  let idx = 0;
-  function renderGroup(group) {
-    const children = [];
-    (template[group] || []).forEach((item) => {
-      if (typeof item === 'string') {
-        children.push(<span key={idx++}>{item}</span>);
-      } else {
-        children.push(renderGroup(item.group));
-      }
-    });
-    let reference = components[group] || <span key={idx++} />;
-    if (!React.isValidElement(reference)) {
-      reference = <span key={idx++}>{reference}</span>;
-    }
-    if (children.length > 0) {
-      return React.cloneElement(reference, { key: idx++ }, children);
-    }
-    return React.cloneElement(reference, { key: idx++ });
-  }
-  return renderGroup('root');
-}
-
-export function format(formatString, args) {
-  if (argsInvolveReact(args)) {
-    return formatForReact(formatString, args);
-  }
-  return sprintf(formatString, ...args);
-}
-
-export function gettext(string, ...args) {
-  if (!string || !i18n) {
-    return string;
-  }
-
-  let rv = i18n.gettext(string);
-  if (args.length > 0) {
-    rv = format(rv, args);
-  }
-  return rv;
-}
-
-export function ngettext(singular, plural, ...args) {
-  return format(i18n.ngettext(singular, plural, args[0] || 0), args);
-}
-
-export function gettextComponentTemplate(template, components) {
-  const tmpl = parseComponentTemplate(i18n.gettext(template));
-  return renderComponentTemplate(tmpl, components);
-}
-
-export const t = gettext;
-export const tn = ngettext;
-export const tct = gettextComponentTemplate;
diff --git a/superset/assets/src/modules/utils.js 
b/superset/assets/src/modules/utils.js
index 1bb656f..bc22c5a 100644
--- a/superset/assets/src/modules/utils.js
+++ b/superset/assets/src/modules/utils.js
@@ -1,10 +1,7 @@
 /* eslint camelcase: 0 */
-import d3 from 'd3';
 import $ from 'jquery';
-import { SupersetClient } from '@superset-ui/core';
+import d3 from 'd3';
 import { formatDate, UTC } from './dates';
-import { COMMON_ERR_MESSAGES } from '../utils/common';
-import { t } from '../locales';
 
 const siFormatter = d3.format('.3s');
 
@@ -109,70 +106,6 @@ export function showModal(options) {
   $(options.modalSelector).modal('show');
 }
 
-
-function showApiMessage(resp) {
-  const template =
-    '<div class="alert"> ' +
-    '<button type="button" class="close" ' +
-    'data-dismiss="alert">\xD7</button> </div>';
-  const severity = resp.severity || 'info';
-  $(template).addClass('alert-' + severity)
-             .append(resp.message)
-             .appendTo($('#alert-container'));
-}
-
-export function getClientErrorObject(response) {
-  // takes a Response object as input, attempts to read response as Json if 
possible,
-  // and returns a Promise that resolves to a plain object with error key and 
text value.
-  return new Promise((resolve) => {
-    if (typeof response === 'string') {
-      resolve({ error: response });
-    } else if (response && response.constructor === Response && 
!response.bodyUsed) {
-      // attempt to read the body as json, and fallback to text. we must clone 
the
-      // response in order to fallback to .text() because Response is 
single-read
-      response.clone().json().then((errorJson) => {
-        let error = { ...response, ...errorJson };
-        if (error.stack) {
-          error = {
-            ...error,
-            error: t('Unexpected error: ') +
-              (error.description || t('(no description, click to see stack 
trace)')),
-            stacktrace: error.stack,
-          };
-        } else if (error.responseText && error.responseText.indexOf('CSRF') >= 
0) {
-          error = {
-            ...error,
-            error: COMMON_ERR_MESSAGES.SESSION_TIMED_OUT,
-          };
-        }
-        resolve(error);
-      }).catch(() => {
-        // fall back to reading as text
-        response.text().then((errorText) => {
-          resolve({ ...response, error: errorText });
-        });
-      });
-    } else {
-      // fall back to Response.statusText or generic error of we cannot read 
the response
-      resolve({ ...response, error: response.statusText || t('An error 
occurred') });
-    }
-  });
-
-}
-
-export function toggleCheckbox(apiUrlPrefix, selector) {
-  SupersetClient.get({ endpoint: apiUrlPrefix + $(selector)[0].checked })
-    .then(() => {})
-    .catch(response =>
-      getClientErrorObject(response)
-        .then((parsedResp) => {
-          if (parsedResp && parsedResp.message) {
-            showApiMessage(parsedResp);
-          }
-        }),
-      );
-}
-
 /**
  * Fix the height of the table body of a DataTable with scrollY set
  */
diff --git a/superset/assets/src/preamble.js b/superset/assets/src/preamble.js
new file mode 100644
index 0000000..9d80dc9
--- /dev/null
+++ b/superset/assets/src/preamble.js
@@ -0,0 +1,24 @@
+import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
+import { configure } from '@superset-ui/translation';
+import setupClient from './setup/setupClient';
+import setupColors from './setup/setupColors';
+
+// Configure translation
+if (typeof window !== 'undefined') {
+  const root = document.getElementById('app');
+  const bootstrapData = root ? JSON.parse(root.getAttribute('data-bootstrap')) 
: {};
+  if (bootstrapData.common && bootstrapData.common.language_pack) {
+    const languagePack = bootstrapData.common.language_pack;
+    configure({ languagePack });
+  } else {
+    configure();
+  }
+} else {
+  configure();
+}
+
+// Setup SupersetClient
+setupClient();
+
+// Setup color palettes
+setupColors();
diff --git a/superset/assets/src/profile/App.jsx 
b/superset/assets/src/profile/App.jsx
index 3ad5bad..d4e175b 100644
--- a/superset/assets/src/profile/App.jsx
+++ b/superset/assets/src/profile/App.jsx
@@ -7,11 +7,11 @@ import { Provider } from 'react-redux';
 import App from './components/App';
 import messageToastReducer from '../messageToasts/reducers';
 import { initEnhancer } from '../reduxUtils';
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
 
 import './main.css';
 
-appSetup();
+setupApp();
 
 const profileViewContainer = document.getElementById('app');
 const bootstrap = 
JSON.parse(profileViewContainer.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/profile/components/App.jsx 
b/superset/assets/src/profile/components/App.jsx
index 0cb9034..c71f7b2 100644
--- a/superset/assets/src/profile/components/App.jsx
+++ b/superset/assets/src/profile/components/App.jsx
@@ -1,12 +1,13 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Col, Row, Tabs, Tab, Panel } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
+
 import Favorites from './Favorites';
 import UserInfo from './UserInfo';
 import Security from './Security';
 import RecentActivity from './RecentActivity';
 import CreatedContent from './CreatedContent';
-import { t } from '../../locales';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/src/profile/components/CreatedContent.jsx 
b/superset/assets/src/profile/components/CreatedContent.jsx
index 00d0f9d..976162f 100644
--- a/superset/assets/src/profile/components/CreatedContent.jsx
+++ b/superset/assets/src/profile/components/CreatedContent.jsx
@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import moment from 'moment';
+import { t } from '@superset-ui/translation';
+
 import TableLoader from '../../components/TableLoader';
-import { t } from '../../locales';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/src/profile/components/Favorites.jsx 
b/superset/assets/src/profile/components/Favorites.jsx
index e0ef112..c6eb3e7 100644
--- a/superset/assets/src/profile/components/Favorites.jsx
+++ b/superset/assets/src/profile/components/Favorites.jsx
@@ -1,8 +1,9 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import moment from 'moment';
+import { t } from '@superset-ui/translation';
+
 import TableLoader from '../../components/TableLoader';
-import { t } from '../../locales';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/src/profile/components/Security.jsx 
b/superset/assets/src/profile/components/Security.jsx
index 748be6b..4783119 100644
--- a/superset/assets/src/profile/components/Security.jsx
+++ b/superset/assets/src/profile/components/Security.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Badge, Label } from 'react-bootstrap';
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/src/profile/components/UserInfo.jsx 
b/superset/assets/src/profile/components/UserInfo.jsx
index 4cc54be..9bd61be 100644
--- a/superset/assets/src/profile/components/UserInfo.jsx
+++ b/superset/assets/src/profile/components/UserInfo.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import Gravatar from 'react-gravatar';
 import moment from 'moment';
 import { Panel } from 'react-bootstrap';
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/src/setup/setupApp.js 
b/superset/assets/src/setup/setupApp.js
new file mode 100644
index 0000000..7d2fda2
--- /dev/null
+++ b/superset/assets/src/setup/setupApp.js
@@ -0,0 +1,57 @@
+/* eslint global-require: 0 */
+import $ from 'jquery';
+import { SupersetClient } from '@superset-ui/core';
+import getClientErrorObject from '../utils/getClientErrorObject';
+
+function showApiMessage(resp) {
+  const template =
+    '<div class="alert"> ' +
+    '<button type="button" class="close" ' +
+    'data-dismiss="alert">\xD7</button> </div>';
+  const severity = resp.severity || 'info';
+  $(template).addClass('alert-' + severity)
+    .append(resp.message)
+    .appendTo($('#alert-container'));
+}
+
+function toggleCheckbox(apiUrlPrefix, selector) {
+  SupersetClient.get({ endpoint: apiUrlPrefix + $(selector)[0].checked })
+    .then(() => {})
+    .catch(response =>
+      getClientErrorObject(response)
+        .then((parsedResp) => {
+          if (parsedResp && parsedResp.message) {
+            showApiMessage(parsedResp);
+          }
+        }),
+      );
+}
+
+export default function setupApp() {
+  $(document).ready(function () {
+    $(':checkbox[data-checkbox-api-prefix]').change(function () {
+      const $this = $(this);
+      const prefix = $this.data('checkbox-api-prefix');
+      const id = $this.attr('id');
+      toggleCheckbox(prefix, '#' + id);
+    });
+
+    // for language picker dropdown
+    $('#language-picker a').click(function (ev) {
+      ev.preventDefault();
+      SupersetClient.get({
+        endpoint: ev.currentTarget.getAttribute('href'),
+        parseMethod: null,
+      })
+        .then(() => {
+          location.reload();
+        });
+    });
+  });
+
+  // A set of hacks to allow apps to run within a FAB template
+  // this allows for the server side generated menus to function
+  window.$ = $;
+  window.jQuery = $;
+  require('bootstrap');
+}
diff --git a/superset/assets/src/utils/common.js 
b/superset/assets/src/utils/common.js
index 9fbe35b..a22ca9a 100644
--- a/superset/assets/src/utils/common.js
+++ b/superset/assets/src/utils/common.js
@@ -1,8 +1,5 @@
-/* eslint global-require: 0 */
+import d3 from 'd3';
 import { SupersetClient } from '@superset-ui/core';
-import { t } from '../locales';
-
-const d3 = require('d3');
 
 export const EARTH_CIRCUMFERENCE_KM = 40075.16;
 export const LUMINANCE_RED_WEIGHT = 0.2126;
@@ -113,10 +110,5 @@ export function optionFromValue(opt) {
   return { value: optionValue(opt), label: optionLabel(opt) };
 }
 
-// Error messages used in many places across applications
-export const COMMON_ERR_MESSAGES = {
-  SESSION_TIMED_OUT: t('Your session timed out, please refresh your page and 
try again.'),
-};
-
 // time_range separator
 export const TIME_RANGE_SEPARATOR = ' : ';
diff --git a/superset/assets/src/utils/errorMessages.js 
b/superset/assets/src/utils/errorMessages.js
new file mode 100644
index 0000000..70117b2
--- /dev/null
+++ b/superset/assets/src/utils/errorMessages.js
@@ -0,0 +1,6 @@
+// Error messages used in many places across applications
+const COMMON_ERR_MESSAGES = {
+  SESSION_TIMED_OUT: 'Your session timed out, please refresh your page and try 
again.',
+};
+
+export default COMMON_ERR_MESSAGES;
diff --git a/superset/assets/src/utils/getClientErrorObject.js 
b/superset/assets/src/utils/getClientErrorObject.js
new file mode 100644
index 0000000..ea0ea44
--- /dev/null
+++ b/superset/assets/src/utils/getClientErrorObject.js
@@ -0,0 +1,40 @@
+import { t } from '@superset-ui/translation';
+import COMMON_ERR_MESSAGES from './errorMessages';
+
+export default function getClientErrorObject(response) {
+  // takes a Response object as input, attempts to read response as Json if 
possible,
+  // and returns a Promise that resolves to a plain object with error key and 
text value.
+  return new Promise((resolve) => {
+    if (typeof response === 'string') {
+      resolve({ error: response });
+    } else if (response && response.constructor === Response && 
!response.bodyUsed) {
+      // attempt to read the body as json, and fallback to text. we must clone 
the
+      // response in order to fallback to .text() because Response is 
single-read
+      response.clone().json().then((errorJson) => {
+        let error = { ...response, ...errorJson };
+        if (error.stack) {
+          error = {
+            ...error,
+            error: t('Unexpected error: ') +
+              (error.description || t('(no description, click to see stack 
trace)')),
+            stacktrace: error.stack,
+          };
+        } else if (error.responseText && error.responseText.indexOf('CSRF') >= 
0) {
+          error = {
+            ...error,
+            error: t(COMMON_ERR_MESSAGES.SESSION_TIMED_OUT),
+          };
+        }
+        resolve(error);
+      }).catch(() => {
+        // fall back to reading as text
+        response.text().then((errorText) => {
+          resolve({ ...response, error: errorText });
+        });
+      });
+    } else {
+      // fall back to Response.statusText or generic error of we cannot read 
the response
+      resolve({ ...response, error: response.statusText || t('An error 
occurred') });
+    }
+  });
+}
diff --git a/superset/assets/src/visualizations/EventFlow/EventFlow.jsx 
b/superset/assets/src/visualizations/EventFlow/EventFlow.jsx
index 7359bda..4a688e6 100644
--- a/superset/assets/src/visualizations/EventFlow/EventFlow.jsx
+++ b/superset/assets/src/visualizations/EventFlow/EventFlow.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { App, withParentSize } from '@data-ui/event-flow';
-import { t } from '../../locales';
+import { t } from '@superset-ui/translation';
 
 const propTypes = {
   className: PropTypes.string,
diff --git a/superset/assets/src/visualizations/FilterBox/FilterBox.jsx 
b/superset/assets/src/visualizations/FilterBox/FilterBox.jsx
index 907e802..05b9c9f 100644
--- a/superset/assets/src/visualizations/FilterBox/FilterBox.jsx
+++ b/superset/assets/src/visualizations/FilterBox/FilterBox.jsx
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import VirtualizedSelect from 'react-virtualized-select';
 import { Creatable } from 'react-select';
 import { Button } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 
 import DateFilterControl from 
'../../explore/components/controls/DateFilterControl';
 import ControlRow from '../../explore/components/ControlRow';
@@ -10,7 +11,6 @@ import Control from '../../explore/components/Control';
 import controls from '../../explore/controls';
 import OnPasteSelect from '../../components/OnPasteSelect';
 import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
-import { t } from '../../locales';
 import './FilterBox.css';
 
 // maps control names to their key in extra_filters
diff --git a/superset/assets/src/visualizations/PlaySlider.jsx 
b/superset/assets/src/visualizations/PlaySlider.jsx
index 88b0335..891c848 100644
--- a/superset/assets/src/visualizations/PlaySlider.jsx
+++ b/superset/assets/src/visualizations/PlaySlider.jsx
@@ -1,14 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Row, Col } from 'react-bootstrap';
-
 import Mousetrap from 'mousetrap';
-
+import { Row, Col } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 import BootrapSliderWrapper from '../components/BootstrapSliderWrapper';
 import './PlaySlider.css';
 
-import { t } from '../locales';
-
 const propTypes = {
   start: PropTypes.number.isRequired,
   step: PropTypes.number.isRequired,
diff --git a/superset/assets/src/visualizations/nvd3/NVD3Vis.js 
b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
index a67c93f..1267b42 100644
--- a/superset/assets/src/visualizations/nvd3/NVD3Vis.js
+++ b/superset/assets/src/visualizations/nvd3/NVD3Vis.js
@@ -4,9 +4,9 @@ import nv from 'nvd3';
 import mathjs from 'mathjs';
 import moment from 'moment';
 import PropTypes from 'prop-types';
+import { t } from '@superset-ui/translation';
 import 'nvd3/build/nv.d3.min.css';
 
-import { t } from '../../locales';
 import ANNOTATION_TYPES, { applyNativeColumns } from 
'../../modules/AnnotationTypes';
 import { getScale, getColor } from 
'../../modules/colors/CategoricalColorNamespace';
 import { formatDateVerbose } from '../../modules/dates';
diff --git a/superset/assets/src/welcome/App.jsx 
b/superset/assets/src/welcome/App.jsx
index b22c162..4a894ca 100644
--- a/superset/assets/src/welcome/App.jsx
+++ b/superset/assets/src/welcome/App.jsx
@@ -6,11 +6,10 @@ import { Provider } from 'react-redux';
 
 import messageToastReducer from '../messageToasts/reducers';
 import { initEnhancer } from '../reduxUtils';
-
-import { appSetup } from '../common';
+import setupApp from '../setup/setupApp';
 import Welcome from './Welcome';
 
-appSetup();
+setupApp();
 
 const container = document.getElementById('app');
 const bootstrap = JSON.parse(container.getAttribute('data-bootstrap'));
diff --git a/superset/assets/src/welcome/DashboardTable.jsx 
b/superset/assets/src/welcome/DashboardTable.jsx
index 29c2988..c03e34c 100644
--- a/superset/assets/src/welcome/DashboardTable.jsx
+++ b/superset/assets/src/welcome/DashboardTable.jsx
@@ -2,9 +2,9 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { Table, Tr, Td, unsafe } from 'reactable';
 import { SupersetClient } from '@superset-ui/core';
-import withToasts from '../messageToasts/enhancers/withToasts';
-import { t } from '../locales';
+import { t } from '@superset-ui/translation';
 
+import withToasts from '../messageToasts/enhancers/withToasts';
 import Loading from '../components/Loading';
 import '../../stylesheets/reactable-pagination.css';
 
diff --git a/superset/assets/src/welcome/Welcome.jsx 
b/superset/assets/src/welcome/Welcome.jsx
index 2f4de97..d059ee1 100644
--- a/superset/assets/src/welcome/Welcome.jsx
+++ b/superset/assets/src/welcome/Welcome.jsx
@@ -1,10 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Panel, Row, Col, Tabs, Tab, FormControl } from 'react-bootstrap';
+import { t } from '@superset-ui/translation';
 import RecentActivity from '../profile/components/RecentActivity';
 import Favorites from '../profile/components/Favorites';
 import DashboardTable from './DashboardTable';
-import { t } from '../locales';
 
 const propTypes = {
   user: PropTypes.object.isRequired,
diff --git a/superset/assets/webpack.config.js 
b/superset/assets/webpack.config.js
index 9da6528..c37ad55 100644
--- a/superset/assets/webpack.config.js
+++ b/superset/assets/webpack.config.js
@@ -79,19 +79,28 @@ if (isDevMode) {
   output.chunkFilename = '[name].[chunkhash].chunk.js';
 }
 
+const PREAMBLE = [
+  'babel-polyfill',
+  path.join(APP_DIR, '/src/preamble.js'),
+];
+
+function addPreamble(entry) {
+  return PREAMBLE.concat([path.join(APP_DIR, entry)]);
+}
+
 const config = {
   node: {
     fs: 'empty',
   },
   entry: {
-    theme: APP_DIR + '/src/theme.js',
-    common: APP_DIR + '/src/common.js',
-    addSlice: ['babel-polyfill', APP_DIR + '/src/addSlice/index.jsx'],
-    explore: ['babel-polyfill', APP_DIR + '/src/explore/index.jsx'],
-    dashboard: ['babel-polyfill', APP_DIR + '/src/dashboard/index.jsx'],
-    sqllab: ['babel-polyfill', APP_DIR + '/src/SqlLab/index.jsx'],
-    welcome: ['babel-polyfill', APP_DIR + '/src/welcome/index.jsx'],
-    profile: ['babel-polyfill', APP_DIR + '/src/profile/index.jsx'],
+    theme: path.join(APP_DIR, '/src/theme.js'),
+    preamble: PREAMBLE,
+    addSlice: addPreamble('/src/addSlice/index.jsx'),
+    explore: addPreamble('/src/explore/index.jsx'),
+    dashboard: addPreamble('/src/dashboard/index.jsx'),
+    sqllab: addPreamble('/src/SqlLab/index.jsx'),
+    welcome: addPreamble('/src/welcome/index.jsx'),
+    profile: addPreamble('/src/profile/index.jsx'),
   },
   output,
   optimization: {
@@ -103,7 +112,7 @@ const config = {
         default: false,
         major: {
           name: 'vendors-major',
-          test: /[\\/]node_modules\/(brace|react[-]dom|core[-]js)[\\/]/,
+          test: 
/[\\/]node_modules\/(brace|react[-]dom|core[-]js|@superset[-]ui\/translation)[\\/]/,
         },
       },
     },
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index a6ffc95..a59ef5e 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -406,6 +406,13 @@
     "@babel/runtime" "^7.1.2"
     whatwg-fetch "^2.0.4"
 
+"@superset-ui/translation@^0.2.1":
+  version "0.2.1"
+  resolved 
"https://registry.yarnpkg.com/@superset-ui/translation/-/translation-0.2.1.tgz#252025d566918782bafc25cb9fe2aa31f9917093";
+  dependencies:
+    "@babel/runtime" "^7.1.2"
+    jed "^1.1.1"
+
 "@types/blob-util@1.3.3":
   version "1.3.3"
   resolved 
"https://registry.yarnpkg.com/@types/blob-util/-/blob-util-1.3.3.tgz#adba644ae34f88e1dd9a5864c66ad651caaf628a";
@@ -2697,7 +2704,7 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
-classnames@^2.1.2, classnames@^2.2.3, classnames@^2.2.4, classnames@^2.2.5:
+classnames@^2.2.3, classnames@^2.2.4, classnames@^2.2.5:
   version "2.2.6"
   resolved 
"https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce";
 
@@ -4452,10 +4459,6 @@ executable@4.1.1:
   dependencies:
     pify "^2.2.0"
 
-exenv@^1.2.0:
-  version "1.2.2"
-  resolved 
"https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d";
-
 exif-parser@^0.1.9:
   version "0.1.12"
   resolved 
"https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922";
@@ -9350,15 +9353,6 @@ react-bootstrap-slider@2.1.5:
     bootstrap-slider "9.9.0"
     es6bindall "^0.0.9"
 
-react-bootstrap-table@^4.3.1:
-  version "4.3.1"
-  resolved 
"https://registry.yarnpkg.com/react-bootstrap-table/-/react-bootstrap-table-4.3.1.tgz#f704be55b7f6bf0557d2fc5bec6d25fd307d0cde";
-  dependencies:
-    classnames "^2.1.2"
-    prop-types "^15.5.10"
-    react-modal "^3.1.7"
-    react-s-alert "^1.3.2"
-
 react-bootstrap@^0.31.5:
   version "0.31.5"
   resolved 
"https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.31.5.tgz#57040fa8b1274e1e074803c21a1b895fdabea05a";
@@ -9455,7 +9449,7 @@ react-is@^16.3.2, react-is@^16.5.2:
   version "16.5.2"
   resolved 
"https://registry.yarnpkg.com/react-is/-/react-is-16.5.2.tgz#e2a7b7c3f5d48062eb769fcb123505eb928722e3";
 
-react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
+react-lifecycles-compat@^3.0.4:
   version "3.0.4"
   resolved 
"https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362";
 
@@ -9488,15 +9482,6 @@ react-markdown@^3.3.0:
     unist-util-visit "^1.3.0"
     xtend "^4.0.1"
 
-react-modal@^3.1.7:
-  version "3.6.1"
-  resolved 
"https://registry.yarnpkg.com/react-modal/-/react-modal-3.6.1.tgz#54d27a1ec2b493bbc451c7efaa3557b6af82332d";
-  dependencies:
-    exenv "^1.2.0"
-    prop-types "^15.5.10"
-    react-lifecycles-compat "^3.0.0"
-    warning "^3.0.0"
-
 react-move@^2.1.0:
   version "2.8.0"
   resolved 
"https://registry.yarnpkg.com/react-move/-/react-move-2.8.0.tgz#63deaf6a0e58ca6769357abfcd91dde44d83a596";
@@ -9536,12 +9521,6 @@ react-resizable@^1.3.3:
     prop-types "15.x"
     react-draggable "^2.2.6 || ^3.0.3"
 
-react-s-alert@^1.3.2:
-  version "1.4.1"
-  resolved 
"https://registry.yarnpkg.com/react-s-alert/-/react-s-alert-1.4.1.tgz#ef3665a9d98c4cf2e448fc2d84e48aeca799bb5a";
-  dependencies:
-    babel-runtime "^6.23.0"
-
 react-search-input@^0.11.3:
   version "0.11.3"
   resolved 
"https://registry.yarnpkg.com/react-search-input/-/react-search-input-0.11.3.tgz#3dd1f9fc584b6bc40a6ee133ae042b6fbb7ae8dd";
@@ -10823,10 +10802,6 @@ split@~0.2.10:
   dependencies:
     through "2"
 
-sprintf-js@^1.1.1:
-  version "1.1.1"
-  resolved 
"https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c";
-
 sprintf-js@~1.0.2:
   version "1.0.3"
   resolved 
"https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c";
diff --git a/superset/templates/superset/base.html 
b/superset/templates/superset/base.html
index b4397f5..b2dba50 100644
--- a/superset/templates/superset/base.html
+++ b/superset/templates/superset/base.html
@@ -10,14 +10,14 @@
 
   {% block head_js %}
     {{super()}}
-    {% for entry in get_unloaded_chunks(js_manifest('theme'), loaded_chunks) %}
-      <script src="{{ entry }}"></script>
-    {% endfor %}
+    {% with filename="theme" %}
+      {% include "superset/partials/_script_tag.html" %}
+    {% endwith %}
   {% endblock %}
 
   {% block tail_js %}
     {{super()}}
-    {% for entry in get_unloaded_chunks(js_manifest('common'), loaded_chunks) 
%}
-      <script src="{{ entry }}"></script>
-    {% endfor %}
+    {% with filename="preamble" %}
+      {% include "superset/partials/_script_tag.html" %}
+    {% endwith %}
   {% endblock %}
diff --git a/superset/templates/superset/basic.html 
b/superset/templates/superset/basic.html
index a5e72f3..f096b55 100644
--- a/superset/templates/superset/basic.html
+++ b/superset/templates/superset/basic.html
@@ -29,12 +29,9 @@
 
     {% endblock %}
 
-    {% for entry in get_unloaded_chunks(js_manifest('theme'), loaded_chunks) %}
-      <script src="{{ entry }}"></script>
-    {% endfor %}
-    {% for entry in get_unloaded_chunks(js_manifest('common'), loaded_chunks) 
%}
-      <script src="{{ entry }}"></script>
-    {% endfor %}
+    {% with filename="theme" %}
+      {% include "superset/partials/_script_tag.html" %}
+    {% endwith %}
 
     <input
       type="hidden"
@@ -79,10 +76,9 @@
     </div>
     {% block tail_js %}
       {% if entry %}
-        {% set entry_files = js_manifest(entry) %}
-        {% for entry in get_unloaded_chunks(entry_files, loaded_chunks) %}
-          <script src="{{ entry }}"></script>
-        {% endfor %}
+        {% with filename=entry %}
+          {% include "superset/partials/_script_tag.html" %}
+        {% endwith %}
       {% endif %}
     {% endblock %}
   </body>
diff --git a/superset/templates/superset/partials/_script_tag.html 
b/superset/templates/superset/partials/_script_tag.html
index f530c7b..1677925 100644
--- a/superset/templates/superset/partials/_script_tag.html
+++ b/superset/templates/superset/partials/_script_tag.html
@@ -1,4 +1,4 @@
-{% block tail_js %}
+{% block partial_js %}
   {% for entry in get_unloaded_chunks(js_manifest(filename), loaded_chunks) %}
     <script src="{{ entry }}"></script>
   {% endfor %}

Reply via email to