diff --git a/config/webpack.common.config.js b/config/webpack.common.config.js index b2845fe..33f128d 100755 --- a/config/webpack.common.config.js +++ b/config/webpack.common.config.js @@ -12,5 +12,8 @@ module.exports = { }, resolve: { extensions: ['.js', '.jsx'], + alias: { + '@edx/frontend-i18n': path.resolve(__dirname, '../src/i18n/'), + }, }, }; diff --git a/package.json b/package.json index 4c544c8..f7fd8f2 100755 --- a/package.json +++ b/package.json @@ -125,7 +125,8 @@ "moduleNameMapper": { "\\.svg": "/__mocks__/svgrMock.js", "\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", - "\\.(css|scss)$": "identity-obj-proxy" + "\\.(css|scss)$": "identity-obj-proxy", + "@edx/frontend-i18n(.*)$": "/src/i18n$1" }, "collectCoverageFrom": [ "src/**/*.{js,jsx}" diff --git a/src/components/App.jsx b/src/components/App.jsx index 5cd2f99..43a04dc 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -9,7 +9,7 @@ import SiteFooter from '@edx/frontend-component-footer'; import { fetchUserAccount, UserAccountApiService } from '@edx/frontend-auth'; import apiClient from '../config/apiClient'; -import { getLocale, getMessages } from '../i18n/i18n-loader'; +import { getLocale, getMessages } from '@edx/frontend-i18n'; // eslint-disable-line import SiteHeader from './common/SiteHeader'; import ConnectedProfilePage from './ProfilePage'; diff --git a/src/components/ProfilePage.jsx b/src/components/ProfilePage.jsx index de8aa79..277ae9b 100644 --- a/src/components/ProfilePage.jsx +++ b/src/components/ProfilePage.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { StatusAlert, Hyperlink } from '@edx/paragon'; import { connect } from 'react-redux'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line // Analytics import { sendTrackingLogEvent } from '@edx/frontend-analytics'; diff --git a/src/components/ProfilePage/Bio.jsx b/src/components/ProfilePage/Bio.jsx index bf4fb68..34996eb 100644 --- a/src/components/ProfilePage/Bio.jsx +++ b/src/components/ProfilePage/Bio.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { ValidationFormGroup } from '@edx/paragon'; import messages from './Bio.messages'; diff --git a/src/components/ProfilePage/Certificates.jsx b/src/components/ProfilePage/Certificates.jsx index 06d057e..42752e4 100644 --- a/src/components/ProfilePage/Certificates.jsx +++ b/src/components/ProfilePage/Certificates.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape, FormattedDate, FormattedMessage } from 'react-intl'; +import { FormattedDate, FormattedMessage } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { Hyperlink } from '@edx/paragon'; import { connect } from 'react-redux'; import get from 'lodash.get'; diff --git a/src/components/ProfilePage/Country.jsx b/src/components/ProfilePage/Country.jsx index 9d4068f..fa26f77 100644 --- a/src/components/ProfilePage/Country.jsx +++ b/src/components/ProfilePage/Country.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { ValidationFormGroup } from '@edx/paragon'; import messages from './Country.messages'; diff --git a/src/components/ProfilePage/Education.jsx b/src/components/ProfilePage/Education.jsx index fc7d49d..b3a9403 100644 --- a/src/components/ProfilePage/Education.jsx +++ b/src/components/ProfilePage/Education.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { FormattedMessage, injectIntl, intlShape } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import get from 'lodash.get'; import { ValidationFormGroup } from '@edx/paragon'; diff --git a/src/components/ProfilePage/Name.jsx b/src/components/ProfilePage/Name.jsx index ba965b8..6ff6b49 100644 --- a/src/components/ProfilePage/Name.jsx +++ b/src/components/ProfilePage/Name.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import messages from './Name.messages'; diff --git a/src/components/ProfilePage/PreferredLanguage.jsx b/src/components/ProfilePage/PreferredLanguage.jsx index 40227df..c10462d 100644 --- a/src/components/ProfilePage/PreferredLanguage.jsx +++ b/src/components/ProfilePage/PreferredLanguage.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { ValidationFormGroup } from '@edx/paragon'; import messages from './PreferredLanguage.messages'; diff --git a/src/components/ProfilePage/ProfileAvatar.jsx b/src/components/ProfilePage/ProfileAvatar.jsx index ad21f65..3189183 100644 --- a/src/components/ProfilePage/ProfileAvatar.jsx +++ b/src/components/ProfilePage/ProfileAvatar.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button, Dropdown } from '@edx/paragon'; -import { FormattedMessage, injectIntl, intlShape } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { ReactComponent as DefaultAvatar } from '../../assets/avatar.svg'; diff --git a/src/components/ProfilePage/SocialLinks.jsx b/src/components/ProfilePage/SocialLinks.jsx index 7428cb7..80572f4 100644 --- a/src/components/ProfilePage/SocialLinks.jsx +++ b/src/components/ProfilePage/SocialLinks.jsx @@ -4,7 +4,8 @@ import { StatusAlert } from '@edx/paragon'; import { connect } from 'react-redux'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTwitter, faFacebook, faLinkedin } from '@fortawesome/free-brands-svg-icons'; -import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import classNames from 'classnames'; import messages from './SocialLinks.messages'; diff --git a/src/components/ProfilePage/elements/EditButton.jsx b/src/components/ProfilePage/elements/EditButton.jsx index 0591a00..0a052b2 100644 --- a/src/components/ProfilePage/elements/EditButton.jsx +++ b/src/components/ProfilePage/elements/EditButton.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPencilAlt } from '@fortawesome/free-solid-svg-icons'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { Button } from '@edx/paragon'; import messages from './EditButton.messages'; diff --git a/src/components/ProfilePage/elements/FormControls.jsx b/src/components/ProfilePage/elements/FormControls.jsx index d002034..eb72800 100644 --- a/src/components/ProfilePage/elements/FormControls.jsx +++ b/src/components/ProfilePage/elements/FormControls.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button, StatefulButton } from '@edx/paragon'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import messages from './FormControls.messages'; diff --git a/src/components/ProfilePage/elements/Visibility.jsx b/src/components/ProfilePage/elements/Visibility.jsx index b5dcf4c..36f5a5e 100644 --- a/src/components/ProfilePage/elements/Visibility.jsx +++ b/src/components/ProfilePage/elements/Visibility.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from '@edx/frontend-i18n'; // eslint-disable-line import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEyeSlash, faEye } from '@fortawesome/free-regular-svg-icons'; diff --git a/src/components/common/SiteHeader.jsx b/src/components/common/SiteHeader.jsx index 4325377..e65be54 100644 --- a/src/components/common/SiteHeader.jsx +++ b/src/components/common/SiteHeader.jsx @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import SiteHeader from '@edx/frontend-component-site-header'; -import { injectIntl } from 'react-intl'; +import { injectIntl } from '@edx/frontend-i18n'; // eslint-disable-line import messages from './SiteHeader.messages'; diff --git a/src/i18n/index.jsx b/src/i18n/index.jsx new file mode 100644 index 0000000..ef4d5a8 --- /dev/null +++ b/src/i18n/index.jsx @@ -0,0 +1,25 @@ +import { intlShape } from 'react-intl'; +import injectIntlWithShim from './injectIntlWithShim'; +import { + getCountryList, + getCountryMessages, + getLanguageList, + getLanguageMessages, + getLocale, + getMessages, + handleRtl, + isRtl, +} from './i18n-loader'; + +export { + injectIntlWithShim as injectIntl, + getCountryList, + getCountryMessages, + getLanguageList, + getLanguageMessages, + getLocale, + getMessages, + handleRtl, + isRtl, + intlShape, +}; diff --git a/src/i18n/injectIntlWithShim.jsx b/src/i18n/injectIntlWithShim.jsx new file mode 100644 index 0000000..7fcb631 --- /dev/null +++ b/src/i18n/injectIntlWithShim.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { injectIntl, intlShape } from 'react-intl'; +import LoggingService from '@edx/frontend-logging'; + + +const injectIntlWithShim = (WrappedComponent) => { + class ShimmedIntlComponent extends React.Component { + static propTypes = { + intl: intlShape.isRequired, + }; + + constructor(props) { + super(props); + this.shimmedIntl = Object.create(this.props.intl, { + formatMessage: { + value: (definition) => { + if (definition === undefined || definition.id === undefined) { + const error = new Error('i18n error: An undefined message was supplied to intl.formatMessage.'); + if (process.env.NODE_ENV !== 'production') { + console.error(error); // eslint-disable-line no-console + return '!!! Missing message supplied to intl.formatMessage !!!'; + } + LoggingService.logError(error); + return ''; // Fail silent in production + } + return this.props.intl.formatMessage(definition); + }, + }, + }); + } + + render() { + return ; + } + } + + return injectIntl(ShimmedIntlComponent); +}; + + +export default injectIntlWithShim; diff --git a/src/selectors/ProfilePageSelector.js b/src/selectors/ProfilePageSelector.js index c945dc1..08b0ba9 100644 --- a/src/selectors/ProfilePageSelector.js +++ b/src/selectors/ProfilePageSelector.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import { getLocale, getLanguageList, getCountryList, getCountryMessages, getLanguageMessages } from '../i18n/i18n-loader'; +import { getLocale, getLanguageList, getCountryList, getCountryMessages, getLanguageMessages } from '@edx/frontend-i18n'; // eslint-disable-line export const formIdSelector = (state, props) => props.formId; export const userAccountSelector = state => state.userAccount;