diff --git a/bin/build-locales b/bin/build-locales index 1984168c7..059c1fc06 100755 --- a/bin/build-locales +++ b/bin/build-locales @@ -42,6 +42,7 @@ var path = require('path'); var languages = require('../languages.json'); var localeCompare = require('./lib/locale-compare'); +var localizedUrls = require('./lib/localized-urls'); // ----------------------------------------------------------------------------- // Main script @@ -92,6 +93,28 @@ files.forEach(function (file) { localeCompare.getIdsForView(view, file, viewLocales, idsWithICU, icuWithIds); }); +// get asset url translations +var localizedAssetUrls = {}; +files = glob.sync(path.resolve(__dirname, '../src/views/**/l10n-static.json')); +files.forEach(function (file) { + var dirPath = file.split('/'); + dirPath.pop(); + var view = dirPath.pop(); + localizedAssetUrls[view] = {}; + + var assetUrls = JSON.parse(fs.readFileSync(file, 'utf8')); + for (var lang in localizedUrls) { + localizedAssetUrls[view][lang] = {}; + for (var key in assetUrls) { + if (localizedUrls[lang].hasOwnProperty(key)) { + localizedAssetUrls[view][lang][key] = localizedUrls[lang][key]; + } else { + localizedAssetUrls[view][lang][key] = assetUrls[key]; + } + } + } +}); + // md5 of english strings with message key as the value for searching po files. // Sample structure: { 'sdfas43534sdfasdf': 'general-general.blah', 'lkjfasdf4t342asdfa': 'about-about.blah' } var md5WithIds = localeCompare.getMD5Map(icuWithIds); @@ -110,5 +133,8 @@ for (i in views) { if (views[i] in viewLocales) { viewTranslations = merge(viewLocales[views[i]], viewTranslations); } + if (views[i] in localizedAssetUrls) { + viewTranslations = merge(viewTranslations, localizedAssetUrls[[views[i]]]); + } localeCompare.writeTranslationsToJS(outputDir, views[i], viewTranslations); } diff --git a/bin/lib/localized-urls.json b/bin/lib/localized-urls.json new file mode 100644 index 000000000..5b85d12e0 --- /dev/null +++ b/bin/lib/localized-urls.json @@ -0,0 +1,52 @@ +{ + "en": { + "cards.starterLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/Scratch2Cards.pdf", + "cards.nameLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/AnimateYourNameCards.pdf", + "cards.pongLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/PongCards.pdf", + "cards.storyLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/StoryCards.pdf", + "cards.danceLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/DanceCards.pdf", + "cards.hideLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/Hide-and-Seek-Cards.pdf" + }, + "ar": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/ar/Scratch2Cards.pdf" + }, + "ca": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/ca/Scratch2Cards.pdf" + }, + "cs": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/cs/Scratch2Cards.pdf" + }, + "de": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/de/Scratch2Cards.pdf" + }, + "es": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/es/Scratch2Cards.pdf" + }, + "fr": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/fr/Scratch2Cards.pdf" + }, + "hr": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/hr/Scratch2Cards.pdf" + }, + "it": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/it/Scratch2Cards.pdf" + }, + "ja": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/ja/Scratch2Cards.pdf" + }, + "ja-hr": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/ja-hr/Scratch2Cards.pdf" + }, + "ko": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/ko/Scratch2Cards.pdf" + }, + "nl": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/nl/Scratch2Cards.pdf" + }, + "pt-br": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/pt-br/Scratch2Cards.pdf" + }, + "sl": { + "cards.starterLink": "//cdn.scratch.mit.edu/scratchr2/static/pdfs/help/sl/Scratch2Cards.pdf" + } +} \ No newline at end of file diff --git a/server/routes.json b/server/routes.json index d32b25ff3..78ac23d5b 100644 --- a/server/routes.json +++ b/server/routes.json @@ -24,6 +24,11 @@ "view": "credits", "title": "Credits" }, + { + "pattern": "/info/cards", + "view": "cards", + "title": "Cards" + }, { "pattern": "/jobs", "view": "jobs", diff --git a/src/views/cards/cards.jsx b/src/views/cards/cards.jsx new file mode 100644 index 000000000..5a6526065 --- /dev/null +++ b/src/views/cards/cards.jsx @@ -0,0 +1,150 @@ +var React = require('react'); +var injectIntl = require('react-intl').injectIntl; +var FormattedMessage = require('react-intl').FormattedMessage; +var render = require('../../lib/render.jsx'); + +var Box = require('../../components/box/box.jsx'); +var Page = require('../../components/page/page.jsx'); + +require('./cards.scss'); + +var Cards = injectIntl(React.createClass({ + type: 'Cards', + render: function () { + var locale = window._locale || 'en'; + var formatMessage = this.props.intl.formatMessage; + var englishLinks = { + 'cards.starterLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/Scratch2Cards.pdf', + 'cards.nameLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/AnimateYourNameCards.pdf', + 'cards.pongLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/PongCards.pdf', + 'cards.storyLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/StoryCards.pdf', + 'cards.danceLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/DanceCards.pdf', + 'cards.hideLink': '//scratch.mit.edu/scratchr2/static/pdfs/help/Hide-and-Seek-Cards.pdf' + }; + var formattedLinks = { + 'cards.starterLink': formatMessage({id: 'cards.starterLink'}), + 'cards.nameLink': formatMessage({id: 'cards.nameLink'}), + 'cards.pongLink': formatMessage({id: 'cards.pongLink'}), + 'cards.storyLink': formatMessage({id: 'cards.storyLink'}), + 'cards.danceLink': formatMessage({id: 'cards.danceLink'}), + 'cards.hideLink': formatMessage({id: 'cards.hideLink'}) + }; + return ( +
+
+
+

+

+
+ Card Use Explanation +
+
+ +
+
+

+ + + + + + + {( + formattedLinks['cards.starterLink'] === englishLinks['cards.starterLink'] && + locale !== 'en' + ) ? [ + + ] : []} + +
+
+

+ + + + + + + {( + formattedLinks['cards.nameLink'] === englishLinks['cards.nameLink'] && + locale !== 'en' + ) ? [ + () + ] : []} + +
+
+

+ + + + + + + {( + formattedLinks['cards.pongLink'] === englishLinks['cards.pongLink'] && + locale !== 'en' + ) ? [ + () + ] : []} + +
+
+
+
+

+ + + + + + + {( + formattedLinks['cards.storyLink'] === englishLinks['cards.storyLink'] && + locale !== 'en' + ) ? [ + () + ] : []} + +
+
+

+ + + + + + + {( + formattedLinks['cards.danceLink'] === englishLinks['cards.danceLink'] && + locale !== 'en' + ) ? [ + () + ] : []} + +
+
+

+ + + + + + + {( + formattedLinks['cards.hideLink'] === englishLinks['cards.hideLink'] && + locale !== 'en' + ) ? [ + () + ] : []} + +
+
+
+
+
+ ); + } +})); + +render(, document.getElementById('app')); diff --git a/src/views/cards/cards.scss b/src/views/cards/cards.scss new file mode 100644 index 000000000..2f1cfeb0d --- /dev/null +++ b/src/views/cards/cards.scss @@ -0,0 +1,43 @@ +@import "../../colors"; +@import "../../typography"; + +.cards { + display: flex; + margin: 1em 0; + align-items: center; + justify-content: center; + + .intro-content { + float: left; + width: 45%; + } + + img { + width: 45%; + } +} + +.cards-container { + text-align: center; + + .card-row { + display: flex; + justify-content: space-around; + align-items: center; + flex-wrap: wrap; + + div { + display: inline-block; + padding: .5em; + + a { + display: block; + + .pdf-icon { + margin-right: .2em; + width: 1em; + } + } + } + } +} diff --git a/src/views/cards/l10n-static.json b/src/views/cards/l10n-static.json new file mode 100644 index 000000000..fe4c92a2c --- /dev/null +++ b/src/views/cards/l10n-static.json @@ -0,0 +1,8 @@ +{ + "cards.starterLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/Scratch2Cards.pdf", + "cards.nameLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/AnimateYourNameCards.pdf", + "cards.pongLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/PongCards.pdf", + "cards.storyLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/StoryCards.pdf", + "cards.danceLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/DanceCards.pdf", + "cards.hideLink": "//scratch.mit.edu/scratchr2/static/pdfs/help/Hide-and-Seek-Cards.pdf" +} diff --git a/src/views/cards/l10n.json b/src/views/cards/l10n.json new file mode 100644 index 000000000..b806810a0 --- /dev/null +++ b/src/views/cards/l10n.json @@ -0,0 +1,13 @@ +{ + "cards.introHeader": "Scratch Cards", + "cards.introContent": "Scratch cards provide a quick way to learn new Scratch code.", + "cards.english": "English", + "cards.introWikiSupport": "Looking for Scratch Cards in your language? Check Scratch Wiki.", + "cards.viewCard": "View Cards", + "cards.starter": "Starter Cards", + "cards.name": "Animate Your Name", + "cards.pong": "Create a Pong Game", + "cards.story": "Animate a Story", + "cards.dance": "Dance, Dance, Dance", + "cards.hide": "Hide and Seek" +} diff --git a/static/images/cards/card-use-overview.png b/static/images/cards/card-use-overview.png new file mode 100644 index 000000000..131b605a4 Binary files /dev/null and b/static/images/cards/card-use-overview.png differ diff --git a/static/images/cards/cards-dance.png b/static/images/cards/cards-dance.png new file mode 100644 index 000000000..2a3468299 Binary files /dev/null and b/static/images/cards/cards-dance.png differ diff --git a/static/images/cards/cards-hide.png b/static/images/cards/cards-hide.png new file mode 100644 index 000000000..7f016fc59 Binary files /dev/null and b/static/images/cards/cards-hide.png differ diff --git a/static/images/cards/cards-name.png b/static/images/cards/cards-name.png new file mode 100644 index 000000000..e4303e4c9 Binary files /dev/null and b/static/images/cards/cards-name.png differ diff --git a/static/images/cards/cards-pong.png b/static/images/cards/cards-pong.png new file mode 100644 index 000000000..f73ff2c81 Binary files /dev/null and b/static/images/cards/cards-pong.png differ diff --git a/static/images/cards/cards-starter.png b/static/images/cards/cards-starter.png new file mode 100644 index 000000000..bad3168c0 Binary files /dev/null and b/static/images/cards/cards-starter.png differ diff --git a/static/images/cards/cards-story.png b/static/images/cards/cards-story.png new file mode 100644 index 000000000..09993b423 Binary files /dev/null and b/static/images/cards/cards-story.png differ diff --git a/static/svgs/pdf-icon-ui-blue.svg b/static/svgs/pdf-icon-ui-blue.svg new file mode 100644 index 000000000..c8030248e --- /dev/null +++ b/static/svgs/pdf-icon-ui-blue.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/test/localization/spot_check_cards_has_strings.js b/test/localization/spot_check_cards_has_strings.js new file mode 100644 index 000000000..2925af3df --- /dev/null +++ b/test/localization/spot_check_cards_has_strings.js @@ -0,0 +1,36 @@ +/* + * spot check that each language has values for the string id keys on Cards page + * that are contained in English (i.e. make sure strings will show up, not ids") + */ +var merge = require('lodash.merge'); +var path = require('path'); +var tap = require('tap'); + +var languages = require('../../languages.json'); +var localeCompare = require('../../bin/lib/locale-compare'); + +tap.test('spotCheckAboutStrings', function (t) { + var isoCodes = Object.keys(languages); + isoCodes.splice(isoCodes.indexOf('en'), 1); + var viewLocales = {}; + var idsWithICU = {}; + var icuWithIds = {}; + localeCompare.getIdsForView( + 'cards', + path.resolve(__dirname, '../../src/views/cards/l10n.json'), + viewLocales, + idsWithICU, + icuWithIds + ); + var md5WithIds = localeCompare.getMD5Map(icuWithIds); + var keysToCheck = Object.keys(merge(viewLocales['cards']['en'])).sort(); + for (var i in isoCodes) { + var translations = localeCompare.getTranslationsForLanguage(isoCodes[i], idsWithICU, md5WithIds); + t.same( + Object.keys(translations['cards'][isoCodes[i]]).sort(), + keysToCheck, + 'check Cards keys for language ' + isoCodes[i] + ); + } + t.end(); +});