diff options
Diffstat (limited to 'front/odiparpack/internals/scripts/extract-intl.js')
| -rw-r--r-- | front/odiparpack/internals/scripts/extract-intl.js | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/front/odiparpack/internals/scripts/extract-intl.js b/front/odiparpack/internals/scripts/extract-intl.js new file mode 100644 index 0000000..087b04e --- /dev/null +++ b/front/odiparpack/internals/scripts/extract-intl.js @@ -0,0 +1,187 @@ +/* eslint-disable */ +/** + * This script will extract the internationalization messages from all components + and package them in the translation json files in the translations file. + */ +const fs = require('fs'); +const nodeGlob = require('glob'); +const transform = require('babel-core').transform; + +const animateProgress = require('./helpers/progress'); +const addCheckmark = require('./helpers/checkmark'); + +const pkg = require('../../package.json'); +const presets = pkg.babel.presets; +const plugins = pkg.babel.plugins || []; + +const i18n = require('../../app/i18n'); + +const DEFAULT_LOCALE = i18n.DEFAULT_LOCALE; + +require('shelljs/global'); + +// Glob to match all js files except test files +const FILES_TO_PARSE = 'app/**/!(*.test).js'; +const locales = i18n.appLocales; + +const newLine = () => process.stdout.write('\n'); + +// Progress Logger +let progress; +const task = message => { + progress = animateProgress(message); + process.stdout.write(message); + + return error => { + if (error) { + process.stderr.write(error); + } + clearTimeout(progress); + return addCheckmark(() => newLine()); + }; +}; + +// Wrap async functions below into a promise +const glob = pattern => + new Promise((resolve, reject) => { + nodeGlob( + pattern, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +const readFile = fileName => + new Promise((resolve, reject) => { + fs.readFile( + fileName, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +const writeFile = (fileName, data) => + new Promise((resolve, reject) => { + fs.writeFile( + fileName, + data, + (error, value) => (error ? reject(error) : resolve(value)), + ); + }); + +// Store existing translations into memory +const oldLocaleMappings = []; +const localeMappings = []; + +// Loop to run once per locale +for (const locale of locales) { + oldLocaleMappings[locale] = {}; + localeMappings[locale] = {}; + // File to store translation messages into + const translationFileName = `app/translations/${locale}.json`; + try { + // Parse the old translation message JSON files + const messages = JSON.parse(fs.readFileSync(translationFileName)); + const messageKeys = Object.keys(messages); + for (const messageKey of messageKeys) { + oldLocaleMappings[locale][messageKey] = messages[messageKey]; + } + } catch (error) { + if (error.code !== 'ENOENT') { + process.stderr.write( + `There was an error loading this translation file: ${translationFileName} + \n${error}`, + ); + } + } +} + +/* push `react-intl` plugin to the existing plugins that are already configured in `package.json` + Example: + ``` + "babel": { + "plugins": [ + ["transform-object-rest-spread", { "useBuiltIns": true }] + ], + "presets": [ + "env", + "react" + ] + } + ``` +*/ +plugins.push(['react-intl']); + +const extractFromFile = fileName => { + return readFile(fileName) + .then(code => { + // Use babel plugin to extract instances where react-intl is used + const { metadata: result } = transform(code, { presets, plugins }); + + for (const message of result['react-intl'].messages) { + for (const locale of locales) { + const oldLocaleMapping = oldLocaleMappings[locale][message.id]; + // Merge old translations into the babel extracted instances where react-intl is used + const newMsg = + locale === DEFAULT_LOCALE ? message.defaultMessage : ''; + localeMappings[locale][message.id] = oldLocaleMapping + ? oldLocaleMapping + : newMsg; + } + } + }) + .catch(error => { + process.stderr.write(`Error transforming file: ${fileName}\n${error}`); + }); +}; + +const memoryTask = glob(FILES_TO_PARSE); +const memoryTaskDone = task('Storing language files in memory'); + +memoryTask.then(files => { + memoryTaskDone(); + + const extractTask = Promise.all( + files.map(fileName => extractFromFile(fileName)), + ); + const extractTaskDone = task('Run extraction on all files'); + // Run extraction on all files that match the glob on line 16 + extractTask.then(result => { + extractTaskDone(); + + // Make the directory if it doesn't exist, especially for first run + mkdir('-p', 'app/translations'); + + let localeTaskDone; + let translationFileName; + + for (const locale of locales) { + translationFileName = `app/translations/${locale}.json`; + localeTaskDone = task( + `Writing translation messages for ${locale} to: ${translationFileName}`, + ); + + // Sort the translation JSON file so that git diffing is easier + // Otherwise the translation messages will jump around every time we extract + let messages = {}; + Object.keys(localeMappings[locale]) + .sort() + .forEach(function(key) { + messages[key] = localeMappings[locale][key]; + }); + + // Write to file the JSON representation of the translation messages + const prettified = `${JSON.stringify(messages, null, 2)}\n`; + + try { + fs.writeFileSync(translationFileName, prettified); + localeTaskDone(); + } catch (error) { + localeTaskDone( + `There was an error saving this translation file: ${translationFileName} + \n${error}`, + ); + } + } + + process.exit(); + }); +}); |
