From 3f91bc2df2c6f9d8437f258233609e9801b7f8f6 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Mon, 1 Feb 2016 17:23:45 -0300 Subject: PLT-7: Refactoring frontend (chunk 9) - sidebar right & rhs --- web/react/components/create_comment.jsx | 52 ++++++++++++++++---- web/react/components/file_upload.jsx | 32 ++++++++++-- web/react/components/file_upload_overlay.jsx | 9 +++- web/react/components/msg_typing.jsx | 42 +++++++++++++--- web/react/components/rhs_comment.jsx | 41 +++++++++++++--- web/react/components/rhs_header_post.jsx | 11 ++++- web/react/components/rhs_root_post.jsx | 29 +++++++++-- web/react/components/search_bar.jsx | 39 ++++++++++----- web/react/components/search_results.jsx | 32 +++++++----- web/react/components/search_results_header.jsx | 17 ++++++- web/react/components/search_results_item.jsx | 24 +++++++-- web/react/components/sidebar_right_menu.jsx | 68 ++++++++++++++++++++++---- web/react/components/textbox.jsx | 20 +++++++- web/react/components/user_profile.jsx | 8 ++- web/static/i18n/en.json | 44 +++++++++++++++++ web/static/i18n/es.json | 47 +++++++++++++++++- 16 files changed, 440 insertions(+), 75 deletions(-) (limited to 'web') diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index aa7ab6a7b..1b552838a 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -16,10 +16,32 @@ import FilePreview from './file_preview.jsx'; import * as Utils from '../utils/utils.jsx'; import Constants from '../utils/constants.jsx'; + +import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; + const ActionTypes = Constants.ActionTypes; const KeyCodes = Constants.KeyCodes; -export default class CreateComment extends React.Component { +const holders = defineMessages({ + commentLength: { + id: 'create_comment.commentLength', + defaultMessage: 'Comment length must be less than {max} characters.' + }, + comment: { + id: 'create_comment.comment', + defaultMessage: 'Add Comment' + }, + addComment: { + id: 'create_comment.addComment', + defaultMessage: 'Add a comment...' + }, + commentTitle: { + id: 'create_comment.commentTitle', + defaultMessage: 'Comment' + } +}); + +class CreateComment extends React.Component { constructor(props) { super(props); @@ -93,7 +115,7 @@ export default class CreateComment extends React.Component { } if (post.message.length > Constants.CHARACTER_LIMIT) { - this.setState({postError: `Comment length must be less than ${Constants.CHARACTER_LIMIT} characters.`}); + this.setState({postError: this.props.intl.formatMessage(holders.commentLength, {max: Constants.CHARACTER_LIMIT})}); return; } @@ -189,7 +211,7 @@ export default class CreateComment extends React.Component { AppDispatcher.handleViewAction({ type: ActionTypes.RECIEVED_EDIT_POST, refocusId: '#reply_textbox', - title: 'Comment', + title: this.props.intl.formatMessage(holders.commentTitle), message: lastPost.message, postId: lastPost.id, channelId: lastPost.channel_id, @@ -305,14 +327,23 @@ export default class CreateComment extends React.Component { let uploadsInProgressText = null; if (this.state.uploadsInProgress.length > 0) { uploadsInProgressText = ( - - {this.state.uploadsInProgress.length === 1 ? 'File uploading' : 'Files uploading'} + + {this.state.uploadsInProgress.length === 1 ? ( + + ) : ( + + )} ); } + const {formatMessage} = this.props.intl; return (
@@ -326,7 +357,7 @@ export default class CreateComment extends React.Component { onKeyPress={this.commentMsgKeyPress} onKeyDown={this.handleKeyDown} messageText={this.state.messageText} - createMessage='Add a comment...' + createMessage={formatMessage(holders.addComment)} initialText='' supportsCommands={false} id='reply_textbox' @@ -351,7 +382,7 @@ export default class CreateComment extends React.Component { {uploadsInProgressText} @@ -366,6 +397,9 @@ export default class CreateComment extends React.Component { } CreateComment.propTypes = { + intl: intlShape.isRequired, channelId: React.PropTypes.string.isRequired, rootId: React.PropTypes.string.isRequired }; + +export default injectIntl(CreateComment); \ No newline at end of file diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 7e6cc2942..2f9146193 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -6,7 +6,24 @@ import Constants from '../utils/constants.jsx'; import ChannelStore from '../stores/channel_store.jsx'; import * as Utils from '../utils/utils.jsx'; -export default class FileUpload extends React.Component { +import {intlShape, injectIntl, defineMessages} from 'mm-intl'; + +const holders = defineMessages({ + limited: { + id: 'file_upload.limited', + defaultMessage: 'Uploads limited to {count} files maximum. Please use additional posts for more files.' + }, + filesAbove: { + id: 'file_upload.filesAbove', + defaultMessage: 'Files above {max}MB could not be uploaded: {filenames}' + }, + fileAbove: { + id: 'file_upload.fileAbove', + defaultMessage: 'File above {max}MB could not be uploaded: {filename}' + } +}); + +class FileUpload extends React.Component { constructor(props) { super(props); @@ -74,14 +91,15 @@ export default class FileUpload extends React.Component { numUploads += 1; } + const {formatMessage} = this.props.intl; if (files.length > uploadsRemaining) { - this.props.onUploadError(`Uploads limited to ${Constants.MAX_UPLOAD_FILES} files maximum. Please use additional posts for more files.`); + this.props.onUploadError(formatMessage(holders.limited, {count: Constants.MAX_UPLOAD_FILES})); } else if (tooLargeFiles.length > 1) { var tooLargeFilenames = tooLargeFiles.map((file) => file.name).join(', '); - this.props.onUploadError(`Files above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFilenames}`); + this.props.onUploadError(formatMessage(holders.filesAbove, {max: (Constants.MAX_FILE_SIZE / 1000000), files: tooLargeFilenames})); } else if (tooLargeFiles.length > 0) { - this.props.onUploadError(`File above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFiles[0].name}`); + this.props.onUploadError(formatMessage(holders.fileAbove, {max: (Constants.MAX_FILE_SIZE / 1000000), file: tooLargeFiles[0].name})); } } @@ -106,6 +124,7 @@ export default class FileUpload extends React.Component { componentDidMount() { var inputDiv = ReactDOM.findDOMNode(this.refs.input); var self = this; + const {formatMessage} = this.props.intl; if (this.props.postType === 'post') { $('.row.main').dragster({ @@ -184,7 +203,7 @@ export default class FileUpload extends React.Component { var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - self.props.getFileCount(ChannelStore.getCurrentId()), numItems); if (numItems > numToUpload) { - self.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.'); + self.props.onUploadError(formatMessage(holders.limited, {count: Constants.MAX_UPLOAD_FILES})); } for (var i = 0; i < items.length && i < numToUpload; i++) { @@ -296,6 +315,7 @@ export default class FileUpload extends React.Component { } FileUpload.propTypes = { + intl: intlShape.isRequired, onUploadError: React.PropTypes.func, getFileCount: React.PropTypes.func, onFileUpload: React.PropTypes.func, @@ -304,3 +324,5 @@ FileUpload.propTypes = { channelId: React.PropTypes.string, postType: React.PropTypes.string }; + +export default injectIntl(FileUpload); \ No newline at end of file diff --git a/web/react/components/file_upload_overlay.jsx b/web/react/components/file_upload_overlay.jsx index dbba00022..497d5aee2 100644 --- a/web/react/components/file_upload_overlay.jsx +++ b/web/react/components/file_upload_overlay.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 FileUploadOverlay extends React.Component { render() { var overlayClass = 'file-overlay hidden'; @@ -19,7 +21,12 @@ export default class FileUploadOverlay extends React.Component { src='/static/images/filesOverlay.png' alt='Files' /> - {'Drop a file to upload it.'} + + + + ); break; default: { const last = users.pop(); - text = users.join(', ') + ' and ' + last + ' are typing...'; + text = ( + + ); break; } } @@ -100,6 +127,9 @@ export default class MsgTyping extends React.Component { } MsgTyping.propTypes = { + intl: intlShape.isRequired, channelId: React.PropTypes.string, parentId: React.PropTypes.string }; + +export default injectIntl(MsgTyping); \ No newline at end of file diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index 7aae5177e..1dd8354d7 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -16,7 +16,16 @@ import * as TextFormatting from '../utils/text_formatting.jsx'; import twemoji from 'twemoji'; import * as EventHelpers from '../dispatcher/event_helpers.jsx'; -export default class RhsComment extends React.Component { +import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedDate} from 'mm-intl'; + +const holders = defineMessages({ + comment: { + id: 'rhs_comment.comment', + defaultMessage: 'Comment' + } +}); + +class RhsComment extends React.Component { constructor(props) { super(props); @@ -95,12 +104,15 @@ export default class RhsComment extends React.Component { data-toggle='modal' data-target='#edit_post' data-refocusid='#reply_textbox' - data-title='Comment' + data-title={this.props.intl.formatMessage(holders.comment)} data-message={post.message} data-postid={post.id} data-channelid={post.channel_id} > - {'Edit'} + ); @@ -117,7 +129,10 @@ export default class RhsComment extends React.Component { role='menuitem' onClick={() => EventHelpers.showDeletePostModal(post, 0)} > - {'Delete'} + ); @@ -165,7 +180,10 @@ export default class RhsComment extends React.Component { href='#' onClick={this.retryComment} > - {'Retry'} + ); } else if (post.state === Constants.POST_LOADING) { @@ -208,7 +226,15 @@ export default class RhsComment extends React.Component {
  • @@ -237,5 +263,8 @@ RhsComment.defaultProps = { post: null }; RhsComment.propTypes = { + intl: intlShape.isRequired, post: React.PropTypes.object }; + +export default injectIntl(RhsComment); \ No newline at end of file diff --git a/web/react/components/rhs_header_post.jsx b/web/react/components/rhs_header_post.jsx index 990b33eb5..d56ba76f8 100644 --- a/web/react/components/rhs_header_post.jsx +++ b/web/react/components/rhs_header_post.jsx @@ -3,6 +3,9 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import Constants from '../utils/constants.jsx'; + +import {FormattedMessage} from 'mm-intl'; + const ActionTypes = Constants.ActionTypes; export default class RhsHeaderPost extends React.Component { @@ -58,7 +61,13 @@ export default class RhsHeaderPost extends React.Component { return (
    - {back}Message Details + + {back} + +
  • ); @@ -110,7 +120,10 @@ export default class RhsRootPost extends React.Component { role='menuitem' onClick={() => EventHelpers.showDeletePostModal(post, this.props.commentCount)} > - {'Delete'} + ); @@ -205,7 +218,15 @@ export default class RhsRootPost extends React.Component { {botIndicator}
  • diff --git a/web/react/components/search_bar.jsx b/web/react/components/search_bar.jsx index 77c9e39b9..35d7e9514 100644 --- a/web/react/components/search_bar.jsx +++ b/web/react/components/search_bar.jsx @@ -11,10 +11,20 @@ import SearchSuggestionList from './suggestion/search_suggestion_list.jsx'; import SearchUserProvider from './suggestion/search_user_provider.jsx'; import * as utils from '../utils/utils.jsx'; import Constants from '../utils/constants.jsx'; + +import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + var ActionTypes = Constants.ActionTypes; var Popover = ReactBootstrap.Popover; -export default class SearchBar extends React.Component { +const holders = defineMessages({ + search: { + id: 'search_bar.search', + defaultMessage: 'Search' + } +}); + +class SearchBar extends React.Component { constructor() { super(); this.mounted = false; @@ -147,7 +157,10 @@ export default class SearchBar extends React.Component { className='search__clear' onClick={this.clearFocus} > - {'Cancel'} + -

    {'Search Options'}

    -
      -
    • - {'Use '}{'"quotation marks"'}{' to search for phrases'} -
    • -
    • - {'Use '}{'from:'}{' to find posts from specific users and '}{'in:'}{' to find posts in specific channels'} -
    • -
    +
  • ); } } + +SearchBar.propTypes = { + intl: intlShape.isRequired +}; + +export default injectIntl(SearchBar); + diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 141181701..9dcc99061 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -8,6 +8,8 @@ import * as Utils from '../utils/utils.jsx'; import SearchResultsHeader from './search_results_header.jsx'; import SearchResultsItem from './search_results_item.jsx'; +import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + function getStateFromStores() { return {results: SearchStore.getSearchResults()}; } @@ -83,25 +85,29 @@ export default class SearchResults extends React.Component { if (!searchTerm && noResults) { ctls = (
    -
      -
    • - {'Use '}{'"quotation marks"'}{' to search for phrases'} -
    • -
    • - {'Use '}{'from:'}{' to find posts from specific users and '}{'in:'}{' to find posts in specific channels'} -
    • -
    +
    ); } else if (noResults) { ctls = (
    -

    {'NO RESULTS'}

    -
      -
    • {'If you\'re searching a partial phrase (ex. searching "rea", looking for "reach" or "reaction"), append a * to your search term'}
    • -
    • {'Due to the volume of results, two letter searches and common words like "this", "a" and "is" won\'t appear in search results'}
    • -
    +

    + +

    +
    ); } else { diff --git a/web/react/components/search_results_header.jsx b/web/react/components/search_results_header.jsx index 581976494..45f56f65a 100644 --- a/web/react/components/search_results_header.jsx +++ b/web/react/components/search_results_header.jsx @@ -3,6 +3,9 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import Constants from '../utils/constants.jsx'; + +import {FormattedMessage} from 'mm-intl'; + var ActionTypes = Constants.ActionTypes; export default class SearchResultsHeader extends React.Component { @@ -34,10 +37,20 @@ export default class SearchResultsHeader extends React.Component { } render() { - var title = 'Search Results'; + var title = ( + + ); if (this.props.isMentionSearch) { - title = 'Recent Mentions'; + title = ( + + ); } return ( diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index e4f83eb1c..a0b252d25 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -10,6 +10,8 @@ import * as TextFormatting from '../utils/text_formatting.jsx'; import Constants from '../utils/constants.jsx'; +import {FormattedMessage, FormattedDate} from 'mm-intl'; + export default class SearchResultsItem extends React.Component { constructor(props) { super(props); @@ -42,7 +44,12 @@ export default class SearchResultsItem extends React.Component { if (channel) { channelName = channel.display_name; if (channel.type === 'D') { - channelName = 'Direct Message'; + channelName = ( + + ); } } @@ -69,7 +76,15 @@ export default class SearchResultsItem extends React.Component {
  • @@ -78,7 +93,10 @@ export default class SearchResultsItem extends React.Component { className='search-item__jump' onClick={this.handleClick} > - {'Jump'} +
  • diff --git a/web/react/components/sidebar_right_menu.jsx b/web/react/components/sidebar_right_menu.jsx index 20c2bf696..4d714e9f1 100644 --- a/web/react/components/sidebar_right_menu.jsx +++ b/web/react/components/sidebar_right_menu.jsx @@ -9,6 +9,8 @@ import * as client from '../utils/client.jsx'; import * as EventHelpers from '../dispatcher/event_helpers.jsx'; import * as utils from '../utils/utils.jsx'; +import {FormattedMessage} from 'mm-intl'; + export default class SidebarRightMenu extends React.Component { componentDidMount() { $('.sidebar--left .dropdown-menu').perfectScrollbar(); @@ -49,7 +51,11 @@ export default class SidebarRightMenu extends React.Component { href='#' onClick={EventHelpers.showInviteMemberModal} > - {'Invite New Member'} + +
  • ); @@ -61,7 +67,11 @@ export default class SidebarRightMenu extends React.Component { href='#' onClick={EventHelpers.showGetTeamInviteLinkModal} > - {'Get Team Invite Link'} + + ); @@ -75,13 +85,23 @@ export default class SidebarRightMenu extends React.Component { href='#' data-toggle='modal' data-target='#team_settings' - >{'Team Settings'} + > + + + ); manageLink = (
  • - {'Manage Members'} + +
  • ); @@ -93,7 +113,12 @@ export default class SidebarRightMenu extends React.Component { - {'System Console'} + + + ); } @@ -114,7 +139,14 @@ export default class SidebarRightMenu extends React.Component { {'Help'} + > + + + + ); } @@ -125,7 +157,14 @@ export default class SidebarRightMenu extends React.Component { {'Report a Problem'} + > + + + + ); } return ( @@ -144,7 +183,11 @@ export default class SidebarRightMenu extends React.Component { href='#' onClick={() => this.setState({showUserSettingsModal: true})} > - {'Account Settings'} + + {teamSettingsLink} @@ -156,7 +199,14 @@ export default class SidebarRightMenu extends React.Component { {'Logout'} + > + + + +
  • {helpLink} {reportLink} diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx index 62c0d5218..bb383aca1 100644 --- a/web/react/components/textbox.jsx +++ b/web/react/components/textbox.jsx @@ -11,6 +11,9 @@ import ErrorStore from '../stores/error_store.jsx'; import * as TextFormatting from '../utils/text_formatting.jsx'; import * as Utils from '../utils/utils.jsx'; import Constants from '../utils/constants.jsx'; + +import {FormattedMessage} from 'mm-intl'; + const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES; export default class Textbox extends React.Component { @@ -143,7 +146,17 @@ export default class Textbox extends React.Component { onClick={this.showPreview} className='textbox-preview-link' > - {this.state.preview ? 'Edit message' : 'Preview'} + {this.state.preview ? ( + + ) : ( + + )} ); } @@ -184,7 +197,10 @@ export default class Textbox extends React.Component { onClick={this.showHelp} className='textbox-help-link' > - {'Help'} + ); diff --git a/web/react/components/user_profile.jsx b/web/react/components/user_profile.jsx index 385cd0f52..1e393cfe9 100644 --- a/web/react/components/user_profile.jsx +++ b/web/react/components/user_profile.jsx @@ -3,6 +3,9 @@ import * as Utils from '../utils/utils.jsx'; import UserStore from '../stores/user_store.jsx'; + +import {FormattedMessage} from 'mm-intl'; + var Popover = ReactBootstrap.Popover; var OverlayTrigger = ReactBootstrap.OverlayTrigger; @@ -87,7 +90,10 @@ export default class UserProfile extends React.Component { className='text-nowrap' key='user-popover-no-email' > - {'Email not shared'} + ); } else { diff --git a/web/static/i18n/en.json b/web/static/i18n/en.json index 62608b85a..78e4c625d 100644 --- a/web/static/i18n/en.json +++ b/web/static/i18n/en.json @@ -496,6 +496,12 @@ "claim.sso_to_email_newPwd": "Enter a new password for your {team} {site} account", "claim.sso_to_email.switchTo": "Switch {type} to email and password", "confirm_modal.cancel": "Cancel", + "create_comment.commentLength": "Comment length must be less than {max} characters.", + "create_comment.comment": "Add Comment", + "create_comment.addComment": "Add a comment...", + "create_comment.commentTitle": "Comment", + "create_comment.file": "File uploading", + "create_comment.files": "Files uploading", "email_verify.verified": "{siteName} Email Verified", "email_verify.verifiedBody": "

    Your email has been verified! Click here to log in.

    ", "email_verify.almost": "{siteName}: You are almost done", @@ -503,6 +509,10 @@ "email_verify.resend": "Resend Email", "email_verify.sent": " Verification email sent.", "error_bar.preview_mode": "Preview Mode: Email notifications have not been configured", + "upload_overlay.info": "Drop a file to upload it.", + "file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.", + "file_upload.filesAbove": "Files above {max}MB could not be uploaded: {filenames}", + "file_upload.fileAbove": "File above {max}MB could not be uploaded: {filename}", "find_team.submitError": "Please enter a valid email address", "find_team.placeholder": "you@domain.com", "find_team.findTitle": "Find Your Team", @@ -579,6 +589,9 @@ "more_direct_channels.countTotal": "{count} {member} of {total} Total", "more_direct_channels.title": "Direct Messages", "more_direct_channels.close": "Close", + "msg_typing.someone": "Someone", + "msg_typing.isTyping": "{user} is typing...", + "msg_typing.areTyping": "{users} and {last} are typing...", "navbar_dropdown.inviteMember": "Invite New Member", "navbar_dropdown.teamLink": "Get Team Invite Link", "navbar_dropdown.manageMembers": "Manage Members", @@ -648,6 +661,24 @@ "register_app.credentialsSave": "I have saved both my Client Id and Client Secret somewhere safe", "register_app.close": "Close", "register_app.dev": "Developer Applications", + "rhs_comment.comment": "Comment", + "rhs_comment.edit": "Edit", + "rhs_comment.del": "Delete", + "rhs_comment.retry": "Retry", + "rhs_header.details": "Message Details", + "rhs_root.direct": "Direct Message", + "rhs_root.edit": "Edit", + "rhs_root.del": "Delete", + "search_bar.search": "Search", + "search_bar.cancel": "Cancel", + "search_bar.usage": "

    Search Options

    • Use \"quotation marks\" to search for phrases
    • Use from: to find posts from specific users and in: to find posts in specific channels
    ", + "search_header.results": "Search Results", + "search_header.title2": "Recent Mentions", + "search_item.direct": "Direct Message", + "search_item.jump": "Jump", + "search_results.usage": "
    • Use \"quotation marks\" to search for phrases
    • Use from: to find posts from specific users and in: to find posts in specific channels
    ", + "search_results.noResults": "NO RESULTS", + "search_results.because": "
      \n
    • If you're searching a partial phrase (ex. searching \"rea\", looking for \"reach\" or \"reaction\"), append a * to your search term
    • \n
    • Due to the volume of results, two letter searches and common words like \"this\", \"a\" and \"is\" won't appear in search results
    • \n
    ", "setting_item_max.save": "Save", "setting_item_max.cancel": "Cancel", "setting_item_min.edit": "Edit", @@ -659,6 +690,15 @@ "setting_upload.select": "Select file", "setting_upload.import": "Import", "sidebar_header.tutorial": "

    Main Menu

    \n

    The Main Menu is where you can Invite New Members, access your Account Settings and set your Theme Color.

    \n

    Team administrators can also access their Team Settings from this menu.

    System administrators will find a System Console option to administrate the entire system.

    ", + "sidebar_right_menu.inviteNew": "Invite New Member", + "sidebar_right_menu.teamLink": "Get Team Invite Link", + "sidebar_right_menu.teamSettings": "Team Settings", + "sidebar_right_menu.manageMembers": "Manage Members", + "sidebar_right_menu.console": "System Console", + "sidebar_right_menu.help": "Help", + "sidebar_right_menu.report": "Report a Problem", + "sidebar_right_menu.accountSettings": "Account Settings", + "sidebar_right_menu.logout": "Logout", "sidebar.tutorialScreen1": "

    Channels

    Channels organize conversations across different topics. They’re open to everyone on your team. To send private communications use Direct Messages for a single person or Private Groups for multiple people.

    ", "sidebar.tutorialScreen2": "

    \"Town Square\" and \"Off-Topic\" channels

    \n

    Here are two public channels to start:

    \n

    Town Square is a place for team-wide communication. Everyone in your team is a member of this channel.

    \n

    Off-Topic is a place for fun and humor outside of work-related channels. You and your team can decide what other channels to create.

    ", "sidebar.tutorialScreen3": "

    Creating and Joining Channels

    \n

    Click \"More...\" to create a new channel or join an existing one.

    \n

    You can also create a new channel or private group by clicking the \"+\" symbol next to the channel or private group header.

    ", @@ -809,6 +849,9 @@ "sso_signup.gitlab": "Create team with GitLab Account", "sso_signup.google": "Create team with Google Apps Account", "sso_signup.find": "Find my teams", + "textbox.edit": "Edit message", + "textbox.preview": "Preview", + "textbox.help": "Help", "tutorial_intro.screenOne": "

    Welcome to:

    \n

    Mattermost

    \n

    Your team communication all in one place, instantly searchable and available anywhere

    \n

    Keep your team connected to help them achieve what matters most.

    ", "tutorial_intro.screenTwo": "

    How Mattermost works:

    \n

    Communication happens in public discussion channels, private groups and direct messages.

    \n

    Everything is archived and searchable from any web-enabled desktop, laptop or phone.

    ", "tutorial_intro.invite": "Invite teammates", @@ -823,6 +866,7 @@ "tutorial_tip.next": "Next", "tutorial_tip.seen": "Seen this before? ", "tutorial_tip.out": "Opt out of these tips.", + "user_profile.notShared": "Email not shared", "user.settings.custom_theme.sidebarBg": "Sidebar BG", "user.settings.custom_theme.sidebarText": "Sidebar Text", "user.settings.custom_theme.sidebarHeaderBg": "Sidebar Header BG", diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json index ee24df1b3..6b5eee94a 100644 --- a/web/static/i18n/es.json +++ b/web/static/i18n/es.json @@ -525,6 +525,12 @@ "claim.sso_to_email.title": "Cambiar la cuenta de {type} a Correo Electrónico", "claim.sso_to_email_newPwd": "Ingresa una nueva contraseña para tu cuenta de {team} {site}", "confirm_modal.cancel": "Cancelar", + "create_comment.addComment": "Agregar un comentario...", + "create_comment.comment": "Agregar Comentario", + "create_comment.commentLength": "El largo del Comentario debe ser menor de {max} caracteres.", + "create_comment.commentTitle": "Comentario", + "create_comment.file": "Subiendo archivo", + "create_comment.files": "Subiendo archivos", "email_signup.address": "Correo electrónico", "email_signup.createTeam": "Crear Equipo", "email_signup.emailError": "Por favor ingresa una dirección de correos válida", @@ -536,6 +542,10 @@ "email_verify.verified": "{siteName} Correo electrónico verificado", "email_verify.verifiedBody": "

    Tu correo electrónico ha sido verificado!! Pincha aquí para iniciar sesión.

    ", "error_bar.preview_mode": "Modo de prueba: Las notificaciones por correo electrónico no han sido configuradas", + "file_upload.fileAbove": "No se puede subir un archivo que pesa más de {max}MB: {filename}", + "file_upload.filesAbove": "No se pueden subir archivos de más de {max}MB: {filenames}", + "file_upload.limited": "Se pueden subir un máximo de {count} archivos. Por favor envía otros mensajes para adjuntar más archivos.", + "file_upload.pasted": "Imagen Pegada en ", "find_team.email": "Correo electrónico", "find_team.findDescription": "Enviamos un correo electrónico con los equipos a los que perteneces.", "find_team.findTitle": "Encuentra tu equipo", @@ -631,6 +641,9 @@ "more_direct_channels.notFound": "No se encontraron usuarios :(", "more_direct_channels.search": "Buscar miembros", "more_direct_channels.title": "Mensajes Directos", + "msg_typing.areTyping": "{users} y {last} están escribiendo...", + "msg_typing.isTyping": "{user} está escribiendo...", + "msg_typing.someone": "Alguien", "navbar_dropdown.about": "Acerca de Mattermost", "navbar_dropdown.accountSettings": "Configurar Cuenta", "navbar_dropdown.console": "Consola de Sistema", @@ -676,6 +689,24 @@ "register_app.register": "Registrar", "register_app.required": "Requerido", "register_app.title": "Registra una Nueva Aplicación", + "rhs_comment.comment": "Comentario", + "rhs_comment.del": "Borrar", + "rhs_comment.edit": "Editar", + "rhs_comment.retry": "Reintentar", + "rhs_header.details": "Detalles del Mensaje", + "rhs_root.del": "Borrar", + "rhs_root.direct": "Mensaje Directo", + "rhs_root.edit": "Editar", + "search_bar.cancel": "Cancelar", + "search_bar.search": "Buscar", + "search_bar.usage": "

    Opciones de Búsqueda

    • Utiliza \"comillas\" para buscar frases
    • Utiliza from: para encontrar mensajes de usuarios en específico e in: para encontrar mensajes de canales específicos
    ", + "search_header.results": "Resultados de la Búsqueda", + "search_header.title2": "Menciones Recientes", + "search_item.direct": "Mensjae Directo", + "search_item.jump": "Ir ", + "search_results.because": "
    • Si estás buscando un frase parcial (ej. buscando \"aud\", tratando de encontrar \"audible\" o \"audifonos\"), agrega un * a la palabra que estás buscando
    • Debido a la cantidad de resultados, la búsqueda con dos letras y palabras comunes como \"this\", \"a\" and \"es\" no aparecerán en los resultados
    • /ul>", + "search_results.noResults": "SIN RESULTADOS", + "search_results.usage": "
      • Utiliza \"comillas\" para buscar frases
      • Utiliza from: para encontrar mensajes de usuarios en específico e in: para encontrar mensajes de canales específicos
      ", "setting_item_max.cancel": "Cancelar", "setting_item_max.save": "Guardar", "setting_item_min.edit": "Editar", @@ -700,6 +731,15 @@ "sidebar.unreadAbove": "Mensaje(s) sin leer arriba", "sidebar.unreadBelow": "Mensaje(s) sin leer abajo", "sidebar_header.tutorial": "

      Menú Principal

      El Menú Principal es donde puedes Invitar a nuevos miembros, podrás Configurar tu Cuenta y seleccionar un Tema para personalizar la apariencia.

      Los administradores del Equipo podrán Configurar el Equipo desde este menú.

      Los administradores del Sistema encontrarán una opción para ir a la Consola de Sistema para administrar el sistema completo.

      ", + "sidebar_right_menu.accountSettings": "Configurar tu Cuenta", + "sidebar_right_menu.console": "Consola del Sistema", + "sidebar_right_menu.help": "Ayuda", + "sidebar_right_menu.inviteNew": "Invitar Nuevo Miembro", + "sidebar_right_menu.logout": "Cerrar sesión", + "sidebar_right_menu.manageMembers": "Adminisrar Miembros", + "sidebar_right_menu.report": "Reporta un Problema", + "sidebar_right_menu.teamLink": "Enlace Invitación al Equipo", + "sidebar_right_menu.teamSettings": "Configurar Equipo", "signup_team.choose": "Selecciona un Equipo", "signup_team.createTeam": "O Crea un Equipo", "signup_team.disabled": "La creación de Equipos ha sido deshabilitada.", @@ -810,6 +850,9 @@ "team_signup_welcome.validEmailError": "Por favor ingresa una dirección de correo electrónico válida", "team_signup_welcome.welcome": "Bienvenido a:", "team_signup_welcome.yes": "Sí, esta dirección es correcta", + "textbox.edit": "Editar mensaje", + "textbox.help": "Ayuda", + "textbox.preview": "Previsualizar", "tutorial_intro.allSet": "Ya estás listo para comenzar", "tutorial_intro.end": "Pincha “Siguiente” para entrar al Canal General. Este es el primer canal que ven tus compañeros cuando ingresan. Utilizalo para mandar mensajes que todos deben leer.", "tutorial_intro.invite": "Invitar compañeros", @@ -824,6 +867,7 @@ "tutorial_tip.ok": "Aceptar", "tutorial_tip.out": "No optar por estos consejos.", "tutorial_tip.seen": "¿Haz visto esto antes? ", + "upload_overlay.info": "Arrastra un archivo para subirlo.", "user.settings.advance.embed_preview": "Mostrar la previsualización de enlaces", "user.settings.advance.enabled": "habilitada(s)", "user.settings.advance.feature": " Característica ", @@ -999,5 +1043,6 @@ "user.settings.security.switchGitlab": "Cambiar para utilizar GitLab SSO", "user.settings.security.switchGoogle": "Cambiar para utilizar Google SSO", "user.settings.security.title": "Configuración de Seguridad", - "user.settings.security.viewHistory": "Visualizar historial de acceso" + "user.settings.security.viewHistory": "Visualizar historial de acceso", + "user_profile.notShared": "Correo no compartido" } \ No newline at end of file -- cgit v1.2.3-1-g7c22 From e7f409a3c7a92d50cf857b808b61f4d5aadea8c3 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Mon, 1 Feb 2016 17:52:43 -0300 Subject: fix hour12 React warning for FormattedDate --- web/react/components/file_upload.jsx | 6 +++++- web/react/components/rhs_comment.jsx | 2 +- web/react/components/rhs_root_post.jsx | 2 +- web/react/components/search_results_item.jsx | 2 +- web/static/i18n/en.json | 1 + web/static/i18n/es.json | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) (limited to 'web') diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 2f9146193..626dbc5b3 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -20,6 +20,10 @@ const holders = defineMessages({ fileAbove: { id: 'file_upload.fileAbove', defaultMessage: 'File above {max}MB could not be uploaded: {filename}' + }, + pasted: { + id: 'file_upload.pasted', + defaultMessage: 'Image Pasted at ' } }); @@ -237,7 +241,7 @@ class FileUpload extends React.Component { min = String(d.getMinutes()); } - var name = 'Image Pasted at ' + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext; + var name = formatMessage(holders.pasted) + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext; formData.append('files', file, name); formData.append('client_ids', clientId); diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index 1dd8354d7..1addebbe4 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -231,7 +231,7 @@ class RhsComment extends React.Component { day='numeric' month='long' year='numeric' - hour12='true' + hour12={true} hour='2-digit' minute='2-digit' /> diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index bc772aaa5..f9f7f8f81 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -223,7 +223,7 @@ export default class RhsRootPost extends React.Component { day='numeric' month='long' year='numeric' - hour12='true' + hour12={true} hour='2-digit' minute='2-digit' /> diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index a0b252d25..0ad091d5b 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -81,7 +81,7 @@ export default class SearchResultsItem extends React.Component { day='numeric' month='long' year='numeric' - hour12='true' + hour12={true} hour='2-digit' minute='2-digit' /> diff --git a/web/static/i18n/en.json b/web/static/i18n/en.json index 78e4c625d..d6401ab6e 100644 --- a/web/static/i18n/en.json +++ b/web/static/i18n/en.json @@ -513,6 +513,7 @@ "file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.", "file_upload.filesAbove": "Files above {max}MB could not be uploaded: {filenames}", "file_upload.fileAbove": "File above {max}MB could not be uploaded: {filename}", + "file_upload.pasted": "Image Pasted at ", "find_team.submitError": "Please enter a valid email address", "find_team.placeholder": "you@domain.com", "find_team.findTitle": "Find Your Team", diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json index 6b5eee94a..cb3e8a199 100644 --- a/web/static/i18n/es.json +++ b/web/static/i18n/es.json @@ -545,7 +545,7 @@ "file_upload.fileAbove": "No se puede subir un archivo que pesa más de {max}MB: {filename}", "file_upload.filesAbove": "No se pueden subir archivos de más de {max}MB: {filenames}", "file_upload.limited": "Se pueden subir un máximo de {count} archivos. Por favor envía otros mensajes para adjuntar más archivos.", - "file_upload.pasted": "Imagen Pegada en ", + "file_upload.pasted": "Imagen Pegada el ", "find_team.email": "Correo electrónico", "find_team.findDescription": "Enviamos un correo electrónico con los equipos a los que perteneces.", "find_team.findTitle": "Encuentra tu equipo", -- cgit v1.2.3-1-g7c22