Skip to content

Commit 4a506f6

Browse files
feat(curriculum): add i18n-curriculum submodule (freeCodeCamp#55341)
Co-authored-by: Oliver Eyton-Williams <[email protected]>
1 parent 35faca5 commit 4a506f6

File tree

6 files changed

+58
-17
lines changed

6 files changed

+58
-17
lines changed

.gitmodules

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "curriculum/i18n-curriculum"]
2+
path = curriculum/i18n-curriculum
3+
url = https://github.com/freeCodeCamp/i18n-curriculum.git
4+
ignore = dirty

client/utils/build-challenges.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ const envData = require('../config/env.json');
66
const {
77
getChallengesForLang,
88
generateChallengeCreator,
9-
CHALLENGES_DIR,
9+
ENGLISH_CHALLENGES_DIR,
1010
META_DIR,
11+
CHALLENGES_DIR,
1112
getChallengesDirForLang
1213
} = require('../../curriculum/get-challenges');
1314

@@ -24,7 +25,11 @@ exports.replaceChallengeNode = () => {
2425
const metaPath = path.resolve(META_DIR, `${blockName}/meta.json`);
2526
delete require.cache[require.resolve(metaPath)];
2627
const meta = require(metaPath);
27-
const englishPath = path.resolve(CHALLENGES_DIR, 'english', filePath);
28+
const englishPath = path.resolve(
29+
ENGLISH_CHALLENGES_DIR,
30+
'english',
31+
filePath
32+
);
2833
const i18nPath = path.resolve(CHALLENGES_DIR, curriculumLocale, filePath);
2934
// TODO: reimplement hot-reloading of certifications
3035
const createChallenge = generateChallengeCreator(

curriculum/get-challenges.js

+37-11
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,34 @@ const { metaSchemaValidator } = require('./schema/meta-schema');
2121

2222
const access = util.promisify(fs.access);
2323

24-
const CHALLENGES_DIR = path.resolve(__dirname, 'challenges');
25-
const META_DIR = path.resolve(CHALLENGES_DIR, '_meta');
26-
exports.CHALLENGES_DIR = CHALLENGES_DIR;
24+
const ENGLISH_CHALLENGES_DIR = path.resolve(__dirname, 'challenges');
25+
const ENGLISH_DICTIONARIES_DIR = path.resolve(__dirname, 'dictionaries');
26+
const META_DIR = path.resolve(ENGLISH_CHALLENGES_DIR, '_meta');
27+
28+
const CURRICULUM_DIR = path.resolve(
29+
__dirname,
30+
process.env.BUILD_WITH_SUBMODULE === 'true'
31+
? 'i18n-curriculum/curriculum'
32+
: '.'
33+
);
34+
35+
const CHALLENGES_DIR = path.resolve(CURRICULUM_DIR, 'challenges');
36+
const DICTIONARIES_DIR = path.resolve(CURRICULUM_DIR, 'dictionaries');
37+
38+
exports.ENGLISH_CHALLENGES_DIR = ENGLISH_CHALLENGES_DIR;
2739
exports.META_DIR = META_DIR;
40+
exports.CHALLENGES_DIR = CHALLENGES_DIR;
2841

2942
const COMMENT_TRANSLATIONS = createCommentMap(
30-
path.resolve(__dirname, 'dictionaries')
43+
DICTIONARIES_DIR,
44+
ENGLISH_DICTIONARIES_DIR
3145
);
3246

33-
function createCommentMap(dictionariesDir) {
34-
// get all the languages for which there are dictionaries.
47+
function createCommentMap(dictionariesDir, englishDictionariesDir) {
48+
// get all the languages for which there are dictionaries. Note: this has to
49+
// include the english dictionaries since translateCommentsInChallenge treats
50+
// all languages equally and will simply remove comments if there is no entry
51+
// in the comment map.
3552
const languages = fs.readdirSync(dictionariesDir);
3653

3754
// get all their dictionaries
@@ -45,11 +62,15 @@ function createCommentMap(dictionariesDir) {
4562

4663
// get the english dicts
4764
const COMMENTS_TO_TRANSLATE = require(
48-
path.resolve(dictionariesDir, 'english', 'comments.json')
65+
path.resolve(englishDictionariesDir, 'english', 'comments.json')
4966
);
5067

5168
const COMMENTS_TO_NOT_TRANSLATE = require(
52-
path.resolve(dictionariesDir, 'english', 'comments-to-not-translate')
69+
path.resolve(
70+
englishDictionariesDir,
71+
'english',
72+
'comments-to-not-translate.json'
73+
)
5374
);
5475

5576
// map from english comment text to translations
@@ -98,7 +119,11 @@ function getTranslationEntry(dicts, { engId, text }) {
98119
}
99120

100121
function getChallengesDirForLang(lang) {
101-
return path.resolve(CHALLENGES_DIR, `${lang}`);
122+
if (lang === 'english') {
123+
return path.resolve(ENGLISH_CHALLENGES_DIR, `${lang}`);
124+
} else {
125+
return path.resolve(CHALLENGES_DIR, `${lang}`);
126+
}
102127
}
103128

104129
function getMetaForBlock(block) {
@@ -221,7 +246,7 @@ async function buildChallenges({ path: filePath }, curriculum, lang) {
221246
const isCert = path.extname(filePath) === '.yml';
222247
const englishPath = path.resolve(
223248
__dirname,
224-
CHALLENGES_DIR,
249+
ENGLISH_CHALLENGES_DIR,
225250
'english',
226251
filePath
227252
);
@@ -336,7 +361,8 @@ function challengeFilesToPolys(files) {
336361

337362
async function assertHasEnglishSource(filePath, lang, englishPath) {
338363
const missingEnglish =
339-
lang !== 'english' && !(await hasEnglishSource(CHALLENGES_DIR, filePath));
364+
lang !== 'english' &&
365+
!(await hasEnglishSource(ENGLISH_CHALLENGES_DIR, filePath));
340366
if (missingEnglish)
341367
throw Error(`Missing English challenge for
342368
${filePath}

curriculum/get-challenges.test.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,14 @@ describe('create non-English challenge', () => {
5656
);
5757

5858
it('returns an object', () => {
59-
expect(typeof createCommentMap(dictionaryDir)).toBe('object');
59+
expect(typeof createCommentMap(dictionaryDir, dictionaryDir)).toBe(
60+
'object'
61+
);
6062
});
6163

6264
it('fallback to the untranslated string', () => {
6365
expect.assertions(2);
64-
const commentMap = createCommentMap(incompleteDictDir);
66+
const commentMap = createCommentMap(incompleteDictDir, incompleteDictDir);
6567
expect(commentMap['To be translated one'].spanish).toEqual(
6668
'Spanish translation one'
6769
);
@@ -78,7 +80,7 @@ describe('create non-English challenge', () => {
7880
'Not translated one',
7981
'Not translated two'
8082
];
81-
const map = createCommentMap(dictionaryDir);
83+
const map = createCommentMap(dictionaryDir, dictionaryDir);
8284
expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds));
8385

8486
const mapValue = map['To be translated one'];
@@ -98,7 +100,7 @@ describe('create non-English challenge', () => {
98100
'Not translated one',
99101
'Not translated two'
100102
];
101-
const map = createCommentMap(dictionaryDir);
103+
const map = createCommentMap(dictionaryDir, dictionaryDir);
102104
expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds));
103105

104106
const translatedOne = map['To be translated one'];

curriculum/i18n-curriculum

Submodule i18n-curriculum added at 531d189

sample.env

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ FREECODECAMP_NODE_ENV=development
5151
CLIENT_LOCALE=english
5252
CURRICULUM_LOCALE=english
5353

54+
# Build using submodule - remove this once the workflow has been entirely moved to use the submodule
55+
BUILD_WITH_SUBMODULE=false
56+
5457
# Show or hide WIP in progress challenges
5558
SHOW_UPCOMING_CHANGES=false
5659
SHOW_NEW_CURRICULUM=true

0 commit comments

Comments
 (0)