From bc8fa9c45bce0e5f76fa0d21744845d129969b8d Mon Sep 17 00:00:00 2001 From: Vinay Date: Sun, 8 Jul 2018 23:12:32 +0800 Subject: [PATCH] Update to React 16 context API --- example/App.js | 2 +- example/index.js | 5 +++-- example/package.json | 4 ++-- lib/context.js | 19 +++++++++++++++++++ lib/provider.js | 35 ++++++++++++++++++++++------------- lib/withTranslate.js | 38 ++++++++++++++++++-------------------- package.json | 4 ++-- src/context.js | 10 ++++++++++ src/provider.js | 36 ++++++++++++++++++++++-------------- src/withTranslate.js | 27 +++++++++++++-------------- 10 files changed, 112 insertions(+), 68 deletions(-) create mode 100644 lib/context.js create mode 100644 src/context.js diff --git a/example/App.js b/example/App.js index fc9e670..f99b2b6 100644 --- a/example/App.js +++ b/example/App.js @@ -5,7 +5,7 @@ import { withTranslate, IntlActions } from 'react-redux-multilingual' const App = ({ translate, dispatch }) => { return (
-

Hey theres

+

Hey there

{translate('hello')}

diff --git a/example/index.js b/example/index.js index 864fdb7..0e33e38 100644 --- a/example/index.js +++ b/example/index.js @@ -6,8 +6,9 @@ import { createStore, combineReducers } from 'redux' import { Provider } from 'react-redux' import App from './App' -let reducers = combineReducers(Object.assign({}, { Intl })) -let store = createStore(reducers) +const defaultLocale = 'zh' +const reducers = combineReducers(Object.assign({}, { Intl })) +const store = createStore(reducers, { Intl: { locale: defaultLocale }}) ReactDOM.render( diff --git a/example/package.json b/example/package.json index bc40ca9..926c9e4 100644 --- a/example/package.json +++ b/example/package.json @@ -9,8 +9,8 @@ "author": "", "license": "ISC", "dependencies": { - "react": "^15.1.0", - "react-dom": "^15.1.0", + "react": "^16.4.1", + "react-dom": "^16.4.1", "react-redux": "^4.4.5", "react-redux-multilingual": "^1.0.4", "redux": "^3.5.2" diff --git a/lib/context.js b/lib/context.js new file mode 100644 index 0000000..d4d29fc --- /dev/null +++ b/lib/context.js @@ -0,0 +1,19 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.TranslateConsumer = exports.TranslateProvider = undefined; + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var TranslateContext = _react2.default.createContext(null); +var TranslateProvider = TranslateContext.Provider, + TranslateConsumer = TranslateContext.Consumer; +exports.TranslateProvider = TranslateProvider; +exports.TranslateConsumer = TranslateConsumer; +exports.default = TranslateContext; \ No newline at end of file diff --git a/lib/provider.js b/lib/provider.js index 651a6e7..04f6557 100644 --- a/lib/provider.js +++ b/lib/provider.js @@ -20,6 +20,10 @@ var _reactRedux = require('react-redux'); var _utils = require('./utils'); +var _actions = require('./actions'); + +var _context = require('./context'); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -37,14 +41,22 @@ var IntlProvider = function (_React$Component) { var _this = _possibleConstructorReturn(this, (IntlProvider.__proto__ || Object.getPrototypeOf(IntlProvider)).call(this, props)); _this.translate = function (key, placeholders, isHTML) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var result = (0, _utils.translateKey)(key, _this.props.translations[_this.props.locale]['messages']); + var tagName = options.tagName || 'div'; if (typeof placeholders === 'undefined') { return result; } - return isHTML ? _react2.default.createElement('div', { dangerouslySetInnerHTML: (0, _utils.createHTMLMarkup)((0, _utils.supplant)(result, placeholders)) }) : (0, _utils.supplant)(result, placeholders); + var finalResult = (0, _utils.supplant)(result, placeholders); + return isHTML ? _react2.default.createElement(tagName, { dangerouslySetInnerHTML: (0, _utils.createHTMLMarkup)(finalResult) }, null) : finalResult; }; - if (!props.translations || !props.locale) { + var translations = props.translations, + locale = props.locale, + setLocale = props.setLocale; + + if (!translations || !locale) { var namePart = _this.constructor.displayName ? ' of ' + _this.constructor.displayName : ''; throw new Error('Could not find translations or locale on this.props ' + namePart); } @@ -52,24 +64,21 @@ var IntlProvider = function (_React$Component) { } _createClass(IntlProvider, [{ - key: 'getChildContext', - value: function getChildContext() { - return { - translate: this.translate - }; - } - }, { key: 'render', value: function render() { - return _react.Children.only(this.props.children); + return _react2.default.createElement( + _context.TranslateProvider, + { value: this.translate }, + this.props.children + ); } }]); return IntlProvider; }(_react2.default.Component); -IntlProvider.childContextTypes = { - translate: _propTypes2.default.func +IntlProvider.defaultProps = { + translations: {} }; @@ -81,4 +90,4 @@ function mapPropsToState(state) { }); } -exports.default = (0, _reactRedux.connect)(mapPropsToState)(IntlProvider); \ No newline at end of file +exports.default = (0, _reactRedux.connect)(mapPropsToState, { setLocale: _actions.setLocale })(IntlProvider); \ No newline at end of file diff --git a/lib/withTranslate.js b/lib/withTranslate.js index 7c92ed5..bffb555 100644 --- a/lib/withTranslate.js +++ b/lib/withTranslate.js @@ -10,27 +10,25 @@ var _react = require('react'); var _react2 = _interopRequireDefault(_react); -var _propTypes = require('prop-types'); - -var _propTypes2 = _interopRequireDefault(_propTypes); - -var _hoistNonReactStatics = require('hoist-non-react-statics'); - -var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics); +var _context = require('./context'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var getComponentDisplayName = function getComponentDisplayName(WrappedComponent) { - return WrappedComponent.displayName || WrappedComponent.name || 'Component'; -}; - -exports.default = function (WrappedComponent) { - var WithTranslate = function WithTranslate(props, context) { - return _react2.default.createElement(WrappedComponent, _extends({}, props, { translate: context.translate })); - }; - WithTranslate.displayName = 'withTranslate(' + getComponentDisplayName(WrappedComponent) + ')'; - WithTranslate.contextTypes = { - translate: _propTypes2.default.func +/** + * Access translate function + * @param {Object} WrappedComponent + * @return {Object} + */ +function withTranslate(WrappedComponent) { + return function (props) { + return _react2.default.createElement( + _context.TranslateConsumer, + null, + function (translate) { + return _react2.default.createElement(WrappedComponent, _extends({}, props, { translate: translate })); + } + ); }; - return (0, _hoistNonReactStatics2.default)(WithTranslate, WrappedComponent); -}; \ No newline at end of file +} + +exports.default = withTranslate; \ No newline at end of file diff --git a/package.json b/package.json index 045b7b0..c5ad9e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-redux-multilingual", - "version": "1.0.4", + "version": "1.0.5", "description": "A simple multilingual translate component and HOC for react and redux", "main": "lib/index.js", "scripts": { @@ -26,7 +26,7 @@ "prop-types": "^15.5.8" }, "peerDependencies": { - "react": "^0.14.0 || ^15.1.0", + "react": ">16.3.0", "react-redux": "^4.4.0", "redux": "^3.3.1" }, diff --git a/src/context.js b/src/context.js new file mode 100644 index 0000000..88b7749 --- /dev/null +++ b/src/context.js @@ -0,0 +1,10 @@ +import React from 'react' + +const TranslateContext = React.createContext(null) +const { + Provider: TranslateProvider, + Consumer: TranslateConsumer +} = TranslateContext + +export { TranslateProvider, TranslateConsumer } +export default TranslateContext \ No newline at end of file diff --git a/src/provider.js b/src/provider.js index 6e6b6ba..c1b5519 100644 --- a/src/provider.js +++ b/src/provider.js @@ -2,34 +2,42 @@ import React, { Children } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' import { supplant, translateKey, createHTMLMarkup } from './utils' +import { setLocale } from './actions' +import { TranslateProvider } from './context' class IntlProvider extends React.Component { constructor (props) { super(props) - if (!props.translations || !props.locale) { + const { translations, locale, setLocale } = props + if (!translations || !locale) { let namePart = this.constructor.displayName ? ' of ' + this.constructor.displayName : '' throw new Error('Could not find translations or locale on this.props ' + namePart) } } - static childContextTypes = { - translate: PropTypes.func + static defaultProps = { + translations: {} }; - translate = (key, placeholders, isHTML) => { - let result = translateKey(key, this.props.translations[this.props.locale]['messages']) + translate = (key, placeholders, isHTML, options = {}) => { + const result = translateKey(key, this.props.translations[this.props.locale]['messages']) + const tagName = options.tagName || 'div' if (typeof placeholders === 'undefined') { return result } + const finalResult = supplant(result, placeholders) return isHTML - ?

- : supplant(result, placeholders) + ? React.createElement( + tagName, + { dangerouslySetInnerHTML: createHTMLMarkup(finalResult) }, + null + ) + : finalResult }; - getChildContext () { - return { - translate: this.translate - } - } render () { - return Children.only(this.props.children) + return ( + + {this.props.children} + + ) } } @@ -41,4 +49,4 @@ function mapPropsToState (state) { } } -export default connect(mapPropsToState)(IntlProvider) +export default connect(mapPropsToState, { setLocale })(IntlProvider) diff --git a/src/withTranslate.js b/src/withTranslate.js index 36b5930..d375d26 100644 --- a/src/withTranslate.js +++ b/src/withTranslate.js @@ -1,18 +1,17 @@ import React from 'react' -import PropTypes from 'prop-types' -import hoistNonReactStatics from 'hoist-non-react-statics' +import { TranslateConsumer } from './context' -const getComponentDisplayName = (WrappedComponent) => { - return WrappedComponent.displayName || WrappedComponent.name || 'Component' +/** + * Access translate function + * @param {Object} WrappedComponent + * @return {Object} + */ +function withTranslate (WrappedComponent) { + return (props) => ( + + {(translate) => } + + ) } -export default (WrappedComponent) => { - const WithTranslate = (props, context) => { - return - } - WithTranslate.displayName = `withTranslate(${getComponentDisplayName(WrappedComponent)})` - WithTranslate.contextTypes = { - translate: PropTypes.func - } - return hoistNonReactStatics(WithTranslate, WrappedComponent) -} +export default withTranslate \ No newline at end of file