summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/admin_console/email_settings.jsx20
-rw-r--r--web/react/components/admin_console/ldap_settings.jsx2
-rw-r--r--web/react/components/audio_video_preview.jsx4
-rw-r--r--web/react/components/center_panel.jsx9
-rw-r--r--web/react/components/channel_loader.jsx52
-rw-r--r--web/react/components/create_post.jsx42
-rw-r--r--web/react/components/file_attachment.jsx16
-rw-r--r--web/react/components/file_info_preview.jsx19
-rw-r--r--web/react/components/login_username.jsx4
-rw-r--r--web/react/components/navbar.jsx89
-rw-r--r--web/react/components/post_attachment.jsx22
-rw-r--r--web/react/components/post_body.jsx47
-rw-r--r--web/react/components/post_focus_view.jsx9
-rw-r--r--web/react/components/post_info.jsx32
-rw-r--r--web/react/components/posts_view.jsx27
-rw-r--r--web/react/components/time_since.jsx20
-rw-r--r--web/react/components/view_image.jsx28
-rw-r--r--web/react/components/view_image_popover_bar.jsx23
18 files changed, 387 insertions, 78 deletions
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index 17f25a04c..435eff036 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -339,7 +339,10 @@ class EmailSettings extends React.Component {
defaultChecked={this.props.config.EmailSettings.EnableSignInWithEmail}
onChange={this.handleChange.bind(this, 'allowSignInWithEmail_true')}
/>
- {'true'}
+ <FormattedMessage
+ id='admin.email.true'
+ defaultMessage='true'
+ />
</label>
<label className='radio-inline'>
<input
@@ -349,7 +352,10 @@ class EmailSettings extends React.Component {
defaultChecked={!this.props.config.EmailSettings.EnableSignInWithEmail}
onChange={this.handleChange.bind(this, 'allowSignInWithEmail_false')}
/>
- {'false'}
+ <FormattedMessage
+ id='admin.email.false'
+ defaultMessage='false'
+ />
</label>
<p className='help-text'>
<FormattedMessage
@@ -380,7 +386,10 @@ class EmailSettings extends React.Component {
defaultChecked={this.props.config.EmailSettings.EnableSignInWithUsername}
onChange={this.handleChange.bind(this, 'allowSignInWithUsername_true')}
/>
- {'true'}
+ <FormattedMessage
+ id='admin.email.true'
+ defaultMessage='true'
+ />
</label>
<label className='radio-inline'>
<input
@@ -390,7 +399,10 @@ class EmailSettings extends React.Component {
defaultChecked={!this.props.config.EmailSettings.EnableSignInWithUsername}
onChange={this.handleChange.bind(this, 'allowSignInWithUsername_false')}
/>
- {'false'}
+ <FormattedMessage
+ id='admin.email.false'
+ defaultMessage='false'
+ />
</label>
<p className='help-text'>
<FormattedMessage
diff --git a/web/react/components/admin_console/ldap_settings.jsx b/web/react/components/admin_console/ldap_settings.jsx
index bc13b3bcd..535c264dd 100644
--- a/web/react/components/admin_console/ldap_settings.jsx
+++ b/web/react/components/admin_console/ldap_settings.jsx
@@ -164,7 +164,7 @@ class LdapSettings extends React.Component {
<div className='banner__content'>
<FormattedHTMLMessage
id='admin.ldap.noLicense'
- defaultMessage='<h4 className="banner__heading">Note:</h4><p>LDAP is an enterprise feature. Your current license does not support LDAP. Click <a href="http://mattermost.com"target="_blank">here</a> for information and pricing on enterprise licenses.</p>'
+ defaultMessage='<h4 class="banner__heading">Note:</h4><p>LDAP is an enterprise feature. Your current license does not support LDAP. Click <a href="http://mattermost.com"target="_blank">here</a> for information and pricing on enterprise licenses.</p>'
/>
</div>
</div>
diff --git a/web/react/components/audio_video_preview.jsx b/web/react/components/audio_video_preview.jsx
index 7d00fbdaa..739c8c95e 100644
--- a/web/react/components/audio_video_preview.jsx
+++ b/web/react/components/audio_video_preview.jsx
@@ -75,6 +75,7 @@ export default class AudioVideoPreview extends React.Component {
filename={this.props.filename}
fileUrl={this.props.fileUrl}
fileInfo={this.props.fileInfo}
+ formatMessage={this.props.formatMessage}
/>
);
}
@@ -110,5 +111,6 @@ AudioVideoPreview.propTypes = {
filename: React.PropTypes.string.isRequired,
fileUrl: React.PropTypes.string.isRequired,
fileInfo: React.PropTypes.object.isRequired,
- maxHeight: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired
+ maxHeight: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired,
+ formatMessage: React.PropTypes.func.isRequired
};
diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx
index 443ecefde..7d2be04d6 100644
--- a/web/react/components/center_panel.jsx
+++ b/web/react/components/center_panel.jsx
@@ -15,6 +15,8 @@ import UserStore from '../stores/user_store.jsx';
import * as Utils from '../utils/utils.jsx';
+import {FormattedMessage} from 'mm-intl';
+
import Constants from '../utils/constants.jsx';
const TutorialSteps = Constants.TutorialSteps;
const Preferences = Constants.Preferences;
@@ -69,8 +71,11 @@ export default class CenterPanel extends React.Component {
onClick={handleClick}
>
<a href=''>
- {'Click here to jump to recent messages. '}
- {<i className='fa fa-arrow-down'></i>}
+ <FormattedMessage
+ id='center_panel.recent'
+ defaultMessage='Click here to jump to recent messages. '
+ />
+ <i className='fa fa-arrow-down'></i>
</a>
</div>
);
diff --git a/web/react/components/channel_loader.jsx b/web/react/components/channel_loader.jsx
index 712d6885f..15571ad93 100644
--- a/web/react/components/channel_loader.jsx
+++ b/web/react/components/channel_loader.jsx
@@ -15,7 +15,40 @@ import PreferenceStore from '../stores/preference_store.jsx';
import * as Utils from '../utils/utils.jsx';
import Constants from '../utils/constants.jsx';
-export default class ChannelLoader extends React.Component {
+import {intlShape, injectIntl, defineMessages} from 'mm-intl';
+
+const holders = defineMessages({
+ socketError: {
+ id: 'channel_loader.socketError',
+ defaultMessage: 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.'
+ },
+ someone: {
+ id: 'channel_loader.someone',
+ defaultMessage: 'Someone'
+ },
+ posted: {
+ id: 'channel_loader.posted',
+ defaultMessage: 'Posted'
+ },
+ uploadedImage: {
+ id: 'channel_loader.uploadedImage',
+ defaultMessage: ' uploaded an image'
+ },
+ uploadedFile: {
+ id: 'channel_loader.uploadedFile',
+ defaultMessage: ' uploaded a file'
+ },
+ something: {
+ id: 'channel_loader.something',
+ defaultMessage: ' did something new'
+ },
+ wrote: {
+ id: 'channel_loader.wrote',
+ defaultMessage: ' wrote: '
+ }
+});
+
+class ChannelLoader extends React.Component {
constructor(props) {
super(props);
@@ -23,6 +56,17 @@ export default class ChannelLoader extends React.Component {
this.onSocketChange = this.onSocketChange.bind(this);
+ const {formatMessage} = this.props.intl;
+ SocketStore.setTranslations({
+ socketError: formatMessage(holders.socketError),
+ someone: formatMessage(holders.someone),
+ posted: formatMessage(holders.posted),
+ uploadedImage: formatMessage(holders.uploadedImage),
+ uploadedFile: formatMessage(holders.uploadedFile),
+ something: formatMessage(holders.something),
+ wrote: formatMessage(holders.wrote)
+ });
+
this.state = {};
}
componentDidMount() {
@@ -126,3 +170,9 @@ export default class ChannelLoader extends React.Component {
return <div/>;
}
}
+
+ChannelLoader.propTypes = {
+ intl: intlShape.isRequired
+};
+
+export default injectIntl(ChannelLoader); \ No newline at end of file
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index de971c43f..ed672cd34 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -21,12 +21,33 @@ import SocketStore from '../stores/socket_store.jsx';
import Constants from '../utils/constants.jsx';
+import {intlShape, injectIntl, defineMessages, FormattedHTMLMessage} from 'mm-intl';
+
const Preferences = Constants.Preferences;
const TutorialSteps = Constants.TutorialSteps;
const ActionTypes = Constants.ActionTypes;
const KeyCodes = Constants.KeyCodes;
-export default class CreatePost extends React.Component {
+const holders = defineMessages({
+ comment: {
+ id: 'create_post.comment',
+ defaultMessage: 'Comment'
+ },
+ post: {
+ id: 'create_post.post',
+ defaultMessage: 'Post'
+ },
+ write: {
+ id: 'create_post.write',
+ defaultMessage: 'Write a message...'
+ },
+ deleteMsg: {
+ id: 'create_post.deleteMsg',
+ defaultMessage: '(message deleted)'
+ }
+});
+
+class CreatePost extends React.Component {
constructor(props) {
super(props);
@@ -49,6 +70,7 @@ export default class CreatePost extends React.Component {
this.sendMessage = this.sendMessage.bind(this);
PostStore.clearDraftUploads();
+ PostStore.deleteMessage(this.props.intl.formatMessage(holders.deleteMsg));
const draft = this.getCurrentDraft();
@@ -361,7 +383,8 @@ export default class CreatePost extends React.Component {
if (!lastPost) {
return;
}
- var type = (lastPost.root_id && lastPost.root_id.length > 0) ? 'Comment' : 'Post';
+ const {formatMessage} = this.props.intl;
+ var type = (lastPost.root_id && lastPost.root_id.length > 0) ? formatMessage(holders.comment) : formatMessage(holders.post);
AppDispatcher.handleViewAction({
type: ActionTypes.RECIEVED_EDIT_POST,
@@ -379,9 +402,10 @@ export default class CreatePost extends React.Component {
screens.push(
<div>
- <h4>{'Sending Messages'}</h4>
- <p>{'Type here to write a message and press '}<strong>{'Enter'}</strong>{' to post it.'}</p>
- <p>{'Click the '}<strong>{'Attachment'}</strong>{' button to upload an image or a file.'}</p>
+ <FormattedHTMLMessage
+ id='create_post.tutorialTip'
+ defaultMessage='<h4>Sending Messages</h4><p>Type here to write a message and press <strong>Enter</strong> to post it.</p><p>Click the <strong>Attachment</strong> button to upload an image or a file.</p>'
+ />
</div>
);
@@ -445,7 +469,7 @@ export default class CreatePost extends React.Component {
onKeyDown={this.handleKeyDown}
onHeightChange={this.resizePostHolder}
messageText={this.state.messageText}
- createMessage='Write a message...'
+ createMessage={this.props.intl.formatMessage(holders.write)}
channelId={this.state.channelId}
id='post_textbox'
ref='textbox'
@@ -482,3 +506,9 @@ export default class CreatePost extends React.Component {
);
}
}
+
+CreatePost.propTypes = {
+ intl: intlShape.isRequired
+};
+
+export default injectIntl(CreatePost); \ No newline at end of file
diff --git a/web/react/components/file_attachment.jsx b/web/react/components/file_attachment.jsx
index eeb218bfe..776394828 100644
--- a/web/react/components/file_attachment.jsx
+++ b/web/react/components/file_attachment.jsx
@@ -5,7 +5,16 @@ import * as utils from '../utils/utils.jsx';
import * as Client from '../utils/client.jsx';
import Constants from '../utils/constants.jsx';
-export default class FileAttachment extends React.Component {
+import {intlShape, injectIntl, defineMessages} from 'mm-intl';
+
+const holders = defineMessages({
+ download: {
+ id: 'file_attachment.download',
+ defaultMessage: 'Download'
+ }
+});
+
+class FileAttachment extends React.Component {
constructor(props) {
super(props);
@@ -266,7 +275,7 @@ export default class FileAttachment extends React.Component {
href={fileUrl}
download={filenameString}
data-toggle='tooltip'
- title={'Download \"' + filenameString + '\"'}
+ title={this.props.intl.formatMessage(holders.download) + ' \"' + filenameString + '\"'}
className='post-image__name'
>
{trimmedFilename}
@@ -291,6 +300,7 @@ export default class FileAttachment extends React.Component {
}
FileAttachment.propTypes = {
+ intl: intlShape.isRequired,
// a list of file pathes displayed by the parent FileAttachmentList
filename: React.PropTypes.string.isRequired,
@@ -301,3 +311,5 @@ FileAttachment.propTypes = {
// handler for when the thumbnail is clicked passed the index above
handleImageClick: React.PropTypes.func
};
+
+export default injectIntl(FileAttachment); \ No newline at end of file
diff --git a/web/react/components/file_info_preview.jsx b/web/react/components/file_info_preview.jsx
index 45d89007f..1dac140c9 100644
--- a/web/react/components/file_info_preview.jsx
+++ b/web/react/components/file_info_preview.jsx
@@ -3,15 +3,28 @@
import * as Utils from '../utils/utils.jsx';
-export default function FileInfoPreview({filename, fileUrl, fileInfo}) {
+import {defineMessages} from 'mm-intl';
+
+const holders = defineMessages({
+ type: {
+ id: 'file_info_preview.type',
+ defaultMessage: 'File type '
+ },
+ size: {
+ id: 'file_info_preview.size',
+ defaultMessage: 'Size '
+ }
+});
+
+export default function FileInfoPreview({filename, fileUrl, fileInfo, formatMessage}) {
// non-image files include a section providing details about the file
const infoParts = [];
if (fileInfo.extension !== '') {
- infoParts.push('File type ' + fileInfo.extension.toUpperCase());
+ infoParts.push(formatMessage(holders.type) + fileInfo.extension.toUpperCase());
}
- infoParts.push('Size ' + Utils.fileSizeToString(fileInfo.size));
+ infoParts.push(formatMessage(holders.size) + Utils.fileSizeToString(fileInfo.size));
const infoString = infoParts.join(', ');
diff --git a/web/react/components/login_username.jsx b/web/react/components/login_username.jsx
index f787490fa..4bd9254c6 100644
--- a/web/react/components/login_username.jsx
+++ b/web/react/components/login_username.jsx
@@ -89,9 +89,9 @@ export default class LoginUsername extends React.Component {
}
},
(err) => {
- if (err.message === 'api.user.login.not_verified.app_error') {
+ if (err.id === 'api.user.login.not_verified.app_error') {
state.serverError = formatMessage(holders.verifyEmailError);
- } else if (err.message === 'store.sql_user.get_by_username.app_error') {
+ } else if (err.id === 'store.sql_user.get_by_username.app_error') {
state.serverError = formatMessage(holders.userNotFoundError);
} else {
state.serverError = err.message;
diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx
index 7326a9ef8..8005678a2 100644
--- a/web/react/components/navbar.jsx
+++ b/web/react/components/navbar.jsx
@@ -24,6 +24,8 @@ import Constants from '../utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
+import {FormattedMessage} from 'mm-intl';
+
const Popover = ReactBootstrap.Popover;
const OverlayTrigger = ReactBootstrap.OverlayTrigger;
@@ -133,7 +135,10 @@ export default class Navbar extends React.Component {
dialogType={ChannelInfoModal}
dialogProps={{channel}}
>
- {'View Info'}
+ <FormattedMessage
+ id='navbar.viewInfo'
+ defaultMessage='View Info'
+ />
</ToggleModalButton>
</li>
);
@@ -145,7 +150,10 @@ export default class Navbar extends React.Component {
href='#'
onClick={this.showEditChannelHeaderModal}
>
- {'Set Channel Header...'}
+ <FormattedMessage
+ id='navbar.setHeader'
+ defaultMessage='Set Channel Header...'
+ />
</a>
</li>
);
@@ -159,7 +167,10 @@ export default class Navbar extends React.Component {
href='#'
onClick={() => this.setState({showEditChannelPurposeModal: true})}
>
- {'Set Channel Purpose...'}
+ <FormattedMessage
+ id='navbar.setPurpose'
+ defaultMessage='Set Channel Purpose...'
+ />
</a>
</li>
);
@@ -175,7 +186,10 @@ export default class Navbar extends React.Component {
dialogType={ChannelInviteModal}
dialogProps={{channel}}
>
- {'Add Members'}
+ <FormattedMessage
+ id='navbar.addMembers'
+ defaultMessage='Add Members'
+ />
</ToggleModalButton>
</li>
);
@@ -187,7 +201,10 @@ export default class Navbar extends React.Component {
href='#'
onClick={this.handleLeave}
>
- {'Leave Channel'}
+ <FormattedMessage
+ id='navbar.leave'
+ defaultMessage='Leave Channel'
+ />
</a>
</li>
);
@@ -205,7 +222,10 @@ export default class Navbar extends React.Component {
href='#'
onClick={() => this.setState({showMembersModal: true})}
>
- {'Manage Members'}
+ <FormattedMessage
+ id='navbar.manageMembers'
+ defaultMessage='Manage Members'
+ />
</a>
</li>
);
@@ -217,7 +237,10 @@ export default class Navbar extends React.Component {
dialogType={DeleteChannelModal}
dialogProps={{channel}}
>
- {'Delete Channel...'}
+ <FormattedMessage
+ id='navbar.delete'
+ defaultMessage='Delete Channel...'
+ />
</ToggleModalButton>
</li>
);
@@ -234,7 +257,10 @@ export default class Navbar extends React.Component {
data-name={channel.name}
data-channelid={channel.id}
>
- {'Rename Channel...'}
+ <FormattedMessage
+ id='navbar.rename'
+ defaultMessage='Rename Channel...'
+ />
</a>
</li>
);
@@ -249,7 +275,10 @@ export default class Navbar extends React.Component {
dialogType={ChannelNotificationsModal}
dialogProps={{channel}}
>
- {'Notification Preferences'}
+ <FormattedMessage
+ id='navbar.preferences'
+ defaultMessage='Notification Preferences'
+ />
</ToggleModalButton>
</li>
);
@@ -319,7 +348,12 @@ export default class Navbar extends React.Component {
data-toggle='collapse'
data-target='#navbar-collapse-1'
>
- <span className='sr-only'>{'Toggle sidebar'}</span>
+ <span className='sr-only'>
+ <FormattedMessage
+ id='navbar.toggle1'
+ defaultMessage='Toggle sidebar'
+ />
+ </span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
@@ -335,7 +369,12 @@ export default class Navbar extends React.Component {
data-target='#sidebar-nav'
onClick={this.toggleLeftSidebar}
>
- <span className='sr-only'>{'Toggle sidebar'}</span>
+ <span className='sr-only'>
+ <FormattedMessage
+ id='navbar.toggle2'
+ defaultMessage='Toggle sidebar'
+ />
+ </span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
@@ -405,6 +444,17 @@ export default class Navbar extends React.Component {
}
if (channel.header.length === 0) {
+ const link = (
+ <a
+ href='#'
+ onClick={this.showEditChannelHeaderModal}
+ >
+ <FormattedMessage
+ id='navbar.click'
+ defaultMessage='Click here'
+ />
+ </a>
+ );
popoverContent = (
<Popover
bsStyle='info'
@@ -412,15 +462,14 @@ export default class Navbar extends React.Component {
id='header-popover'
>
<div>
- {'No channel header yet.'}
- <br/>
- <a
- href='#'
- onClick={this.showEditChannelHeaderModal}
- >
- {'Click here'}
- </a>
- {' to add one.'}
+ <FormattedMessage
+ id='navbar.noHeader'
+ defaultMessage='No channel header yet.{newline}{link} to add one.'
+ values={{
+ newline: (<br/>),
+ link: (link)
+ }}
+ />
</div>
</Popover>
);
diff --git a/web/react/components/post_attachment.jsx b/web/react/components/post_attachment.jsx
index 676bc91af..2eedfb7c1 100644
--- a/web/react/components/post_attachment.jsx
+++ b/web/react/components/post_attachment.jsx
@@ -3,7 +3,20 @@
import * as TextFormatting from '../utils/text_formatting.jsx';
-export default class PostAttachment extends React.Component {
+import {intlShape, injectIntl, defineMessages} from 'mm-intl';
+
+const holders = defineMessages({
+ collapse: {
+ id: 'post_attachment.collapse',
+ defaultMessage: '▲ collapse text'
+ },
+ more: {
+ id: 'post_attachment.more',
+ defaultMessage: '▼ read more'
+ }
+});
+
+class PostAttachment extends React.Component {
constructor(props) {
super(props);
@@ -28,7 +41,7 @@ export default class PostAttachment extends React.Component {
getInitState() {
const shouldCollapse = this.shouldCollapse();
const text = TextFormatting.formatText(this.props.attachment.text || '');
- const uncollapsedText = text + (shouldCollapse ? '<a class="attachment-link-more" href="#">▲ collapse text</a>' : '');
+ const uncollapsedText = text + (shouldCollapse ? `<a class="attachment-link-more" href="#">${this.props.intl.formatMessage(holders.collapse)}</a>` : '');
const collapsedText = shouldCollapse ? this.getCollapsedText() : text;
return {
@@ -62,7 +75,7 @@ export default class PostAttachment extends React.Component {
text = text.substr(0, 700);
}
- return TextFormatting.formatText(text) + '<a class="attachment-link-more" href="#">▼ read more</a>';
+ return TextFormatting.formatText(text) + `<a class="attachment-link-more" href="#">${this.props.intl.formatMessage(holders.more)}</a>`;
}
getFieldsTable() {
@@ -292,5 +305,8 @@ export default class PostAttachment extends React.Component {
}
PostAttachment.propTypes = {
+ intl: intlShape.isRequired,
attachment: React.PropTypes.object.isRequired
};
+
+export default injectIntl(PostAttachment);
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index b1657f0eb..16f8528b2 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -14,7 +14,20 @@ import YoutubeVideo from './youtube_video.jsx';
import providers from './providers.json';
-export default class PostBody extends React.Component {
+import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
+
+const holders = defineMessages({
+ plusOne: {
+ id: 'post_body.plusOne',
+ defaultMessage: ' plus 1 other file'
+ },
+ plusMore: {
+ id: 'post_body.plusMore',
+ defaultMessage: ' plus {count} other files'
+ }
+});
+
+class PostBody extends React.Component {
constructor(props) {
super(props);
@@ -187,6 +200,7 @@ export default class PostBody extends React.Component {
}
render() {
+ const {formatMessage} = this.props.intl;
const post = this.props.post;
const filenames = this.props.post.filenames;
const parentPost = this.props.parentPost;
@@ -208,10 +222,12 @@ export default class PostBody extends React.Component {
username = parentPost.props.override_username;
}
- if (username.slice(-1) === 's') {
- apostrophe = '\'';
- } else {
- apostrophe = '\'s';
+ if (global.window.mm_locale === 'en') {
+ if (username.slice(-1) === 's') {
+ apostrophe = '\'';
+ } else {
+ apostrophe = '\'s';
+ }
}
name = (
<a
@@ -230,16 +246,23 @@ export default class PostBody extends React.Component {
message = parentPost.filenames[0].split('/').pop();
if (parentPost.filenames.length === 2) {
- message += ' plus 1 other file';
+ message += formatMessage(holders.plusOne);
} else if (parentPost.filenames.length > 2) {
- message += ` plus ${parentPost.filenames.length - 1} other files`;
+ message += formatMessage(holders.plusMore, {count: (parentPost.filenames.length - 1)});
}
}
comment = (
<div className='post__link'>
<span>
- {'Commented on '}{name}{apostrophe}{' message: '}
+ <FormattedMessage
+ id='post_body.commentedOn'
+ defaultMessage='Commented on {name}{apostrophe} message: '
+ values={{
+ name: (name),
+ apostrophe: apostrophe
+ }}
+ />
<a
className='theme'
onClick={this.props.handleCommentClick}
@@ -260,7 +283,10 @@ export default class PostBody extends React.Component {
href='#'
onClick={this.props.retryPost}
>
- {'Retry'}
+ <FormattedMessage
+ id='post_body.retry'
+ defaultMessage='Retry'
+ />
</a>
);
} else if (post.state === Constants.POST_LOADING) {
@@ -313,8 +339,11 @@ export default class PostBody extends React.Component {
}
PostBody.propTypes = {
+ intl: intlShape.isRequired,
post: React.PropTypes.object.isRequired,
parentPost: React.PropTypes.object,
retryPost: React.PropTypes.func.isRequired,
handleCommentClick: React.PropTypes.func.isRequired
};
+
+export default injectIntl(PostBody); \ No newline at end of file
diff --git a/web/react/components/post_focus_view.jsx b/web/react/components/post_focus_view.jsx
index adcd78839..b9b6acd5f 100644
--- a/web/react/components/post_focus_view.jsx
+++ b/web/react/components/post_focus_view.jsx
@@ -7,6 +7,8 @@ import PostStore from '../stores/post_store.jsx';
import ChannelStore from '../stores/channel_store.jsx';
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
+import {FormattedMessage} from 'mm-intl';
+
export default class PostFocusView extends React.Component {
constructor(props) {
super(props);
@@ -73,7 +75,12 @@ export default class PostFocusView extends React.Component {
getIntroMessage() {
return (
<div className='channel-intro'>
- <h4 className='channel-intro__title'>{'Beginning of Channel Archives'}</h4>
+ <h4 className='channel-intro__title'>
+ <FormattedMessage
+ id='post_focus_view.beginning'
+ defaultMessage='Beginning of Channel Archives'
+ />
+ </h4>
</div>
);
}
diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx
index 0fb9d7f4a..ddb393520 100644
--- a/web/react/components/post_info.jsx
+++ b/web/react/components/post_info.jsx
@@ -9,6 +9,8 @@ import * as EventHelpers from '../dispatcher/event_helpers.jsx';
import Constants from '../utils/constants.jsx';
+import {FormattedMessage} from 'mm-intl';
+
const Overlay = ReactBootstrap.Overlay;
const Popover = ReactBootstrap.Popover;
@@ -53,7 +55,10 @@ export default class PostInfo extends React.Component {
href='#'
onClick={this.props.handleCommentClick}
>
- {'Reply'}
+ <FormattedMessage
+ id='post_info.reply'
+ defaultMessage='Reply'
+ />
</a>
</li>
);
@@ -68,7 +73,10 @@ export default class PostInfo extends React.Component {
href='#'
onClick={(e) => this.setState({target: e.target, show: !this.state.show})}
>
- {'Permalink'}
+ <FormattedMessage
+ id='post_info.permalink'
+ defaultMessage='Permalink'
+ />
</a>
</li>
);
@@ -84,7 +92,10 @@ export default class PostInfo extends React.Component {
role='menuitem'
onClick={() => EventHelpers.showDeletePostModal(post, dataComments)}
>
- {'Delete'}
+ <FormattedMessage
+ id='post_info.del'
+ defaultMessage='Delete'
+ />
</a>
</li>
);
@@ -108,7 +119,10 @@ export default class PostInfo extends React.Component {
data-channelid={post.channel_id}
data-comments={dataComments}
>
- {'Edit'}
+ <FormattedMessage
+ id='post_info.edit'
+ defaultMessage='Edit'
+ />
</a>
</li>
);
@@ -183,7 +197,15 @@ export default class PostInfo extends React.Component {
var dropdown = this.createDropdown();
const permalink = TeamStore.getCurrentTeamUrl() + '/pl/' + post.id;
- const copyButtonText = this.state.copiedLink ? (<div>{'Copy '}<i className='fa fa-check'/></div>) : 'Copy';
+ const copyButtonText = this.state.copiedLink ? (
+ <div>
+ <FormattedMessage
+ id='post_info.copy'
+ defaultMessage='Copy '
+ />
+ <i className='fa fa-check'/></div>
+ ) : (<FormattedMessage id='post_info.copy' />);
+
const permalinkOverlay = (
<Popover
id='permalink-overlay'
diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx
index 856403af5..f108ace2e 100644
--- a/web/react/components/posts_view.jsx
+++ b/web/react/components/posts_view.jsx
@@ -8,6 +8,9 @@ import * as Utils from '../utils/utils.jsx';
import Post from './post.jsx';
import Constants from '../utils/constants.jsx';
import DelayedAction from '../utils/delayed_action.jsx';
+
+import {FormattedDate, FormattedMessage} from 'mm-intl';
+
const Preferences = Constants.Preferences;
export default class PostsView extends React.Component {
@@ -250,7 +253,15 @@ export default class PostsView extends React.Component {
className='date-separator'
>
<hr className='separator__hr' />
- <div className='separator__text'>{currentPostDay.toDateString()}</div>
+ <div className='separator__text'>
+ <FormattedDate
+ value={currentPostDay}
+ weekday='short'
+ month='short'
+ day='2-digit'
+ year='numeric'
+ />
+ </div>
</div>
);
}
@@ -276,7 +287,12 @@ export default class PostsView extends React.Component {
<hr
className='separator__hr'
/>
- <div className='separator__text'>{'New Messages'}</div>
+ <div className='separator__text'>
+ <FormattedMessage
+ id='posts_view.newMsg'
+ defaultMessage='New Messages'
+ />
+ </div>
</div>
);
}
@@ -420,7 +436,10 @@ export default class PostsView extends React.Component {
href='#'
onClick={this.loadMorePostsTop}
>
- {'Load more messages'}
+ <FormattedMessage
+ id='posts_view.loadMore'
+ defaultMessage='Load more messages'
+ />
</a>
);
} else {
@@ -436,7 +455,7 @@ export default class PostsView extends React.Component {
href='#'
onClick={this.loadMorePostsBottom}
>
- {'Load more messages'}
+ <FormattedMessage id='posts_view.loadMore' />
</a>
);
} else {
diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx
index 0b549b1e6..ba8dbffcc 100644
--- a/web/react/components/time_since.jsx
+++ b/web/react/components/time_since.jsx
@@ -2,7 +2,8 @@
// See License.txt for license information.
import Constants from '../utils/constants.jsx';
-import * as Utils from '../utils/utils.jsx';
+
+import {FormattedRelative, FormattedDate} from 'mm-intl';
var Tooltip = ReactBootstrap.Tooltip;
var OverlayTrigger = ReactBootstrap.OverlayTrigger;
@@ -20,20 +21,25 @@ export default class TimeSince extends React.Component {
clearInterval(this.intervalId);
}
render() {
- const displayDate = Utils.displayDate(this.props.eventTime);
- const displayTime = Utils.displayTime(this.props.eventTime);
-
if (this.props.sameUser) {
return (
<time className='post__time'>
- {Utils.displayTime(this.props.eventTime)}
+ <FormattedRelative value={this.props.eventTime} />
</time>
);
}
const tooltip = (
<Tooltip id={'time-since-tooltip-' + this.props.eventTime}>
- {displayDate + ' at ' + displayTime}
+ <FormattedDate
+ value={this.props.eventTime}
+ month='long'
+ day='numeric'
+ year='numeric'
+ hour12={true}
+ hour='numeric'
+ minute='2-digit'
+ />
</Tooltip>
);
@@ -44,7 +50,7 @@ export default class TimeSince extends React.Component {
overlay={tooltip}
>
<time className='post__time'>
- {Utils.displayDateTime(this.props.eventTime)}
+ <FormattedRelative value={this.props.eventTime} />
</time>
</OverlayTrigger>
);
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index d11f8a21c..90885e495 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -9,10 +9,20 @@ import Constants from '../utils/constants.jsx';
import FileInfoPreview from './file_info_preview.jsx';
import FileStore from '../stores/file_store.jsx';
import ViewImagePopoverBar from './view_image_popover_bar.jsx';
+
+import {intlShape, injectIntl, defineMessages} from 'mm-intl';
+
const Modal = ReactBootstrap.Modal;
const KeyCodes = Constants.KeyCodes;
-export default class ViewImageModal extends React.Component {
+const holders = defineMessages({
+ loading: {
+ id: 'view_image.loading',
+ defaultMessage: 'Loading '
+ }
+});
+
+class ViewImageModal extends React.Component {
constructor(props) {
super(props);
@@ -235,6 +245,7 @@ export default class ViewImageModal extends React.Component {
fileUrl={fileUrl}
fileInfo={this.state.fileInfo}
maxHeight={this.state.imgHeight}
+ formatMessage={this.props.intl.formatMessage}
/>
);
} else {
@@ -243,6 +254,7 @@ export default class ViewImageModal extends React.Component {
filename={filename}
fileUrl={fileUrl}
fileInfo={fileInfo}
+ formatMessage={this.props.intl.formatMessage}
/>
);
}
@@ -250,7 +262,12 @@ export default class ViewImageModal extends React.Component {
// display a progress indicator when the preview for an image is still loading
const progress = Math.floor(this.state.progress[this.state.imgId]);
- content = <LoadingImagePreview progress={progress} />;
+ content = (
+ <LoadingImagePreview
+ progress={progress}
+ loading={this.props.intl.formatMessage(holders.loading)}
+ />
+ );
}
let leftArrow = null;
@@ -335,6 +352,7 @@ ViewImageModal.defaultProps = {
startId: 0
};
ViewImageModal.propTypes = {
+ intl: intlShape.isRequired,
show: React.PropTypes.bool.isRequired,
onModalDismissed: React.PropTypes.func.isRequired,
filenames: React.PropTypes.array,
@@ -344,12 +362,12 @@ ViewImageModal.propTypes = {
startId: React.PropTypes.number
};
-function LoadingImagePreview({progress}) {
+function LoadingImagePreview({progress, loading}) {
let progressView = null;
if (progress) {
progressView = (
<span className='loader-percent'>
- {'Loading ' + progress + '%'}
+ {loading + progress + '%'}
</span>
);
}
@@ -386,3 +404,5 @@ function ImagePreview({filename, fileUrl, fileInfo, maxHeight}) {
</a>
);
}
+
+export default injectIntl(ViewImageModal); \ No newline at end of file
diff --git a/web/react/components/view_image_popover_bar.jsx b/web/react/components/view_image_popover_bar.jsx
index 1287f4fba..97671b845 100644
--- a/web/react/components/view_image_popover_bar.jsx
+++ b/web/react/components/view_image_popover_bar.jsx
@@ -1,6 +1,8 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+import {FormattedMessage} from 'mm-intl';
+
export default class ViewImagePopoverBar extends React.Component {
constructor(props) {
super(props);
@@ -16,7 +18,10 @@ export default class ViewImagePopoverBar extends React.Component {
data-title='Public Image'
onClick={this.props.getPublicLink}
>
- {'Get Public Link'}
+ <FormattedMessage
+ id='view_image_popover.publicLink'
+ defaultMessage='Get Public Link'
+ />
</a>
<span className='text'>{' | '}</span>
</div>
@@ -33,7 +38,16 @@ export default class ViewImagePopoverBar extends React.Component {
ref='imageFooter'
className={footerClass}
>
- <span className='pull-left text'>{'File ' + (this.props.fileId + 1) + ' of ' + this.props.totalFiles}</span>
+ <span className='pull-left text'>
+ <FormattedMessage
+ id='view_image_popover.file'
+ defaultMessage='File {count} of {total}'
+ values={{
+ count: (this.props.fileId + 1),
+ total: this.props.totalFiles
+ }}
+ />
+ </span>
<div className='image-links'>
{publicLink}
<a
@@ -41,7 +55,10 @@ export default class ViewImagePopoverBar extends React.Component {
download={this.props.filename}
className='text'
>
- {'Download'}
+ <FormattedMessage
+ id='view_image_popover.download'
+ defaultMessage='Download'
+ />
</a>
</div>
</div>