Merge pull request #3861 from LLK/develop

Update Release Branch with Changes from Develop
This commit is contained in:
Karishma Chadha 2020-05-06 17:41:25 -04:00 committed by GitHub
commit b5cb9fb45e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 975 additions and 892 deletions

1130
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -128,7 +128,7 @@
"redux-mock-store": "^1.2.3",
"redux-thunk": "2.0.1",
"sass-loader": "6.0.6",
"scratch-gui": "0.1.0-prerelease.20200430160141",
"scratch-gui": "0.1.0-prerelease.20200506210159",
"scratch-l10n": "latest",
"selenium-webdriver": "3.6.0",
"slick-carousel": "1.6.0",

View file

@ -8,7 +8,7 @@ const HelpForm = props => {
const title = `formTitle=${props.title}`;
const username = `helpdesk_ticket[custom_field][cf_scratch_name_40167]=${props.user.username || ''}`;
const formSubject = `helpdesk_ticket[subject]=${props.subject}`;
const formDescription = `helpdesk_ticket[description]=${props.body}`;
const reportLink = `helpdesk_ticket[custom_field][cf_inappropriate_report_link_40167]=${props.body || ''}`;
return (
<div>
<script
@ -26,10 +26,10 @@ const HelpForm = props => {
<iframe
className="freshwidget-embedded-form"
frameBorder="0"
height="594px"
height="644px"
id="freshwidget-embedded-form"
scrolling="no"
src={`${prefix}&${title}&${username}&${formSubject}&${formDescription}`}
src={`${prefix}&${title}&${username}&${formSubject}&${reportLink}`}
title={<FormattedMessage id="contactUs.questionsForum" />}
width="100%"
/>

View file

@ -7,8 +7,35 @@ const PropTypes = require('prop-types');
const React = require('react');
const Button = require('../forms/button.jsx');
const Spinner = require('../spinner/spinner.jsx');
require('./helpwidget.scss');
// map Scratch locale to supported Freshdesk locale
const freshdeskLocale = locale => {
// most locales in Scratch and Freshdesk use the two letter code. Define exceptions:
const localeMap = {
'es-419': 'es-LA',
'ja': 'ja-JP',
'ja-Hira': 'ja-JP',
'lv': 'lv-LV',
'nb': 'nb-NO',
'nn': 'nb-NO',
'pt': 'pt-PT',
'pt-br': 'pt-BR',
'ru': 'ru-RU',
'sv': 'sv-SE',
'zh-cn': 'zh-CN',
'zh-tw': 'zh-TW'
};
if (localeMap.hasOwnProperty(locale)) {
return localeMap[locale];
}
// locale will either be supported by Freshdesk, or will default to English if not
return locale;
};
/**
* Footer link that opens Freshdesk help widger
* Button or link that opens the Freshdesk Help widget
* see https://developers.freshdesk.com/widget-api/
*/
class HelpWidget extends React.Component {
constructor (props) {
@ -17,8 +44,21 @@ class HelpWidget extends React.Component {
'handleOpenWidget',
'openPopup'
]);
this.state = {
waiting: false
};
}
componentDidMount () {
if (this.props.subject !== '') {
// if passed Inappropriate content params load the script and open the popup
this.loadScript();
}
}
componentWillUnmount () {
window.FreshworksWidget('destroy');
document.getElementById('helpwidgetscript').remove();
}
loadScript () {
// don't add the script to the page more than once
if (document.getElementById('helpwidgetscript') === null) {
const script = document.createElement('script');
@ -30,7 +70,7 @@ class HelpWidget extends React.Component {
window.fwSettings = {
widget_id: 4000000089,
locale: this.props.intl.locale
locale: freshdeskLocale(this.props.intl.locale)
};
document.body.appendChild(script);
}
@ -42,30 +82,40 @@ class HelpWidget extends React.Component {
/* eslint-enable */
// don't show the Freshdesk button
window.FreshworksWidget('hide', 'launcher');
window.FreshworksWidget('setLabels', {
fr: {
banner: 'Bienvenue a Support',
const labels = {};
labels[freshdeskLocale(this.props.intl.locale)] = {
banner: this.props.intl.formatMessage({id: 'helpWidget.banner'}),
contact_form: {
title: this.props.intl.formatMessage({id: 'contactUs.contactScratch'})
}
}
});
if (this.props.subject !== '') {
// open the popup already on the form if passed Inappropriate content params
this.openPopup(true);
title: this.props.intl.formatMessage({id: 'general.contactUs'}),
submit: this.props.intl.formatMessage({id: 'helpWidget.submit'}),
confirmation: this.props.intl.formatMessage({id: 'helpWidget.confirmation'})
}
};
window.FreshworksWidget('setLabels', labels);
window.FreshworksWidget('disable', 'ticketForm', ['custom_fields.cf_inappropriate_report_link']);
window.FreshworksWidget('hide', 'ticketForm', ['custom_fields.cf_inappropriate_report_link']);
// open the popup already on the form if passed Inappropriate content param
this.openPopup(this.props.subject !== '');
}
handleOpenWidget (e) {
this.setState({waiting: true});
e.preventDefault();
// if the Widget is already defined, just open, otherwise load the widget script
if (typeof window.FreshworksWidget === 'function') {
this.openPopup();
} else {
this.loadScript();
}
}
openPopup (formOpen) {
if (typeof window.FreshworksWidget === 'function') {
window.FreshworksWidget('prefill', 'ticketForm', {
subject: this.props.subject,
description: this.props.body,
custom_fields: {
cf_scratch_name: this.props.user.username
cf_scratch_name: this.props.user.username,
cf_inappropriate_report_link: this.props.body
}
});
if (formOpen) {
@ -73,7 +123,9 @@ class HelpWidget extends React.Component {
} else {
window.FreshworksWidget('open');
}
}
// there may still be a little delay before the widget is visible, but there's
// no callback to attach this to.
this.setState({waiting: false});
}
render () {
return (
@ -82,9 +134,19 @@ class HelpWidget extends React.Component {
onClick={this.handleOpenWidget}
>
{this.props.button ? (
this.state.waiting ? (
<Button className="gethelp-button">
<Spinner
className="spinner"
/>
<FormattedMessage id="general.getHelp" />
</Button>
) : (
<Button className="gethelp-button">
<FormattedMessage id="general.getHelp" />
</Button>
)
) : (<FormattedMessage id="general.getHelp" />)
}
</a>

View file

@ -0,0 +1,14 @@
.gethelp-button {
position: relative;
margin-bottom: 2rem;
.spinner {
position: absolute;
width: 2rem;
height: 2rem;
left: 50%;
margin-left: -1rem;
top: 50%;
margin-top: -1rem;
}
}

View file

@ -355,6 +355,10 @@
"social.copyLinkLinkText": "Copy link",
"social.embedCopiedResultText": "Copied",
"helpWidget.banner": "Welcome to Support",
"helpWidget.submit": "Send",
"helpWidget.confirmation": "Thank you for your message.",
"bluetooth.enableLocationServicesTitle": "Make sure you have location services enabled on Chromebooks or Android tablets",
"bluetooth.enableLocationServicesText": "Bluetooth can be used to provide location data to the app. In addition to granting the Scratch App permission to access location, location must be enabled in your general device settings. Search for 'Location' in your settings, and make sure it is on. On Chromebooks search for 'Location' in the Google Play Store Android preferences."
}

View file

@ -8,5 +8,5 @@ const flagInUrl = flag => {
};
module.exports = {
CONTACT_US_POPUP: isStaging() && flagInUrl('CONTACT_US_POPUP')
CONTACT_US_POPUP: flagInUrl('CONTACT_US_POPUP')
};

View file

@ -8,7 +8,7 @@ const render = require('../../lib/render.jsx');
const HelpForm = require('../../components/helpform/helpform.jsx');
const HelpWidget = require('../../components/helpwidget/helpwidget.jsx');
const {CONTACT_US_POPUP} = require('../../lib/feature-flags.js');
const CONTACT_US_POPUP = true;
const InformationPage = require('../../components/informationpage/informationpage.jsx');
require('./contact-us.scss');
@ -25,11 +25,11 @@ class ContactUs extends React.Component {
// The subject is not localized because sending in English is easier for Scratch Team
if (query.indexOf('studio=') !== -1) {
scratchId = query.match(/studio=([0-9]+)/)[1];
this.state.subject = `Inappropriate content reported in studio ${scratchId}`;
this.state.subject = `Issue reported with studio ${scratchId}`;
this.state.body = `https://scratch.mit.edu/studios/${scratchId}`;
} else if (query.indexOf('profile=') !== -1) {
scratchId = query.match(/profile=([a-zA-Z0-9-_]+)/)[1];
this.state.subject = `Inappropriate content reported in profile ${scratchId}`;
this.state.subject = `Issue reported with profile ${scratchId}`;
this.state.body = `https://scratch.mit.edu/users/${scratchId}`;
} else if (query.indexOf('confirmation=') !== -1) {
this.state.subject = 'Problem with email confirmation';
@ -99,9 +99,24 @@ class ContactUs extends React.Component {
<p><FormattedMessage id="contactUs.forumsIntro" /></p>
<p><FormattedMessage id="contactUs.forumsHelp" /></p>
<ul>
<li><a href="/discuss/4/"><FormattedMessage id="contactUs.questionsLinkText" /></a></li>
<li><a href="/discuss/7/"><FormattedMessage id="contactUs.scriptsLinkText" /></a></li>
<li><a href="/discuss/3/"><FormattedMessage id="contactUs.bugsLinkText" /></a></li>
<li><FormattedMessage
id="contactUs.questionsText"
values={{questionsLink: (
<a href="/discuss/4/"><FormattedMessage id="contactUs.questionsLinkText" /></a>
)}}
/></li>
<li><FormattedMessage
id="contactUs.scriptsText"
values={{scriptsLink: (
<a href="/discuss/7/"><FormattedMessage id="contactUs.scriptsLinkText" /></a>
)}}
/></li>
<li><FormattedMessage
id="contactUs.bugsText"
values={{bugsLink: (
<a href="/discuss/3/"><FormattedMessage id="contactUs.bugsLinkText" /></a>
)}}
/></li>
</ul>
<h3>
<FormattedMessage id="contactUs.needSupport" />

View file

@ -1,8 +1,3 @@
#contact-us.helpwidget {
margin-bottom: 0;
}
.contact-us {
.gethelp-button {
margin-bottom: 2rem;
}
}

View file

@ -4,10 +4,13 @@
"contactUs.faqLinkText":"Frequently Asked Questions",
"contactUs.forumsInfo":"If you cannot find an answer in the FAQ, there are many experienced Scratchers in the Discussion Forums who are happy to help.",
"contactUs.forumsLinkText":"Discussion Forums",
"contactUs.questionsText":"{questionsLink}: Ask others in the community about anything related to Scratch.",
"contactUs.questionsForum":"You can ask general questions about how to do stuff in the {questionsLink} forum.",
"contactUs.questionsLinkText":"Questions About Scratch",
"contactUs.scriptsText":"{scriptsLink}: Get help with the blocks or code to make your project work.",
"contactUs.scriptsForum":"If you need help with a specific project, try posting in the {scriptsLink} forum.",
"contactUs.scriptsLinkText":"Help with Scripts",
"contactUs.bugsText":"{bugsLink}: Find out how to deal with technical issues you encounter on the Scratch website or in the project editor.",
"contactUs.bugsForum":"If you want to report a bug in Scratch, check the {bugsLink} forum. It's the best place to report bugs and see if others are experiencing similar difficulties.",
"contactUs.bugsLinkText":"Bugs and Glitches",
"contactUs.formIntro":"If you still need to contact us, please fill out the form below with as much detail as you can. If you have any screenshots, attachments or links that help to explain your problem, please include them. We get a lot of mail, so we may not be able to respond to your message.",

View file

@ -156,10 +156,10 @@ const Credits = () => (
Chris Graves, Joel Gritter, Megan Haddadi, Connor Hudson,
Christina Huang, Tony Hwang, Abdulrahman Idlbi, Randy Jou,
Lily Kim, Tauntaun Kim, Saskia Leggett, Tim Mickel,
Amon Millner, My Nguyen, Lisa O&apos;Brien, Tina Quach,
Ricarose Roque, Andrea Saxman, Jay Silver, Tammy Stern,
Lis Sylvan, Hanako Tjia, Claudia Urrea, Julia Zimmerman,
Oren Zuckerman.
Amon Millner, My Nguyen, Lisa O&apos;Brien, Abisola Okuk,
Tina Quach, Ricarose Roque, Andrea Saxman, Jay Silver,
Andrew Sliwinski, Tammy Stern, Lis Sylvan, Hanako Tjia,
Claudia Urrea, Julia Zimmerman, Oren Zuckerman.
</p>
<p>
<FormattedMessage id="credits.partnersBody" />

View file

@ -1,242 +1,232 @@
[
{
"userName": "labdalla",
"userId": 35687410,
"name": "Lena"
},
{
"userName": "shaanmasala",
"userId": 29995562,
"name": "Yusuf"
},
{
"userName": "ceebee",
"userId": 2755634,
"name": "Christan"
},
{
"userName": "Zinnea",
"userId": 35911243,
"name": "Zo\u00eb"
},
{
"userName": "binnieb",
"userId": 53715539,
"name": "Robyn"
},
{
"userName": "designerd",
"userId": 3581881,
"name": "Carl"
},
{
"userName": "leoburd",
"userId": 385,
"name": "Leo"
},
{
"userName": "FredDog",
"userId": 2496866,
"name": "Jolie"
},
{
"userName": "kittyloaf",
"userId": 27383273,
"name": "Karishma"
},
{
"userName": "Za-Chary",
"userId": 974363,
"name": "Zachary"
},
{
"userName": "shruti",
"userId": 3714374,
"name": "Shruti"
},
{
"userName": "pixelmoth",
"userId": 2408962,
"name": "Jacy"
},
{
"userName": "Champ99",
"userId": 900283,
"name": "Champika"
},
{
"userName": "dietbacon",
"userId": 24137617,
"name": "Mark"
},
{
"userName": "rmiel",
"userId": 34557192,
"name": "Elizabeth"
},
{
"userName": "Mos20",
"userId": 52545208,
"name": "Joan"
},
{
"userName": "lilyland",
"userId": 17184580,
"name": "Lily"
},
{
"userName": "bluecrazie",
"userId": 50257624,
"name": "JT"
},
{
"userName": "chrisg",
"userId": 1494,
"name": "Chris"
},
{
"userName": "Paddle2See",
"userId": 49156,
"name": "Mark"
},
{
"userName": "codubee",
"userId": 10866958,
"name": "Colby"
},
{
"userName": "khanning",
"userId": 1553886,
"name": "Kreg"
},
{
"userName": "pizzafordessert",
"userId": 22183577,
"name": "Sean"
},
{
"userName": "sgcc_",
"userId": 21986973,
"name": "Paul"
},
{
"userName": "amylaser",
"userId": 17462181,
"name": "Amy"
},
{
"userName": "dsquare",
"userId": 527836,
"name": "DD"
},
{
"userName": "dinopickles",
"userId": 34607790,
"name": "Katelyn"
},
{
"userName": "harakou",
"userId": 373646,
"name": "Dalton"
},
{
"userName": "mwikali",
"userId": 24838781,
"name": "Marian"
},
{
"userName": "",
"userId": "",
"name": "Abisola"
},
{
"userName": "KayOh",
"userId": 3018280,
"name": "Kristin"
},
{
"userName": "scmb1",
"userId": 246290,
"name": "Sarah"
},
{
"userName": "tarmelop",
"userId": 2286560,
"name": "Carmelo"
},
{
"userName": "mres",
"userId": 167,
"name": "Mitchel"
},
{
"userName": "ericr",
"userId": 159,
"name": "Eric"
},
{
"userName": "natalie",
"userId": 169,
"name": "Natalie"
},
{
"userName": "raimondious",
"userId": 2584924,
"name": "Ray"
},
{
"userName": "speakvisually",
"userId": 3484484,
"name": "Eric"
},
{
"userName": "thisandagain",
"userId": 1709047,
"name": "Andrew"
},
{
"userName": "BrycedTea",
"userId": 2029640,
"name": "Bryce"
},
{
"userName": "jaleesa",
"userId": 2374106,
"name": "Jaleesa"
},
{
"userName": "algorithmar",
"userId": 43013126,
"name": "Maren"
},
{
"userName": "cheddargirl",
"userId": 159139,
"name": "Franchette"
},
{
"userName": "wheelsonfire",
"userId": 10001044,
"name": "Ben"
},
{
"userName": "achouse",
"userId": 4747093,
"name": "Annie"
},
{
"userName": "wheelsonfire",
"userId": 10001044,
"name": "Ben"
},
{
"userName": "BrycedTea",
"userId": 2029640,
"name": "Bryce"
},
{
"userName": "designerd",
"userId": 3581881,
"name": "Carl"
},
{
"userName": "tarmelop",
"userId": 2286560,
"name": "Carmelo"
},
{
"userName": "Champ99",
"userId": 900283,
"name": "Champika"
},
{
"userName": "chrisg",
"userId": 1494,
"name": "Chris"
},
{
"userName": "cwillisf",
"userId": 3532363,
"name": "Chris"
},
{
"userName": "ceebee",
"userId": 2755634,
"name": "Christan"
},
{
"userName": "codubee",
"userId": 10866958,
"name": "Colby"
},
{
"userName": "harakou",
"userId": 373646,
"name": "Dalton"
},
{
"userName": "dsquare",
"userId": 527836,
"name": "DD"
},
{
"userName": "rmiel",
"userId": 34557192,
"name": "Elizabeth"
},
{
"userName": "ericr",
"userId": 159,
"name": "Eric"
},
{
"userName": "speakvisually",
"userId": 3484484,
"name": "Eric"
},
{
"userName": "cheddargirl",
"userId": 159139,
"name": "Franchette"
},
{
"userName": "pixelmoth",
"userId": 2408962,
"name": "Jacy"
},
{
"userName": "jaleesa",
"userId": 2374106,
"name": "Jaleesa"
},
{
"userName": "Mos20",
"userId": 52545208,
"name": "Joan"
},
{
"userName": "FredDog",
"userId": 2496866,
"name": "Jolie"
},
{
"userName": "bluecrazie",
"userId": 50257624,
"name": "JT"
},
{
"userName": "MunchtheCat",
"userId": 59383434,
"name": "Kait"
},
{
"userName": "kittyloaf",
"userId": 27383273,
"name": "Karishma"
},
{
"userName": "dinopickles",
"userId": 34607790,
"name": "Katelyn"
},
{
"userName": "pondermake",
"userId": 26779669,
"name": "Kathy"
},
{
"userName": "MunchtheCat",
"userId": 59383434,
"name": "Kait"
"userName": "khanning",
"userId": 1553886,
"name": "Kreg"
},
{
"userName": "KayOh",
"userId": 3018280,
"name": "Kristin"
},
{
"userName": "labdalla",
"userId": 35687410,
"name": "Lena"
},
{
"userName": "leoburd",
"userId": 385,
"name": "Leo"
},
{
"userName": "lilyland",
"userId": 17184580,
"name": "Lily"
},
{
"userName": "algorithmar",
"userId": 43013126,
"name": "Maren"
},
{
"userName": "mwikali",
"userId": 24838781,
"name": "Marian"
},
{
"userName": "dietbacon",
"userId": 24137617,
"name": "Mark"
},
{
"userName": "Paddle2See",
"userId": 49156,
"name": "Mark"
},
{
"userName": "mres",
"userId": 167,
"name": "Mitchel"
},
{
"userName": "natalie",
"userId": 169,
"name": "Natalie"
},
{
"userName": "sgcc_",
"userId": 21986973,
"name": "Paul"
},
{
"userName": "raimondious",
"userId": 2584924,
"name": "Ray"
},
{
"userName": "binnieb",
"userId": 53715539,
"name": "Robyn"
},
{
"userName": "scmb1",
"userId": 246290,
"name": "Sarah"
},
{
"userName": "pizzafordessert",
"userId": 22183577,
"name": "Sean"
},
{
"userName": "shruti",
"userId": 3714374,
"name": "Shruti"
},
{
"userName": "shaanmasala",
"userId": 29995562,
"name": "Yusuf"
},
{
"userName": "Za-Chary",
"userId": 974363,
"name": "Zachary"
},
{
"userName": "Zinnea",
"userId": 35911243,
"name": "Zo\u00eb"
}
]

View file

@ -12,6 +12,25 @@ const InformationPage = require('../../../components/informationpage/information
const TeacherFaq = props => (
<InformationPage title={props.intl.formatMessage({id: 'teacherfaq.title'})}>
<div className="inner info-inner">
<section id="educator-questions">
<span className="nav-spacer" />
<h2><FormattedMessage id="teacherfaq.educatorTitle" /></h2>
<dl>
<dt><FormattedMessage id="teacherfaq.educatorGetStartedTitle" /></dt>
<dd>
<FormattedMessage
id="teacherfaq.educatorGetStartedBody"
values={{
educatorResourcesLink: (
<a href="/educators#resources">
<FormattedMessage id="teacherfaq.educatorResourcesLink" />
</a>
)
}}
/>
</dd>
</dl>
</section>
<section id="teacher-accounts">
<span className="nav-spacer" />
<h2><FormattedMessage id="teacherfaq.title" /></h2>
@ -29,8 +48,6 @@ const TeacherFaq = props => (
/>
<dt><FormattedMessage id="teacherfaq.teacherSignUpTitle" /></dt>
<dd><FormattedHTMLMessage id="teacherfaq.teacherSignUpBody" /></dd>
<dt><FormattedMessage id="teacherfaq.teacherWaitTitle" /></dt>
<dd><FormattedMessage id="teacherfaq.teacherWaitBody" /></dd>
<dt><FormattedMessage id="teacherfaq.classMultipleTeachersTitle" /></dt>
<dd><FormattedMessage id="teacherfaq.classMultipleTeachersBody" /></dd>
<dt><FormattedMessage id="teacherfaq.convertToTeacherTitle" /></dt>
@ -74,6 +91,16 @@ const TeacherFaq = props => (
</dd>
<dt><FormattedMessage id="teacherfaq.teacherEdTitle" /></dt>
<dd><FormattedHTMLMessage id="teacherfaq.teacherEdBody" /></dd>
<dt><FormattedMessage id="teacherfaq.teacherFeaturesTitle" /></dt>
<dd><FormattedHTMLMessage id="teacherfaq.teacherFeaturesBody" /></dd>
<ul>
<li><FormattedMessage id="teacherfaq.teacherFeaturesConvert" /></li>
<li><FormattedMessage id="teacherfaq.teacherMoveStudents" /></li>
<li><FormattedMessage id="teacherfaq.teacherMultipleClasses" /></li>
<li><FormattedMessage id="teacherfaq.teacherLMSs" /></li>
<li><FormattedMessage id="teacherfaq.teacherLimitStudent" /></li>
</ul>
<dd><FormattedHTMLMessage id="teacherfaq.teacherWillNotImplement" /></dd>
</dl>
</section>
<section id="student-accounts">

View file

@ -1,11 +1,13 @@
{
"teacherfaq.title": "Scratch Teacher Account FAQ",
"teacherfaq.educatorTitle": "Scratch Educator FAQ",
"teacherfaq.educatorGetStartedTitle": "Im an educator who is new to Scratch, how can I get started?",
"teacherfaq.educatorGetStartedBody": "Scratch has many resources available to help you get started! Please see our {educatorResourcesLink} for Guides, Tutorials, and many other resources to help you run your class with Scratch!",
"teacherfaq.educatorResourcesLink": "Educator Resources page",
"teacherfaq.teacherWhatTitle": "What are teacher accounts?",
"teacherfaq.teacherWhatBody": "A Scratch Teacher Account provides educators with additional features to manage student participation on Scratch, including the ability to create student accounts, organize student projects into studios, and monitor student comments. Learn more about Teacher Accounts in the video below:",
"teacherfaq.teacherSignUpTitle": "How do I request a teacher account?",
"teacherfaq.teacherSignUpBody": "To request a Teacher Account, please go to the teacher account <a href=\"/educators/register\">request form</a>.",
"teacherfaq.teacherWaitTitle": "Why do I have to wait one day for my account?",
"teacherfaq.teacherWaitBody": "The Scratch Team uses this time to manually review account creation submissions to verify the account creator is an educator.",
"teacherfaq.classMultipleTeachersTitle": "Can a class have multiple teachers?",
"teacherfaq.classMultipleTeachersBody": "A class can only have one teacher account associated with it.",
"teacherfaq.convertToTeacherTitle": "I already have a Scratch account, can you make it a Teacher account?",
@ -19,10 +21,18 @@
"teacherfaq.teacherGoogleBody": "No, Scratch does not connect with any classroom management services.",
"teacherfaq.teacherEdTitle": "Are Scratch Teacher accounts linked to ScratchEd accounts?",
"teacherfaq.teacherEdBody": "No, Scratch Teacher accounts are not linked to <a href=\"http://scratched.gse.harvard.edu/\">ScratchEd</a> accounts.",
"teacherfaq.teacherFeaturesTitle": "Does this feature exist, and if not, can you please add it?",
"teacherfaq.teacherFeaturesBody": "Many features are commonly requested, including:",
"teacherfaq.teacherFeaturesConvert": "Converting existing Scratch Accounts into Student Accounts",
"teacherfaq.teacherMoveStudents": "Moving Student Accounts to other Teacher Accounts and Classes",
"teacherfaq.teacherMultipleClasses": "Having Student Accounts be in multiple Classes, or associated with multiple Teacher Accounts",
"teacherfaq.teacherLMSs": "Connecting with classroom management systems like Google Classroom and Clever",
"teacherfaq.teacherLimitStudent": "Limit what features students have, such as seeing or being able to post comments",
"teacherfaq.teacherWillNotImplement": "It is not currently possible to do any of these things on Scratch. We would love to expand the functionality of Teacher Accounts, and all of these features are things we would like to add. However, Scratch is a small organization and our resources are limited, so it may take us a very long time before we can implement any of these changes.",
"teacherfaq.studentTransferTitle": "Can I transfer a student from one Teacher Account or class to another?",
"teacherfaq.studentTransferBody": "No, it is not possible to transfer students from one class or teacher to another. You can create a new Student Account for the student using a different Teacher Account if they need to be part of a new class.",
"teacherfaq.studentAccountsTitle": "Student Accounts",
"teacherfaq.studentVerifyTitle": "Do I have to verify each of my students' emails?",
"teacherfaq.studentVerifyTitle": "Do I have to verify each of my student emails?",
"teacherfaq.studentVerifyBody": "No. The Teacher Accounts email address is used for all Student Accounts, so there is no need to verify students email addresses.",
"teacherfaq.studentEndTitle": "What happens when I \"end\" my class?",
"teacherfaq.studentEndBody": "When you end a class, your class profile page will be hidden and your students will no longer be able to log in (but their projects and the class studios will still be visible on the site). You may re-open the class at any time. ",

View file

@ -37,7 +37,9 @@
"teacherlanding.signupTips" : "Sign up to receive {signupTipsLink} from the Scratch Team",
"teacherlanding.signupTipsLink" : "updates and tips",
"teacherlanding.accountsTitle": "Teacher Accounts in Scratch",
"teacherlanding.accountsDescription": "As an educator, you can request a Scratch Teacher Account, which makes it easier to create accounts for groups of students and to manage your students projects and comments. To learn more, see the <a href=\"/educators/faq\">Teacher Account FAQ page</a>.",
"teacherlanding.accountsRequestInfo": "As an educator, you can request a Scratch Teacher Account, which makes it easier to create accounts for students and to manage their projects and comments. To learn more, see the {setupGuideLink} and the {teacherAccountFaqLink}.",
"teacherlanding.accountsSetupGuide": "Teacher Account Setup Guide",
"teacherlanding.accountsFaqPage": "Teacher Account FAQ page",
"teacherlanding.requestAccount": "Request Account"
}

View file

@ -1,4 +1,3 @@
const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage;
const FormattedMessage = require('react-intl').FormattedMessage;
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
@ -338,7 +337,21 @@ const Landing = props => (
<FormattedMessage id="teacherlanding.accountsTitle" />
</h2>
<p>
<FormattedHTMLMessage id="teacherlanding.accountsDescription" />
<FormattedMessage
id="teacherlanding.accountsRequestInfo"
values={{
setupGuideLink: (
<a href="https://docs.google.com/document/d/1Qb8Lyeiivr-oB49p5Bo17iXU5qxGpBJHuFa_KR5aW-o/view" >
<FormattedMessage id="teacherlanding.accountsSetupGuide" />
</a>
),
teacherAccountFaqLink: (
<a href="/educators/faq">
<FormattedMessage id="teacherlanding.accountsFaqPage" />
</a>
)
}}
/>
</p>
<SubNavigation
align="left"

View file

@ -1,52 +0,0 @@
/*
* Check that there are no duplicate strings in any individual l10n json file.
*/
var path = require('path');
var fs = require('fs');
var tap = require('tap');
var routes = require('../../src/routes.json');
const noDuplicateValues = (idsToCheck, name) => {
let values = {};
for (const key in idsToCheck) {
if (values.hasOwnProperty(idsToCheck[key])) {
// duplicate values
// return false;
tap.fail(`${name}.${idsToCheck[key]} has duplicates`);
} else {
values[idsToCheck[key]] = key;
}
}
tap.pass();
// return true;
};
tap.test('generalCheckForDuplicates', function (t) {
const ids = require(path.resolve(__dirname, '../../src/l10n.json')); // eslint-disable-line global-require
noDuplicateValues(ids, 'general');
t.end();
});
for (var v in routes) {
if (typeof routes[v].redirect !== 'undefined') {
continue;
}
var subdir = routes[v].view.split('/');
subdir.pop();
var name = routes[v].name;
var uri = path.resolve(__dirname, '../../src/views/' + subdir.join('/') + '/l10n.json');
try {
var file = fs.readFileSync(uri, 'utf8');
var ids = JSON.parse(file);
tap.test(name + 'CheckForDuplicates', function (t) { // eslint-disable-line no-loop-func
noDuplicateValues(ids, name);
t.end();
});
} catch (err) {
if (err.code !== 'ENOENT') {
// ignore if ENOENT for routes with no l10n file, throw error for anything else
throw err;
}
}
}