Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/electron_settings

This commit is contained in:
Michael Telatynski 2017-05-29 21:56:45 +01:00
commit a2229ced11
91 changed files with 5619 additions and 777 deletions

View file

@ -16,15 +16,16 @@ limitations under the License.
'use strict';
var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");
var PresetValues = {
import React from 'react';
import q from 'q';
import { _t } from '../../languageHandler';
import sdk from '../../index';
import MatrixClientPeg from '../../MatrixClientPeg';
const PresetValues = {
PrivateChat: "private_chat",
PublicChat: "public_chat",
Custom: "custom",
};
var q = require('q');
var sdk = require('../../index');
module.exports = React.createClass({
displayName: 'CreateRoom',
@ -231,7 +232,7 @@ module.exports = React.createClass({
if (curr_phase == this.phases.ERROR) {
error_box = (
<div className="mx_Error">
An error occured: {this.state.error_string}
{_t('An error occured: %(error_string)s', {error_string: this.state.error_string})}
</div>
);
}
@ -248,27 +249,27 @@ module.exports = React.createClass({
<div className="mx_CreateRoom">
<SimpleRoomHeader title="CreateRoom" collapsedRhs={ this.props.collapsedRhs }/>
<div className="mx_CreateRoom_body">
<input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder="Name"/> <br />
<textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder="Topic"/> <br />
<input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder={_t('Name')}/> <br />
<textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder={_t('Topic')}/> <br />
<RoomAlias ref="alias" alias={this.state.alias} homeserver={ domain } onChange={this.onAliasChanged}/> <br />
<UserSelector ref="user_selector" selected_users={this.state.invited_users} onChange={this.onInviteChanged}/> <br />
<Presets ref="presets" onChange={this.onPresetChanged} preset={this.state.preset}/> <br />
<div>
<label>
<input type="checkbox" ref="is_private" checked={this.state.is_private} onChange={this.onPrivateChanged}/>
Make this room private
{_t('Make this room private')}
</label>
</div>
<div>
<label>
<input type="checkbox" ref="share_history" checked={this.state.share_history} onChange={this.onShareHistoryChanged}/>
Share message history with new users
{_t('Share message history with new users')}
</label>
</div>
<div className="mx_CreateRoom_encrypt">
<label>
<input type="checkbox" ref="encrypt" checked={this.state.encrypt} onChange={this.onEncryptChanged}/>
Encrypt room
{_t('Encrypt room')}
</label>
</div>
<div>

View file

@ -14,13 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
var ReactDOM = require("react-dom");
import React from 'react';
var Matrix = require("matrix-js-sdk");
var sdk = require('../../index');
var MatrixClientPeg = require("../../MatrixClientPeg");
var dis = require("../../dispatcher");
import Matrix from 'matrix-js-sdk';
import sdk from '../../index';
import MatrixClientPeg from '../../MatrixClientPeg';
import { _t } from '../../languageHandler';
/*
* Component which shows the filtered file using a TimelinePanel
@ -116,7 +115,7 @@ var FilePanel = React.createClass({
showUrlPreview = { false }
tileShape="file_grid"
opacity={ this.props.opacity }
empty="There are no visible files in this room"
empty={_t('There are no visible files in this room')}
/>
);
}

View file

@ -183,7 +183,7 @@ export default React.createClass({
ConferenceHandler={this.props.ConferenceHandler}
scrollStateMap={this._scrollStateMap}
/>;
if (!this.props.collapse_rhs) right_panel = <RightPanel roomId={this.props.currentRoomId} opacity={this.props.sideOpacity} />;
if (!this.props.collapse_rhs) right_panel = <RightPanel roomId={this.props.currentRoomId} opacity={this.props.rightOpacity} />;
break;
case PageTypes.UserSettings:
@ -195,7 +195,7 @@ export default React.createClass({
referralBaseUrl={this.props.config.referralBaseUrl}
teamToken={this.props.teamToken}
/>;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/>;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>;
break;
case PageTypes.CreateRoom:
@ -203,7 +203,7 @@ export default React.createClass({
onRoomCreated={this.props.onRoomCreated}
collapsedRhs={this.props.collapse_rhs}
/>;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/>;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>;
break;
case PageTypes.RoomDirectory:
@ -219,12 +219,12 @@ export default React.createClass({
teamServerUrl={this.props.config.teamServerConfig.teamServerURL}
teamToken={this.props.teamToken}
/>
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/>
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>
break;
case PageTypes.UserView:
page_element = null; // deliberately null for now
right_panel = <RightPanel userId={this.props.viewUserId} opacity={this.props.sideOpacity} />;
right_panel = <RightPanel userId={this.props.viewUserId} opacity={this.props.rightOpacity} />;
break;
}
@ -253,7 +253,7 @@ export default React.createClass({
<LeftPanel
selectedRoom={this.props.currentRoomId}
collapsed={this.props.collapse_lhs || false}
opacity={this.props.sideOpacity}
opacity={this.props.leftOpacity}
teamToken={this.props.teamToken}
/>
<main className='mx_MatrixChat_middlePanel'>

View file

@ -36,6 +36,7 @@ import PageTypes from '../../PageTypes';
import createRoom from "../../createRoom";
import * as UDEHandler from '../../UnknownDeviceErrorHandler';
import { _t } from '../../languageHandler';
module.exports = React.createClass({
displayName: 'MatrixChat',
@ -116,8 +117,9 @@ module.exports = React.createClass({
collapse_rhs: false,
ready: false,
width: 10000,
sideOpacity: 1.0,
leftOpacity: 1.0,
middleOpacity: 1.0,
rightOpacity: 1.0,
version: null,
newVersion: null,
@ -246,7 +248,6 @@ module.exports = React.createClass({
UDEHandler.startListening();
this.focusComposer = false;
window.addEventListener("focus", this.onFocus);
// this can technically be done anywhere but doing this here keeps all
// the routing url path logic together.
@ -375,8 +376,8 @@ module.exports = React.createClass({
break;
case 'reject_invite':
Modal.createDialog(QuestionDialog, {
title: "Reject invitation",
description: "Are you sure you want to reject the invitation?",
title: _t('Reject invitation'),
description: _t('Are you sure you want to reject the invitation?'),
onFinished: (confirm) => {
if (confirm) {
// FIXME: controller shouldn't be loading a view :(
@ -391,7 +392,7 @@ module.exports = React.createClass({
}, (err) => {
modal.close();
Modal.createDialog(ErrorDialog, {
title: "Failed to reject invitation",
title: _t('Failed to reject invitation'),
description: err.toString(),
});
});
@ -437,11 +438,11 @@ module.exports = React.createClass({
//this._setPage(PageTypes.CreateRoom);
//this.notifyNewScreen('new');
Modal.createDialog(TextInputDialog, {
title: "Create Room",
description: "Room name (optional)",
button: "Create Room",
onFinished: (shouldCreate, name) => {
if (shouldCreate) {
title: _t('Create Room'),
description: _t('Room name (optional)'),
button: _t('Create Room'),
onFinished: (should_create, name) => {
if (should_create) {
const createOpts = {};
if (name) createOpts.name = name;
createRoom({createOpts}).done();
@ -490,12 +491,14 @@ module.exports = React.createClass({
collapse_rhs: false,
});
break;
case 'ui_opacity':
case 'ui_opacity': {
const sideDefault = payload.sideOpacity >= 0.0 ? payload.sideOpacity : 1.0;
this.setState({
sideOpacity: payload.sideOpacity,
middleOpacity: payload.middleOpacity,
leftOpacity: payload.leftOpacity >= 0.0 ? payload.leftOpacity : sideDefault,
middleOpacity: payload.middleOpacity || 1.0,
rightOpacity: payload.rightOpacity >= 0.0 ? payload.rightOpacity : sideDefault,
});
break;
break; }
case 'set_theme':
this._onSetTheme(payload.value);
break;
@ -653,16 +656,20 @@ module.exports = React.createClass({
_createChat: function() {
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
Modal.createDialog(ChatInviteDialog, {
title: "Start a new chat",
title: _t('Start a chat'),
description: _t("Who would you like to communicate with?"),
placeholder: _t("Email, name or matrix ID"),
button: _t("Start Chat")
});
},
_invite: function(roomId) {
const ChatInviteDialog = sdk.getComponent("dialogs.ChatInviteDialog");
Modal.createDialog(ChatInviteDialog, {
title: "Invite new room members",
button: "Send Invites",
description: "Who would you like to add to this room?",
title: _t('Invite new room members'),
description: _t('Who would you like to add to this room?'),
button: _t('Send Invites'),
placeholder: _t("Email, name or matrix ID"),
roomId: roomId,
});
},
@ -886,8 +893,8 @@ module.exports = React.createClass({
cli.on('Session.logged_out', function(call) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Signed Out",
description: "For security, this session has been signed out. Please sign in again.",
title: _t('Signed Out'),
description: _t('For security, this session has been signed out. Please sign in again.'),
});
dis.dispatch({
action: 'logout',
@ -905,10 +912,6 @@ module.exports = React.createClass({
});
},
onFocus: function(ev) {
dis.dispatch({action: 'focus_composer'});
},
showScreen: function(screen, params) {
if (screen == 'register') {
dis.dispatch({
@ -1199,7 +1202,7 @@ module.exports = React.createClass({
<div className="mx_MatrixChat_splash">
<Spinner />
<a href="#" className="mx_MatrixChat_splashButtons" onClick={ this.onLogoutClick }>
Logout
{ _t('Logout') }
</a>
</div>
);

View file

@ -84,6 +84,12 @@ module.exports = React.createClass({
// shape parameter to be passed to EventTiles
tileShape: React.PropTypes.string,
// show twelve hour timestamps
isTwelveHour: React.PropTypes.bool,
// show timestamps always
alwaysShowTimestamps: React.PropTypes.bool,
},
componentWillMount: function() {
@ -230,8 +236,8 @@ module.exports = React.createClass({
},
_getEventTiles: function() {
var EventTile = sdk.getComponent('rooms.EventTile');
var DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventTile = sdk.getComponent('rooms.EventTile');
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
this.eventNodes = {};
@ -413,8 +419,8 @@ module.exports = React.createClass({
},
_getTilesForEvent: function(prevEvent, mxEv, last) {
var EventTile = sdk.getComponent('rooms.EventTile');
var DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventTile = sdk.getComponent('rooms.EventTile');
const DateSeparator = sdk.getComponent('messages.DateSeparator');
var ret = [];
// is this a continuation of the previous message?
@ -468,7 +474,6 @@ module.exports = React.createClass({
if (this.props.manageReadReceipts) {
readReceipts = this._getReadReceiptsForEvent(mxEv);
}
ret.push(
<li key={eventId}
ref={this._collectEventNode.bind(this, eventId)}
@ -482,6 +487,7 @@ module.exports = React.createClass({
checkUnmounting={this._isUnmounting}
eventSendStatus={mxEv.status}
tileShape={this.props.tileShape}
isTwelveHour={this.props.isTwelveHour}
last={last} isSelectedEvent={highlight}/>
</li>
);
@ -615,8 +621,13 @@ module.exports = React.createClass({
var style = this.props.hidden ? { display: 'none' } : {};
style.opacity = this.props.opacity;
var className = this.props.className + " mx_fadable";
if (this.props.alwaysShowTimestamps) {
className += " mx_MessagePanel_alwaysShowTimestamps";
}
return (
<ScrollPanel ref="scrollPanel" className={ this.props.className + " mx_fadable" }
<ScrollPanel ref="scrollPanel" className={ className }
onScroll={ this.props.onScroll }
onResize={ this.onResize }
onFillRequest={ this.props.onFillRequest }

View file

@ -16,7 +16,7 @@ limitations under the License.
var React = require('react');
var ReactDOM = require("react-dom");
import { _t } from '../../languageHandler';
var Matrix = require("matrix-js-sdk");
var sdk = require('../../index');
var MatrixClientPeg = require("../../MatrixClientPeg");
@ -37,7 +37,6 @@ var NotificationPanel = React.createClass({
var Loader = sdk.getComponent("elements.Spinner");
var timelineSet = MatrixClientPeg.get().getNotifTimelineSet();
if (timelineSet) {
return (
<TimelinePanel key={"NotificationPanel_" + this.props.roomId}
@ -48,7 +47,7 @@ var NotificationPanel = React.createClass({
showUrlPreview = { false }
opacity={ this.props.opacity }
tileShape="notif"
empty="You have no visible notifications"
empty={ _t('You have no visible notifications') }
/>
);
}

View file

@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
var sdk = require('../../index');
var dis = require("../../dispatcher");
var WhoIsTyping = require("../../WhoIsTyping");
var MatrixClientPeg = require("../../MatrixClientPeg");
const MemberAvatar = require("../views/avatars/MemberAvatar");
import React from 'react';
import { _t } from '../../languageHandler';
import sdk from '../../index';
import dis from '../../dispatcher';
import WhoIsTyping from '../../WhoIsTyping';
import MatrixClientPeg from '../../MatrixClientPeg';
import MemberAvatar from '../views/avatars/MemberAvatar';
const HIDE_DEBOUNCE_MS = 10000;
const STATUS_BAR_HIDDEN = 0;
@ -175,8 +176,8 @@ module.exports = React.createClass({
<div className="mx_RoomStatusBar_scrollDownIndicator"
onClick={ this.props.onScrollToBottomClick }>
<img src="img/scrolldown.svg" width="24" height="24"
alt="Scroll to bottom of page"
title="Scroll to bottom of page"/>
alt={ _t("Scroll to bottom of page") }
title={ _t("Scroll to bottom of page") }/>
</div>
);
}
@ -250,10 +251,10 @@ module.exports = React.createClass({
<div className="mx_RoomStatusBar_connectionLostBar">
<img src="img/warning.svg" width="24" height="23" title="/!\ " alt="/!\ "/>
<div className="mx_RoomStatusBar_connectionLostBar_title">
Connectivity to the server has been lost.
{_t('Connectivity to the server has been lost.')}
</div>
<div className="mx_RoomStatusBar_connectionLostBar_desc">
Sent messages will be stored until your connection has returned.
{_t('Sent messages will be stored until your connection has returned.')}
</div>
</div>
);
@ -266,7 +267,7 @@ module.exports = React.createClass({
<TabCompleteBar tabComplete={this.props.tabComplete} />
<div className="mx_RoomStatusBar_tabCompleteEol" title="->|">
<TintableSvg src="img/eol.svg" width="22" height="16"/>
Auto-complete
{_t('Auto-complete')}
</div>
</div>
</div>
@ -283,13 +284,12 @@ module.exports = React.createClass({
<div className="mx_RoomStatusBar_connectionLostBar_desc">
<a className="mx_RoomStatusBar_resend_link"
onClick={ this.props.onResendAllClick }>
Resend all
</a> or <a
{_t('Resend all')}
</a> {_t('or')} <a
className="mx_RoomStatusBar_resend_link"
onClick={ this.props.onCancelAllClick }>
cancel all
</a> now. You can also select individual messages to
resend or cancel.
{_t('cancel all')}
</a> {_t('now. You can also select individual messages to resend or cancel.')}
</div>
</div>
);
@ -324,7 +324,7 @@ module.exports = React.createClass({
if (this.props.hasActiveCall) {
return (
<div className="mx_RoomStatusBar_callBar">
<b>Active call</b>
<b>{_t('Active call')}</b>
</div>
);
}

View file

@ -25,6 +25,7 @@ var ReactDOM = require("react-dom");
var q = require("q");
var classNames = require("classnames");
var Matrix = require("matrix-js-sdk");
import { _t } from '../../languageHandler';
var UserSettingsStore = require('../../UserSettingsStore');
var MatrixClientPeg = require("../../MatrixClientPeg");
@ -124,6 +125,8 @@ module.exports = React.createClass({
room: null,
roomId: null,
roomLoading: true,
forwardingEvent: null,
editingRoomSettings: false,
uploadingRoomSettings: false,
numUnreadMessages: 0,
@ -296,7 +299,7 @@ module.exports = React.createClass({
componentWillReceiveProps: function(newProps) {
if (newProps.roomAddress != this.props.roomAddress) {
throw new Error("changing room on a RoomView is not supported");
throw new Error(_t("changing room on a RoomView is not supported"));
}
if (newProps.eventId != this.props.eventId) {
@ -370,10 +373,10 @@ module.exports = React.createClass({
onPageUnload(event) {
if (ContentMessages.getCurrentUploads().length > 0) {
return event.returnValue =
'You seem to be uploading files, are you sure you want to quit?';
_t("You seem to be uploading files, are you sure you want to quit?");
} else if (this._getCallForRoom() && this.state.callState !== 'ended') {
return event.returnValue =
'You seem to be in a call, are you sure you want to quit?';
_t("You seem to be in a call, are you sure you want to quit?");
}
},
@ -451,6 +454,11 @@ module.exports = React.createClass({
callState: callState
});
break;
case 'forward_event':
this.setState({
forwardingEvent: payload.content,
});
break;
}
},
@ -530,14 +538,14 @@ module.exports = React.createClass({
if (!userHasUsedEncryption) {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Warning!",
title: _t("Warning!"),
hasCancelButton: false,
description: (
<div>
<p>End-to-end encryption is in beta and may not be reliable.</p>
<p>You should <b>not</b> yet trust it to secure data.</p>
<p>Devices will <b>not</b> yet be able to decrypt history from before they joined the room.</p>
<p>Encrypted messages will not be visible on clients that do not yet implement encryption.</p>
<p>{ _t("End-to-end encryption is in beta and may not be reliable") }.</p>
<p>{ _t("You should not yet trust it to secure data") }.</p>
<p>{ _t("Devices will not yet be able to decrypt history from before they joined the room") }.</p>
<p>{ _t("Encrypted messages will not be visible on clients that do not yet implement encryption") }.</p>
</div>
),
});
@ -708,10 +716,10 @@ module.exports = React.createClass({
if (!unsentMessages.length) return "";
for (const event of unsentMessages) {
if (!event.error || event.error.name !== "UnknownDeviceError") {
return "Some of your messages have not been sent.";
return _t("Some of your messages have not been sent") + ".";
}
}
return "Message not sent due to unknown devices being present";
return _t("Message not sent due to unknown devices being present");
},
_getUnsentMessages: function(room) {
@ -871,15 +879,15 @@ module.exports = React.createClass({
) {
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: "Failed to join the room",
description: "This room is private or inaccessible to guests. You may be able to join if you register."
title: _t("Failed to join the room"),
description: _t("This room is private or inaccessible to guests. You may be able to join if you register") + "."
});
} else {
var msg = error.message ? error.message : JSON.stringify(error);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to join room",
description: msg
title: _t("Failed to join room"),
description: msg,
});
}
}).done();
@ -939,8 +947,8 @@ module.exports = React.createClass({
if (MatrixClientPeg.get().isGuest()) {
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: "Please Register",
description: "Guest users can't upload files. Please register to upload."
title: _t("Please Register"),
description: _t("Guest users can't upload files. Please register to upload") + "."
});
return;
}
@ -959,8 +967,8 @@ module.exports = React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to upload file " + file + " " + error);
Modal.createDialog(ErrorDialog, {
title: "Failed to upload file",
description: ((error && error.message) ? error.message : "Server may be unavailable, overloaded, or the file too big"),
title: _t('Failed to upload file'),
description: ((error && error.message) ? error.message : _t("Server may be unavailable, overloaded, or the file too big")),
});
});
},
@ -1046,8 +1054,8 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Search failed: " + error);
Modal.createDialog(ErrorDialog, {
title: "Search failed",
description: ((error && error.message) ? error.message : "Server may be unavailable, overloaded, or search timed out :("),
title: _t("Search failed"),
description: ((error && error.message) ? error.message : _t("Server may be unavailable, overloaded, or search timed out :(")),
});
}).finally(function() {
self.setState({
@ -1082,12 +1090,12 @@ module.exports = React.createClass({
if (!this.state.searchResults.next_batch) {
if (this.state.searchResults.results.length == 0) {
ret.push(<li key="search-top-marker">
<h2 className="mx_RoomView_topMarker">No results</h2>
<h2 className="mx_RoomView_topMarker">{ _t("No results") }</h2>
</li>
);
} else {
ret.push(<li key="search-top-marker">
<h2 className="mx_RoomView_topMarker">No more results</h2>
<h2 className="mx_RoomView_topMarker">{ _t("No more results") }</h2>
</li>
);
}
@ -1124,10 +1132,10 @@ module.exports = React.createClass({
// it. We should tell the js sdk to go and find out about
// it. But that's not an issue currently, as synapse only
// returns results for rooms we're joined to.
var roomName = room ? room.name : "Unknown room "+roomId;
var roomName = room ? room.name : _t("Unknown room %(roomId)s", { roomId: roomId });
ret.push(<li key={mxEv.getId() + "-room"}>
<h1>Room: { roomName }</h1>
<h1>{ _t("Room") }: { roomName }</h1>
</li>);
lastRoomId = roomId;
}
@ -1173,7 +1181,7 @@ module.exports = React.createClass({
});
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to save settings",
title: _t("Failed to save settings"),
description: fails.map(function(result) { return result.reason; }).join("\n"),
});
// still editing room settings
@ -1194,7 +1202,10 @@ module.exports = React.createClass({
onCancelClick: function() {
console.log("updateTint from onCancelClick");
this.updateTint();
this.setState({editingRoomSettings: false});
this.setState({
editingRoomSettings: false,
forwardingEvent: null,
});
dis.dispatch({action: 'focus_composer'});
},
@ -1209,11 +1220,11 @@ module.exports = React.createClass({
MatrixClientPeg.get().forget(this.state.room.roomId).done(function() {
dis.dispatch({ action: 'view_next_room' });
}, function(err) {
var errCode = err.errcode || "unknown error code";
var errCode = err.errcode || _t("unknown error code");
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Error",
description: `Failed to forget room (${errCode})`
title: _t("Error"),
description: _t("Failed to forget room %(errCode)s", { errCode: errCode }),
});
});
},
@ -1234,8 +1245,8 @@ module.exports = React.createClass({
var msg = error.message ? error.message : JSON.stringify(error);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to reject invite",
description: msg
title: _t("Failed to reject invite"),
description: msg,
});
self.setState({
@ -1472,16 +1483,17 @@ module.exports = React.createClass({
},
render: function() {
var RoomHeader = sdk.getComponent('rooms.RoomHeader');
var MessageComposer = sdk.getComponent('rooms.MessageComposer');
var RoomSettings = sdk.getComponent("rooms.RoomSettings");
var AuxPanel = sdk.getComponent("rooms.AuxPanel");
var SearchBar = sdk.getComponent("rooms.SearchBar");
var ScrollPanel = sdk.getComponent("structures.ScrollPanel");
var TintableSvg = sdk.getComponent("elements.TintableSvg");
var RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
var Loader = sdk.getComponent("elements.Spinner");
var TimelinePanel = sdk.getComponent("structures.TimelinePanel");
const RoomHeader = sdk.getComponent('rooms.RoomHeader');
const MessageComposer = sdk.getComponent('rooms.MessageComposer');
const ForwardMessage = sdk.getComponent("rooms.ForwardMessage");
const RoomSettings = sdk.getComponent("rooms.RoomSettings");
const AuxPanel = sdk.getComponent("rooms.AuxPanel");
const SearchBar = sdk.getComponent("rooms.SearchBar");
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
const Loader = sdk.getComponent("elements.Spinner");
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
if (!this.state.room) {
if (this.state.roomLoading) {
@ -1609,17 +1621,16 @@ module.exports = React.createClass({
/>;
}
var aux = null;
if (this.state.editingRoomSettings) {
let aux = null;
if (this.state.forwardingEvent !== null) {
aux = <ForwardMessage onCancelClick={this.onCancelClick} currentRoomId={this.state.room.roomId} mxEvent={this.state.forwardingEvent} />;
} else if (this.state.editingRoomSettings) {
aux = <RoomSettings ref="room_settings" onSaveClick={this.onSettingsSaveClick} onCancelClick={this.onCancelClick} room={this.state.room} />;
}
else if (this.state.uploadingRoomSettings) {
} else if (this.state.uploadingRoomSettings) {
aux = <Loader/>;
}
else if (this.state.searching) {
} else if (this.state.searching) {
aux = <SearchBar ref="search_bar" searchInProgress={this.state.searchInProgress } onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch}/>;
}
else if (!myMember || myMember.membership !== "join") {
} else if (!myMember || myMember.membership !== "join") {
// We do have a room object for this room, but we're not currently in it.
// We may have a 3rd party invite to it.
var inviterName = undefined;
@ -1681,7 +1692,7 @@ module.exports = React.createClass({
if (call.type === "video") {
zoomButton = (
<div className="mx_RoomView_voipButton" onClick={this.onFullscreenClick} title="Fill screen">
<div className="mx_RoomView_voipButton" onClick={this.onFullscreenClick} title={ _t("Fill screen") }>
<TintableSvg src="img/fullscreen.svg" width="29" height="22" style={{ marginTop: 1, marginRight: 4 }}/>
</div>
);
@ -1689,14 +1700,14 @@ module.exports = React.createClass({
videoMuteButton =
<div className="mx_RoomView_voipButton" onClick={this.onMuteVideoClick}>
<TintableSvg src={call.isLocalVideoMuted() ? "img/video-unmute.svg" : "img/video-mute.svg"}
alt={call.isLocalVideoMuted() ? "Click to unmute video" : "Click to mute video"}
alt={call.isLocalVideoMuted() ? _t("Click to unmute video") : _t("Click to mute video")}
width="31" height="27"/>
</div>;
}
voiceMuteButton =
<div className="mx_RoomView_voipButton" onClick={this.onMuteAudioClick}>
<TintableSvg src={call.isMicrophoneMuted() ? "img/voice-unmute.svg" : "img/voice-mute.svg"}
alt={call.isMicrophoneMuted() ? "Click to unmute audio" : "Click to mute audio"}
alt={call.isMicrophoneMuted() ? _t("Click to unmute audio") : _t("Click to mute audio")}
width="21" height="26"/>
</div>;
@ -1732,14 +1743,13 @@ module.exports = React.createClass({
}
// console.log("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview);
var messagePanel = (
<TimelinePanel ref={this._gatherTimelinePanelRef}
timelineSet={this.state.room.getUnfilteredTimelineSet()}
manageReadReceipts={!UserSettingsStore.getSyncedSetting('hideReadReceipts', false)}
manageReadMarkers={true}
hidden={hideMessagePanel}
highlightedEventId={this.props.highlightedEventId}
highlightedEventId={this.state.forwardingEvent ? this.state.forwardingEvent.getId() : this.props.highlightedEventId}
eventId={this.props.eventId}
eventPixelOffset={this.props.eventPixelOffset}
onScroll={ this.onMessageListScroll }
@ -1777,7 +1787,7 @@ module.exports = React.createClass({
onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick}
onSaveClick={this.onSettingsSaveClick}
onCancelClick={this.onCancelClick}
onCancelClick={aux ? this.onCancelClick : null}
onForgetClick={
(myMember && myMember.membership === "leave") ? this.onForgetClick : null
}

View file

@ -23,12 +23,14 @@ var Matrix = require("matrix-js-sdk");
var EventTimeline = Matrix.EventTimeline;
var sdk = require('../../index');
import { _t } from '../../languageHandler';
var MatrixClientPeg = require("../../MatrixClientPeg");
var dis = require("../../dispatcher");
var ObjectUtils = require('../../ObjectUtils');
var Modal = require("../../Modal");
var UserActivity = require("../../UserActivity");
var KeyCode = require('../../KeyCode');
import UserSettingsStore from '../../UserSettingsStore';
var PAGINATE_SIZE = 20;
var INITIAL_SIZE = 20;
@ -122,7 +124,7 @@ var TimelinePanel = React.createClass({
let initialReadMarker = null;
if (this.props.manageReadMarkers) {
const readmarker = this.props.timelineSet.room.getAccountData('m.fully_read');
if (readmarker){
if (readmarker) {
initialReadMarker = readmarker.getContent().event_id;
} else {
initialReadMarker = this._getCurrentReadReceipt();
@ -171,6 +173,12 @@ var TimelinePanel = React.createClass({
// cache of matrixClient.getSyncState() (but from the 'sync' event)
clientSyncState: MatrixClientPeg.get().getSyncState(),
// should the event tiles have twelve hour times
isTwelveHour: UserSettingsStore.getSyncedSetting('showTwelveHourTimestamps'),
// always show timestamps on event tiles?
alwaysShowTimestamps: UserSettingsStore.getSyncedSetting('alwaysShowTimestamps'),
};
},
@ -907,14 +915,11 @@ var TimelinePanel = React.createClass({
});
};
}
var message = "Tried to load a specific point in this room's timeline, but ";
if (error.errcode == 'M_FORBIDDEN') {
message += "you do not have permission to view the message in question.";
} else {
message += "was unable to find it.";
}
var message = (error.errcode == 'M_FORBIDDEN')
? _t("Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question") + "."
: _t("Tried to load a specific point in this room's timeline, but was unable to find it") + ".";
Modal.createDialog(ErrorDialog, {
title: "Failed to load timeline position",
title: _t("Failed to load timeline position"),
description: message,
onFinished: onFinished,
});
@ -1106,7 +1111,6 @@ var TimelinePanel = React.createClass({
const forwardPaginating = (
this.state.forwardPaginating || this.state.clientSyncState == 'PREPARED'
);
return (
<MessagePanel ref="messagePanel"
hidden={ this.props.hidden }
@ -1125,6 +1129,8 @@ var TimelinePanel = React.createClass({
onFillRequest={ this.onMessageListFillRequest }
onUnfillRequest={ this.onMessageListUnfillRequest }
opacity={ this.props.opacity }
isTwelveHour={ this.state.isTwelveHour }
alwaysShowTimestamps={ this.state.alwaysShowTimestamps }
className={ this.props.className }
tileShape={ this.props.tileShape }
/>

View file

@ -29,6 +29,8 @@ const Email = require('../../email');
const AddThreepid = require('../../AddThreepid');
const SdkConfig = require('../../SdkConfig');
import AccessibleButton from '../views/elements/AccessibleButton';
import { _t } from '../../languageHandler';
import * as languageHandler from '../../languageHandler';
import * as FormattingUtils from '../../utils/FormattingUtils';
// if this looks like a release, use the 'version' from package.json; else use
@ -53,6 +55,8 @@ const gHVersionLabel = function(repo, token='') {
// Enumerate some simple 'flip a bit' UI settings (if any).
// 'id' gives the key name in the im.vector.web.settings account data event
// 'label' is how we describe it in the UI.
// Warning: Each "label" string below must be added to i18n/strings/en_EN.json,
// since they will be translated when rendered.
const SETTINGS_LABELS = [
{
id: 'autoplayGifsAndVideos',
@ -66,7 +70,6 @@ const SETTINGS_LABELS = [
id: 'dontSendTypingNotifications',
label: "Don't send typing notifications",
},
/*
{
id: 'alwaysShowTimestamps',
label: 'Always show message timestamps',
@ -75,6 +78,7 @@ const SETTINGS_LABELS = [
id: 'showTwelveHourTimestamps',
label: 'Show timestamps in 12 hour format (e.g. 2:30pm)',
},
/*
{
id: 'useCompactLayout',
label: 'Use compact timeline layout',
@ -86,6 +90,8 @@ const SETTINGS_LABELS = [
*/
];
// Warning: Each "label" string below must be added to i18n/strings/en_EN.json,
// since they will be translated when rendered.
const CRYPTO_SETTINGS_LABELS = [
{
id: 'blacklistUnverifiedDevices',
@ -119,7 +125,6 @@ const THEMES = [
},
];
module.exports = React.createClass({
displayName: 'UserSettings',
@ -205,6 +210,10 @@ module.exports = React.createClass({
ipcRenderer.send('settings_get');
}
this.setState({
language: languageHandler.getCurrentLanguage(),
});
},
componentDidMount: function() {
@ -249,8 +258,8 @@ module.exports = React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to load user settings: " + error);
Modal.createDialog(ErrorDialog, {
title: "Can't load user settings",
description: ((error && error.message) ? error.message : "Server may be unavailable or overloaded"),
title: _t("Can't load user settings"),
description: ((error && error.message) ? error.message : _t("Server may be unavailable or overloaded")),
});
});
},
@ -265,8 +274,8 @@ module.exports = React.createClass({
if (MatrixClientPeg.get().isGuest()) {
const NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: "Please Register",
description: "Guests can't set avatars. Please register.",
title: _t("Please Register"),
description: _t("Guests can't set avatars. Please register."),
});
return;
}
@ -291,8 +300,8 @@ module.exports = React.createClass({
console.error("Failed to set avatar: " + err);
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Failed to set avatar",
description: ((err && err.message) ? err.message : "Operation failed"),
title: _t("Failed to set avatar."),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
});
},
@ -300,19 +309,19 @@ module.exports = React.createClass({
onLogoutClicked: function(ev) {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Sign out?",
title: _t("Sign out"),
description:
<div>
For security, logging out will delete any end-to-end encryption keys from this browser.
If you want to be able to decrypt your conversation history from future Riot sessions,
please export your room keys for safe-keeping.
{ _t("For security, logging out will delete any end-to-end " +
"encryption keys from this browser. If you want to be able " +
"to decrypt your conversation history from future Riot sessions, " +
"please export your room keys for safe-keeping.") }.
</div>,
button: "Sign out",
button: _t("Sign out"),
extraButtons: [
<button key="export" className="mx_Dialog_primary"
onClick={this._onExportE2eKeysClicked}>
Export E2E room keys
{ _t("Export E2E room keys") }
</button>,
],
onFinished: (confirmed) => {
@ -329,14 +338,14 @@ module.exports = React.createClass({
onPasswordChangeError: function(err) {
let errMsg = err.error || "";
if (err.httpStatus === 403) {
errMsg = "Failed to change password. Is your password correct?";
errMsg = _t("Failed to change password. Is your password correct?");
} else if (err.httpStatus) {
errMsg += ` (HTTP status ${err.httpStatus})`;
}
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to change password: " + errMsg);
Modal.createDialog(ErrorDialog, {
title: "Error",
title: _t("Error"),
description: errMsg,
});
},
@ -344,10 +353,8 @@ module.exports = React.createClass({
onPasswordChanged: function() {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Success",
description: `Your password was successfully changed. You will not
receive push notifications on other devices until you
log back in to them.`,
title: _t("Success"),
description: _t("Your password was successfully changed. You will not receive push notifications on other devices until you log back in to them") + ".",
});
},
@ -373,8 +380,8 @@ module.exports = React.createClass({
const emailAddress = this.refs.add_email_input.value;
if (!Email.looksValid(emailAddress)) {
Modal.createDialog(ErrorDialog, {
title: "Invalid Email Address",
description: "This doesn't appear to be a valid email address",
title: _t("Invalid Email Address"),
description: _t("This doesn't appear to be a valid email address"),
});
return;
}
@ -383,17 +390,17 @@ module.exports = React.createClass({
// same here.
this._addThreepid.addEmailAddress(emailAddress, true).done(() => {
Modal.createDialog(QuestionDialog, {
title: "Verification Pending",
description: "Please check your email and click on the link it contains. Once this is done, click continue.",
button: 'Continue',
title: _t("Verification Pending"),
description: _t("Please check your email and click on the link it contains. Once this is done, click continue."),
button: _t('Continue'),
onFinished: this.onEmailDialogFinished,
});
}, (err) => {
this.setState({email_add_pending: false});
console.error("Unable to add email address " + emailAddress + " " + err);
Modal.createDialog(ErrorDialog, {
title: "Unable to add email address",
description: ((err && err.message) ? err.message : "Operation failed"),
title: _t("Unable to add email address"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
});
ReactDOM.findDOMNode(this.refs.add_email_input).blur();
@ -403,9 +410,9 @@ module.exports = React.createClass({
onRemoveThreepidClicked: function(threepid) {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Remove Contact Information?",
description: "Remove " + threepid.address + "?",
button: 'Remove',
title: _t("Remove Contact Information?"),
description: _t("Remove %(threePid)s?", { threePid : threepid.address }),
button: _t('Remove'),
onFinished: (submit) => {
if (submit) {
this.setState({
@ -417,8 +424,8 @@ module.exports = React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Unable to remove contact information: " + err);
Modal.createDialog(ErrorDialog, {
title: "Unable to remove contact information",
description: ((err && err.message) ? err.message : "Operation failed"),
title: _t("Unable to remove contact information"),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
}).done();
}
@ -444,22 +451,22 @@ module.exports = React.createClass({
this.setState({email_add_pending: false});
}, (err) => {
this.setState({email_add_pending: false});
if (err.errcode === 'M_THREEPID_AUTH_FAILED') {
if (err.errcode == 'M_THREEPID_AUTH_FAILED') {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
let message = "Unable to verify email address. ";
message += "Please check your email and click on the link it contains. Once this is done, click continue.";
let message = _t("Unable to verify email address.") + " " +
_t("Please check your email and click on the link it contains. Once this is done, click continue.");
Modal.createDialog(QuestionDialog, {
title: "Verification Pending",
title: _t("Verification Pending"),
description: message,
button: 'Continue',
button: _t('Continue'),
onFinished: this.onEmailDialogFinished,
});
} else {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Unable to verify email address: " + err);
Modal.createDialog(ErrorDialog, {
title: "Unable to verify email address",
description: ((err && err.message) ? err.message : "Operation failed"),
title: _t("Unable to verify email address."),
description: ((err && err.message) ? err.message : _t("Operation failed")),
});
}
});
@ -549,20 +556,43 @@ module.exports = React.createClass({
<div>
<h3>Referral</h3>
<div className="mx_UserSettings_section">
Refer a friend to Riot: <a href={href}>{href}</a>
{_t("Refer a friend to Riot:")} <a href={href}>{href}</a>
</div>
</div>
);
},
onLanguageChange: function(newLang) {
if(this.state.language !== newLang) {
UserSettingsStore.setLocalSetting('language', newLang);
this.setState({
language: newLang,
});
PlatformPeg.get().reload();
}
},
_renderLanguageSetting: function () {
const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown');
return <div>
<label htmlFor="languageSelector">{_t('Interface Language')}</label>
<LanguageDropdown ref="language" onOptionChange={this.onLanguageChange}
className="mx_UserSettings_language"
value={this.state.language}
/>
</div>;
},
_renderUserInterfaceSettings: function() {
return (
<div>
<h3>User Interface</h3>
<h3>{ _t("User Interface") }</h3>
<div className="mx_UserSettings_section">
{ this._renderUrlPreviewSelector() }
{ SETTINGS_LABELS.map( this._renderSyncedSetting ) }
{ THEMES.map( this._renderThemeSelector ) }
{ this._renderLanguageSetting() }
</div>
</div>
);
@ -576,7 +606,7 @@ module.exports = React.createClass({
onChange={ (e) => UserSettingsStore.setUrlPreviewsDisabled(e.target.checked) }
/>
<label htmlFor="urlPreviewsDisabled">
Disable inline URL previews by default
{ _t("Disable inline URL previews by default") }
</label>
</div>;
},
@ -589,7 +619,7 @@ module.exports = React.createClass({
onChange={ (e) => UserSettingsStore.setSyncedSetting(setting.id, e.target.checked) }
/>
<label htmlFor={ setting.id }>
{ setting.label }
{ _t(setting.label) }
</label>
</div>;
},
@ -623,7 +653,7 @@ module.exports = React.createClass({
const deviceId = client.deviceId;
let identityKey = client.getDeviceEd25519Key();
if (!identityKey) {
identityKey = "<not supported>";
identityKey = _t("<not supported>");
} else {
identityKey = FormattingUtils.formatCryptoKey(identityKey);
}
@ -635,18 +665,18 @@ module.exports = React.createClass({
<div className="mx_UserSettings_importExportButtons">
<AccessibleButton className="mx_UserSettings_button"
onClick={this._onExportE2eKeysClicked}>
Export E2E room keys
{ _t("Export E2E room keys") }
</AccessibleButton>
<AccessibleButton className="mx_UserSettings_button"
onClick={this._onImportE2eKeysClicked}>
Import E2E room keys
{ _t("Import E2E room keys") }
</AccessibleButton>
</div>
);
}
return (
<div>
<h3>Cryptography</h3>
<h3>{ _t("Cryptography") }</h3>
<div className="mx_UserSettings_section mx_UserSettings_cryptoSection">
<ul>
<li><label>Device ID:</label> <span><code>{deviceId}</code></span></li>
@ -677,7 +707,7 @@ module.exports = React.createClass({
}
/>
<label htmlFor={ setting.id }>
{ setting.label }
{ _t(setting.label) }
</label>
</div>;
},
@ -698,11 +728,11 @@ module.exports = React.createClass({
}
return (
<div>
<h3>Bug Report</h3>
<h3>{ _t("Bug Report") }</h3>
<div className="mx_UserSettings_section">
<p>Found a bug?</p>
<p>{ _t("Found a bug?") }</p>
<button className="mx_UserSettings_button danger"
onClick={this._onBugReportClicked}>Report it
onClick={this._onBugReportClicked}>{_t('Report it')}
</button>
</div>
</div>
@ -725,8 +755,8 @@ module.exports = React.createClass({
e.target.checked = false;
const NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: "Please Register",
description: "Guests can't use labs features. Please register.",
title: _t("Please Register"),
description: _t("Guests can't use labs features. Please register."),
});
return;
}
@ -739,9 +769,9 @@ module.exports = React.createClass({
));
return (
<div>
<h3>Labs</h3>
<h3>{ _t("Labs") }</h3>
<div className="mx_UserSettings_section">
<p>These are experimental features that may break in unexpected ways. Use with caution.</p>
<p>{ _t("These are experimental features that may break in unexpected ways") }. { _t("Use with caution") }.</p>
{features}
</div>
</div>
@ -753,10 +783,10 @@ module.exports = React.createClass({
if (MatrixClientPeg.get().isGuest()) return null;
return <div>
<h3>Deactivate Account</h3>
<h3>{ _t("Deactivate Account") }</h3>
<div className="mx_UserSettings_section">
<AccessibleButton className="mx_UserSettings_button danger"
onClick={this._onDeactivateAccountClicked}>Deactivate my account
onClick={this._onDeactivateAccountClicked}> { _t("Deactivate my account") }
</AccessibleButton>
</div>
</div>;
@ -764,11 +794,11 @@ module.exports = React.createClass({
_renderClearCache: function() {
return <div>
<h3>Clear Cache</h3>
<h3>{ _t("Clear Cache") }</h3>
<div className="mx_UserSettings_section">
<AccessibleButton className="mx_UserSettings_button danger"
onClick={this._onClearCacheClicked}>
Clear Cache and Reload
{ _t("Clear Cache and Reload") }
</AccessibleButton>
</div>
</div>;
@ -797,7 +827,7 @@ module.exports = React.createClass({
}
return <div>
<h3>Bulk Options</h3>
<h3>{ _t("Bulk Options") }</h3>
<div className="mx_UserSettings_section">
{reject}
</div>
@ -840,7 +870,8 @@ module.exports = React.createClass({
},
nameForMedium: function(medium) {
if (medium === 'msisdn') return 'Phone';
if (medium === 'msisdn') return _t('Phone');
if (medium === 'email') return _t('Email');
return medium[0].toUpperCase() + medium.slice(1);
},
@ -889,7 +920,7 @@ module.exports = React.createClass({
/>
</div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/cancel-small.svg" width="14" height="14" alt="Remove" onClick={this.onRemoveThreepidClicked.bind(this, val)} />
<img src="img/cancel-small.svg" width="14" height="14" alt={ _t("Remove") } onClick={this.onRemoveThreepidClicked.bind(this, val)} />
</div>
</div>
);
@ -901,14 +932,14 @@ module.exports = React.createClass({
addEmailSection = (
<div className="mx_UserSettings_profileTableRow" key="_newEmail">
<div className="mx_UserSettings_profileLabelCell">
<label>Email</label>
<label>{_t('Email')}</label>
</div>
<div className="mx_UserSettings_profileInputCell">
<EditableText
ref="add_email_input"
className="mx_UserSettings_editable"
placeholderClassName="mx_UserSettings_threepidPlaceholder"
placeholder={ "Add email address" }
placeholder={ _t("Add email address") }
blurToCancel={ false }
onValueChanged={ this._onAddEmailEditFinished } />
</div>
@ -930,7 +961,7 @@ module.exports = React.createClass({
if (MatrixClientPeg.get().isGuest()) {
accountJsx = (
<div className="mx_UserSettings_button" onClick={this.onUpgradeClicked}>
Create an account
{ _t("Create an account") }
</div>
);
} else {
@ -948,7 +979,7 @@ module.exports = React.createClass({
let notificationArea;
if (!MatrixClientPeg.get().isGuest() && this.state.threepids !== undefined) {
notificationArea = (<div>
<h3>Notifications</h3>
<h3>{ _t("Notifications") }</h3>
<div className="mx_UserSettings_section">
<Notifications threepids={this.state.threepids} brand={this.props.brand} />
@ -967,7 +998,7 @@ module.exports = React.createClass({
return (
<div className="mx_UserSettings">
<SimpleRoomHeader
title="Settings"
title={ _t("Settings") }
collapsedRhs={ this.props.collapsedRhs }
onCancelClick={ this.props.onClose }
/>
@ -975,13 +1006,13 @@ module.exports = React.createClass({
<GeminiScrollbar className="mx_UserSettings_body"
autoshow={true}>
<h3>Profile</h3>
<h3>{ _t("Profile") }</h3>
<div className="mx_UserSettings_section">
<div className="mx_UserSettings_profileTable">
<div className="mx_UserSettings_profileTableRow">
<div className="mx_UserSettings_profileLabelCell">
<label htmlFor="displayName">Display name</label>
<label htmlFor="displayName">{ _t('Display name') }</label>
</div>
<div className="mx_UserSettings_profileInputCell">
<ChangeDisplayName />
@ -998,7 +1029,7 @@ module.exports = React.createClass({
<div className="mx_UserSettings_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg" className="mx_filterFlipColor"
alt="Upload avatar" title="Upload avatar"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") }
width="17" height="15" />
</label>
<input id="avatarInput" type="file" onChange={this.onAvatarSelected}/>
@ -1006,12 +1037,12 @@ module.exports = React.createClass({
</div>
</div>
<h3>Account</h3>
<h3>{ _t("Account") }</h3>
<div className="mx_UserSettings_section">
<div className="mx_UserSettings_section cadcampoHide">
<AccessibleButton className="mx_UserSettings_logout mx_UserSettings_button" onClick={this.onLogoutClicked}>
Sign out
{ _t("Sign out") }
</AccessibleButton>
{accountJsx}
@ -1030,34 +1061,31 @@ module.exports = React.createClass({
{PlatformPeg.get().isElectron() && this._renderElectronSettings()}
<h3>Advanced</h3>
<h3>{ _t("Advanced") }</h3>
<div className="mx_UserSettings_section">
<div className="mx_UserSettings_advanced">
Logged in as {this._me}
{ _t("Logged in as:") } {this._me}
</div>
<div className="mx_UserSettings_advanced">
Access Token: <span className="mx_UserSettings_advanced_spoiler"
onClick={this._showSpoiler}
data-spoiler={ MatrixClientPeg.get().getAccessToken() }
>&lt;click to reveal&gt;</span>
{_t('Access Token:')} <span className="mx_UserSettings_advanced_spoiler" onClick={this._showSpoiler} data-spoiler={ MatrixClientPeg.get().getAccessToken() }>&lt;{ _t("click to reveal") }&gt;</span>
</div>
<div className="mx_UserSettings_advanced">
Homeserver is { MatrixClientPeg.get().getHomeserverUrl() }
{ _t("Homeserver is") } { MatrixClientPeg.get().getHomeserverUrl() }
</div>
<div className="mx_UserSettings_advanced">
Identity Server is { MatrixClientPeg.get().getIdentityServerUrl() }
{ _t("Identity Server is") } { MatrixClientPeg.get().getIdentityServerUrl() }
</div>
<div className="mx_UserSettings_advanced">
matrix-react-sdk version: {(REACT_SDK_VERSION !== '<local>')
{_t('matrix-react-sdk version:')} {(REACT_SDK_VERSION !== '<local>')
? gHVersionLabel('matrix-org/matrix-react-sdk', REACT_SDK_VERSION)
: REACT_SDK_VERSION
}<br/>
riot-web version: {(this.state.vectorVersion !== undefined)
{_t('riot-web version:')} {(this.state.vectorVersion !== undefined)
? gHVersionLabel('vector-im/riot-web', this.state.vectorVersion)
: 'unknown'
}<br/>
olm version: {olmVersionString}<br/>
{ _t("olm version:") } {olmVersionString}<br/>
</div>
</div>

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict';
var React = require('react');
import { _t } from '../../../languageHandler';
var sdk = require('../../../index');
var Modal = require("../../../Modal");
var MatrixClientPeg = require('../../../MatrixClientPeg');
@ -54,7 +55,7 @@ module.exports = React.createClass({
progress: "sent_email"
});
}, (err) => {
this.showErrorDialog("Failed to send email: " + err.message);
this.showErrorDialog(_t('Failed to send email') + ": " + err.message);
this.setState({
progress: null
});
@ -78,30 +79,33 @@ module.exports = React.createClass({
ev.preventDefault();
if (!this.state.email) {
this.showErrorDialog("The email address linked to your account must be entered.");
this.showErrorDialog(_t('The email address linked to your account must be entered.'));
}
else if (!this.state.password || !this.state.password2) {
this.showErrorDialog("A new password must be entered.");
this.showErrorDialog(_t('A new password must be entered.'));
}
else if (this.state.password !== this.state.password2) {
this.showErrorDialog("New passwords must match each other.");
this.showErrorDialog(_t('New passwords must match each other.'));
}
else {
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Warning",
title: _t('Warning!'),
description:
<div>
Resetting password will currently reset any end-to-end encryption keys on all devices,
making encrypted chat history unreadable, unless you first export your room keys
and re-import them afterwards.
In future this <a href="https://github.com/vector-im/riot-web/issues/2671">will be improved</a>.
{ _t(
'Resetting password will currently reset any ' +
'end-to-end encryption keys on all devices, ' +
'making encrypted chat history unreadable, ' +
'unless you first export your room keys and re-import ' +
'them afterwards. In future this will be improved.'
) }
</div>,
button: "Continue",
button: _t('Continue'),
extraButtons: [
<button className="mx_Dialog_primary"
onClick={this._onExportE2eKeysClicked}>
Export E2E room keys
{ _t('Export E2E room keys') }
</button>
],
onFinished: (confirmed) => {
@ -150,7 +154,7 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: title,
description: body
description: body,
});
},
@ -168,22 +172,20 @@ module.exports = React.createClass({
else if (this.state.progress === "sent_email") {
resetPasswordJsx = (
<div>
An email has been sent to {this.state.email}. Once you&#39;ve followed
the link it contains, click below.
{ _t('An email has been sent to') } {this.state.email}. { _t('Once you&#39;ve followed the link it contains, click below') }.
<br />
<input className="mx_Login_submit" type="button" onClick={this.onVerify}
value="I have verified my email address" />
value={ _t('I have verified my email address') } />
</div>
);
}
else if (this.state.progress === "complete") {
resetPasswordJsx = (
<div>
<p>Your password has been reset.</p>
<p>You have been logged out of all devices and will no longer receive push notifications.
To re-enable notifications, sign in again on each device.</p>
<p>{ _t('Your password has been reset') }.</p>
<p>{ _t('You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device') }.</p>
<input className="mx_Login_submit" type="button" onClick={this.props.onComplete}
value="Return to login screen" />
value={ _t('Return to login screen') } />
</div>
);
}
@ -191,7 +193,7 @@ module.exports = React.createClass({
resetPasswordJsx = (
<div>
<div className="mx_Login_prompt">
To reset your password, enter the email address linked to your account:
{ _t('To reset your password, enter the email address linked to your account') }:
</div>
<div>
<form onSubmit={this.onSubmitForm}>
@ -199,21 +201,21 @@ module.exports = React.createClass({
name="reset_email" // define a name so browser's password autofill gets less confused
value={this.state.email}
onChange={this.onInputChanged.bind(this, "email")}
placeholder="Email address" autoFocus />
placeholder={ _t('Email address') } autoFocus />
<br />
<input className="mx_Login_field" ref="pass" type="password"
name="reset_password"
value={this.state.password}
onChange={this.onInputChanged.bind(this, "password")}
placeholder="New password" />
placeholder={ _t('New password') } />
<br />
<input className="mx_Login_field" ref="pass" type="password"
name="reset_password_confirm"
value={this.state.password2}
onChange={this.onInputChanged.bind(this, "password2")}
placeholder="Confirm your new password" />
placeholder={ _t('Confirm your new password') } />
<br />
<input className="mx_Login_submit" type="submit" value="Send Reset Email" />
<input className="mx_Login_submit" type="submit" value={ _t('Send Reset Email') } />
</form>
<ServerConfig ref="serverConfig"
withToggleButton={true}
@ -230,7 +232,7 @@ module.exports = React.createClass({
Return to login
</a>
<a className="mx_Login_create" onClick={this.props.onRegisterClick} href="#">
Create a new account
{ _t('Create an account') }
</a>
<LoginFooter />
</div>

View file

@ -18,8 +18,8 @@ limitations under the License.
'use strict';
import React from 'react';
import { _t } from '../../../languageHandler';
import ReactDOM from 'react-dom';
import url from 'url';
import sdk from '../../../index';
import Login from '../../../Login';
@ -222,15 +222,17 @@ module.exports = React.createClass({
(this.state.enteredHomeserverUrl.startsWith("http:") ||
!this.state.enteredHomeserverUrl.startsWith("http")))
{
const urlStart = <a href='https://www.google.com/search?&q=enable%20unsafe%20scripts'>;
const urlEnd = </a>;
errorText = <span>
Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar.
Either use HTTPS or <a href='https://www.google.com/search?&q=enable%20unsafe%20scripts'>enable unsafe scripts</a>
{ _t('Can\'t connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or %(urlStart)s enable unsafe scripts %(urlEnd)s', {urlStart: urlStart, urlEnd: urlEnd})}
</span>;
}
else {
const urlStart = <a href={this.state.enteredHomeserverUrl}>;
const urlEnd = </a>;
errorText = <span>
Can't connect to homeserver - please check your connectivity and ensure
your <a href={ this.state.enteredHomeserverUrl }>homeserver's SSL certificate</a> is trusted.
{ _t('Can\'t connect to homeserver - please check your connectivity and ensure your %(urlStart)s homeserver\'s SSL certificate %(urlEnd)s is trusted', {urlStart: urlStart, urlEnd: urlEnd})}
</span>;
}
}
@ -242,12 +244,6 @@ module.exports = React.createClass({
switch (step) {
case 'm.login.password':
const PasswordLogin = sdk.getComponent('login.PasswordLogin');
// HSs that are not matrix.org may not be configured to have their
// domain name === domain part.
let hsDomain = url.parse(this.state.enteredHomeserverUrl).hostname;
if (hsDomain !== 'matrix.org') {
hsDomain = null;
}
return (
<PasswordLogin
onSubmit={this.onPasswordLogin}
@ -259,7 +255,6 @@ module.exports = React.createClass({
onPhoneNumberChanged={this.onPhoneNumberChanged}
onForgotPasswordClick={this.props.onForgotPasswordClick}
loginIncorrect={this.state.loginIncorrect}
hsDomain={hsDomain}
/>
);
case 'm.login.cas':
@ -273,8 +268,7 @@ module.exports = React.createClass({
}
return (
<div>
Sorry, this homeserver is using a login which is not
recognised ({step})
{ _t('Sorry, this homeserver is using a login which is not recognised ')}({step})
</div>
);
}
@ -291,7 +285,7 @@ module.exports = React.createClass({
if (this.props.enableGuest) {
loginAsGuestJsx =
<a className="mx_Login_create" onClick={this._onLoginAsGuestClick} href="#">
Login as guest
{ _t('Login as guest')}
</a>;
}
@ -299,7 +293,7 @@ module.exports = React.createClass({
if (this.props.onCancelClick) {
returnToAppJsx =
<a className="mx_Login_create" onClick={this.props.onCancelClick} href="#">
Return to app
{ _t('Return to app')}
</a>;
}
@ -308,7 +302,7 @@ module.exports = React.createClass({
<div className="mx_Login_box">
<LoginHeader />
<div>
<h2>Sign in
<h2>{ _t('Sign in')}
{ loader }
</h2>
{ this.componentForStep(this.state.currentFlow) }
@ -324,7 +318,7 @@ module.exports = React.createClass({
{ this.state.errorText }
</div>
<a className="mx_Login_create" onClick={this.props.onRegisterClick} href="#">
Create a new account
{ _t('Create an account')}
</a>
{ loginAsGuestJsx }
{ returnToAppJsx }

View file

@ -16,9 +16,10 @@ limitations under the License.
'use strict';
var React = require('react');
var sdk = require('../../../index');
var MatrixClientPeg = require('../../../MatrixClientPeg');
import React from 'react';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'PostRegistration',
@ -64,12 +65,12 @@ module.exports = React.createClass({
<div className="mx_Login_box">
<LoginHeader />
<div className="mx_Login_profile">
Set a display name:
{ _t('Set a display name:') }
<ChangeDisplayName />
Upload an avatar:
{ _t('Upload an avatar:') }
<ChangeAvatar
initialAvatarUrl={this.state.avatarUrl} />
<button onClick={this.props.onComplete}>Continue</button>
<button onClick={this.props.onComplete}>{ _t('Continue') }</button>
{this.state.errorString}
</div>
</div>

View file

@ -27,6 +27,7 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import RegistrationForm from '../../views/login/RegistrationForm';
import CaptchaForm from '../../views/login/CaptchaForm';
import RtsClient from '../../../RtsClient';
import { _t } from '../../../languageHandler';
const MIN_PASSWORD_LENGTH = 6;
@ -162,7 +163,7 @@ module.exports = React.createClass({
msisdn_available |= flow.stages.indexOf('m.login.msisdn') > -1;
}
if (!msisdn_available) {
msg = "This server does not support authentication with a phone number";
msg = _t('This server does not support authentication with a phone number.');
}
}
this.setState({
@ -260,29 +261,29 @@ module.exports = React.createClass({
var errMsg;
switch (errCode) {
case "RegistrationForm.ERR_PASSWORD_MISSING":
errMsg = "Missing password.";
errMsg = _t('Missing password.');
break;
case "RegistrationForm.ERR_PASSWORD_MISMATCH":
errMsg = "Passwords don't match.";
errMsg = _t('Passwords don\'t match.');
break;
case "RegistrationForm.ERR_PASSWORD_LENGTH":
errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
errMsg = _t('Password too short (min %(MIN_PASSWORD_LENGTH)s).', {MIN_PASSWORD_LENGTH: $MIN_PASSWORD_LENGTH})
break;
case "RegistrationForm.ERR_EMAIL_INVALID":
errMsg = "This doesn't look like a valid email address";
errMsg = _t('This doesn\'t look like a valid email address.');
break;
case "RegistrationForm.ERR_PHONE_NUMBER_INVALID":
errMsg = "This doesn't look like a valid phone number";
errMsg = _t('This doesn\'t look like a valid phone number.');
break;
case "RegistrationForm.ERR_USERNAME_INVALID":
errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores.";
errMsg = _t('User names may only contain letters, numbers, dots, hyphens and underscores.');
break;
case "RegistrationForm.ERR_USERNAME_BLANK":
errMsg = "You need to enter a user name";
errMsg = _t('You need to enter a user name.');
break;
default:
console.error("Unknown error code: %s", errCode);
errMsg = "An unknown error occurred.";
errMsg = _t('An unknown error occurred.');
break;
}
this.setState({
@ -400,7 +401,7 @@ module.exports = React.createClass({
if (this.props.onCancelClick) {
returnToAppJsx = (
<a className="mx_Login_create" onClick={this.props.onCancelClick} href="#">
Return to app
{_t('Return to app')}
</a>
);
}
@ -413,10 +414,10 @@ module.exports = React.createClass({
this.state.teamSelected.domain + "/icon.png" :
null}
/>
<h2>Create an account</h2>
<h2>{_t('Create an account')}</h2>
{registerBody}
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
I already have an account
{_t('I already have an account')}
</a>
{returnToAppJsx}
<LoginFooter />