Unverified Commit ff2e90e1 authored by Benjamin Wheeler's avatar Benjamin Wheeler Committed by GitHub

Merge pull request #3643 from benjiwheeler/translations-automate-push

Introduce new tx-push-www script to automate string push to transifex
parents 7bfaa27e 80b87bc8
......@@ -139,3 +139,9 @@ stages:
- test
- name: smoke
if: type != pull_request
- provider: script
on:
branch: develop
condition: $TRAVIS_EVENT_TYPE == cron
skip_cleanup: true
script: npm run i18n:push
[main]
host = https://www.transifex.com
lang_map = zh_CN:zh-cn, zh_TW:zh-tw, pt_BR:pt-br, es_419:es-419, aa_DJ:aa-dj
[scratch-website.explore-l10njson]
file_filter = localizations/explore/<lang>.json
source_file = src/views/explore/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.general-l10njson]
file_filter = localizations/general/<lang>.json
source_file = src/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.wedo2-l10njson]
file_filter = localizations/wedo2/<lang>.json
source_file = src/views/wedo2/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.teacherregistration-l10njson]
file_filter = localizations/teacherregistration/<lang>.json
source_file = src/views/teacherregistration/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.dmca-l10njson]
file_filter = localizations/dmca/<lang>.json
source_file = src/views/dmca/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.jobs-l10njson]
file_filter = localizations/jobs/<lang>.json
source_file = src/views/jobs/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.faq-l10njson]
file_filter = localizations/faq/<lang>.json
source_file = src/views/faq/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.about-l10njson]
file_filter = localizations/about/<lang>.json
source_file = src/views/about/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.teacher-faq-l10njson]
file_filter = localizations/teacher-faq/<lang>.json
source_file = src/views/teachers/faq/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.developers-l10njson]
file_filter = localizations/developers/<lang>.json
source_file = src/views/developers/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.guidelines-l10njson]
file_filter = localizations/guidelines/<lang>.json
source_file = src/views/guidelines/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.educator-landing-l10njson]
file_filter = localizations/educator-landing/<lang>.json
source_file = src/views/teachers/landing/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.splash-l10njson]
file_filter = localizations/splash/<lang>.json
source_file = src/views/splash/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.conference-index-2019-l10njson]
file_filter = localizations/conference-index-2019/<lang>.json
source_file = src/views/conference/2019/index/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.conference-index-2017-l10njson]
file_filter = localizations/conference-index-2017/<lang>.json
source_file = src/views/conference/2017/index/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.credits-l10njson]
file_filter = localizations/credits/<lang>.json
source_file = src/views/credits/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.download-l10njson]
file_filter = localizations/download/<lang>.json
source_file = src/views/download/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.download-scratch2-l10njson]
file_filter = localizations/download/scratch2/<lang>.json
source_file = src/views/download/scratch2/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.camp-l10njson]
file_filter = localizations/camp/<lang>.json
source_file = src/views/camp/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.messages-l10njson]
file_filter = localizations/messages/<lang>.json
source_file = src/views/messages/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.research-l10njson]
file_filter = localizations/research/<lang>.json
source_file = src/views/research/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.preview-l10njson]
file_filter = localizations/preview/<lang>.json
source_file = src/views/preview/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.ev3-l10njson]
source_file = src/views/ev3/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.microbit-l10njson]
source_file = src/views/microbit/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.boost-l10njson]
source_file = src/views/boost/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.gdxfor-l10njson]
source_file = src/views/gdxfor/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.search-l10njson]
file_filter = localizations/search/<lang>.json
source_file = src/views/search/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.wedo2-legacy-l10njson]
source_file = src/views/wedo2-legacy/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.parents-l10njson]
source_file = src/views/parents/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.scratch_14-l10njson]
source_file = src/views/scratch_1.4/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.ideas-l10njson]
source_file = src/views/ideas/l10n.json
source_lang = en
type = KEYVALUEJSON
[scratch-website.starter-projects-l10njson]
source_file = src/views/starter-projects/l10n.json
source_lang = en
type = KEYVALUEJSON
......@@ -35,10 +35,9 @@ if (args[0] === 'execute') {
process.stdout.write('executing tx initializtion\n');
execute = '--execute';
} else {
process.stdout.write('Dry run: pass "execute" as a parameter to add --execute switch to commands\n');
process.stdout.write('Dry run: pass "--execute" as a parameter to execute push files to transifex\n');
}
// set up l10n resources for the scratch-website project as
// [scratch-website.<view>_l10njson]
// use 'general' for the root l10n.json
......
#!/usr/bin/env node
/*
Push www strings to Transifex, using scratch-l10n's tx-push-src.js script
1. for every file like src/views/.../l10n.json, call tx-push-src.js
2. also call tx-push-src.js on the general file, src/l10n.json
The format of tx-push-src.js's arguments is:
$ tx-push-src.js tx-project tx-resource english-json-file
So, for example, src/views/parents/l10n.json will use:
$ tx-push-src.js scratch-website parents-l10njson src/views/parents/l10n.json
*/
const glob = require('glob');
const execSync = require('child_process').execSync;
// determine if this is a dry run, or if we're really pushing to transifex
let execute = false;
const args = process.argv.slice(2);
if (args[0] === '--execute') {
process.stdout.write('pushing to transifex...\n');
execute = true;
} else {
process.stdout.write('Dry run: pass "execute" as a parameter to add --execute switch to commands\n');
}
// exceptions to the usual relationship between file path and corresponding
// transifex resource name
const overrides = {
'src/views/teachers/faq/l10n.json': 'teacher-faq-l10njson',
'src/views/teachers/landing/l10n.json': 'educator-landing-l10njson',
'src/views/conference/2020/index/l10n.json': 'conference-index-2020-l10njson',
'src/views/conference/2019/index/l10n.json': 'conference-index-2019-l10njson',
'src/views/conference/2017/index/l10n.json': 'conference-index-2017-l10njson'
};
// convert an l10n file path to the usual format of the corresponding
// transifex resource name. E.g., for file path src/views/parents/l10n.json ,
// return parents-l10njson.
const txResourceNameFromPath = l10nFilePath => {
const pathRegexp = /(src\/views\/)?(.*)/g;
const match = pathRegexp.exec(l10nFilePath);
let resourceName = match[2];
resourceName = resourceName.replace(/\//g, '-');
resourceName = resourceName.replace(/\./g, '');
return resourceName;
};
// start with the general l10n file, which is an exception to the format
let resources = [{
filename: 'src/l10n.json',
resourceName: 'general-l10njson'
}];
glob('src/views/**/l10n.json', {}, function (er, files) {
files.forEach(filename => {
// figure out likely resource name from file path
let resourceName = txResourceNameFromPath(filename);
if (filename in overrides) { // see if it needs overriding
resourceName = overrides[filename];
}
resources.push({
filename: filename,
resourceName: resourceName
});
});
let cmd;
resources.forEach(resource => {
cmd = `$(npm bin)/tx-push-src scratch-website ${resource.resourceName} ${resource.filename}`;
if (execute) {
// push all the source files to transifex - force update
process.stdout.write(`running command: ${cmd}\n`);
execSync(cmd, {stdio: 'inherit'});
} else {
process.stdout.write(`command we would run: ${cmd}\n`);
}
});
});
......@@ -26,6 +26,7 @@
"deploy:s3:all": "npm run deploy:s3cmd -- --exclude '.DS_Store' --exclude '*.svg' --exclude '*.js' ./build/ s3://$S3_BUCKET_NAME/",
"deploy:s3:svg": "npm run deploy:s3cmd -- --exclude '*' --include '*.svg' --mime-type 'image/svg+xml' ./build/ s3://$S3_BUCKET_NAME/",
"deploy:s3:js": "npm run deploy:s3cmd -- --exclude '*' --include '*.js' --mime-type 'application/javascript' ./build/ s3://$S3_BUCKET_NAME/",
"i18n:push": "tx-push-www --execute",
"translate:urls": "node ./bin/get-localized-urls localized-urls.json",
"translate:files": "node ./bin/build-locales node_modules/scratch-l10n/www intl",
"translate": "npm run translate:urls && npm run translate:files"
......
{
"preview-faq.title": "Scratch 3.0 FAQ"
}
const cheerio = require('cheerio');
const injectIntl = require('react-intl').injectIntl;
const intlShape = require('react-intl').intlShape;
const React = require('react');
const xhr = require('xhr');
const InformationPage = require('../../components/informationpage/informationpage.jsx');
const Page = require('../../components/page/www/page.jsx');
const render = require('../../lib/render.jsx');
require('./preview-faq.scss');
class PreviewFaq extends React.Component {
constructor (props) {
super(props);
this.state = {
faqDoc: {__html: ''}
};
}
componentDidMount () {
xhr({
method: 'GET',
uri: 'https://docs.google.com/document/d/e/2PACX-1vQZFrpOagYqEwcrBBCplIomiyguPAodIJVnCq9Sr11WDI_aa2b-JtDWak-Aiu-cwWobTXftRMF6wBbd/pub?embedded=true'
}, (error, response, body) => {
const $ = cheerio.load(body);
this.setState({faqDoc: {__html: $('html').html()}});
});
}
render () {
return (
<InformationPage title={this.props.intl.formatMessage({id: 'preview-faq.title'})}>
<div className="inner">
<div
className="preview-faq"
dangerouslySetInnerHTML={this.state.faqDoc} // eslint-disable-line react/no-danger
/>
</div>
</InformationPage>
);
}
}
PreviewFaq.propTypes = {
intl: intlShape
};
const WrappedPreviewFAQ = injectIntl(PreviewFaq);
render(<Page><WrappedPreviewFAQ /></Page>, document.getElementById('app'));
#view {
padding: 0;
}
.preview-faq {
margin-bottom: 5rem;
}
.title-banner-h1 {
line-height: 1.7em !important;
font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif !important;
font-size: 2.5rem !important;
font-weight: 900 !important;
}
.preview-faq li {
margin: 0 2rem !important;
}
{
"cards.Scratch2CardsLink": "https://resources.scratch.mit.edu/www/cards/en/Scratch2Cards.pdf",
"cards.ScratchCardsAllLink": "https://resources.scratch.mit.edu/www/cards/en/ScratchCardsAll.pdf",
"cards.catchCardsLink": "https://resources.scratch.mit.edu/www/cards/en/catchCards.pdf",
"cards.danceCardsLink": "https://resources.scratch.mit.edu/www/cards/en/danceCards.pdf",
"cards.dressupCardsLink": "https://resources.scratch.mit.edu/www/cards/en/dressupCards.pdf",
"cards.fashionCardsLink": "https://resources.scratch.mit.edu/www/cards/en/fashionCards.pdf",
"cards.flyCardsLink": "https://resources.scratch.mit.edu/www/cards/en/flyCards.pdf",
"cards.hide-seekCardsLink": "https://resources.scratch.mit.edu/www/cards/en/hide-seekCards.pdf",
"cards.musicCardsLink": "https://resources.scratch.mit.edu/www/cards/en/musicCards.pdf",
"cards.nameCardsLink": "https://resources.scratch.mit.edu/www/cards/en/nameCards.pdf",
"cards.petCardsLink": "https://resources.scratch.mit.edu/www/cards/en/petCards.pdf",
"cards.pongCardsLink": "https://resources.scratch.mit.edu/www/cards/en/pongCards.pdf",
"cards.raceCardsLink": "https://resources.scratch.mit.edu/www/cards/en/raceCards.pdf",
"cards.storyCardsLink": "https://resources.scratch.mit.edu/www/cards/en/storyCards.pdf",
"guides.CatchGuideLink": "https://resources.scratch.mit.edu/www/guides/en/CatchGuide.pdf",
"guides.DanceGuideLink": "https://resources.scratch.mit.edu/www/guides/en/DanceGuide.pdf",
"guides.FashionGuideLink": "https://resources.scratch.mit.edu/www/guides/en/FashionGuide.pdf",
"guides.FlyGuideLink": "https://resources.scratch.mit.edu/www/guides/en/FlyGuide.pdf",
"guides.Getting-Started-Guide-Scratch2Link": "https://resources.scratch.mit.edu/www/guides/en/Getting-Started-Guide-Scratch2.pdf",
"guides.HideandSeekGuideLink": "https://resources.scratch.mit.edu/www/guides/en/HideandSeekGuide.pdf",
"guides.MusicGuideLink": "https://resources.scratch.mit.edu/www/guides/en/MusicGuide.pdf",
"guides.NameGuideLink": "https://resources.scratch.mit.edu/www/guides/en/NameGuide.pdf",
"guides.PetGuideLink": "https://resources.scratch.mit.edu/www/guides/en/PetGuide.pdf",
"guides.PongGuideLink": "https://resources.scratch.mit.edu/www/guides/en/PongGuide.pdf",
"guides.RaceGuideLink": "https://resources.scratch.mit.edu/www/guides/en/RaceGuide.pdf",
"guides.StoryGuideLink": "https://resources.scratch.mit.edu/www/guides/en/StoryGuide.pdf"
}
{
"tips.title": "Getting Started",
"tips.subTitle": "Start making projects in Scratch by trying the <a href=\"/projects/editor/?tip_bar=getStarted\" class=\"mod-underline\">online tutorial</a> or downloading the <a href=\"{GettingStartedPDF}\" class=\"mod-underline\">PDF Guide</a>.",
"tips.tryGettingStarted": "Try the Getting Started tutorial",
"tips.tttHeader": "Things to Try",
"tips.tttBody": "What do you want to make with Scratch? For each activity, you can try the <strong>Tutorial</strong>, download a set of <strong>Activity Cards</strong>, or view the <strong>Educator Guide</strong>.",
"tips.cardsHeader": "Get the Entire Collection of Activity Cards",
"tips.cardsBody": "With the Scratch Activity Cards, you can learn to create interactive games, stories, music, animations, and more!",
"tips.cardsPurchase": "Purchase Printed Set",
"tips.starterProjectsHeader": "Starter Projects",
"tips.starterProjectsBody": "You can play with Starter Projects to get ideas for making your own projects.",
"tips.starterProjectsPlay": "Play with Starter Projects",
"tips.offlineEditorHeader": "Offline Editor",
"tips.offlineEditorBody": "To create projects without an Internet connection, you can <a href=\"/download\">download the offline editor</a>.",
"tips.questionsHeader": "Questions",
"tips.questionsBody": "Have more questions? See the <a href=\"/info/faq\">Frequently Asked Questions</a> or visit the <a href=\"/discuss/7/\">Help with Scripts Forum</a>.",
"ttt.tutorial": "Tutorial",
"tile.guides": "See Cards and Guides",
"tile.tryIt": "Try It",
"ttt.placeholder": "Placeholder text",
"ttt.tutorialSubtitle": "Find out how to make this project using a step-by-step tutorial in Scratch.",
"ttt.activityTitle": "Activity Cards",
"ttt.activitySubtitle": "Explore new coding ideas using this set of illustrated cards you can print out.",
"ttt.educatorTitle": "Educator Guide",
"ttt.educatorSubtitle": "Use this educator guide to plan and lead a one-hour Scratch workshop.",
"ttt.open": "Open",
"ttt.MakeItFlyTitle": "Make It Fly",
"ttt.MakeItFlyDescription": "Animate the Scratch Cat, The Powerpuff Girls, or even a taco!",
"ttt.AnimateYourNameTitle": "Animate a Name",
"ttt.AnimateYourNameDescription": "Animate the letters of your username, initials, or favorite word.",
"ttt.RaceTitle": "Race to the Finish",
"ttt.RaceDescription": "Make a game where two characters race each other.",
"ttt.MakeMusicTitle": "Make Music",
"ttt.MakeMusicDescription": "Choose instruments, add sounds, and press keys to play music.",
"ttt.HideAndSeekTitle": "Hide and Seek",
"ttt.HideAndSeekDescription": "Make a hide-and-seek game with characters that appear and disappear.",
"ttt.StoryTitle": "Create a Story",
"ttt.StoryDescription": "Choose characters, add conversation, and bring your story to life.",
"ttt.FashionTitle": "Fashion Game",
"ttt.FashionDescription": "Make a game where you dress a character with different clothes and styles.",
"ttt.PongTitle": "Pong Game",
"ttt.PongDescription": "Make a bouncing ball game with sounds, points, and other effects.",
"ttt.DanceTitle": "Let's Dance",
"ttt.DanceDescription": "Design an animated dance scene with music and dance moves.",
"ttt.CatchTitle": "Catch Game",
"ttt.CatchDescription": "Make a game where you catch things falling from the sky.",
"ttt.VirtualPetTitle": "Virtual Pet",
"ttt.VirtualPetDescription": "Create an interactive pet that can eat, drink, and play."
}
This diff is collapsed.
@import "../../colors";
@import "../../frameless";
$base-bg: $ui-white;
#view {
background-color: $ui-gray;
padding: 0;
}
.tips-resources {
background-color: $ui-white;
overflow: hidden;
}
.ttt-section {
display: flex;
margin: 0 auto;
text-align: center;
justify-content: center;
flex-wrap: wrap;
align-items: center;
}
.tips-divider {
border-top: 1px solid $ui-gray;
width: 100%;
}
.tips-banner-image {
max-width: calc(100% - 2rem);
}
.tips-button {
margin-right: .75rem;
background-color: $ui-blue;
color: $ui-white;
font-size: 1rem;
&.getting-started-button {
margin-right: 0;
background-color: $ui-white;
color: $link-blue;
}
img {
margin-right: 1rem;
height: 1.25rem;
vertical-align: middle;
}
a {
color: $ui-white;
}
}
.purchase-button {
img {
margin-right: 0;
margin-left: .75rem;
width: 1rem;
vertical-align: baseline;
}
}
.tips-info-section {
padding: 2.5rem 0;
width: 100%;
justify-content: space-between;
}
.tips-info-body {
text-align: left;
}
.tips-cards-buttons {
a {
white-space: normal;
}
}
img.tips-icon {
height: 1.75rem;
}
//4 columns
@media #{$small} {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols4;
}
}
}
.ttt-head {
p {
max-width: $cols4;
}
}
//put the image first if in 4-column
.tips-info-body {
max-width: $cols4;
text-align: center;
&.tips-illustration {
order: -1;
img {
width: $cols4;
}
}
.button {
width: 100%;
}
}
}
//6 columns
@media #{$medium} {
.title-banner {
&.masthead {
p {
max-width: $cols6;
}
}
}
.ttt-head {
p {
max-width: $cols6;
}
}
.tips-info-body.tips-illustration {
order: -1;
img {
width: $cols4;
}
}
.tips-info-body {
max-width: $cols4;
text-align: center;
}
}
//8 columns
@media #{$intermediate} {
.title-banner {
&.masthead {
padding-bottom: 2rem;
p {
max-width: $cols6;
}
}
}
.ttt-head {
p {
max-width: $cols6;
}
}
.tips-info-section {
&.mod-align-top {
align-items: flex-start;
}
}
.tips-info-body {
max-width: $cols4;
}
.tips-button {
width: 100%;
}
img.mod-flow-left {
transform: translate(-1*$cols2);
}
}
// 12 columns
@media #{$big} {
.title-banner {
&.masthead {
padding-bottom: 1.25rem;
p {
max-width: $cols8;
}
}
}
.ttt-head {
p {
max-width: $cols8;
}
}
.tips-info-section {
&.mod-align-top {
align-items: flex-start;
}
}
.tips-info-body {
max-width: $cols6;
&.mod-narrow {
max-width: $cols5;
}
}
}
[
{
"title": "ttt.AnimateYourNameTitle",
"description": "ttt.AnimateYourNameDescription",
"thumbUrl": "/images/ttt/animate-your-name.jpg",
"bannerUrl": "/images/ttt/animate-your-name-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=name",
"activityLoc": "cards.nameCardsLink",
"guideLoc": "guides.NameGuideLink"
},
{
"title": "ttt.MakeItFlyTitle",
"description": "ttt.MakeItFlyDescription",
"thumbUrl": "/images/ttt/make-it-fly.jpg",
"bannerUrl": "/images/ttt/make-it-fly-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=fly",
"activityLoc": "cards.flyCardsLink",
"guideLoc": "guides.FlyGuideLink"
},
{
"title": "ttt.MakeMusicTitle",
"description": "ttt.MakeMusicDescription",
"thumbUrl": "/images/ttt/make-music.jpg",
"bannerUrl": "/images/ttt/make-music-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=music",
"activityLoc": "cards.musicCardsLink",
"guideLoc": "guides.MusicGuideLink"
},
{
"title": "ttt.RaceTitle",
"description": "ttt.RaceDescription",
"thumbUrl": "/images/ttt/race-to-the-finish.jpg",
"bannerUrl": "/images/ttt/race-to-the-finish-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=racegame",
"activityLoc": "cards.raceCardsLink",
"guideLoc": "guides.RaceGuideLink"
},
{
"title": "ttt.HideAndSeekTitle",
"description": "ttt.HideAndSeekDescription",
"thumbUrl": "/images/ttt/hide-and-seek.jpg",
"bannerUrl": "/images/ttt/hide-and-seek-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=hide",
"activityLoc": "cards.hide-seekCardsLink",
"guideLoc": "guides.HideandSeekGuideLink"
},
{
"title": "ttt.FashionTitle",
"description": "ttt.FashionDescription",
"thumbUrl": "/images/ttt/fashion-game.jpg",
"bannerUrl": "/images/ttt/fashion-game-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=fashion",
"activityLoc": "cards.fashionCardsLink",
"guideLoc": "guides.FashionGuideLink"
},
{
"title": "ttt.StoryTitle",
"description": "ttt.StoryDescription",
"thumbUrl": "/images/ttt/create-a-story.jpg",
"bannerUrl": "/images/ttt/create-a-story-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=story",
"activityLoc": "cards.storyCardsLink",
"guideLoc": "guides.StoryGuideLink"
},
{
"title": "ttt.PongTitle",
"description": "ttt.PongDescription",
"thumbUrl": "/images/ttt/pong-game.jpg",
"bannerUrl": "/images/ttt/pong-game-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=pong",
"activityLoc": "cards.pongCardsLink",
"guideLoc": "guides.PongGuideLink"
},
{
"title": "ttt.DanceTitle",
"description": "ttt.DanceDescription",
"thumbUrl": "/images/ttt/lets-dance.jpg",
"bannerUrl": "/images/ttt/lets-dance-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=dance",
"activityLoc": "cards.danceCardsLink",
"guideLoc": "guides.DanceGuideLink"
},
{
"title": "ttt.CatchTitle",
"description": "ttt.CatchDescription",
"thumbUrl": "/images/ttt/catch-game.jpg",
"bannerUrl": "/images/ttt/catch-game-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=catch",
"activityLoc": "cards.catchCardsLink",
"guideLoc": "guides.CatchGuideLink"
},
{
"title": "ttt.VirtualPetTitle",
"description": "ttt.VirtualPetDescription",
"thumbUrl": "/images/ttt/virtual-pet.jpg",
"bannerUrl": "/images/ttt/virtual-pet-banner.jpg",
"tutorialLoc": "/projects/editor/?tip_bar=pet",
"activityLoc": "cards.petCardsLink",
"guideLoc": "guides.PetGuideLink"
}
]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment