Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
RiotTranslate 2017-05-28 11:10:16 +00:00
commit f08d40fb7b
12 changed files with 199 additions and 54 deletions

2
.gitignore vendored
View file

@ -10,5 +10,5 @@ npm-debug.log
# test reports created by karma # test reports created by karma
/karma-reports /karma-reports
# ignore auto-generated component index /.idea
/src/component-index.js /src/component-index.js

View file

@ -42,9 +42,17 @@ foreach my $tuple (@$src_strings) {
print "\nChecking en_EN\n"; print "\nChecking en_EN\n";
my $count = 0; my $count = 0;
my $remaining_src = {};
foreach (keys %$src) { $remaining_src->{$_}++ };
foreach my $k (sort keys %$en) { foreach my $k (sort keys %$en) {
# crappy heuristic to ignore country codes for now... # crappy heuristic to ignore country codes for now...
next if ($k =~ /^(..|..-..)$/); next if ($k =~ /^(..|..-..)$/);
if ($en->{$k} ne $k) {
printf ("%50s %24s\t%s\n", "en_EN", "en_EN is not symmetrical", $k);
}
if (!$src->{$k}) { if (!$src->{$k}) {
if ($src->{$k. '.'}) { if ($src->{$k. '.'}) {
printf ("%50s %24s\t%s\n", $src->{$k. '.'}, "src has fullstop!", $k); printf ("%50s %24s\t%s\n", $src->{$k. '.'}, "src has fullstop!", $k);
@ -61,9 +69,13 @@ foreach my $k (sort keys %$en) {
} }
else { else {
$count++; $count++;
delete $remaining_src->{$k};
} }
} }
printf ("$count/" . (scalar keys %$src) . " strings found in src are present in en_EN\n"); printf ("$count/" . (scalar keys %$src) . " strings found in src are present in en_EN\n");
foreach (keys %$remaining_src) {
print "missing: $_\n";
}
opendir(DIR, $i18ndir) || die $!; opendir(DIR, $i18ndir) || die $!;
my @files = readdir(DIR); my @files = readdir(DIR);
@ -74,12 +86,32 @@ foreach my $lang (grep { -f "$i18ndir/$_" && !/(basefile|en_EN)\.json/ } @files)
my $map = read_i18n($i18ndir."/".$lang); my $map = read_i18n($i18ndir."/".$lang);
my $count = 0; my $count = 0;
my $remaining_en = {};
foreach (keys %$en) { $remaining_en->{$_}++ };
foreach my $k (sort keys %$map) { foreach my $k (sort keys %$map) {
{
no warnings 'uninitialized';
my $vars = {};
while ($k =~ /%\((.*?)\)s/g) {
$vars->{$1}++;
}
while ($map->{$k} =~ /%\((.*?)\)s/g) {
$vars->{$1}--;
}
foreach my $var (keys %$vars) {
if ($vars->{$var} != 0) {
printf ("%10s %24s\t%s\n", $lang, "Broken var ($var)s", $k);
}
}
}
if ($en->{$k}) { if ($en->{$k}) {
if ($map->{$k} eq $k) { if ($map->{$k} eq $k) {
printf ("%10s %24s\t%s\n", $lang, "Untranslated string?", $k); printf ("%10s %24s\t%s\n", $lang, "Untranslated string?", $k);
} }
$count++; $count++;
delete $remaining_en->{$k};
} }
else { else {
if ($en->{$k . "."}) { if ($en->{$k . "."}) {
@ -97,6 +129,12 @@ foreach my $lang (grep { -f "$i18ndir/$_" && !/(basefile|en_EN)\.json/ } @files)
} }
} }
if (scalar keys %$remaining_en < 100) {
foreach (keys %$remaining_en) {
printf ("%10s %24s\t%s\n", $lang, "Not yet translated", $_);
}
}
printf ("$count/" . (scalar keys %$en) . " strings translated\n"); printf ("$count/" . (scalar keys %$en) . " strings translated\n");
} }

View file

@ -22,7 +22,7 @@ let isDialogOpen = false;
const onAction = function(payload) { const onAction = function(payload) {
if (payload.action === 'unknown_device_error' && !isDialogOpen) { if (payload.action === 'unknown_device_error' && !isDialogOpen) {
var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog');
isDialogOpen = true; isDialogOpen = true;
Modal.createDialog(UnknownDeviceDialog, { Modal.createDialog(UnknownDeviceDialog, {
devices: payload.err.devices, devices: payload.err.devices,
@ -33,17 +33,17 @@ const onAction = function(payload) {
// https://github.com/vector-im/riot-web/issues/3148 // https://github.com/vector-im/riot-web/issues/3148
console.log('UnknownDeviceDialog closed with '+r); console.log('UnknownDeviceDialog closed with '+r);
}, },
}, "mx_Dialog_unknownDevice"); }, 'mx_Dialog_unknownDevice');
} }
} };
let ref = null; let ref = null;
export function startListening () { export function startListening() {
ref = dis.register(onAction); ref = dis.register(onAction);
} }
export function stopListening () { export function stopListening() {
if (ref) { if (ref) {
dis.unregister(ref); dis.unregister(ref);
ref = null; ref = null;

View file

@ -183,7 +183,7 @@ export default React.createClass({
ConferenceHandler={this.props.ConferenceHandler} ConferenceHandler={this.props.ConferenceHandler}
scrollStateMap={this._scrollStateMap} scrollStateMap={this._scrollStateMap}
/>; />;
if (!this.props.collapse_rhs) right_panel = <RightPanel roomId={this.props.currentRoomId} opacity={this.props.sideOpacity} />; if (!this.props.collapse_rhs) right_panel = <RightPanel roomId={this.props.currentRoomId} opacity={this.props.rightOpacity} />;
break; break;
case PageTypes.UserSettings: case PageTypes.UserSettings:
@ -195,7 +195,7 @@ export default React.createClass({
referralBaseUrl={this.props.config.referralBaseUrl} referralBaseUrl={this.props.config.referralBaseUrl}
teamToken={this.props.teamToken} teamToken={this.props.teamToken}
/>; />;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/>; if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>;
break; break;
case PageTypes.CreateRoom: case PageTypes.CreateRoom:
@ -203,7 +203,7 @@ export default React.createClass({
onRoomCreated={this.props.onRoomCreated} onRoomCreated={this.props.onRoomCreated}
collapsedRhs={this.props.collapse_rhs} collapsedRhs={this.props.collapse_rhs}
/>; />;
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/>; if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>;
break; break;
case PageTypes.RoomDirectory: case PageTypes.RoomDirectory:
@ -219,12 +219,12 @@ export default React.createClass({
teamServerUrl={this.props.config.teamServerConfig.teamServerURL} teamServerUrl={this.props.config.teamServerConfig.teamServerURL}
teamToken={this.props.teamToken} teamToken={this.props.teamToken}
/> />
if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.sideOpacity}/> if (!this.props.collapse_rhs) right_panel = <RightPanel opacity={this.props.rightOpacity}/>
break; break;
case PageTypes.UserView: case PageTypes.UserView:
page_element = null; // deliberately null for now page_element = null; // deliberately null for now
right_panel = <RightPanel userId={this.props.viewUserId} opacity={this.props.sideOpacity} />; right_panel = <RightPanel userId={this.props.viewUserId} opacity={this.props.rightOpacity} />;
break; break;
} }
@ -253,7 +253,7 @@ export default React.createClass({
<LeftPanel <LeftPanel
selectedRoom={this.props.currentRoomId} selectedRoom={this.props.currentRoomId}
collapsed={this.props.collapse_lhs || false} collapsed={this.props.collapse_lhs || false}
opacity={this.props.sideOpacity} opacity={this.props.leftOpacity}
teamToken={this.props.teamToken} teamToken={this.props.teamToken}
/> />
<main className='mx_MatrixChat_middlePanel'> <main className='mx_MatrixChat_middlePanel'>

View file

@ -117,8 +117,9 @@ module.exports = React.createClass({
collapse_rhs: false, collapse_rhs: false,
ready: false, ready: false,
width: 10000, width: 10000,
sideOpacity: 1.0, leftOpacity: 1.0,
middleOpacity: 1.0, middleOpacity: 1.0,
rightOpacity: 1.0,
version: null, version: null,
newVersion: null, newVersion: null,
@ -247,7 +248,6 @@ module.exports = React.createClass({
UDEHandler.startListening(); UDEHandler.startListening();
this.focusComposer = false; this.focusComposer = false;
window.addEventListener("focus", this.onFocus);
// this can technically be done anywhere but doing this here keeps all // this can technically be done anywhere but doing this here keeps all
// the routing url path logic together. // the routing url path logic together.
@ -491,12 +491,14 @@ module.exports = React.createClass({
collapse_rhs: false, collapse_rhs: false,
}); });
break; break;
case 'ui_opacity': case 'ui_opacity': {
const sideDefault = payload.sideOpacity >= 0.0 ? payload.sideOpacity : 1.0;
this.setState({ this.setState({
sideOpacity: payload.sideOpacity, leftOpacity: payload.leftOpacity >= 0.0 ? payload.leftOpacity : sideDefault,
middleOpacity: payload.middleOpacity, middleOpacity: payload.middleOpacity || 1.0,
rightOpacity: payload.rightOpacity >= 0.0 ? payload.rightOpacity : sideDefault,
}); });
break; break; }
case 'set_theme': case 'set_theme':
this._onSetTheme(payload.value); this._onSetTheme(payload.value);
break; break;
@ -910,10 +912,6 @@ module.exports = React.createClass({
}); });
}, },
onFocus: function(ev) {
dis.dispatch({action: 'focus_composer'});
},
showScreen: function(screen, params) { showScreen: function(screen, params) {
if (screen == 'register') { if (screen == 'register') {
dis.dispatch({ dis.dispatch({

View file

@ -125,6 +125,8 @@ module.exports = React.createClass({
room: null, room: null,
roomId: null, roomId: null,
roomLoading: true, roomLoading: true,
forwardingEvent: null,
editingRoomSettings: false, editingRoomSettings: false,
uploadingRoomSettings: false, uploadingRoomSettings: false,
numUnreadMessages: 0, numUnreadMessages: 0,
@ -452,6 +454,11 @@ module.exports = React.createClass({
callState: callState callState: callState
}); });
break;
case 'forward_event':
this.setState({
forwardingEvent: payload.content,
});
break; break;
} }
}, },
@ -1195,7 +1202,10 @@ module.exports = React.createClass({
onCancelClick: function() { onCancelClick: function() {
console.log("updateTint from onCancelClick"); console.log("updateTint from onCancelClick");
this.updateTint(); this.updateTint();
this.setState({editingRoomSettings: false}); this.setState({
editingRoomSettings: false,
forwardingEvent: null,
});
dis.dispatch({action: 'focus_composer'}); dis.dispatch({action: 'focus_composer'});
}, },
@ -1473,16 +1483,17 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
var RoomHeader = sdk.getComponent('rooms.RoomHeader'); const RoomHeader = sdk.getComponent('rooms.RoomHeader');
var MessageComposer = sdk.getComponent('rooms.MessageComposer'); const MessageComposer = sdk.getComponent('rooms.MessageComposer');
var RoomSettings = sdk.getComponent("rooms.RoomSettings"); const ForwardMessage = sdk.getComponent("rooms.ForwardMessage");
var AuxPanel = sdk.getComponent("rooms.AuxPanel"); const RoomSettings = sdk.getComponent("rooms.RoomSettings");
var SearchBar = sdk.getComponent("rooms.SearchBar"); const AuxPanel = sdk.getComponent("rooms.AuxPanel");
var ScrollPanel = sdk.getComponent("structures.ScrollPanel"); const SearchBar = sdk.getComponent("rooms.SearchBar");
var TintableSvg = sdk.getComponent("elements.TintableSvg"); const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
var RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
var Loader = sdk.getComponent("elements.Spinner"); const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
var TimelinePanel = sdk.getComponent("structures.TimelinePanel"); const Loader = sdk.getComponent("elements.Spinner");
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
if (!this.state.room) { if (!this.state.room) {
if (this.state.roomLoading) { if (this.state.roomLoading) {
@ -1610,17 +1621,16 @@ module.exports = React.createClass({
/>; />;
} }
var aux = null; let aux = null;
if (this.state.editingRoomSettings) { if (this.state.forwardingEvent !== null) {
aux = <ForwardMessage onCancelClick={this.onCancelClick} currentRoomId={this.state.room.roomId} mxEvent={this.state.forwardingEvent} />;
} else if (this.state.editingRoomSettings) {
aux = <RoomSettings ref="room_settings" onSaveClick={this.onSettingsSaveClick} onCancelClick={this.onCancelClick} room={this.state.room} />; aux = <RoomSettings ref="room_settings" onSaveClick={this.onSettingsSaveClick} onCancelClick={this.onCancelClick} room={this.state.room} />;
} } else if (this.state.uploadingRoomSettings) {
else if (this.state.uploadingRoomSettings) {
aux = <Loader/>; aux = <Loader/>;
} } else if (this.state.searching) {
else if (this.state.searching) {
aux = <SearchBar ref="search_bar" searchInProgress={this.state.searchInProgress } onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch}/>; aux = <SearchBar ref="search_bar" searchInProgress={this.state.searchInProgress } onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch}/>;
} } else if (!myMember || myMember.membership !== "join") {
else if (!myMember || myMember.membership !== "join") {
// We do have a room object for this room, but we're not currently in it. // We do have a room object for this room, but we're not currently in it.
// We may have a 3rd party invite to it. // We may have a 3rd party invite to it.
var inviterName = undefined; var inviterName = undefined;
@ -1733,14 +1743,13 @@ module.exports = React.createClass({
} }
// console.log("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview); // console.log("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview);
var messagePanel = ( var messagePanel = (
<TimelinePanel ref={this._gatherTimelinePanelRef} <TimelinePanel ref={this._gatherTimelinePanelRef}
timelineSet={this.state.room.getUnfilteredTimelineSet()} timelineSet={this.state.room.getUnfilteredTimelineSet()}
manageReadReceipts={!UserSettingsStore.getSyncedSetting('hideReadReceipts', false)} manageReadReceipts={!UserSettingsStore.getSyncedSetting('hideReadReceipts', false)}
manageReadMarkers={true} manageReadMarkers={true}
hidden={hideMessagePanel} hidden={hideMessagePanel}
highlightedEventId={this.props.highlightedEventId} highlightedEventId={this.state.forwardingEvent ? this.state.forwardingEvent.getId() : this.props.highlightedEventId}
eventId={this.props.eventId} eventId={this.props.eventId}
eventPixelOffset={this.props.eventPixelOffset} eventPixelOffset={this.props.eventPixelOffset}
onScroll={ this.onMessageListScroll } onScroll={ this.onMessageListScroll }
@ -1778,7 +1787,7 @@ module.exports = React.createClass({
onSearchClick={this.onSearchClick} onSearchClick={this.onSearchClick}
onSettingsClick={this.onSettingsClick} onSettingsClick={this.onSettingsClick}
onSaveClick={this.onSettingsSaveClick} onSaveClick={this.onSettingsSaveClick}
onCancelClick={this.onCancelClick} onCancelClick={aux ? this.onCancelClick : null}
onForgetClick={ onForgetClick={
(myMember && myMember.membership === "leave") ? this.onForgetClick : null (myMember && myMember.membership === "leave") ? this.onForgetClick : null
} }

View file

@ -545,12 +545,14 @@ module.exports = React.createClass({
); );
}, },
onLanguageChange: function(l) { onLanguageChange: function(newLang) {
UserSettingsStore.setLocalSetting('language', l); if(this.state.language !== newLang) {
this.setState({ UserSettingsStore.setLocalSetting('language', newLang);
language: l, this.setState({
}); language: newLang,
PlatformPeg.get().reload(); });
PlatformPeg.get().reload();
}
}, },
_renderLanguageSetting: function () { _renderLanguageSetting: function () {

View file

@ -0,0 +1,95 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2017 Michael Telatynski
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 KeyCode from '../../../KeyCode';
module.exports = React.createClass({
displayName: 'ForwardMessage',
propTypes: {
currentRoomId: React.PropTypes.string.isRequired,
/* the MatrixEvent to be forwarded */
mxEvent: React.PropTypes.object.isRequired,
onCancelClick: React.PropTypes.func.isRequired,
},
componentWillMount: function() {
dis.dispatch({
action: 'ui_opacity',
leftOpacity: 1.0,
rightOpacity: 0.3,
middleOpacity: 0.5,
});
},
componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction);
document.addEventListener('keydown', this._onKeyDown);
},
componentWillUnmount: function() {
dis.dispatch({
action: 'ui_opacity',
sideOpacity: 1.0,
middleOpacity: 1.0,
});
dis.unregister(this.dispatcherRef);
document.removeEventListener('keydown', this._onKeyDown);
},
onAction: function(payload) {
if (payload.action === 'view_room') {
const event = this.props.mxEvent;
const Client = MatrixClientPeg.get();
Client.sendEvent(payload.room_id, event.getType(), event.getContent()).done(() => {
dis.dispatch({action: 'message_sent'});
}, (err) => {
if (err.name === "UnknownDeviceError") {
dis.dispatch({
action: 'unknown_device_error',
err: err,
room: Client.getRoom(payload.room_id),
});
}
dis.dispatch({action: 'message_send_failed'});
});
if (this.props.currentRoomId === payload.room_id) this.props.onCancelClick();
}
},
_onKeyDown: function(ev) {
switch (ev.keyCode) {
case KeyCode.ESCAPE:
this.props.onCancelClick();
break;
}
},
render: function() {
return (
<div className="mx_ForwardMessage">
<h1>Please select the destination room for this message</h1>
</div>
);
},
});

View file

@ -189,6 +189,9 @@ module.exports = React.createClass({
); );
save_button = <AccessibleButton className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save</AccessibleButton>; save_button = <AccessibleButton className="mx_RoomHeader_textButton" onClick={this.props.onSaveClick}>Save</AccessibleButton>;
}
if (this.props.onCancelClick) {
cancel_button = <CancelButton onClick={this.props.onCancelClick}/>; cancel_button = <CancelButton onClick={this.props.onCancelClick}/>;
} }

View file

@ -16,13 +16,13 @@ limitations under the License.
'use strict'; 'use strict';
var flux = require("flux"); const flux = require("flux");
class MatrixDispatcher extends flux.Dispatcher { class MatrixDispatcher extends flux.Dispatcher {
/** /**
* @param {Object} payload Required. The payload to dispatch. * @param {Object} payload Required. The payload to dispatch.
* Must contain at least an 'action' key. * Must contain at least an 'action' key.
* @param {boolean} sync Optional. Pass true to dispatch * @param {boolean=} sync Optional. Pass true to dispatch
* synchronously. This is useful for anything triggering * synchronously. This is useful for anything triggering
* an operation that the browser requires user interaction * an operation that the browser requires user interaction
* for. * for.

View file

@ -270,7 +270,7 @@
"Failed to reject invitation": "Échec lors du rejet de l'invitation", "Failed to reject invitation": "Échec lors du rejet de l'invitation",
"Failed to save settings": "Échec lors de la sauvegarde des paramètres", "Failed to save settings": "Échec lors de la sauvegarde des paramètres",
"Failed to send email": "Échec lors de lenvoi de le-mail", "Failed to send email": "Échec lors de lenvoi de le-mail",
"Failed to send request": "Échec lors de lenvoi de la requête", "Failed to send request.": "Échec lors de lenvoi de la requête.",
"Failed to set display name": "Échec lors de l'enregistrement du nom d'affichage", "Failed to set display name": "Échec lors de l'enregistrement du nom d'affichage",
"Failed to set up conference call": "Échec lors de létablissement de lappel", "Failed to set up conference call": "Échec lors de létablissement de lappel",
"Failed to toggle moderator status": "Échec lors de létablissement du statut de modérateur", "Failed to toggle moderator status": "Échec lors de létablissement du statut de modérateur",

View file

@ -449,7 +449,7 @@
"sx": "Суту", "sx": "Суту",
"zh-hk": "Китайский (Гонконг)", "zh-hk": "Китайский (Гонконг)",
"A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "На +%(msisdn)s было отправлено текстовое сообщение. Пожалуйста, введите проверочный код из него", "A text message has been sent to +%(msisdn)s. Please enter the verification code it contains": "На +%(msisdn)s было отправлено текстовое сообщение. Пожалуйста, введите проверочный код из него",
"and %(overflowCount)s others...": "и %(overflowCounts)s других...", "and %(overflowCount)s others...": "и %(overflowCount)s других...",
"Are you sure?": "Вы уверены?", "Are you sure?": "Вы уверены?",
"Autoplay GIFs and videos": "Проигрывать GIF и видео автоматически", "Autoplay GIFs and videos": "Проигрывать GIF и видео автоматически",
"Can't connect to homeserver - please check your connectivity and ensure your %(urlStart)s homeserver's SSL certificate %(urlEnd)s is trusted": "Невозможно соединиться с домашним сервером - проверьте своё соединение и убедитесь, что %(urlStart)s SSL-сертификат вашего домашнего сервера %(urlEnd)s включён в доверяемые", "Can't connect to homeserver - please check your connectivity and ensure your %(urlStart)s homeserver's SSL certificate %(urlEnd)s is trusted": "Невозможно соединиться с домашним сервером - проверьте своё соединение и убедитесь, что %(urlStart)s SSL-сертификат вашего домашнего сервера %(urlEnd)s включён в доверяемые",