From c91e6cb530b3e1050b2248b831da23a0dc548060 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 7 Jun 2018 01:02:34 +0100
Subject: [PATCH 1/5] make click to insert nick work on join/parts, /me's etc
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
res/css/_components.scss | 1 +
res/css/views/elements/_TextForEvent.scss | 19 +++
src/TextForEvent.js | 158 +++++++++++++---------
3 files changed, 113 insertions(+), 65 deletions(-)
create mode 100644 res/css/views/elements/_TextForEvent.scss
diff --git a/res/css/_components.scss b/res/css/_components.scss
index 2734939ae3..3f36b6bbdf 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -59,6 +59,7 @@
@import "./views/elements/_RoleButton.scss";
@import "./views/elements/_Spinner.scss";
@import "./views/elements/_SyntaxHighlight.scss";
+@import "./views/elements/_TextForEvent.scss";
@import "./views/elements/_ToolTipButton.scss";
@import "./views/globals/_MatrixToolbar.scss";
@import "./views/groups/_GroupPublicityToggle.scss";
diff --git a/res/css/views/elements/_TextForEvent.scss b/res/css/views/elements/_TextForEvent.scss
new file mode 100644
index 0000000000..8d46cbf84c
--- /dev/null
+++ b/res/css/views/elements/_TextForEvent.scss
@@ -0,0 +1,19 @@
+/*
+Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
+
+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.
+*/
+
+.mx_TextForEvent_username {
+ cursor: pointer;
+}
diff --git a/src/TextForEvent.js b/src/TextForEvent.js
index 712150af4d..0cdaaac4ab 100644
--- a/src/TextForEvent.js
+++ b/src/TextForEvent.js
@@ -17,11 +17,28 @@ import MatrixClientPeg from './MatrixClientPeg';
import CallHandler from './CallHandler';
import { _t } from './languageHandler';
import * as Roles from './Roles';
+import dis from "./dispatcher";
+import React from 'react';
+
+function onUsernameClick(e) {
+ dis.dispatch({
+ action: 'insert_mention',
+ user_id: e.target.id,
+ });
+}
+
+function makeUsernameSpan(mxid, text) {
+ return { text };
+}
function textForMemberEvent(ev) {
// XXX: SYJS-16 "sender is sometimes null for join messages"
const senderName = ev.sender ? ev.sender.name : ev.getSender();
const targetName = ev.target ? ev.target.name : ev.getStateKey();
+
+ const sender = makeUsernameSpan(ev.getSender(), senderName);
+ const target = makeUsernameSpan(ev.getStateKey(), targetName);
+
const prevContent = ev.getPrevContent();
const content = ev.getContent();
@@ -32,47 +49,48 @@ function textForMemberEvent(ev) {
const threePidContent = content.third_party_invite;
if (threePidContent) {
if (threePidContent.display_name) {
- return _t('%(targetName)s accepted the invitation for %(displayName)s.', {
- targetName,
+ return _t(' accepted the invitation for %(displayName)s.', {
displayName: threePidContent.display_name,
+ }, {
+ target,
});
} else {
- return _t('%(targetName)s accepted an invitation.', {targetName});
+ return _t(' accepted an invitation.', {}, {target});
}
} else {
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
- return _t('%(senderName)s requested a VoIP conference.', {senderName});
+ return _t(' requested a VoIP conference.', {}, {sender});
} else {
- return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
+ return _t(' invited .', {}, {sender, target});
}
}
}
case 'ban':
- return _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + reason;
+ return _t(' banned .', {}, {sender, target}) + ' ' + reason;
case 'join':
if (prevContent && prevContent.membership === 'join') {
if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
- return _t('%(oldDisplayName)s changed their display name to %(displayName)s.', {
- oldDisplayName: prevContent.displayname,
- displayName: content.displayname,
+ return _t(' changed their display name to .', {}, {
+ oldDisplayName: makeUsernameSpan(ev.getStateKey(), prevContent.displayname),
+ displayName: makeUsernameSpan(ev.getStateKey(), content.displayname),
});
} else if (!prevContent.displayname && content.displayname) {
- return _t('%(senderName)s set their display name to %(displayName)s.', {
- senderName: ev.getSender(),
- displayName: content.displayname,
+ return _t(' set their display name to .', {}, {
+ sender,
+ displayName: makeUsernameSpan(ev.getSender(), content.displayname),
});
} else if (prevContent.displayname && !content.displayname) {
- return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', {
- senderName,
- oldDisplayName: prevContent.displayname,
+ return _t(' removed their display name ().', {
+ sender,
+ oldDisplayName: makeUsernameSpan(ev.getSender(), prevContent.displayname),
});
} else if (prevContent.avatar_url && !content.avatar_url) {
- return _t('%(senderName)s removed their profile picture.', {senderName});
+ return _t(' removed their profile picture.', {}, {sender});
} else if (prevContent.avatar_url && content.avatar_url &&
prevContent.avatar_url !== content.avatar_url) {
- return _t('%(senderName)s changed their profile picture.', {senderName});
+ return _t(' changed their profile picture.', {}, {sender});
} else if (!prevContent.avatar_url && content.avatar_url) {
- return _t('%(senderName)s set a profile picture.', {senderName});
+ return _t(' set a profile picture.', {}, {sender});
} else {
// suppress null rejoins
return '';
@@ -82,7 +100,7 @@ function textForMemberEvent(ev) {
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
return _t('VoIP conference started.');
} else {
- return _t('%(targetName)s joined the room.', {targetName});
+ return _t(' joined the room.', {}, {target});
}
}
case 'leave':
@@ -90,42 +108,42 @@ function textForMemberEvent(ev) {
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
return _t('VoIP conference finished.');
} else if (prevContent.membership === "invite") {
- return _t('%(targetName)s rejected the invitation.', {targetName});
+ return _t(' rejected the invitation.', {}, {target});
} else {
- return _t('%(targetName)s left the room.', {targetName});
+ return _t(' left the room.', {}, {target});
}
} else if (prevContent.membership === "ban") {
- return _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName});
+ return _t(' unbanned .', {}, {sender, target});
} else if (prevContent.membership === "join") {
- return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason;
+ return _t(' kicked .', {}, {sender, target}) + ' ' + reason;
} else if (prevContent.membership === "invite") {
- return _t('%(senderName)s withdrew %(targetName)s\'s invitation.', {
- senderName,
- targetName,
- }) + ' ' + reason;
+ return _t(' withdrew \'s invitation.', {}, {sender, target}) + ' ' + reason;
} else {
- return _t('%(targetName)s left the room.', {targetName});
+ return _t(' left the room.', {}, {target});
}
}
}
function textForTopicEvent(ev) {
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
- return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', {
- senderDisplayName,
+ return _t(' changed the topic to "%(topic)s".', {
topic: ev.getContent().topic,
+ }, {
+ sender: makeUsernameSpan(ev.getSender(), senderDisplayName),
});
}
function textForRoomNameEvent(ev) {
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
+ const sender = makeUsernameSpan(ev.getSender(), senderDisplayName);
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
- return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName});
+ return _t(' removed the room name.', {}, {sender});
}
- return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', {
- senderDisplayName,
+ return _t(' changed the room name to %(roomName)s.', {
roomName: ev.getContent().name,
+ }, {
+ sender,
});
}
@@ -135,7 +153,9 @@ function textForMessageEvent(ev) {
if (ev.getContent().msgtype === "m.emote") {
message = "* " + senderDisplayName + " " + message;
} else if (ev.getContent().msgtype === "m.image") {
- message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName});
+ message = _t(' sent an image.', {}, {
+ sender: makeUsernameSpan(ev.getSender(), senderDisplayName),
+ });
}
return message;
}
@@ -143,7 +163,9 @@ function textForMessageEvent(ev) {
function textForCallAnswerEvent(event) {
const senderName = event.sender ? event.sender.name : _t('Someone');
const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
- return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported;
+ return _t(' answered the call.', {}, {
+ sender: makeUsernameSpan(event.getSender(), senderName),
+ }) + ' ' + supported;
}
function textForCallHangupEvent(event) {
@@ -161,11 +183,14 @@ function textForCallHangupEvent(event) {
reason = _t('(unknown failure: %(reason)s)', {reason: eventContent.reason});
}
}
- return _t('%(senderName)s ended the call.', {senderName}) + ' ' + reason;
+ return _t(' ended the call.', {}, {
+ sender: makeUsernameSpan(event.getSender(), senderName),
+ }) + ' ' + reason;
}
function textForCallInviteEvent(event) {
const senderName = event.sender ? event.sender.name : _t('Someone');
+ const sender = makeUsernameSpan(event.getSender(), senderName);
// FIXME: Find a better way to determine this from the event?
let callType = "voice";
if (event.getContent().offer && event.getContent().offer.sdp &&
@@ -173,43 +198,47 @@ function textForCallInviteEvent(event) {
callType = "video";
}
const supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
- return _t('%(senderName)s placed a %(callType)s call.', {senderName, callType}) + ' ' + supported;
+ return _t(' placed a %(callType)s call.', {callType}, {sender}) + ' ' + supported;
}
function textForThreePidInviteEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
- return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', {
- senderName,
+ return _t(' sent an invitation to %(targetDisplayName)s to join the room.', {
targetDisplayName: event.getContent().display_name,
+ }, {
+ sender: makeUsernameSpan(event.getSender(), senderName),
});
}
function textForHistoryVisibilityEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
+ const sender = makeUsernameSpan(event.getSender(), senderName);
switch (event.getContent().history_visibility) {
case 'invited':
- return _t('%(senderName)s made future room history visible to all room members, '
- + 'from the point they are invited.', {senderName});
+ return _t(' made future room history visible to all room members, '
+ + 'from the point they are invited.', {}, {sender});
case 'joined':
- return _t('%(senderName)s made future room history visible to all room members, '
- + 'from the point they joined.', {senderName});
+ return _t(' made future room history visible to all room members, '
+ + 'from the point they joined.', {}, {sender});
case 'shared':
- return _t('%(senderName)s made future room history visible to all room members.', {senderName});
+ return _t(' made future room history visible to all room members.', {}, {sender});
case 'world_readable':
- return _t('%(senderName)s made future room history visible to anyone.', {senderName});
+ return _t(' made future room history visible to anyone.', {}, {sender});
default:
- return _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', {
- senderName,
+ return _t(' made future room history visible to unknown (%(visibility)s).', {
visibility: event.getContent().history_visibility,
+ }, {
+ sender,
});
}
}
function textForEncryptionEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
- return _t('%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).', {
- senderName,
+ return _t(' turned on end-to-end encryption (algorithm %(algorithm)s).', {
algorithm: event.getContent().algorithm,
+ }, {
+ sender: makeUsernameSpan(event.getSender(), senderName),
});
}
@@ -241,10 +270,11 @@ function textForPowerEvent(event) {
const to = event.getContent().users[userId];
if (to !== from) {
diff.push(
- _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
- userId,
+ _t(' from %(fromPowerLevel)s to %(toPowerLevel)s', {
fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
toPowerLevel: Roles.textualPowerLevel(to, userDefault),
+ }, {
+ user: makeUsernameSpan(userId, userId),
}),
);
}
@@ -252,19 +282,23 @@ function textForPowerEvent(event) {
if (!diff.length) {
return '';
}
- return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', {
- senderName,
+ return _t(' changed the power level of %(powerLevelDiffText)s.', {
powerLevelDiffText: diff.join(", "),
+ }, {
+ sender: makeUsernameSpan(event.getSender(), senderName),
});
}
function textForPinnedEvent(event) {
- const senderName = event.getSender();
- return _t("%(senderName)s changed the pinned messages for the room.", {senderName});
+ const senderName = event.sender ? event.sender.name : event.getSender();
+ const sender = makeUsernameSpan(event.getSender(), senderName);
+ return _t(" changed the pinned messages for the room.", {}, {sender});
}
function textForWidgetEvent(event) {
- const senderName = event.getSender();
+ const senderName = event.sender ? event.sender.name : event.getSender();
+ const sender = makeUsernameSpan(event.getSender(), senderName);
+
const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
const {name, type, url} = event.getContent() || {};
@@ -278,18 +312,12 @@ function textForWidgetEvent(event) {
// equivalent to that condition.
if (url) {
if (prevUrl) {
- return _t('%(widgetName)s widget modified by %(senderName)s', {
- widgetName, senderName,
- });
+ return _t('%(widgetName)s widget modified by ', {widgetName}, {sender});
} else {
- return _t('%(widgetName)s widget added by %(senderName)s', {
- widgetName, senderName,
- });
+ return _t('%(widgetName)s widget added by ', {widgetName}, {sender});
}
} else {
- return _t('%(widgetName)s widget removed by %(senderName)s', {
- widgetName, senderName,
- });
+ return _t('%(widgetName)s widget removed by ', {widgetName}, {sender});
}
}
From 1d91469104bae6f94c33cc772130cb5c67b52847 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 29 Jun 2018 14:52:25 +0100
Subject: [PATCH 2/5] switch to and use `` over ``
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/TextForEvent.js | 68 +++++++++++++++++++++++++++------------------
1 file changed, 41 insertions(+), 27 deletions(-)
diff --git a/src/TextForEvent.js b/src/TextForEvent.js
index 0cdaaac4ab..3d2e3c1fb5 100644
--- a/src/TextForEvent.js
+++ b/src/TextForEvent.js
@@ -19,16 +19,30 @@ import { _t } from './languageHandler';
import * as Roles from './Roles';
import dis from "./dispatcher";
import React from 'react';
+import PropTypes from 'prop-types';
-function onUsernameClick(e) {
- dis.dispatch({
- action: 'insert_mention',
- user_id: e.target.id,
- });
-}
+class ClickableUsername extends React.PureComponent {
+ static propTypes = {
+ mxid: PropTypes.string.isRequired,
+ text: PropTypes.string.isRequired,
+ };
-function makeUsernameSpan(mxid, text) {
- return { text };
+ constructor(props) {
+ super(props);
+ this.onClick = this.onClick.bind(this);
+ }
+
+ onClick() {
+ dis.dispatch({
+ action: 'insert_mention',
+ user_id: this.props.mxid,
+ });
+ }
+
+ render() {
+ const {mxid, text} = this.props;
+ return { text };
+ }
}
function textForMemberEvent(ev) {
@@ -36,8 +50,8 @@ function textForMemberEvent(ev) {
const senderName = ev.sender ? ev.sender.name : ev.getSender();
const targetName = ev.target ? ev.target.name : ev.getStateKey();
- const sender = makeUsernameSpan(ev.getSender(), senderName);
- const target = makeUsernameSpan(ev.getStateKey(), targetName);
+ const sender = ;
+ const target = ;
const prevContent = ev.getPrevContent();
const content = ev.getContent();
@@ -71,18 +85,18 @@ function textForMemberEvent(ev) {
if (prevContent && prevContent.membership === 'join') {
if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
return _t(' changed their display name to .', {}, {
- oldDisplayName: makeUsernameSpan(ev.getStateKey(), prevContent.displayname),
- displayName: makeUsernameSpan(ev.getStateKey(), content.displayname),
+ oldDisplayName: ,
+ displayName: ,
});
} else if (!prevContent.displayname && content.displayname) {
return _t(' set their display name to .', {}, {
sender,
- displayName: makeUsernameSpan(ev.getSender(), content.displayname),
+ displayName: ,
});
} else if (prevContent.displayname && !content.displayname) {
return _t(' removed their display name ().', {
sender,
- oldDisplayName: makeUsernameSpan(ev.getSender(), prevContent.displayname),
+ oldDisplayName: ,
});
} else if (prevContent.avatar_url && !content.avatar_url) {
return _t(' removed their profile picture.', {}, {sender});
@@ -129,13 +143,13 @@ function textForTopicEvent(ev) {
return _t(' changed the topic to "%(topic)s".', {
topic: ev.getContent().topic,
}, {
- sender: makeUsernameSpan(ev.getSender(), senderDisplayName),
+ sender: ,
});
}
function textForRoomNameEvent(ev) {
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
- const sender = makeUsernameSpan(ev.getSender(), senderDisplayName);
+ const sender = ;
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
return _t(' removed the room name.', {}, {sender});
@@ -154,7 +168,7 @@ function textForMessageEvent(ev) {
message = "* " + senderDisplayName + " " + message;
} else if (ev.getContent().msgtype === "m.image") {
message = _t(' sent an image.', {}, {
- sender: makeUsernameSpan(ev.getSender(), senderDisplayName),
+ sender: ,
});
}
return message;
@@ -164,7 +178,7 @@ function textForCallAnswerEvent(event) {
const senderName = event.sender ? event.sender.name : _t('Someone');
const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
return _t(' answered the call.', {}, {
- sender: makeUsernameSpan(event.getSender(), senderName),
+ sender: ,
}) + ' ' + supported;
}
@@ -184,13 +198,13 @@ function textForCallHangupEvent(event) {
}
}
return _t(' ended the call.', {}, {
- sender: makeUsernameSpan(event.getSender(), senderName),
+ sender: ,
}) + ' ' + reason;
}
function textForCallInviteEvent(event) {
const senderName = event.sender ? event.sender.name : _t('Someone');
- const sender = makeUsernameSpan(event.getSender(), senderName);
+ const sender = ;
// FIXME: Find a better way to determine this from the event?
let callType = "voice";
if (event.getContent().offer && event.getContent().offer.sdp &&
@@ -206,13 +220,13 @@ function textForThreePidInviteEvent(event) {
return _t(' sent an invitation to %(targetDisplayName)s to join the room.', {
targetDisplayName: event.getContent().display_name,
}, {
- sender: makeUsernameSpan(event.getSender(), senderName),
+ sender: ,
});
}
function textForHistoryVisibilityEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
- const sender = makeUsernameSpan(event.getSender(), senderName);
+ const sender = ;
switch (event.getContent().history_visibility) {
case 'invited':
return _t(' made future room history visible to all room members, '
@@ -238,7 +252,7 @@ function textForEncryptionEvent(event) {
return _t(' turned on end-to-end encryption (algorithm %(algorithm)s).', {
algorithm: event.getContent().algorithm,
}, {
- sender: makeUsernameSpan(event.getSender(), senderName),
+ sender: ,
});
}
@@ -274,7 +288,7 @@ function textForPowerEvent(event) {
fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
toPowerLevel: Roles.textualPowerLevel(to, userDefault),
}, {
- user: makeUsernameSpan(userId, userId),
+ user: ,
}),
);
}
@@ -285,19 +299,19 @@ function textForPowerEvent(event) {
return _t(' changed the power level of %(powerLevelDiffText)s.', {
powerLevelDiffText: diff.join(", "),
}, {
- sender: makeUsernameSpan(event.getSender(), senderName),
+ sender: ,
});
}
function textForPinnedEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
- const sender = makeUsernameSpan(event.getSender(), senderName);
+ const sender = ;
return _t(" changed the pinned messages for the room.", {}, {sender});
}
function textForWidgetEvent(event) {
const senderName = event.sender ? event.sender.name : event.getSender();
- const sender = makeUsernameSpan(event.getSender(), senderName);
+ const sender = ;
const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
const {name, type, url} = event.getContent() || {};
From dddf7991b904353eb6884b185d17fd877256b226 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 29 Jun 2018 14:52:50 +0100
Subject: [PATCH 3/5] create map-i18n to aid with transforming the i18n entries
not to waste them
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
scripts/map-i18n.js | 69 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
create mode 100644 scripts/map-i18n.js
diff --git a/scripts/map-i18n.js b/scripts/map-i18n.js
new file mode 100644
index 0000000000..32f81d5e82
--- /dev/null
+++ b/scripts/map-i18n.js
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+/*
+ * Looks through all the translation files and maps matches of fromRegex
+ * in both key and value of the i18n translation to toStr where i18nKeyRegex
+ * matches. Simplifies changing from text to react replacements.
+ * e.g:
+ * node scripts\map-i18n.js "%\(targetName\)s accepted the invitation for %\(displayName\)s\." "%\(targetName\)s" ""
+ */
+
+const fs = require('fs');
+const path = require('path');
+
+const I18NDIR = 'src/i18n/strings';
+
+if (process.argv.length !== 5) {
+ console.error("Required exactly 3 arguments");
+ console.info("Usage: ");
+ return;
+}
+
+const [, , i18nKey, fromStr, toStr] = process.argv;
+const i18nKeyRegex = new RegExp(i18nKey, 'i');
+const fromRegex = new RegExp(fromStr, 'i');
+
+console.info(`Replacing instances of "${fromRegex}" with "${toStr}" in keys and values where key matches "${i18nKey}"`);
+
+for (const filename of fs.readdirSync(I18NDIR)) {
+ if (!filename.endsWith('.json')) continue;
+
+ let numChanged = 0;
+
+ const trs = JSON.parse(fs.readFileSync(path.join(I18NDIR, filename)));
+ for (const tr of Object.keys(trs)) {
+ if (i18nKeyRegex.test(tr) && (fromRegex.test(tr) || fromRegex.test(tr))) {
+ const v = trs[tr];
+ delete trs[tr];
+
+ trs[tr.replace(fromRegex, toStr)] = v.replace(fromRegex, toStr);
+ numChanged++;
+ }
+ }
+
+ if (numChanged > 0) {
+ console.log(`${filename}: transformed ${numChanged} translations`);
+ // XXX: This is totally relying on the impl serialising the JSON object in the
+ // same order as they were parsed from the file. JSON.stringify() has a specific argument
+ // that can be used to control the order, but JSON.parse() lacks any kind of equivalent.
+ // Empirically this does maintain the order on my system, so I'm going to leave it like
+ // this for now.
+ fs.writeFileSync(path.join(I18NDIR, filename), JSON.stringify(trs, undefined, 4) + "\n");
+ }
+}
From 36ace9dcb935b7b91f87963c3d8815566ecc0e69 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 29 Jun 2018 15:21:44 +0100
Subject: [PATCH 4/5] using map-i18n remap all changed `%(...)s` => `<...>` to
keep i18n
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/i18n/strings/bg.json | 80 +++++++++++++++++------------------
src/i18n/strings/ca.json | 80 +++++++++++++++++------------------
src/i18n/strings/cs.json | 78 +++++++++++++++++-----------------
src/i18n/strings/da.json | 48 ++++++++++-----------
src/i18n/strings/de_DE.json | 80 +++++++++++++++++------------------
src/i18n/strings/el.json | 80 +++++++++++++++++------------------
src/i18n/strings/en_EN.json | 80 +++++++++++++++++------------------
src/i18n/strings/en_US.json | 76 ++++++++++++++++-----------------
src/i18n/strings/eo.json | 80 +++++++++++++++++------------------
src/i18n/strings/es.json | 64 ++++++++++++++--------------
src/i18n/strings/eu.json | 80 +++++++++++++++++------------------
src/i18n/strings/fi.json | 78 +++++++++++++++++-----------------
src/i18n/strings/fr.json | 80 +++++++++++++++++------------------
src/i18n/strings/gl.json | 80 +++++++++++++++++------------------
src/i18n/strings/hu.json | 80 +++++++++++++++++------------------
src/i18n/strings/id.json | 20 ++++-----
src/i18n/strings/is.json | 10 ++---
src/i18n/strings/it.json | 80 +++++++++++++++++------------------
src/i18n/strings/ja.json | 4 +-
src/i18n/strings/ko.json | 70 +++++++++++++++---------------
src/i18n/strings/lv.json | 80 +++++++++++++++++------------------
src/i18n/strings/nl.json | 80 +++++++++++++++++------------------
src/i18n/strings/pl.json | 80 +++++++++++++++++------------------
src/i18n/strings/pt.json | 76 ++++++++++++++++-----------------
src/i18n/strings/pt_BR.json | 80 +++++++++++++++++------------------
src/i18n/strings/ru.json | 80 +++++++++++++++++------------------
src/i18n/strings/sk.json | 80 +++++++++++++++++------------------
src/i18n/strings/sr.json | 80 +++++++++++++++++------------------
src/i18n/strings/sv.json | 80 +++++++++++++++++------------------
src/i18n/strings/te.json | 10 ++---
src/i18n/strings/th.json | 48 ++++++++++-----------
src/i18n/strings/tr.json | 70 +++++++++++++++---------------
src/i18n/strings/uk.json | 20 ++++-----
src/i18n/strings/zh_Hans.json | 80 +++++++++++++++++------------------
src/i18n/strings/zh_Hant.json | 80 +++++++++++++++++------------------
35 files changed, 1176 insertions(+), 1176 deletions(-)
diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json
index 5ec9a93bc5..cd5cf5058e 100644
--- a/src/i18n/strings/bg.json
+++ b/src/i18n/strings/bg.json
@@ -148,49 +148,13 @@
"Verified key": "Потвърден ключ",
"Unrecognised command:": "Неразпозната команда:",
"Reason": "Причина",
- "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s прие поканата за %(displayName)s.",
- "%(targetName)s accepted an invitation.": "%(targetName)s прие поканата.",
- "%(senderName)s requested a VoIP conference.": "%(senderName)s заяви VoIP групов разговор.",
- "%(senderName)s invited %(targetName)s.": "%(senderName)s покани %(targetName)s.",
- "%(senderName)s banned %(targetName)s.": "%(senderName)s блокира %(targetName)s.",
- "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s смени своето име на %(displayName)s.",
- "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s си сложи име %(displayName)s.",
- "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s премахна своето име (%(oldDisplayName)s).",
- "%(senderName)s removed their profile picture.": "%(senderName)s премахна своята профилна снимка.",
- "%(senderName)s changed their profile picture.": "%(senderName)s промени своята профилна снимка.",
- "%(senderName)s set a profile picture.": "%(senderName)s зададе снимка на профила си.",
"VoIP conference started.": "Започна VoIP групов разговор.",
- "%(targetName)s joined the room.": "%(targetName)s се присъедини към стаята.",
"VoIP conference finished.": "Груповият разговор приключи.",
- "%(targetName)s rejected the invitation.": "%(targetName)s отхвърли поканата.",
- "%(targetName)s left the room.": "%(targetName)s напусна стаята.",
- "%(senderName)s unbanned %(targetName)s.": "%(senderName)s отблокира %(targetName)s.",
- "%(senderName)s kicked %(targetName)s.": "%(senderName)s изгони %(targetName)s.",
- "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s оттегли поканата си за %(targetName)s.",
- "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s смени темата на \"%(topic)s\".",
- "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s премахна името на стаята.",
- "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s промени името на стаята на %(roomName)s.",
"%(senderDisplayName)s sent an image.": "%(senderDisplayName)s изпрати снимка.",
"Someone": "Някой",
"(not supported by this browser)": "(не се поддържа от този браузър)",
- "%(senderName)s answered the call.": "%(senderName)s отговори на повикването.",
"(no answer)": "(няма отговор)",
"(unknown failure: %(reason)s)": "(неизвестна грешка: %(reason)s)",
- "%(senderName)s ended the call.": "%(senderName)s прекрати разговора.",
- "%(senderName)s placed a %(callType)s call.": "%(senderName)s започна %(callType)s разговор.",
- "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s изпрати покана на %(targetDisplayName)s да се присъедини към стаята.",
- "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s направи бъдещата история на стаята видима за всички членове, от момента на поканването им в нея.",
- "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s направи бъдещата история на стаята видима за всички членове, от момента на присъединяването им в нея.",
- "%(senderName)s made future room history visible to all room members.": "%(senderName)s направи бъдещата история на стаята видима за всички членове в нея.",
- "%(senderName)s made future room history visible to anyone.": "%(senderName)s направи бъдещата история на стаята видима за всеки.",
- "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s направи бъдещата история на стаята видима по непознат начин (%(visibility)s).",
- "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s включи шифроване от край до край (алгоритъм %(algorithm)s).",
- "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s от %(fromPowerLevel)s на %(toPowerLevel)s",
- "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s смени нивото на достъп на %(powerLevelDiffText)s.",
- "%(senderName)s changed the pinned messages for the room.": "%(senderName)s смени закачените съобщения за стаята.",
- "%(widgetName)s widget modified by %(senderName)s": "Приспособлението %(widgetName)s беше променено от %(senderName)s",
- "%(widgetName)s widget added by %(senderName)s": "Приспособлението %(widgetName)s беше добавено от %(senderName)s",
- "%(widgetName)s widget removed by %(senderName)s": "Приспособлението %(widgetName)s беше премахнато от %(senderName)s",
"%(displayName)s is typing": "%(displayName)s пише",
"%(names)s and %(count)s others are typing|other": "%(names)s и %(count)s други пишат",
"%(names)s and %(count)s others are typing|one": "%(names)s и още един човек пишат",
@@ -526,9 +490,6 @@
"Invalid file%(extra)s": "Невалиден файл%(extra)s",
"Error decrypting image": "Грешка при разшифроване на снимка",
"Error decrypting video": "Грешка при разшифроване на видео",
- "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s промени аватара на %(roomName)s",
- "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s премахна аватара на стаята.",
- "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s промени аватара на стаята на
",
"Copied!": "Копирано!",
"Failed to copy": "Неуспешно копиране",
"Add an Integration": "Добавяне на интеграция",
@@ -1181,5 +1142,44 @@
"To continue using the %(homeserverDomain)s homeserver you must review and agree to our terms and conditions.": "За да продължите да ползвате %(homeserverDomain)s е необходимо да прегледате и да се съгласите с правилата и условията за ползване.",
"Review terms and conditions": "Прегледай правилата и условията",
"Failed to indicate account erasure": "Неуспешно указване на желанието за изтриване на акаунта",
- "Try the app first": "Първо пробвайте приложението"
+ "Try the app first": "Първо пробвайте приложението",
+ " accepted the invitation for %(displayName)s.": " прие поканата за %(displayName)s.",
+ " accepted an invitation.": " прие поканата.",
+ " requested a VoIP conference.": " заяви VoIP групов разговор.",
+ " invited .": " покани .",
+ " banned .": " блокира .",
+ " changed their display name to .": " смени своето име на .",
+ " set their display name to .": " си сложи име .",
+ " removed their display name ().": " премахна своето име ().",
+ " removed their profile picture.": " премахна своята профилна снимка.",
+ " changed their profile picture.": " промени своята профилна снимка.",
+ " set a profile picture.": " зададе снимка на профила си.",
+ " joined the room.": " се присъедини към стаята.",
+ " rejected the invitation.": " отхвърли поканата.",
+ " left the room.": " напусна стаята.",
+ " unbanned .": " отблокира .",
+ " kicked .": " изгони .",
+ " withdrew 's invitation.": " оттегли поканата си за .",
+ " changed the topic to \"%(topic)s\".": " смени темата на \"%(topic)s\".",
+ " changed the room name to %(roomName)s.": " промени името на стаята на %(roomName)s.",
+ " changed the avatar for %(roomName)s": " промени аватара на %(roomName)s",
+ " changed the room avatar to
": " промени аватара на стаята на
",
+ " removed the room name.": " премахна името на стаята.",
+ " removed the room avatar.": " премахна аватара на стаята.",
+ " answered the call.": " отговори на повикването.",
+ " ended the call.": " прекрати разговора.",
+ " placed a %(callType)s call.": " започна %(callType)s разговор.",
+ " sent an invitation to %(targetDisplayName)s to join the room.": " изпрати покана на %(targetDisplayName)s да се присъедини към стаята.",
+ " made future room history visible to all room members, from the point they are invited.": " направи бъдещата история на стаята видима за всички членове, от момента на поканването им в нея.",
+ " made future room history visible to all room members, from the point they joined.": " направи бъдещата история на стаята видима за всички членове, от момента на присъединяването им в нея.",
+ " made future room history visible to all room members.": " направи бъдещата история на стаята видима за всички членове в нея.",
+ " made future room history visible to anyone.": " направи бъдещата история на стаята видима за всеки.",
+ " made future room history visible to unknown (%(visibility)s).": " направи бъдещата история на стаята видима по непознат начин (%(visibility)s).",
+ " turned on end-to-end encryption (algorithm %(algorithm)s).": " включи шифроване от край до край (алгоритъм %(algorithm)s).",
+ " from %(fromPowerLevel)s to %(toPowerLevel)s": " от %(fromPowerLevel)s на %(toPowerLevel)s",
+ " changed the power level of %(powerLevelDiffText)s.": " смени нивото на достъп на %(powerLevelDiffText)s.",
+ " changed the pinned messages for the room.": " смени закачените съобщения за стаята.",
+ "%(widgetName)s widget modified by ": "Приспособлението %(widgetName)s беше променено от ",
+ "%(widgetName)s widget added by ": "Приспособлението %(widgetName)s беше добавено от ",
+ "%(widgetName)s widget removed by ": "Приспособлението %(widgetName)s беше премахнато от "
}
diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json
index 98d51e99ac..2e84e60e4c 100644
--- a/src/i18n/strings/ca.json
+++ b/src/i18n/strings/ca.json
@@ -153,49 +153,14 @@
"The signing key you provided matches the signing key you received from %(userId)s's device %(deviceId)s. Device marked as verified.": "La clau de signatura que heu proporcionat coincideix amb la clau de signatura que heu rebut del dispositiu %(deviceId)s de l'usuari %(userId)s. S'ha marcat el dispositiu com a dispositiu verificat.",
"Unrecognised command:": "Ordre no reconegut:",
"Reason": "Raó",
- "%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s ha acceptat la invitació de %(displayName)s.",
- "%(targetName)s accepted an invitation.": "%(targetName)s ha acceptat una invitació.",
- "%(senderName)s requested a VoIP conference.": "%(senderName)s ha sol·licitat una conferència VoIP.",
- "%(senderName)s invited %(targetName)s.": "%(senderName)s ha convidat a %(targetName)s.",
- "%(senderName)s banned %(targetName)s.": "%(senderName)s ha expulsat a %(targetName)s.",
- "%(senderName)s set their display name to %(displayName)s.": "%(senderName)s ha establert %(displayName)s com el seu nom visible.",
- "%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s ha retirat el seu nom visible %(oldDisplayName)s.",
- "%(senderName)s removed their profile picture.": "%(senderName)s ha retirat la seva foto de perfil.",
- "%(senderName)s changed their profile picture.": "%(senderName)s ha canviat la seva foto de perfil.",
- "%(senderName)s set a profile picture.": "%(senderName)s ha establert una foto de perfil.",
"VoIP conference started.": "S'ha iniciat la conferència VoIP.",
- "%(targetName)s joined the room.": "%(targetName)s ha entrat a la sala.",
"VoIP conference finished.": "S'ha finalitzat la conferència VoIP.",
- "%(targetName)s rejected the invitation.": "%(targetName)s ha rebutjat la invitació.",
- "%(targetName)s left the room.": "%(targetName)s ha sortir de la sala.",
- "%(senderName)s unbanned %(targetName)s.": "%(senderName)s ha readmès a %(targetName)s.",
- "%(senderName)s kicked %(targetName)s.": "%(senderName)s ha fet fora a %(targetName)s.",
- "%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s ha retirat la invitació per a %(targetName)s.",
- "%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s ha canviat el tema a \"%(topic)s\".",
- "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s ha eliminat el nom de la sala.",
- "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s ha canviat el nom de la sala a %(roomName)s.",
"%(senderDisplayName)s sent an image.": "%(senderDisplayName)s ha enviat una imatge.",
"Someone": "Algú",
"(not supported by this browser)": "(no és compatible amb aquest navegador)",
- "%(senderName)s answered the call.": "%(senderName)s ha contestat la trucada.",
"(could not connect media)": "(no s'ha pogut connectar el medi)",
"(no answer)": "(sense resposta)",
"(unknown failure: %(reason)s)": "(error desconegut: %(reason)s)",
- "%(senderName)s ended the call.": "%(senderName)s ha penjat.",
- "%(senderName)s placed a %(callType)s call.": "%(senderName)s ha col·locat una trucada de %(callType)s.",
- "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.": "%(senderName)s ha enviat una invitació a %(targetDisplayName)s a entrar a aquesta sala.",
- "%(senderName)s made future room history visible to all room members, from the point they are invited.": "%(senderName)s ha fet visible l'històric futur de la sala per a tots els membres, a partir de que hi són convidats.",
- "%(senderName)s made future room history visible to all room members, from the point they joined.": "%(senderName)s ha fet visible l'històric futur de la sala a tots els membres, des de que entren a la sala.",
- "%(senderName)s made future room history visible to all room members.": "%(senderName)s ha fet visible l'històric futur de la sala a tots els membres de la sala.",
- "%(senderName)s made future room history visible to anyone.": "%(senderName)s ha fet visible l´historial de la sala per a tothom.",
- "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s ha fet visible l'històric de la sala per a desconeguts (%(visibility)s).",
- "%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).": "%(senderName)s ha activat l'encriptació d'extrem a extrem (algoritme %(algorithm)s).",
- "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s de %(fromPowerLevel)s fins %(toPowerLevel)s",
- "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s ha canviat el nivell de potència de %(powerLevelDiffText)s.",
- "%(senderName)s changed the pinned messages for the room.": "%(senderName)s ha canviat els missatges fixats de la sala.",
- "%(widgetName)s widget modified by %(senderName)s": "%(senderName)s ha modificat el giny %(widgetName)s",
- "%(widgetName)s widget added by %(senderName)s": "%(senderName)s ha afegit el giny %(widgetName)s",
- "%(widgetName)s widget removed by %(senderName)s": "%(senderName)s ha eliminat el giny %(widgetName)s",
"%(displayName)s is typing": "%(displayName)s està escrivint",
"%(names)s and %(count)s others are typing|other": "%(names)s i %(count)s més estan escrivint",
"%(names)s and %(count)s others are typing|one": "%(names)s i algú altre està escrivint",
@@ -495,9 +460,6 @@
"Invalid file%(extra)s": "Fitxer invàlid%(extra)s",
"Error decrypting image": "S'ha produït un error en desencriptar la imatge",
"Error decrypting video": "S'ha produït un error en desencriptar el vídeo",
- "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s ha canviat el seu avatar per a la sala %(roomName)s",
- "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s ha eliminat l'avatar de la sala.",
- "%(senderDisplayName)s changed the room avatar to
": "%(senderDisplayName)s ha canviat l'avatar de la sala per aquest
",
"Copied!": "Copiat!",
"Failed to copy": "No s'ha pogut copiar",
"Add an Integration": "Afegeix una integració",
@@ -851,7 +813,6 @@
"Your homeserver's URL": "URL del teu homeserver",
"Your identity server's URL": "URL del teu servidor d'identitat",
"Analytics": "Analítiques",
- "%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s ha canviat el seu nom visible a %(displayName)s.",
"Server may be unavailable or overloaded": "El servidor pot estar inaccessible o sobrecarregat",
"Display name": "Nom visible",
"Identity Server is": "El servidor d'identitat es",
@@ -1016,5 +977,44 @@
"Collapse panel": "Col·lapsa el tauler",
"With your current browser, the look and feel of the application may be completely incorrect, and some or all features may not function. If you want to try it anyway you can continue, but you are on your own in terms of any issues you may encounter!": "Amb el vostre navegador actual, l'aparença de l'aplicació pot ser completament incorrecta i algunes o totes les funcions poden no funcionar correctament. Si voleu provar-ho de totes maneres, podeu continuar, però esteu sols pel que fa als problemes que pugueu trobar!",
"Checking for an update...": "Comprovant si hi ha actualitzacions...",
- "There are advanced notifications which are not shown here": "Hi ha notificacions avançades que no es mostren aquí"
+ "There are advanced notifications which are not shown here": "Hi ha notificacions avançades que no es mostren aquí",
+ " accepted the invitation for %(displayName)s.": " ha acceptat la invitació de %(displayName)s.",
+ " accepted an invitation.": " ha acceptat una invitació.",
+ " requested a VoIP conference.": " ha sol·licitat una conferència VoIP.",
+ " invited .": " ha convidat a .",
+ " banned .": " ha expulsat a .",
+ " changed their display name to .": " ha canviat el seu nom visible a .",
+ " set their display name to .": " ha establert com el seu nom visible.",
+ " removed their display name ().": " ha retirat el seu nom visible .",
+ " removed their profile picture.": " ha retirat la seva foto de perfil.",
+ " changed their profile picture.": " ha canviat la seva foto de perfil.",
+ " set a profile picture.": " ha establert una foto de perfil.",
+ " joined the room.": " ha entrat a la sala.",
+ " rejected the invitation.": " ha rebutjat la invitació.",
+ " left the room.": " ha sortir de la sala.",
+ " unbanned .": " ha readmès a .",
+ " kicked .": " ha fet fora a .",
+ " withdrew 's invitation.": " ha retirat la invitació per a .",
+ " changed the topic to \"%(topic)s\".": " ha canviat el tema a \"%(topic)s\".",
+ " changed the room name to %(roomName)s.": " ha canviat el nom de la sala a %(roomName)s.",
+ " changed the avatar for %(roomName)s": " ha canviat el seu avatar per a la sala %(roomName)s",
+ " changed the room avatar to
": " ha canviat l'avatar de la sala per aquest
",
+ " removed the room name.": " ha eliminat el nom de la sala.",
+ " removed the room avatar.": " ha eliminat l'avatar de la sala.",
+ " answered the call.": " ha contestat la trucada.",
+ " ended the call.": " ha penjat.",
+ " placed a %(callType)s call.": " ha col·locat una trucada de %(callType)s.",
+ " sent an invitation to %(targetDisplayName)s to join the room.": " ha enviat una invitació a %(targetDisplayName)s a entrar a aquesta sala.",
+ " made future room history visible to all room members, from the point they are invited.": " ha fet visible l'històric futur de la sala per a tots els membres, a partir de que hi són convidats.",
+ " made future room history visible to all room members, from the point they joined.": " ha fet visible l'històric futur de la sala a tots els membres, des de que entren a la sala.",
+ " made future room history visible to all room members.": " ha fet visible l'històric futur de la sala a tots els membres de la sala.",
+ " made future room history visible to anyone.": " ha fet visible l´historial de la sala per a tothom.",
+ " made future room history visible to unknown (%(visibility)s).": " ha fet visible l'històric de la sala per a desconeguts (%(visibility)s).",
+ " turned on end-to-end encryption (algorithm %(algorithm)s).": " ha activat l'encriptació d'extrem a extrem (algoritme %(algorithm)s).",
+ " from %(fromPowerLevel)s to %(toPowerLevel)s": " de %(fromPowerLevel)s fins %(toPowerLevel)s",
+ " changed the power level of %(powerLevelDiffText)s.": " ha canviat el nivell de potència de %(powerLevelDiffText)s.",
+ " changed the pinned messages for the room.": " ha canviat els missatges fixats de la sala.",
+ "%(widgetName)s widget modified by ": " ha modificat el giny %(widgetName)s",
+ "%(widgetName)s widget added by