Merge pull request #1056 from matrix-org/kegan/translation-tamarin

Add remaining translations
This commit is contained in:
Matthew Hodgson 2017-06-08 15:06:26 +01:00 committed by GitHub
commit f26aeef2bf
32 changed files with 217 additions and 99 deletions

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict';
var React = require('react');
import { _t } from '../../../languageHandler';
var Presets = {
PrivateChat: "private_chat",
@ -46,9 +47,9 @@ module.exports = React.createClass({
render: function() {
return (
<select className="mx_Presets" onChange={this.onValueChanged} value={this.props.preset}>
<option value={this.Presets.PrivateChat}>Private Chat</option>
<option value={this.Presets.PublicChat}>Public Chat</option>
<option value={this.Presets.Custom}>Custom</option>
<option value={this.Presets.PrivateChat}>{_t("Private Chat")}</option>
<option value={this.Presets.PublicChat}>{_t("Public Chat")}</option>
<option value={this.Presets.Custom}>{_t("Custom")}</option>
</select>
);
}

View file

@ -15,6 +15,7 @@ limitations under the License.
*/
var React = require('react');
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'RoomAlias',
@ -94,7 +95,7 @@ module.exports = React.createClass({
render: function() {
return (
<input type="text" className="mx_RoomAlias" placeholder="Alias (optional)"
<input type="text" className="mx_RoomAlias" placeholder={_t("Alias (optional)")}
onChange={this.onValueChanged} onFocus={this.onFocus} onBlur={this.onBlur}
value={this.props.alias}/>
);

View file

@ -86,7 +86,7 @@ export default class DeactivateAccountDialog extends React.Component {
passwordBoxClass = 'error';
}
const okLabel = this.state.busy ? <Loader /> : 'Deactivate Account';
const okLabel = this.state.busy ? <Loader /> : _t('Deactivate Account');
const okEnabled = this.state.confirmButtonEnabled && !this.state.busy;
let cancelButton = null;

View file

@ -78,7 +78,7 @@ export default React.createClass({
<AccessibleButton onClick={this._onDismissClick}
className="mx_UserSettings_button"
>
Dismiss
{_t("Dismiss")}
</AccessibleButton>
</div>
);

View file

@ -18,7 +18,7 @@ import React from 'react';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import { _t, _tJsx } from '../../../languageHandler';
export default React.createClass({
@ -44,8 +44,11 @@ export default React.createClass({
if (SdkConfig.get().bug_report_endpoint_url) {
bugreport = (
<p>Otherwise, <a onClick={this._sendBugReport} href='#'>
click here</a> to send a bug report.
<p>
{_tJsx(
"Otherwise, <a>click here</a> to send a bug report.",
/<a>(.*?)<\/a>/, (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{sub}</a>,
)}
</p>
);
}

View file

@ -145,7 +145,7 @@ export default React.createClass({
console.log("UnknownDeviceDialog closed by escape");
this.props.onFinished();
}}
title='Room contains unknown devices'
title={_t('Room contains unknown devices')}
>
<GeminiScrollbar autoshow={false} className="mx_Dialog_content">
<h4>
@ -162,7 +162,7 @@ export default React.createClass({
this.props.onFinished();
Resend.resendUnsentEvents(this.props.room);
}}>
Send anyway
{_t("Send anyway")}
</button>
<button className="mx_Dialog_primary" autoFocus={ true }
onClick={() => {

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';
module.exports = React.createClass({
displayName: 'TruncatedList',
@ -33,7 +34,7 @@ module.exports = React.createClass({
truncateAt: 2,
createOverflowElement: function(overflowCount, totalCount) {
return (
<div>And {overflowCount} more...</div>
<div>{_t("And %(count)s more...", {count: overflowCount})}</div>
);
}
};

View file

@ -440,7 +440,7 @@ export const FallbackAuthEntry = React.createClass({
render: function() {
return (
<div>
<a onClick={this._onShowFallbackClick}>Start authentication</a>
<a onClick={this._onShowFallbackClick}>{_t("Start authentication")}</a>
<div className="error">
{this.props.errorText}
</div>

View file

@ -101,7 +101,7 @@ module.exports = React.createClass({
if (this.refs.email.value == '') {
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
Modal.createDialog(QuestionDialog, {
title: "Warning!",
title: _t("Warning!"),
description:
<div>
{_t("If you don't specify an email address, you won't be able to reset your password. " +
@ -335,7 +335,7 @@ module.exports = React.createClass({
);
const registerButton = (
<input className="mx_Login_submit" type="submit" value="Register" />
<input className="mx_Login_submit" type="submit" value={_t("Register")} />
);
let placeholderUserName = _t("User name");

View file

@ -19,7 +19,7 @@ import MatrixClientPeg from "../../../MatrixClientPeg";
import sdk from '../../../index';
import dis from "../../../dispatcher";
import ObjectUtils from '../../../ObjectUtils';
import { _t } from '../../../languageHandler';
import { _t, _tJsx} from '../../../languageHandler';
module.exports = React.createClass({
@ -78,7 +78,7 @@ module.exports = React.createClass({
fileDropTarget = (
<div className="mx_RoomView_fileDropTarget">
<div className="mx_RoomView_fileDropTargetLabel"
title="Drop File Here">
title={_t("Drop File Here")}>
<TintableSvg src="img/upload-big.svg" width="45" height="59"/>
<br/>
{_t("Drop file here to upload")}
@ -95,9 +95,14 @@ module.exports = React.createClass({
}
else {
joinText = (<span>
Join as <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'voice');}}
href="#">voice</a> or <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'video'); }}
href="#">video</a>.
{_tJsx(
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.",
[/<voiceText>(.*?)<\/voiceText>/, /<videoText>(.*?)<\/videoText>/],
[
(sub) => <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'voice');}} href="#">{sub}</a>,
(sub) => <a onClick={(event)=>{ this.onConferenceNotificationClick(event, 'video');}} href="#">{sub}</a>,
]
)}
</span>);
}

View file

@ -21,6 +21,7 @@ var React = require('react');
var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require('../../../index');
import AccessibleButton from '../elements/AccessibleButton';
import { _t } from '../../../languageHandler';
var PRESENCE_CLASS = {
@ -140,10 +141,10 @@ module.exports = React.createClass({
var power;
var powerLevel = this.props.powerLevel;
if (powerLevel >= 50 && powerLevel < 99) {
power = <img src="img/mod.svg" className="mx_EntityTile_power" width="16" height="17" alt="Mod"/>;
power = <img src="img/mod.svg" className="mx_EntityTile_power" width="16" height="17" alt={_t("Moderator")}/>;
}
if (powerLevel >= 99) {
power = <img src="img/admin.svg" className="mx_EntityTile_power" width="16" height="17" alt="Admin"/>;
power = <img src="img/admin.svg" className="mx_EntityTile_power" width="16" height="17" alt={_t("Admin")}/>;
}

View file

@ -487,22 +487,22 @@ module.exports = WithMatrixClient(React.createClass({
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" />;
e2e = <img style={{ cursor: 'initial', marginLeft: '-1px' }} className="mx_EventTile_e2eIcon" alt={_t("Encrypted by a verified device")} src="img/e2e-verified.svg" width="10" height="12" />;
}
// real padlocks
else if (this.props.mxEvent.isEncrypted() || (e2eEnabled && this.props.eventSendStatus)) {
if (this.props.mxEvent.getContent().msgtype === 'm.bad.encrypted') {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Undecryptable" src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} />;
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt={_t("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={_t("Encrypted by a 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" }}/>;
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt={_t("Encrypted by an unverified device")} src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }}/>;
}
}
else if (e2eEnabled) {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Unencrypted message" src="img/e2e-unencrypted.svg" width="12" height="12"/>;
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt={_t("Unencrypted message")} src="img/e2e-unencrypted.svg" width="12" height="12"/>;
}
const timestamp = this.props.mxEvent.getTs() ?
<MessageTimestamp showTwelveHour={this.props.isTwelveHour} ts={this.props.mxEvent.getTs()} /> : null;

View file

@ -26,19 +26,19 @@ export default class MemberDeviceInfo extends React.Component {
if (this.props.device.isBlocked()) {
indicator = (
<div className="mx_MemberDeviceInfo_blacklisted">
<img src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} alt="Blacklisted"/>
<img src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} alt={_t("Blacklisted")}/>
</div>
);
} else if (this.props.device.isVerified()) {
indicator = (
<div className="mx_MemberDeviceInfo_verified">
<img src="img/e2e-verified.svg" width="10" height="12" alt="Verified"/>
<img src="img/e2e-verified.svg" width="10" height="12" alt={_t("Verified")}/>
</div>
);
} else {
indicator = (
<div className="mx_MemberDeviceInfo_unverified">
<img src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }} alt="Unverified"/>
<img src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }} alt={_t("Unverified")}/>
</div>
);
}

View file

@ -432,7 +432,7 @@ module.exports = WithMatrixClient(React.createClass({
title: _t("Warning!"),
description:
<div>
{ _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("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: _t("Continue"),
@ -701,7 +701,7 @@ module.exports = WithMatrixClient(React.createClass({
if (kickButton || banButton || muteButton || giveModButton) {
adminTools =
<div>
<h3>Admin tools</h3>
<h3>{_t("Admin tools")}</h3>
<div className="mx_MemberInfo_buttons">
{muteButton}
@ -739,7 +739,7 @@ module.exports = WithMatrixClient(React.createClass({
{ this.props.member.userId }
</div>
<div className="mx_MemberInfo_profileField">
{ _t("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

@ -22,6 +22,7 @@ var MatrixClientPeg = require('../../../MatrixClientPeg');
var sdk = require('../../../index');
var dis = require('../../../dispatcher');
var Modal = require("../../../Modal");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'MemberTile',
@ -63,7 +64,7 @@ module.exports = React.createClass({
},
getPowerLabel: function() {
return this.props.member.userId + " (power " + this.props.member.powerLevel + ")";
return _t("%(userName)s (power %(powerLevelNumber)s)", {userName: this.props.member.userId, powerLevelNumber: this.props.member.powerLevel});
},
render: function() {

View file

@ -109,7 +109,7 @@ export default class MessageComposer extends React.Component {
let fileList = [];
for (let i=0; i<files.length; i++) {
fileList.push(<li key={i}>
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> {files[i].name || 'Attachment'}
<TintableSvg key={i} src="img/files.svg" width="16" height="16" /> {files[i].name || _t('Attachment')}
</li>);
}
@ -287,7 +287,7 @@ export default class MessageComposer extends React.Component {
const formattingButton = (
<img className="mx_MessageComposer_formatting"
title="Show Text Formatting Toolbar"
title={_t("Show Text Formatting Toolbar")}
src="img/button-text-formatting.svg"
onClick={this.onToggleFormattingClicked}
style={{visibility: this.state.showFormatting ||

View file

@ -23,6 +23,7 @@ var sdk = require('../../../index');
var Velociraptor = require('../../../Velociraptor');
require('../../../VelocityBounce');
import { _t } from '../../../languageHandler';
import DateUtils from '../../../DateUtils';
@ -169,8 +170,10 @@ module.exports = React.createClass({
let title;
if (this.props.timestamp) {
title = "Seen by " + this.props.member.userId + " at " +
DateUtils.formatDate(new Date(this.props.timestamp));
title = _t(
"Seen by %(userName)s at %(dateTime)s",
{userName: this.props.member.userId, dateTime: DateUtils.formatDate(new Date(this.props.timestamp))}
);
}
return (

View file

@ -213,7 +213,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;{ _t("(~%(searchCount)s results)", { searchCount: this.props.searchInfo.searchCount }) }</div>;
searchStatus = <div className="mx_RoomHeader_searchStatus">&nbsp;{ _t("(~%(count)s results)", { count: this.props.searchInfo.searchCount }) }</div>;
}
// XXX: this is a bit inefficient - we could just compare room.name for 'Empty room'...
@ -288,7 +288,7 @@ module.exports = React.createClass({
var settings_button;
if (this.props.onSettingsClick) {
settings_button =
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSettingsClick} title="Settings">
<AccessibleButton className="mx_RoomHeader_button" onClick={this.props.onSettingsClick} title={_t("Settings")}>
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/>
</AccessibleButton>;
}

View file

@ -19,6 +19,7 @@ limitations under the License.
var React = require('react');
var sdk = require('../../../index');
var MatrixClientPeg = require('../../../MatrixClientPeg');
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'RoomNameEditor',
@ -35,8 +36,8 @@ module.exports = React.createClass({
this._initialName = name ? name.getContent().name : '';
this._placeholderName = "Unnamed Room";
if (defaultName && defaultName !== 'Empty room') {
this._placeholderName = _t("Unnamed Room");
if (defaultName && defaultName !== 'Empty room') { // default name from JS SDK, needs no translation as we don't ever show it.
this._placeholderName += " (" + defaultName + ")";
}
},

View file

@ -21,7 +21,7 @@ var React = require('react');
var sdk = require('../../../index');
var MatrixClientPeg = require('../../../MatrixClientPeg');
import { _t } from '../../../languageHandler';
import { _t, _tJsx } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'RoomPreviewBar',
@ -84,7 +84,7 @@ module.exports = React.createClass({
},
_roomNameElement: function(fallback) {
fallback = fallback || 'a room';
fallback = fallback || _t('a room');
const name = this.props.room ? this.props.room.name : (this.props.room_alias || "");
return name ? name : fallback;
},
@ -114,8 +114,7 @@ module.exports = React.createClass({
if (this.props.invitedEmail) {
if (this.state.threePidFetchError) {
emailMatchBlock = <div className="error">
Unable to ascertain that the address this invite was
sent to matches one associated with your account.
{_t("Unable to ascertain that the address this invite was sent to matches one associated with your account.")}
</div>;
} else if (this.state.invitedEmailMxid != MatrixClientPeg.get().credentials.userId) {
emailMatchBlock =
@ -124,28 +123,35 @@ module.exports = React.createClass({
<img src="img/warning.svg" width="24" height="23" title= "/!\\" alt="/!\\" />
</div>
<div className="mx_RoomPreviewBar_warningText">
This invitation was sent to <b><span className="email">{this.props.invitedEmail}</span></b>, which is not associated with this account.<br/>
You may wish to login with a different account, or add this email to this account.
{_t("This invitation was sent to an email address which is not associated with this account:")}
<b><span className="email">{this.props.invitedEmail}</span></b>
<br/>
{_t("You may wish to login with a different account, or add this email to this account.")}
</div>
</div>;
}
}
// TODO: find a way to respect HTML in counterpart!
joinBlock = (
<div>
<div className="mx_RoomPreviewBar_invite_text">
{ _t('You have been invited to join this room by %(inviterName)s', {inviterName: this.props.inviterName}) }
</div>
<div className="mx_RoomPreviewBar_join_text">
{ _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?') }
{ _tJsx(
'Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?',
[/<acceptText>(.*?)<\/acceptText>/, /<declineText>(.*?)<\/declineText>/],
[
(sub) => <a onClick={ this.props.onJoinClick }>{sub}</a>,
(sub) => <a onClick={ this.props.onRejectClick }>{sub}</a>
]
)}
</div>
{emailMatchBlock}
</div>
);
} else if (kicked || banned) {
const verb = kicked ? 'kicked' : 'banned';
const roomName = this._roomNameElement('this room');
const roomName = this._roomNameElement(_t('This room'));
const kickerMember = this.props.room.currentState.getMember(
myMember.events.member.getSender()
);
@ -153,29 +159,39 @@ module.exports = React.createClass({
kickerMember.name : myMember.events.member.getSender();
let reason;
if (myMember.events.member.getContent().reason) {
reason = <div>Reason: {myMember.events.member.getContent().reason}</div>
reason = <div>{_t("Reason: %(reasonText)s", {reasonText: myMember.events.member.getContent().reason})}</div>
}
let rejoinBlock;
if (!banned) {
rejoinBlock = <div><a onClick={ this.props.onJoinClick }><b>Rejoin</b></a></div>;
rejoinBlock = <div><a onClick={ this.props.onJoinClick }><b>{_t("Rejoin")}</b></a></div>;
}
let actionText;
if (kicked) {
actionText = _t("You have been kicked from %(roomName)s by %(userName)s.", {roomName: roomName, userName: kickerName});
}
else if (banned) {
actionText = _t("You have been banned from %(roomName)s by %(userName)s.", {roomName: roomName, userName: kickerName});
} // no other options possible due to the kicked || banned check above.
joinBlock = (
<div>
<div className="mx_RoomPreviewBar_join_text">
You have been {verb} from {roomName} by {kickerName}.<br />
{actionText}
<br />
{reason}
{rejoinBlock}
<a onClick={ this.props.onForgetClick }><b>Forget</b></a>
<a onClick={ this.props.onForgetClick }><b>{_t("Forget room")}</b></a>
</div>
</div>
);
} else if (this.props.error) {
var name = this.props.roomAlias || "This room";
var name = this.props.roomAlias || _t("This room");
var error;
if (this.props.error.errcode == 'M_NOT_FOUND') {
error = name + " does not exist";
error = _t("%(roomName)s does not exist.", {roomName: name});
} else {
error = name + " is not accessible at this time";
error = _t("%(roomName)s is not accessible at this time.", {roomName: name});
}
joinBlock = (
<div>
@ -189,8 +205,12 @@ module.exports = React.createClass({
joinBlock = (
<div>
<div className="mx_RoomPreviewBar_join_text">
{ _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') }!
{ _t('You are trying to access %(roomName)s.', {roomName: name}) }
<br/>
{ _tJsx("<a>Click here</a> to join the discussion!",
/<a>(.*?)<\/a>/,
(sub) => <a onClick={ this.props.onJoinClick }><b>{sub}</b></a>
)}
</div>
</div>
);

View file

@ -17,7 +17,7 @@ limitations under the License.
import q from 'q';
import React from 'react';
import { _t } from '../../../languageHandler';
import { _t, _tJsx } from '../../../languageHandler';
import MatrixClientPeg from '../../../MatrixClientPeg';
import SdkConfig from '../../../SdkConfig';
import sdk from '../../../index';
@ -46,7 +46,7 @@ const BannedUser = React.createClass({
const ConfirmUserActionDialog = sdk.getComponent("dialogs.ConfirmUserActionDialog");
Modal.createDialog(ConfirmUserActionDialog, {
member: this.props.member,
action: 'Unban',
action: _t('Unban'),
danger: false,
onFinished: (proceed) => {
if (!proceed) return;
@ -597,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" />
}
{ isEncrypted ? "Encryption is enabled in this room" : "Encryption is not enabled in this room" }.
{ isEncrypted ? _t("Encryption is enabled in this room") : _t("Encryption is not enabled in this room") }.
</label>
{ settings }
</div>
@ -653,7 +653,7 @@ module.exports = React.createClass({
{Object.keys(user_levels).map(function(user, i) {
return (
<li className="mx_RoomSettings_userLevel" key={user}>
{ user } { _t('is a') } <PowerSelector value={ user_levels[user] } disabled={true}/>
{ _t("%(user)s is a", {user: user}) } <PowerSelector value={ user_levels[user] } disabled={true}/>
</li>
);
})}
@ -754,7 +754,11 @@ module.exports = React.createClass({
if (this.state.join_rule === "public" && aliasCount == 0) {
addressWarning =
<div className="mx_RoomSettings_warning">
{ _t('To link to a room it must have') } <a href="#addresses"> { _t('an address') }</a>.
{ _tJsx(
'To link to a room it must have <a>an address</a>.',
/<a>(.*?)<\/a>/,
(sub) => <a href="#addresses">{sub}</a>
)}
</div>;
}

View file

@ -20,6 +20,7 @@ import React from 'react';
import dis from '../../../dispatcher';
import AccessibleButton from '../elements/AccessibleButton';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
// cancel button which is shared between room header and simple room header
export function CancelButton(props) {
@ -28,7 +29,7 @@ export function CancelButton(props) {
return (
<AccessibleButton className='mx_RoomHeader_cancelButton' onClick={onClick}>
<img src="img/cancel.svg" className='mx_filterFlipColor'
width="18" height="18" alt="Cancel"/>
width="18" height="18" alt={_t("Cancel")}/>
</AccessibleButton>
);
}

View file

@ -41,7 +41,7 @@ module.exports = React.createClass({
</div>
<img className="mx_TopUnreadMessagesBar_close mx_filterFlipColor"
src="img/cancel.svg" width="18" height="18"
alt="Close" title="Close"
alt={_t("Close")} title={_t("Close")}
onClick={this.props.onCloseClick} />
</div>
);

View file

@ -165,7 +165,7 @@ export default WithMatrixClient(React.createClass({
</div>
</div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<input type="image" value="Add" src="img/plus.svg" width="14" height="14" />
<input type="image" value={_t("Add")} src="img/plus.svg" width="14" height="14" />
</div>
</form>
);

View file

@ -17,6 +17,7 @@ limitations under the License.
var React = require('react');
var MatrixClientPeg = require("../../../MatrixClientPeg");
var sdk = require('../../../index');
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'ChangeAvatar',
@ -105,7 +106,7 @@ module.exports = React.createClass({
onError: function(error) {
this.setState({
errorText: "Failed to upload profile picture!"
errorText: _t("Failed to upload profile picture!")
});
},
@ -127,7 +128,7 @@ module.exports = React.createClass({
if (this.props.showUploadSection) {
uploadSection = (
<div className={this.props.className}>
Upload new:
{_t("Upload new:")}
<input type="file" accept="image/*" onChange={this.onFileSelected}/>
{this.state.errorText}
</div>

View file

@ -18,6 +18,7 @@ limitations under the License.
var React = require('react');
var sdk = require('../../../index');
var MatrixClientPeg = require("../../../MatrixClientPeg");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'ChangeDisplayName',
@ -52,7 +53,7 @@ module.exports = React.createClass({
return (
<EditableTextContainer
getInitialValue={this._getDisplayName}
placeholder="No display name"
placeholder={_t("No display name")}
blurToSubmit={true}
onSubmit={this._changeDisplayName} />
);

View file

@ -53,7 +53,7 @@ module.exports = React.createClass({
onCheckPassword: function(oldPass, newPass, confirmPass) {
if (newPass !== confirmPass) {
return {
error: _t("New passwords don't match") + "."
error: _t("New passwords don't match")
};
} else if (!newPass || newPass.length === 0) {
return {

View file

@ -19,6 +19,7 @@ import classNames from 'classnames';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
export default class DevicesPanel extends React.Component {
@ -54,10 +55,10 @@ export default class DevicesPanel extends React.Component {
var errtxt;
if (error.httpStatus == 404) {
// 404 probably means the HS doesn't yet support the API.
errtxt = "Your home server does not support device management.";
errtxt = _t("Your home server does not support device management.");
} else {
console.error("Error loading devices:", error);
errtxt = "Unable to load device list.";
errtxt = _t("Unable to load device list");
}
this.setState({deviceLoadError: errtxt});
}
@ -127,9 +128,9 @@ export default class DevicesPanel extends React.Component {
return (
<div className={classes}>
<div className="mx_DevicesPanel_header">
<div className="mx_DevicesPanel_deviceId">ID</div>
<div className="mx_DevicesPanel_deviceName">Name</div>
<div className="mx_DevicesPanel_deviceLastSeen">Last seen</div>
<div className="mx_DevicesPanel_deviceId">{_t("Device ID")}</div>
<div className="mx_DevicesPanel_deviceName">{_t("Device Name")}</div>
<div className="mx_DevicesPanel_deviceLastSeen">{_t("Last seen")}</div>
<div className="mx_DevicesPanel_deviceButtons"></div>
</div>
{devices.map(this._renderDevice)}

View file

@ -18,6 +18,7 @@ limitations under the License.
var React = require("react");
var Notifier = require("../../../Notifier");
var dis = require("../../../dispatcher");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'EnableNotificationsButton',
@ -60,13 +61,13 @@ module.exports = React.createClass({
if (this.enabled()) {
return (
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>
Disable Notifications
{_t("Disable Notifications")}
</button>
);
} else {
return (
<button className="mx_EnableNotificationsButton" onClick={this.onClick}>
Enable Notifications
{_t("Enable Notifications")}
</button>
);
}

View file

@ -18,6 +18,7 @@ var dis = require("../../../dispatcher");
var CallHandler = require("../../../CallHandler");
var sdk = require('../../../index');
var MatrixClientPeg = require("../../../MatrixClientPeg");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'CallView',
@ -130,7 +131,11 @@ module.exports = React.createClass({
var voice;
if (this.state.call && this.state.call.type === "voice" && this.props.showVoice) {
var callRoom = MatrixClientPeg.get().getRoom(this.state.call.roomId);
voice = <div className="mx_CallView_voice" onClick={ this.props.onClick }>Active call ({ callRoom.name })</div>;
voice = (
<div className="mx_CallView_voice" onClick={ this.props.onClick }>
{_t("Active call (%(roomName)s)", {roomName: callRoom.name})}
</div>
);
}
return (

View file

@ -17,6 +17,7 @@ var React = require('react');
var MatrixClientPeg = require('../../../MatrixClientPeg');
var dis = require("../../../dispatcher");
var CallHandler = require("../../../CallHandler");
import { _t } from '../../../languageHandler';
module.exports = React.createClass({
displayName: 'IncomingCallBox',
@ -45,23 +46,36 @@ module.exports = React.createClass({
room = MatrixClientPeg.get().getRoom(this.props.incomingCall.roomId);
}
var caller = room ? room.name : "unknown";
var caller = room ? room.name : _t("unknown caller");
let incomingCallText = null;
if (this.props.incomingCall) {
if (this.props.incomingCall.type === "voice") {
incomingCallText = _t("Incoming voice call from %(name)s", {name: caller});
}
else if (this.props.incomingCall.type === "video") {
incomingCallText = _t("Incoming video call from %(name)s", {name: caller});
}
else {
incomingCallText = _t("Incoming call from %(name)s", {name: caller});
}
}
return (
<div className="mx_IncomingCallBox" id="incomingCallBox">
<img className="mx_IncomingCallBox_chevron" src="img/chevron-left.png" width="9" height="16" />
<div className="mx_IncomingCallBox_title">
Incoming { this.props.incomingCall ? this.props.incomingCall.type : '' } call from { caller }
{incomingCallText}
</div>
<div className="mx_IncomingCallBox_buttons">
<div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_decline" onClick={this.onRejectClick}>
Decline
{_t("Decline")}
</div>
</div>
<div className="mx_IncomingCallBox_buttons_cell">
<div className="mx_IncomingCallBox_buttons_accept" onClick={this.onAnswerClick}>
Accept
{_t("Accept")}
</div>
</div>
</div>

View file

@ -120,17 +120,21 @@
"zh-tw":"Chinese (Taiwan)",
"zu":"Zulu",
"A registered account is required for this action": "A registered account is required for this action",
"a room": "a room",
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains",
"accept": "accept",
"Accept": "Accept",
"%(targetName)s accepted an invitation.": "%(targetName)s accepted an invitation.",
"%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.",
"Account": "Account",
"Access Token:": "Access Token:",
"Active call (%(roomName)s)": "Active call (%(roomName)s)",
"Add": "Add",
"Add a topic": "Add a topic",
"Add email address": "Add email address",
"Add phone number": "Add phone number",
"Admin": "Admin",
"Admin tools": "Admin tools",
"And %(count)s more...": "And %(count)s more...",
"VoIP": "VoIP",
"Missing Media Permissions, click here to request.": "Missing Media Permissions, click here to request.",
"No Microphones detected": "No Microphones detected",
@ -145,10 +149,10 @@
"Hide removed messages": "Hide removed messages",
"Always show message timestamps": "Always show message timestamps",
"Authentication": "Authentication",
"Alias (optional)": "Alias (optional)",
"all room members": "all room members",
"all room members, from the point they are invited": "all room members, from the point they are invited",
"all room members, from the point they joined": "all room members, from the point they joined",
"an address": "an address",
"and": "and",
"%(items)s and %(remaining)s others": "%(items)s and %(remaining)s others",
"%(items)s and one other": "%(items)s and one other",
@ -197,13 +201,14 @@
"Claimed Ed25519 fingerprint key": "Claimed Ed25519 fingerprint key",
"Clear Cache and Reload": "Clear Cache and Reload",
"Clear Cache": "Clear Cache",
"Click here": "Click here",
"<a>Click here</a> to join the discussion!": "<a>Click here</a> to join the discussion!",
"Click here to fix": "Click here to fix",
"Click to mute audio": "Click to mute audio",
"Click to mute video": "Click to mute video",
"click to reveal": "click to reveal",
"Click to unmute video": "Click to unmute video",
"Click to unmute audio": "Click to unmute audio",
"Close": "Close",
"Command error": "Command error",
"Commands": "Commands",
"Conference call failed.": "Conference call failed.",
@ -218,16 +223,18 @@
"one": "%(count)s new message",
"other": "%(count)s new messages"
},
"Create a new chat or reuse an existing one": "Create a new chat or reuse an existing one",
"Create an account": "Create an account",
"Create Room": "Create Room",
"Cryptography": "Cryptography",
"Current password": "Current password",
"Curve25519 identity key": "Curve25519 identity key",
"Custom": "Custom",
"Custom level": "Custom level",
"/ddg is not a command": "/ddg is not a command",
"Deactivate Account": "Deactivate Account",
"Deactivate my account": "Deactivate my account",
"decline": "decline",
"Decline": "Decline",
"Decrypt %(text)s": "Decrypt %(text)s",
"Decryption error": "Decryption error",
"(default: %(userName)s)": "(default: %(userName)s)",
@ -244,6 +251,7 @@
"Devices will not yet be able to decrypt history from before they joined the room": "Devices will not yet be able to decrypt history from before they joined the room",
"Direct Chat": "Direct Chat",
"Direct chats": "Direct chats",
"Disable Notifications": "Disable Notifications",
"disabled": "disabled",
"Disable inline URL previews by default": "Disable inline URL previews by default",
"Disable markdown formatting": "Disable markdown formatting",
@ -252,6 +260,7 @@
"Displays action": "Displays action",
"Don't send typing notifications": "Don't send typing notifications",
"Download %(text)s": "Download %(text)s",
"Drop File Here": "Drop File Here",
"Drop here %(toAction)s": "Drop here %(toAction)s",
"Drop here to tag %(section)s": "Drop here to tag %(section)s",
"Ed25519 fingerprint": "Ed25519 fingerprint",
@ -261,9 +270,14 @@
"Email, name or matrix ID": "Email, name or matrix ID",
"Emoji": "Emoji",
"Enable encryption": "Enable encryption",
"Enable Notifications": "Enable Notifications",
"enabled": "enabled",
"Encrypted by a verified device": "Encrypted by a verified device",
"Encrypted by an unverified device": "Encrypted by an unverified device",
"Encrypted messages will not be visible on clients that do not yet implement encryption": "Encrypted messages will not be visible on clients that do not yet implement encryption",
"Encrypted room": "Encrypted room",
"Encryption is enabled in this room": "Encryption is enabled in this room",
"Encryption is not enabled in this room": "Encryption is not enabled in this room",
"%(senderName)s ended the call.": "%(senderName)s ended the call.",
"End-to-end encryption information": "End-to-end encryption information",
"End-to-end encryption is in beta and may not be reliable": "End-to-end encryption is in beta and may not be reliable",
@ -301,6 +315,7 @@
"Failed to toggle moderator status": "Failed to toggle moderator status",
"Failed to unban": "Failed to unban",
"Failed to upload file": "Failed to upload file",
"Failed to upload profile picture!": "Failed to upload profile picture!",
"Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email",
"Failure to create room": "Failure to create room",
"Favourite": "Favourite",
@ -331,6 +346,9 @@
"I have verified my email address": "I have verified my email address",
"Import": "Import",
"Import E2E room keys": "Import E2E room keys",
"Incoming call from %(name)s": "Incoming call from %(name)s",
"Incoming video call from %(name)s": "Incoming video call from %(name)s",
"Incoming voice call from %(name)s": "Incoming voice call from %(name)s",
"Incorrect username and/or password.": "Incorrect username and/or password.",
"Incorrect verification code": "Incorrect verification code",
"Interface Language": "Interface Language",
@ -343,11 +361,11 @@
"Invited": "Invited",
"Invites": "Invites",
"Invites user with given id to current room": "Invites user with given id to current room",
"is a": "is a",
"'%(alias)s' is not a valid format for an address": "'%(alias)s' is not a valid format for an address",
"'%(alias)s' is not a valid format for an alias": "'%(alias)s' is not a valid format for an alias",
"%(displayName)s is typing": "%(displayName)s is typing",
"Sign in with": "Sign in with",
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.",
"Join Room": "Join Room",
"joined and left": "joined and left",
"joined": "joined",
@ -358,11 +376,12 @@
"Kick": "Kick",
"Kicks user with given id": "Kicks user with given id",
"Labs": "Labs",
"Last seen": "Last seen",
"Leave room": "Leave room",
"left and rejoined": "left and rejoined",
"left": "left",
"%(targetName)s left the room.": "%(targetName)s left the room.",
"Level": "Level",
"Level:": "Level:",
"List this room in %(domain)s's room directory?": "List this room in %(domain)s's room directory?",
"Local addresses for this room:": "Local addresses for this room:",
"Logged in as:": "Logged in as:",
@ -401,6 +420,7 @@
"<not supported>": "<not supported>",
"NOT verified": "NOT verified",
"No devices with registered encryption keys": "No devices with registered encryption keys",
"No display name": "No display name",
"No more results": "No more results",
"No results": "No results",
"No users have specific privileges in this room": "No users have specific privileges in this room",
@ -410,6 +430,7 @@
"Once you&#39;ve followed the link it contains, click below": "Once you&#39;ve followed the link it contains, click below",
"Only people who have been invited": "Only people who have been invited",
"Operation failed": "Operation failed",
"Otherwise, <a>click here</a> to send a bug report.": "Otherwise, <a>click here</a> to send a bug report.",
"Password": "Password",
"Password:": "Password:",
"Passwords can't be empty": "Passwords can't be empty",
@ -422,9 +443,12 @@
"Power level must be positive integer.": "Power level must be positive integer.",
"Press": "Press",
"Privacy warning": "Privacy warning",
"Private Chat": "Private Chat",
"Privileged Users": "Privileged Users",
"Profile": "Profile",
"Public Chat": "Public Chat",
"Reason": "Reason",
"Reason: %(reasonText)s": "Reason: %(reasonText)s",
"Revoke Moderator": "Revoke Moderator",
"Refer a friend to Riot:": "Refer a friend to Riot:",
"Register": "Register",
@ -432,6 +456,7 @@
"rejected": "rejected",
"%(targetName)s rejected the invitation.": "%(targetName)s rejected the invitation.",
"Reject invitation": "Reject invitation",
"Rejoin": "Rejoin",
"Remote addresses for this room:": "Remote addresses for this room:",
"Remove Contact Information?": "Remove Contact Information?",
"%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s removed their display name (%(oldDisplayName)s).",
@ -450,7 +475,10 @@
"riot-web version:": "riot-web version:",
"Room %(roomId)s not visible": "Room %(roomId)s not visible",
"Room Colour": "Room Colour",
"Room contains unknown devices": "Room contains unknown devices",
"Room name (optional)": "Room name (optional)",
"%(roomName)s does not exist.": "%(roomName)s does not exist.",
"%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.",
"Rooms": "Rooms",
"Save": "Save",
"Scroll to bottom of page": "Scroll to bottom of page",
@ -458,8 +486,11 @@
"Search": "Search",
"Search failed": "Search failed",
"Searches DuckDuckGo for results": "Searches DuckDuckGo for results",
"Searching known users": "Searching known users",
"Seen by %(userName)s at %(dateTime)s": "Seen by %(userName)s at %(dateTime)s",
"Send a message (unencrypted)": "Send a message (unencrypted)",
"Send an encrypted message": "Send an encrypted message",
"Send anyway": "Send anyway",
"Sender device information": "Sender device information",
"Send Invites": "Send Invites",
"Send Reset Email": "Send Reset Email",
@ -476,9 +507,11 @@
"Session ID": "Session ID",
"%(senderName)s set a profile picture.": "%(senderName)s set a profile picture.",
"%(senderName)s set their display name to %(displayName)s.": "%(senderName)s set their display name to %(displayName)s.",
"Set": "Set",
"Setting a user name will create a fresh account": "Setting a user name will create a fresh account",
"Settings": "Settings",
"Show panel": "Show panel",
"Show Text Formatting Toolbar": "Show Text Formatting Toolbar",
"Show timestamps in 12 hour format (e.g. 2:30pm)": "Show timestamps in 12 hour format (e.g. 2:30pm)",
"Signed Out": "Signed Out",
"Sign in": "Sign in",
@ -490,6 +523,7 @@
"Someone": "Someone",
"Sorry, this homeserver is using a login which is not recognised ": "Sorry, this homeserver is using a login which is not recognised ",
"Start a chat": "Start a chat",
"Start authentication": "Start authentication",
"Start Chat": "Start Chat",
"Submit": "Submit",
"Success": "Success",
@ -500,7 +534,7 @@
"The main address for this room is": "The main address for this room is",
"The phone number entered looks invalid": "The phone number entered looks invalid",
"The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.",
"This action cannot be performed by a guest user. Please register to be able to do this": "This action cannot be performed by a guest user. Please register to be able to do this",
"This action cannot be performed by a guest user. Please register to be able to do this.": "This action cannot be performed by a guest user. Please register to be able to do this.",
"This email address is already in use": "This email address is already in use",
"This email address was not found": "This email address was not found",
"%(actionVerb)s this person?": "%(actionVerb)s this person?",
@ -509,15 +543,16 @@
"The file '%(fileName)s' failed to upload": "The file '%(fileName)s' failed to upload",
"The remote side failed to pick up": "The remote side failed to pick up",
"This Home Server does not support login using email address.": "This Home Server does not support login using email address.",
"This invitation was sent to an email address which is not associated with this account:": "This invitation was sent to an email address which is not associated with this account:",
"There was a problem logging in.": "There was a problem logging in.",
"This room has no local addresses": "This room has no local addresses",
"This room is not recognised.": "This room is not recognised.",
"These are experimental features that may break in unexpected ways": "These are experimental features that may break in unexpected ways",
"The visibility of existing history will be unchanged": "The visibility of existing history will be unchanged",
"This doesn't appear to be a valid email address": "This doesn't appear to be a valid email address",
"this invitation?": "this invitation?",
"This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled",
"This phone number is already in use": "This phone number is already in use",
"This room": "This room",
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
"This room's internal ID is": "This room's internal ID is",
"times": "times",
@ -527,9 +562,8 @@
"to demote": "to demote",
"to favourite": "to favourite",
"To invite users into the room": "To invite users into the room",
"to join the discussion": "to join the discussion",
"To kick users": "To kick users",
"To link to a room it must have": "To link to a room it must have",
"To link to a room it must have <a>an address</a>.": "To link to a room it must have <a>an address</a>.",
"to make a room or": "to make a room or",
"To remove other users' messages": "To remove other users' messages",
"To reset your password, enter the email address linked to your account": "To reset your password, enter the email address linked to your account",
@ -551,11 +585,15 @@
"Unable to verify email address.": "Unable to verify email address.",
"Unban": "Unban",
"%(senderName)s unbanned %(targetName)s.": "%(senderName)s unbanned %(targetName)s.",
"Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Unable to ascertain that the address this invite was sent to matches one associated with your account.",
"Unable to capture screen": "Unable to capture screen",
"Unable to enable Notifications": "Unable to enable Notifications",
"Unable to load device list": "Unable to load device list",
"Undecryptable": "Undecryptable",
"Unencrypted room": "Unencrypted room",
"unencrypted": "unencrypted",
"Unencrypted message": "Unencrypted message",
"unknown caller": "unknown caller",
"Unknown command": "Unknown command",
"unknown device": "unknown device",
"unknown error code": "unknown error code",
@ -563,8 +601,10 @@
"Unknown (user, device) pair:": "Unknown (user, device) pair:",
"unknown": "unknown",
"Unmute": "Unmute",
"Unnamed Room": "Unnamed Room",
"Unrecognised command:": "Unrecognised command:",
"Unrecognised room alias:": "Unrecognised room alias:",
"Unverified": "Unverified",
"Uploading %(filename)s and %(count)s others": {
"zero": "Uploading %(filename)s",
"one": "Uploading %(filename)s and %(count)s other",
@ -575,18 +615,22 @@
"Upload Failed": "Upload Failed",
"Upload Files": "Upload Files",
"Upload file": "Upload file",
"Upload new:": "Upload new:",
"Usage": "Usage",
"Use compact timeline layout": "Use compact timeline layout",
"Use with caution": "Use with caution",
"User ID": "User ID",
"User Interface": "User Interface",
"%(user)s is a": "%(user)s is a",
"User name": "User name",
"%(userName)s (power %(powerLevelNumber)s)": "%(userName)s (power %(powerLevelNumber)s)",
"Username invalid: %(errMessage)s": "Username invalid: %(errMessage)s",
"Users": "Users",
"User": "User",
"Verification Pending": "Verification Pending",
"Verification": "Verification",
"verified": "verified",
"Verified": "Verified",
"Verified key": "Verified key",
"Video call": "Video call",
"Voice call": "Voice call",
@ -603,19 +647,23 @@
"Who would you like to communicate with?": "Who would you like to communicate with?",
"Searching known users": "Searching known users",
"%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s withdrew %(targetName)s's invitation.",
"Would you like to": "Would you like to",
"Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?": "Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?",
"You already have existing direct chats with this user:": "You already have existing direct chats with this user:",
"You are already in a call.": "You are already in a call.",
"You're not in any rooms yet! Press": "You're not in any rooms yet! Press",
"You are trying to access %(roomName)s": "You are trying to access %(roomName)s",
"You are trying to access %(roomName)s.": "You are trying to access %(roomName)s.",
"You cannot place a call with yourself.": "You cannot place a call with yourself.",
"You cannot place VoIP calls in this browser.": "You cannot place VoIP calls in this browser.",
"You do not have permission to post to this room": "You do not have permission to post to this room",
"You have been banned from %(roomName)s by %(userName)s.": "You have been banned from %(roomName)s by %(userName)s.",
"You have been invited to join this room by %(inviterName)s": "You have been invited to join this room by %(inviterName)s",
"You have been kicked from %(roomName)s by %(userName)s.": "You have been kicked from %(roomName)s by %(userName)s.",
"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": "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",
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
"You have entered an invalid contact. Try using their Matrix ID or email address.": "You have entered an invalid contact. Try using their Matrix ID or email address.",
"You have no visible notifications": "You have no visible notifications",
"You may wish to login with a different account, or add this email to this account.": "You may wish to login with a different account, or add this email to this account.",
"you must be a": "you must be a",
"You must <a>register</a> to use this functionality": "You must <a>register</a> to use this functionality",
"You need to be able to invite users to do that.": "You need to be able to invite users to do that.",
@ -628,7 +676,8 @@
"You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?",
"You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?",
"You should not yet trust it to secure data": "You should not yet trust it to secure data",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself",
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.",
"Your home server does not support device management.": "Your home server does not support device management.",
"Sun": "Sun",
"Mon": "Mon",
"Tue": "Tue",
@ -675,7 +724,10 @@
"Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.",
"Auto-complete": "Auto-complete",
"<a>Resend all</a> or <a>cancel all</a> now. You can also select individual messages to resend or cancel.": "<a>Resend all</a> or <a>cancel all</a> now. You can also select individual messages to resend or cancel.",
"(~%(searchCount)s results)": "(~%(searchCount)s results)",
"(~%(count)s results)": {
"one": "(~%(count)s result)",
"other": "(~%(count)s results)"
},
"Cancel": "Cancel",
"or": "or",
"Active call": "Active call",
@ -781,6 +833,7 @@
"To continue, please enter your password.": "To continue, please enter your password.",
"To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:",
"Device name": "Device name",
"Device Name": "Device Name",
"Device key": "Device key",
"If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.",
"In future this verification process will be more sophisticated.": "In future this verification process will be more sophisticated.",