UNPKG

@instructure/canvas-rce

Version:

A component wrapping Canvas's usage of Tinymce

218 lines (196 loc) 7.75 kB
#!/usr/bin/env node /* * Copyright (C) 2021 - present Instructure, Inc. * * This file is part of Canvas. * * Canvas is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, version 3 of the License. * * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * For each locale there are 2 files we need. One is a .json file with the RCE * translations that's managed by the canvas-lms translation process and lives in * @instructure/translations. The other is a .js file downloaded from * https://www.tiny.cloud/get-tiny/language-packages/. * These two sources support different locales and each have their own * locale -> file nameing scheme, making it easy to get out of sync. * * This script uses the list of files in @instructure/translations for the rce as * the source of the list of RCE supported locales, maps the tinymce supported locales * as closely as possible to them (using src/rce/editorLanguage.js), and generates * the set of files the RCE will import which in turn imports both sets of * translations data. * * RCE translations come from @instructure/translations * tinymce translations come from src/translations/tinymce * the generated locale files are in src/translations/locales * * In addition, ./src/getTranslations.js is generated which defines a function that * imports the right src/translations/locales file based on the given locale. This * has the effect of webpack splitting each locales/*.js file into its own bundle. * * The output from this script gets checked in. * This script is run as a prelude to the build, and if no translated data files have * changes, it should not generate any changes in its output. * * If you update the tinymce translation packages (and you should periodically), * check the mapping in src/rce/editorLanguages.js to be sure it's still complete. */ const fs = require('fs') const path = require('path') const {getTranslationList, readTranslationFile} = require('@instructure/translations') const {editorLanguage} = require('../src/rce/editorLanguage.js') // Here we go. installTranslations() .then(() => { console.log('Translations installed.') process.exit(0) }) .catch(err => { console.error('Failed installing translations', err) process.exit(1) }) // The driver that does all the work. async function installTranslations() { const canvasTranslations = await getTranslationList() const canvasLocaleFileBasenames = canvasTranslations.map(t => t.replace('.json', '')) const tinyLocales = mapCanvasLocalesToTiny(canvasLocaleFileBasenames) generateCombinedImporters(canvasLocaleFileBasenames, tinyLocales) // different file systems return the list of files in different orders // (e.g. da vs da-x-k12) so sort them to get a uniform order // of the case statements out of generateGetTranslations generateGetTranslations(canvasLocaleFileBasenames.sort()) } // given the array of canvas locales, return // the mapping to the corresponding tinymce locales function mapCanvasLocalesToTiny(canvasLocales) { const tinyLocales = {} for (const locale of canvasLocales) { tinyLocales[locale] = editorLanguage(locale) } return tinyLocales } // there's one file in src/translations/locales for each canvas locale // that imports adds the canvas strings to formatMessage and // imports the corresponding tinymce translations if one exists function generateCombinedImporters(canvasLocaleFileBasenames, tinyLocales) { removeStaleTranslationFiles(canvasLocaleFileBasenames) for (const basename of canvasLocaleFileBasenames) { const filepath = path.resolve( __dirname, path.join('../src/translations/locales', `${basename}.js`), ) const content = localeFileContent(basename, tinyLocales[basename]) fs.writeFileSync(filepath, content, {flag: 'w'}) } } // if there are any existing src/translations/locales files // for locales no longer in the new list, remove them function removeStaleTranslationFiles(locales) { const newLocalesFiles = locales.map(l => `${l}.js`) const localesDir = path.resolve(__dirname, '../src/translations/locales') const curLocalesFiles = fs.readdirSync(localesDir) const staleFiles = curLocalesFiles.filter(f => !newLocalesFiles.includes(f)) for (const f of staleFiles) { fs.rmSync(path.resolve(localesDir, f)) } } const copyright = `/* * Copyright (C) 2021 - present Instructure, Inc. * * This file is part of Canvas. * * Canvas is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, version 3 of the License. * * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ ` // the content of the file being generated in generateCombinedImporters function localeFileContent(canvasLocaleFileBasename, tinyLocale) { // some translation files have '_', but no canvas locale does, // they all use '-'. let canvasLocale = canvasLocaleFileBasename.replace(/_/g, '-') const localeData = readTranslationFile('canvas-rce', canvasLocaleFileBasename) const preface = `${copyright} import formatMessage from '../../format-message' ` const tinyimport = tinyLocale ? `import '../tinymce/${tinyLocale}' ` : '' const rceLocaleDef = ` const locale = ${localeData} ` if (/-/.test(canvasLocale)) { canvasLocale = `'${canvasLocale}'` } const trailer = ` formatMessage.addLocale({${canvasLocale}: locale}) ` return `${preface}${tinyimport}${rceLocaleDef}${trailer}` } // generate the getTranslations() function // that serves to code-split the translations // into their own webpack bundle then provide // them to the RCE function generateGetTranslations(localeFileBasenames) { const preface = `${copyright} /* * ******************************************************** * This file is generated by scripts/installTranslations.js * as part of the build. DO NOT EDIT * ******************************************************** */ export default function getTranslations(locale) { const transReadyPromise = new Promise((resolve, reject) => { import('tinymce') .then(() => { let p switch (locale) { ` const cases = [] for (const locale of localeFileBasenames) { cases.push(` case '${locale.replace(/_/g, '-')}': p = import('./translations/locales/${locale}') break`) } const trailer = ` default: p = Promise.resolve(null) } p.then(resolve).catch(reject) }) .catch(() => { throw new Error('Failed loading tinymce.') }) }) return transReadyPromise } ` const getlocalelist = ` export function getLocaleList() { return [ '${localeFileBasenames.map(l => l.replace(/_/g, '-')).join("',\n '")}', ] } ` const content = `${preface}${cases.join('\n')}${trailer}${getlocalelist}` fs.writeFileSync('./src/getTranslations.js', content, {flag: 'w'}) }