diff --git a/curriculum/__fixtures__/dictionaries/chinese/comments.js b/curriculum/__fixtures__/dictionaries/chinese/comments.js new file mode 100644 index 0000000000..4997de02e6 --- /dev/null +++ b/curriculum/__fixtures__/dictionaries/chinese/comments.js @@ -0,0 +1,12 @@ +const TRANSLATIONS = [ + { + id: 'hyek8f', + text: 'Chinese translation one' + }, + { + id: 'rscjup', + text: 'Chinese translation two' + } +]; + +module.exports = TRANSLATIONS; diff --git a/curriculum/__fixtures__/dictionaries/english/comments.js b/curriculum/__fixtures__/dictionaries/english/comments.js new file mode 100644 index 0000000000..68a980c32e --- /dev/null +++ b/curriculum/__fixtures__/dictionaries/english/comments.js @@ -0,0 +1,24 @@ +const COMMENTS_TO_TRANSLATE = [ + { + id: 'hyek8f', + text: 'To be translated one' + }, + { + id: 'rscjup', + text: 'To be translated two' + } +]; + +const COMMENTS_TO_NOT_TRANSLATE = [ + { + id: 'rms15q', + text: 'Not translated one' + }, + { + id: '78gz3i', + text: 'Not translated two' + } +]; + +exports.COMMENTS_TO_TRANSLATE = COMMENTS_TO_TRANSLATE; +exports.COMMENTS_TO_NOT_TRANSLATE = COMMENTS_TO_NOT_TRANSLATE; diff --git a/curriculum/__fixtures__/dictionaries/spanish/comments.js b/curriculum/__fixtures__/dictionaries/spanish/comments.js new file mode 100644 index 0000000000..f180b6d897 --- /dev/null +++ b/curriculum/__fixtures__/dictionaries/spanish/comments.js @@ -0,0 +1,12 @@ +const TRANSLATIONS = [ + { + id: 'hyek8f', + text: 'Spanish translation one' + }, + { + id: 'rscjup', + text: 'Spanish translation two' + } +]; + +module.exports = TRANSLATIONS; diff --git a/curriculum/dictionaries/chinese/comments.js b/curriculum/dictionaries/chinese/comments.js new file mode 100644 index 0000000000..d6c2a06ffe --- /dev/null +++ b/curriculum/dictionaries/chinese/comments.js @@ -0,0 +1,441 @@ +/* eslint-disable max-len */ +// NOTE: updates to translations will not appear until the client is restarted +// i.e. close it and run npm run develop + +// Only translate the text that is not surround by single backticks +const TRANSLATIONS = [ + { + id: 'hyek8f', + text: 'comment placeholder (needs translation)' + }, + { + id: 'rscjup', + text: 'comment placeholder (needs translation)' + }, + { + id: 'am2xch', + text: 'comment placeholder (needs translation)' + }, + { + id: '6rztdg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'to1vwe', + text: 'comment placeholder (needs translation)' + }, + { + id: '31b7ey', + text: 'comment placeholder (needs translation)' + }, + { + id: 'c24by8', + text: 'comment placeholder (needs translation)' + }, + { + id: 'jbrt8k', + text: 'comment placeholder (needs translation)' + }, + { + id: 'zkh12d', + text: 'comment placeholder (needs translation)' + }, + { + id: 'mobihi', + text: 'comment placeholder (needs translation)' + }, + { + id: 'v3ups9', + text: 'comment placeholder (needs translation)' + }, + { + id: 'iw4a3a', + text: 'comment placeholder (needs translation)' + }, + { + id: '463xp8', + text: 'comment placeholder (needs translation)' + }, + { + id: 'u3inrm', + text: 'comment placeholder (needs translation)' + }, + { + id: 'axnbgg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'i2kck7', + text: 'comment placeholder (needs translation)' + }, + { + id: 'dlbobn', + text: 'comment placeholder (needs translation)' + }, + { + id: 'v127zb', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ejm0ql', + text: 'comment placeholder (needs translation)' + }, + { + id: 'iwch6t', + text: 'comment placeholder (needs translation)' + }, + { + id: 'hihhyz', + text: 'comment placeholder (needs translation)' + }, + { + id: 'sdxti5', + text: 'comment placeholder (needs translation)' + }, + { + id: 'wfw6sc', + text: 'comment placeholder (needs translation)' + }, + { + id: 'sjw6f4', + text: 'comment placeholder (needs translation)' + }, + { + id: 'nupsh2', + text: 'comment placeholder (needs translation)' + }, + { + id: 'xfjb3s', + text: 'comment placeholder (needs translation)' + }, + { + id: 'htpjk7', + text: 'comment placeholder (needs translation)' + }, + { + id: 'tfzdsp', + text: 'comment placeholder (needs translation)' + }, + { + id: 'zh20mi', + text: 'comment placeholder (needs translation)' + }, + { + id: '43qs4c', + text: 'comment placeholder (needs translation)' + }, + { + id: 'nen3qo', + text: 'comment placeholder (needs translation)' + }, + { + id: '0cwyam', + text: 'comment placeholder (needs translation)' + }, + { + id: 'fq0wsg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'tegkqa', + text: 'comment placeholder (needs translation)' + }, + { + id: 'b5oihn', + text: 'comment placeholder (needs translation)' + }, + { + id: '91y4pd', + text: 'comment placeholder (needs translation)' + }, + { + id: 'eie1vk', + text: 'comment placeholder (needs translation)' + }, + { + id: '5s7nnl', + text: 'comment placeholder (needs translation)' + }, + { + id: '34qe2q', + text: 'comment placeholder (needs translation)' + }, + { + id: '2c1wra', + text: 'comment placeholder (needs translation)' + }, + { + id: '923cpg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'picsyf', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ysjr1s', + text: 'comment placeholder (needs translation)' + }, + { + id: 'kjd1am', + text: 'comment placeholder (needs translation)' + }, + { + id: '5tx4ow', + text: 'comment placeholder (needs translation)' + }, + { + id: '9yu58b', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ciddtb', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ixx548', + text: 'comment placeholder (needs translation)' + }, + { + id: '6mbhjj', + text: 'comment placeholder (needs translation)' + }, + { + id: 'jshtzq', + text: 'comment placeholder (needs translation)' + }, + { + id: 'cw1ghf', + text: 'comment placeholder (needs translation)' + }, + { + id: 'iuccln', + text: 'comment placeholder (needs translation)' + }, + { + id: 'bm2mop', + text: 'comment placeholder (needs translation)' + }, + { + id: 'kchz5k', + text: 'comment placeholder (needs translation)' + }, + { + id: 'bfd23c', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ead98i', + text: 'comment placeholder (needs translation)' + }, + { + id: '7zf0i2', + text: 'comment placeholder (needs translation)' + }, + { + id: '5j2l88', + text: 'comment placeholder (needs translation)' + }, + { + id: 'e843r9', + text: 'comment placeholder (needs translation)' + }, + { + id: '5fvehh', + text: 'comment placeholder (needs translation)' + }, + { + id: 'qn720a', + text: 'comment placeholder (needs translation)' + }, + { + id: 'j86mef', + text: 'comment placeholder (needs translation)' + }, + { + id: 'mk7rvy', + text: 'comment placeholder (needs translation)' + }, + { + id: 'n7vm1s', + text: 'comment placeholder (needs translation)' + }, + { + id: 'cvh4x7', + text: 'comment placeholder (needs translation)' + }, + { + id: 'lvmnm7', + text: 'comment placeholder (needs translation)' + }, + { + id: 'avpx79', + text: 'comment placeholder (needs translation)' + }, + { + id: '0b5ps6', + text: 'comment placeholder (needs translation)' + }, + { + id: 'uemoej', + text: 'comment placeholder (needs translation)' + }, + { + id: 'lm86nf', + text: 'comment placeholder (needs translation)' + }, + { + id: 'qscelx', + text: 'comment placeholder (needs translation)' + }, + { + id: 'atqiig', + text: 'comment placeholder (needs translation)' + }, + { + id: 'yq81wg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'kxio9j', + text: 'comment placeholder (needs translation)' + }, + { + id: 'alh6pw', + text: 'comment placeholder (needs translation)' + }, + { + id: '1cfidd', + text: 'comment placeholder (needs translation)' + }, + { + id: '96tntk', + text: 'comment placeholder (needs translation)' + }, + { + id: '58a5g7', + text: 'comment placeholder (needs translation)' + }, + { + id: '71bus9', + text: 'comment placeholder (needs translation)' + }, + { + id: '7wp46n', + text: 'comment placeholder (needs translation)' + }, + { + id: 'oefvg5', + text: 'comment placeholder (needs translation)' + }, + { + id: 'mnt4d3', + text: 'comment placeholder (needs translation)' + }, + { + id: 'fhe9m4', + text: 'comment placeholder (needs translation)' + }, + { + id: 'za434b', + text: 'comment placeholder (needs translation)' + }, + { + id: '7c1fv9', + text: 'comment placeholder (needs translation)' + }, + { + id: 'r44ovx', + text: 'comment placeholder (needs translation)' + }, + { + id: 'cl8peb', + text: 'comment placeholder (needs translation)' + }, + { + id: '1xi3cv', + text: 'comment placeholder (needs translation)' + }, + { + id: '3gc01a', + text: 'comment placeholder (needs translation)' + }, + { + id: '14kfog', + text: 'comment placeholder (needs translation)' + }, + { + id: 'd1shtt', + text: 'comment placeholder (needs translation)' + }, + { + id: 'pqq6sy', + text: 'comment placeholder (needs translation)' + }, + { + id: 'nd2oxy', + text: 'comment placeholder (needs translation)' + }, + { + id: 'ocm81t', + text: 'comment placeholder (needs translation)' + }, + { + id: 'or9p5p', + text: 'comment placeholder (needs translation)' + }, + { + id: 'g1608f', + text: 'comment placeholder (needs translation)' + }, + { + id: 'bheu99', + text: 'comment placeholder (needs translation)' + }, + { + id: 'x1djjr', + text: 'comment placeholder (needs translation)' + }, + { + id: '22ta95', + text: 'comment placeholder (needs translation)' + }, + { + id: 'w43c7l', + text: 'comment placeholder (needs translation)' + }, + { + id: 'pgckoj', + text: 'comment placeholder (needs translation)' + }, + { + id: '2xiqvv', + text: 'comment placeholder (needs translation)' + }, + { + id: '2sx8zg', + text: 'comment placeholder (needs translation)' + }, + { + id: 'xmjfd8', + text: 'comment placeholder (needs translation)' + }, + { + id: 'es69h6', + text: 'comment placeholder (needs translation)' + }, + { + id: 'fho5t5', + text: 'comment placeholder (needs translation)' + }, + { + id: '00kcrm', + text: 'comment placeholder (needs translation)' + }, + { + id: 'sxpg2a', + text: 'comment placeholder (needs translation)' + } +]; + +module.exports = TRANSLATIONS; diff --git a/curriculum/getChallenges.js b/curriculum/getChallenges.js index cff04f85f8..3723789b3c 100644 --- a/curriculum/getChallenges.js +++ b/curriculum/getChallenges.js @@ -10,10 +10,6 @@ const { translateCommentsInChallenge } = require('../tools/challenge-md-parser/translation-parser/translation-parser'); /* eslint-enable max-len*/ -const { - COMMENTS_TO_TRANSLATE, - COMMENTS_TO_NOT_TRANSLATE -} = require('./dictionaries/english/comments'); const { isAuditedCert } = require('../utils/is-audited'); const { dasherize, nameify } = require('../utils/slugs'); @@ -28,6 +24,78 @@ const metaDir = path.resolve(challengesDir, '_meta'); exports.challengesDir = challengesDir; exports.metaDir = metaDir; +const COMMENT_TRANSLATIONS = createCommentMap( + path.resolve(__dirname, './dictionaries') +); + +function createCommentMap(dictionariesDir) { + // get all the languages for which there are dictionaries. + const languages = fs + .readdirSync(dictionariesDir) + .filter(x => x !== 'english'); + + // get all their dictionaries + const dictionaries = languages.reduce( + (acc, lang) => ({ + ...acc, + [lang]: require(path.resolve(dictionariesDir, lang, 'comments')) + }), + {} + ); + + // get the english dicts + const { + COMMENTS_TO_TRANSLATE, + COMMENTS_TO_NOT_TRANSLATE + } = require(path.resolve(dictionariesDir, 'english', 'comments')); + + // map from english comment text to translations + const translatedCommentMap = COMMENTS_TO_TRANSLATE.reduce( + (acc, { id, text }) => { + return { + ...acc, + [text]: getTranslationEntry(dictionaries, { engId: id, text }) + }; + }, + {} + ); + + // map from english comment text to itself + const untranslatableCommentMap = COMMENTS_TO_NOT_TRANSLATE.reduce( + (acc, { text }) => { + const englishEntry = languages.reduce( + (acc, lang) => ({ + ...acc, + [lang]: text + }), + {} + ); + return { + ...acc, + [text]: englishEntry + }; + }, + {} + ); + + return { ...translatedCommentMap, ...untranslatableCommentMap }; +} + +exports.createCommentMap = createCommentMap; + +function getTranslationEntry(dicts, { engId, text }) { + return Object.keys(dicts).reduce((acc, lang) => { + const entry = dicts[lang].find(({ id }) => engId === id); + if (entry) { + return { ...acc, [lang]: entry.text }; + } else { + throw Error(`Missing translation for comment +'${text}' + with id of ${engId}`); + } + }, {}); +} + function getChallengesDirForLang(lang) { return path.resolve(challengesDir, `./${lang}`); } diff --git a/curriculum/getChallenges.test.js b/curriculum/getChallenges.test.js index 83228fa00a..e45c4fb665 100644 --- a/curriculum/getChallenges.test.js +++ b/curriculum/getChallenges.test.js @@ -1,7 +1,10 @@ /* global expect beforeAll */ +const path = require('path'); + const { createChallengeCreator, - hasEnglishSourceCreator + hasEnglishSourceCreator, + createCommentMap } = require('./getChallenges'); const EXISTING_CHALLENGE_PATH = 'challenge.md'; @@ -46,4 +49,67 @@ It should be in expect(sourceExists).toBe(false); }); }); + + describe('createCommentMap', () => { + const dictionaryDir = path.resolve( + __dirname, + '__fixtures__', + 'dictionaries' + ); + it('returns an object', () => { + expect(typeof createCommentMap(dictionaryDir)).toBe('object'); + }); + + it('returns an object with an expected form', () => { + expect.assertions(4); + const expectedIds = [ + 'To be translated one', + 'To be translated two', + 'Not translated one', + 'Not translated two' + ]; + const map = createCommentMap(dictionaryDir); + expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds)); + + const mapValue = map['To be translated one']; + + expect(Object.keys(mapValue)).toEqual( + expect.arrayContaining(['chinese', 'spanish']) + ); + expect(typeof mapValue.chinese).toBe('string'); + expect(typeof mapValue.spanish).toBe('string'); + }); + + it('returns an object with expected values', () => { + expect.assertions(9); + const expectedIds = [ + 'To be translated one', + 'To be translated two', + 'Not translated one', + 'Not translated two' + ]; + const map = createCommentMap(dictionaryDir); + expect(Object.keys(map)).toEqual(expect.arrayContaining(expectedIds)); + + const translatedOne = map['To be translated one']; + + expect(translatedOne.chinese).toBe('Chinese translation one'); + expect(translatedOne.spanish).toBe('Spanish translation one'); + + const translatedTwo = map['To be translated two']; + + expect(translatedTwo.chinese).toBe('Chinese translation two'); + expect(translatedTwo.spanish).toBe('Spanish translation two'); + + const untranslatedOne = map['Not translated one']; + + expect(untranslatedOne.chinese).toBe('Not translated one'); + expect(untranslatedOne.spanish).toBe('Not translated one'); + + const untranslatedTwo = map['Not translated two']; + + expect(untranslatedTwo.chinese).toBe('Not translated two'); + expect(untranslatedTwo.spanish).toBe('Not translated two'); + }); + }); });