From 2b6aff535ed8091133b31492f76230aa2b574663 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 23 Mar 2020 14:07:05 -0300 Subject: [PATCH] Migrate "i18n-provider" to new context API (#8213) The "i18n-provider" module has been replaced by a new `i18n.js` module in the `contexts` directory which provides the `t` function via the new React Context API. The legacy context API is still used throughout the codebase, so a legacy context provider has also been added as a shim until we migrate away from the old API. The migration does require changing every single place where the `t` function is used, so it is a non-trivial amount of work. This shim allows us to tackle it one piece at a time without breaking anything. This was placed in a new `contexts` directory because it didn't seem to belong in any existing categories. It certainly isn't a higher-order component. --- .storybook/preview.js | 2 +- ui/app/contexts/i18n.js | 61 +++++++++++++++++++ ui/app/ducks/locale/locale.js | 4 ++ ui/app/ducks/metamask/metamask.js | 2 + .../higher-order-components/i18n-provider.js | 46 -------------- ui/app/pages/index.js | 16 +++-- 6 files changed, 78 insertions(+), 53 deletions(-) create mode 100644 ui/app/contexts/i18n.js delete mode 100644 ui/app/helpers/higher-order-components/i18n-provider.js diff --git a/.storybook/preview.js b/.storybook/preview.js index 4100c1b27..1ad59ab78 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,7 +1,7 @@ import React from 'react' import { addDecorator, addParameters } from '@storybook/react' import { withKnobs } from '@storybook/addon-knobs/react' -import I18nProvider from '../ui/app/helpers/higher-order-components/i18n-provider' +import I18nProvider from '../ui/app/contexts/i18n' import { Provider } from 'react-redux' import configureStore from '../ui/app/store/store' import '../ui/app/css/index.scss' diff --git a/ui/app/contexts/i18n.js b/ui/app/contexts/i18n.js new file mode 100644 index 000000000..eb5d4e1cd --- /dev/null +++ b/ui/app/contexts/i18n.js @@ -0,0 +1,61 @@ +import React, { Component, createContext, useMemo } from 'react' +import PropTypes from 'prop-types' +import { useSelector } from 'react-redux' +import { getMessage } from '../helpers/utils/i18n-helper' +import { getCurrentLocale } from '../ducks/metamask/metamask' +import { getCurrentLocaleMessages, getEnLocaleMessages } from '../ducks/locale/locale' + +export const I18nContext = createContext((key) => `[${key}]`) + +export const I18nProvider = (props) => { + const currentLocale = useSelector(getCurrentLocale) + const current = useSelector(getCurrentLocaleMessages) + const en = useSelector(getEnLocaleMessages) + + const t = useMemo(() => { + return (key, ...args) => ( + getMessage(currentLocale, current, key, ...args) || + getMessage(currentLocale, en, key, ...args) + ) + }, [currentLocale, current, en]) + + return ( + + { props.children } + + ) +} + +I18nProvider.propTypes = { + children: PropTypes.node, +} + +I18nProvider.defaultProps = { + children: undefined, +} + +export class LegacyI18nProvider extends Component { + static propTypes = { + children: PropTypes.node, + } + + static defaultProps = { + children: undefined, + } + + static contextType = I18nContext + + static childContextTypes = { + t: PropTypes.func, + } + + getChildContext () { + return { + t: this.context, + } + } + + render () { + return this.props.children + } +} diff --git a/ui/app/ducks/locale/locale.js b/ui/app/ducks/locale/locale.js index d815acfeb..323a82d46 100644 --- a/ui/app/ducks/locale/locale.js +++ b/ui/app/ducks/locale/locale.js @@ -11,3 +11,7 @@ export default function reduceLocaleMessages (state = {}, { type, value }) { return state } } + +export const getCurrentLocaleMessages = (state) => state.localeMessages.current + +export const getEnLocaleMessages = (state) => state.localeMessages.en diff --git a/ui/app/ducks/metamask/metamask.js b/ui/app/ducks/metamask/metamask.js index af3eff43f..a326763d0 100644 --- a/ui/app/ducks/metamask/metamask.js +++ b/ui/app/ducks/metamask/metamask.js @@ -379,3 +379,5 @@ export default function reduceMetamask (state = {}, action) { return metamaskState } } + +export const getCurrentLocale = (state) => state.metamask.currentLocale diff --git a/ui/app/helpers/higher-order-components/i18n-provider.js b/ui/app/helpers/higher-order-components/i18n-provider.js deleted file mode 100644 index bf61ed292..000000000 --- a/ui/app/helpers/higher-order-components/i18n-provider.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Component } from 'react' -import { connect } from 'react-redux' -import PropTypes from 'prop-types' -import { getMessage } from '../utils/i18n-helper' - -class I18nProvider extends Component { - getChildContext () { - const { localeMessages, currentLocale } = this.props - const { current, en } = localeMessages - return { - /** - * Returns a localized message for the given key - * @param {string} key - The message key - * @param {string[]} args - A list of message substitution replacements - * @returns {string|undefined|null} - The localized message if available - */ - t (key, ...args) { - return getMessage(currentLocale, current, key, ...args) || getMessage(currentLocale, en, key, ...args) - }, - } - } - - render () { - return this.props.children - } -} - -I18nProvider.propTypes = { - localeMessages: PropTypes.object, - currentLocale: PropTypes.string, - children: PropTypes.object, -} - -I18nProvider.childContextTypes = { - t: PropTypes.func, -} - -const mapStateToProps = (state) => { - const { localeMessages, metamask: { currentLocale } } = state - return { - currentLocale, - localeMessages, - } -} - -export default connect(mapStateToProps)(I18nProvider) diff --git a/ui/app/pages/index.js b/ui/app/pages/index.js index 7de4fb408..3d8ccf165 100644 --- a/ui/app/pages/index.js +++ b/ui/app/pages/index.js @@ -5,7 +5,7 @@ import { HashRouter } from 'react-router-dom' import * as Sentry from '@sentry/browser' import ErrorPage from './error' import Routes from './routes' -import I18nProvider from '../helpers/higher-order-components/i18n-provider' +import { I18nProvider, LegacyI18nProvider } from '../contexts/i18n' import MetaMetricsProvider from '../helpers/higher-order-components/metametrics/metametrics.provider' class Index extends PureComponent { @@ -27,10 +27,12 @@ class Index extends PureComponent { return ( - + + + ) @@ -41,7 +43,9 @@ class Index extends PureComponent { - + + +