about summary refs log tree commit diff
path: root/app/assets/javascripts/components/features
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2016-11-16 17:20:52 +0100
committerEugen Rochko <eugen@zeonfederated.com>2016-11-16 17:20:52 +0100
commit01e43c3e5799b575a70798056945365ddf51f3ad (patch)
tree75801dd3733930cc05cd3c26795cef382a4c1e5d /app/assets/javascripts/components/features
parent546c4718e781f8900ba6498307ccb1e659de5edd (diff)
Adding react-intl i18n to the frontend. No translations yet
Diffstat (limited to 'app/assets/javascripts/components/features')
-rw-r--r--app/assets/javascripts/components/features/account/components/action_bar.jsx39
-rw-r--r--app/assets/javascripts/components/features/account_timeline/index.jsx12
-rw-r--r--app/assets/javascripts/components/features/compose/components/compose_form.jsx8
-rw-r--r--app/assets/javascripts/components/features/compose/components/navigation_bar.jsx9
-rw-r--r--app/assets/javascripts/components/features/compose/components/reply_indicator.jsx14
-rw-r--r--app/assets/javascripts/components/features/compose/components/search.jsx5
-rw-r--r--app/assets/javascripts/components/features/compose/components/suggestions_box.jsx9
-rw-r--r--app/assets/javascripts/components/features/compose/components/upload_button.jsx7
-rw-r--r--app/assets/javascripts/components/features/compose/components/upload_form.jsx11
-rw-r--r--app/assets/javascripts/components/features/favourites/index.jsx18
-rw-r--r--app/assets/javascripts/components/features/followers/components/account.jsx17
-rw-r--r--app/assets/javascripts/components/features/getting_started/index.jsx12
-rw-r--r--app/assets/javascripts/components/features/home_timeline/index.jsx13
-rw-r--r--app/assets/javascripts/components/features/mentions_timeline/index.jsx11
-rw-r--r--app/assets/javascripts/components/features/public_timeline/index.jsx7
-rw-r--r--app/assets/javascripts/components/features/reblogs/index.jsx18
-rw-r--r--app/assets/javascripts/components/features/status/components/action_bar.jsx21
-rw-r--r--app/assets/javascripts/components/features/status/components/detailed_status.jsx18
-rw-r--r--app/assets/javascripts/components/features/ui/components/tabs_bar.jsx9
19 files changed, 140 insertions, 118 deletions
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>
   );
 };