Skip to content

Commit

Permalink
Fix GH 1102: Don’t allow duplicate strings in a single l10n file (#1150)
Browse files Browse the repository at this point in the history
* Don’t allow duplicate strings in a single l10n file

Added check_duplicate_strings to test for duplicates in a single file.
removed duplicates - tried to keep the more generic ‘key’

* revised test case for safer file reads
  • Loading branch information
chrisgarrity committed Jan 19, 2017
1 parent 4c6522f commit e1a0e9f
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/components/modal/ttt/modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var TTTModal = React.createClass({
src="/svgs/ttt/tutorial.svg"
alt="tutorial-icon"
/>
<FormattedMessage id="ttt.tutorialTitle" />
<FormattedMessage id="ttt.tutorial" />
</div>
<p className="modal-content-ttt-subtitle">
<FormattedMessage id="ttt.tutorialSubtitle" />
Expand Down
6 changes: 3 additions & 3 deletions src/components/registration/steps.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ module.exports = {
return (
<Slide className="registration-step phone-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.phoneStepTitle" />
<intl.FormattedMessage id="teacherRegistration.phoneNumber" />
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.phoneStepDescription" />
Expand Down Expand Up @@ -535,7 +535,7 @@ module.exports = {
return (
<Slide className="registration-step organization-step">
<h2>
<intl.FormattedMessage id="teacherRegistration.orgStepTitle" />
<intl.FormattedMessage id="teacherRegistration.organization" />
</h2>
<p className="description">
<intl.FormattedMessage id="teacherRegistration.orgStepDescription" />
Expand Down Expand Up @@ -790,7 +790,7 @@ module.exports = {
render: function () {
var formatMessage = this.props.intl.formatMessage;
var textAreaClass = (this.state.characterCount > this.props.maxCharacters) ? 'fail' : '';

return (
<Slide className="registration-step usescratch-step">
<h2>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ttt-tile/ttt-tile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var TTTTile = React.createClass({
<div className="ttt-tile-info">

<div className="ttt-tile-tag">
<FormattedMessage id='tile.tutorial' defaultMessage='Tutorial'/>
<FormattedMessage id='ttt.tutorial' defaultMessage='Tutorial'/>
</div>
<h4 className="ttt-tile-title">{this.props.title}</h4>
<p className="ttt-tile-description">
Expand Down
1 change: 0 additions & 1 deletion src/l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@
"registration.usernameStepDescription": "Fill in the following forms to request an account. The approval process may take up to 24 hours.",
"registration.studentUsernameStepDescription": "You can make games, animations, and stories using Scratch. Setting up an account is easy and it's free. Fill in the form below to get started.",
"registration.studentUsernameStepHelpText": "Already have a Scratch account?",
"registration.studentUsernameStepTitle": "Create a Scratch Account",
"registration.studentUsernameStepTooltip": "You'll need to create a new Scratch account to join this class.",
"registration.studentUsernameFieldHelpText": "For safety, don't use your real name!",
"registration.usernameStepTitle": "Request a Teacher Account",
Expand Down
2 changes: 1 addition & 1 deletion src/views/developers/developers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ var Developers = React.createClass({
<div className="body-copy column">
<h3><FormattedMessage id='developers.learningPrinciplesTitle' /></h3>
<dl>
<dt><FormattedMessage id='developers.learningPrinciplesProjectsTitle' /></dt>
<dt><FormattedMessage id='developers.ProjectsTitle' /></dt>
<dd>
<FormattedMessage id='developers.learningPrinciplesProjectsBody' />
</dd>
Expand Down
1 change: 0 additions & 1 deletion src/views/developers/l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"developers.wwwIntro": "Scratch-www is a standalone web client for the Scratch Community, built using React and Redux. Access the code and documentation <a href=\"https://github.com/LLK/scratch-www\">here</a>.",
"developers.principlesIntro": "We created Scratch to empower young people to think creatively, reason systematically, and work collaboratively. We are guided by a set of <b>Learning Principles</b> and <b>Design Principles</b> that we hope you will follow as you develop new tools and technologies with Scratch Blocks.",
"developers.learningPrinciplesTitle": "Learning Principles",
"developers.learningPrinciplesProjectsTitle": "Projects",
"developers.learningPrinciplesProjectsBody": "People learn best when they are actively working on projects — generating new ideas, designing prototypes, making improvements and creating final products.",
"developers.learningPrinciplesPassionTitle": "Passion",
"developers.learningPrinciplesPassionBody": "When people focus on things they care about, they work longer and harder, persist in the face of challenges, and learn more in the process.",
Expand Down
2 changes: 1 addition & 1 deletion src/views/studentregistration/studentregistration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ var StudentRegistration = intl.injectIntl(React.createClass({
render: function () {
var demographicsDescription = this.props.intl.formatMessage({
id: 'registration.studentPersonalStepDescription'});
var usernameTitle = this.props.intl.formatMessage({id: 'registration.studentUsernameStepTitle'});
var usernameTitle = this.props.intl.formatMessage({id: 'registration.usernameStepTitleScratcher'});
var usernameHelp = this.props.intl.formatMessage({id: 'registration.studentUsernameFieldHelpText'});
var usernameDescription = (
this.props.intl.formatMessage({id: 'registration.studentUsernameStepDescription'}) + ' ' +
Expand Down
2 changes: 0 additions & 2 deletions src/views/teacherregistration/l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
"teacherRegistration.nameStepDescription": "Your name will not be displayed publicly, and will be kept confidential and secure.",
"teacherRegistration.firstName": "First Name",
"teacherRegistration.lastName": "Last Name",
"teacherRegistration.phoneStepTitle": "Phone Number",
"teacherRegistration.phoneNumber": "Phone Number",
"teacherRegistration.phoneStepDescription": "Your phone number will not be displayed publicly, and will be kept confidential and secure",
"teacherRegistration.phoneConsent": "Yes, the Scratch Team may call me to verify my Teacher Account if needed",
"teacherRegistration.validationPhoneNumber": "Please enter a valid phone number",
"teacherRegistration.validationPhoneConsent": "You must consent to verification of your Teacher Account",
"teacherRegistration.orgStepTitle": "Organization",
"teacherRegistration.orgStepDescription": "Your information will not be displayed publicly, and will be kept confidential and secure",
"teacherRegistration.organization": "Organization",
"teacherRegistration.orgTitle": "Your Role",
Expand Down
1 change: 0 additions & 1 deletion src/views/teachers/landing/l10n.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"teacherlanding.title": "Scratch for Educators",
"teacherlanding.intro": "Your students can use Scratch to code their own interactive stories, animations, and games. In the process, they learn to think creatively, reason systematically, and work collaboratively — essential skills for everyone in today’s society.",
"teacherlanding.inPracticeAnchor": "Who Uses Scratch?",
"teacherlanding.resourcesAnchor": "Resources",
"teacherlanding.inPracticeTitle": "Who Uses Scratch?",
"teacherlanding.inPracticeIntro": "Educators are using Scratch in a wide variety of: ",
Expand Down
2 changes: 1 addition & 1 deletion src/views/teachers/landing/landing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var Landing = injectIntl(React.createClass({
<SubNavigation className="inner">
<a href="#in-practice">
<li>
<FormattedMessage id="teacherlanding.inPracticeAnchor" />
<FormattedMessage id="teacherlanding.inPracticeTitle" />
</li>
</a>
<a href="#resources">
Expand Down
3 changes: 1 addition & 2 deletions src/views/thingstotry/l10n.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{
"tile.tutorial": "Tutorial",
"ttt.tutorial": "Tutorial",
"tile.guides": "See Cards and Guides",
"tile.tryIt": "Try It",
"ttt.placeholder": "Placeholder text",
"ttt.title": "Things to Try",
"ttt.subTitle": "You can get started with Scratch in a variety of ways. Click a picture to try the <strong className=\"title-banner-strong\">Tutorial</strong>. You can also download a set of <strong className=\"title-banner-strong\">Activity Cards</strong> and <strong className=\"title-banner-strong\">Educator Guide</strong> for each theme.",
"ttt.tutorialTitle": "Tutorial",
"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.",
Expand Down
52 changes: 52 additions & 0 deletions test/localization/check_duplicate_strings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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');

function noDuplicateValues (idsToCheck, name) {
var values = {};
for (var 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) {
var ids = require(path.resolve(__dirname, '../../src/l10n.json'));
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) {
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;
}
}
}

0 comments on commit e1a0e9f

Please sign in to comment.