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:
		
				
					committed by
					
						
						Eugen Rochko
					
				
			
			
				
	
			
			
			
						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"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user