diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js
index 59d8c74022..8848a33deb 100644
--- a/src/components/structures/login/Login.js
+++ b/src/components/structures/login/Login.js
@@ -18,7 +18,7 @@ limitations under the License.
'use strict';
import React from 'react';
-import { _t } from '../../../languageHandler';
+import { _t, _tJsx } from '../../../languageHandler';
import ReactDOM from 'react-dom';
import sdk from '../../../index';
import Login from '../../../Login';
diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js
index 25a920d2e0..49f89aa469 100644
--- a/src/components/views/elements/LanguageDropdown.js
+++ b/src/components/views/elements/LanguageDropdown.js
@@ -40,14 +40,7 @@ export default class LanguageDropdown extends React.Component {
}
componentWillMount() {
- languageHandler.getAllLanguageKeysFromJson().then((langKeys) => {
- const langs = [];
- langKeys.forEach((languageKey) => {
- langs.push({
- value: languageKey,
- label: _t(languageKey)
- });
- });
+ languageHandler.getAllLanguagesFromJson().then((langs) => {
langs.sort(function(a, b){
if(a.label < b.label) return -1;
if(a.label > b.label) return 1;
diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js
index f12ef3ac9d..a4a117b9cb 100644
--- a/src/components/views/elements/PowerSelector.js
+++ b/src/components/views/elements/PowerSelector.js
@@ -118,7 +118,7 @@ module.exports = React.createClass({
});
options.push({ value: "Custom", text: "Custom level" });
options = options.map((op) => {
- return ;
+ return ;
});
select =
diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js
new file mode 100644
index 0000000000..525f7b81ee
--- /dev/null
+++ b/src/components/views/messages/RoomAvatarEvent.js
@@ -0,0 +1,92 @@
+/*
+Copyright 2017 Vector Creations 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.
+*/
+
+import React from 'react';
+import MatrixClientPeg from '../../../MatrixClientPeg';
+import { ContentRepo } from 'matrix-js-sdk';
+import { _t, _tJsx } from '../../../languageHandler';
+import sdk from '../../../index';
+import Modal from '../../../Modal';
+import AccessibleButton from '../elements/AccessibleButton';
+
+module.exports = React.createClass({
+ displayName: 'RoomAvatarEvent',
+
+ propTypes: {
+ /* the MatrixEvent to show */
+ mxEvent: React.PropTypes.object.isRequired,
+ },
+
+ onAvatarClick: function(name) {
+ var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(this.props.mxEvent.getContent().url);
+ var ImageView = sdk.getComponent("elements.ImageView");
+ var params = {
+ src: httpUrl,
+ name: name,
+ };
+ Modal.createDialog(ImageView, params, "mx_Dialog_lightbox");
+ },
+
+ render: function() {
+ var ev = this.props.mxEvent;
+ var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
+ var BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
+
+ var room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
+ var name = _t('%(senderDisplayName)s changed the avatar for %(roomName)s', {
+ senderDisplayName: senderDisplayName,
+ roomName: room ? room.name : '',
+ });
+
+ if (!ev.getContent().url || ev.getContent().url.trim().length === 0) {
+ return (
+
+ { _t('%(senderDisplayName)s removed the room avatar.', {senderDisplayName: senderDisplayName}) }
+
+ );
+ }
+
+ var url = ContentRepo.getHttpUriForMxc(
+ MatrixClientPeg.get().getHomeserverUrl(),
+ ev.getContent().url,
+ 14 * window.devicePixelRatio,
+ 14 * window.devicePixelRatio,
+ 'crop'
+ );
+
+ // it sucks that _tJsx doesn't support normal _t substitutions :((
+ return (
+
+ { _tJsx('$senderDisplayName changed the room avatar to
',
+ [
+ /\$senderDisplayName/,
+ /
/,
+ ],
+ [
+ (sub) => senderDisplayName,
+ (sub) =>
+
+
+ ,
+ ]
+ )
+ }
+
+ );
+ },
+});
diff --git a/src/components/views/messages/TextualEvent.js b/src/components/views/messages/TextualEvent.js
index 8319dbd434..088f7cbbc6 100644
--- a/src/components/views/messages/TextualEvent.js
+++ b/src/components/views/messages/TextualEvent.js
@@ -24,6 +24,11 @@ import sdk from '../../../index';
module.exports = React.createClass({
displayName: 'TextualEvent',
+ propTypes: {
+ /* the MatrixEvent to show */
+ mxEvent: React.PropTypes.object.isRequired,
+ },
+
render: function() {
const EmojiText = sdk.getComponent('elements.EmojiText');
var text = TextForEvent.textForEvent(this.props.mxEvent);
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index d9a6925793..e527f53170 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -38,6 +38,7 @@ var eventTileTypes = {
'm.call.answer' : 'messages.TextualEvent',
'm.call.hangup' : 'messages.TextualEvent',
'm.room.name' : 'messages.TextualEvent',
+ 'm.room.avatar' : 'messages.RoomAvatarEvent',
'm.room.topic' : 'messages.TextualEvent',
'm.room.third_party_invite' : 'messages.TextualEvent',
'm.room.history_visibility' : 'messages.TextualEvent',
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 15aa3916bc..95baf1f50e 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -776,5 +776,8 @@
"Online": "Online",
"Idle": "Idle",
"Offline": "Offline",
- "Disable URL previews for this room (affects only you)": "Disable URL previews for this room (affects only you)"
+ "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 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"
}
diff --git a/src/languageHandler.js b/src/languageHandler.js
index 1c3acab082..ab29dd926e 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -133,7 +133,7 @@ export function setLanguage(preferredLangs) {
throw new Error("Unable to find an appropriate language");
}
- return getLanguage(i18nFolder + availLangs[langToUse]);
+ return getLanguage(i18nFolder + availLangs[langToUse].fileName);
}).then((langData) => {
counterpart.registerTranslations(langToUse, langData);
counterpart.setLocale(langToUse);
@@ -142,16 +142,25 @@ export function setLanguage(preferredLangs) {
// Set 'en' as fallback language:
if (langToUse != "en") {
- return getLanguage(i18nFolder + availLangs['en']);
+ return getLanguage(i18nFolder + availLangs['en'].fileName);
}
}).then((langData) => {
if (langData) counterpart.registerTranslations('en', langData);
});
};
-export function getAllLanguageKeysFromJson() {
- return getLangsJson().then((langs) => {
- return Object.keys(langs);
+export function getAllLanguagesFromJson() {
+ return getLangsJson().then((langsObject) => {
+ var langs = [];
+ for (var langKey in langsObject) {
+ if (langsObject.hasOwnProperty(langKey)) {
+ langs.push({
+ 'value': langKey,
+ 'label': langsObject[langKey].label
+ });
+ }
+ }
+ return langs;
});
}