diff --git a/package.json b/package.json
index d6695f2..f740fef 100644
--- a/package.json
+++ b/package.json
@@ -59,15 +59,6 @@
"morgan": "^1.7.0",
"node-sass": "^3.12.4",
"postcss-loader": "^1.1.1",
- "react": "^15.4.0",
- "react-addons-test-utils": "^15.4.1",
- "react-css-themr": "^1.6.0",
- "react-dom": "^15.4.0",
- "react-hot-loader": "^1.3.1",
- "react-redux": "^4.4.6",
- "react-router": "^3.0.0",
- "redux": "^3.6.0",
- "redux-thunk": "^2.1.0",
"rimraf": "^2.5.4",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
@@ -76,5 +67,17 @@
"webpack": "^1.13.3",
"webpack-dev-middleware": "^1.8.4",
"webpack-hot-middleware": "^2.13.2"
+ },
+ "dependencies": {
+ "react-intl": "^2.2.3",
+ "react": "^15.4.0",
+ "react-addons-test-utils": "^15.4.1",
+ "react-css-themr": "^1.6.0",
+ "react-dom": "^15.4.0",
+ "react-hot-loader": "^1.3.1",
+ "react-redux": "^4.4.6",
+ "react-router": "^3.0.0",
+ "redux": "^3.6.0",
+ "redux-thunk": "^2.1.0"
}
}
diff --git a/src/Form/Input/index.jsx b/src/Form/Input/index.jsx
new file mode 100644
index 0000000..9f25661
--- /dev/null
+++ b/src/Form/Input/index.jsx
@@ -0,0 +1,49 @@
+import React, {
+ Component,
+ PropTypes
+} from 'react';
+
+import {
+ intlShape,
+ injectIntl
+} from 'react-intl';
+
+
+
+class Input extends Component {
+ render() {
+ const { type, intl, value, required, id, onChange, placeholder } = this.props;
+ const props = {
+ type,
+ value,
+ required,
+ id,
+ onChange
+ };
+ if (placeholder) {
+ const { formatMessage } = intl;
+ props.placeholder = formatMessage(placeholder);
+ }
+ return (
+
+ );
+ }
+}
+
+Input.propTypes = {
+ type: PropTypes.string,
+ intl: intlShape.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ required: PropTypes.bool,
+ id: PropTypes.string,
+ onChange: PropTypes.func,
+ placeholder: PropTypes.object,
+};
+
+Input.defaultProps = {
+ inputType: 'text'
+};
+
+export default injectIntl(Input);
diff --git a/src/Login/index.js b/src/Login/index.js
deleted file mode 100644
index 2cde355..0000000
--- a/src/Login/index.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-import {themr} from 'react-css-themr';
-import {connect} from 'react-redux';
-
-import {setUsername, setPassword, toggleRemember, attemptLogin} from './actions';
-import style from './style.scss';
-import constants from '../constants';
-
-class Login extends Component {
- static propTypes = {
- theme: PropTypes.object.isRequired,
- username: PropTypes.string,
- password: PropTypes.string,
- remember: PropTypes.bool,
- onUsernameChange: PropTypes.func,
- onPasswordChange: PropTypes.func,
- onRememberToggle: PropTypes.func,
- onLogin: PropTypes.func
- }
-
- render() {
- const {theme, username, password, remember, onUsernameChange, onPasswordChange, onRememberToggle, onLogin} = this.props;
- return (
-
- );
- }
-}
-
-const ReduxLogin = connect((state) => {
- const {login} = state;
- return {
- username: login.username,
- password: login.password,
- remember: login.remember
- };
-}, (dispatch) => {
- return {
- onUsernameChange: (val) => { dispatch(setUsername(val)); },
- onPasswordChange: (val) => { dispatch(setPassword(val)); },
- onRememberToggle: (val) => { dispatch(toggleRemember(val)); },
- onLogin: (uid, password) => { dispatch(attemptLogin(uid, password)); }
- };
-})(Login);
-
-export {Login as LoginBase};
-export default themr('LOGIN', style)(ReduxLogin);
diff --git a/src/Login/index.jsx b/src/Login/index.jsx
new file mode 100644
index 0000000..6b002f7
--- /dev/null
+++ b/src/Login/index.jsx
@@ -0,0 +1,148 @@
+import React, { Component, PropTypes } from 'react';
+import { themr } from 'react-css-themr';
+import { connect } from 'react-redux';
+import {
+ addLocaleData,
+ IntlProvider,
+ FormattedMessage,
+ defineMessages
+} from 'react-intl';
+import enLocaleData from 'react-intl/locale-data/en';
+import zhLocaleData from 'react-intl/locale-data/zh';
+
+import { setUsername, setPassword, toggleRemember, attemptLogin } from './actions';
+import Input from '../Form/Input';
+import style from './style.scss';
+import constants from '../constants';
+import zhMessage from './l10n/zh_CN';
+import enMessage from './l10n/en_US';
+
+addLocaleData(enLocaleData);
+addLocaleData(zhLocaleData);
+
+const getLocaleMessage = (locale) => {
+ switch (locale) {
+ case 'en':
+ return enMessage;
+ case 'zh':
+ return zhMessage;
+ }
+}
+
+const placeholderMessages = defineMessages({
+ username: {
+ id: 'placeholder.username'
+ },
+ password: {
+ id: 'placeholder.password'
+ }
+})
+
+class Login extends Component {
+ static propTypes = {
+ theme: PropTypes.object.isRequired,
+ username: PropTypes.string,
+ password: PropTypes.string,
+ remember: PropTypes.bool,
+ onUsernameChange: PropTypes.func,
+ onPasswordChange: PropTypes.func,
+ onRememberToggle: PropTypes.func,
+ onLogin: PropTypes.func,
+ locale: PropTypes.string
+ }
+
+ static defaultProps = {
+ locale: 'en'
+ }
+
+ render() {
+ const {theme, username, password, remember, onUsernameChange, onPasswordChange, onRememberToggle, onLogin, locale} = this.props;
+ return (
+
+
+
+ );
+ }
+}
+
+const ReduxLogin = connect((state) => {
+ const {login} = state;
+ return {
+ username: login.username,
+ password: login.password,
+ remember: login.remember
+ };
+}, (dispatch) => {
+ return {
+ onUsernameChange: (val) => {dispatch(setUsername(val)); },
+ onPasswordChange: (val) => {dispatch(setPassword(val)); },
+ onRememberToggle: (val) => {dispatch(toggleRemember(val)); },
+ onLogin: (uid, password) => {dispatch(attemptLogin(uid, password)); }
+ };
+})(Login);
+
+export {Login as LoginBase};
+export default themr('LOGIN', style)(ReduxLogin);
diff --git a/src/Login/l10n/en_US.js b/src/Login/l10n/en_US.js
new file mode 100644
index 0000000..9911e5c
--- /dev/null
+++ b/src/Login/l10n/en_US.js
@@ -0,0 +1,11 @@
+export default {
+ LOGIN: 'Login',
+ USERNAME: 'Username',
+ PASSWORD: 'Password',
+ REMEMBER: 'Remember',
+ SUBMIT: 'Submit',
+ FULLNAME: 'Full name',
+ REGISTER: 'Register',
+ 'placeholder.username': 'Please input your username',
+ 'placeholder.password': 'Please input your password'
+};
diff --git a/src/Login/l10n/zh_CN.js b/src/Login/l10n/zh_CN.js
new file mode 100644
index 0000000..c7f2fe2
--- /dev/null
+++ b/src/Login/l10n/zh_CN.js
@@ -0,0 +1,11 @@
+export default {
+ LOGIN: '登录',
+ USERNAME: '用户名',
+ PASSWORD: '密码',
+ REMEMBER: '记住我',
+ SUBMIT: '确认',
+ FULLNAME: '全名',
+ REGISTER: '注册',
+ 'placeholder.username': '请输入用户名',
+ 'placeholder.password': '请输入密码'
+};
diff --git a/test/login.js b/test/login.js
index 6043e5e..ce15fe0 100644
--- a/test/login.js
+++ b/test/login.js
@@ -8,18 +8,18 @@ describe('', () => {
it('should include username input', () => {
const wrapper = shallow();
- // console.log(wrapper.debug());
- expect(wrapper.find('input[type="text"]')).to.have.length(1);
+ // console.log(wrapper.find('[type="text"]').debug());
+ expect(wrapper.find('[type="text"]')).to.have.length(1);
});
it('should include password input', () => {
const wrapper = shallow();
- expect(wrapper.find('input[type="password"]')).to.have.length(1);
+ expect(wrapper.find('[type="password"]')).to.have.length(1);
});
it('should include checkbox input', () => {
const wrapper = shallow();
- expect(wrapper.find('input[type="checkbox"]')).to.have.length(1);
+ expect(wrapper.find('[type="checkbox"]')).to.have.length(1);
});
it('should include submit button', () => {