Add remaining translations!

Every file has now been manually vetted by me. Due to the extent of
the changes, I've been unable to test all scenarios to make sure this
all works. :(
This commit is contained in:
Kegan Dougal 2017-06-08 14:08:51 +01:00
parent 1c58a9cd5e
commit 00df956ca2
15 changed files with 130 additions and 69 deletions

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 <a>voice</a> or <a>video</a>.",
[/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/],
[
(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

@ -378,7 +378,7 @@ module.exports = WithMatrixClient(React.createClass({
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: _t("Please Register"),
description: _t("This action cannot be performed by a guest user. Please register to be able to do this") + ".",
description: _t("This action cannot be performed by a guest user. Please register to be able to do this."),
});
} else {
console.error("Toggle moderator error:" + err);
@ -436,7 +436,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"),
@ -705,7 +705,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}
@ -743,7 +743,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

@ -94,7 +94,7 @@ export default class MessageComposer extends React.Component {
let NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, {
title: _t('Please Register'),
description: _t('Guest users can\'t upload files. Please register to upload') + '.',
description: _t('Guest users can\'t upload files. Please register to upload.'),
});
return;
}
@ -113,7 +113,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>);
}
@ -291,7 +291,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 <a>accept</a> or <a>decline</a> this invitation?',
[/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/],
[
(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>
);