From 00df956ca24b39134641573ea9456bbdd7d63565 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Jun 2017 14:08:51 +0100 Subject: [PATCH] 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. :( --- src/components/views/rooms/AuxPanel.js | 15 +++-- src/components/views/rooms/EntityTile.js | 5 +- src/components/views/rooms/EventTile.js | 10 ++-- .../views/rooms/MemberDeviceInfo.js | 6 +- src/components/views/rooms/MemberInfo.js | 8 +-- src/components/views/rooms/MemberTile.js | 3 +- src/components/views/rooms/MessageComposer.js | 6 +- .../views/rooms/ReadReceiptMarker.js | 7 ++- src/components/views/rooms/RoomHeader.js | 4 +- src/components/views/rooms/RoomNameEditor.js | 5 +- src/components/views/rooms/RoomPreviewBar.js | 58 +++++++++++++------ src/components/views/rooms/RoomSettings.js | 14 +++-- .../views/rooms/SimpleRoomHeader.js | 3 +- .../views/rooms/TopUnreadMessagesBar.js | 2 +- src/i18n/strings/en_EN.json | 53 ++++++++++++----- 15 files changed, 130 insertions(+), 69 deletions(-) diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index f53512e684..7e7a670aea 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -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 = (
+ title={_t("Drop File Here")}>
{_t("Drop file here to upload")} @@ -95,9 +95,14 @@ module.exports = React.createClass({ } else { joinText = ( - Join as { this.onConferenceNotificationClick(event, 'voice');}} - href="#">voice or { this.onConferenceNotificationClick(event, 'video'); }} - href="#">video. + {_tJsx( + "Join as voice or video.", + [/(.*?)<\/a>/, /(.*?)<\/a>/], + [ + (sub) => { this.onConferenceNotificationClick(event, 'voice');}} href="#">{sub}, + (sub) => { this.onConferenceNotificationClick(event, 'video');}} href="#">{sub}, + ] + )} ); } diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.js index 71e8fb0be7..015b7b4603 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.js @@ -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 = Mod; + power = {_t("Moderator")}/; } if (powerLevel >= 99) { - power = Admin; + power = {_t("Admin")}/; } diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index e527f53170..80f062aef7 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -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 = Encrypted by verified device; + e2e = {_t("Encrypted; } // real padlocks else if (this.props.mxEvent.isEncrypted() || (e2eEnabled && this.props.eventSendStatus)) { if (this.props.mxEvent.getContent().msgtype === 'm.bad.encrypted') { - e2e = Undecryptable; + e2e = {_t("Undecryptable")}; } else if (this.state.verified == true || (e2eEnabled && this.props.eventSendStatus)) { - e2e = Encrypted by verified device; + e2e = {_t("Encrypted; } else { - e2e = Encrypted by unverified device; + e2e = {_t("Encrypted; } } else if (e2eEnabled) { - e2e = Unencrypted message; + e2e = {_t("Unencrypted; } const timestamp = this.props.mxEvent.getTs() ? : null; diff --git a/src/components/views/rooms/MemberDeviceInfo.js b/src/components/views/rooms/MemberDeviceInfo.js index af44bf7f99..33b919835c 100644 --- a/src/components/views/rooms/MemberDeviceInfo.js +++ b/src/components/views/rooms/MemberDeviceInfo.js @@ -26,19 +26,19 @@ export default class MemberDeviceInfo extends React.Component { if (this.props.device.isBlocked()) { indicator = (
- Blacklisted + {_t("Blacklisted")}/
); } else if (this.props.device.isVerified()) { indicator = (
- Verified + {_t("Verified")}/
); } else { indicator = (
- Unverified + {_t("Unverified")}/
); } diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index 86d39f91ec..0c66dd4f11 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -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:
- { _t("You will not be able to undo this change as you are promoting the user to have the same power level as yourself") }.
+ { _t("You will not be able to undo this change as you are promoting the user to have the same power level as yourself.") }
{ _t("Are you sure?") }
, button: _t("Continue"), @@ -705,7 +705,7 @@ module.exports = WithMatrixClient(React.createClass({ if (kickButton || banButton || muteButton || giveModButton) { adminTools =
-

Admin tools

+

{_t("Admin tools")}

{muteButton} @@ -743,7 +743,7 @@ module.exports = WithMatrixClient(React.createClass({ { this.props.member.userId }
- { _t("Level") }: + { _t("Level:") }
- {files[i].name || 'Attachment'} + {files[i].name || _t('Attachment')} ); } @@ -291,7 +291,7 @@ export default class MessageComposer extends React.Component { const formattingButton = (  { _t("(~%(searchCount)s results)", { searchCount: this.props.searchInfo.searchCount }) }
; + searchStatus =
 { _t("(~%(count)s results)", { count: this.props.searchInfo.searchCount }) }
; } // 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 = - + ; } diff --git a/src/components/views/rooms/RoomNameEditor.js b/src/components/views/rooms/RoomNameEditor.js index 773b713584..0fc2d1669c 100644 --- a/src/components/views/rooms/RoomNameEditor.js +++ b/src/components/views/rooms/RoomNameEditor.js @@ -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 + ")"; } }, diff --git a/src/components/views/rooms/RoomPreviewBar.js b/src/components/views/rooms/RoomPreviewBar.js index b20b2ef58e..8aa1f353a6 100644 --- a/src/components/views/rooms/RoomPreviewBar.js +++ b/src/components/views/rooms/RoomPreviewBar.js @@ -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 =
- 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.")}
; } else if (this.state.invitedEmailMxid != MatrixClientPeg.get().credentials.userId) { emailMatchBlock = @@ -124,28 +123,35 @@ module.exports = React.createClass({ /!\\
- This invitation was sent to {this.props.invitedEmail}, which is not associated with this account.
- 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:")} + {this.props.invitedEmail} +
+ {_t("You may wish to login with a different account, or add this email to this account.")}
; } } - // TODO: find a way to respect HTML in counterpart! joinBlock = (
{ _t('You have been invited to join this room by %(inviterName)s', {inviterName: this.props.inviterName}) }
- { _t('Would you like to') } { _t('accept') } { _t('or') } { _t('decline') } { _t('this invitation?') } + { _tJsx( + 'Would you like to accept or decline this invitation?', + [/(.*?)<\/a>/, /(.*?)<\/a>/], + [ + (sub) => {sub}, + (sub) => {sub} + ] + )}
{emailMatchBlock}
); } 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 =
Reason: {myMember.events.member.getContent().reason}
+ reason =
{_t("Reason: %(reasonText)s", {reasonText: myMember.events.member.getContent().reason})}
} let rejoinBlock; if (!banned) { - rejoinBlock =
Rejoin
; + rejoinBlock =
{_t("Rejoin")}
; } + + 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 = (
- You have been {verb} from {roomName} by {kickerName}.
+ {actionText} +
{reason} {rejoinBlock} - Forget + {_t("Forget room")}
); } 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 = (
@@ -189,8 +205,12 @@ module.exports = React.createClass({ joinBlock = (
- { _t('You are trying to access %(roomName)s', {roomName: name}) }.
- { _t('Click here') } { _t('to join the discussion') }! + { _t('You are trying to access %(roomName)s.', {roomName: name}) } +
+ { _tJsx("Click here to join the discussion!", + /(.*?)<\/a>/, + (sub) => {sub} + )}
); diff --git a/src/components/views/rooms/RoomSettings.js b/src/components/views/rooms/RoomSettings.js index 205f614ba2..f31fc68afc 100644 --- a/src/components/views/rooms/RoomSettings.js +++ b/src/components/views/rooms/RoomSettings.js @@ -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({ ? : } - { 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") }. { settings }
@@ -653,7 +653,7 @@ module.exports = React.createClass({ {Object.keys(user_levels).map(function(user, i) { return (
  • - { user } { _t('is a') } + { _t("%(user)s is a", {user: user}) }
  • ); })} @@ -754,7 +754,11 @@ module.exports = React.createClass({ if (this.state.join_rule === "public" && aliasCount == 0) { addressWarning =
    - { _t('To link to a room it must have') } { _t('an address') }. + { _tJsx( + 'To link to a room it must have an address.', + /(.*?)<\/a>/, + (sub) => {sub} + )}
    ; } diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index a6f342af86..44ec7c29aa 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -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 ( Cancel + width="18" height="18" alt={_t("Cancel")}/> ); } diff --git a/src/components/views/rooms/TopUnreadMessagesBar.js b/src/components/views/rooms/TopUnreadMessagesBar.js index 45aba66633..aa1f86483e 100644 --- a/src/components/views/rooms/TopUnreadMessagesBar.js +++ b/src/components/views/rooms/TopUnreadMessagesBar.js @@ -41,7 +41,7 @@ module.exports = React.createClass({
    Close ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index de1adc539d..6026298cd6 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -120,8 +120,8 @@ "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.", @@ -133,6 +133,7 @@ "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.", @@ -152,7 +153,6 @@ "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", @@ -201,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", + "Click here to join the discussion!": "Click here 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.", @@ -234,7 +235,6 @@ "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)", @@ -260,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", @@ -271,8 +272,12 @@ "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", @@ -354,11 +359,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 voice or video.": "Join as voice or video.", "Join Room": "Join Room", "joined and left": "joined and left", "joined": "joined", @@ -374,7 +379,7 @@ "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:", @@ -441,6 +446,7 @@ "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", @@ -448,6 +454,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).", @@ -468,6 +475,8 @@ "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", "Saving room color settings is only available to registered users": "Saving room color settings is only available to registered users", @@ -477,6 +486,7 @@ "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", @@ -500,6 +510,7 @@ "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", @@ -522,7 +533,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?", @@ -531,6 +542,7 @@ "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.", @@ -538,9 +550,9 @@ "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", @@ -550,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 an address.": "To link to a room it must have an address.", "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", @@ -574,11 +585,14 @@ "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", @@ -587,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", @@ -605,12 +621,15 @@ "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)", "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", @@ -626,20 +645,23 @@ "Who would you like to add to this room?": "Who would you like to add to this room?", "Who would you like to communicate with?": "Who would you like to communicate with?", "%(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 accept or decline this invitation?": "Would you like to accept or decline 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 disabled URL previews by default.": "You have disabled URL previews by default.", "You have enabled URL previews by default.": "You have enabled 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 register to use this functionality": "You must register 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.", @@ -652,7 +674,7 @@ "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", @@ -700,7 +722,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", "Resend all or cancel all now. You can also select individual messages to resend or cancel.": "Resend all or cancel all 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",