Merge branch 'develop' into new-guest-access

This commit is contained in:
Matthew Hodgson 2017-05-28 22:58:18 +01:00
commit 5c885922d9
90 changed files with 5814 additions and 831 deletions

View file

@ -16,8 +16,10 @@ limitations under the License.
'use strict';
var React = require('react');
var classNames = require("classnames");
import { _t } from '../../../languageHandler';
var Modal = require('../../../Modal');
var sdk = require('../../../index');
@ -129,6 +131,9 @@ module.exports = WithMatrixClient(React.createClass({
* for now.
*/
tileShape: React.PropTypes.string,
// show twelve hour timestamps
isTwelveHour: React.PropTypes.bool,
},
getInitialState: function() {
@ -404,9 +409,10 @@ module.exports = WithMatrixClient(React.createClass({
var isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1);
const isRedacted = (eventType === 'm.room.message') && this.props.isRedacted;
var classes = classNames({
const classes = classNames({
mx_EventTile: true,
mx_EventTile_info: isInfoMessage,
mx_EventTile_12hr: this.props.isTwelveHour,
mx_EventTile_encrypting: this.props.eventSendStatus == 'encrypting',
mx_EventTile_sending: isSending,
mx_EventTile_notSent: this.props.eventSendStatus == 'not_sent',
@ -464,9 +470,9 @@ module.exports = WithMatrixClient(React.createClass({
if (needsSenderProfile) {
let aux = null;
if (!this.props.tileShape) {
if (msgtype === 'm.image') aux = "sent an image";
else if (msgtype === 'm.video') aux = "sent a video";
else if (msgtype === 'm.file') aux = "uploaded a file";
if (msgtype === 'm.image') aux = _t('sent an image');
else if (msgtype === 'm.video') aux = _t('sent a video');
else if (msgtype === 'm.file') aux = _t('uploaded a file');
sender = <SenderProfile onClick={ this.onSenderProfileClick } mxEvent={this.props.mxEvent} aux={aux} />;
}
else {
@ -474,11 +480,10 @@ module.exports = WithMatrixClient(React.createClass({
}
}
var editButton = (
const editButton = (
<span className="mx_EventTile_editButton" title="Options" onClick={this.onEditClicked} />
);
var e2e;
let e2e;
// cosmetic padlocks:
if ((e2eEnabled && this.props.eventSendStatus) || this.props.mxEvent.getType() === 'm.room.encryption') {
e2e = <img style={{ cursor: 'initial', marginLeft: '-1px' }} className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12" />;
@ -489,7 +494,7 @@ module.exports = WithMatrixClient(React.createClass({
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Undecryptable" src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} />;
}
else if (this.state.verified == true || (e2eEnabled && this.props.eventSendStatus)) {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12"/>;
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12"/>;
}
else {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by unverified device" src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }}/>;
@ -499,11 +504,10 @@ module.exports = WithMatrixClient(React.createClass({
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Unencrypted message" src="img/e2e-unencrypted.svg" width="12" height="12"/>;
}
const timestamp = this.props.mxEvent.getTs() ?
<MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null;
<MessageTimestamp showTwelveHour={this.props.isTwelveHour} ts={this.props.mxEvent.getTs()} /> : null;
if (this.props.tileShape === "notif") {
var room = this.props.matrixClient.getRoom(this.props.mxEvent.getRoomId());
const room = this.props.matrixClient.getRoom(this.props.mxEvent.getRoomId());
return (
<div className={classes}>
<div className="mx_EventTile_roomName">

View file

@ -0,0 +1,96 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2017 Michael Telatynski
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import dis from '../../../dispatcher';
import KeyCode from '../../../KeyCode';
module.exports = React.createClass({
displayName: 'ForwardMessage',
propTypes: {
currentRoomId: React.PropTypes.string.isRequired,
/* the MatrixEvent to be forwarded */
mxEvent: React.PropTypes.object.isRequired,
onCancelClick: React.PropTypes.func.isRequired,
},
componentWillMount: function() {
dis.dispatch({
action: 'ui_opacity',
leftOpacity: 1.0,
rightOpacity: 0.3,
middleOpacity: 0.5,
});
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
document.addEventListener('keydown', this._onKeyDown);
},
componentWillUnmount: function() {
dis.dispatch({
action: 'ui_opacity',
sideOpacity: 1.0,
middleOpacity: 1.0,
});
dis.unregister(this.dispatcherRef);
document.removeEventListener('keydown', this._onKeyDown);
},
onAction: function(payload) {
if (payload.action === 'view_room') {
const event = this.props.mxEvent;
const Client = MatrixClientPeg.get();
Client.sendEvent(payload.room_id, event.getType(), event.getContent()).done(() => {
dis.dispatch({action: 'message_sent'});
}, (err) => {
if (err.name === "UnknownDeviceError") {
dis.dispatch({
action: 'unknown_device_error',
err: err,
room: Client.getRoom(payload.room_id),
});
}
dis.dispatch({action: 'message_send_failed'});
});
if (this.props.currentRoomId === payload.room_id) this.props.onCancelClick();
}
},
_onKeyDown: function(ev) {
switch (ev.keyCode) {
case KeyCode.ESCAPE:
this.props.onCancelClick();
break;
}
},
render: function() {
return (
<div className="mx_ForwardMessage">
<h1>{_t('Please select the destination room for this message')}</h1>
</div>
);
},
});

View file

@ -31,6 +31,7 @@ import classNames from 'classnames';
import dis from '../../../dispatcher';
import Modal from '../../../Modal';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import createRoom from '../../../createRoom';
import DMRoomMap from '../../../utils/DMRoomMap';
import Unread from '../../../Unread';
@ -219,7 +220,7 @@ module.exports = WithMatrixClient(React.createClass({
onKick: function() {
const membership = this.props.member.membership;
const kickLabel = membership === "invite" ? "Disinvite" : "Kick";
const kickLabel = membership === "invite" ? _t("Disinvite") : _t("Kick");
const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog");
Modal.createDialog(ConfirmUserActionDialog, {
member: this.props.member,
@ -241,7 +242,7 @@ module.exports = WithMatrixClient(React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Kick error: " + err);
Modal.createDialog(ErrorDialog, {
title: "Failed to kick",
title: _t("Failed to kick"),
description: ((err && err.message) ? err.message : "Operation failed"),
});
}
@ -256,7 +257,7 @@ module.exports = WithMatrixClient(React.createClass({
const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog");
Modal.createDialog(ConfirmUserActionDialog, {
member: this.props.member,
action: this.props.member.membership == 'ban' ? 'Unban' : 'Ban',
action: this.props.member.membership == 'ban' ? _t("Unban") : _t("Ban"),
askReason: this.props.member.membership != 'ban',
danger: this.props.member.membership != 'ban',
onFinished: (proceed, reason) => {
@ -283,8 +284,8 @@ module.exports = WithMatrixClient(React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Ban error: " + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to ban user",
title: _t("Error"),
description: _t("Failed to ban user"),
});
}
).finally(()=>{
@ -333,8 +334,8 @@ module.exports = WithMatrixClient(React.createClass({
}, function(err) {
console.error("Mute error: " + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to mute user",
title: _t("Error"),
description: _t("Failed to mute user"),
});
}
).finally(()=>{
@ -378,8 +379,8 @@ module.exports = WithMatrixClient(React.createClass({
} else {
console.error("Toggle moderator error:" + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to toggle moderator status",
title: _t("Error"),
description: _t("Failed to toggle moderator status"),
});
}
}
@ -399,8 +400,8 @@ module.exports = WithMatrixClient(React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to change power level " + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to change power level",
title: _t("Error"),
description: _t("Failed to change power level"),
});
}
).finally(()=>{
@ -428,13 +429,13 @@ module.exports = WithMatrixClient(React.createClass({
if (parseInt(myPower) === parseInt(powerLevel)) {
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Warning",
title: _t("Warning!"),
description:
<div>
You will not be able to undo this change as you are promoting the user to have the same power level as yourself.<br/>
Are you sure?
{ _t("You will not be able to undo this change as you are promoting the user to have the same power level as yourself") }.<br/>
{ _t("Are you sure?") }
</div>,
button: "Continue",
button: _t("Continue"),
onFinished: function(confirmed) {
if (confirmed) {
self._applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
@ -577,9 +578,9 @@ module.exports = WithMatrixClient(React.createClass({
// still loading
devComponents = <Spinner />;
} else if (devices === null) {
devComponents = "Unable to load device list";
devComponents = _t("Unable to load device list");
} else if (devices.length === 0) {
devComponents = "No devices with registered encryption keys";
devComponents = _t("No devices with registered encryption keys");
} else {
devComponents = [];
for (var i = 0; i < devices.length; i++) {
@ -591,7 +592,7 @@ module.exports = WithMatrixClient(React.createClass({
return (
<div>
<h3>Devices</h3>
<h3>{ _t("Devices") }</h3>
<div className="mx_MemberInfo_devices">
{devComponents}
</div>
@ -640,11 +641,11 @@ module.exports = WithMatrixClient(React.createClass({
<div className="mx_RoomTile_avatar">
<img src="img/create-big.svg" width="26" height="26" />
</div>
<div className={labelClasses}><i>Start new chat</i></div>
<div className={labelClasses}><i>{ _t("Start a chat") }</i></div>
</AccessibleButton>;
startChat = <div>
<h3>Direct chats</h3>
<h3>{ _t("Direct chats") }</h3>
{tiles}
{startNewChat}
</div>;
@ -657,7 +658,7 @@ module.exports = WithMatrixClient(React.createClass({
if (this.state.can.kick) {
const membership = this.props.member.membership;
const kickLabel = membership === "invite" ? "Disinvite" : "Kick";
const kickLabel = membership === "invite" ? _t("Disinvite") : _t("Kick");
kickButton = (
<AccessibleButton className="mx_MemberInfo_field"
onClick={this.onKick}>
@ -666,9 +667,9 @@ module.exports = WithMatrixClient(React.createClass({
);
}
if (this.state.can.ban) {
let label = 'Ban';
let label = _t("Ban");
if (this.props.member.membership == 'ban') {
label = 'Unban';
label = _t("Unban");
}
banButton = (
<AccessibleButton className="mx_MemberInfo_field"
@ -678,7 +679,7 @@ module.exports = WithMatrixClient(React.createClass({
);
}
if (this.state.can.mute) {
const muteLabel = this.state.muted ? "Unmute" : "Mute";
const muteLabel = this.state.muted ? _t("Unmute") : _t("Mute");
muteButton = (
<AccessibleButton className="mx_MemberInfo_field"
onClick={this.onMuteToggle}>
@ -687,7 +688,7 @@ module.exports = WithMatrixClient(React.createClass({
);
}
if (this.state.can.toggleMod) {
var giveOpLabel = this.state.isTargetMod ? "Revoke Moderator" : "Make Moderator";
var giveOpLabel = this.state.isTargetMod ? _t("Revoke Moderator") : _t("Make Moderator");
giveModButton = <AccessibleButton className="mx_MemberInfo_field" onClick={this.onModToggle}>
{giveOpLabel}
</AccessibleButton>;
@ -738,7 +739,7 @@ module.exports = WithMatrixClient(React.createClass({
{ this.props.member.userId }
</div>
<div className="mx_MemberInfo_profileField">
Level: <b><PowerSelector controlled={true} value={ parseInt(this.props.member.powerLevel) } disabled={ !this.state.can.modifyLevel } onChange={ this.onPowerChange }/></b>
{ _t("Level") }: <b><PowerSelector controlled={true} value={ parseInt(this.props.member.powerLevel) } disabled={ !this.state.can.modifyLevel } onChange={ this.onPowerChange }/></b>
</div>
<div className="mx_MemberInfo_profileField">
<PresenceLabel activeAgo={ presenceLastActiveAgo }

View file

@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
import { _t } from '../../../languageHandler';
var classNames = require('classnames');
var Matrix = require("matrix-js-sdk");
var q = require('q');
@ -207,7 +208,9 @@ module.exports = React.createClass({
// For now we'll pretend this is any entity. It should probably be a separate tile.
var EntityTile = sdk.getComponent("rooms.EntityTile");
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
var text = "and " + overflowCount + " other" + (overflowCount > 1 ? "s" : "") + "...";
var text = (overflowCount > 1)
? _t("and %(overflowCount)s others...", { overflowCount: overflowCount })
: _t("and one other...");
return (
<EntityTile className="mx_EntityTile_ellipsis" avatarJsx={
<BaseAvatar url="img/ellipsis.svg" name="..." width={36} height={36} />
@ -363,8 +366,8 @@ module.exports = React.createClass({
var inputBox = (
<form autoComplete="off">
<input className="mx_MemberList_query" id="mx_MemberList_query" type="text"
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
placeholder="Filter room members" />
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
placeholder={ _t('Filter room members') } />
</form>
);

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
var React = require('react');
import { _t } from '../../../languageHandler';
var CallHandler = require('../../../CallHandler');
var MatrixClientPeg = require('../../../MatrixClientPeg');
var Modal = require('../../../Modal');
@ -114,10 +114,10 @@ export default class MessageComposer extends React.Component {
}
Modal.createDialog(QuestionDialog, {
title: "Upload Files",
title: _t('Upload Files'),
description: (
<div>
<p>Are you sure you want upload the following files?</p>
<p>{ _t('Are you sure you want upload the following files?') }</p>
<ul style={{listStyle: 'none', textAlign: 'left'}}>
{fileList}
</ul>
@ -236,11 +236,11 @@ export default class MessageComposer extends React.Component {
if (roomIsEncrypted) {
// FIXME: show a /!\ if there are untrusted devices in the room...
e2eImg = 'img/e2e-verified.svg';
e2eTitle = 'Encrypted room';
e2eTitle = _t('Encrypted room');
e2eClass = 'mx_MessageComposer_e2eIcon';
} else {
e2eImg = 'img/e2e-unencrypted.svg';
e2eTitle = 'Unencrypted room';
e2eTitle = _t('Unencrypted room');
e2eClass = 'mx_MessageComposer_e2eIcon mx_filterFlipColor';
}
@ -253,16 +253,16 @@ export default class MessageComposer extends React.Component {
if (this.props.callState && this.props.callState !== 'ended') {
hangupButton =
<div key="controls_hangup" className="mx_MessageComposer_hangup" onClick={this.onHangupClick}>
<img src="img/hangup.svg" alt="Hangup" title="Hangup" width="25" height="26"/>
<img src="img/hangup.svg" alt={ _t('Hangup') } title={ _t('Hangup') } width="25" height="26"/>
</div>;
}
else {
callButton =
<div key="controls_call" className="mx_MessageComposer_voicecall" onClick={this.onVoiceCallClick} title="Voice call">
<div key="controls_call" className="mx_MessageComposer_voicecall" onClick={this.onVoiceCallClick} title={ _t('Voice call') }>
<TintableSvg src="img/icon-call.svg" width="35" height="35"/>
</div>;
videoCallButton =
<div key="controls_videocall" className="mx_MessageComposer_videocall" onClick={this.onCallClick} title="Video call">
<div key="controls_videocall" className="mx_MessageComposer_videocall" onClick={this.onCallClick} title={ _t('Video call') }>
<TintableSvg src="img/icons-video.svg" width="35" height="35"/>
</div>;
}
@ -276,7 +276,7 @@ export default class MessageComposer extends React.Component {
// complex because of conference calls.
var uploadButton = (
<div key="controls_upload" className="mx_MessageComposer_upload"
onClick={this.onUploadClick} title="Upload file">
onClick={this.onUploadClick} title={ _t('Upload file') }>
<TintableSvg src="img/icons-upload.svg" width="35" height="35"/>
<input ref="uploadInput" type="file"
style={uploadInputStyle}
@ -296,7 +296,7 @@ export default class MessageComposer extends React.Component {
);
const placeholderText = roomIsEncrypted ?
"Send an encrypted message…" : "Send a message (unencrypted)…";
_t('Send an encrypted message') + '…' : _t('Send a message (unencrypted)') + '…';
controls.push(
<MessageComposerInput
@ -321,7 +321,7 @@ export default class MessageComposer extends React.Component {
} else {
controls.push(
<div key="controls_error" className="mx_MessageComposer_noperm_error">
You do not have permission to post to this room
{ _t('You do not have permission to post to this room') }
</div>
);
}
@ -350,7 +350,7 @@ export default class MessageComposer extends React.Component {
mx_filterFlipColor: true,
});
return <img className={className}
title={name}
title={ _t(name) }
onMouseDown={disabled ? null : onFormatButtonClicked}
key={name}
src={`img/button-text-${name}${suffix}.svg`}
@ -370,11 +370,11 @@ export default class MessageComposer extends React.Component {
<div className="mx_MessageComposer_formatbar" style={this.state.showFormatting ? {} : {display: 'none'}}>
{formatButtons}
<div style={{flex: 1}}></div>
<img title={`Turn Markdown ${this.state.inputState.isRichtextEnabled ? 'on' : 'off'}`}
<img title={ this.state.inputState.isRichtextEnabled ? _t("Turn Markdown on") : _t("Turn Markdown off") }
onMouseDown={this.onToggleMarkdownClicked}
className="mx_MessageComposer_formatbar_markdown mx_filterFlipColor"
src={`img/button-md-${!this.state.inputState.isRichtextEnabled}.png`} />
<img title="Hide Text Formatting Toolbar"
<img title={ _t("Hide Text Formatting Toolbar") }
onClick={this.onToggleFormattingClicked}
className="mx_MessageComposer_formatbar_cancel mx_filterFlipColor"
src="img/icon-text-cancel.svg" />

View file

@ -30,6 +30,7 @@ import type {MatrixClient} from 'matrix-js-sdk/lib/matrix';
import SlashCommands from '../../../SlashCommands';
import Modal from '../../../Modal';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import dis from '../../../dispatcher';
import KeyCode from '../../../KeyCode';
@ -504,8 +505,8 @@ export default class MessageComposerInput extends React.Component {
console.error("Command failure: %s", err);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Server error",
description: ((err && err.message) ? err.message : "Server unavailable, overloaded, or something else went wrong."),
title: _t("Server error"),
description: ((err && err.message) ? err.message : _t("Server unavailable, overloaded, or something else went wrong") + "."),
});
});
}
@ -513,8 +514,8 @@ export default class MessageComposerInput extends React.Component {
console.error(cmd.error);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Command error",
description: cmd.error
title: _t("Command error"),
description: cmd.error,
});
}
return true;
@ -719,7 +720,7 @@ export default class MessageComposerInput extends React.Component {
<div className={className}>
<img className="mx_MessageComposer_input_markdownIndicator mx_filterFlipColor"
onMouseDown={this.onMarkdownToggleClicked}
title={`Markdown is ${this.state.isRichtextEnabled ? 'disabled' : 'enabled'}`}
title={ this.state.isRichtextEnabled ? _t("Markdown is disabled") : _t("Markdown is enabled")}
src={`img/button-md-${!this.state.isRichtextEnabled}.png`} />
<Editor ref="editor"
placeholder={this.props.placeholder}

View file

@ -20,6 +20,7 @@ var SlashCommands = require("../../../SlashCommands");
var Modal = require("../../../Modal");
var MemberEntry = require("../../../TabCompleteEntries").MemberEntry;
var sdk = require('../../../index');
import { _t } from '../../../languageHandler';
import UserSettingsStore from "../../../UserSettingsStore";
var dis = require("../../../dispatcher");
@ -294,8 +295,8 @@ export default React.createClass({
else {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Unknown command",
description: "Usage: /markdown on|off"
title: _t("Unknown command"),
description: _t("Usage") + ": /markdown on|off",
});
}
return;
@ -314,8 +315,8 @@ export default React.createClass({
console.error("Command failure: %s", err);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Server error",
description: ((err && err.message) ? err.message : "Server unavailable, overloaded, or something else went wrong."),
title: _t("Server error"),
description: ((err && err.message) ? err.message : _t("Server unavailable, overloaded, or something else went wrong") + "."),
});
});
}
@ -323,8 +324,8 @@ export default React.createClass({
console.error(cmd.error);
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, {
title: "Command error",
description: cmd.error
title: _t("Command error"),
description: cmd.error,
});
}
return;

View file

@ -19,6 +19,7 @@ limitations under the License.
var React = require('react');
var classNames = require('classnames');
var sdk = require('../../../index');
import { _t } from '../../../languageHandler';
var MatrixClientPeg = require('../../../MatrixClientPeg');
var Modal = require("../../../Modal");
var dis = require("../../../dispatcher");
@ -119,8 +120,8 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set avatar: " + errMsg);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to set avatar.",
title: _t("Error"),
description: _t("Failed to set avatar."),
});
}).done();
},
@ -188,6 +189,9 @@ module.exports = React.createClass({
);
save_button = <AccessibleButton className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save</AccessibleButton>;
}
if (this.props.onCancelClick) {
cancel_button = <CancelButton onClick={this.props.onCancelClick}/>;
}
@ -205,7 +209,7 @@ module.exports = React.createClass({
// don't display the search count until the search completes and
// gives us a valid (possibly zero) searchCount.
if (this.props.searchInfo && this.props.searchInfo.searchCount !== undefined && this.props.searchInfo.searchCount !== null) {
searchStatus = <div className="mx_RoomHeader_searchStatus">&nbsp;(~{ this.props.searchInfo.searchCount } results)</div>;
searchStatus = <div className="mx_RoomHeader_searchStatus">&nbsp;{ _t("(~%(searchCount)s results)", { searchCount: this.props.searchInfo.searchCount }) }</div>;
}
// XXX: this is a bit inefficient - we could just compare room.name for 'Empty room'...
@ -220,7 +224,7 @@ module.exports = React.createClass({
}
}
var roomName = 'Join Room';
var roomName = _t("Join Room");
if (this.props.oobData && this.props.oobData.name) {
roomName = this.props.oobData.name;
} else if (this.props.room) {
@ -261,7 +265,7 @@ module.exports = React.createClass({
<div className="mx_RoomHeader_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg"
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 }/>
@ -296,7 +300,7 @@ module.exports = React.createClass({
var forget_button;
if (this.props.onForgetClick) {
forget_button =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onForgetClick} title="Forget room">
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onForgetClick} title={ _t("Forget room") }>
<TintableSvg src="img/leave.svg" width="26" height="20"/>
</AccessibleButton>;
}
@ -304,7 +308,7 @@ module.exports = React.createClass({
let search_button;
if (this.props.onSearchClick && this.props.inRoom) {
search_button =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSearchClick} title="Search">
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSearchClick} title={ _t("Search") }>
<TintableSvg src="img/icons-search.svg" width="35" height="35"/>
</AccessibleButton>;
}
@ -312,7 +316,7 @@ module.exports = React.createClass({
var rightPanel_buttons;
if (this.props.collapsedRhs) {
rightPanel_buttons =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.onShowRhsClick} title="Show panel">
<AccessibleButton className="mx_RoomHeader_button" onClick={this.onShowRhsClick} title={ _t('Show panel') }>
<TintableSvg src="img/maximise.svg" width="10" height="16"/>
</AccessibleButton>;
}

View file

@ -18,6 +18,7 @@ limitations under the License.
'use strict';
var React = require("react");
var ReactDOM = require("react-dom");
import { _t } from '../../../languageHandler';
var GeminiScrollbar = require('react-gemini-scrollbar');
var MatrixClientPeg = require("../../../MatrixClientPeg");
var CallHandler = require('../../../CallHandler');
@ -559,13 +560,12 @@ module.exports = React.createClass({
render: function() {
var RoomSubList = sdk.getComponent('structures.RoomSubList');
var self = this;
return (
<GeminiScrollbar className="mx_RoomList_scrollbar"
autoshow={true} onScroll={ self._whenScrolling } ref="gemscroll">
<div className="mx_RoomList">
<RoomSubList list={ self.state.lists['im.vector.fake.invite'] }
label="Invites"
label={ _t('Invites') }
editable={ false }
order="recent"
selectedRoom={ self.props.selectedRoom }
@ -576,7 +576,7 @@ module.exports = React.createClass({
onShowMoreRooms={ self.onShowMoreRooms } />
<RoomSubList list={ self.state.lists['m.favourite'] }
label="Favourites"
label={ _t('Favourites') }
tagName="m.favourite"
emptyContent={this._getEmptyContent('m.favourite')}
editable={ true }
@ -589,7 +589,7 @@ module.exports = React.createClass({
onShowMoreRooms={ self.onShowMoreRooms } />
<RoomSubList list={ self.state.lists['im.vector.fake.direct'] }
label="People"
label={ _t('People') }
tagName="im.vector.fake.direct"
emptyContent={this._getEmptyContent('im.vector.fake.direct')}
headerItems={this._getHeaderItems('im.vector.fake.direct')}
@ -604,7 +604,7 @@ module.exports = React.createClass({
onShowMoreRooms={ self.onShowMoreRooms } />
<RoomSubList list={ self.state.lists['im.vector.fake.recent'] }
label="Rooms"
label={ _t('Rooms') }
editable={ true }
emptyContent={this._getEmptyContent('im.vector.fake.recent')}
headerItems={this._getHeaderItems('im.vector.fake.recent')}
@ -636,7 +636,7 @@ module.exports = React.createClass({
}) }
<RoomSubList list={ self.state.lists['m.lowpriority'] }
label="Low priority"
label={ _t('Low priority') }
tagName="m.lowpriority"
emptyContent={this._getEmptyContent('m.lowpriority')}
editable={ true }
@ -649,7 +649,7 @@ module.exports = React.createClass({
onShowMoreRooms={ self.onShowMoreRooms } />
<RoomSubList list={ self.state.lists['im.vector.fake.archived'] }
label="Historical"
label={ _t('Historical') }
editable={ false }
order="recent"
selectedRoom={ self.props.selectedRoom }

View file

@ -21,6 +21,8 @@ var React = require('react');
var sdk = require('../../../index');
var MatrixClientPeg = require('../../../MatrixClientPeg');
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'RoomPreviewBar',
@ -84,7 +86,7 @@ module.exports = React.createClass({
_roomNameElement: function(fallback) {
fallback = fallback || 'a room';
const name = this.props.room ? this.props.room.name : (this.props.room_alias || "");
return name ? <b>{ name }</b> : fallback;
return name ? name : fallback;
},
render: function() {
@ -128,13 +130,14 @@ module.exports = React.createClass({
</div>;
}
}
// TODO: find a way to respect HTML in counterpart!
joinBlock = (
<div>
<div className="mx_RoomPreviewBar_invite_text">
You have been invited to join this room by <b>{ this.props.inviterName }</b>
{ _t('You have been invited to join this room by %(inviterName)s', {inviterName: this.props.inviterName}) }
</div>
<div className="mx_RoomPreviewBar_join_text">
Would you like to <a onClick={ this.props.onJoinClick }>accept</a> or <a onClick={ this.props.onRejectClick }>decline</a> this invitation?
{ _t('Would you like to') } <a onClick={ this.props.onJoinClick }>{ _t('accept') }</a> { _t('or') } <a onClick={ this.props.onRejectClick }>{ _t('decline') }</a> { _t('this invitation?') }
</div>
{emailMatchBlock}
</div>
@ -186,8 +189,8 @@ module.exports = React.createClass({
joinBlock = (
<div>
<div className="mx_RoomPreviewBar_join_text">
You are trying to access { name }.<br/>
<a onClick={ this.props.onJoinClick }><b>Click here</b></a> to join the discussion!
{ _t('You are trying to access %(roomName)s', {roomName: name}) }.<br/>
<a onClick={ this.props.onJoinClick }><b>{ _t('Click here') }</b></a> { _t('to join the discussion') }!
</div>
</div>
);
@ -196,7 +199,7 @@ module.exports = React.createClass({
if (this.props.canPreview) {
previewBlock = (
<div className="mx_RoomPreviewBar_preview_text">
This is a preview of this room. Room interactions have been disabled.
{ _t('This is a preview of this room. Room interactions have been disabled') }.
</div>
);
}

View file

@ -17,6 +17,7 @@ limitations under the License.
import q from 'q';
import React from 'react';
import { _t } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import SdkConfig from '../../../SdkConfig';
import sdk from '../../../index';
@ -56,8 +57,8 @@ const BannedUser = React.createClass({
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to unban: " + err);
Modal.createDialog(ErrorDialog, {
title: "Error",
description: "Failed to unban",
title: _t('Error'),
description: _t('Failed to unban'),
});
}).done();
},
@ -70,7 +71,7 @@ const BannedUser = React.createClass({
<AccessibleButton className="mx_RoomSettings_unbanButton"
onClick={this._onUnbanClick}
>
Unban
{ _t('Unban') }
</AccessibleButton>
{this.props.member.userId}
</li>
@ -400,13 +401,13 @@ module.exports = React.createClass({
var value = ev.target.value;
Modal.createDialog(QuestionDialog, {
title: "Privacy warning",
title: _t('Privacy warning'),
description:
<div>
Changes to who can read history will only apply to future messages in this room.<br/>
The visibility of existing history will be unchanged.
{ _t('Changes to who can read history will only apply to future messages in this room') }.<br/>
{ _t('The visibility of existing history will be unchanged') }.
</div>,
button: "Continue",
button: _t('Continue'),
onFinished: function(confirmed) {
if (confirmed) {
self.setState({
@ -523,11 +524,11 @@ module.exports = React.createClass({
MatrixClientPeg.get().forget(this.props.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 }),
});
});
},
@ -537,14 +538,14 @@ module.exports = React.createClass({
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Warning!",
title: _t('Warning!'),
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>Once encryption is enabled for a room it <b>cannot</b> be turned off again (for now).</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('Once encryption is enabled for a room it cannot be turned off again (for now)') }.</p>
<p>{ _t('Encrypted messages will not be visible on clients that do not yet implement encryption') }.</p>
</div>
),
onFinished: confirm=>{
@ -572,7 +573,7 @@ module.exports = React.createClass({
<input type="checkbox" ref="blacklistUnverified"
defaultChecked={ isGlobalBlacklistUnverified || isRoomBlacklistUnverified }
disabled={ isGlobalBlacklistUnverified || (this.refs.encrypt && !this.refs.encrypt.checked) }/>
Never send encrypted messages to unverified devices in this room from this device.
{ _t('Never send encrypted messages to unverified devices in this room from this device') }.
</label>;
if (!isEncrypted &&
@ -582,7 +583,7 @@ module.exports = React.createClass({
<label>
<input type="checkbox" ref="encrypt" onClick={ this.onEnableEncryptionClick }/>
<img className="mx_RoomSettings_e2eIcon" src="img/e2e-unencrypted.svg" width="12" height="12" />
Enable encryption (warning: cannot be disabled again!)
{ _t('Enable encryption') } { _t('(warning: cannot be disabled again!)') }
</label>
{ settings }
</div>
@ -596,7 +597,7 @@ module.exports = React.createClass({
? <img className="mx_RoomSettings_e2eIcon" src="img/e2e-verified.svg" width="10" height="12" />
: <img className="mx_RoomSettings_e2eIcon" src="img/e2e-unencrypted.svg" width="12" height="12" />
}
Encryption is { isEncrypted ? "" : "not " } enabled in this room.
{ isEncrypted ? "Encryption is enabled in this room" : "Encryption is not enabled in this room" }.
</label>
{ settings }
</div>
@ -647,12 +648,12 @@ module.exports = React.createClass({
if (Object.keys(user_levels).length) {
userLevelsSection =
<div>
<h3>Privileged Users</h3>
<h3>{ _t('Privileged Users') }</h3>
<ul className="mx_RoomSettings_userLevels">
{Object.keys(user_levels).map(function(user, i) {
return (
<li className="mx_RoomSettings_userLevel" key={user}>
{ user } is a <PowerSelector value={ user_levels[user] } disabled={true}/>
{ user } { _t('is a') } <PowerSelector value={ user_levels[user] } disabled={true}/>
</li>
);
})}
@ -660,7 +661,7 @@ module.exports = React.createClass({
</div>;
}
else {
userLevelsSection = <div>No users have specific privileges in this room.</div>;
userLevelsSection = <div>{ _t('No users have specific privileges in this room') }.</div>;
}
var banned = this.props.room.getMembersWithMembership("ban");
@ -668,7 +669,7 @@ module.exports = React.createClass({
if (banned.length) {
bannedUsersSection =
<div>
<h3>Banned users</h3>
<h3>{ _t('Banned users') }</h3>
<ul className="mx_RoomSettings_banned">
{banned.map(function(member) {
return (
@ -683,7 +684,7 @@ module.exports = React.createClass({
if (this._yankValueFromEvent("m.room.create", "m.federate") === false) {
unfederatableSection = (
<div className="mx_RoomSettings_powerLevel">
Ths room is not accessible by remote Matrix servers.
{ _t('This room is not accessible by remote Matrix servers') }.
</div>
);
}
@ -694,14 +695,14 @@ module.exports = React.createClass({
if (myMember.membership === "join") {
leaveButton = (
<AccessibleButton className="mx_RoomSettings_leaveButton" onClick={ this.onLeaveClick }>
Leave room
{ _t('Leave room') }
</AccessibleButton>
);
}
else if (myMember.membership === "leave") {
leaveButton = (
<AccessibleButton className="mx_RoomSettings_leaveButton" onClick={ this.onForgetClick }>
Forget room
{ _t('Forget room') }
</AccessibleButton>
);
}
@ -711,8 +712,8 @@ module.exports = React.createClass({
// TODO: support editing custom user_levels
var tags = [
{ name: "m.favourite", label: "Favourite", ref: "tag_favourite" },
{ name: "m.lowpriority", label: "Low priority", ref: "tag_lowpriority" },
{ name: "m.favourite", label: _t('Favourite'), ref: "tag_favourite" },
{ name: "m.lowpriority", label: _t('Low priority'), ref: "tag_lowpriority" },
];
Object.keys(this.state.tags).sort().forEach(function(tagName) {
@ -753,7 +754,7 @@ module.exports = React.createClass({
if (this.state.join_rule === "public" && aliasCount == 0) {
addressWarning =
<div className="mx_RoomSettings_warning">
To link to a room it must have <a href="#addresses">an address</a>.
{ _t('To link to a room it must have') } <a href="#addresses"> { _t('an address') }</a>.
</div>;
}
@ -761,10 +762,10 @@ module.exports = React.createClass({
if (this.state.join_rule !== "public" && this.state.guest_access === "forbidden") {
inviteGuestWarning =
<div className="mx_RoomSettings_warning">
Guests cannot join this room even if explicitly invited. <a href="#" onClick={ (e) => {
{ _t('Guests cannot join this room even if explicitly invited.') } <a href="#" onClick={ (e) => {
this.setState({ join_rule: "invite", guest_access: "can_join" });
e.preventDefault();
}}>Click here to fix</a>.
}}>{ _t('Click here to fix') }</a>.
</div>;
}
@ -776,7 +777,7 @@ module.exports = React.createClass({
console.error(this.state.scalar_error);
integrationsError = (
<span className="mx_RoomSettings_integrationsButton_errorPopup">
Could not connect to the integration server
{ _t('Could not connect to the integration server') }
</span>
);
}
@ -784,7 +785,7 @@ module.exports = React.createClass({
if (this.scalarClient.hasCredentials()) {
integrationsButton = (
<div className="mx_RoomSettings_integrationsButton" onClick={ this.onManageIntegrations }>
Manage Integrations
{ _t('Manage Integrations') }
</div>
);
} else if (this.state.scalar_error) {
@ -797,7 +798,7 @@ module.exports = React.createClass({
} else {
integrationsButton = (
<div className="mx_RoomSettings_integrationsButton" style={{opacity: 0.5}}>
Manage Integrations
{ _t('Manage Integrations') }
</div>
);
}
@ -813,28 +814,28 @@ module.exports = React.createClass({
<div className="mx_RoomSettings_toggles">
<div className="mx_RoomSettings_settings">
<h3>Who can access this room?</h3>
<h3>{ _t('Who can access this room?') }</h3>
{ inviteGuestWarning }
<label>
<input type="radio" name="roomVis" value="invite_only"
disabled={ !this.mayChangeRoomAccess() }
onChange={this._onRoomAccessRadioToggle}
checked={this.state.join_rule !== "public"}/>
Only people who have been invited
{ _t('Only people who have been invited') }
</label>
<label>
<input type="radio" name="roomVis" value="public_no_guests"
disabled={ !this.mayChangeRoomAccess() }
onChange={this._onRoomAccessRadioToggle}
checked={this.state.join_rule === "public" && this.state.guest_access !== "can_join"}/>
Anyone who knows the room's link, apart from guests
{ _t('Anyone who knows the room\'s link, apart from guests') }
</label>
<label>
<input type="radio" name="roomVis" value="public_with_guests"
disabled={ !this.mayChangeRoomAccess() }
onChange={this._onRoomAccessRadioToggle}
checked={this.state.join_rule === "public" && this.state.guest_access === "can_join"}/>
Anyone who knows the room's link, including guests
{ _t('Anyone who knows the room\'s link, including guests') }
</label>
{ addressWarning }
<br/>
@ -847,7 +848,7 @@ module.exports = React.createClass({
</label>
</div>
<div className="mx_RoomSettings_settings">
<h3>Who can read history?</h3>
<h3>{ _t('Who can read history?') }</h3>
<label>
<input type="radio" name="historyVis" value="world_readable"
disabled={ !roomState.mayClientSendStateEvent("m.room.history_visibility", cli) }
@ -860,28 +861,28 @@ module.exports = React.createClass({
disabled={ !roomState.mayClientSendStateEvent("m.room.history_visibility", cli) }
checked={historyVisibility === "shared"}
onChange={this._onHistoryRadioToggle} />
Members only (since the point in time of selecting this option)
{ _t('Members only') } ({ _t('since the point in time of selecting this option') })
</label>
<label>
<input type="radio" name="historyVis" value="invited"
disabled={ !roomState.mayClientSendStateEvent("m.room.history_visibility", cli) }
checked={historyVisibility === "invited"}
onChange={this._onHistoryRadioToggle} />
Members only (since they were invited)
{ _t('Members only') } ({ _t('since they were invited') })
</label>
<label >
<input type="radio" name="historyVis" value="joined"
disabled={ !roomState.mayClientSendStateEvent("m.room.history_visibility", cli) }
checked={historyVisibility === "joined"}
onChange={this._onHistoryRadioToggle} />
Members only (since they joined)
{ _t('Members only') } ({ _t('since they joined') })
</label>
</div>
</div>
<div>
<h3>Room Colour</h3>
<h3>{ _t('Room Colour') }</h3>
<ColorSettings ref="color_settings" room={this.props.room} />
</div>
@ -899,41 +900,41 @@ module.exports = React.createClass({
<UrlPreviewSettings ref="url_preview_settings" room={this.props.room} />
<h3>Permissions</h3>
<h3>{ _t('Permissions') }</h3>
<div className="mx_RoomSettings_powerLevels mx_RoomSettings_settings">
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">The default role for new room members is </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('The default role for new room members is') } </span>
<PowerSelector ref="users_default" value={default_user_level} controlled={false} disabled={!can_change_levels || current_user_level < default_user_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To send messages, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To send messages') }, { _t('you must be a') } </span>
<PowerSelector ref="events_default" value={send_level} controlled={false} disabled={!can_change_levels || current_user_level < send_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To invite users into the room, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To invite users into the room') }, { _t('you must be a') } </span>
<PowerSelector ref="invite" value={invite_level} controlled={false} disabled={!can_change_levels || current_user_level < invite_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To configure the room, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To configure the room') }, { _t('you must be a') } </span>
<PowerSelector ref="state_default" value={state_level} controlled={false} disabled={!can_change_levels || current_user_level < state_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To kick users, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To kick users') }, { _t('you must be a') } </span>
<PowerSelector ref="kick" value={kick_level} controlled={false} disabled={!can_change_levels || current_user_level < kick_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To ban users, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To ban users') }, { _t('you must be a') } </span>
<PowerSelector ref="ban" value={ban_level} controlled={false} disabled={!can_change_levels || current_user_level < ban_level} onChange={this.onPowerLevelsChanged}/>
</div>
<div className="mx_RoomSettings_powerLevel">
<span className="mx_RoomSettings_powerLevelKey">To redact other users' messages, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To redact other users\' messages') }, { _t('you must be a') } </span>
<PowerSelector ref="redact" value={redact_level} controlled={false} disabled={!can_change_levels || current_user_level < redact_level} onChange={this.onPowerLevelsChanged}/>
</div>
{Object.keys(events_levels).map(function(event_type, i) {
return (
<div className="mx_RoomSettings_powerLevel" key={event_type}>
<span className="mx_RoomSettings_powerLevelKey">To send events of type <code>{ event_type }</code>, you must be a </span>
<span className="mx_RoomSettings_powerLevelKey">{ _t('To send events of type') } <code>{ event_type }</code>, { _t('you must be a') } </span>
<PowerSelector value={ events_levels[event_type] } controlled={false} disabled={true} onChange={self.onPowerLevelsChanged}/>
</div>
);
@ -946,9 +947,9 @@ module.exports = React.createClass({
{ bannedUsersSection }
<h3>Advanced</h3>
<h3>{ _t('Advanced') }</h3>
<div className="mx_RoomSettings_settings">
This room's internal ID is <code>{ this.props.room.roomId }</code>
{ _t('This room\'s internal ID is') } <code>{ this.props.room.roomId }</code>
</div>
</div>
);

View file

@ -17,6 +17,7 @@ var React = require('react');
var MatrixClientPeg = require("../../../MatrixClientPeg");
var Modal = require("../../../Modal");
var sdk = require("../../../index");
import { _t } from '../../../languageHandler';
var GeminiScrollbar = require('react-gemini-scrollbar');
// A list capable of displaying entities which conform to the SearchableEntity
@ -25,7 +26,6 @@ var SearchableEntityList = React.createClass({
displayName: 'SearchableEntityList',
propTypes: {
searchPlaceholderText: React.PropTypes.string,
emptyQueryShowsAll: React.PropTypes.bool,
showInputBox: React.PropTypes.bool,
onQueryChanged: React.PropTypes.func, // fn(inputText)
@ -37,7 +37,6 @@ var SearchableEntityList = React.createClass({
getDefaultProps: function() {
return {
showInputBox: true,
searchPlaceholderText: "Search",
entities: [],
emptyQueryShowsAll: false,
onSubmit: function() {},
@ -118,7 +117,9 @@ var SearchableEntityList = React.createClass({
_createOverflowEntity: function(overflowCount, totalCount) {
var EntityTile = sdk.getComponent("rooms.EntityTile");
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
var text = "and " + overflowCount + " other" + (overflowCount > 1 ? "s" : "") + "...";
var text = (overflowCount > 1)
? _t("and %(overflowCount)s others...", { overflowCount: overflowCount })
: _t("and one other...");
return (
<EntityTile className="mx_EntityTile_ellipsis" avatarJsx={
<BaseAvatar url="img/ellipsis.svg" name="..." width={36} height={36} />
@ -137,7 +138,7 @@ var SearchableEntityList = React.createClass({
onChange={this.onQueryChanged} value={this.state.query}
onFocus= {() => { this.setState({ focused: true }); }}
onBlur= {() => { this.setState({ focused: false }); }}
placeholder={this.props.searchPlaceholderText} />
placeholder={ _t("Search") } />
</form>
);
}

View file

@ -18,6 +18,7 @@ limitations under the License.
'use strict';
var React = require('react');
import { _t } from '../../../languageHandler';
var sdk = require('../../../index');
module.exports = React.createClass({
@ -34,8 +35,8 @@ module.exports = React.createClass({
<div className="mx_TopUnreadMessagesBar_scrollUp"
onClick={this.props.onScrollUpClick}>
<img src="img/scrollto.svg" width="24" height="24"
alt="Scroll to unread messages"
title="Scroll to unread messages"/>
alt={ _t('Scroll to unread messages') }
title={ _t('Scroll to unread messages') }/>
Jump to first unread message.
</div>
<img className="mx_TopUnreadMessagesBar_close mx_filterFlipColor"
@ -46,4 +47,3 @@ module.exports = React.createClass({
);
},
});