Merge branch 'locales' into 'master'

Locales

Closes #7

See merge request soapbox-pub/soapbox-fe!44
merge-requests/45/merge
Alex Gleason 4 years ago
commit 7e16536d70

@ -21,8 +21,7 @@ const defaultSettings = ImmutableMap({
deleteModal: true, deleteModal: true,
defaultPrivacy: 'public', defaultPrivacy: 'public',
themeMode: 'light', themeMode: 'light',
// locale: navigator.language.slice(0, 2) || 'en', // FIXME: Dynamic locales locale: navigator.language.split(/[-_]/)[0] || 'en',
locale: 'en',
systemFont: false, systemFont: false,
dyslexicFont: false, dyslexicFont: false,

@ -9,14 +9,13 @@ import {
import { updateNotificationsQueue, expandNotifications } from './notifications'; import { updateNotificationsQueue, expandNotifications } from './notifications';
import { updateConversations } from './conversations'; import { updateConversations } from './conversations';
import { fetchFilters } from './filters'; import { fetchFilters } from './filters';
import { getLocale } from '../locales'; import { getSettings } from 'soapbox/actions/settings';
import messages from 'soapbox/locales/messages';
const { messages } = getLocale();
export function connectTimelineStream(timelineId, path, pollingRefresh = null, accept = null) { export function connectTimelineStream(timelineId, path, pollingRefresh = null, accept = null) {
return connectStream (path, pollingRefresh, (dispatch, getState) => { return connectStream (path, pollingRefresh, (dispatch, getState) => {
const locale = getState().getIn(['meta', 'locale']); const locale = getSettings(getState()).get('locale');
return { return {
onConnect() { onConnect() {
@ -36,7 +35,9 @@ export function connectTimelineStream(timelineId, path, pollingRefresh = null, a
dispatch(deleteFromTimelines(data.payload)); dispatch(deleteFromTimelines(data.payload));
break; break;
case 'notification': case 'notification':
messages[locale]().then(messages => {
dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname)); dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname));
}).catch(() => {});
break; break;
case 'conversation': case 'conversation':
dispatch(updateConversations(JSON.parse(data.payload))); dispatch(updateConversations(JSON.parse(data.payload)));

@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl';
const LoadingIndicator = () => ( const LoadingIndicator = () => (
<div className='loading-indicator'> <div className='loading-indicator'>
<div className='loading-indicator__figure' /> <div className='loading-indicator__figure' />
<FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' /> <span><FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' /></span>
</div> </div>
); );

@ -122,7 +122,7 @@ class RelativeTimestamp extends React.Component {
}; };
state = { state = {
now: this.props.intl.now(), now: Date.now(),
}; };
static defaultProps = { static defaultProps = {
@ -139,7 +139,7 @@ class RelativeTimestamp extends React.Component {
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (this.props.timestamp !== nextProps.timestamp) { if (this.props.timestamp !== nextProps.timestamp) {
this.setState({ now: this.props.intl.now() }); this.setState({ now: Date.now() });
} }
} }
@ -166,7 +166,7 @@ class RelativeTimestamp extends React.Component {
const delay = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder); const delay = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder);
this._timer = setTimeout(() => { this._timer = setTimeout(() => {
this.setState({ now: this.props.intl.now() }); this.setState({ now: Date.now() });
}, delay); }, delay);
} }

@ -1,41 +0,0 @@
import React from 'react';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import configureStore from '../store/configureStore';
import { hydrateStore } from '../actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales';
import Compose from '../features/standalone/compose';
import initialState from '../initial_state';
import { fetchCustomEmojis } from '../actions/custom_emojis';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
const store = configureStore();
if (initialState) {
store.dispatch(hydrateStore(initialState));
}
store.dispatch(fetchCustomEmojis());
export default class TimelineContainer extends React.PureComponent {
static propTypes = {
locale: PropTypes.string.isRequired,
};
render() {
const { locale } = this.props;
return (
<IntlProvider locale={locale} messages={messages}>
<Provider store={store}>
<Compose />
</Provider>
</IntlProvider>
);
}
}

@ -1,92 +0,0 @@
import React, { PureComponent, Fragment } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales';
import MediaGallery from '../components/media_gallery';
import Video from '../features/video';
import Card from '../features/status/components/card';
import Poll from 'soapbox/components/poll';
import ModalRoot from '../components/modal_root';
import MediaModal from '../features/ui/components/media_modal';
import { List as ImmutableList, fromJS } from 'immutable';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
const MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll };
export default class MediaContainer extends PureComponent {
static propTypes = {
locale: PropTypes.string.isRequired,
components: PropTypes.object.isRequired,
};
state = {
media: null,
index: null,
time: null,
};
handleOpenMedia = (media, index) => {
document.body.classList.add('with-modals--active');
this.setState({ media, index });
}
handleOpenVideo = (video, time) => {
const media = ImmutableList([video]);
document.body.classList.add('with-modals--active');
this.setState({ media, time });
}
handleCloseMedia = () => {
document.body.classList.remove('with-modals--active');
this.setState({ media: null, index: null, time: null });
}
render() {
const { locale, components } = this.props;
return (
<IntlProvider locale={locale} messages={messages}>
<Fragment>
{[].map.call(components, (component, i) => {
const componentName = component.getAttribute('data-component');
const Component = MEDIA_COMPONENTS[componentName];
const { media, card, poll, ...props } = JSON.parse(component.getAttribute('data-props'));
Object.assign(props, {
...(media ? { media: fromJS(media) } : {}),
...(card ? { card: fromJS(card) } : {}),
...(poll ? { poll: fromJS(poll) } : {}),
...(componentName === 'Video' ? {
onOpenVideo: this.handleOpenVideo,
} : {
onOpenMedia: this.handleOpenMedia,
}),
});
return ReactDOM.createPortal(
<Component {...props} key={`media-${i}`} />,
component,
);
})}
<ModalRoot onClose={this.handleCloseMedia}>
{this.state.media && (
<MediaModal
media={this.state.media}
index={this.state.index || 0}
time={this.state.time}
onClose={this.handleCloseMedia}
/>
)}
</ModalRoot>
</Fragment>
</IntlProvider>
);
}
}

@ -14,8 +14,7 @@ import UI from '../features/ui';
// import Introduction from '../features/introduction'; // import Introduction from '../features/introduction';
import { fetchCustomEmojis } from '../actions/custom_emojis'; import { fetchCustomEmojis } from '../actions/custom_emojis';
import { hydrateStore } from '../actions/store'; import { hydrateStore } from '../actions/store';
import { IntlProvider, addLocaleData } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { getLocale } from '../locales';
import initialState from '../initial_state'; import initialState from '../initial_state';
import ErrorBoundary from '../components/error_boundary'; import ErrorBoundary from '../components/error_boundary';
import { fetchInstance } from 'soapbox/actions/instance'; import { fetchInstance } from 'soapbox/actions/instance';
@ -24,6 +23,7 @@ import { fetchMe } from 'soapbox/actions/me';
import PublicLayout from 'soapbox/features/public_layout'; import PublicLayout from 'soapbox/features/public_layout';
import { getSettings } from 'soapbox/actions/settings'; import { getSettings } from 'soapbox/actions/settings';
import { generateThemeCss } from 'soapbox/utils/theme'; import { generateThemeCss } from 'soapbox/utils/theme';
import messages from 'soapbox/locales/messages';
export const store = configureStore(); export const store = configureStore();
const hydrateAction = hydrateStore(initialState); const hydrateAction = hydrateStore(initialState);
@ -69,12 +69,35 @@ class SoapboxMount extends React.PureComponent {
dispatch: PropTypes.func, dispatch: PropTypes.func,
}; };
state = {
messages: {},
localeLoading: true,
}
setMessages = () => {
messages[this.props.locale]().then(messages => {
this.setState({ messages, localeLoading: false });
}).catch(() => {});
}
maybeUpdateMessages = prevProps => {
if (this.props.locale !== prevProps.locale) {
this.setMessages();
};
}
componentDidMount() {
this.setMessages();
}
componentDidUpdate(prevProps) {
this.maybeUpdateMessages(prevProps);
}
render() { render() {
const { me, themeCss, locale } = this.props; const { me, themeCss, locale } = this.props;
if (me === null) return null; if (me === null) return null;
if (this.state.localeLoading) return null;
const { localeData, messages } = getLocale();
addLocaleData(localeData);
// Disabling introduction for launch // Disabling introduction for launch
// const { showIntroduction } = this.props; // const { showIntroduction } = this.props;
@ -91,7 +114,7 @@ class SoapboxMount extends React.PureComponent {
}); });
return ( return (
<IntlProvider locale={locale} messages={messages}> <IntlProvider locale={locale} messages={this.state.messages}>
<> <>
<Helmet> <Helmet>
<body className={bodyClass} /> <body className={bodyClass} />

@ -1,58 +0,0 @@
import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
import configureStore from '../store/configureStore';
import { hydrateStore } from '../actions/store';
import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales';
import PublicTimeline from '../features/standalone/public_timeline';
import HashtagTimeline from '../features/standalone/hashtag_timeline';
import ModalContainer from '../features/ui/containers/modal_container';
import initialState from '../initial_state';
const { localeData, messages } = getLocale();
addLocaleData(localeData);
const store = configureStore();
if (initialState) {
store.dispatch(hydrateStore(initialState));
}
export default class TimelineContainer extends React.PureComponent {
static propTypes = {
locale: PropTypes.string.isRequired,
hashtag: PropTypes.string,
local: PropTypes.bool,
};
render() {
const { locale, hashtag, local } = this.props;
let timeline;
if (hashtag) {
timeline = <HashtagTimeline hashtag={hashtag} />;
} else {
timeline = <PublicTimeline local={local} />;
}
return (
<IntlProvider locale={locale} messages={messages}>
<Provider store={store}>
<Fragment>
{timeline}
{ReactDOM.createPortal(
<ModalContainer />,
document.getElementById('modal-container'),
)}
</Fragment>
</Provider>
</IntlProvider>
);
}
}

@ -15,6 +15,68 @@ import {
} from 'soapbox/features/forms'; } from 'soapbox/features/forms';
import SettingsCheckbox from './components/settings_checkbox'; import SettingsCheckbox from './components/settings_checkbox';
const languages = {
en: 'English',
ar: 'العربية',
ast: 'Asturianu',
bg: 'Български',
bn: 'বাংলা',
ca: 'Català',
co: 'Corsu',
cs: 'Čeština',
cy: 'Cymraeg',
da: 'Dansk',
de: 'Deutsch',
el: 'Ελληνικά',
eo: 'Esperanto',
es: 'Español',
eu: 'Euskara',
fa: 'فارسی',
fi: 'Suomi',
fr: 'Français',
ga: 'Gaeilge',
gl: 'Galego',
he: 'עברית',
hi: 'हिन्दी',
hr: 'Hrvatski',
hu: 'Magyar',
hy: 'Հայերեն',
id: 'Bahasa Indonesia',
io: 'Ido',
it: 'Italiano',
ja: '日本語',
ka: 'ქართული',
kk: 'Қазақша',
ko: '한국어',
lt: 'Lietuvių',
lv: 'Latviešu',
ml: 'മലയാളം',
ms: 'Bahasa Melayu',
nl: 'Nederlands',
no: 'Norsk',
oc: 'Occitan',
pl: 'Polski',
pt: 'Português',
'pt-BR': 'Português do Brasil',
ro: 'Română',
ru: 'Русский',
sk: 'Slovenčina',
sl: 'Slovenščina',
sq: 'Shqip',
sr: 'Српски',
'sr-Latn': 'Srpski (latinica)',
sv: 'Svenska',
ta: 'தமிழ்',
te: 'తెలుగు',
th: 'ไทย',
tr: 'Türkçe',
uk: 'Українська',
zh: '中文',
'zh-CN': '简体中文',
'zh-HK': '繁體中文(香港)',
'zh-TW': '繁體中文(臺灣)',
};
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'column.preferences', defaultMessage: 'Preferences' }, heading: { id: 'column.preferences', defaultMessage: 'Preferences' },
}); });
@ -33,10 +95,11 @@ class Preferences extends ImmutablePureComponent {
settings: ImmutablePropTypes.map, settings: ImmutablePropTypes.map,
}; };
onThemeChange = e => { onSelectChange = path => {
const { dispatch } = this.props; return e => {
dispatch(changeSetting(['themeMode'], e.target.value)); this.props.dispatch(changeSetting(path, e.target.value));
} };
};
onDefaultPrivacyChange = e => { onDefaultPrivacyChange = e => {
const { dispatch } = this.props; const { dispatch } = this.props;
@ -51,10 +114,19 @@ class Preferences extends ImmutablePureComponent {
<SimpleForm> <SimpleForm>
<FieldsGroup> <FieldsGroup>
<SelectDropdown <SelectDropdown
label='Theme mode' label='Theme'
items={{ light: 'Light', dark: 'Dark' }} items={{ light: 'Light', dark: 'Dark' }}
defaultValue={settings.get('themeMode')} defaultValue={settings.get('themeMode')}
onChange={this.onThemeChange} onChange={this.onSelectChange(['themeMode'])}
/>
</FieldsGroup>
<FieldsGroup>
<SelectDropdown
label='Language'
items={languages}
defaultValue={settings.get('locale')}
onChange={this.onSelectChange(['locale'])}
/> />
</FieldsGroup> </FieldsGroup>

@ -14,7 +14,7 @@ const mapStateToProps = (state, props) => ({
}); });
const wave = ( const wave = (
<svg class='wave' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 889' width='1440px' height='889px' preserveAspectRatio='none'> <svg className='wave' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 889' width='1440px' height='889px' preserveAspectRatio='none'>
<path d='M 0 0 L 0 851.82031 C 115.03104 776.54213 236.097 723.10606 363.20703 691.54492 C 640.06491 622.80164 852.93698 468.14039 954.31055 358.01367 C 1092.1151 208.31032 1206.0509 47.69868 1365.3828 13.457031 C 1391.8162 7.7762737 1416.6827 3.2957237 1440 0.001953125 L 1440 0 L 0 0 z' fill='var(--background-color)' /> <path d='M 0 0 L 0 851.82031 C 115.03104 776.54213 236.097 723.10606 363.20703 691.54492 C 640.06491 622.80164 852.93698 468.14039 954.31055 358.01367 C 1092.1151 208.31032 1206.0509 47.69868 1365.3828 13.457031 C 1391.8162 7.7762737 1416.6827 3.2957237 1440 0.001953125 L 1440 0 L 0 0 z' fill='var(--background-color)' />
</svg> </svg>
); );

@ -68,26 +68,26 @@ class TabsBar extends React.PureComponent {
links.push( links.push(
<Link key='logo' className='tabs-bar__link--logo' to='/' data-preview-title-id='column.home'> <Link key='logo' className='tabs-bar__link--logo' to='/' data-preview-title-id='column.home'>
<img alt='Logo' src={logo} /> <img alt='Logo' src={logo} />
<FormattedMessage id='tabs_bar.home' defaultMessage='Home' /> <span><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></span>
</Link>); </Link>);
} }
links.push( links.push(
<NavLink key='home' className='tabs-bar__link' exact to='/' data-preview-title-id='column.home'> <NavLink key='home' className='tabs-bar__link' exact to='/' data-preview-title-id='column.home'>
<Icon id='home' /> <Icon id='home' />
<FormattedMessage id='tabs_bar.home' defaultMessage='Home' /> <span><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></span>
</NavLink>); </NavLink>);
if (account) { if (account) {
links.push( links.push(
<NavLink key='notifications' className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications'> <NavLink key='notifications' className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications'>
<Icon id='bell' /> <Icon id='bell' />
<NotificationsCounterIcon /> <NotificationsCounterIcon />
<FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /> <span><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></span>
</NavLink>); </NavLink>);
} }
links.push( links.push(
<NavLink key='search' className='tabs-bar__link tabs-bar__link--search' to='/search' data-preview-title-id='tabs_bar.search'> <NavLink key='search' className='tabs-bar__link tabs-bar__link--search' to='/search' data-preview-title-id='tabs_bar.search'>
<Icon id='search' /> <Icon id='search' />
<FormattedMessage id='tabs_bar.search' defaultMessage='Search' /> <span><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></span>
</NavLink> </NavLink>
); );
return links.map((link) => return links.map((link) =>

@ -0,0 +1,64 @@
export default {
'ar': () => import(/* webpackChunkName: "locale_ar" */'./ar.json'),
'ast': () => import(/* webpackChunkName: "locale_ast" */'./ast.json'),
'bg': () => import(/* webpackChunkName: "locale_bg" */'./bg.json'),
'bn': () => import(/* webpackChunkName: "locale_bn" */'./bn.json'),
'br': () => import(/* webpackChunkName: "locale_br" */'./br.json'),
'ca': () => import(/* webpackChunkName: "locale_ca" */'./ca.json'),
'co': () => import(/* webpackChunkName: "locale_co" */'./co.json'),
'cs': () => import(/* webpackChunkName: "locale_cs" */'./cs.json'),
'cy': () => import(/* webpackChunkName: "locale_cy" */'./cy.json'),
'da': () => import(/* webpackChunkName: "locale_da" */'./da.json'),
'de': () => import(/* webpackChunkName: "locale_de" */'./de.json'),
'el': () => import(/* webpackChunkName: "locale_el" */'./el.json'),
'en': () => import(/* webpackChunkName: "locale_en" */'./en.json'),
'eo': () => import(/* webpackChunkName: "locale_eo" */'./eo.json'),
'es-AR': () => import(/* webpackChunkName: "locale_es-AR" */'./es-AR.json'),
'es': () => import(/* webpackChunkName: "locale_es" */'./es.json'),
'et': () => import(/* webpackChunkName: "locale_et" */'./et.json'),
'eu': () => import(/* webpackChunkName: "locale_eu" */'./eu.json'),
'fa': () => import(/* webpackChunkName: "locale_fa" */'./fa.json'),
'fi': () => import(/* webpackChunkName: "locale_fi" */'./fi.json'),
'fr': () => import(/* webpackChunkName: "locale_fr" */'./fr.json'),
'ga': () => import(/* webpackChunkName: "locale_ga" */'./ga.json'),
'gl': () => import(/* webpackChunkName: "locale_gl" */'./gl.json'),
'he': () => import(/* webpackChunkName: "locale_he" */'./he.json'),
'hi': () => import(/* webpackChunkName: "locale_hi" */'./hi.json'),
'hr': () => import(/* webpackChunkName: "locale_hr" */'./hr.json'),
'hu': () => import(/* webpackChunkName: "locale_hu" */'./hu.json'),
'hy': () => import(/* webpackChunkName: "locale_hy" */'./hy.json'),
'id': () => import(/* webpackChunkName: "locale_id" */'./id.json'),
'io': () => import(/* webpackChunkName: "locale_io" */'./io.json'),
'it': () => import(/* webpackChunkName: "locale_it" */'./it.json'),
'ja': () => import(/* webpackChunkName: "locale_ja" */'./ja.json'),
'ka': () => import(/* webpackChunkName: "locale_ka" */'./ka.json'),
'kk': () => import(/* webpackChunkName: "locale_kk" */'./kk.json'),
'ko': () => import(/* webpackChunkName: "locale_ko" */'./ko.json'),
'lt': () => import(/* webpackChunkName: "locale_lt" */'./lt.json'),
'lv': () => import(/* webpackChunkName: "locale_lv" */'./lv.json'),
'mk': () => import(/* webpackChunkName: "locale_mk" */'./mk.json'),
'ms': () => import(/* webpackChunkName: "locale_ms" */'./ms.json'),
'nl': () => import(/* webpackChunkName: "locale_nl" */'./nl.json'),
'nn': () => import(/* webpackChunkName: "locale_nn" */'./nn.json'),
'no': () => import(/* webpackChunkName: "locale_no" */'./no.json'),
'oc': () => import(/* webpackChunkName: "locale_oc" */'./oc.json'),
'pl': () => import(/* webpackChunkName: "locale_pl" */'./pl.json'),
'pt-BR': () => import(/* webpackChunkName: "locale_pt-BR" */'./pt-BR.json'),
'pt': () => import(/* webpackChunkName: "locale_pt" */'./pt.json'),
'ro': () => import(/* webpackChunkName: "locale_ro" */'./ro.json'),
'ru': () => import(/* webpackChunkName: "locale_ru" */'./ru.json'),
'sk': () => import(/* webpackChunkName: "locale_sk" */'./sk.json'),
'sl': () => import(/* webpackChunkName: "locale_sl" */'./sl.json'),
'sq': () => import(/* webpackChunkName: "locale_sq" */'./sq.json'),
'sr': () => import(/* webpackChunkName: "locale_sr" */'./sr.json'),
'sr-Latn': () => import(/* webpackChunkName: "locale_sr-Latn" */'./sr-Latn.json'),
'sv': () => import(/* webpackChunkName: "locale_sv" */'./sv.json'),
'ta': () => import(/* webpackChunkName: "locale_ta" */'./ta.json'),
'te': () => import(/* webpackChunkName: "locale_te" */'./te.json'),
'th': () => import(/* webpackChunkName: "locale_th" */'./th.json'),
'tr': () => import(/* webpackChunkName: "locale_tr" */'./tr.json'),
'uk': () => import(/* webpackChunkName: "locale_uk" */'./uk.json'),
'zh-CN': () => import(/* webpackChunkName: "locale_zh-CN" */'./zh-CN.json'),
'zh-HK': () => import(/* webpackChunkName: "locale_zh-HK" */'./zh-HK.json'),
'zh-TW': () => import(/* webpackChunkName: "locale_zh-TW" */'./zh-TW.json'),
};

@ -106,7 +106,7 @@
"react-hotkeys": "^1.1.4", "react-hotkeys": "^1.1.4",
"react-immutable-proptypes": "^2.1.0", "react-immutable-proptypes": "^2.1.0",
"react-immutable-pure-component": "^1.1.1", "react-immutable-pure-component": "^1.1.1",
"react-intl": "^2.9.0", "react-intl": "^4.6.6",
"react-masonry-infinite": "^1.2.2", "react-masonry-infinite": "^1.2.2",
"react-motion": "^0.5.2", "react-motion": "^0.5.2",
"react-notification": "^6.8.4", "react-notification": "^6.8.4",

@ -1,50 +0,0 @@
// 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/soapbox/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/soapbox/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/soapbox/locales/${locale}.json';
import localeData from ${JSON.stringify(localeDataPath)};
import { setLocale } from '../../app/soapbox/locales';
setLocale({messages, localeData});
`;
fs.writeFileSync(localePath, localeContent, 'utf8');
outPaths.push(localePath);
});
module.exports = outPaths;

@ -1,24 +1,17 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect // Note: You must restart bin/webpack-dev-server for changes to take effect
const webpack = require('webpack'); const webpack = require('webpack');
const { basename, join, resolve } = require('path'); const { join, resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const AssetsManifestPlugin = require('webpack-assets-manifest'); const AssetsManifestPlugin = require('webpack-assets-manifest');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin'); const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const extname = require('path-complete-extname');
const { env, settings, output } = require('./configuration'); const { env, settings, output } = require('./configuration');
const rules = require('./rules'); const rules = require('./rules');
const localePackPaths = require('./generateLocalePacks');
module.exports = { module.exports = {
entry: Object.assign( entry: Object.assign(
{ application: resolve('app/application.js') }, { application: resolve('app/application.js') },
localePackPaths.reduce((map, entry) => {
const localMap = map;
localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry);
return localMap;
}, {}),
{ styles: resolve(join(settings.source_path, 'styles/application.scss')) } { styles: resolve(join(settings.source_path, 'styles/application.scss')) }
), ),

@ -932,6 +932,41 @@
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.8.2.tgz#576ff7fb1230185b619a75d258cbc98f0867a8dc" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.8.2.tgz#576ff7fb1230185b619a75d258cbc98f0867a8dc"
integrity sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw== integrity sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw==
"@formatjs/intl-displaynames@^2.2.4":
version "2.2.4"
resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-2.2.4.tgz#c85d59b0d157470347fdfe86fb8fba7da998ebe1"
integrity sha512-/pRjDRcWub+JZ1B/oPHUhYdukyXoV28cyTMtSPNwEwxF1KIBz44X+EUaZuens9nM8DJtD3GvR9SnlicdT+tb9Q==
dependencies:
"@formatjs/intl-utils" "^3.3.1"
"@formatjs/intl-listformat@^2.2.4":
version "2.2.4"
resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-2.2.4.tgz#c7014ae7b593b9e20d24b6620e148122162903dc"
integrity sha512-sVKRJcrny4N/T2Z0k6qCfvYnl45zlPZcPWoafpLx7JDklWdhqIegdmtT6pncnDdCOLvV8AeyS9JHK3M6+UXWCg==
dependencies:
"@formatjs/intl-utils" "^3.3.1"
"@formatjs/intl-numberformat@^4.2.4":
version "4.2.4"
resolved "https://registry.yarnpkg.com/@formatjs/intl-numberformat/-/intl-numberformat-4.2.4.tgz#8d8e5b7d3ac9a3ed651b7895c806355ca3d24bc4"
integrity sha512-uPaDLCIZn/ORqmFE56CorGIU0wZZFgc1h7sjZ2ARxL1BG1dZBI8bLYSdb243xZYU/b/1fnRTVpZi4UJjW9NEOw==
dependencies:
"@formatjs/intl-utils" "^3.3.1"
"@formatjs/intl-relativetimeformat@^5.2.4":
version "5.2.4"
resolved "https://registry.yarnpkg.com/@formatjs/intl-relativetimeformat/-/intl-relativetimeformat-5.2.4.tgz#21465c3d4070c1a62abff531a9feec9390972bf8"
integrity sha512-dY3KBGWT6fPa+JM9zEUNOjfsKWJPd58lME0UdC10NidGzvQS74AmmUB06Fa3vRZm+u/1m6hJycIh7qy38MHnZA==
dependencies:
"@formatjs/intl-utils" "^3.3.1"
"@formatjs/intl-utils@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@formatjs/intl-utils/-/intl-utils-3.3.1.tgz#7ceadbb7e251318729d9bf693731e1a5dcdfa15a"
integrity sha512-7AAicg2wqCJQ+gFEw5Nxp+ttavajBrPAD1HDmzA4jzvUCrF5a2NCJm/c5qON3VBubWWF2cu8HglEouj2h/l7KQ==
dependencies:
emojis-list "^3.0.0"
"@jest/console@^24.7.1": "@jest/console@^24.7.1":
version "24.7.1" version "24.7.1"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
@ -1135,11 +1170,24 @@
"@types/minimatch" "*" "@types/minimatch" "*"
"@types/node" "*" "@types/node" "*"
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/html-minifier-terser@^5.0.0": "@types/html-minifier-terser@^5.0.0":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880"
integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA==
"@types/invariant@^2.2.31":
version "2.2.33"
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.33.tgz#ec5eec29c63bf5e4ca164e9feb3ef7337cdcbadb"
integrity sha512-/jUNmS8d4bCKdqslfxW6dg/9Gksfzxz67IYfqApHn+HvHlMVXwYv2zpTDnS/yaK9BB0i0GlBTaYci0EFE62Hmw==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@ -1170,11 +1218,24 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/q@^1.5.1": "@types/q@^1.5.1":
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18"
integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA== integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==
"@types/react@*":
version "16.9.35"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.35.tgz#a0830d172e8aadd9bd41709ba2281a3124bbd368"
integrity sha512-q0n0SsWcGc8nDqH2GJfWQWUOmZSJhXV64CjVN5SvcNti3TdEaA3AH0D8DwNmMdzjMAC/78tB8nAZIlV8yTz+zQ==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/react@16.4.6": "@types/react@16.4.6":
version "16.4.6" version "16.4.6"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.6.tgz#5024957c6bcef4f02823accf5974faba2e54fada" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.6.tgz#5024957c6bcef4f02823accf5974faba2e54fada"
@ -3561,6 +3622,11 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
emotion@^9.1.2: emotion@^9.1.2:
version "9.2.12" version "9.2.12"
resolved "https://registry.yarnpkg.com/emotion/-/emotion-9.2.12.tgz#53925aaa005614e65c6e43db8243c843574d1ea9" resolved "https://registry.yarnpkg.com/emotion/-/emotion-9.2.12.tgz#53925aaa005614e65c6e43db8243c843574d1ea9"
@ -4944,6 +5010,13 @@ hoist-non-react-statics@^3.3.0:
dependencies: dependencies:
react-is "^16.7.0" react-is "^16.7.0"
hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
homedir-polyfill@^1.0.1: homedir-polyfill@^1.0.1:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
@ -5312,20 +5385,15 @@ intersection-observer@^0.7.0:
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9" resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9"
integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg== integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==
intl-format-cache@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316"
integrity sha1-BKNp/sv61tpgBbrh8UMzMy3PkxY=
intl-format-cache@^4.2.2: intl-format-cache@^4.2.2:
version "4.2.2" version "4.2.2"
resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-4.2.2.tgz#4e745d4cda3aa9df2495f0493bed4c6c4ff7093d" resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-4.2.2.tgz#4e745d4cda3aa9df2495f0493bed4c6c4ff7093d"
integrity sha512-7tY3XadLn8rMHiYVUzH/6NmOe944nJ59LdAWuFm64/m2OfFAEkZTtTHxrEtoxq7HWFddX4aRwDb9P8KB5Z2AvQ== integrity sha512-7tY3XadLn8rMHiYVUzH/6NmOe944nJ59LdAWuFm64/m2OfFAEkZTtTHxrEtoxq7HWFddX4aRwDb9P8KB5Z2AvQ==
intl-messageformat-parser@1.4.0: intl-format-cache@^4.2.36:
version "1.4.0" version "4.2.36"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-4.2.36.tgz#d23eba77be5357c0f5efb5e059024d3a9b3576d3"
integrity sha1-tD1FqXRoytvkQzHXS7Ho3qRPwHU= integrity sha512-fOPm5Z0Krge7/rYq6hc1c/m8HRu9MwgnhLU7M9J4w3wHZS2RQwyZ0kpzmY9n86YRuUlcH29bGoeKDx/7D1nRhg==
intl-messageformat-parser@^1.6.3: intl-messageformat-parser@^1.6.3:
version "1.6.3" version "1.6.3"
@ -5337,12 +5405,12 @@ intl-messageformat-parser@^3.2.1:
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-3.2.1.tgz#598795221267cbbd206f1497c42ffced9b5565b6" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-3.2.1.tgz#598795221267cbbd206f1497c42ffced9b5565b6"
integrity sha512-ajCL1k1ha0mUrutlBTo5vcTzyfdH2OoghUu8SmR7tJ1D0uifZh9Hqd3ZC2SYVv/GTfTdW//rgKonMgAhZWmwZg== integrity sha512-ajCL1k1ha0mUrutlBTo5vcTzyfdH2OoghUu8SmR7tJ1D0uifZh9Hqd3ZC2SYVv/GTfTdW//rgKonMgAhZWmwZg==
intl-messageformat@^2.0.0, intl-messageformat@^2.1.0: intl-messageformat-parser@^5.1.1:
version "2.2.0" version "5.1.1"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-5.1.1.tgz#1f223c6c615ada46bd8902cdae7f5f7c21f08934"
integrity sha1-NFvNRt5jC3aDMwwuUhd/9eq0hPw= integrity sha512-KSKa+pGpxhfAtx9CptkdqGebs2/f6GWAGfoWsPe6SvxRNk6egYFfewpyH3YXwY2ZMeiZ/Q82buWZhxHKazFrBQ==
dependencies: dependencies:
intl-messageformat-parser "1.4.0" "@formatjs/intl-numberformat" "^4.2.4"
intl-messageformat@^7.0.0: intl-messageformat@^7.0.0:
version "7.3.2" version "7.3.2"
@ -5352,6 +5420,14 @@ intl-messageformat@^7.0.0:
intl-format-cache "^4.2.2" intl-format-cache "^4.2.2"
intl-messageformat-parser "^3.2.1" intl-messageformat-parser "^3.2.1"
intl-messageformat@^8.3.21:
version "8.3.21"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-8.3.21.tgz#525a6597d7860a6048e16297f81f762ee8e9e10e"
integrity sha512-zicqT9IVMwPFDATBZhkXI7y/opo3BOKcTS+vPdco7H9sGWXx0m+aAE3Irvgmfhp7gyJEmfdAxU6+6mJW49/sVw==
dependencies:
intl-format-cache "^4.2.36"
intl-messageformat-parser "^5.1.1"
intl-pluralrules@^1.1.1: intl-pluralrules@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/intl-pluralrules/-/intl-pluralrules-1.1.1.tgz#b7ee135a9f0f5630d57a59c4a7ab8b875484f64d" resolved "https://registry.yarnpkg.com/intl-pluralrules/-/intl-pluralrules-1.1.1.tgz#b7ee135a9f0f5630d57a59c4a7ab8b875484f64d"
@ -5359,19 +5435,12 @@ intl-pluralrules@^1.1.1:
dependencies: dependencies:
make-plural "^6.0.1" make-plural "^6.0.1"
intl-relativeformat@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-2.2.0.tgz#6aca95d019ec8d30b6c5653b6629f9983ea5b6c5"
integrity sha512-4bV/7kSKaPEmu6ArxXf9xjv1ny74Zkwuey8Pm01NH4zggPP7JHwg2STk8Y3JdspCKRDriwIyLRfEXnj2ZLr4Bw==
dependencies:
intl-messageformat "^2.0.0"
intl@^1.2.5: intl@^1.2.5:
version "1.2.5" version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94= integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=
invariant@^2.1.1, invariant@^2.2.2, invariant@^2.2.4: invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@ -8592,16 +8661,23 @@ react-intl-translations-manager@^5.0.3:
json-stable-stringify "^1.0.1" json-stable-stringify "^1.0.1"
mkdirp "^0.5.1" mkdirp "^0.5.1"
react-intl@^2.9.0: react-intl@^4.6.6:
version "2.9.0" version "4.6.6"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.9.0.tgz#c97c5d17d4718f1575fdbd5a769f96018a3b1843" resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-4.6.6.tgz#58653e78ae8f905b80c785b0a9c862ffaa30d543"
integrity sha512-27jnDlb/d2A7mSJwrbOBnUgD+rPep+abmoJE511Tf8BnoONIAUehy/U1zZCHGO17mnOwMWxqN4qC0nW11cD6rA== integrity sha512-ykah1umgIOHTC4DZ5fFn6U5ZtSMW5sZKKG5sFL5xrNA55UVnzU3g+v1j0fapO85VMC8x6db+ixP9mgX60Ziupw==
dependencies: dependencies:
hoist-non-react-statics "^3.3.0" "@formatjs/intl-displaynames" "^2.2.4"
intl-format-cache "^2.0.5" "@formatjs/intl-listformat" "^2.2.4"
intl-messageformat "^2.1.0" "@formatjs/intl-numberformat" "^4.2.4"
intl-relativeformat "^2.1.0" "@formatjs/intl-relativetimeformat" "^5.2.4"
invariant "^2.1.1" "@formatjs/intl-utils" "^3.3.1"
"@types/hoist-non-react-statics" "^3.3.1"
"@types/invariant" "^2.2.31"
hoist-non-react-statics "^3.3.2"
intl-format-cache "^4.2.36"
intl-messageformat "^8.3.21"
intl-messageformat-parser "^5.1.1"
shallow-equal "^1.2.1"
react-is@^16.3.2, react-is@^16.6.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.2, react-is@^16.8.4: react-is@^16.3.2, react-is@^16.6.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.2, react-is@^16.8.4:
version "16.8.6" version "16.8.6"
@ -9558,6 +9634,11 @@ shallow-clone@^3.0.0:
dependencies: dependencies:
kind-of "^6.0.2" kind-of "^6.0.2"
shallow-equal@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
shebang-command@^1.2.0: shebang-command@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"

Loading…
Cancel
Save