-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #9 add localization to login component using react-intl package #22
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React, { | ||
Component, | ||
PropTypes | ||
} from 'react'; | ||
|
||
import { | ||
intlShape, | ||
injectIntl | ||
} from 'react-intl'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really a fan of this style except when you are importing a lot of items. We should decide if we like this and consider allowing/disallowing it in our linting rules. |
||
|
||
|
||
|
||
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 | ||
{...props} | ||
/> | ||
); | ||
} | ||
} | ||
|
||
Input.propTypes = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be static propTypes = {...} inside the class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you use the static PropType syntax here |
||
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 = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static defaultProps = {..} |
||
inputType: 'text' | ||
}; | ||
|
||
export default injectIntl(Input); |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import React, { Component, PropTypes } from 'react'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently not putting .jsx extensions on code. If we want to, we should be consistent about it. I do not have a strong opinion on whether we should or should not. |
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we bundling all of the locale data inside webpack? Won't this make our exports huge? |
||
|
||
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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All these are required properties? |
||
locale: PropTypes.string | ||
} | ||
|
||
static defaultProps = { | ||
locale: 'en' | ||
} | ||
|
||
render() { | ||
const {theme, username, password, remember, onUsernameChange, onPasswordChange, onRememberToggle, onLogin, locale} = this.props; | ||
return ( | ||
<IntlProvider locale={locale} messages={getLocaleMessage(locale)}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel wrapping every component with localization wrapper feels like an overkill. Instead, can we do this once is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, putting this in Redux is a good solution because we can dynamically load it from the server. |
||
<div className={theme.container}> | ||
<fieldset> | ||
<legend> | ||
<FormattedMessage | ||
id="LOGIN" | ||
/> | ||
</legend> | ||
<div className={theme.property}> | ||
<label | ||
className={theme.propertyLabel} | ||
htmlFor='uname' | ||
> | ||
<FormattedMessage | ||
id="USERNAME" | ||
/> | ||
</label> | ||
<Input | ||
type='text' | ||
id='uname' | ||
placeholder={placeholderMessages.username} | ||
required={true} | ||
value={username} | ||
onChange={(e) => { onUsernameChange(e.target.value); }} | ||
/> | ||
<Input | ||
type='checkbox' | ||
id='remember' | ||
required={true} | ||
value={remember} | ||
onChange={(e) => { onRememberToggle(e.target.checked); }} | ||
/> | ||
<label | ||
className={theme.propertyLabel} | ||
htmlFor='remember' | ||
> | ||
<FormattedMessage | ||
id="REMEMBER" | ||
/> | ||
</label> | ||
</div> | ||
<div className={theme.property}> | ||
<label className={theme.propertyLabel} htmlFor='pword'> | ||
<FormattedMessage | ||
id="PASSWORD" | ||
/> | ||
</label> | ||
<Input | ||
type='password' | ||
id='pword' | ||
placeholder={placeholderMessages.password} | ||
required={true} | ||
value={password} | ||
onChange={(e) => { onPasswordChange(e.target.value); }} | ||
/> | ||
</div> | ||
<div className={theme.login}> | ||
<button type='submit' onClick={() => { onLogin(username, password); }}> | ||
<FormattedMessage | ||
id="SUBMIT" | ||
/> | ||
</button> | ||
</div> | ||
</fieldset> | ||
</div> | ||
</IntlProvider> | ||
); | ||
} | ||
} | ||
|
||
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); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export default { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make these json files? |
||
LOGIN: 'Login', | ||
USERNAME: 'Username', | ||
PASSWORD: 'Password', | ||
REMEMBER: 'Remember', | ||
SUBMIT: 'Submit', | ||
FULLNAME: 'Full name', | ||
REGISTER: 'Register', | ||
'placeholder.username': 'Please input your username', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a fan of mixing ALLCAPS with dot.format. |
||
'placeholder.password': 'Please input your password' | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export default { | ||
LOGIN: '登录', | ||
USERNAME: '用户名', | ||
PASSWORD: '密码', | ||
REMEMBER: '记住我', | ||
SUBMIT: '确认', | ||
FULLNAME: '全名', | ||
REGISTER: '注册', | ||
'placeholder.username': '请输入用户名', | ||
'placeholder.password': '请输入密码' | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have all of these external dependencies all of a sudden? We shouldn't need any of these... Specifically, our only external dependency would be React, but we webpack everything up when we build, so our exports can be used anywhere regardless of environment.