forked from fedi/mastodon
Only load Intl data for current language (#3130)
* Only load Intl data for current language * Extract common chunk only from application.js and public.js * Generate locale packs, avoid caching on window object
This commit is contained in:
parent
73e4468ff3
commit
9d04de1c8d
|
@ -41,34 +41,12 @@ import FavouritedStatuses from '../features/favourited_statuses';
|
|||
import Blocks from '../features/blocks';
|
||||
import Mutes from '../features/mutes';
|
||||
import Report from '../features/report';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import ar from 'react-intl/locale-data/ar';
|
||||
import bg from 'react-intl/locale-data/bg';
|
||||
import ca from 'react-intl/locale-data/ca';
|
||||
import de from 'react-intl/locale-data/de';
|
||||
import en from 'react-intl/locale-data/en';
|
||||
import eo from 'react-intl/locale-data/eo';
|
||||
import es from 'react-intl/locale-data/es';
|
||||
import fa from 'react-intl/locale-data/fa';
|
||||
import fi from 'react-intl/locale-data/fi';
|
||||
import fr from 'react-intl/locale-data/fr';
|
||||
import he from 'react-intl/locale-data/he';
|
||||
import hr from 'react-intl/locale-data/hr';
|
||||
import hu from 'react-intl/locale-data/hu';
|
||||
import id from 'react-intl/locale-data/id';
|
||||
import it from 'react-intl/locale-data/it';
|
||||
import ja from 'react-intl/locale-data/ja';
|
||||
import nl from 'react-intl/locale-data/nl';
|
||||
import no from 'react-intl/locale-data/no';
|
||||
import oc from '../locales/locale-data/oc';
|
||||
import pt from 'react-intl/locale-data/pt';
|
||||
import ru from 'react-intl/locale-data/ru';
|
||||
import uk from 'react-intl/locale-data/uk';
|
||||
import zh from 'react-intl/locale-data/zh';
|
||||
import tr from 'react-intl/locale-data/tr';
|
||||
import getMessagesForLocale from '../locales';
|
||||
import { hydrateStore } from '../actions/store';
|
||||
import createStream from '../stream';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import { getLocale } from '../locales';
|
||||
const { localeData, messages } = getLocale();
|
||||
addLocaleData(localeData);
|
||||
|
||||
const store = configureStore();
|
||||
const initialState = JSON.parse(document.getElementById("initial-state").textContent);
|
||||
|
@ -78,33 +56,6 @@ const browserHistory = useRouterHistory(createBrowserHistory)({
|
|||
basename: '/web',
|
||||
});
|
||||
|
||||
addLocaleData([
|
||||
...ar,
|
||||
...bg,
|
||||
...ca,
|
||||
...de,
|
||||
...en,
|
||||
...eo,
|
||||
...es,
|
||||
...fa,
|
||||
...fi,
|
||||
...fr,
|
||||
...he,
|
||||
...hr,
|
||||
...hu,
|
||||
...id,
|
||||
...it,
|
||||
...ja,
|
||||
...nl,
|
||||
...no,
|
||||
...oc,
|
||||
...pt,
|
||||
...ru,
|
||||
...uk,
|
||||
...zh,
|
||||
...tr,
|
||||
]);
|
||||
|
||||
class Mastodon extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -145,7 +96,7 @@ class Mastodon extends React.PureComponent {
|
|||
store.dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
case 'notification':
|
||||
store.dispatch(updateNotifications(JSON.parse(data.payload), getMessagesForLocale(locale), locale));
|
||||
store.dispatch(updateNotifications(JSON.parse(data.payload), messages, locale));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -183,7 +134,7 @@ class Mastodon extends React.PureComponent {
|
|||
const { locale } = this.props;
|
||||
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={getMessagesForLocale(locale)}>
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<Provider store={store}>
|
||||
<Router history={browserHistory} render={applyRouterMiddleware(useScroll())}>
|
||||
<Route path='/' component={UI}>
|
||||
|
|
|
@ -1,61 +1,9 @@
|
|||
import ar from './ar.json';
|
||||
import en from './en.json';
|
||||
import ca from './ca.json';
|
||||
import de from './de.json';
|
||||
import es from './es.json';
|
||||
import fa from './fa.json';
|
||||
import he from './he.json';
|
||||
import hr from './hr.json';
|
||||
import hu from './hu.json';
|
||||
import io from './io.json';
|
||||
import it from './it.json';
|
||||
import fr from './fr.json';
|
||||
import nl from './nl.json';
|
||||
import no from './no.json';
|
||||
import oc from './oc.json';
|
||||
import pt from './pt.json';
|
||||
import pt_br from './pt-BR.json';
|
||||
import uk from './uk.json';
|
||||
import fi from './fi.json';
|
||||
import eo from './eo.json';
|
||||
import ru from './ru.json';
|
||||
import ja from './ja.json';
|
||||
import zh_hk from './zh-HK.json';
|
||||
import zh_cn from './zh-CN.json';
|
||||
import bg from './bg.json';
|
||||
import id from './id.json';
|
||||
import tr from './tr.json';
|
||||
let theLocale;
|
||||
|
||||
const locales = {
|
||||
ar,
|
||||
en,
|
||||
ca,
|
||||
de,
|
||||
es,
|
||||
fa,
|
||||
he,
|
||||
hr,
|
||||
hu,
|
||||
io,
|
||||
it,
|
||||
fr,
|
||||
nl,
|
||||
no,
|
||||
oc,
|
||||
pt,
|
||||
'pt-BR': pt_br,
|
||||
uk,
|
||||
fi,
|
||||
eo,
|
||||
ru,
|
||||
ja,
|
||||
'zh-HK': zh_hk,
|
||||
'zh-CN': zh_cn,
|
||||
bg,
|
||||
id,
|
||||
tr,
|
||||
};
|
||||
export function setLocale(locale) {
|
||||
theLocale = locale;
|
||||
}
|
||||
|
||||
export default function getMessagesForLocale(locale) {
|
||||
return locales[locale];
|
||||
};
|
||||
export function getLocale() {
|
||||
return theLocale;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
= stylesheet_pack_tag 'application', media: 'all'
|
||||
= javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous'
|
||||
= javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous'
|
||||
= csrf_meta_tags
|
||||
|
||||
= yield :header_tags
|
||||
|
|
52
config/webpack/generateLocalePacks.js
Normal file
52
config/webpack/generateLocalePacks.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
// To avoid adding a lot of boilerplate, locale packs are
|
||||
// automatically generated here. These are written into the tmp/
|
||||
// directory and then used to generate locale_en.js, locale_fr.js, etc.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const rimraf = require('rimraf');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
const localesJsonPath = path.join(__dirname, '../../app/javascript/mastodon/locales');
|
||||
const locales = fs.readdirSync(localesJsonPath).filter(filename => {
|
||||
return /\.json$/.test(filename) &&
|
||||
!/defaultMessages/.test(filename) &&
|
||||
!/whitelist/.test(filename);
|
||||
}).map(filename => filename.replace(/\.json$/, ''));
|
||||
|
||||
const outPath = path.join(__dirname, '../../tmp/packs');
|
||||
|
||||
rimraf.sync(outPath);
|
||||
mkdirp.sync(outPath);
|
||||
|
||||
const outPaths = [];
|
||||
|
||||
locales.forEach(locale => {
|
||||
const localePath = path.join(outPath, `locale_${locale}.js`);
|
||||
const baseLocale = locale.split('-')[0]; // e.g. 'zh-TW' -> 'zh'
|
||||
const localeDataPath = [
|
||||
// first try react-intl
|
||||
`../../node_modules/react-intl/locale-data/${baseLocale}.js`,
|
||||
// then check locales/locale-data
|
||||
`../../app/javascript/mastodon/locales/locale-data/${baseLocale}.js`,
|
||||
// fall back to English (this is what react-intl does anyway)
|
||||
`../../node_modules/react-intl/locale-data/en.js`,
|
||||
].filter(filename => fs.existsSync(path.join(outPath, filename)))
|
||||
.map(filename => filename.replace(/..\/..\/node_modules\//, ''))[0];
|
||||
|
||||
const localeContent = `//
|
||||
// locale_${locale}.js
|
||||
// automatically generated by generateLocalePacks.js
|
||||
//
|
||||
import messages from '../../app/javascript/mastodon/locales/${locale}.json';
|
||||
import localeData from ${JSON.stringify(localeDataPath)};
|
||||
import { setLocale } from '../../app/javascript/mastodon/locales';
|
||||
setLocale({messages, localeData});
|
||||
`;
|
||||
fs.writeFileSync(localePath, localeContent, 'utf8');
|
||||
outPaths.push(localePath);
|
||||
});
|
||||
|
||||
module.exports = outPaths;
|
||||
|
||||
|
|
@ -10,15 +10,20 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|||
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||
const extname = require('path-complete-extname');
|
||||
const { env, paths, publicPath, loadersDir } = require('./configuration.js');
|
||||
const localePackPaths = require('./generateLocalePacks');
|
||||
|
||||
const extensionGlob = `**/*{${paths.extensions.join(',')}}*`;
|
||||
const packPaths = sync(join(paths.source, paths.entry, extensionGlob));
|
||||
const entryPacks = [].concat(packPaths).concat(localePackPaths);
|
||||
|
||||
module.exports = {
|
||||
entry: packPaths.reduce(
|
||||
entry: entryPacks.reduce(
|
||||
(map, entry) => {
|
||||
const localMap = map;
|
||||
const namespace = relative(join(paths.source, paths.entry), dirname(entry));
|
||||
let namespace = relative(join(paths.source, paths.entry), dirname(entry));
|
||||
if (namespace === '../../../tmp/packs') {
|
||||
namespace = ''; // generated by generateLocalePacks.js
|
||||
}
|
||||
localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry);
|
||||
return localMap;
|
||||
}, {}
|
||||
|
@ -41,7 +46,15 @@ module.exports = {
|
|||
new ManifestPlugin({ fileName: paths.manifest, publicPath, writeToFileEmit: true }),
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'common',
|
||||
minChunks: 2,
|
||||
minChunks: (module, count) => {
|
||||
if (module.resource && /node_modules\/react-intl/.test(module.resource)) {
|
||||
// skip react-intl because it's useless to put in the common chunk,
|
||||
// e.g. because "shared" modules between zh-TW and zh-CN will never
|
||||
// be loaded together
|
||||
return false;
|
||||
}
|
||||
return count >= 2;
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
"is-nan": "^1.2.1",
|
||||
"js-yaml": "^3.8.3",
|
||||
"lodash": "^4.17.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-sass": "^4.5.2",
|
||||
"npmlog": "^4.0.2",
|
||||
"object-assign": "^4.1.1",
|
||||
|
@ -91,6 +92,7 @@
|
|||
"redux-immutable": "^3.1.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"reselect": "^2.5.4",
|
||||
"rimraf": "^2.6.1",
|
||||
"sass-loader": "^6.0.3",
|
||||
"stringz": "^0.1.2",
|
||||
"style-loader": "^0.16.1",
|
||||
|
|
28
yarn.lock
28
yarn.lock
|
@ -5407,15 +5407,6 @@ react-redux-loading-bar@2.4.1:
|
|||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-2.4.1.tgz#8df64db362f065b5453fbbb7379a5cf62440129a"
|
||||
|
||||
react-redux@^4.4.5:
|
||||
version "4.4.5"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-4.4.5.tgz#f509a2981be2252d10c629ef7c559347a4aec457"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^1.0.3"
|
||||
invariant "^2.0.0"
|
||||
lodash "^4.2.0"
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
react-redux@^5.0.4:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.4.tgz#1563babadcfb2672f57f9ceaa439fb16bf85d55b"
|
||||
|
@ -5476,12 +5467,6 @@ react-test-renderer@^15.5.4:
|
|||
fbjs "^0.8.9"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
react-themeable@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e"
|
||||
dependencies:
|
||||
object-assign "^3.0.0"
|
||||
|
||||
react-toggle@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-toggle/-/react-toggle-2.1.1.tgz#80600a64417a1acc8aaa4c1477f7fbdb88b988fb"
|
||||
|
@ -5792,6 +5777,12 @@ rimraf@2, rimraf@^2.2.8, rimraf@~2.5.0, rimraf@~2.5.1:
|
|||
dependencies:
|
||||
glob "^7.0.5"
|
||||
|
||||
rimraf@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
|
||||
dependencies:
|
||||
glob "^7.0.5"
|
||||
|
||||
ripemd160@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce"
|
||||
|
@ -5843,13 +5834,6 @@ scroll-behavior@^0.8.0:
|
|||
dom-helpers "^2.4.0"
|
||||
invariant "^2.2.1"
|
||||
|
||||
scss-tokenizer@^0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
|
||||
dependencies:
|
||||
js-base64 "^2.1.8"
|
||||
source-map "^0.4.2"
|
||||
|
||||
seed-random@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54"
|
||||
|
|
Loading…
Reference in a new issue