diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js
index 453394249f..995d5f8531 100644
--- a/src/components/views/messages/RoomAvatarEvent.js
+++ b/src/components/views/messages/RoomAvatarEvent.js
@@ -70,9 +70,9 @@ module.exports = React.createClass({
// it sucks that _tJsx doesn't support normal _t substitutions :((
return (
- { _tJsx('$senderDisplayName changed the room avatar to
',
+ { _tJsx('%(senderDisplayName)s changed the room avatar to
',
[
- /\$senderDisplayName/,
+ /%\(senderDisplayName\)s/,
/
/,
],
[
diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js
index c0468c38c2..64b23238e5 100644
--- a/src/components/views/messages/TextualBody.js
+++ b/src/components/views/messages/TextualBody.js
@@ -354,7 +354,9 @@ module.exports = React.createClass({
const mxEvent = this.props.mxEvent;
const content = mxEvent.getContent();
- let body = HtmlUtils.bodyToHtml(content, this.props.highlights, {});
+ let body = HtmlUtils.bodyToHtml(content, this.props.highlights, {
+ disableBigEmoji: UserSettingsStore.getSyncedSetting('TextualBody.disableBigEmoji', false),
+ });
if (this.props.highlightLink) {
body =
{ body };
diff --git a/src/components/views/room_settings/ColorSettings.js b/src/components/views/room_settings/ColorSettings.js
index d914390bd8..bfdaa49f65 100644
--- a/src/components/views/room_settings/ColorSettings.js
+++ b/src/components/views/room_settings/ColorSettings.js
@@ -34,7 +34,7 @@ const ROOM_COLORS = [
["#dad658", "#f5f4ea"],
["#80c553", "#eef5ea"],
["#bb814e", "#eee8e3"],
- ["#595959", "#ececec"],
+ //["#595959", "#ececec"], // Grey makes everything appear disabled, so remove it for now
];
module.exports = React.createClass({
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index f92dc0b97a..499d0ec09a 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -44,6 +44,7 @@ const eventTileTypes = {
'm.room.history_visibility': 'messages.TextualEvent',
'm.room.encryption': 'messages.TextualEvent',
'm.room.power_levels': 'messages.TextualEvent',
+ 'm.room.pinned_events' : 'messages.TextualEvent',
'im.vector.modular.widgets': 'messages.TextualEvent',
};
diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js
index 180db1d5dd..f768487509 100644
--- a/src/components/views/rooms/MemberInfo.js
+++ b/src/components/views/rooms/MemberInfo.js
@@ -626,22 +626,49 @@ module.exports = withMatrixClient(React.createClass({
},
_renderUserOptions: function() {
- // Only allow the user to ignore the user if its not ourselves
+ const cli = this.props.matrixClient;
+ const member = this.props.member;
+
let ignoreButton = null;
- if (this.props.member.userId !== this.props.matrixClient.getUserId()) {
+ let readReceiptButton = null;
+
+ // Only allow the user to ignore the user if its not ourselves
+ // same goes for jumping to read receipt
+ if (member.userId !== cli.getUserId()) {
ignoreButton = (
{ this.state.isIgnoring ? _t("Unignore") : _t("Ignore") }
);
+
+ if (member.roomId) {
+ const room = cli.getRoom(member.roomId);
+ const eventId = room.getEventReadUpTo(member.userId);
+
+ const onReadReceiptButton = function() {
+ dis.dispatch({
+ action: 'view_room',
+ highlighted: true,
+ event_id: eventId,
+ room_id: member.roomId,
+ });
+ };
+
+ readReceiptButton = (
+
+ { _t('Jump to read receipt') }
+
+ );
+ }
}
- if (!ignoreButton) return null;
+ if (!ignoreButton && !readReceiptButton) return null;
return (
{ _t("User Options") }
+ { readReceiptButton }
{ ignoreButton }
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js
index 0713a4ae8a..04b6089559 100644
--- a/src/components/views/rooms/MemberList.js
+++ b/src/components/views/rooms/MemberList.js
@@ -146,8 +146,8 @@ module.exports = React.createClass({
const newState = {
members: this.roomMembers(),
};
- newState.filteredJoinedMembers = this._filterMembers(newState.members, 'join');
- newState.filteredInvitedMembers = this._filterMembers(newState.members, 'invite');
+ newState.filteredJoinedMembers = this._filterMembers(newState.members, 'join', this.state.searchQuery);
+ newState.filteredInvitedMembers = this._filterMembers(newState.members, 'invite', this.state.searchQuery);
this.setState(newState);
}, 500),
@@ -187,7 +187,7 @@ module.exports = React.createClass({
const user_id = all_user_ids[i];
const m = all_members[user_id];
- if (m.membership == 'join' || m.membership == 'invite') {
+ if (m.membership === 'join' || m.membership === 'invite') {
if ((ConferenceHandler && !ConferenceHandler.isConferenceUser(user_id)) || !ConferenceHandler) {
to_display.push(user_id);
++count;
@@ -302,6 +302,7 @@ module.exports = React.createClass({
const m = this.memberDict[userId];
if (query) {
+ query = query.toLowerCase();
const matchesName = m.name.toLowerCase().indexOf(query) !== -1;
const matchesId = m.userId.toLowerCase().indexOf(query) !== -1;
@@ -310,7 +311,7 @@ module.exports = React.createClass({
}
}
- return m.membership == membership;
+ return m.membership === membership;
});
},
diff --git a/src/components/views/rooms/PinnedEventTile.js b/src/components/views/rooms/PinnedEventTile.js
new file mode 100644
index 0000000000..65b41d946a
--- /dev/null
+++ b/src/components/views/rooms/PinnedEventTile.js
@@ -0,0 +1,90 @@
+/*
+Copyright 2017 Travis Ralston
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from "react";
+import MatrixClientPeg from "../../../MatrixClientPeg";
+import dis from "../../../dispatcher";
+import AccessibleButton from "../elements/AccessibleButton";
+import MessageEvent from "../messages/MessageEvent";
+import MemberAvatar from "../avatars/MemberAvatar";
+import { _t } from '../../../languageHandler';
+
+module.exports = React.createClass({
+ displayName: 'PinnedEventTile',
+ propTypes: {
+ mxRoom: React.PropTypes.object.isRequired,
+ mxEvent: React.PropTypes.object.isRequired,
+ onUnpinned: React.PropTypes.func,
+ },
+ onTileClicked: function() {
+ dis.dispatch({
+ action: 'view_room',
+ event_id: this.props.mxEvent.getId(),
+ highlighted: true,
+ room_id: this.props.mxEvent.getRoomId(),
+ });
+ },
+ onUnpinClicked: function() {
+ const pinnedEvents = this.props.mxRoom.currentState.getStateEvents("m.room.pinned_events", "");
+ if (!pinnedEvents || !pinnedEvents.getContent().pinned) {
+ // Nothing to do: already unpinned
+ if (this.props.onUnpinned) this.props.onUnpinned();
+ } else {
+ const pinned = pinnedEvents.getContent().pinned;
+ const index = pinned.indexOf(this.props.mxEvent.getId());
+ if (index !== -1) {
+ pinned.splice(index, 1);
+ MatrixClientPeg.get().sendStateEvent(this.props.mxRoom.roomId, 'm.room.pinned_events', {pinned}, '')
+ .then(() => {
+ if (this.props.onUnpinned) this.props.onUnpinned();
+ });
+ } else if (this.props.onUnpinned) this.props.onUnpinned();
+ }
+ },
+ _canUnpin: function() {
+ return this.props.mxRoom.currentState.mayClientSendStateEvent('m.room.pinned_events', MatrixClientPeg.get());
+ },
+ render: function() {
+ const sender = this.props.mxRoom.getMember(this.props.mxEvent.getSender());
+ const avatarSize = 40;
+
+ let unpinButton = null;
+ if (this._canUnpin()) {
+ unpinButton = (
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ { _t("Jump to message") }
+
+ { unpinButton }
+
+
+
+
+ { sender.name }
+
+
+
+ );
+ },
+});
diff --git a/src/components/views/rooms/PinnedEventsPanel.js b/src/components/views/rooms/PinnedEventsPanel.js
new file mode 100644
index 0000000000..deea03f030
--- /dev/null
+++ b/src/components/views/rooms/PinnedEventsPanel.js
@@ -0,0 +1,105 @@
+/*
+Copyright 2017 Travis Ralston
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from "react";
+import MatrixClientPeg from "../../../MatrixClientPeg";
+import AccessibleButton from "../elements/AccessibleButton";
+import PinnedEventTile from "./PinnedEventTile";
+import { _t } from '../../../languageHandler';
+
+module.exports = React.createClass({
+ displayName: 'PinnedEventsPanel',
+ propTypes: {
+ // The Room from the js-sdk we're going to show pinned events for
+ room: React.PropTypes.object.isRequired,
+
+ onCancelClick: React.PropTypes.func,
+ },
+
+ getInitialState: function() {
+ return {
+ loading: true,
+ };
+ },
+
+ componentDidMount: function() {
+ this._updatePinnedMessages();
+ },
+
+ _updatePinnedMessages: function() {
+ const pinnedEvents = this.props.room.currentState.getStateEvents("m.room.pinned_events", "");
+ if (!pinnedEvents || !pinnedEvents.getContent().pinned) {
+ this.setState({ loading: false, pinned: [] });
+ } else {
+ const promises = [];
+ const cli = MatrixClientPeg.get();
+
+ pinnedEvents.getContent().pinned.map((eventId) => {
+ promises.push(cli.getEventTimeline(this.props.room.getUnfilteredTimelineSet(), eventId, 0).then(
+ (timeline) => {
+ const event = timeline.getEvents().find((e) => e.getId() === eventId);
+ return {eventId, timeline, event};
+ }).catch((err) => {
+ console.error("Error looking up pinned event " + eventId + " in room " + this.props.room.roomId);
+ console.error(err);
+ return null; // return lack of context to avoid unhandled errors
+ }));
+ });
+
+ Promise.all(promises).then((contexts) => {
+ // Filter out the messages before we try to render them
+ const pinned = contexts.filter((context) => {
+ if (!context) return false; // no context == not applicable for the room
+ if (context.event.getType() !== "m.room.message") return false;
+ if (context.event.isRedacted()) return false;
+ return true;
+ });
+
+ this.setState({ loading: false, pinned });
+ });
+ }
+ },
+
+ _getPinnedTiles: function() {
+ if (this.state.pinned.length == 0) {
+ return (
{ _t("No pinned messages.") }
);
+ }
+
+ return this.state.pinned.map((context) => {
+ return (
);
+ });
+ },
+
+ render: function() {
+ let tiles =
{ _t("Loading...") }
;
+ if (this.state && !this.state.loading) {
+ tiles = this._getPinnedTiles();
+ }
+
+ return (
+
+
+
+
{ _t("Pinned Messages") }
+ { tiles }
+
+
+ );
+ },
+});
diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js
index 42cbb90cd9..4df0ff738c 100644
--- a/src/components/views/rooms/RoomHeader.js
+++ b/src/components/views/rooms/RoomHeader.js
@@ -31,6 +31,7 @@ import linkifyMatrix from '../../../linkify-matrix';
import AccessibleButton from '../elements/AccessibleButton';
import ManageIntegsButton from '../elements/ManageIntegsButton';
import {CancelButton} from './SimpleRoomHeader';
+import UserSettingsStore from "../../../UserSettingsStore";
linkifyMatrix(linkify);
@@ -45,6 +46,7 @@ module.exports = React.createClass({
inRoom: React.PropTypes.bool,
collapsedRhs: React.PropTypes.bool,
onSettingsClick: React.PropTypes.func,
+ onPinnedClick: React.PropTypes.func,
onSaveClick: React.PropTypes.func,
onSearchClick: React.PropTypes.func,
onLeaveClick: React.PropTypes.func,
@@ -129,6 +131,10 @@ module.exports = React.createClass({
}).done();
},
+ onAvatarRemoveClick: function() {
+ MatrixClientPeg.get().sendStateEvent(this.props.room.roomId, 'm.room.avatar', {url: null}, '');
+ },
+
onShowRhsClick: function(ev) {
dis.dispatch({ action: 'show_right_panel' });
},
@@ -172,6 +178,7 @@ module.exports = React.createClass({
let spinner = null;
let saveButton = null;
let settingsButton = null;
+ let pinnedEventsButton = null;
let canSetRoomName;
let canSetRoomAvatar;
@@ -268,11 +275,15 @@ module.exports = React.createClass({
+
+
+
);
} else if (this.props.room || (this.props.oobData && this.props.oobData.name)) {
@@ -290,6 +301,13 @@ module.exports = React.createClass({
;
}
+ if (this.props.onPinnedClick && UserSettingsStore.isFeatureEnabled('feature_pinning')) {
+ pinnedEventsButton =
+
;
+ }
+
// var leave_button;
// if (this.props.onLeaveClick) {
// leave_button =
@@ -334,6 +352,7 @@ module.exports = React.createClass({
rightRow =
{ settingsButton }
+ { pinnedEventsButton }
{ manageIntegsButton }
{ forgetButton }
{ searchButton }
diff --git a/src/components/views/settings/ChangeAvatar.js b/src/components/views/settings/ChangeAvatar.js
index b3204ab86e..a363dc2c60 100644
--- a/src/components/views/settings/ChangeAvatar.js
+++ b/src/components/views/settings/ChangeAvatar.js
@@ -53,6 +53,10 @@ module.exports = React.createClass({
};
},
+ componentWillMount: function() {
+ MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
+ },
+
componentWillReceiveProps: function(newProps) {
if (this.avatarSet) {
// don't clobber what the user has just set
@@ -63,6 +67,28 @@ module.exports = React.createClass({
});
},
+ componentWillUnmount: function() {
+ if (MatrixClientPeg.get()) {
+ MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
+ }
+ },
+
+ onRoomStateEvents: function(ev) {
+ if (!this.props.room) {
+ return;
+ }
+
+ if (ev.getRoomId() !== this.props.room.roomId || ev.getType() !== 'm.room.avatar'
+ || ev.getSender() !== MatrixClientPeg.get().getUserId()) {
+ return;
+ }
+
+ if (!ev.getContent().url) {
+ this.avatarSet = false;
+ this.setState({}); // force update
+ }
+ },
+
setAvatarFromFile: function(file) {
let newUrl = null;
diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json
index 63f21e80a1..c7b05de215 100644
--- a/src/i18n/strings/de_DE.json
+++ b/src/i18n/strings/de_DE.json
@@ -728,7 +728,7 @@
"WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and device %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!": "WARNUNG: SCHLÜSSEL-VERIFIZIERUNG FEHLGESCHLAGEN! Der Signatur-Schlüssel für %(userId)s und das Gerät %(deviceId)s ist \"%(fprint)s\", welcher nicht mit dem bereitgestellten Schlüssel \"%(fingerprint)s\" übereinstimmt. Dies kann bedeuten, dass deine Kommunikation abgehört wird!",
"You have
disabled URL previews by default.": "Du hast die URL-Vorschau standardmäßig
deaktiviert.",
"You have
enabled URL previews by default.": "Du hast die URL-Vorschau standardmäßig
aktiviert.",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName hat das Raum-Bild geändert zu
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s hat das Raum-Bild geändert zu
",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s hat das Raum-Bild für %(roomName)s geändert",
"Hide removed messages": "Gelöschte Nachrichten verbergen",
"Start new chat": "Neuen Chat starten",
diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json
index 99ae411d94..06009b0b3b 100644
--- a/src/i18n/strings/el.json
+++ b/src/i18n/strings/el.json
@@ -639,7 +639,7 @@
"Disable URL previews by default for participants in this room": "Απενεργοποίηση της προεπισκόπησης συνδέσμων για όλους τους συμμετέχοντες στο δωμάτιο",
"Disable URL previews for this room (affects only you)": "Απενεργοποίηση της προεπισκόπησης συνδέσμων για αυτό το δωμάτιο (επηρεάζει μόνο εσάς)",
" (unsupported)": " (μη υποστηριζόμενο)",
- "$senderDisplayName changed the room avatar to
": "Ο $senderDisplayName άλλαξε την εικόνα του δωματίου σε
",
+ "%(senderDisplayName)s changed the room avatar to
": "Ο %(senderDisplayName)s άλλαξε την εικόνα του δωματίου σε
",
"Missing Media Permissions, click here to request.": "Λείπουν τα δικαιώματα πολύμεσων, κάντε κλικ για να ζητήσετε.",
"You may need to manually permit Riot to access your microphone/webcam": "Μπορεί να χρειαστεί να ορίσετε χειροκίνητα την πρόσβαση του Riot στο μικρόφωνο/κάμερα",
"Can't connect to homeserver - please check your connectivity, ensure your
homeserver's SSL certificate is trusted, and that a browser extension is not blocking requests.": "Δεν είναι δυνατή η σύνδεση στον διακομιστή - παρακαλούμε ελέγξτε την συνδεσιμότητα, βεβαιωθείτε ότι το
πιστοποιητικό SSL του διακομιστή είναι έμπιστο και ότι κάποιο πρόσθετο περιηγητή δεν αποτρέπει τα αιτήματα.",
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index e542253641..df236636a2 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -252,6 +252,7 @@
"%(targetName)s joined the room.": "%(targetName)s joined the room.",
"Joins room with given alias": "Joins room with given alias",
"Jump to first unread message.": "Jump to first unread message.",
+ "Jump to read receipt": "Jump to read receipt",
"%(senderName)s kicked %(targetName)s.": "%(senderName)s kicked %(targetName)s.",
"Kick": "Kick",
"Kicks user with given id": "Kicks user with given id",
@@ -289,6 +290,7 @@
"matrix-react-sdk version:": "matrix-react-sdk version:",
"Matrix Apps": "Matrix Apps",
"Members only": "Members only",
+ "Disable big emoji in chat": "Disable big emoji in chat",
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
"Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present",
"Missing room_id in request": "Missing room_id in request",
@@ -609,6 +611,7 @@
"Room": "Room",
"Copied!": "Copied!",
"Failed to copy": "Failed to copy",
+ "There's no one else here! Would you like to
invite others or
stop warning about the empty room?": "There's no one else here! Would you like to
invite others or
stop warning about the empty room?",
"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.",
"
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.",
@@ -616,6 +619,7 @@
"(~%(count)s results)|other": "(~%(count)s results)",
"Cancel": "Cancel",
"or": "or",
+ "Message Pinning": "Message Pinning",
"Active call": "Active call",
"Monday": "Monday",
"Tuesday": "Tuesday",
@@ -632,6 +636,7 @@
"quote": "quote",
"bullet": "bullet",
"numbullet": "numbullet",
+ "Remove avatar": "Remove avatar",
"%(severalUsers)sjoined %(repeats)s times": "%(severalUsers)sjoined %(repeats)s times",
"%(oneUser)sjoined %(repeats)s times": "%(oneUser)sjoined %(repeats)s times",
"%(severalUsers)sjoined": "%(severalUsers)sjoined",
@@ -785,7 +790,7 @@
"Start chatting": "Start chatting",
"Start Chatting": "Start Chatting",
"Click on the button below to start chatting!": "Click on the button below to start chatting!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName changed the room avatar to
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s changed the room avatar to
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
"Username available": "Username available",
@@ -885,6 +890,8 @@
"Add rooms to the group summary": "Add rooms to the group summary",
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
"Room name or alias": "Room name or alias",
+ "Pinned Messages": "Pinned Messages",
+ "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
"You are an administrator of this group": "You are an administrator of this group",
"Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:",
"Failed to remove the room from the summary of %(groupId)s": "Failed to remove the room from the summary of %(groupId)s",
@@ -917,5 +924,7 @@
"Related groups for this room:": "Related groups for this room:",
"This room has no related groups": "This room has no related groups",
"New group ID (e.g. +foo:%(localDomain)s)": "New group ID (e.g. +foo:%(localDomain)s)",
+ "Invites sent": "Invites sent",
+ "Your group invitations have been sent.": "Your group invitations have been sent.",
"%(serverName)s Matrix ID": "%(serverName)s Matrix ID"
}
diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json
index 5236e959d4..7326b54799 100644
--- a/src/i18n/strings/en_US.json
+++ b/src/i18n/strings/en_US.json
@@ -705,7 +705,7 @@
"Idle": "Idle",
"Offline": "Offline",
"Disable URL previews for this room (affects only you)": "Disable URL previews for this room (affects only you)",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName changed the room avatar to
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s changed the room avatar to
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
"Active call (%(roomName)s)": "Active call (%(roomName)s)",
@@ -844,6 +844,7 @@
"+example:%(domain)s": "+example:%(domain)s",
"Group IDs must be of the form +localpart:%(domain)s": "Group IDs must be of the form +localpart:%(domain)s",
"Room creation failed": "Room creation failed",
+ "Pinned Messages": "Pinned Messages",
"You are a member of these groups:": "You are a member of these groups:",
"Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.": "Create a group to represent your community! Define a set of rooms and your own custom homepage to mark out your space in the Matrix universe.",
"Join an existing group": "Join an existing group",
@@ -859,6 +860,7 @@
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
"Robot check is currently unavailable on desktop - please use a
web browser": "Robot check is currently unavailable on desktop - please use a
web browser",
"Verifies a user, device, and pubkey tuple": "Verifies a user, device, and pubkey tuple",
+ "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.",
"It is currently only possible to create groups on your own home server: use a group ID ending with %(domain)s": "It is currently only possible to create groups on your own home server: use a group ID ending with %(domain)s",
"To join an existing group you'll have to know its group identifier; this will look something like
+example:matrix.org.": "To join an existing group you'll have to know its group identifier; this will look something like
+example:matrix.org.",
"%(weekDayName)s, %(monthName)s %(day)s": "%(weekDayName)s, %(monthName)s %(day)s",
diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json
index fcad984ff5..825940fdc4 100644
--- a/src/i18n/strings/eu.json
+++ b/src/i18n/strings/eu.json
@@ -736,7 +736,7 @@
"Start chatting": "Hasi txateatzen",
"Start Chatting": "Hasi txateatzen",
"Click on the button below to start chatting!": "Egin klik beheko botoian txateatzen hasteko!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName erabiltzaileak gelaren abatarra aldatu du beste honetara:
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s erabiltzaileak gelaren abatarra aldatu du beste honetara:
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s erabiltzaileak gelaren abatarra ezabatu du.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s erabiltzaileak %(roomName)s gelaren abatarra aldatu du",
"Username available": "Erabiltzaile-izena eskuragarri dago",
diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json
index d07a162f8d..3a45793b7c 100644
--- a/src/i18n/strings/fr.json
+++ b/src/i18n/strings/fr.json
@@ -637,7 +637,7 @@
"for %(amount)sm": "depuis %(amount)sm",
"for %(amount)sh": "depuis %(amount)sh",
"for %(amount)sd": "depuis %(amount)sj",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName a changé l’avatar du salon en
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s a changé l’avatar du salon en
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s a supprimé l'avatar du salon.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s a changé l’avatar de %(roomName)s",
"Device already verified!": "Appareil déjà vérifié !",
diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json
index bcd3452a6c..4e2c39b27b 100644
--- a/src/i18n/strings/hu.json
+++ b/src/i18n/strings/hu.json
@@ -723,7 +723,7 @@
"Start chatting": "Csevegés indítása",
"Start Chatting": "Csevegés indítása",
"Click on the button below to start chatting!": "Csevegés indításához kattints a gombra alább!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName megváltoztatta a szoba avatar képét:
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s megváltoztatta a szoba avatar képét:
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s törölte a szoba avatar képét.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s megváltoztatta %(roomName)s szoba avatar képét",
"Username available": "Szabad felhasználói név",
diff --git a/src/i18n/strings/ko.json b/src/i18n/strings/ko.json
index 307ee762ef..98a07e629d 100644
--- a/src/i18n/strings/ko.json
+++ b/src/i18n/strings/ko.json
@@ -743,7 +743,7 @@
"Start chatting": "이야기하기",
"Start Chatting": "이야기하기",
"Click on the button below to start chatting!": "이야기하려면 아래 버튼을 누르세요!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName님이 방 아바타를
로 바꾸셨어요",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s님이 방 아바타를
로 바꾸셨어요",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s님이 방 아바타를 지우셨어요.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s가 %(roomName)s 방의 아바타를 바꾸셨어요",
"Username available": "쓸 수 있는 사용자 이름",
diff --git a/src/i18n/strings/lv.json b/src/i18n/strings/lv.json
index 0a5e999015..164b6226d9 100644
--- a/src/i18n/strings/lv.json
+++ b/src/i18n/strings/lv.json
@@ -619,7 +619,7 @@
"Dec": "Dec.",
"Set a display name:": "Iestatīt redzamo vārdu:",
"This image cannot be displayed.": "Šo attēlu nav iespējams parādīt.",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName nomainīja istabas attēlu uz
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s nomainīja istabas attēlu uz
",
"Upload an avatar:": "Augšuplādē profila attēlu:",
"This server does not support authentication with a phone number.": "Šis serveris neatbalsta autentifikāciju pēc telefona numura.",
"Missing password.": "Trūkst parole.",
diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json
index 38ca640fc8..c12a2ad81c 100644
--- a/src/i18n/strings/nl.json
+++ b/src/i18n/strings/nl.json
@@ -746,7 +746,7 @@
"Start chatting": "Start met praten",
"Start Chatting": "Start Met Praten",
"Click on the button below to start chatting!": "Klik op de knop hieronder om te starten met praten!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName heeft de ruimte avatar aangepast naar
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s heeft de ruimte avatar aangepast naar
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s heeft de ruimte avatar verwijderd.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s veranderde de avatar voor %(roomName)s",
"Username available": "Gebruikersnaam beschikbaar",
diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json
index 0b11e26c44..66e7b2aa28 100644
--- a/src/i18n/strings/pl.json
+++ b/src/i18n/strings/pl.json
@@ -771,7 +771,7 @@
"for %(amount)sd": "%(amount)s dni",
"Idle": "Bezczynny",
"Check for update": "Sprawdź aktualizacje",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName zmienił awatar pokoju na
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s zmienił awatar pokoju na
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s usunął awatar pokoju.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s zmienił awatar %(roomName)s",
"This will be your account name on the
homeserver, or you can pick a
different server.": "To będzie twoja nazwa konta na
serwerze domowym; możesz też wybrać
inny serwer.",
diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json
index 56beb43e33..73d7e6ca68 100644
--- a/src/i18n/strings/pt.json
+++ b/src/i18n/strings/pt.json
@@ -699,7 +699,7 @@
"for %(amount)sd": "por %(amount)sd",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a imagem da sala.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName alterou a imagem da sala para
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s alterou a imagem da sala para
",
"Missing Media Permissions, click here to request.": "Faltam permissões para uso de mídia no seu computador. Clique aqui para solicitá-las.",
"No Microphones detected": "Não foi detetado nenhum microfone",
"No Webcams detected": "Não foi detetada nenhuma Webcam",
diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json
index 109c0bb6c2..691cf8d9bf 100644
--- a/src/i18n/strings/pt_BR.json
+++ b/src/i18n/strings/pt_BR.json
@@ -696,7 +696,7 @@
"for %(amount)sd": "por %(amount)sd",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removeu a imagem da sala.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s alterou a imagem da sala %(roomName)s",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName alterou a imagem da sala para
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s alterou a imagem da sala para
",
"Missing Media Permissions, click here to request.": "Faltam permissões para uso de mídia no seu computador. Clique aqui para solicitá-las.",
"No Microphones detected": "Não foi detectado nenhum microfone",
"No Webcams detected": "Não foi detectada nenhuma Webcam",
diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json
index ab09fd1700..fffce4f328 100644
--- a/src/i18n/strings/ru.json
+++ b/src/i18n/strings/ru.json
@@ -705,7 +705,7 @@
"Idle": "Неактивен",
"Offline": "Не в сети",
"Disable URL previews for this room (affects only you)": "Отключить предпросмотр URL-адресов для этой комнаты (влияет только на вас)",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName сменил аватар комнаты на
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s сменил аватар комнаты на
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s удалил аватар комнаты.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s сменил аватар для %(roomName)s",
"Create new room": "Создать новую комнату",
diff --git a/src/i18n/strings/tr.json b/src/i18n/strings/tr.json
index 98be1c9a64..fdc06f741c 100644
--- a/src/i18n/strings/tr.json
+++ b/src/i18n/strings/tr.json
@@ -738,7 +738,7 @@
"Start chatting": "Sohbeti başlat",
"Start Chatting": "Sohbeti Başlat",
"Click on the button below to start chatting!": "Sohbeti başlatmak için aşağıdaki butona tıklayın!",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName odanın avatarını
olarak çevirdi",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s odanın avatarını
olarak çevirdi",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s odanın avatarını kaldırdı.",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s %(roomName)s için avatarı değiştirdi",
"Username available": "Kullanıcı ismi uygun",
diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json
index 83aadd5178..35e18b9793 100644
--- a/src/i18n/strings/zh_Hant.json
+++ b/src/i18n/strings/zh_Hant.json
@@ -228,7 +228,7 @@
"Idle": "閒置",
"Offline": "下線",
"Disable URL previews for this room (affects only you)": "在這個房間禁止URL預覽(只影響你)",
- "$senderDisplayName changed the room avatar to
": "$senderDisplayName 更改了聊天室的圖像為
",
+ "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s 更改了聊天室的圖像為
",
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s 移除了聊天室圖片。",
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s 更改了聊天室 %(roomName)s 圖像",
"Cancel": "取消",
diff --git a/src/languageHandler.js b/src/languageHandler.js
index b2fc65c46d..a90b78c40e 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -109,8 +109,9 @@ export function _tJsx(jsxText, patterns, subs) {
}
// The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
- const tJsxText = _t(jsxText);
+ const tJsxText = _t(jsxText, {interpolate: false});
const output = [tJsxText];
+
for (let i = 0; i < patterns.length; i++) {
// convert the last element in 'output' into 3 elements (pre-text, sub function, post-text).
// Rinse and repeat for other patterns (using post-text).