Merge branch 'issue7461-localize-remaining-labels' of github.com:diegobenetti/bigbluebutton into test-loc

This commit is contained in:
Anton Georgiev 2019-05-24 15:17:00 +00:00
commit 420bb9b3f8
12 changed files with 197 additions and 107 deletions

View File

@ -231,7 +231,13 @@ class Poll extends Component {
renderActivePollOptions() {
const {
intl, publishPoll, stopPoll, currentUser, currentPoll, getUser,
intl,
publishPoll,
stopPoll,
currentUser,
currentPoll,
getUser,
pollAnswerIds,
} = this.props;
return (
@ -246,6 +252,7 @@ class Poll extends Component {
currentUser,
getUser,
currentPoll,
pollAnswerIds,
}}
handleBackClick={this.handleBackClick}
/>

View File

@ -33,5 +33,6 @@ export default withTracker(() => {
currentPoll: Service.currentPoll(),
getUser: Service.getUser,
resetPollPanel: Session.get('resetPollPanel') || false,
pollAnswerIds: Service.pollAnswerIds,
};
})(PollContainer);

View File

@ -43,7 +43,9 @@ const getResponseString = (obj) => {
class LiveResult extends Component {
static getDerivedStateFromProps(nextProps) {
const { currentPoll, getUser } = nextProps;
const {
currentPoll, getUser, intl, pollAnswerIds,
} = nextProps;
if (!currentPoll) return null;
@ -71,19 +73,29 @@ class LiveResult extends Component {
};
})
.sort(Service.sortUsers)
.reduce((acc, user) => [
...acc,
(
<tr key={_.uniqueId('stats-')}>
<td className={styles.resultLeft}>{user.name}</td>
<td className={styles.resultRight}>{user.answer}</td>
</tr>
),
], []);
.reduce((acc, user) => {
const formattedMessageIndex = user.answer.toLowerCase();
return ([
...acc,
(
<tr key={_.uniqueId('stats-')}>
<td className={styles.resultLeft}>{user.name}</td>
<td className={styles.resultRight}>
{
pollAnswerIds[formattedMessageIndex]
? intl.formatMessage(pollAnswerIds[formattedMessageIndex])
: user.answer
}
</td>
</tr>
),
]);
}, []);
const pollStats = [];
answers.map((obj) => {
const formattedMessageIndex = obj.key.toLowerCase();
const pct = Math.round(obj.numVotes / numRespondents * 100);
const pctFotmatted = `${Number.isNaN(pct) ? 0 : pct}%`;
@ -94,7 +106,11 @@ class LiveResult extends Component {
return pollStats.push(
<div className={styles.main} key={_.uniqueId('stats-')}>
<div className={styles.left}>
{obj.key}
{
pollAnswerIds[formattedMessageIndex]
? intl.formatMessage(pollAnswerIds[formattedMessageIndex])
: obj.key
}
</div>
<div className={styles.center}>
<div className={styles.barShade} style={calculatedWidth} />

View File

@ -11,6 +11,45 @@ import Polls from '/imports/api/polls';
// 'A-5' = A,B,C,D,E
const pollTypes = ['YN', 'TF', 'A-2', 'A-3', 'A-4', 'A-5', 'custom'];
const pollAnswerIds = {
true: {
id: 'app.poll.answer.true',
description: 'label for poll answer True',
},
false: {
id: 'app.poll.answer.false',
description: 'label for poll answer False',
},
yes: {
id: 'app.poll.answer.yes',
description: 'label for poll answer Yes',
},
no: {
id: 'app.poll.answer.no',
description: 'label for poll answer No',
},
a: {
id: 'app.poll.answer.a',
description: 'label for poll answer A',
},
b: {
id: 'app.poll.answer.b',
description: 'label for poll answer B',
},
c: {
id: 'app.poll.answer.c',
description: 'label for poll answer C',
},
d: {
id: 'app.poll.answer.d',
description: 'label for poll answer D',
},
e: {
id: 'app.poll.answer.e',
description: 'label for poll answer E',
},
};
export default {
currentUser: () => Users.findOne({ userId: Auth.userID }),
pollTypes,
@ -18,4 +57,5 @@ export default {
publishPoll: () => makeCall('publishPoll'),
currentPoll: () => Polls.findOne({ meetingId: Auth.meetingID }),
getUser: userId => Users.findOne({ userId }),
pollAnswerIds,
};

View File

@ -36,7 +36,9 @@ class Polling extends Component {
}
render() {
const { intl, poll, handleVote } = this.props;
const {
intl, poll, handleVote, pollAnswerIds,
} = this.props;
const { stackOptions, answers } = poll;
const pollAnswerStyles = {
[styles.pollingAnswers]: true,
@ -57,40 +59,48 @@ class Polling extends Component {
{intl.formatMessage(intlMessages.pollingTitleLabel)}
</div>
<div className={cx(pollAnswerStyles)}>
{poll.answers.map(pollAnswer => (
<div
key={pollAnswer.id}
className={styles.pollButtonWrapper}
>
<Tooltip
{poll.answers.map((pollAnswer) => {
const formattedMessageIndex = pollAnswer.key.toLowerCase();
let label = pollAnswer.key;
if (pollAnswerIds[formattedMessageIndex]) {
label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]);
}
return (
<div
key={pollAnswer.id}
title={pollAnswer.key}
className={styles.pollButtonWrapper}
>
<Button
className={styles.pollingButton}
color="primary"
size="md"
label={pollAnswer.key}
key={pollAnswer.key}
onClick={() => handleVote(poll.pollId, pollAnswer)}
aria-labelledby={`pollAnswerLabel${pollAnswer.key}`}
aria-describedby={`pollAnswerDesc${pollAnswer.key}`}
/>
</Tooltip>
<div
className={styles.hidden}
id={`pollAnswerLabel${pollAnswer.key}`}
>
{intl.formatMessage(intlMessages.pollAnswerLabel, { 0: pollAnswer.key })}
<Tooltip
key={pollAnswer.id}
title={label}
>
<Button
className={styles.pollingButton}
color="primary"
size="md"
label={label}
key={pollAnswer.key}
onClick={() => handleVote(poll.pollId, pollAnswer)}
aria-labelledby={`pollAnswerLabel${pollAnswer.key}`}
aria-describedby={`pollAnswerDesc${pollAnswer.key}`}
/>
</Tooltip>
<div
className={styles.hidden}
id={`pollAnswerLabel${pollAnswer.key}`}
>
{intl.formatMessage(intlMessages.pollAnswerLabel, { 0: label })}
</div>
<div
className={styles.hidden}
id={`pollAnswerDesc${pollAnswer.key}`}
>
{intl.formatMessage(intlMessages.pollAnswerDesc, { 0: label })}
</div>
</div>
<div
className={styles.hidden}
id={`pollAnswerDesc${pollAnswer.key}`}
>
{intl.formatMessage(intlMessages.pollAnswerDesc, { 0: pollAnswer.key })}
</div>
</div>
))}
);
})}
</div>
</div>
</div>);

View File

@ -4,6 +4,7 @@ import { withTracker } from 'meteor/react-meteor-data';
import Users from '/imports/api/users';
import Auth from '/imports/ui/services/auth';
import PollingService from './service';
import Service from '/imports/ui/components/poll/service';
import PollingComponent from './component';
const propTypes = {
@ -23,6 +24,11 @@ const PollingContainer = ({ pollExists, ...props }) => {
PollingContainer.propTypes = propTypes;
export default withTracker(() => {
const data = PollingService.mapPolls();
return data;
const { pollExists, handleVote, poll } = PollingService.mapPolls();
return ({
pollExists,
handleVote,
poll,
pollAnswerIds: Service.pollAnswerIds,
});
})(PollingContainer);

View File

@ -249,7 +249,6 @@ class Settings extends Component {
const {
intl,
mountModal,
notify,
} = this.props;
const {
current,
@ -260,16 +259,11 @@ class Settings extends Component {
title={intl.formatMessage(intlMessages.SettingsLabel)}
confirm={{
callback: () => {
this.updateSettings(current);
this.updateSettings(current, intl.formatMessage(intlMessages.savedAlertLabel));
/* We need to use mountModal(null) here to prevent submenu state updates,
* from re-opening the modal.
*/
mountModal(null);
notify(
intl.formatMessage(intlMessages.savedAlertLabel),
'info',
'settings',
);
},
label: intl.formatMessage(intlMessages.SaveLabel),
description: intl.formatMessage(intlMessages.SaveLabelDesc),

View File

@ -1,7 +1,6 @@
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import SettingsService from '/imports/ui/services/settings';
import { notify } from '/imports/ui/services/notification';
import Settings from './component';
import {
@ -25,5 +24,4 @@ export default withTracker(() => ({
locales: getClosedCaptionLocales(),
availableLocales: getAvailableLocales(),
isModerator: getUserRoles() === 'MODERATOR',
notify,
}))(SettingsContainer);

View File

@ -3,6 +3,7 @@ import Captions from '/imports/api/captions';
import Auth from '/imports/ui/services/auth';
import _ from 'lodash';
import Settings from '/imports/ui/services/settings';
import { notify } from '/imports/ui/services/notification';
const getClosedCaptionLocales = () => {
// list of unique locales in the Captions Collection
@ -22,9 +23,20 @@ const getUserRoles = () => {
return user.role;
};
const updateSettings = (obj) => {
const updateSettings = (obj, msg) => {
Object.keys(obj).forEach(k => (Settings[k] = obj[k]));
Settings.save();
if (msg) {
// prevents React state update on unmounted component
setTimeout(() => {
notify(
msg,
'info',
'settings',
);
}, 0);
}
};
const getAvailableLocales = () => fetch('/html5client/locales').then(locales => locales.json());

View File

@ -37,7 +37,7 @@ class UserPolls extends PureComponent {
<div className={styles.messages}>
{
<h2 className={styles.smallTitle}>
{'Polling'}
{intl.formatMessage(intlMessages.pollLabel)}
</h2>
}
<div className={styles.scrollableList}>

View File

@ -1,15 +1,9 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { notify } from '/imports/ui/services/notification';
import Service from '/imports/ui/components/poll/service';
import { defineMessages, injectIntl } from 'react-intl';
const intlMessages = defineMessages({
pollPublishedLabel: {
id: 'app.whiteboard.annotations.poll',
description: 'message displayed when a poll is published',
},
});
class PollDrawComponent extends Component {
constructor(props) {
super(props);
@ -60,18 +54,12 @@ class PollDrawComponent extends Component {
}
componentWillMount() {
const { intl } = this.props;
notify(
intl.formatMessage(intlMessages.pollPublishedLabel),
'info',
'polling',
);
// in this part we retrieve the props and perform initial calculations for the state
// calculating only the parts which have to be done just once and don't require
// rendering / rerendering the text objects
const { points, result } = this.props.annotation;
const { slideWidth, slideHeight } = this.props;
const { slideWidth, slideHeight, intl } = this.props;
// x1 and y1 - coordinates of the top left corner of the annotation
// initial width and height are the width and height of the annotation
@ -135,6 +123,11 @@ class PollDrawComponent extends Component {
const maxLineHeight = (innerHeight * 0.75) / textArray.length;
const lineToMeasure = textArray[0];
const pollAnswerIds = Service.pollAnswerIds;
const messageIndex = lineToMeasure[0].toLowerCase();
if (pollAnswerIds[messageIndex]) {
lineToMeasure[0] = intl.formatMessage(pollAnswerIds[messageIndex]);
}
// saving all the initial calculations in the state
this.setState({
@ -190,9 +183,9 @@ class PollDrawComponent extends Component {
// first check if we can still increase the font-size
if (this.state.fontSizeDirection === 1) {
if (keySizes.width < maxLineWidth && keySizes.height < maxLineHeight &&
voteSizes.width < maxLineWidth && voteSizes.height < maxLineHeight &&
percSizes.width < maxLineWidth && percSizes.height < maxLineHeight) {
if (keySizes.width < maxLineWidth && keySizes.height < maxLineHeight
&& voteSizes.width < maxLineWidth && voteSizes.height < maxLineHeight
&& percSizes.width < maxLineWidth && percSizes.height < maxLineHeight) {
return this.setState({
calcFontSize: this.state.calcFontSize + 1,
});
@ -203,11 +196,11 @@ class PollDrawComponent extends Component {
fontSizeDirection: -1,
calcFontSize: this.state.calcFontSize - 1,
});
} else if (this.state.fontSizeDirection === -1) {
} if (this.state.fontSizeDirection === -1) {
// check if the font-size is still bigger than allowed
if (keySizes.width > maxLineWidth || keySizes.height > maxLineHeight ||
voteSizes.width > maxLineWidth || voteSizes.height > maxLineHeight ||
percSizes.width > maxLineWidth || percSizes.height > maxLineHeight) {
if (keySizes.width > maxLineWidth || keySizes.height > maxLineHeight
|| voteSizes.width > maxLineWidth || voteSizes.height > maxLineHeight
|| percSizes.width > maxLineWidth || percSizes.height > maxLineHeight) {
return this.setState({
calcFontSize: this.state.calcFontSize - 1,
});
@ -289,7 +282,9 @@ class PollDrawComponent extends Component {
thickness,
} = this.state;
const { annotation } = this.props;
const { annotation, intl } = this.props;
const pollAnswerIds = Service.pollAnswerIds;
//* ********************************************************************************************
//* *****************************************MAGIC NUMBER***************************************
@ -323,8 +318,8 @@ class PollDrawComponent extends Component {
// Initial coordinates of the percentage column
let yRight = ((innerRect.y + verticalPadding) + (barHeight / 2)) - magicNumber;
const xRight = ((((innerRect.x + (horizontalPadding * 3)) +
maxLeftWidth) + maxRightWidth) + maxBarWidth + 1);
const xRight = ((((innerRect.x + (horizontalPadding * 3))
+ maxLeftWidth) + maxRightWidth) + maxBarWidth + 1);
let yNumVotes = (innerRect.y + verticalPadding) - magicNumber;
const extendedTextArray = [];
@ -336,6 +331,12 @@ class PollDrawComponent extends Component {
barWidth = (annotation.result[i].numVotes / maxNumVotes) * maxBarWidth;
}
let label = textArray[i][0];
const formattedMessageIndex = label.toLowerCase();
if (pollAnswerIds[formattedMessageIndex]) {
label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]);
}
// coordinates and color of the text inside the line bar
// xNumVotesDefault and xNumVotesMovedRight are 2 different x coordinates for the text
// since if the line bar is too small then we place the number to the right of the bar
@ -352,11 +353,10 @@ class PollDrawComponent extends Component {
color = 'white';
}
extendedTextArray[i] =
{
extendedTextArray[i] = {
key: `${annotation.id}_${textArray[i][3]}`,
keyColumn: {
keyString: textArray[i][0],
keyString: label,
xLeft,
yLeft,
},
@ -412,19 +412,19 @@ class PollDrawComponent extends Component {
fontSize={calcFontSize}
textAnchor="start"
>
{extendedTextArray.map(line =>
(<tspan
{extendedTextArray.map(line => (
<tspan
x={line.keyColumn.xLeft}
y={line.keyColumn.yLeft}
dy={maxLineHeight / 2}
key={`${line.key}_key`}
>
{line.keyColumn.keyString}
</tspan>),
)}
</tspan>
))}
</text>
{extendedTextArray.map(line =>
(<rect
{extendedTextArray.map(line => (
<rect
key={`${line.key}_bar`}
x={line.barColumn.xBar}
y={line.barColumn.yBar}
@ -433,8 +433,8 @@ class PollDrawComponent extends Component {
stroke="#333333"
fill="#333333"
strokeWidth={thickness - 1}
/>),
)}
/>
))}
<text
x={innerRect.x}
y={innerRect.y}
@ -443,16 +443,16 @@ class PollDrawComponent extends Component {
fontSize={calcFontSize}
textAnchor="end"
>
{extendedTextArray.map(line =>
(<tspan
{extendedTextArray.map(line => (
<tspan
x={line.percentColumn.xRight}
y={line.percentColumn.yRight}
dy={maxLineHeight / 2}
key={`${line.key}_percent`}
>
{line.percentColumn.percentString}
</tspan>),
)}
</tspan>
))}
</text>
<text
x={innerRect.x}
@ -461,8 +461,8 @@ class PollDrawComponent extends Component {
fontFamily="Arial"
fontSize={calcFontSize}
>
{extendedTextArray.map(line =>
(<tspan
{extendedTextArray.map(line => (
<tspan
x={line.barColumn.xNumVotes + (line.barColumn.barWidth / 2)}
y={line.barColumn.yNumVotes + (line.barColumn.barHeight / 2)}
dy={maxLineHeight / 2}
@ -470,8 +470,8 @@ class PollDrawComponent extends Component {
fill={line.barColumn.color}
>
{line.barColumn.numVotes}
</tspan>),
)}
</tspan>
))}
</text>
</g>
);
@ -522,9 +522,7 @@ class PollDrawComponent extends Component {
}
return (
<g>
{this.state.textArray.map(line =>
this.renderLine(line),
)
{this.state.textArray.map(line => this.renderLine(line))
}
<text
fontFamily="Arial"
@ -542,10 +540,9 @@ class PollDrawComponent extends Component {
render() {
return (
<g>
{this.state.prepareToDisplay ?
this.renderTestStrings()
:
this.renderPoll()
{this.state.prepareToDisplay
? this.renderTestStrings()
: this.renderPoll()
}
</g>
);

View File

@ -162,6 +162,15 @@
"app.poll.a3": "A / B / C",
"app.poll.a4": "A / B / C / D",
"app.poll.a5": "A / B / C / D / E",
"app.poll.answer.true": "True",
"app.poll.answer.false": "False",
"app.poll.answer.yes": "Yes",
"app.poll.answer.no": "No",
"app.poll.answer.a": "A",
"app.poll.answer.b": "B",
"app.poll.answer.c": "C",
"app.poll.answer.d": "D",
"app.poll.answer.e": "E",
"app.poll.liveResult.usersTitle": "Users",
"app.poll.liveResult.responsesTitle": "Response",
"app.polling.pollingTitle": "Polling options",