feat(curriculum): add i18n-curriculum submodule (#55341)

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Tom
2024-07-09 09:21:38 -05:00
committed by GitHub
parent 35faca5df6
commit 4a506f6e06
6 changed files with 60 additions and 19 deletions

4
.gitmodules vendored Normal file
View File

@@ -0,0 +1,4 @@
[submodule "curriculum/i18n-curriculum"]
path = curriculum/i18n-curriculum
url = https://github.com/freeCodeCamp/i18n-curriculum.git
ignore = dirty

View File

@@ -6,8 +6,9 @@ const envData = require('../config/env.json');
const { const {
getChallengesForLang, getChallengesForLang,
generateChallengeCreator, generateChallengeCreator,
CHALLENGES_DIR, ENGLISH_CHALLENGES_DIR,
META_DIR, META_DIR,
CHALLENGES_DIR,
getChallengesDirForLang getChallengesDirForLang
} = require('../../curriculum/get-challenges'); } = require('../../curriculum/get-challenges');
@@ -24,7 +25,11 @@ exports.replaceChallengeNode = () => {
const metaPath = path.resolve(META_DIR, `${blockName}/meta.json`); const metaPath = path.resolve(META_DIR, `${blockName}/meta.json`);
delete require.cache[require.resolve(metaPath)]; delete require.cache[require.resolve(metaPath)];
const meta = require(metaPath); const meta = require(metaPath);
const englishPath = path.resolve(CHALLENGES_DIR, 'english', filePath); const englishPath = path.resolve(
ENGLISH_CHALLENGES_DIR,
'english',
filePath
);
const i18nPath = path.resolve(CHALLENGES_DIR, curriculumLocale, filePath); const i18nPath = path.resolve(CHALLENGES_DIR, curriculumLocale, filePath);
// TODO: reimplement hot-reloading of certifications // TODO: reimplement hot-reloading of certifications
const createChallenge = generateChallengeCreator( const createChallenge = generateChallengeCreator(

View File

@@ -21,17 +21,34 @@ const { metaSchemaValidator } = require('./schema/meta-schema');
const access = util.promisify(fs.access); const access = util.promisify(fs.access);
const CHALLENGES_DIR = path.resolve(__dirname, 'challenges'); const ENGLISH_CHALLENGES_DIR = path.resolve(__dirname, 'challenges');
const META_DIR = path.resolve(CHALLENGES_DIR, '_meta'); const ENGLISH_DICTIONARIES_DIR = path.resolve(__dirname, 'dictionaries');
exports.CHALLENGES_DIR = CHALLENGES_DIR; const META_DIR = path.resolve(ENGLISH_CHALLENGES_DIR, '_meta');
exports.META_DIR = META_DIR;
const COMMENT_TRANSLATIONS = createCommentMap( const CURRICULUM_DIR = path.resolve(
path.resolve(__dirname, 'dictionaries') __dirname,
process.env.BUILD_WITH_SUBMODULE === 'true'
? 'i18n-curriculum/curriculum'
: '.'
); );
function createCommentMap(dictionariesDir) { const CHALLENGES_DIR = path.resolve(CURRICULUM_DIR, 'challenges');
// get all the languages for which there are dictionaries. const DICTIONARIES_DIR = path.resolve(CURRICULUM_DIR, 'dictionaries');
exports.ENGLISH_CHALLENGES_DIR = ENGLISH_CHALLENGES_DIR;
exports.META_DIR = META_DIR;
exports.CHALLENGES_DIR = CHALLENGES_DIR;
const COMMENT_TRANSLATIONS = createCommentMap(
DICTIONARIES_DIR,
ENGLISH_DICTIONARIES_DIR
);
function createCommentMap(dictionariesDir, englishDictionariesDir) {
// get all the languages for which there are dictionaries. Note: this has to
// include the english dictionaries since translateCommentsInChallenge treats
// all languages equally and will simply remove comments if there is no entry
// in the comment map.
const languages = fs.readdirSync(dictionariesDir); const languages = fs.readdirSync(dictionariesDir);
// get all their dictionaries // get all their dictionaries
@@ -45,11 +62,15 @@ function createCommentMap(dictionariesDir) {
// get the english dicts // get the english dicts
const COMMENTS_TO_TRANSLATE = require( const COMMENTS_TO_TRANSLATE = require(
path.resolve(dictionariesDir, 'english', 'comments.json') path.resolve(englishDictionariesDir, 'english', 'comments.json')
); );
const COMMENTS_TO_NOT_TRANSLATE = require( const COMMENTS_TO_NOT_TRANSLATE = require(
path.resolve(dictionariesDir, 'english', 'comments-to-not-translate') path.resolve(
englishDictionariesDir,
'english',
'comments-to-not-translate.json'
)
); );
// map from english comment text to translations // map from english comment text to translations
@@ -98,8 +119,12 @@ function getTranslationEntry(dicts, { engId, text }) {
} }
function getChallengesDirForLang(lang) { function getChallengesDirForLang(lang) {
if (lang === 'english') {
return path.resolve(ENGLISH_CHALLENGES_DIR, `${lang}`);
} else {
return path.resolve(CHALLENGES_DIR, `${lang}`); return path.resolve(CHALLENGES_DIR, `${lang}`);
} }
}
function getMetaForBlock(block) { function getMetaForBlock(block) {
return JSON.parse( return JSON.parse(
@@ -221,7 +246,7 @@ async function buildChallenges({ path: filePath }, curriculum, lang) {
const isCert = path.extname(filePath) === '.yml'; const isCert = path.extname(filePath) === '.yml';
const englishPath = path.resolve( const englishPath = path.resolve(
__dirname, __dirname,
CHALLENGES_DIR, ENGLISH_CHALLENGES_DIR,
'english', 'english',
filePath filePath
); );
@@ -336,7 +361,8 @@ function challengeFilesToPolys(files) {
async function assertHasEnglishSource(filePath, lang, englishPath) { async function assertHasEnglishSource(filePath, lang, englishPath) {
const missingEnglish = const missingEnglish =
lang !== 'english' && !(await hasEnglishSource(CHALLENGES_DIR, filePath)); lang !== 'english' &&
!(await hasEnglishSource(ENGLISH_CHALLENGES_DIR, filePath));
if (missingEnglish) if (missingEnglish)
throw Error(`Missing English challenge for throw Error(`Missing English challenge for
${filePath} ${filePath}

View File

@@ -56,12 +56,14 @@ describe('create non-English challenge', () => {
); );
it('returns an object', () => { it('returns an object', () => {
expect(typeof createCommentMap(dictionaryDir)).toBe('object'); expect(typeof createCommentMap(dictionaryDir, dictionaryDir)).toBe(
'object'
);
}); });
it('fallback to the untranslated string', () => { it('fallback to the untranslated string', () => {
expect.assertions(2); expect.assertions(2);
const commentMap = createCommentMap(incompleteDictDir); const commentMap = createCommentMap(incompleteDictDir, incompleteDictDir);
expect(commentMap['To be translated one'].spanish).toEqual( expect(commentMap['To be translated one'].spanish).toEqual(
'Spanish translation one' 'Spanish translation one'
); );
@@ -78,7 +80,7 @@ describe('create non-English challenge', () => {
'Not translated one', 'Not translated one',
'Not translated two' 'Not translated two'
]; ];
const map = createCommentMap(dictionaryDir); const map = createCommentMap(dictionaryDir, dictionaryDir);
expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds)); expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds));
const mapValue = map['To be translated one']; const mapValue = map['To be translated one'];
@@ -98,7 +100,7 @@ describe('create non-English challenge', () => {
'Not translated one', 'Not translated one',
'Not translated two' 'Not translated two'
]; ];
const map = createCommentMap(dictionaryDir); const map = createCommentMap(dictionaryDir, dictionaryDir);
expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds)); expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds));
const translatedOne = map['To be translated one']; const translatedOne = map['To be translated one'];

View File

@@ -51,6 +51,9 @@ FREECODECAMP_NODE_ENV=development
CLIENT_LOCALE=english CLIENT_LOCALE=english
CURRICULUM_LOCALE=english CURRICULUM_LOCALE=english
# Build using submodule - remove this once the workflow has been entirely moved to use the submodule
BUILD_WITH_SUBMODULE=false
# Show or hide WIP in progress challenges # Show or hide WIP in progress challenges
SHOW_UPCOMING_CHANGES=false SHOW_UPCOMING_CHANGES=false
SHOW_NEW_CURRICULUM=true SHOW_NEW_CURRICULUM=true