diff options
Diffstat (limited to 'app/assets/javascripts')
28 files changed, 230 insertions, 222 deletions
diff --git a/app/assets/javascripts/components/components/column_back_button.jsx b/app/assets/javascripts/components/components/column_back_button.jsx index c3ed8f8d0..2f499c749 100644 --- a/app/assets/javascripts/components/components/column_back_button.jsx +++ b/app/assets/javascripts/components/components/column_back_button.jsx @@ -1,4 +1,5 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; +import { FormattedMessage } from 'react-intl'; const outerStyle = { padding: '15px', @@ -30,7 +31,7 @@ const ColumnBackButton = React.createClass({ return ( <div onClick={this.handleClick} style={outerStyle} className='column-back-button'> <i className='fa fa-fw fa-chevron-left' style={iconStyle} /> - Back + <FormattedMessage id='column_back_button.label' defaultMessage='Back' /> </div> ); } diff --git a/app/assets/javascripts/components/components/lightbox.jsx b/app/assets/javascripts/components/components/lightbox.jsx index aef0bac14..537bab954 100644 --- a/app/assets/javascripts/components/components/lightbox.jsx +++ b/app/assets/javascripts/components/components/lightbox.jsx @@ -1,6 +1,7 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import IconButton from './icon_button'; import { Motion, spring } from 'react-motion'; +import { injectIntl } from 'react-intl'; const overlayStyle = { position: 'fixed', @@ -40,14 +41,14 @@ const Lightbox = React.createClass({ mixins: [PureRenderMixin], render () { - const { isVisible, onOverlayClicked, onCloseClicked, children } = this.props; + const { intl, isVisible, onOverlayClicked, onCloseClicked, children } = this.props; return ( <div className='lightbox' style={{...overlayStyle, display: isVisible ? 'flex' : 'none'}} onClick={onOverlayClicked}> <Motion defaultStyle={{ y: -200 }} style={{ y: spring(isVisible ? 0 : -200) }}> {({ y }) => <div style={{...dialogStyle, transform: `translateY(${y}px)`}}> - <IconButton title='Close' icon='times' onClick={onCloseClicked} size={16} style={closeStyle} /> + <IconButton title={intl.formatMessage({ id: 'lightbox.close', defaultMessage: 'Close' })} icon='times' onClick={onCloseClicked} size={16} style={closeStyle} /> {children} </div> } @@ -58,4 +59,4 @@ const Lightbox = React.createClass({ }); -export default Lightbox; +export default injectIntl(Lightbox); diff --git a/app/assets/javascripts/components/components/loading_indicator.jsx b/app/assets/javascripts/components/components/loading_indicator.jsx index 7b738ac32..fd5acae84 100644 --- a/app/assets/javascripts/components/components/loading_indicator.jsx +++ b/app/assets/javascripts/components/components/loading_indicator.jsx @@ -1,3 +1,5 @@ +import { FormattedMessage } from 'react-intl'; + const LoadingIndicator = () => { const style = { textAlign: 'center', @@ -7,7 +9,7 @@ const LoadingIndicator = () => { paddingTop: '120px' }; - return <div style={style}>Loading...</div>; + return <div style={style}><FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' /></div>; }; export default LoadingIndicator; diff --git a/app/assets/javascripts/components/components/relative_timestamp.jsx b/app/assets/javascripts/components/components/relative_timestamp.jsx index 1de44bb95..96f99cca8 100644 --- a/app/assets/javascripts/components/components/relative_timestamp.jsx +++ b/app/assets/javascripts/components/components/relative_timestamp.jsx @@ -1,52 +1,24 @@ -import moment from 'moment'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; - -moment.updateLocale('en', { - relativeTime : { - future: "in %s", - past: "%s", - s: "%ds", - m: "1m", - mm: "%dm", - h: "1h", - hh: "%dh", - d: "1d", - dd: "%dd", - M: "1mo", - MM: "%dmo", - y: "1y", - yy: "%dy" - } -}); - -const RelativeTimestamp = React.createClass({ - - propTypes: { - timestamp: React.PropTypes.string.isRequired, - now: React.PropTypes.any - }, - - mixins: [PureRenderMixin], - - render () { - const timestamp = moment(this.props.timestamp); - const now = this.props.now; - - let string = ''; - - if (timestamp.isAfter(now)) { - string = 'Just now'; - } else { - string = timestamp.from(now); - } - - return ( - <span> - {string} - </span> - ); +import { + FormattedMessage, + FormattedDate, + FormattedRelative +} from 'react-intl'; + +const RelativeTimestamp = ({ timestamp, now }) => { + const diff = (new Date(now)) - (new Date(timestamp)); + + if (diff < 0) { + return <FormattedMessage id='relative_time.just_now' defaultMessage='Just now' /> + } else if (diff > (3600 * 24 * 7 * 1000)) { + return <FormattedDate value={timestamp} /> + } else { + return <FormattedRelative value={timestamp} initialNow={now} updateInterval={0} /> } +}; -}); +RelativeTimestamp.propTypes = { + timestamp: React.PropTypes.string.isRequired, + now: React.PropTypes.any +}; export default RelativeTimestamp; diff --git a/app/assets/javascripts/components/components/status.jsx b/app/assets/javascripts/components/components/status.jsx index ff14ba4f1..8077308c4 100644 --- a/app/assets/javascripts/components/components/status.jsx +++ b/app/assets/javascripts/components/components/status.jsx @@ -1,12 +1,13 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; -import Avatar from './avatar'; -import RelativeTimestamp from './relative_timestamp'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import DisplayName from './display_name'; -import MediaGallery from './media_gallery'; -import VideoPlayer from './video_player'; -import StatusContent from './status_content'; -import StatusActionBar from './status_action_bar'; +import Avatar from './avatar'; +import RelativeTimestamp from './relative_timestamp'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import DisplayName from './display_name'; +import MediaGallery from './media_gallery'; +import VideoPlayer from './video_player'; +import StatusContent from './status_content'; +import StatusActionBar from './status_action_bar'; +import { FormattedMessage } from 'react-intl'; const Status = React.createClass({ @@ -59,7 +60,7 @@ const Status = React.createClass({ <div style={{ cursor: 'default' }}> <div style={{ marginLeft: '68px', color: '#616b86', padding: '8px 0', paddingBottom: '2px', fontSize: '14px', position: 'relative' }}> <div style={{ position: 'absolute', 'left': '-26px'}}><i className='fa fa-fw fa-retweet'></i></div> - <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{displayName}</strong></a> reblogged + <FormattedMessage id='status.reblogged_by' defaultMessage='{name} reblogged' values={{ name: <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{displayName}</strong></a> }} /> </div> <Status {...other} wrapped={true} status={status.get('reblog')} /> diff --git a/app/assets/javascripts/components/components/status_action_bar.jsx b/app/assets/javascripts/components/components/status_action_bar.jsx index e80ce824f..8883d0806 100644 --- a/app/assets/javascripts/components/components/status_action_bar.jsx +++ b/app/assets/javascripts/components/components/status_action_bar.jsx @@ -1,7 +1,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import IconButton from './icon_button'; -import DropdownMenu from './dropdown_menu'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import IconButton from './icon_button'; +import DropdownMenu from './dropdown_menu'; +import { injectIntl } from 'react-intl'; const StatusActionBar = React.createClass({ propTypes: { @@ -36,20 +37,20 @@ const StatusActionBar = React.createClass({ }, render () { - const { status, me } = this.props; + const { status, me, intl } = this.props; let menu = []; if (status.getIn(['account', 'id']) === me) { - menu.push({ text: 'Delete', action: this.handleDeleteClick }); + menu.push({ text: intl.formatMessage({ id: 'status.delete', defaultMessage: 'Delete' }), action: this.handleDeleteClick }); } else { - menu.push({ text: 'Mention', action: this.handleMentionClick }); + menu.push({ text: intl.formatMessage({ id: 'status.mention', defaultMessage: 'Mention' }), action: this.handleMentionClick }); } return ( <div style={{ marginTop: '10px', overflow: 'hidden' }}> - <div style={{ float: 'left', marginRight: '18px'}}><IconButton title='Reply' icon='reply' onClick={this.handleReplyClick} /></div> - <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={this.handleReblogClick} /></div> - <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> + <div style={{ float: 'left', marginRight: '18px'}}><IconButton title={intl.formatMessage({ id: 'status.reply', defaultMessage: 'Reply' })} icon='reply' onClick={this.handleReplyClick} /></div> + <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('reblogged')} title={intl.formatMessage({ id: 'status.reblog', defaultMessage: 'Reblog' })} icon='retweet' onClick={this.handleReblogClick} /></div> + <div style={{ float: 'left', marginRight: '18px'}}><IconButton active={status.get('favourited')} title={intl.formatMessage({ id: 'status.favourite', defaultMessage: 'Favourite' })} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> <div style={{ width: '18px', height: '18px', float: 'left' }}> <DropdownMenu items={menu} icon='ellipsis-h' size={18} /> @@ -60,4 +61,4 @@ const StatusActionBar = React.createClass({ }); -export default StatusActionBar; +export default injectIntl(StatusActionBar); diff --git a/app/assets/javascripts/components/components/status_list.jsx b/app/assets/javascripts/components/components/status_list.jsx index 58aa94cc0..d5d69c989 100644 --- a/app/assets/javascripts/components/components/status_list.jsx +++ b/app/assets/javascripts/components/components/status_list.jsx @@ -3,7 +3,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import { ScrollContainer } from 'react-router-scroll'; import StatusContainer from '../containers/status_container'; -import moment from 'moment'; const StatusList = React.createClass({ @@ -21,14 +20,14 @@ const StatusList = React.createClass({ getInitialState () { return { - now: moment() + now: new Date() }; }, mixins: [PureRenderMixin], componentDidMount () { - this._interval = setInterval(() => this.setState({ now: moment() }), 60000); + this._interval = setInterval(() => this.setState({ now: new Date() }), 60000); }, componentWillUnmount () { diff --git a/app/assets/javascripts/components/components/video_player.jsx b/app/assets/javascripts/components/components/video_player.jsx index 209db33a7..2c236b996 100644 --- a/app/assets/javascripts/components/components/video_player.jsx +++ b/app/assets/javascripts/components/components/video_player.jsx @@ -1,6 +1,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import IconButton from './icon_button'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import IconButton from './icon_button'; +import { injectIntl } from 'react-intl'; const videoStyle = { position: 'relative', @@ -59,14 +60,16 @@ const VideoPlayer = React.createClass({ }, render () { + const { media, intl, width, height } = this.props; + return ( - <div style={{ cursor: 'default', marginTop: '8px', overflow: 'hidden', width: `${this.props.width}px`, height: `${this.props.height}px`, boxSizing: 'border-box', background: '#000', position: 'relative' }}> - <div style={muteStyle}><IconButton title='Toggle sound' icon={this.state.muted ? 'volume-up' : 'volume-off'} onClick={this.handleClick} /></div> - <video src={this.props.media.get('url')} autoPlay='true' loop={true} muted={this.state.muted} style={videoStyle} onClick={this.handleVideoClick} /> + <div style={{ cursor: 'default', marginTop: '8px', overflow: 'hidden', width: `${width}px`, height: `${height}px`, boxSizing: 'border-box', background: '#000', position: 'relative' }}> + <div style={muteStyle}><IconButton title={intl.formatMessage({ id: 'video_player.toggle_sound', defaultMessage: 'Toggle sound' })} icon={this.state.muted ? 'volume-up' : 'volume-off'} onClick={this.handleClick} /></div> + <video src={media.get('url')} autoPlay='true' loop={true} muted={this.state.muted} style={videoStyle} onClick={this.handleVideoClick} /> </div> ); } }); -export default VideoPlayer; +export default injectIntl(VideoPlayer); diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index 20b57998a..dbc32076b 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -32,6 +32,7 @@ import Following from '../features/following'; import Reblogs from '../features/reblogs'; import Favourites from '../features/favourites'; import HashtagTimeline from '../features/hashtag_timeline'; +import { IntlProvider } from 'react-intl'; const store = configureStore(); @@ -44,7 +45,8 @@ const Mastodon = React.createClass({ propTypes: { token: React.PropTypes.string.isRequired, timelines: React.PropTypes.object, - account: React.PropTypes.string + account: React.PropTypes.string, + locale: React.PropTypes.string.isRequired }, mixins: [PureRenderMixin], @@ -81,30 +83,34 @@ const Mastodon = React.createClass({ }, render () { + const { locale } = this.props; + return ( - <Provider store={store}> - <Router history={browserHistory} render={applyRouterMiddleware(useScroll())}> - <Route path='/' component={UI}> - <IndexRoute component={GettingStarted} /> - - <Route path='timelines/home' component={HomeTimeline} /> - <Route path='timelines/mentions' component={MentionsTimeline} /> - <Route path='timelines/public' component={PublicTimeline} /> - <Route path='timelines/tag/:id' component={HashtagTimeline} /> - - <Route path='statuses/new' component={Compose} /> - <Route path='statuses/:statusId' component={Status} /> - <Route path='statuses/:statusId/reblogs' component={Reblogs} /> - <Route path='statuses/:statusId/favourites' component={Favourites} /> - - <Route path='accounts/:accountId' component={Account}> - <IndexRoute component={AccountTimeline} /> - <Route path='followers' component={Followers} /> - <Route path='following' component={Following} /> + <IntlProvider locale={locale}> + <Provider store={store}> + <Router history={browserHistory} render={applyRouterMiddleware(useScroll())}> + <Route path='/' component={UI}> + <IndexRoute component={GettingStarted} /> + + <Route path='timelines/home' component={HomeTimeline} /> + <Route path='timelines/mentions' component={MentionsTimeline} /> + <Route path='timelines/public' component={PublicTimeline} /> + <Route path='timelines/tag/:id' component={HashtagTimeline} /> + + <Route path='statuses/new' component={Compose} /> + <Route path='statuses/:statusId' component={Status} /> + <Route path='statuses/:statusId/reblogs' component={Reblogs} /> + <Route path='statuses/:statusId/favourites' component={Favourites} /> + + <Route path='accounts/:accountId' component={Account}> + <IndexRoute component={AccountTimeline} /> + <Route path='followers' component={Followers} /> + <Route path='following' component={Following} /> + </Route> </Route> - </Route> - </Router> - </Provider> + </Router> + </Provider> + </IntlProvider> ); } diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx index e0532dca1..f8d051439 100644 --- a/app/assets/javascripts/components/features/account/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/account/components/action_bar.jsx @@ -1,7 +1,8 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import DropdownMenu from '../../../components/dropdown_menu'; -import { Link } from 'react-router'; +import DropdownMenu from '../../../components/dropdown_menu'; +import { Link } from 'react-router'; +import { injectIntl, FormattedMessage, FormattedNumber } from 'react-intl'; const outerStyle = { borderTop: '1px solid #363c4b', @@ -36,22 +37,22 @@ const ActionBar = React.createClass({ mixins: [PureRenderMixin], render () { - const { account, me } = this.props; + const { account, me, intl } = this.props; let menu = []; - menu.push({ text: 'Mention', action: this.props.onMention }); + menu.push({ text: intl.formatMessage({ id: 'account.mention', defaultMessage: 'Mention' }), action: this.props.onMention }); if (account.get('id') === me) { - menu.push({ text: 'Edit profile', href: '/settings/profile' }); + menu.push({ text: intl.formatMessage({ id: 'account.edit_profile', defaultMessage: 'Edit profile' }), href: '/settings/profile' }); } else if (account.getIn(['relationship', 'blocking'])) { - menu.push({ text: 'Unblock', action: this.props.onBlock }); + menu.push({ text: intl.formatMessage({ id: 'account.unblock', defaultMessage: 'Unblock' }), action: this.props.onBlock }); } else if (account.getIn(['relationship', 'following'])) { - menu.push({ text: 'Unfollow', action: this.props.onFollow }); - menu.push({ text: 'Block', action: this.props.onBlock }); + menu.push({ text: intl.formatMessage({ id: 'account.unfollow', defaultMessage: 'Unfollow' }), action: this.props.onFollow }); + menu.push({ text: intl.formatMessage({ id: 'account.block', defaultMessage: 'Block' }), action: this.props.onBlock }); } else { - menu.push({ text: 'Follow', action: this.props.onFollow }); - menu.push({ text: 'Block', action: this.props.onBlock }); + menu.push({ text: intl.formatMessage({ id: 'account.follow', defaultMessage: 'Follow' }), action: this.props.onFollow }); + menu.push({ text: intl.formatMessage({ id: 'account.block', defaultMessage: 'Block' }), action: this.props.onBlock }); } return ( @@ -62,24 +63,24 @@ const ActionBar = React.createClass({ <div style={outerLinksStyle}> <Link to={`/accounts/${account.get('id')}`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', borderLeft: '1px solid #363c4b', padding: '10px', paddingRight: '5px' }}> - <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Posts</span> - <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('statuses_count')}</span> + <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.posts' defaultMessage='Posts' /></span> + <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('statuses_count')} /></span> </Link> <Link to={`/accounts/${account.get('id')}/following`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', borderLeft: '1px solid #363c4b', padding: '10px 5px' }}> - <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Follows</span> - <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('following_count')}</span> + <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.follows' defaultMessage='Follows' /></span> + <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('following_count')} /></span> </Link> <Link to={`/accounts/${account.get('id')}/followers`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', padding: '10px 5px', borderLeft: '1px solid #363c4b' }}> - <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}>Followers</span> - <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('followers_count')}</span> + <span style={{ display: 'block', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.followers' defaultMessage='Followers' /></span> + <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('followers_count')} /></span> </Link> </div> </div> ); - }, + } }); -export default ActionBar; +export default injectIntl(ActionBar); diff --git a/app/assets/javascripts/components/features/account_timeline/index.jsx b/app/assets/javascripts/components/features/account_timeline/index.jsx index cae88efdb..7a3dbe160 100644 --- a/app/assets/javascripts/components/features/account_timeline/index.jsx +++ b/app/assets/javascripts/components/features/account_timeline/index.jsx @@ -1,12 +1,12 @@ -import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import ImmutablePropTypes from 'react-immutable-proptypes'; +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; import { fetchAccountTimeline, expandAccountTimeline -} from '../../actions/accounts'; -import StatusList from '../../components/status_list'; -import LoadingIndicator from '../../components/loading_indicator'; +} from '../../actions/accounts'; +import StatusList from '../../components/status_list'; +import LoadingIndicator from '../../components/loading_indicator'; const mapStateToProps = (state, props) => ({ statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId)]), diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx index ead8e0008..5aa041f09 100644 --- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx +++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx @@ -8,6 +8,7 @@ import Autosuggest from 'react-autosuggest'; import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container'; import { debounce } from 'react-decoration'; import UploadButtonContainer from '../containers/upload_button_container'; +import { injectIntl } from 'react-intl'; const getTokenForSuggestions = (str, caretPosition) => { let word; @@ -134,6 +135,7 @@ const ComposeForm = React.createClass({ }, render () { + const { intl } = this.props; let replyArea = ''; const disabled = this.props.is_submitting || this.props.is_uploading; @@ -142,7 +144,7 @@ const ComposeForm = React.createClass({ } const inputProps = { - placeholder: 'What is on your mind?', + placeholder: intl.formatMessage({ id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' }), value: this.props.text, onKeyUp: this.handleKeyUp, onChange: this.handleChange, @@ -167,7 +169,7 @@ const ComposeForm = React.createClass({ /> <div style={{ marginTop: '10px', overflow: 'hidden' }}> - <div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={disabled} /></div> + <div style={{ float: 'right' }}><Button text={intl.formatMessage({ id: 'compose_form.publish', defaultMessage: 'Publish' })} onClick={this.handleSubmit} disabled={disabled} /></div> <div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div> <UploadButtonContainer style={{ paddingTop: '4px' }} /> </div> @@ -177,4 +179,4 @@ const ComposeForm = React.createClass({ }); -export default ComposeForm; +export default injectIntl(ComposeForm); diff --git a/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx b/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx index d2dae141f..4ba6d2290 100644 --- a/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx +++ b/app/assets/javascripts/components/features/compose/components/navigation_bar.jsx @@ -1,9 +1,10 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; import Avatar from '../../../components/avatar'; -import IconButton from '../../../components/icon_button'; -import DisplayName from '../../../components/display_name'; -import { Link } from 'react-router'; +import IconButton from '../../../components/icon_button'; +import DisplayName from '../../../components/display_name'; +import { Link } from 'react-router'; +import { FormattedMessage } from 'react-intl'; const NavigationBar = React.createClass({ propTypes: { @@ -19,7 +20,7 @@ const NavigationBar = React.createClass({ <div style={{ flex: '1 1 auto', marginLeft: '8px', color: '#9baec8' }}> <strong style={{ fontWeight: '500', display: 'block', color: '#fff' }}>{this.props.account.get('acct')}</strong> - <a href='/settings/profile' style={{ color: 'inherit', textDecoration: 'none' }}>Settings</a> · <Link to='/timelines/public' style={{ color: 'inherit', textDecoration: 'none' }}>Public timeline</Link> · <a href='/auth/sign_out' data-method='delete' style={{ color: 'inherit', textDecoration: 'none' }}>Logout</a> + <a href='/settings/profile' style={{ color: 'inherit', textDecoration: 'none' }}><FormattedMessage id='navigation_bar.settings' defaultMessage='Settings' /></a> · <Link to='/timelines/public' style={{ color: 'inherit', textDecoration: 'none' }}><FormattedMessage id='navigation_bar.public_timeline' defaultMessage='Public timeline' /></Link> · <a href='/auth/sign_out' data-method='delete' style={{ color: 'inherit', textDecoration: 'none' }}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a> </div> </div> ); diff --git a/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx b/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx index 6298d3de9..4b34f09bf 100644 --- a/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx +++ b/app/assets/javascripts/components/features/compose/components/reply_indicator.jsx @@ -3,11 +3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import Avatar from '../../../components/avatar'; import IconButton from '../../../components/icon_button'; import DisplayName from '../../../components/display_name'; -import emojione from 'emojione'; - -emojione.imageType = 'png'; -emojione.sprites = false; -emojione.imagePathPNG = '/emoji/'; +import emojify from '../../../emoji'; +import { injectIntl } from 'react-intl'; const ReplyIndicator = React.createClass({ @@ -34,12 +31,13 @@ const ReplyIndicator = React.createClass({ }, render () { - let content = { __html: emojione.unicodeToImage(this.props.status.get('content')) }; + const { intl } = this.props; + const content = { __html: emojify(this.props.status.get('content')) }; return ( <div style={{ background: '#9baec8', padding: '10px' }}> <div style={{ overflow: 'hidden', marginBottom: '5px' }}> - <div style={{ float: 'right', lineHeight: '24px' }}><IconButton title='Cancel' icon='times' onClick={this.handleClick} /></div> + <div style={{ float: 'right', lineHeight: '24px' }}><IconButton title={intl.formatMessage({ id: 'reply_indicator.cancel', defaultMessage: 'Cancel' })} icon='times' onClick={this.handleClick} /></div> <a href={this.props.status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px', color: '#282c37', textDecoration: 'none', overflow: 'hidden', lineHeight: '24px' }}> <div style={{ float: 'left', marginRight: '5px' }}><Avatar size={24} src={this.props.status.getIn(['account', 'avatar'])} /></div> @@ -54,4 +52,4 @@ const ReplyIndicator = React.createClass({ }); -export default ReplyIndicator; +export default injectIntl(ReplyIndicator); diff --git a/app/assets/javascripts/components/features/compose/components/search.jsx b/app/assets/javascripts/components/features/compose/components/search.jsx index 37efbe5df..65df336cc 100644 --- a/app/assets/javascripts/components/features/compose/components/search.jsx +++ b/app/assets/javascripts/components/features/compose/components/search.jsx @@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import Autosuggest from 'react-autosuggest'; import AutosuggestAccountContainer from '../containers/autosuggest_account_container'; import { debounce } from 'react-decoration'; +import { injectIntl } from 'react-intl'; const getSuggestionValue = suggestion => suggestion.value; @@ -94,7 +95,7 @@ const Search = React.createClass({ render () { const inputProps = { - placeholder: 'Search', + placeholder: this.props.intl.formatMessage({ id: 'search.placeholder', defaultMessage: 'Search' }), value: this.props.value, onChange: this.onChange, style: inputStyle @@ -125,4 +126,4 @@ const Search = React.createClass({ }); -export default Search; +export default injectIntl(Search); diff --git a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx b/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx index 70c2fca6e..697902275 100644 --- a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx +++ b/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx @@ -1,6 +1,7 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import AccountContainer from '../../followers/containers/account_container'; +import AccountContainer from '../../followers/containers/account_container'; +import { FormattedMessage } from 'react-intl'; const outerStyle = { position: 'relative' @@ -66,13 +67,13 @@ const SuggestionsBox = React.createClass({ let nextLink = ''; if (accountIds.size > perWindow) { - nextLink = <a href='#' style={nextStyle} onClick={this.handleNextClick}>Refresh</a>; + nextLink = <a href='#' style={nextStyle} onClick={this.handleNextClick}><FormattedMessage id='suggestions_box.refresh' defaultMessage='Refresh' /></a>; } return ( <div style={outerStyle}> <strong style={headerStyle}> - Who to follow {nextLink} + <FormattedMessage id='suggestions_box.who_to_follow' defaultMessage='Who to follow' /> {nextLink} </strong> {accountIds.skip(perWindow * this.state.index).take(perWindow).map(accountId => <AccountContainer key={accountId} id={accountId} withNote={false} />)} diff --git a/app/assets/javascripts/components/features/compose/components/upload_button.jsx b/app/assets/javascripts/components/features/compose/components/upload_button.jsx index 8289e0a09..cc251835f 100644 --- a/app/assets/javascripts/components/features/compose/components/upload_button.jsx +++ b/app/assets/javascripts/components/features/compose/components/upload_button.jsx @@ -1,5 +1,6 @@ import PureRenderMixin from 'react-addons-pure-render-mixin'; import IconButton from '../../../components/icon_button'; +import { injectIntl } from 'react-intl'; const UploadButton = React.createClass({ @@ -26,9 +27,11 @@ const UploadButton = React.createClass({ }, render () { + const { intl } = this.props; + return ( <div style={this.props.style}> - <IconButton icon='photo' title='Add media' disabled={this.props.disabled} onClick={this.handleClick} size={24} /> + <IconButton icon='photo' title={intl.formatMessage({ id: 'upload_button.label', defaultMessage: 'Add media' })} disabled={this.props.disabled} onClick={this.handleClick} size={24} /> <input ref={this.setRef} type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} /> </div> ); @@ -36,4 +39,4 @@ const UploadButton = React.createClass({ }); -export default UploadButton; +export default injectIntl(UploadButton); diff --git a/app/assets/javascripts/components/features/compose/components/upload_form.jsx b/app/assets/javascripts/components/features/compose/components/upload_form.jsx index eab504b48..72c2b9535 100644 --- a/app/assets/javascripts/components/features/compose/components/upload_form.jsx +++ b/app/assets/javascripts/components/features/compose/components/upload_form.jsx @@ -1,6 +1,7 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import IconButton from '../../../components/icon_button'; +import IconButton from '../../../components/icon_button'; +import { injectIntl } from 'react-intl'; const UploadForm = React.createClass({ @@ -13,10 +14,12 @@ const UploadForm = React.createClass({ mixins: [PureRenderMixin], render () { + const { intl } = this.props; + const uploads = this.props.media.map(attachment => ( <div key={attachment.get('id')} style={{ borderRadius: '4px', marginBottom: '10px' }} className='transparent-background'> <div style={{ width: '100%', height: '100px', borderRadius: '4px', background: `url(${attachment.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }}> - <IconButton icon='times' title='Undo' size={36} onClick={this.props.onRemoveFile.bind(this, attachment.get('id'))} /> + <IconButton icon='times' title={intl.formatMessage({ id: 'upload_form.undo', defaultMessage: 'Undo' })} size={36} onClick={this.props.onRemoveFile.bind(this, attachment.get('id'))} /> </div> </div> )); @@ -30,4 +33,4 @@ const UploadForm = React.createClass({ }); -export default UploadForm; +export default injectIntl(UploadForm); diff --git a/app/assets/javascripts/components/features/favourites/index.jsx b/app/assets/javascripts/components/features/favourites/index.jsx index 8f15bcad9..5c9ea498b 100644 --- a/app/assets/javascripts/components/features/favourites/index.jsx +++ b/app/assets/javascripts/components/features/favourites/index.jsx @@ -1,12 +1,12 @@ -import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchFavourites } from '../../actions/interactions'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../followers/containers/account_container'; -import Column from '../ui/components/column'; -import ColumnBackButton from '../../components/column_back_button'; +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import LoadingIndicator from '../../components/loading_indicator'; +import { fetchFavourites } from '../../actions/interactions'; +import { ScrollContainer } from 'react-router-scroll'; +import AccountContainer from '../followers/containers/account_container'; +import Column from '../ui/components/column'; +import ColumnBackButton from '../../components/column_back_button'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'favourited_by', Number(props.params.statusId)]) diff --git a/app/assets/javascripts/components/features/followers/components/account.jsx b/app/assets/javascripts/components/features/followers/components/account.jsx index adcd90360..123a40cab 100644 --- a/app/assets/javascripts/components/features/followers/components/account.jsx +++ b/app/assets/javascripts/components/features/followers/components/account.jsx @@ -1,9 +1,10 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; -import { Link } from 'react-router'; -import IconButton from '../../../components/icon_button'; +import Avatar from '../../../components/avatar'; +import DisplayName from '../../../components/display_name'; +import { Link } from 'react-router'; +import IconButton from '../../../components/icon_button'; +import { injectIntl } from 'react-intl'; const outerStyle = { padding: '10px', @@ -51,7 +52,7 @@ const Account = React.createClass({ }, render () { - const { account, me, withNote } = this.props; + const { account, me, withNote, intl } = this.props; if (!account) { return <div />; @@ -68,7 +69,7 @@ const Account = React.createClass({ buttons = ( <div style={buttonsStyle}> - <IconButton icon={following ? 'user-times' : 'user-plus'} title='Follow' onClick={this.handleFollow} active={following} /> + <IconButton icon={following ? 'user-times' : 'user-plus'} title={intl.formatMessage({ id: 'account.follow', defaultMessage: 'Follow' })} onClick={this.handleFollow} active={following} /> </div> ); } @@ -91,4 +92,4 @@ const Account = React.createClass({ }); -export default Account; +export default injectIntl(Account); diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx index d5792dd9e..5a9c4db89 100644 --- a/app/assets/javascripts/components/features/getting_started/index.jsx +++ b/app/assets/javascripts/components/features/getting_started/index.jsx @@ -1,15 +1,15 @@ -import Column from '../ui/components/column'; +import Column from '../ui/components/column'; import { Link } from 'react-router'; +import { FormattedMessage } from 'react-intl'; const GettingStarted = () => { return ( <Column> <div className='static-content'> - <h1>Getting started</h1> - <p>You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the form in the bottom of the sidebar.</p> - <p>If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.</p> - <p>The developer of this project can be followed as Gargron@mastodon.social</p> - <p>Also <Link to='/timelines/public' style={{ color: '#2b90d9', textDecoration: 'none' }}>check out the public timeline for a start</Link>!</p> + <h1><FormattedMessage id='getting_started.heading' defaultMessage='Getting started' /></h1> + <p><FormattedMessage id='getting_started.about_addressing' defaultMessage='You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the form at the top of the sidebar.' /></p> + <p><FormattedMessage id='getting_started.about_shortcuts' defaultMessage='If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.' /></p> + <p><FormattedMessage id='getting_started.about_developer' defaultMessage='The developer of this project can be followed as Gargron@mastodon.social' /></p> </div> </Column> ); diff --git a/app/assets/javascripts/components/features/home_timeline/index.jsx b/app/assets/javascripts/components/features/home_timeline/index.jsx index e4cd8bdca..117a4a72d 100644 --- a/app/assets/javascripts/components/features/home_timeline/index.jsx +++ b/app/assets/javascripts/components/features/home_timeline/index.jsx @@ -1,8 +1,9 @@ -import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../ui/components/column'; import { refreshTimeline } from '../../actions/timelines'; +import { injectIntl } from 'react-intl'; const HomeTimeline = React.createClass({ @@ -17,8 +18,10 @@ const HomeTimeline = React.createClass({ }, render () { + const { intl } = this.props; + return ( - <Column icon='home' heading='Home'> + <Column icon='home' heading={intl.formatMessage({ id: 'column.home', defaultMessage: 'Home' })}> <StatusListContainer {...this.props} type='home' /> </Column> ); @@ -26,4 +29,4 @@ const HomeTimeline = React.createClass({ }); -export default connect()(HomeTimeline); +export default connect()(injectIntl(HomeTimeline)); diff --git a/app/assets/javascripts/components/features/mentions_timeline/index.jsx b/app/assets/javascripts/components/features/mentions_timeline/index.jsx index 919a75d18..9f1caa235 100644 --- a/app/assets/javascripts/components/features/mentions_timeline/index.jsx +++ b/app/assets/javascripts/components/features/mentions_timeline/index.jsx @@ -1,8 +1,9 @@ import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import StatusListContainer from '../ui/containers/status_list_container'; -import Column from '../ui/components/column'; +import Column from '../ui/components/column'; import { refreshTimeline } from '../../actions/timelines'; +import { injectIntl } from 'react-intl'; const MentionsTimeline = React.createClass({ @@ -17,8 +18,10 @@ const MentionsTimeline = React.createClass({ }, render () { + const { intl } = this.props; + return ( - <Column icon='at' heading='Mentions'> + <Column icon='at' heading={intl.formatMessage({ id: 'column.mentions', defaultMessage: 'Mentions' })}> <StatusListContainer {...this.props} type='mentions' /> </Column> ); @@ -26,4 +29,4 @@ const MentionsTimeline = React.createClass({ }); -export default connect()(MentionsTimeline); +export default connect()(injectIntl(MentionsTimeline)); diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx index 12f73ba9b..445a4fc63 100644 --- a/app/assets/javascripts/components/features/public_timeline/index.jsx +++ b/app/assets/javascripts/components/features/public_timeline/index.jsx @@ -7,6 +7,7 @@ import { updateTimeline, deleteFromTimelines } from '../../actions/timelines'; +import { injectIntl } from 'react-intl'; const PublicTimeline = React.createClass({ @@ -44,8 +45,10 @@ const PublicTimeline = React.createClass({ }, render () { + const { intl } = this.props; + return ( - <Column icon='globe' heading='Public'> + <Column icon='globe' heading={intl.formatMessage({ id: 'column.public', defaultMessage: 'Public' })}> <StatusListContainer type='public' /> </Column> ); @@ -53,4 +56,4 @@ const PublicTimeline = React.createClass({ }); -export default connect()(PublicTimeline); +export default connect()(injectIntl(PublicTimeline)); diff --git a/app/assets/javascripts/components/features/reblogs/index.jsx b/app/assets/javascripts/components/features/reblogs/index.jsx index 2b62d3a27..5f22065f6 100644 --- a/app/assets/javascripts/components/features/reblogs/index.jsx +++ b/app/assets/javascripts/components/features/reblogs/index.jsx @@ -1,12 +1,12 @@ -import { connect } from 'react-redux'; -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import LoadingIndicator from '../../components/loading_indicator'; -import { fetchReblogs } from '../../actions/interactions'; -import { ScrollContainer } from 'react-router-scroll'; -import AccountContainer from '../followers/containers/account_container'; -import Column from '../ui/components/column'; -import ColumnBackButton from '../../components/column_back_button'; +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import LoadingIndicator from '../../components/loading_indicator'; +import { fetchReblogs } from '../../actions/interactions'; +import { ScrollContainer } from 'react-router-scroll'; +import AccountContainer from '../followers/containers/account_container'; +import Column from '../ui/components/column'; +import ColumnBackButton from '../../components/column_back_button'; const mapStateToProps = (state, props) => ({ accountIds: state.getIn(['user_lists', 'reblogged_by', Number(props.params.statusId)]) diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx index b1202ad8e..d855176f2 100644 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/status/components/action_bar.jsx @@ -1,7 +1,8 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; -import IconButton from '../../../components/icon_button'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import IconButton from '../../../components/icon_button'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import DropdownMenu from '../../../components/dropdown_menu'; +import DropdownMenu from '../../../components/dropdown_menu'; +import { injectIntl } from 'react-intl'; const ActionBar = React.createClass({ @@ -38,21 +39,21 @@ const ActionBar = React.createClass({ }, render () { - const { status, me } = this.props; + const { status, me, intl } = this.props; let menu = []; if (me === status.getIn(['account', 'id'])) { - menu.push({ text: 'Delete', action: this.handleDeleteClick }); + menu.push({ text: intl.formatMessage({ id: 'status.delete', defaultMessage: 'Delete' }), action: this.handleDeleteClick }); } else { - menu.push({ text: 'Mention', action: this.handleMentionClick }); + menu.push({ text: intl.formatMessage({ id: 'status.mention', defaultMessage: 'Mention' }), action: this.handleMentionClick }); } return ( <div style={{ background: '#2f3441', display: 'flex', flexDirection: 'row', borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px 0' }}> - <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title='Reply' icon='reply' onClick={this.handleReplyClick} /></div> - <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={this.handleReblogClick} /></div> - <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> + <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title={intl.formatMessage({ id: 'status.reply', defaultMessage: 'Reply' })} icon='reply' onClick={this.handleReplyClick} /></div> + <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('reblogged')} title={intl.formatMessage({ id: 'status.reblog', defaultMessage: 'Reblog' })} icon='retweet' onClick={this.handleReblogClick} /></div> + <div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title={intl.formatMessage({ id: 'status.favourite', defaultMessage: 'Favourite' })} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> <div style={{ flex: '1 1 auto', textAlign: 'center' }}><DropdownMenu size={18} icon='ellipsis-h' items={menu} /></div> </div> ); @@ -60,4 +61,4 @@ const ActionBar = React.createClass({ }); -export default ActionBar; +export default injectIntl(ActionBar); diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx index 71335970f..8efdf195f 100644 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx @@ -1,12 +1,12 @@ -import PureRenderMixin from 'react-addons-pure-render-mixin'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; -import StatusContent from '../../../components/status_content'; -import MediaGallery from '../../../components/media_gallery'; -import VideoPlayer from '../../../components/video_player'; -import moment from 'moment'; -import { Link } from 'react-router'; +import Avatar from '../../../components/avatar'; +import DisplayName from '../../../components/display_name'; +import StatusContent from '../../../components/status_content'; +import MediaGallery from '../../../components/media_gallery'; +import VideoPlayer from '../../../components/video_player'; +import { Link } from 'react-router'; +import { FormattedDate, FormattedNumber } from 'react-intl'; const DetailedStatus = React.createClass({ @@ -54,7 +54,7 @@ const DetailedStatus = React.createClass({ {media} <div style={{ marginTop: '15px', color: '#616b86', fontSize: '14px', lineHeight: '18px' }}> - <a className='detailed-status__datetime' style={{ color: 'inherit' }} href={status.get('url')} target='_blank' rel='noopener'>{moment(status.get('created_at')).format('HH:mm, DD MMM Y')}</a> · <Link to={`/statuses/${status.get('id')}/reblogs`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-retweet' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}>{status.get('reblogs_count')}</span></Link> · <Link to={`/statuses/${status.get('id')}/favourites`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-star' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}>{status.get('favourites_count')}</span></Link> + <a className='detailed-status__datetime' style={{ color: 'inherit' }} href={status.get('url')} target='_blank' rel='noopener'><FormattedDate value={status.get('created_at')} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /></a> · <Link to={`/statuses/${status.get('id')}/reblogs`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-retweet' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('reblogs_count')} /></span></Link> · <Link to={`/statuses/${status.get('id')}/favourites`} style={{ color: 'inherit', textDecoration: 'none' }}><i className='fa fa-star' /><span style={{ fontWeight: '500', fontSize: '12px', marginLeft: '6px', display: 'inline-block' }}><FormattedNumber value={status.get('favourites_count')} /></span></Link> </div> </div> ); diff --git a/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx b/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx index 723f8c9ac..8313d8826 100644 --- a/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx +++ b/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx @@ -1,4 +1,5 @@ import { Link } from 'react-router'; +import { FormattedMessage } from 'react-intl'; const outerStyle = { background: '#373b4a', @@ -28,10 +29,10 @@ const tabActiveStyle = { const TabsBar = () => { return ( <div style={outerStyle}> - <Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/new'><i className='fa fa-fw fa-pencil' /> Compose</Link> - <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/home'><i className='fa fa-fw fa-home' /> Home</Link> - <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/mentions'><i className='fa fa-fw fa-at' /> Mentions</Link> - <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/public'><i className='fa fa-fw fa-globe' /> Public</Link> + <Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/new'><i className='fa fa-fw fa-pencil' /> <FormattedMessage id='tabs_bar.compose' defaultMessage='Compose' /></Link> + <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/home'><i className='fa fa-fw fa-home' /> <FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></Link> + <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/mentions'><i className='fa fa-fw fa-at' /> <FormattedMessage id='tabs_bar.mentions' defaultMessage='Mentions' /></Link> + <Link style={tabStyle} activeStyle={tabActiveStyle} to='/timelines/public'><i className='fa fa-fw fa-globe' /> <FormattedMessage id='tabs_bar.public' defaultMessage='Public' /></Link> </div> ); }; |