Skip to content
Snippets Groups Projects
Commit 01e43c3e authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Adding react-intl i18n to the frontend. No translations yet

parent 546c4718
No related branches found
No related tags found
No related merge requests found
Showing
with 170 additions and 173 deletions
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import { FormattedMessage } from 'react-intl';
const outerStyle = { const outerStyle = {
padding: '15px', padding: '15px',
...@@ -30,7 +31,7 @@ const ColumnBackButton = React.createClass({ ...@@ -30,7 +31,7 @@ const ColumnBackButton = React.createClass({
return ( return (
<div onClick={this.handleClick} style={outerStyle} className='column-back-button'> <div onClick={this.handleClick} style={outerStyle} className='column-back-button'>
<i className='fa fa-fw fa-chevron-left' style={iconStyle} /> <i className='fa fa-fw fa-chevron-left' style={iconStyle} />
Back <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
</div> </div>
); );
} }
......
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import IconButton from './icon_button'; import IconButton from './icon_button';
import { Motion, spring } from 'react-motion'; import { Motion, spring } from 'react-motion';
import { injectIntl } from 'react-intl';
const overlayStyle = { const overlayStyle = {
position: 'fixed', position: 'fixed',
...@@ -40,14 +41,14 @@ const Lightbox = React.createClass({ ...@@ -40,14 +41,14 @@ const Lightbox = React.createClass({
mixins: [PureRenderMixin], mixins: [PureRenderMixin],
render () { render () {
const { isVisible, onOverlayClicked, onCloseClicked, children } = this.props; const { intl, isVisible, onOverlayClicked, onCloseClicked, children } = this.props;
return ( return (
<div className='lightbox' style={{...overlayStyle, display: isVisible ? 'flex' : 'none'}} onClick={onOverlayClicked}> <div className='lightbox' style={{...overlayStyle, display: isVisible ? 'flex' : 'none'}} onClick={onOverlayClicked}>
<Motion defaultStyle={{ y: -200 }} style={{ y: spring(isVisible ? 0 : -200) }}> <Motion defaultStyle={{ y: -200 }} style={{ y: spring(isVisible ? 0 : -200) }}>
{({ y }) => {({ y }) =>
<div style={{...dialogStyle, transform: `translateY(${y}px)`}}> <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} {children}
</div> </div>
} }
...@@ -58,4 +59,4 @@ const Lightbox = React.createClass({ ...@@ -58,4 +59,4 @@ const Lightbox = React.createClass({
}); });
export default Lightbox; export default injectIntl(Lightbox);
import { FormattedMessage } from 'react-intl';
const LoadingIndicator = () => { const LoadingIndicator = () => {
const style = { const style = {
textAlign: 'center', textAlign: 'center',
...@@ -7,7 +9,7 @@ const LoadingIndicator = () => { ...@@ -7,7 +9,7 @@ const LoadingIndicator = () => {
paddingTop: '120px' paddingTop: '120px'
}; };
return <div style={style}>Loading...</div>; return <div style={style}><FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' /></div>;
}; };
export default LoadingIndicator; export default LoadingIndicator;
import moment from 'moment'; import {
import PureRenderMixin from 'react-addons-pure-render-mixin'; FormattedMessage,
FormattedDate,
moment.updateLocale('en', { FormattedRelative
relativeTime : { } from 'react-intl';
future: "in %s",
past: "%s", const RelativeTimestamp = ({ timestamp, now }) => {
s: "%ds", const diff = (new Date(now)) - (new Date(timestamp));
m: "1m",
mm: "%dm", if (diff < 0) {
h: "1h", return <FormattedMessage id='relative_time.just_now' defaultMessage='Just now' />
hh: "%dh", } else if (diff > (3600 * 24 * 7 * 1000)) {
d: "1d", return <FormattedDate value={timestamp} />
dd: "%dd", } else {
M: "1mo", return <FormattedRelative value={timestamp} initialNow={now} updateInterval={0} />
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>
);
} }
};
}); RelativeTimestamp.propTypes = {
timestamp: React.PropTypes.string.isRequired,
now: React.PropTypes.any
};
export default RelativeTimestamp; export default RelativeTimestamp;
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from './avatar'; import Avatar from './avatar';
import RelativeTimestamp from './relative_timestamp'; import RelativeTimestamp from './relative_timestamp';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import DisplayName from './display_name'; import DisplayName from './display_name';
import MediaGallery from './media_gallery'; import MediaGallery from './media_gallery';
import VideoPlayer from './video_player'; import VideoPlayer from './video_player';
import StatusContent from './status_content'; import StatusContent from './status_content';
import StatusActionBar from './status_action_bar'; import StatusActionBar from './status_action_bar';
import { FormattedMessage } from 'react-intl';
const Status = React.createClass({ const Status = React.createClass({
...@@ -59,7 +60,7 @@ const Status = React.createClass({ ...@@ -59,7 +60,7 @@ const Status = React.createClass({
<div style={{ cursor: 'default' }}> <div style={{ cursor: 'default' }}>
<div style={{ marginLeft: '68px', color: '#616b86', padding: '8px 0', paddingBottom: '2px', fontSize: '14px', position: 'relative' }}> <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> <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> </div>
<Status {...other} wrapped={true} status={status.get('reblog')} /> <Status {...other} wrapped={true} status={status.get('reblog')} />
......
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import IconButton from './icon_button'; import IconButton from './icon_button';
import DropdownMenu from './dropdown_menu'; import DropdownMenu from './dropdown_menu';
import { injectIntl } from 'react-intl';
const StatusActionBar = React.createClass({ const StatusActionBar = React.createClass({
propTypes: { propTypes: {
...@@ -36,20 +37,20 @@ const StatusActionBar = React.createClass({ ...@@ -36,20 +37,20 @@ const StatusActionBar = React.createClass({
}, },
render () { render () {
const { status, me } = this.props; const { status, me, intl } = this.props;
let menu = []; let menu = [];
if (status.getIn(['account', 'id']) === me) { 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 { } else {
menu.push({ text: 'Mention', action: this.handleMentionClick }); menu.push({ text: intl.formatMessage({ id: 'status.mention', defaultMessage: 'Mention' }), action: this.handleMentionClick });
} }
return ( return (
<div style={{ marginTop: '10px', overflow: 'hidden' }}> <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 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='Reblog' icon='retweet' onClick={this.handleReblogClick} /></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='Favourite' icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></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' }}> <div style={{ width: '18px', height: '18px', float: 'left' }}>
<DropdownMenu items={menu} icon='ellipsis-h' size={18} /> <DropdownMenu items={menu} icon='ellipsis-h' size={18} />
...@@ -60,4 +61,4 @@ const StatusActionBar = React.createClass({ ...@@ -60,4 +61,4 @@ const StatusActionBar = React.createClass({
}); });
export default StatusActionBar; export default injectIntl(StatusActionBar);
...@@ -3,7 +3,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; ...@@ -3,7 +3,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import { ScrollContainer } from 'react-router-scroll'; import { ScrollContainer } from 'react-router-scroll';
import StatusContainer from '../containers/status_container'; import StatusContainer from '../containers/status_container';
import moment from 'moment';
const StatusList = React.createClass({ const StatusList = React.createClass({
...@@ -21,14 +20,14 @@ const StatusList = React.createClass({ ...@@ -21,14 +20,14 @@ const StatusList = React.createClass({
getInitialState () { getInitialState () {
return { return {
now: moment() now: new Date()
}; };
}, },
mixins: [PureRenderMixin], mixins: [PureRenderMixin],
componentDidMount () { componentDidMount () {
this._interval = setInterval(() => this.setState({ now: moment() }), 60000); this._interval = setInterval(() => this.setState({ now: new Date() }), 60000);
}, },
componentWillUnmount () { componentWillUnmount () {
......
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import IconButton from './icon_button'; import IconButton from './icon_button';
import { injectIntl } from 'react-intl';
const videoStyle = { const videoStyle = {
position: 'relative', position: 'relative',
...@@ -59,14 +60,16 @@ const VideoPlayer = React.createClass({ ...@@ -59,14 +60,16 @@ const VideoPlayer = React.createClass({
}, },
render () { render () {
const { media, intl, width, height } = this.props;
return ( 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={{ cursor: 'default', marginTop: '8px', overflow: 'hidden', width: `${width}px`, height: `${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> <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={this.props.media.get('url')} autoPlay='true' loop={true} muted={this.state.muted} style={videoStyle} onClick={this.handleVideoClick} /> <video src={media.get('url')} autoPlay='true' loop={true} muted={this.state.muted} style={videoStyle} onClick={this.handleVideoClick} />
</div> </div>
); );
} }
}); });
export default VideoPlayer; export default injectIntl(VideoPlayer);
...@@ -32,6 +32,7 @@ import Following from '../features/following'; ...@@ -32,6 +32,7 @@ import Following from '../features/following';
import Reblogs from '../features/reblogs'; import Reblogs from '../features/reblogs';
import Favourites from '../features/favourites'; import Favourites from '../features/favourites';
import HashtagTimeline from '../features/hashtag_timeline'; import HashtagTimeline from '../features/hashtag_timeline';
import { IntlProvider } from 'react-intl';
const store = configureStore(); const store = configureStore();
...@@ -44,7 +45,8 @@ const Mastodon = React.createClass({ ...@@ -44,7 +45,8 @@ const Mastodon = React.createClass({
propTypes: { propTypes: {
token: React.PropTypes.string.isRequired, token: React.PropTypes.string.isRequired,
timelines: React.PropTypes.object, timelines: React.PropTypes.object,
account: React.PropTypes.string account: React.PropTypes.string,
locale: React.PropTypes.string.isRequired
}, },
mixins: [PureRenderMixin], mixins: [PureRenderMixin],
...@@ -81,30 +83,34 @@ const Mastodon = React.createClass({ ...@@ -81,30 +83,34 @@ const Mastodon = React.createClass({
}, },
render () { render () {
const { locale } = this.props;
return ( return (
<Provider store={store}> <IntlProvider locale={locale}>
<Router history={browserHistory} render={applyRouterMiddleware(useScroll())}> <Provider store={store}>
<Route path='/' component={UI}> <Router history={browserHistory} render={applyRouterMiddleware(useScroll())}>
<IndexRoute component={GettingStarted} /> <Route path='/' component={UI}>
<IndexRoute component={GettingStarted} />
<Route path='timelines/home' component={HomeTimeline} />
<Route path='timelines/mentions' component={MentionsTimeline} /> <Route path='timelines/home' component={HomeTimeline} />
<Route path='timelines/public' component={PublicTimeline} /> <Route path='timelines/mentions' component={MentionsTimeline} />
<Route path='timelines/tag/:id' component={HashtagTimeline} /> <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/new' component={Compose} />
<Route path='statuses/:statusId/reblogs' component={Reblogs} /> <Route path='statuses/:statusId' component={Status} />
<Route path='statuses/:statusId/favourites' component={Favourites} /> <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='accounts/:accountId' component={Account}>
<Route path='followers' component={Followers} /> <IndexRoute component={AccountTimeline} />
<Route path='following' component={Following} /> <Route path='followers' component={Followers} />
<Route path='following' component={Following} />
</Route>
</Route> </Route>
</Route> </Router>
</Router> </Provider>
</Provider> </IntlProvider>
); );
} }
......
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import DropdownMenu from '../../../components/dropdown_menu'; import DropdownMenu from '../../../components/dropdown_menu';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
const outerStyle = { const outerStyle = {
borderTop: '1px solid #363c4b', borderTop: '1px solid #363c4b',
...@@ -36,22 +37,22 @@ const ActionBar = React.createClass({ ...@@ -36,22 +37,22 @@ const ActionBar = React.createClass({
mixins: [PureRenderMixin], mixins: [PureRenderMixin],
render () { render () {
const { account, me } = this.props; const { account, me, intl } = this.props;
let menu = []; 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) { 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'])) { } 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'])) { } else if (account.getIn(['relationship', 'following'])) {
menu.push({ text: 'Unfollow', action: this.props.onFollow }); menu.push({ text: intl.formatMessage({ id: 'account.unfollow', defaultMessage: 'Unfollow' }), action: this.props.onFollow });
menu.push({ text: 'Block', action: this.props.onBlock }); menu.push({ text: intl.formatMessage({ id: 'account.block', defaultMessage: 'Block' }), action: this.props.onBlock });
} else { } else {
menu.push({ text: 'Follow', action: this.props.onFollow }); menu.push({ text: intl.formatMessage({ id: 'account.follow', defaultMessage: 'Follow' }), action: this.props.onFollow });
menu.push({ text: 'Block', action: this.props.onBlock }); menu.push({ text: intl.formatMessage({ id: 'account.block', defaultMessage: 'Block' }), action: this.props.onBlock });
} }
return ( return (
...@@ -62,24 +63,24 @@ const ActionBar = React.createClass({ ...@@ -62,24 +63,24 @@ const ActionBar = React.createClass({
<div style={outerLinksStyle}> <div style={outerLinksStyle}>
<Link to={`/accounts/${account.get('id')}`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', borderLeft: '1px solid #363c4b', padding: '10px', paddingRight: '5px' }}> <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', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.posts' defaultMessage='Posts' /></span>
<span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('statuses_count')}</span> <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('statuses_count')} /></span>
</Link> </Link>
<Link to={`/accounts/${account.get('id')}/following`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', borderLeft: '1px solid #363c4b', padding: '10px 5px' }}> <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', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.follows' defaultMessage='Follows' /></span>
<span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('following_count')}</span> <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('following_count')} /></span>
</Link> </Link>
<Link to={`/accounts/${account.get('id')}/followers`} style={{ textDecoration: 'none', overflow: 'hidden', width: '80px', padding: '10px 5px', borderLeft: '1px solid #363c4b' }}> <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', textTransform: 'uppercase', fontSize: '11px', color: '#616b86' }}><FormattedMessage id='account.followers' defaultMessage='Followers' /></span>
<span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}>{account.get('followers_count')}</span> <span style={{ display: 'block', fontSize: '15px', fontWeight: '500', color: '#fff' }}><FormattedNumber value={account.get('followers_count')} /></span>
</Link> </Link>
</div> </div>
</div> </div>
); );
}, }
}); });
export default ActionBar; export default injectIntl(ActionBar);
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { import {
fetchAccountTimeline, fetchAccountTimeline,
expandAccountTimeline expandAccountTimeline
} from '../../actions/accounts'; } from '../../actions/accounts';
import StatusList from '../../components/status_list'; import StatusList from '../../components/status_list';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
const mapStateToProps = (state, props) => ({ const mapStateToProps = (state, props) => ({
statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId)]), statusIds: state.getIn(['timelines', 'accounts_timelines', Number(props.params.accountId)]),
......
...@@ -8,6 +8,7 @@ import Autosuggest from 'react-autosuggest'; ...@@ -8,6 +8,7 @@ import Autosuggest from 'react-autosuggest';
import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container'; import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container';
import { debounce } from 'react-decoration'; import { debounce } from 'react-decoration';
import UploadButtonContainer from '../containers/upload_button_container'; import UploadButtonContainer from '../containers/upload_button_container';
import { injectIntl } from 'react-intl';
const getTokenForSuggestions = (str, caretPosition) => { const getTokenForSuggestions = (str, caretPosition) => {
let word; let word;
...@@ -134,6 +135,7 @@ const ComposeForm = React.createClass({ ...@@ -134,6 +135,7 @@ const ComposeForm = React.createClass({
}, },
render () { render () {
const { intl } = this.props;
let replyArea = ''; let replyArea = '';
const disabled = this.props.is_submitting || this.props.is_uploading; const disabled = this.props.is_submitting || this.props.is_uploading;
...@@ -142,7 +144,7 @@ const ComposeForm = React.createClass({ ...@@ -142,7 +144,7 @@ const ComposeForm = React.createClass({
} }
const inputProps = { 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, value: this.props.text,
onKeyUp: this.handleKeyUp, onKeyUp: this.handleKeyUp,
onChange: this.handleChange, onChange: this.handleChange,
...@@ -167,7 +169,7 @@ const ComposeForm = React.createClass({ ...@@ -167,7 +169,7 @@ const ComposeForm = React.createClass({
/> />
<div style={{ marginTop: '10px', overflow: 'hidden' }}> <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> <div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
<UploadButtonContainer style={{ paddingTop: '4px' }} /> <UploadButtonContainer style={{ paddingTop: '4px' }} />
</div> </div>
...@@ -177,4 +179,4 @@ const ComposeForm = React.createClass({ ...@@ -177,4 +179,4 @@ const ComposeForm = React.createClass({
}); });
export default ComposeForm; export default injectIntl(ComposeForm);
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar'; import Avatar from '../../../components/avatar';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
import DisplayName from '../../../components/display_name'; import DisplayName from '../../../components/display_name';
import { Link } from 'react-router'; import { Link } from 'react-router';
import { FormattedMessage } from 'react-intl';
const NavigationBar = React.createClass({ const NavigationBar = React.createClass({
propTypes: { propTypes: {
...@@ -19,7 +20,7 @@ const NavigationBar = React.createClass({ ...@@ -19,7 +20,7 @@ const NavigationBar = React.createClass({
<div style={{ flex: '1 1 auto', marginLeft: '8px', color: '#9baec8' }}> <div style={{ flex: '1 1 auto', marginLeft: '8px', color: '#9baec8' }}>
<strong style={{ fontWeight: '500', display: 'block', color: '#fff' }}>{this.props.account.get('acct')}</strong> <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>
</div> </div>
); );
......
...@@ -3,11 +3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; ...@@ -3,11 +3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar'; import Avatar from '../../../components/avatar';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
import DisplayName from '../../../components/display_name'; import DisplayName from '../../../components/display_name';
import emojione from 'emojione'; import emojify from '../../../emoji';
import { injectIntl } from 'react-intl';
emojione.imageType = 'png';
emojione.sprites = false;
emojione.imagePathPNG = '/emoji/';
const ReplyIndicator = React.createClass({ const ReplyIndicator = React.createClass({
...@@ -34,12 +31,13 @@ const ReplyIndicator = React.createClass({ ...@@ -34,12 +31,13 @@ const ReplyIndicator = React.createClass({
}, },
render () { 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 ( return (
<div style={{ background: '#9baec8', padding: '10px' }}> <div style={{ background: '#9baec8', padding: '10px' }}>
<div style={{ overflow: 'hidden', marginBottom: '5px' }}> <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' }}> <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> <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({ ...@@ -54,4 +52,4 @@ const ReplyIndicator = React.createClass({
}); });
export default ReplyIndicator; export default injectIntl(ReplyIndicator);
...@@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; ...@@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import Autosuggest from 'react-autosuggest'; import Autosuggest from 'react-autosuggest';
import AutosuggestAccountContainer from '../containers/autosuggest_account_container'; import AutosuggestAccountContainer from '../containers/autosuggest_account_container';
import { debounce } from 'react-decoration'; import { debounce } from 'react-decoration';
import { injectIntl } from 'react-intl';
const getSuggestionValue = suggestion => suggestion.value; const getSuggestionValue = suggestion => suggestion.value;
...@@ -94,7 +95,7 @@ const Search = React.createClass({ ...@@ -94,7 +95,7 @@ const Search = React.createClass({
render () { render () {
const inputProps = { const inputProps = {
placeholder: 'Search', placeholder: this.props.intl.formatMessage({ id: 'search.placeholder', defaultMessage: 'Search' }),
value: this.props.value, value: this.props.value,
onChange: this.onChange, onChange: this.onChange,
style: inputStyle style: inputStyle
...@@ -125,4 +126,4 @@ const Search = React.createClass({ ...@@ -125,4 +126,4 @@ const Search = React.createClass({
}); });
export default Search; export default injectIntl(Search);
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; 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 = { const outerStyle = {
position: 'relative' position: 'relative'
...@@ -66,13 +67,13 @@ const SuggestionsBox = React.createClass({ ...@@ -66,13 +67,13 @@ const SuggestionsBox = React.createClass({
let nextLink = ''; let nextLink = '';
if (accountIds.size > perWindow) { 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 ( return (
<div style={outerStyle}> <div style={outerStyle}>
<strong style={headerStyle}> <strong style={headerStyle}>
Who to follow {nextLink} <FormattedMessage id='suggestions_box.who_to_follow' defaultMessage='Who to follow' /> {nextLink}
</strong> </strong>
{accountIds.skip(perWindow * this.state.index).take(perWindow).map(accountId => <AccountContainer key={accountId} id={accountId} withNote={false} />)} {accountIds.skip(perWindow * this.state.index).take(perWindow).map(accountId => <AccountContainer key={accountId} id={accountId} withNote={false} />)}
......
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
import { injectIntl } from 'react-intl';
const UploadButton = React.createClass({ const UploadButton = React.createClass({
...@@ -26,9 +27,11 @@ const UploadButton = React.createClass({ ...@@ -26,9 +27,11 @@ const UploadButton = React.createClass({
}, },
render () { render () {
const { intl } = this.props;
return ( return (
<div style={this.props.style}> <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' }} /> <input ref={this.setRef} type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} />
</div> </div>
); );
...@@ -36,4 +39,4 @@ const UploadButton = React.createClass({ ...@@ -36,4 +39,4 @@ const UploadButton = React.createClass({
}); });
export default UploadButton; export default injectIntl(UploadButton);
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; 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({ const UploadForm = React.createClass({
...@@ -13,10 +14,12 @@ const UploadForm = React.createClass({ ...@@ -13,10 +14,12 @@ const UploadForm = React.createClass({
mixins: [PureRenderMixin], mixins: [PureRenderMixin],
render () { render () {
const { intl } = this.props;
const uploads = this.props.media.map(attachment => ( const uploads = this.props.media.map(attachment => (
<div key={attachment.get('id')} style={{ borderRadius: '4px', marginBottom: '10px' }} className='transparent-background'> <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' }}> <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>
</div> </div>
)); ));
...@@ -30,4 +33,4 @@ const UploadForm = React.createClass({ ...@@ -30,4 +33,4 @@ const UploadForm = React.createClass({
}); });
export default UploadForm; export default injectIntl(UploadForm);
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import { fetchFavourites } from '../../actions/interactions'; import { fetchFavourites } from '../../actions/interactions';
import { ScrollContainer } from 'react-router-scroll'; import { ScrollContainer } from 'react-router-scroll';
import AccountContainer from '../followers/containers/account_container'; import AccountContainer from '../followers/containers/account_container';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButton from '../../components/column_back_button'; import ColumnBackButton from '../../components/column_back_button';
const mapStateToProps = (state, props) => ({ const mapStateToProps = (state, props) => ({
accountIds: state.getIn(['user_lists', 'favourited_by', Number(props.params.statusId)]) accountIds: state.getIn(['user_lists', 'favourited_by', Number(props.params.statusId)])
......
import PureRenderMixin from 'react-addons-pure-render-mixin'; import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar'; import Avatar from '../../../components/avatar';
import DisplayName from '../../../components/display_name'; import DisplayName from '../../../components/display_name';
import { Link } from 'react-router'; import { Link } from 'react-router';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
import { injectIntl } from 'react-intl';
const outerStyle = { const outerStyle = {
padding: '10px', padding: '10px',
...@@ -51,7 +52,7 @@ const Account = React.createClass({ ...@@ -51,7 +52,7 @@ const Account = React.createClass({
}, },
render () { render () {
const { account, me, withNote } = this.props; const { account, me, withNote, intl } = this.props;
if (!account) { if (!account) {
return <div />; return <div />;
...@@ -68,7 +69,7 @@ const Account = React.createClass({ ...@@ -68,7 +69,7 @@ const Account = React.createClass({
buttons = ( buttons = (
<div style={buttonsStyle}> <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> </div>
); );
} }
...@@ -91,4 +92,4 @@ const Account = React.createClass({ ...@@ -91,4 +92,4 @@ const Account = React.createClass({
}); });
export default Account; export default injectIntl(Account);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment