From 06f7b29fc3953b554eb5ceea3c840abd87e84ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Ramos?= Date: Thu, 20 Oct 2016 20:42:39 +0100 Subject: [PATCH] internationalization suppport --- backend/package.json | 3 + backend/src/index.html | 12 ++ backend/src/index.js | 21 ++- backend/src/locales.js | 11 ++ backend/static/.gitignore | 2 + frontend/README.md | 4 + frontend/locales/en-us.json | 3 + frontend/locales/pt-pt.json | 3 + frontend/package.json | 15 +- frontend/scripts/build-locales.js | 74 ++++++++++ frontend/src/containers/app.js | 1 + frontend/src/containers/home.js | 9 +- frontend/src/intl.js | 38 +++++ frontend/src/root.js | 14 +- frontend/src/state/reducers/index.js | 3 +- frontend/src/state/reducers/intl.js | 7 + frontend/static/.gitignore | 2 + frontend/static/.gitkeep | 0 frontend/static/index.html | 4 + frontend/webpack/config.js | 4 + frontend/yarn.lock | 198 +++++++++++++++++++++++++-- 21 files changed, 403 insertions(+), 25 deletions(-) create mode 100644 backend/src/index.html create mode 100644 backend/src/locales.js create mode 100644 backend/static/.gitignore create mode 100644 frontend/locales/en-us.json create mode 100644 frontend/locales/pt-pt.json create mode 100644 frontend/scripts/build-locales.js create mode 100644 frontend/src/intl.js create mode 100644 frontend/src/state/reducers/intl.js create mode 100644 frontend/static/.gitignore delete mode 100644 frontend/static/.gitkeep diff --git a/backend/package.json b/backend/package.json index 0439a379..3faeabe5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,6 +12,9 @@ }, "dependencies": { "express": "^4.14.0", + "locale": "^0.1.0", + "lodash.template": "^4.4.0", + "lodash.uniq": "^4.5.0", "st": "^1.2.0" }, "devDependencies": { diff --git a/backend/src/index.html b/backend/src/index.html new file mode 100644 index 00000000..0e4aa3aa --- /dev/null +++ b/backend/src/index.html @@ -0,0 +1,12 @@ + + + + Joyent Triton Dashboard + + +
+ + + + + diff --git a/backend/src/index.js b/backend/src/index.js index d4f73e28..3cace565 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,13 +1,19 @@ +const template = require('lodash.template'); +const locale = require('locale'); const path = require('path'); const express = require('express'); const st = require('st'); +const fs = require('fs'); const app = express(); +const index = path.join(__dirname, './index.html'); +const html = template(fs.readFileSync(index, 'utf-8')); + var mount = st({ path: path.join(__dirname, '../static'), url: 'static/', - index: 'index.html', + index: false, dot: false, passthrough: false, gzip: true, @@ -15,11 +21,18 @@ var mount = st({ }); app.use(mount); +app.use(locale(require('./locales'))); app.get('/*', (req, res, next) => { - mount(Object.assign(req, { - sturl: '/static/index.html' - }), res, next); + const locale = (req.locale || '').toLowerCase(); + const lang = locale.split(/\-/)[0]; + + res.header('Content-Type', 'text/html'); + + res.send(html({ + locale, + lang + })); }); app.listen(8000, (err, address) => { diff --git a/backend/src/locales.js b/backend/src/locales.js new file mode 100644 index 00000000..d75eee7e --- /dev/null +++ b/backend/src/locales.js @@ -0,0 +1,11 @@ +const uniq = require('lodash.uniq'); +const fs = require('fs'); +const path = require('path'); + +const files = fs.readdirSync(path.join(__dirname, '../static/locales')); + +module.exports = uniq(files.map((file) => { + return file.replace(/\.js$/, ''); +}).filter((file) => { + return file.match(/.*?-.*?/); +})); diff --git a/backend/static/.gitignore b/backend/static/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/backend/static/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/frontend/README.md b/frontend/README.md index f1cf7b5d..4e233a73 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -26,6 +26,8 @@ npm run test │   ├── store.js │   └── thunks ├── static +├── locales +├── scripts ├── test ├── webpack ├── .babelrc @@ -38,6 +40,8 @@ npm run test - **src/state/actions.js**: Not only exports all the actions available (declared in the file), but also goes through all the thunks and exports them. - **src/state/thunks**: Directory to place thunks so that actions or reducers don't get too confusing. - **src/state/reducers**: Each file here represents a reducer scope. So, `state.app` will be controlled in `reducers/app.js`. + - **locales**: Translation definitions for each locale supported. + - **scripts**: Utility scripts (e.g. building localizations). - **test**: Self explanatory. - **webpack**: Webpack configuration for multiple enviroments. Development configuration includes a dev-server and hot module replacement support. - **.babelrc**: This babel configuration outputs ES2015 code, so it will produce code only for modern browsers. diff --git a/frontend/locales/en-us.json b/frontend/locales/en-us.json new file mode 100644 index 00000000..8f8d7125 --- /dev/null +++ b/frontend/locales/en-us.json @@ -0,0 +1,3 @@ +{ + "greetings": "Hello" +} \ No newline at end of file diff --git a/frontend/locales/pt-pt.json b/frontend/locales/pt-pt.json new file mode 100644 index 00000000..1eb32ea0 --- /dev/null +++ b/frontend/locales/pt-pt.json @@ -0,0 +1,3 @@ +{ + "greetings": "Olá" +} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 1182e4b2..d59a5bf7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,9 +8,11 @@ "lint": "eslint .", "test": "NODE_ENV=test nyc ava test/*.js --verbose", "open": "nyc report --reporter=html & open coverage/index.html", - "coverage": "nyc check-coverage --statements 100 --functions 100 --lines 100 --branches 100" + "coverage": "nyc check-coverage --statements 100 --functions 100 --lines 100 --branches 100", + "build-locales": "NODE_ENV=test babel-node scripts/build-locales" }, "dependencies": { + "babel-cli": "^6.16.0", "babel-core": "^6.17.0", "babel-loader": "^6.2.5", "babel-plugin-add-module-exports": "^0.2.1", @@ -21,9 +23,13 @@ "constant-case": "^2.0.0", "fast-async": "^6.1.1", "json-loader": "^0.5.4", + "ncp": "^2.0.0", + "querystring": "^0.2.0", "react": "^15.3.2", "react-dom": "^15.3.2", "react-hot-loader": "^3.0.0-beta.6", + "react-intl": "^2.1.5", + "react-intl-redux": "^0.1.0", "react-redux": "^4.4.5", "react-router": "^4.0.0-alpha.4", "reduce-reducers": "^0.1.2", @@ -33,7 +39,9 @@ "redux-logger": "^2.7.0", "redux-promise-middleware": "^4.1.0", "redux-thunk": "^2.1.0", - "webpack": "^2.1.0-beta.25" + "thenify": "^3.2.1", + "webpack": "^2.1.0-beta.25", + "webpack-shell-plugin": "^0.4.3" }, "devDependencies": { "ava": "^0.16.0", @@ -52,7 +60,8 @@ "nyc": "^8.3.1", "pre-commit": "^1.1.3", "react-addons-test-utils": "^15.3.2", - "webpack-dev-server": "^1.16.2" + "webpack-dev-server": "^1.16.2", + "webpack-shell-plugin": "^0.4.3" }, "ava": { "failFast": true, diff --git a/frontend/scripts/build-locales.js b/frontend/scripts/build-locales.js new file mode 100644 index 00000000..8ca37b7b --- /dev/null +++ b/frontend/scripts/build-locales.js @@ -0,0 +1,74 @@ +const path = require('path'); +const thenify = require('thenify'); +const fs = require('fs'); +const Ncp = require('ncp'); + +const readdir = thenify(fs.readdir); +const writeFile = thenify(fs.writeFile); +const readFile = thenify(fs.readFile); +const ncp = thenify(Ncp.ncp); + +const root = path.join(__dirname, '../locales'); +const sttic = path.join(__dirname, '../static/locales'); +const intl = path.join(__dirname, '../node_modules/react-intl/locale-data'); + +const source = ({ + name, + json +}) => ` + (() => { + const Locales = window.Locales || {}; + Locales['${name}'] = ${json}; + window.Locales = Locales; + })(); +`; + +const compile = async () => { + const files = await readdir(root); + const jsons = files.filter(filename => path.extname(filename) === '.json'); + + const locales = files.reduce((res, filename) => { + const name = path.parse(filename).name; + const json = JSON.stringify(require(path.join(root, filename))); + const lang = name.split(/\-/)[0]; + + return { + ...res, + [name]: { + lang, + json, + filename + } + }; + }, {}); + + await Promise.all(Object.keys(locales).map((name) => { + console.log(`Copying locale-data for ${name}`); + + const locale = locales[name]; + const source = path.join(intl, `${locale.lang}.js`); + const destination = path.join(sttic, `${locale.lang}.js`); + + return ncp(source, destination); + })); + + + + return await Promise.all(Object.keys(locales).map((name) => { + console.log(`Writing ${name}.js`); + + const locale = locales[name]; + + return writeFile(path.join(sttic, `${name}.js`), source({ + ...locale, + name + })); + })); +}; + +console.log('Building Locales'); +compile().then(() => { + console.log('Locales Built'); +}, (err) => { + throw err; +}); diff --git a/frontend/src/containers/app.js b/frontend/src/containers/app.js index b7600a42..d64b7f03 100644 --- a/frontend/src/containers/app.js +++ b/frontend/src/containers/app.js @@ -28,6 +28,7 @@ const App = connect()(React.createClass({ // ugly hack needed because of a limitation of react-router api // that doens't pass it's instance to matched routes + // wait for react-router-redux@5 dispatch(updateRouter(router)); }, render: function() { diff --git a/frontend/src/containers/home.js b/frontend/src/containers/home.js index db54116e..6677effd 100644 --- a/frontend/src/containers/home.js +++ b/frontend/src/containers/home.js @@ -1,9 +1,16 @@ const React = require('react'); +const ReactIntl = require('react-intl'); + +const { + FormattedMessage +} = ReactIntl; module.exports = () => { return (
-

Home

+

+ +

); }; diff --git a/frontend/src/intl.js b/frontend/src/intl.js new file mode 100644 index 00000000..c771ce54 --- /dev/null +++ b/frontend/src/intl.js @@ -0,0 +1,38 @@ +const qs = require('querystring'); +const ReactIntl = require('react-intl'); + +const { + addLocaleData +} = ReactIntl; + +module.exports = (({ + Locales = {}, + ReactIntlLocaleData = {} +}) => { + const en = Locales['en-us'] || {}; + + Object.keys(ReactIntlLocaleData).forEach((lang) => { + addLocaleData(ReactIntlLocaleData[lang] || []); + }); + + // http://stackoverflow.com/a/38150585 + const detectedLocale = ( + qs.parse((document.location.search || '').replace(/^\?/, '')).locale || + navigator.languages && navigator.languages[0] || // Chrome / Firefox + navigator.language || // All browsers + navigator.userLanguage || // IE <= 10 + 'en-US' + ).toLowerCase(); + + const lang = detectedLocale.split(/\-/)[0]; + const locale = ReactIntlLocaleData[lang] ? + (Locales[detectedLocale] ? detectedLocale : 'en-us') : 'en-us'; + + return { + locale, + messages: { + ...en, + ...(Locales[locale] || {}) + } + }; +})(window); diff --git a/frontend/src/root.js b/frontend/src/root.js index 78fc1998..db12152c 100644 --- a/frontend/src/root.js +++ b/frontend/src/root.js @@ -1,4 +1,6 @@ +const qs = require('querystring'); const React = require('react'); +const ReactIntlRedux = require('react-intl-redux'); const ReactHotLoader = require('react-hot-loader'); const ReactRedux = require('react-redux'); const ReactRouter = require('react-router'); @@ -6,6 +8,10 @@ const ReactRouter = require('react-router'); const App = require('./containers/app'); const store = require('./state/store'); +const { + IntlProvider +} = ReactIntlRedux; + const { AppContainer } = ReactHotLoader; @@ -22,9 +28,11 @@ module.exports = () => { return ( - - {App} - + + + {App} + + ); diff --git a/frontend/src/state/reducers/index.js b/frontend/src/state/reducers/index.js index 935f2b24..5c9bd0ec 100644 --- a/frontend/src/state/reducers/index.js +++ b/frontend/src/state/reducers/index.js @@ -6,6 +6,7 @@ const { module.exports = () => { return combineReducers({ - app: require('./app.js') + app: require('./app.js'), + intl: require('./intl.js') }); }; diff --git a/frontend/src/state/reducers/intl.js b/frontend/src/state/reducers/intl.js new file mode 100644 index 00000000..479a5936 --- /dev/null +++ b/frontend/src/state/reducers/intl.js @@ -0,0 +1,7 @@ +const ReduxActions = require('redux-actions'); + +const { + handleActions +} = ReduxActions; + +module.exports = handleActions({}, require('../../intl')); diff --git a/frontend/static/.gitignore b/frontend/static/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/frontend/static/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/frontend/static/.gitkeep b/frontend/static/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/static/index.html b/frontend/static/index.html index d36d2c24..c831e18e 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -5,6 +5,10 @@
+ + + + diff --git a/frontend/webpack/config.js b/frontend/webpack/config.js index d07044da..ef1b0be1 100644 --- a/frontend/webpack/config.js +++ b/frontend/webpack/config.js @@ -1,5 +1,6 @@ const pkg = require('../package.json'); const webpack = require('webpack'); +const WebpackShellPlugin = require('webpack-shell-plugin'); const path = require('path'); module.exports = { @@ -17,6 +18,9 @@ module.exports = { APP_NAME: JSON.stringify(pkg.name), APP_VERSION: JSON.stringify(pkg.version) } + }), + new WebpackShellPlugin({ + onBuildStart: ['npm run build-locales'] }) ], module: { diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 52adeff1..3e26ca49 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -66,7 +66,7 @@ ansi-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" -ansi-styles@^2.2.1: +ansi-styles@^2.1.0, ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -74,6 +74,10 @@ ansi-styles@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + anymatch@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" @@ -138,7 +142,7 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" -array-uniq@^1.0.1, array-uniq@^1.0.2: +array-uniq@^1.0.0, array-uniq@^1.0.1, array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -308,6 +312,32 @@ aws4@^1.2.1: version "1.5.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" +babel-cli: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.16.0.tgz#4e0d1cf40442ef78330f7fef88eb3a0a1b16bd37" + dependencies: + babel-core "^6.16.0" + babel-polyfill "^6.16.0" + babel-register "^6.16.0" + babel-runtime "^6.9.0" + bin-version-check "^2.1.0" + chalk "1.1.1" + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^0.1.0" + glob "^5.0.5" + lodash "^4.2.0" + log-symbols "^1.0.2" + output-file-sync "^1.1.0" + path-exists "^1.0.0" + path-is-absolute "^1.0.0" + request "^2.65.0" + slash "^1.0.0" + source-map "^0.5.0" + v8flags "^2.0.10" + optionalDependencies: + chokidar "^1.0.0" + babel-code-frame@^6.16.0, babel-code-frame@^6.7.5: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de" @@ -316,7 +346,7 @@ babel-code-frame@^6.16.0, babel-code-frame@^6.7.5: esutils "^2.0.2" js-tokens "^2.0.0" -babel-core@^6.16.0, babel-core@^6.17.0, babel-core@^6.3.21: +babel-core, babel-core@^6.16.0, babel-core@^6.3.21: version "6.17.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.17.0.tgz#6c4576447df479e241e58c807e4bc7da4db7f425" dependencies: @@ -848,6 +878,14 @@ babel-plugin-transform-strict-mode@^6.8.0: babel-runtime "^6.0.0" babel-types "^6.8.0" +babel-polyfill@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422" + dependencies: + babel-runtime "^6.9.1" + core-js "^2.4.0" + regenerator-runtime "^0.9.5" + babel-preset-es2015@^6.3.13: version "6.16.0" resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.16.0.tgz#59acecd1efbebaf48f89404840f2fe78c4d2ad5c" @@ -990,6 +1028,21 @@ big.js@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" +bin-version-check@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bin-version-check/-/bin-version-check-2.1.0.tgz#e4e5df290b9069f7d111324031efc13fdd11a5b0" + dependencies: + bin-version "^1.0.0" + minimist "^1.1.0" + semver "^4.0.3" + semver-truncate "^1.0.0" + +bin-version@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/bin-version/-/bin-version-1.0.4.tgz#9eb498ee6fd76f7ab9a7c160436f89579435d78e" + dependencies: + find-versions "^1.0.0" + binary-extensions@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d" @@ -1223,6 +1276,16 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chalk@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.1.tgz#509afb67066e7499f7eb3535c77445772ae2d019" + dependencies: + ansi-styles "^2.1.0" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + cheerio@^0.22.0: version "0.22.0" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" @@ -1244,7 +1307,7 @@ cheerio@^0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -chokidar@^1.4.2, chokidar@^1.4.3: +chokidar@^1.0.0, chokidar@^1.4.2, chokidar@^1.4.3: version "1.6.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" dependencies: @@ -1340,7 +1403,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@^2.9.0: +commander@^2.8.1, commander@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -2181,6 +2244,15 @@ find-up@^1.0.0, find-up@^1.1.2: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-versions@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-1.2.1.tgz#cbde9f12e38575a0af1be1b9a2c5d5fd8f186b62" + dependencies: + array-uniq "^1.0.0" + get-stdin "^4.0.1" + meow "^3.5.0" + semver-regex "^1.0.0" + flat-cache@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff" @@ -2235,6 +2307,10 @@ fresh@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" +fs-readdir-recursive@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2318,6 +2394,16 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob@^5.0.5: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.0.3, glob@^7.0.5, glob@^7.0.6: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" @@ -2376,7 +2462,7 @@ got@^5.0.0: unzip-response "^1.0.0" url-parse-lax "^1.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.2, graceful-fs@^4.1.4: version "4.1.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.9.tgz#baacba37d19d11f9d146d3578bc99958c3787e29" @@ -2603,7 +2689,27 @@ interpret@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" -invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1: +intl-format-cache@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.0.5.tgz#b484cefcb9353f374f25de389a3ceea1af18d7c9" + +intl-messageformat-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz#5906b7f953ab7470e0dc8549097b648b991892ff" + +intl-messageformat@^1.3.0, intl-messageformat@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae" + dependencies: + intl-messageformat-parser "1.2.0" + +intl-relativeformat@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-1.3.0.tgz#893dc7076fccd380cf091a2300c380fa57ace45b" + dependencies: + intl-messageformat "1.3.0" + +invariant@^2.0.0, invariant@^2.1.1, invariant@^2.2.0, invariant@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.1.tgz#b097010547668c7e337028ebe816ebe36c8a8d54" dependencies: @@ -3114,6 +3220,12 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.16.2, lodash@^4.2.0, lo version "4.16.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.4.tgz#01ce306b9bad1319f2a5528674f88297aeb70127" +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -3181,7 +3293,7 @@ memory-fs@^0.3.0, memory-fs@~0.3.0: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.7.0: +meow@^3.5.0, meow@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" dependencies: @@ -3253,7 +3365,7 @@ minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" -minimatch@^3.0.0, minimatch@^3.0.2: +minimatch@^3.0.0, minimatch@^3.0.2, "minimatch@2 || 3": version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: @@ -3302,6 +3414,10 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +ncp: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -3593,6 +3709,14 @@ osenv@^0.1.0: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + package-hash@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-1.2.0.tgz#003e56cd57b736a6ed6114cc2b81542672770e44" @@ -3910,7 +4034,7 @@ querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" -querystring@0.2.0: +querystring@^0.2.0, querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -3971,6 +4095,24 @@ react-hot-loader@^3.0.0-beta.6: redbox-react "^1.2.5" source-map "^0.4.4" +react-intl, react-intl@^2.1.3: + version "2.1.5" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.1.5.tgz#f9795ea34b790dcb5d0d8ef7060dddbe85bf8763" + dependencies: + intl-format-cache "^2.0.5" + intl-messageformat "^1.3.0" + intl-relativeformat "^1.3.0" + invariant "^2.1.1" + +react-intl-redux: + version "0.1.0" + resolved "https://registry.yarnpkg.com/react-intl-redux/-/react-intl-redux-0.1.0.tgz#94d9cef8214707ae0effa3e5113a35000c7b0baa" + dependencies: + react-intl "^2.1.3" + react-redux "^4.4.5" + redux "^3.5.2" + warning "^3.0.0" + react-proxy@^3.0.0-alpha.0: version "3.0.0-alpha.1" resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-3.0.0-alpha.1.tgz#4400426bcfa80caa6724c7755695315209fa4b07" @@ -4108,7 +4250,7 @@ redux-thunk@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98" -redux@^3.6.0: +redux@^3.5.2, redux@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" dependencies: @@ -4182,7 +4324,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2.x: +request@^2.65.0, request@2.x: version "2.75.0" resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" dependencies: @@ -4292,7 +4434,21 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" -semver@^5.0.3, semver@^5.1.0, semver@~5.3.0, "semver@2 || 3 || 4 || 5": +semver-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9" + +semver-truncate@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" + dependencies: + semver "^5.3.0" + +semver@^4.0.3: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0, "semver@2 || 3 || 4 || 5": version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -4652,6 +4808,12 @@ the-argv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/the-argv/-/the-argv-1.0.0.tgz#0084705005730dd84db755253c931ae398db9522" +thenify@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -4848,6 +5010,12 @@ uuid@^2.0.1, uuid@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" +v8flags@^2.0.10: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -4912,6 +5080,10 @@ webpack-dev-server@^1.16.2: supports-color "^3.1.1" webpack-dev-middleware "^1.4.0" +webpack-shell-plugin: + version "0.4.3" + resolved "https://registry.yarnpkg.com/webpack-shell-plugin/-/webpack-shell-plugin-0.4.3.tgz#a633e98c16b3bed5b6963e98059ca783841f3043" + webpack-sources@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.2.tgz#057a3f3255f8ba561b901d9150589aa103a57e65"