Translate src/components/structures

Includes some pluralisation! Tested them manually to make sure they work.
This commit is contained in:
Kegan Dougal 2017-06-07 11:40:46 +01:00
parent 184c2d5e58
commit 4127e7121c
11 changed files with 59 additions and 39 deletions

View file

@ -246,7 +246,7 @@ module.exports = React.createClass({
return ( return (
<div className="mx_CreateRoom"> <div className="mx_CreateRoom">
<SimpleRoomHeader title="CreateRoom" collapsedRhs={ this.props.collapsedRhs }/> <SimpleRoomHeader title={_t("Create Room")} collapsedRhs={ this.props.collapsedRhs }/>
<div className="mx_CreateRoom_body"> <div className="mx_CreateRoom_body">
<input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder={_t('Name')}/> <br /> <input type="text" ref="room_name" value={this.state.room_name} onChange={this.onNameChange} placeholder={_t('Name')}/> <br />
<textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder={_t('Topic')}/> <br /> <textarea className="mx_CreateRoom_description" ref="topic" value={this.state.topic} onChange={this.onTopicChange} placeholder={_t('Topic')}/> <br />

View file

@ -19,7 +19,7 @@ import React from 'react';
import Matrix from 'matrix-js-sdk'; import Matrix from 'matrix-js-sdk';
import sdk from '../../index'; import sdk from '../../index';
import MatrixClientPeg from '../../MatrixClientPeg'; import MatrixClientPeg from '../../MatrixClientPeg';
import { _t } from '../../languageHandler'; import { _t, _tJsx } from '../../languageHandler';
/* /*
* Component which shows the filtered file using a TimelinePanel * Component which shows the filtered file using a TimelinePanel
@ -91,7 +91,9 @@ var FilePanel = React.createClass({
render: function() { render: function() {
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
return <div className="mx_FilePanel mx_RoomView_messageListWrapper"> return <div className="mx_FilePanel mx_RoomView_messageListWrapper">
<div className="mx_RoomView_empty">You must <a href="#/register">register</a> to use this functionality</div> <div className="mx_RoomView_empty">
{_tJsx("You must <a>register</a> to use this functionality", /<a>(.*?)<\/a>/, (sub) => <a href="#/register" key="sub">{sub}</a>)}
</div>
</div>; </div>;
} else if (this.noRoom) { } else if (this.noRoom) {
return <div className="mx_FilePanel mx_RoomView_messageListWrapper"> return <div className="mx_FilePanel mx_RoomView_messageListWrapper">

View file

@ -1133,7 +1133,15 @@ module.exports = React.createClass({
PlatformPeg.get().setNotificationCount(notifCount); PlatformPeg.get().setNotificationCount(notifCount);
} }
document.title = `Riot ${state === "ERROR" ? " [offline]" : ""}${notifCount > 0 ? ` [${notifCount}]` : ""}`; let title = "Riot ";
if (state === "ERROR") {
title += `[${_t("Offline")}] `;
}
if (notifCount > 0) {
title += `[${notifCount}]`;
}
document.title = title;
}, },
onUserSettingsClose: function() { onUserSettingsClose: function() {

View file

@ -15,7 +15,7 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import { _t } from '../../languageHandler'; import { _t, _tJsx } from '../../languageHandler';
import sdk from '../../index'; import sdk from '../../index';
import WhoIsTyping from '../../WhoIsTyping'; import WhoIsTyping from '../../WhoIsTyping';
import MatrixClientPeg from '../../MatrixClientPeg'; import MatrixClientPeg from '../../MatrixClientPeg';
@ -281,14 +281,13 @@ module.exports = React.createClass({
{ this.props.unsentMessageError } { this.props.unsentMessageError }
</div> </div>
<div className="mx_RoomStatusBar_connectionLostBar_desc"> <div className="mx_RoomStatusBar_connectionLostBar_desc">
<a className="mx_RoomStatusBar_resend_link" {_tJsx("<a>Resend all</a> or <a>cancel all</a> now. You can also select individual messages to resend or cancel.",
onClick={ this.props.onResendAllClick }> [/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/],
{_t('Resend all')} [
</a> {_t('or')} <a (sub) => <a className="mx_RoomStatusBar_resend_link" key="resend" onClick={ this.props.onResendAllClick }>{sub}</a>,
className="mx_RoomStatusBar_resend_link" (sub) => <a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={ this.props.onCancelAllClick }>{sub}</a>,
onClick={ this.props.onCancelAllClick }> ]
{_t('cancel all')} )}
</a> {_t('now. You can also select individual messages to resend or cancel.')}
</div> </div>
</div> </div>
); );
@ -297,8 +296,8 @@ module.exports = React.createClass({
// unread count trumps who is typing since the unread count is only // unread count trumps who is typing since the unread count is only
// set when you've scrolled up // set when you've scrolled up
if (this.props.numUnreadMessages) { if (this.props.numUnreadMessages) {
var unreadMsgs = this.props.numUnreadMessages + " new message" + // MUST use var name "count" for pluralization to kick in
(this.props.numUnreadMessages > 1 ? "s" : ""); var unreadMsgs = _t("%(count)s new messages", {count: this.props.numUnreadMessages});
return ( return (
<div className="mx_RoomStatusBar_unreadMessagesBar" <div className="mx_RoomStatusBar_unreadMessagesBar"

View file

@ -716,7 +716,7 @@ module.exports = React.createClass({
if (!unsentMessages.length) return ""; if (!unsentMessages.length) return "";
for (const event of unsentMessages) { for (const event of unsentMessages) {
if (!event.error || event.error.name !== "UnknownDeviceError") { if (!event.error || event.error.name !== "UnknownDeviceError") {
return _t("Some of your messages have not been sent") + "."; return _t("Some of your messages have not been sent.");
} }
} }
return _t("Message not sent due to unknown devices being present"); return _t("Message not sent due to unknown devices being present");
@ -880,7 +880,7 @@ module.exports = React.createClass({
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, { Modal.createDialog(NeedToRegisterDialog, {
title: _t("Failed to join the room"), title: _t("Failed to join the room"),
description: _t("This room is private or inaccessible to guests. You may be able to join if you register") + "." description: _t("This room is private or inaccessible to guests. You may be able to join if you register.")
}); });
} else { } else {
var msg = error.message ? error.message : JSON.stringify(error); var msg = error.message ? error.message : JSON.stringify(error);
@ -948,7 +948,7 @@ module.exports = React.createClass({
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, { Modal.createDialog(NeedToRegisterDialog, {
title: _t("Please Register"), 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; return;
} }

View file

@ -921,8 +921,8 @@ var TimelinePanel = React.createClass({
}; };
} }
var message = (error.errcode == 'M_FORBIDDEN') var message = (error.errcode == 'M_FORBIDDEN')
? _t("Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question") + "." ? _t("Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.")
: _t("Tried to load a specific point in this room's timeline, but was unable to find it") + "."; : _t("Tried to load a specific point in this room's timeline, but was unable to find it.");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("Failed to load timeline position"), title: _t("Failed to load timeline position"),
description: message, description: message,

View file

@ -18,6 +18,7 @@ var React = require('react');
var ContentMessages = require('../../ContentMessages'); var ContentMessages = require('../../ContentMessages');
var dis = require('../../dispatcher'); var dis = require('../../dispatcher');
var filesize = require('filesize'); var filesize = require('filesize');
import { _t } from '../../languageHandler';
module.exports = React.createClass({displayName: 'UploadBar', module.exports = React.createClass({displayName: 'UploadBar',
propTypes: { propTypes: {
@ -81,10 +82,8 @@ module.exports = React.createClass({displayName: 'UploadBar',
uploadedSize = uploadedSize.replace(/ .*/, ''); uploadedSize = uploadedSize.replace(/ .*/, '');
} }
var others; // MUST use var name 'count' for pluralization to kick in
if (uploads.length > 1) { var uploadText = _t("Uploading %(filename)s and %(count)s others", {filename: upload.fileName, count: (uploads.length - 1)});
others = ' and ' + (uploads.length - 1) + ' other' + (uploads.length > 2 ? 's' : '');
}
return ( return (
<div className="mx_UploadBar"> <div className="mx_UploadBar">
@ -98,7 +97,7 @@ module.exports = React.createClass({displayName: 'UploadBar',
<div className="mx_UploadBar_uploadBytes"> <div className="mx_UploadBar_uploadBytes">
{ uploadedSize } / { totalSize } { uploadedSize } / { totalSize }
</div> </div>
<div className="mx_UploadBar_uploadFilename">Uploading {upload.fileName}{others}</div> <div className="mx_UploadBar_uploadFilename">{uploadText}</div>
</div> </div>
); );
} }

View file

@ -757,7 +757,7 @@ module.exports = React.createClass({
const DevicesPanel = sdk.getComponent('settings.DevicesPanel'); const DevicesPanel = sdk.getComponent('settings.DevicesPanel');
return ( return (
<div> <div>
<h3>Devices</h3> <h3>{_t("Devices")}</h3>
<DevicesPanel className="mx_UserSettings_section"/> <DevicesPanel className="mx_UserSettings_section"/>
</div> </div>
); );
@ -1102,7 +1102,7 @@ module.exports = React.createClass({
onValueChanged={ this._onAddEmailEditFinished } /> onValueChanged={ this._onAddEmailEditFinished } />
</div> </div>
<div className="mx_UserSettings_threepidButton mx_filterFlipColor"> <div className="mx_UserSettings_threepidButton mx_filterFlipColor">
<img src="img/plus.svg" width="14" height="14" alt="Add" onClick={this._addEmail} /> <img src="img/plus.svg" width="14" height="14" alt={_t("Add")} onClick={this._addEmail} />
</div> </div>
</div> </div>
); );

View file

@ -129,7 +129,7 @@ module.exports = React.createClass({
onPhoneNumberChanged: function(phoneNumber) { onPhoneNumberChanged: function(phoneNumber) {
// Validate the phone number entered // Validate the phone number entered
if (!PHONE_NUMBER_REGEX.test(phoneNumber)) { if (!PHONE_NUMBER_REGEX.test(phoneNumber)) {
this.setState({ errorText: 'The phone number entered looks invalid' }); this.setState({ errorText: _t('The phone number entered looks invalid') });
return; return;
} }
@ -213,8 +213,8 @@ module.exports = React.createClass({
errCode = "HTTP " + err.httpStatus; errCode = "HTTP " + err.httpStatus;
} }
let errorText = "Error: Problem communicating with the given homeserver " + let errorText = _t("Error: Problem communicating with the given homeserver.") +
(errCode ? "(" + errCode + ")" : ""); (errCode ? " (" + errCode + ")" : "");
if (err.cors === 'rejected') { if (err.cors === 'rejected') {
if (window.location.protocol === 'https:' && if (window.location.protocol === 'https:' &&

View file

@ -50,7 +50,7 @@ module.exports = React.createClass({
}); });
}, function(error) { }, function(error) {
self.setState({ self.setState({
errorString: "Failed to fetch avatar URL", errorString: _t("Failed to fetch avatar URL"),
busy: false busy: false
}); });
}); });

View file

@ -126,6 +126,7 @@
"%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.", "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.",
"Account": "Account", "Account": "Account",
"Access Token:": "Access Token:", "Access Token:": "Access Token:",
"Add": "Add",
"Add a topic": "Add a topic", "Add a topic": "Add a topic",
"Add email address": "Add email address", "Add email address": "Add email address",
"Add phone number": "Add phone number", "Add phone number": "Add phone number",
@ -213,6 +214,10 @@
"Confirm your new password": "Confirm your new password", "Confirm your new password": "Confirm your new password",
"Continue": "Continue", "Continue": "Continue",
"Could not connect to the integration server": "Could not connect to the integration server", "Could not connect to the integration server": "Could not connect to the integration server",
"%(count)s new messages": {
"one": "%(count)s new message",
"other": "%(count)s new messages"
},
"Create an account": "Create an account", "Create an account": "Create an account",
"Create Room": "Create Room", "Create Room": "Create Room",
"Cryptography": "Cryptography", "Cryptography": "Cryptography",
@ -265,6 +270,7 @@
"Enter Code": "Enter Code", "Enter Code": "Enter Code",
"Error": "Error", "Error": "Error",
"Error decrypting attachment": "Error decrypting attachment", "Error decrypting attachment": "Error decrypting attachment",
"Error: Problem communicating with the given homeserver.": "Error: Problem communicating with the given homeserver.",
"Event information": "Event information", "Event information": "Event information",
"Existing Call": "Existing Call", "Existing Call": "Existing Call",
"Export": "Export", "Export": "Export",
@ -273,6 +279,7 @@
"Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?", "Failed to change password. Is your password correct?": "Failed to change password. Is your password correct?",
"Failed to change power level": "Failed to change power level", "Failed to change power level": "Failed to change power level",
"Failed to delete device": "Failed to delete device", "Failed to delete device": "Failed to delete device",
"Failed to fetch avatar URL": "Failed to fetch avatar URL",
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s", "Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"Failed to join room": "Failed to join room", "Failed to join room": "Failed to join room",
"Failed to join the room": "Failed to join the room", "Failed to join the room": "Failed to join the room",
@ -309,7 +316,7 @@
"Guest access is disabled on this Home Server.": "Guest access is disabled on this Home Server.", "Guest access is disabled on this Home Server.": "Guest access is disabled on this Home Server.",
"Guests can't set avatars. Please register.": "Guests can't set avatars. Please register.", "Guests can't set avatars. Please register.": "Guests can't set avatars. Please register.",
"Guest users can't create new rooms. Please register to create room and start a chat.": "Guest users can't create new rooms. Please register to create room and start a chat.", "Guest users can't create new rooms. Please register to create room and start a chat.": "Guest users can't create new rooms. Please register to create room and start a chat.",
"Guest users can't upload files. Please register to upload": "Guest users can't upload files. Please register to upload", "Guest users can't upload files. Please register to upload.": "Guest users can't upload files. Please register to upload.",
"Guests can't use labs features. Please register.": "Guests can't use labs features. Please register.", "Guests can't use labs features. Please register.": "Guests can't use labs features. Please register.",
"Guests cannot join this room even if explicitly invited.": "Guests cannot join this room even if explicitly invited.", "Guests cannot join this room even if explicitly invited.": "Guests cannot join this room even if explicitly invited.",
"had": "had", "had": "had",
@ -477,7 +484,7 @@
"since the point in time of selecting this option": "since the point in time of selecting this option", "since the point in time of selecting this option": "since the point in time of selecting this option",
"since they joined": "since they joined", "since they joined": "since they joined",
"since they were invited": "since they were invited", "since they were invited": "since they were invited",
"Some of your messages have not been sent": "Some of your messages have not been sent", "Some of your messages have not been sent.": "Some of your messages have not been sent.",
"Someone": "Someone", "Someone": "Someone",
"Sorry, this homeserver is using a login which is not recognised ": "Sorry, this homeserver is using a login which is not recognised ", "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 a chat": "Start a chat",
@ -489,6 +496,7 @@
"Tagged as: ": "Tagged as: ", "Tagged as: ": "Tagged as: ",
"The default role for new room members is": "The default role for new room members is", "The default role for new room members is": "The default role for new room members is",
"The main address for this room is": "The main address for this room is", "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.", "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 is already in use": "This email address is already in use",
@ -502,7 +510,7 @@
"There was a problem logging in.": "There was a problem logging in.", "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 has no local addresses": "This room has no local addresses",
"This room is not recognised.": "This room is not recognised.", "This room is not recognised.": "This room is not recognised.",
"This room is private or inaccessible to guests. You may be able to join if you register": "This room is private or inaccessible to guests. You may be able to join if you register", "This room is private or inaccessible to guests. You may be able to join if you register.": "This room is private or inaccessible to guests. You may be able to join if you register.",
"These are experimental features that may break in unexpected ways": "These are experimental features that may break in unexpected ways", "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", "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 doesn't appear to be a valid email address": "This doesn't appear to be a valid email address",
@ -531,8 +539,8 @@
"to tag as %(tagName)s": "to tag as %(tagName)s", "to tag as %(tagName)s": "to tag as %(tagName)s",
"to tag direct chat": "to tag direct chat", "to tag direct chat": "to tag direct chat",
"To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question", "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.",
"Tried to load a specific point in this room's timeline, but was unable to find it": "Tried to load a specific point in this room's timeline, but was unable to find it", "Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.",
"Turn Markdown off": "Turn Markdown off", "Turn Markdown off": "Turn Markdown off",
"Turn Markdown on": "Turn Markdown on", "Turn Markdown on": "Turn Markdown on",
"%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).", "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).",
@ -556,6 +564,11 @@
"Unmute": "Unmute", "Unmute": "Unmute",
"Unrecognised command:": "Unrecognised command:", "Unrecognised command:": "Unrecognised command:",
"Unrecognised room alias:": "Unrecognised room alias:", "Unrecognised room alias:": "Unrecognised room alias:",
"Uploading %(filename)s and %(count)s others": {
"zero": "Uploading %(filename)s",
"one": "Uploading %(filename)s and %(count)s other",
"other": "Uploading %(filename)s and %(count)s others"
},
"uploaded a file": "uploaded a file", "uploaded a file": "uploaded a file",
"Upload avatar": "Upload avatar", "Upload avatar": "Upload avatar",
"Upload Failed": "Upload Failed", "Upload Failed": "Upload Failed",
@ -601,6 +614,7 @@
"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 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 have no visible notifications": "You have no visible notifications",
"you must be a": "you must be a", "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.", "You need to be able to invite users to do that.": "You need to be able to invite users to do that.",
"You need to be logged in.": "You need to be logged in.", "You need to be logged in.": "You need to be logged in.",
"You need to enter a user name.": "You need to enter a user name.", "You need to enter a user name.": "You need to enter a user name.",
@ -657,12 +671,10 @@
"Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.",
"Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.",
"Auto-complete": "Auto-complete", "Auto-complete": "Auto-complete",
"Resend all": "Resend all", "<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)", "(~%(searchCount)s results)": "(~%(searchCount)s results)",
"Cancel": "Cancel", "Cancel": "Cancel",
"cancel all": "cancel all",
"or": "or", "or": "or",
"now. You can also select individual messages to resend or cancel.": "now. You can also select individual messages to resend or cancel.",
"Active call": "Active call", "Active call": "Active call",
"Monday": "Monday", "Monday": "Monday",
"Tuesday": "Tuesday", "Tuesday": "Tuesday",